放置卡尔卡松瓷砖


23

棋盘游戏

在棋盘游戏“ Carcassonne ”中,玩家通过匹配边缘来放置瓷砖,并通过创建较大的连续地形获得最高分。以下是(大致)游戏中包含的图块的类型和数量:

#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像素x 55像素
  • 磁贴将仅具有示例磁贴中当前使用的颜色。

笔记

  • 至少2次通过后,您的答案必须包含示例输出(建议更多)。
  • 这是原始棋盘游戏的局部和不准确渲染,您无需应用此处未提及的任何规则或策略。

得分

  • 您的分数是提交内容的字节数。
  • 图片数据不包含在您的分数中。
  • 最低分获胜。


玩一个完整的游戏

您可能希望编写一个使用子任务玩完整游戏的脚本,该脚本可能包括:

  • 放置从全套85中伪随机选择的图块。
  • 如果无法放置图块,则将其返回到集合中。
  • 重复此操作,直到已放置所有图块-或无法连续放置两个图块。

它不会包含在您的字节数中,也不会提高您的分数,但是我很可能会为这种答案提供赏金。


1
12、15和17之间的区别是什么?
kaine 2014年

感谢您注意到,有17个重复项。但是15个区域确实有所不同,因为它可能会封闭一个地形区域。(顺便说一句,如果仅像素的角接触,则颜色区域不是连续的)
jsh 2014年

因此,一个15和两个2s可以制作2个单独的大小为2的黑色部分。而一个12和两个2s可以制作一个3个大的黑色部分。好。
kaine 2014年

2
1.如果可以使用ms油漆填充桶工具更改区域的颜色,则该区域为连续区域。在您的示例中,将有7个连续的区域。2.听起来合理。只要您使用指定的两个图像,就可以根据需要执行此操作。3.您可以按照自己喜欢的任何方式描绘空白。透明度是一个不错的选择。您还可以使用示例图块中未包含的任何颜色。
jsh 2014年

1
@ hosch250播放区域是无限的(根据需要扩展)。在游戏中只有第一个图块的情况下,第一个图块就是整个游戏区域。
jlahd 2014年

Answers:


8

使用PerlMagick的Perl 5: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.png25.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 2014年

@jlahd你是对的。对于测试,我逆转了条件,因为不关闭区域要容易得多(在实际游戏中关闭区域也是更好的策略)。但是现在我不确定这种逆向条件是否还能正常工作。我今天将解决此问题。
2014年

@jlahd固定,感谢您的注意。相反,所有BTW都可以。
nutki 2014年

15

Common Lisp 2650 2221 1992 1186 1111字节

更新: “轻松”打高尔夫球现已完成,要取得更大的进步,就需要进行更大的改变。

更新2:随着比赛的加剧,新版本不再支持当前比赛场地矩形内的位置(这将额外增加57个字节)。默认情况下,此选项以及简单的速度优化在模拟器的可下载版本中启用,但在下面的官方答案中未启用。

更新3:较小的接口更改,以增加主要字节数。

我也创建了一个简单的Web UI。完整的软件包(单个LISP文件和切片图像)可以在此处下载。尝试一下,安装hunchentootzpngpng-read与quiclisp,负载carcassonne.lisp,并连接到localhost:8080。该代码已在CCL / Windows和SBCL / Linux上进行了测试。上面提到的库仅在UI /模拟器部分才需要;解决方案本身就是普通的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使用两个参数来调用该函数:当前的游戏场地和要放置的磁贴。两者都应该是2D数组;图块55x55,并且该字段的倍数。此外,字段数组必须是可调的。该函数返回一个包含两个元素的列表,其中新字段作为其第一个参数。第二个元素是NIL是否无法放置图块,否则是一个列表,其中包含该数组上最新图块的左上角坐标和旋转以及该图块的得分。此信息可用于可视化目的。

请注意,在以后的调用中,c即使第二个列表元素为,也必须使用返回的新字段NIL(原始数组可能已被adjust-arrayed并因此无效)。

现在,该代码有点慢,字节数优化带来了多余的计算。下面的示例在我的系统上完成了大约三分钟。

对所有85个图块运行的示例:

在此处输入图片说明

Web UI屏幕截图:

在此处输入图片说明


最好将位置放置在当前矩形内是一个好主意。我注意到,如果您选择简单的路线,这往往会令人生厌。
BMac 2014年

而不是获胜分数,但是您可以获得一些不错的创新的赏金。
jsh 2014年

9

DarkBASIC Pro:2078 1932 1744字节

更新:更多的高尔夫运动

更新:现在完全符合规范,包括更喜欢非平仓选择。

我选择DarkBASIC是因为它很冗长,但它提供了一个非常直接和简单的命令集来处理图像。

我为没有DarkBASIC编译器(Windows)的人上传了EXE 。

样品输出

#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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.