Покладіть плитку Каркассон


23

Настільна гра

У настільній грі « Каркассон » гравці розміщують плитки, підрівнюючи їх краї та заробляючи найвищі бали, створюючи великі суміжні ділянки місцевості. Нижче наведено (приблизно) типи та кількість плиток, що входять у гру:

#01 x4 введіть тут опис зображення #02 x5 введіть тут опис зображення #03 x8 введіть тут опис зображення #04 x2 введіть тут опис зображення

#05 x9 введіть тут опис зображення #06 x4 введіть тут опис зображення #07 x1 введіть тут опис зображення #08 x3 введіть тут опис зображення

#09 x3 введіть тут опис зображення #10 x3 введіть тут опис зображення #11 x4 введіть тут опис зображення #12 x5 введіть тут опис зображення

#13 x3 введіть тут опис зображення #14 x3 введіть тут опис зображення #15 x2 введіть тут опис зображення #16 x5 введіть тут опис зображення

#17 x5 введіть тут опис зображення #18 x2 введіть тут опис зображення #19 x3 введіть тут опис зображення #20 x1 введіть тут опис зображення

#21 x5 введіть тут опис зображення #22 x2 введіть тут опис зображення #23 x1 введіть тут опис зображення #24 x1 введіть тут опис зображення

#25 x1 введіть тут опис зображення

Завдання

Ви повинні розмістити плитку, підрівнюючи краї, намагаючись підтримувати найбільші можливі суміжні ділянки місцевості.

Розміщення

  • Плитки можна розміщувати лише в одному з (до 4) порожніх просторів, прилеглих до будь-якої існуючої плитки (або плитки) в ігровій зоні.
  • Плитку можна обертати на 90, 180 або 270 градусів.

Збіг по краях

  • Краї розміщеної плитки повинні відповідати дотичним краям (до 4) сусідніх плиток, тобто дотикові пікселі одного кольору.

Суміжний рельєф

  • "Закриття ділянки місцевості" означає розміщення плитки таким чином, щоб будь-яка сусідня зона кольору не могла бути продовжена з подальшим розміщенням плитки.
  • Якщо можливе альтернативне розміщення, його слід вибирати над будь-яким розміщенням плитки, яке закривало б місцевість.
  • Якщо вам доведеться вибирати між кількома місцями закриття, виберіть будь-яке. Якщо вам доведеться вибирати між кількома місцями, які не закриваються, виберіть будь-яке.
  • Не враховуйте # ff00ff (кутові пікселі) під час обчислення суміжних площ. Також нехтуйте будівлями, тобто кольоровими ділянками, які вже повністю укладені в плитку.

Вхідні дані

  • Вхід - це два зображення:

    1. Ігрова зона.

      • Початкова ігрова площа складається з плитки #11(однієї плитки).
      • Розширена ігрова область, створена як вихід, також повинна підтримуватися як вхід.
    2. Плитка, яку потрібно укласти.

      • Усі приклади плитки повинні підтримуватися як вхідні дані.
  • Визначте відповідні краї / суміжний рельєф місцевості, використовуючи лише дані цього зображення. Немає жорсткого кодування.

Вихід

  • Вихід - це зображення, що показує результуючу ігрову область після розміщення плитки.
  • Зображення повинно бути сумісним з вашою власною програмою, тобто воно може використовуватися як введення ігрової зони.
  • Якщо розмістити плитку неможливо, поверніть помилку.

Ви можете припустити, що

  • Плитки завжди 55 px на 55 px
  • Плитки завжди матимуть ті кольори, які зараз використовуються на прикладі плиток.

Примітки

  • Ваша відповідь повинна містити приклад виведення після принаймні 2 пропусків (рекомендується більше).
  • Це часткове та неточне відображення оригінальної настільної гри, вам не потрібно застосовувати жодне з правил та тактик, які не згадані тут.

Оцінка

  • Ваш рахунок - це кількість байтів для вашого подання.
  • Дані про зображення не включаються до вашої оцінки.
  • Виграє найнижчий рахунок.


Гра в повну гру

Ви можете написати сценарій, який використовує ваш підрозділ, щоб грати в повну гру, яка може складатися з:

  • Розміщення плитки вибрано псевдовипадково з повного набору 85.
  • Повернення плитки до набору, якщо її неможливо розмістити.
  • Повторюйте, поки не буде розміщена кожна плитка - або поки не вдасться розмістити дві плитки підряд.

Він не буде включений до вашого числа байтів або не покращить ваш рахунок, але я, швидше за все, запропонував би нагороду за такий вид відповіді.


1
яка різниця між 12, 15 та 17?
kaine

спасибі за те, що це зрозуміло, 17 було дублікатом. проте 15 відрізняються, оскільки потенційно можуть закрити ділянку місцевості. (btw, кольори області не є суміжними, якщо торкаються лише куточки пікселів)
jsh

Таким чином, один 15 та два 2 можуть зробити 2 окремих чорних ділянки розміром 2. У той час як один 12 та два 2 можуть замість цього зробити чорні зрізи, які є 3 великими. Добре.
kaine

2
1. якщо ви могли використовувати інструмент відро для заповнення фарби ms, щоб змінити колір області, це суміжна область. у вашому прикладі було б 7 суміжних областей. 2. що звучить розумно. доки ви використовуєте два зображення, як зазначено, ви можете робити це як завгодно. 3. Ви можете зобразити порожній простір будь-яким способом. прозорість - хороший варіант. ви також можете використовувати будь-який колір, який не вказаний у прикладі плиток.
jsh

1
@ hosch250 ігрова область нескінченна (розширюється за потребою). Щойно перша плитка на виставі, перша плитка - це вся ігрова область.
jlahd

Відповіді:


8

Perl 5 з PerlMagick: 875 789 763

Я не рахував лінію, починаючи з sub wякої використовується для сортування позицій на відстані до центру, щоб віддати перевагу компактним рішенням (зараз працює належним чином). У цій версії уникнути закриття не хочеться, але я вважаю, що навпаки є більш цікавою та вірною грі. Для цього змініть рядок $s=$t if!grep...на $s=$t if grep....

use Image::Magick;
sub p{/x/;@o=$r->GetPixel(y=>$'+pop,x,$`+pop);"@o"}
sub o{$w=&p;"0 0 0"eq$w?3:&p eq$w}
sub f{$r->FloodfillPaint(y=>$J+$',x,$I+$&,channel,All,fill,@_)}
($i=Image::Magick->new)->Read(@ARGV);$r=$b=$i->[0];
$h=$b->Get(rows)+112;$:=$b->Get(width)+112;
$b->Extent(geometry,"$:x$h-56-56",background,none);
@v=grep p()eq"0 0 0",map{map-54+55*$_.x.($'*55-54),//..$:/55}1..$h/55;
sub w{$_=pop;/x/;abs($:-2*$`)+abs($h-2*$')}@v=sort{w($b)<=>w($a)}@v;
map{map{/x/;$I=$`;$J=$';$r=$b->Clone();
($t=$r)->Composite(image,$i->[1],x,$I,y=>$J);
if((o(27,0,27,-1)&o(0,27,-1,27)&o(27,54,27,55)&o(54,27,55,27))==1){
$s=$t if!grep{/../;$r=$t->Clone();f(none);f(red);
!grep{p()eq"1 0 0"}@v}
map{/..$/;($_,$&.$`)}map{($_.-1,$_.55)}10,27,45;
$o=$r=$t;}$i->[1]->Rotate(degrees,90)}($_)x4}@v;
$s||=$o or exit 1;$s->Trim();$s->Write("car.png")

Використання: perl car.pl board.png tile.png. Результат зберігається в car.png. Стан виходу - 1, якщо плитку неможливо було розмістити.

Сценарій для запуску повноцінної гри. Він приймає код , вказаний вище в файлі car.plі плитки зберігаються в tilesкаталозі з іменем 01.pngв 25.png.

use List::Util shuffle;$x='00';
@t=shuffle map{($x++)x$_}split'',a4582941333353325523152111;
`cp tiles/11.png car.png`;
$i++,`perl car.pl car.png tiles/$_.png`,print"placed $i\n"for@t

Зараз це працює досить повільно. 8-12 хвилин на моїй машині. З найкращим закриттям: Віддайте перевагу прикладу закриття із закриттям уникайте (зверніть увагу, що нічого не закрито).


Здається, тест на площу закритий працює неправильно . Останнє розміщене було місто-плитка з кутом доріг (0,1).
jlahd

@jlahd Ви праві. Для тестів я змінив умову, оскільки набагато простіше не закривати регіон (також краще стратегія в реальній грі закрити їх). Але зараз я не впевнений, чи спрацьовує ця зворотна умова навіть справно. Я сьогодні це виправлю.
nutki

@jlahd Виправлено, дякую, що помітили. Зворотна умова була в порядку після BTW.
nutki

15

Common Lisp, 2650 2221 1992 1186 1111 байт

Оновлення: "Легкий" гольф зараз зроблено, подальший приріст вимагатиме великих змін.

Оновлення 2: Коли конкуренція стає все жорсткішою, нова версія більше не надає переваги позиціям у поточному прямокутнику ігрового поля (це було б додатково на 57 байт). Цей параметр, а також проста оптимізація швидкості, увімкнено за замовчуванням у завантажуваній версії з тренажером, але не в офіційній відповіді нижче.

Оновлення 3: Незначні зміни інтерфейсу для значного збільшення кількості байтів.

Я також створив простий веб-інтерфейс. Повний пакет (один файл LISP та зображення плитки) можна завантажити тут . Для того, щоб спробувати, встановити hunchentoot, zpngі png-readз quiclisp, навантаження в carcassonne.lisp, і підключитися до localhost:8080. Код був протестований на CCL / Windows та SBCL / Linux. Вищезазначені бібліотеки потрібні лише для частини інтерфейсу / симулятора; саме рішення є простим ANSI Common Lisp.

(defun c(f p &aux b a s z(c 55))
  (macrolet((d(v l &body b)`(dotimes(,v,l),@b))
            (b(b c)`(d i c(d j c(setf,b,c))))
            (r(&rest p)`(aref,@p))
            (n(u v i j)`(and(setf l(*(f,u,v)l))
                            (find(r f(+,u,i)(+,v,j))`(0,(r f,u,v))))))
    (labels((p(p w)(d y(ceiling w 2)(d x(- w y y)(rotatef(r p y #6=(+ x y))(r p #6##7=(- w y))(r p #7##8=(- w x y))(r p #8#y)))))
            (a(y x)(or(if(= 0(r f y x))1 #4=(and(= 1(incf(r s y x)))(=(r f y x)z)(push`(,y,x)a)0))0))
            (f(y x)(setf z(r f y x))(if #4#(loop for((y x))= a while(pop a)maximize(+(a(1- y)x)(a y(1- x))(a(1+ y)x)(a y(1+ x))))1)))
      (d i 8(when(d x #1=(array-dimension f 0)(or(= 0(r f(- #1#52 i)x))(return t)))(setf f(adjust-array f`(#2=,(+ #1#c)#2#))))(p f(1- #1#)))
      (d i 4(d u #9=(/ #1#c)(d v #9#
        (let((y(* u c))(x(* v c))(l 9e9))
          (when(= 0(r f y x))
            (b #10=(r f(+ y i)(+ x j))(r p i j))
            (setf s(make-array`(,#1#,#1#))a())
            (ignore-errors(if(> #11=(*(loop for d from 1 to 53
                                            sum(+(n y #3=(+ x d)-1 0)(n #5=(+ y d)(+ 54 x)0 1)(n(+ 54 y)#3#1 0)(n #5#x 0 -1)))
                                      (1+ l))
                                (or(car b)0))
                             (setf b`(,#11#,i,y,x))))
            (b #10#0)))))
         (p p 54))
      (when b(d j(cadr b)(p p 54))(b(r f(+(third b)i)(+(nth 3 b)j))(r p i j)))
      `(,f,b))))

Усі канали ліній та проміжки між лініями призначені лише для косметики, щоб забезпечити розбірливість і не зараховуються до загальної суми.

Ви повинні викликати функцію cз двома аргументами: Поточне ігрове поле та плитка для розміщення. Обидва повинні бути двовимірними масивами; плитка 55х55 і поле кратне цього. Крім того, масив поля повинен бути регульованим. Функція повертає двоелементний список з новим полем в якості першого аргументу. Другий елемент - NILякщо плитка не може бути розміщена, або в іншому випадку список містить координати вгорі ліворуч та обертання останньої плитки на цьому масиві та бал за цю плитку. Цю інформацію можна використовувати для цілей візуалізації.

Зауважте, що при подальших викликах ви повинні використовувати нове поле, повернене cнавіть у тому випадку, якщо другий елемент списку є NIL(можливо, початковий масив був adjust-arrayвідредагований і таким чином недійсний).

Код зараз трохи на повільній стороні, оптимізація підрахунку байтів призводить до надмірних обчислень. Наведений нижче приклад виконаний приблизно за три хвилини в моїй системі.

Приклад запуску для всіх 85 плиток:

введіть тут опис зображення

Скріншот веб-інтерфейсу:

введіть тут опис зображення


Віддати перевагу розташуванню розташування в межах поточного прямокутника - це гарна ідея. Я помітив, що це, як правило, змія, якщо ви скористаєтеся легким маршрутом.
BMac

не виграшний бал, але ви отримуєте винагороду за кілька приємних нововведень.
jsh

9

DarkBASIC Pro: 2078 рік 1932 1744 байт

ОНОВЛЕННЯ: Просто більше зусиль з гольфу

ОНОВЛЕННЯ: Тепер повністю відповідає специфікації, включаючи перевагу не закриваючого вибору.

Я вибрав DarkBASIC, оскільки, хоча він є досить багатослівним, він забезпечує надзвичайно простий і простий набір команд для маніпулювання зображеннями.

Я завантажив EXE для людей, які не мають компілятора DarkBASIC ( Windows ).

Вибірка зразка

#constant m memblock
#constant f function
#constant k endfunction
#constant z exitfunction
#constant i image
#constant e endif
#constant t then
#constant o or
#constant s paste image
#constant n next
#constant r for
set i colorkey 0,20,0:load i "map.png",1:f$="next.png"
if file exist(f$)=0 t f$=str$(rnd(24)+1)+".png"
load i f$,2:make m from i 1,1:make m from i 2,2
global ts,h,j,u,v,td
ts=i width(2):h=i width(1):j=i height(1):u=h/ts:v=j/ts:td=ts*2
create bitmap 2,h+td+1,j+td+1:r b=1 to 4:r xx=0 to u+1:r yy=0 to v+1:x=xx*ts-1:y=yy*ts-1
cls 5120:s 1,ts,ts,1:if (a(x+1,y) o a(x,y+1) o a(x-ts,y) o a(x,y-ts)) and a(x,y)=0
x1=ts*xx:y1=ts*yy:make i from m 2,2:s 2,x1,y1,1
cl=0:r fd=0 to 1:r x2=1 to ts-2:r yt=0 to 1:y2=yt*ts-yt:y3=yt*ts+yt-1
aa=x2:ab=x2:ba=y2:bb=y3:t2=y1:r t3=0 to 1:p=point(x1+aa,y1+ba):q=point(x1+ab,y1+bb)
if p<>q and rgbg(q)<>20 and t2+b>0 t goto fa
if fd and p<>0xFF0000
if l(x1+aa,y1+ba,p)=0 t cl=1
e
aa=y2:ba=x2:bb=x2:ab=y3:t2=x1:n t3:n yt:n x2:n fd:dn=1:c=xx-1:g=yy-1:make i from m 3,2:if cl=0 t goto dm
e
fa:
n y:n x
d=ts/2:r x=0 to d:r y=0 to d-1:vx=ts-1-x:vy=ts-1-y:t1=rd(x,y):t2=rd(vy,x):wr(vy,x,t1):t1=rd(vx,vy):wr(vx,vy,t2):t2=rd(y,vx):wr(y,vx,t1):wr(x,y,t2):n x:n y:n b
dm:
if dn=0 t report error "Not placed"
p=c<0:q=g<0:t1=h+ts*(p o c>=u):t2=j+ts*(q o g>=v):cls 5120:p=ts*p:q=ts*q:s 1,p,q,1:s 3,c*ts+p,g*ts+q,1:get i 1,0,0,t1,t2,1:save i "map.png",1
end
f l(x,y,w)
if x<0 o y<0 o x>=h+td o y>=j+td t z 1
p=point(x,y)
if rgbg(p)=20 t z 1
if p<>w t z 0
dot x,y,0xFF0000:rt=l(x+1,y,p) o l(x-1,y,p) o l(x,y+1,p) o l(x,y-1,p)
k rt
f rd(x,y)
w=m dword(2,0):b=m dword(2,12+(y*w+x)*4)
k b
f wr(x,y,d)
w=m dword(2,0):write m dword 2,12+(y*w+x)*4,d
k
f a(x,y)
if x<0 o y<0 o x>=h o y>=j t z 0
b=m byte(1,15+(y*h+x)*4)
k b
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.