Đặt gạch Carcassonne


23

Trò chơi hội đồng quản trị

Trong trò chơi cờ " Carcassonne ", người chơi đặt các ô bằng cách ghép các cạnh của chúng và kiếm được điểm số cao nhất thông qua việc tạo ra các khu vực địa hình tiếp giáp lớn. Sau đây là (đại khái) các loại và số lượng gạch có trong trò chơi:

#01 x4 nhập mô tả hình ảnh ở đây #02 x5 nhập mô tả hình ảnh ở đây #03 x8 nhập mô tả hình ảnh ở đây #04 x2 nhập mô tả hình ảnh ở đây

#05 x9 nhập mô tả hình ảnh ở đây #06 x4 nhập mô tả hình ảnh ở đây #07 x1 nhập mô tả hình ảnh ở đây #08 x3 nhập mô tả hình ảnh ở đây

#09 x3 nhập mô tả hình ảnh ở đây #10 x3 nhập mô tả hình ảnh ở đây #11 x4 nhập mô tả hình ảnh ở đây #12 x5 nhập mô tả hình ảnh ở đây

#13 x3 nhập mô tả hình ảnh ở đây #14 x3 nhập mô tả hình ảnh ở đây #15 x2 nhập mô tả hình ảnh ở đây #16 x5 nhập mô tả hình ảnh ở đây

#17 x5 nhập mô tả hình ảnh ở đây #18 x2 nhập mô tả hình ảnh ở đây #19 x3 nhập mô tả hình ảnh ở đây #20 x1 nhập mô tả hình ảnh ở đây

#21 x5 nhập mô tả hình ảnh ở đây #22 x2 nhập mô tả hình ảnh ở đây #23 x1 nhập mô tả hình ảnh ở đây #24 x1 nhập mô tả hình ảnh ở đây

#25 x1 nhập mô tả hình ảnh ở đây

Nhiệm vụ

Bạn phải đặt một lát bằng cách khớp các cạnh, trong khi cố gắng duy trì các khu vực tiếp giáp lớn nhất có thể có của địa hình.

Vị trí

  • Gạch chỉ có thể được đặt ở một trong (tối đa 4) khoảng trống liền kề với bất kỳ gạch (hoặc gạch) hiện có nào trong khu vực chơi.
  • Gạch có thể được xoay 90, 180 hoặc 270 độ.

Khớp cạnh

  • Các cạnh của một ô được đặt phải khớp với các cạnh chạm của (tối đa 4) các ô lân cận, tức là các pixel chạm có cùng màu.

Địa hình tiếp giáp

  • "Đóng một khu vực địa hình" có nghĩa là đặt một lát sao cho không thể tiếp tục bất kỳ vùng màu tiếp giáp nào với các vị trí ô tiếp theo.
  • Nếu một vị trí thay thế là có thể, nó phải được chọn trên bất kỳ vị trí gạch nào sẽ đóng một khu vực địa hình.
  • Nếu bạn phải chọn giữa một số vị trí đóng, hãy chọn bất kỳ vị trí nào. Nếu bạn phải chọn giữa một số vị trí không đóng, hãy chọn bất kỳ vị trí nào.
  • Bỏ qua # ff00ff (các pixel góc) khi tính toán các khu vực tiếp giáp. Cũng bỏ qua các tòa nhà, tức là các khu vực màu đã được bao kín hoàn toàn trong một ô.

Đầu vào

  • Đầu vào là hai hình ảnh:

    1. Khu vui chơi.

      • Khu vực chơi ban đầu bao gồm gạch #11(một gạch đơn).
      • Khu vực chơi tăng cường được tạo như đầu ra cũng phải được hỗ trợ làm đầu vào.
    2. Các gạch được đặt.

      • Tất cả các ô mẫu phải được hỗ trợ làm đầu vào.
  • Xác định các cạnh phù hợp / địa hình tiếp giáp chỉ sử dụng dữ liệu hình ảnh này. Không mã hóa.

Đầu ra

  • Đầu ra là một hình ảnh hiển thị khu vực chơi kết quả sau khi đặt gạch.
  • Hình ảnh phải tương thích với chương trình của riêng bạn, tức là nó có thể được sử dụng làm đầu vào khu vực chơi.
  • Nếu không thể đặt lát, trả lại lỗi.

Bạn có thể cho rằng

  • Gạch luôn là 55 px x 55 px
  • Gạch sẽ chỉ bao gồm các màu hiện đang được sử dụng trong các ví dụ gạch.

Ghi chú

  • Câu trả lời của bạn phải có đầu ra ví dụ sau ít nhất 2 lần vượt qua (được khuyến khích nhiều hơn).
  • Đây là kết xuất một phần và không chính xác của trò chơi ban đầu, bạn không cần phải áp dụng bất kỳ quy tắc hoặc chiến thuật nào không được đề cập ở đây.

Ghi bàn

  • Điểm của bạn là số byte của trình của bạn.
  • Dữ liệu hình ảnh không được bao gồm trong điểm số của bạn.
  • Điểm số thấp nhất chiến thắng.


Chơi một trò chơi đầy đủ

Bạn có thể muốn viết một kịch bản sử dụng người phục tùng của mình để chơi một trò chơi đầy đủ, có thể bao gồm:

  • Đặt một ô được chọn giả ngẫu nhiên trong toàn bộ 85.
  • Trả lại gạch cho tập hợp nếu nó không thể được đặt.
  • Lặp lại cho đến khi mọi ô được đặt - hoặc cho đến khi hai ô trong một hàng không thể được đặt.

Nó sẽ không được bao gồm trong số byte của bạn hoặc cải thiện điểm số của bạn, nhưng tôi có thể sẽ cung cấp tiền thưởng cho loại câu trả lời này.


1
sự khác biệt giữa 12, 15 và 17 là gì?
kaine

cảm ơn vì đã nắm bắt điều đó, 17 là một bản sao. tuy nhiên 15 không khác nhau vì nó có khả năng đóng một khu vực địa hình. (btw, các vùng màu không liền kề nhau nếu chỉ các góc của pixel chạm vào)
jsh

Vì vậy, một 15 và 2 2 có thể tạo 2 phần màu đen riêng biệt có kích thước 2. Trong khi một phần 12 và 2 2 có thể tạo ra một phần màu đen lớn hơn 3 phần thay thế. Được.
kaine

2
1. nếu bạn có thể sử dụng công cụ xô đổ sơn ms để thay đổi màu của một khu vực thì đó là khu vực tiếp giáp. trong ví dụ của bạn sẽ có 7 khu vực tiếp giáp nhau. 2. nghe có vẻ hợp lý. miễn là bạn sử dụng hai hình ảnh như được chỉ định, bạn có thể làm điều này theo cách bạn muốn. 3. bạn có thể mô tả không gian trống theo bất kỳ cách nào bạn muốn. minh bạch là một lựa chọn tốt. bạn cũng có thể sử dụng bất kỳ màu nào không có trong các ô mẫu.
jsh

1
@ hosch250 khu vực chơi là vô hạn (mở rộng khi cần thiết). Chỉ với ô đầu tiên trong vở kịch, ô đầu tiên toàn bộ khu vực chơi.
jmusd

Câu trả lời:


8

Perl 5 với PerlMagick: 875 789 763

Tôi đã không đếm dòng bắt đầu bằng sub w, được sử dụng để sắp xếp các vị trí trên khoảng cách đến trung tâm để thích các giải pháp nhỏ gọn (hiện đang hoạt động đúng). Trong phiên bản này, việc đóng được tránh như yêu cầu nhưng tôi thấy điều ngược lại thú vị và đúng với trò chơi hơn. Để đạt được điều đó thay đổi dòng $s=$t if!grep...đến $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")

Cách sử dụng : perl car.pl board.png tile.png. Kết quả được lưu trữ trong car.png. Trạng thái thoát là 1 nếu gạch không thể được đặt.

Kịch bản để chạy một trò chơi hoàn chỉnh. Nó giả định mã trên là trong file car.plvà gạch được lưu trữ trong tilesthư mục có tên 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

Điều này chạy khá chậm bây giờ. 8-12 phút trên máy của tôi. Với đóng ưu tiên: Thích ví dụ đóng cửa Với đóng đóng tránh (lưu ý không có gì được đóng).


Các thử nghiệm gần khu vực dường như không hoạt động đúng . Ngói góc thành phố với (0,1) là cái cuối cùng được đặt.
jmusd

@jmusd Bạn nói đúng. Đối với các bài kiểm tra, tôi đã đảo ngược điều kiện vì việc đóng một khu vực sẽ dễ dàng hơn nhiều (cũng là một chiến lược tốt hơn trong trò chơi thực tế để đóng chúng). Nhưng bây giờ tôi không chắc điều kiện ngược này thậm chí có hoạt động đúng không. Tôi sẽ sửa nó ngay hôm nay.
nutki

@jlahd Đã sửa, cảm ơn vì đã chú ý. Điều kiện ngược lại là OK sau tất cả BTW.
nutki

15

Lisp thường gặp, 2650 2221 1992 1186 1111 byte

Cập nhật: Chơi golf "dễ dàng" hiện đã được thực hiện, việc tăng thêm sẽ đòi hỏi những thay đổi lớn hơn.

Cập nhật 2: Với sự cạnh tranh ngày càng khốc liệt, phiên bản mới không còn ưu tiên các vị trí bên trong hình chữ nhật của sân chơi hiện tại (đó sẽ là thêm 57 byte). Tùy chọn này, cũng như tối ưu hóa tốc độ đơn giản, được bật theo mặc định trong phiên bản có thể tải xuống với trình giả lập, nhưng không có trong câu trả lời chính thức dưới đây.

Cập nhật 3: Thay đổi giao diện nhỏ để tăng số byte chính.

Tôi đã tạo một giao diện người dùng web đơn giản là tốt. Có thể tải xuống toàn bộ gói (một tệp LISP và hình ảnh xếp hình) tại đây . Để thử nó, cài đặt hunchentoot, zpngpng-readvới quiclisp, tải carcassonne.lisp, và kết nối với localhost:8080. Mã này đã được thử nghiệm trên CCL / Windows và SBCL / Linux. Các thư viện được đề cập ở trên chỉ cần thiết cho phần UI / giả lập; bản thân giải pháp là 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))))

Tất cả các nguồn cấp dữ liệu và khoảng cách bắt đầu dòng chỉ dành cho mỹ phẩm, để đảm bảo mức độ dễ đọc và không được tính vào tổng tiền.

Bạn nên gọi hàm cvới hai đối số: Trường phát hiện tại và ô xếp để đặt. Cả hai nên là mảng 2D; gạch 55x55 và trường bội số đó. Ngoài ra, mảng trường phải được điều chỉnh. Hàm trả về danh sách hai thành phần với trường mới làm đối số đầu tiên. Yếu tố thứ hai làNIL nếu ô không thể được đặt, hoặc nếu không thì một danh sách chứa tọa độ trên cùng bên trái và xoay của ô mới nhất trên mảng đó và điểm cho ô đó. Thông tin này có thể được sử dụng cho mục đích trực quan.

Lưu ý rằng trong các cuộc gọi tiếp theo, bạn phải sử dụng trường mới được trả về cngay cả khi phần tử danh sách thứ hai là NIL(mảng ban đầu có thể đã đượcadjust-array ed và do đó bị vô hiệu).

Mã bây giờ là một chút về phía chậm, tối ưu hóa số byte dẫn đến tính toán dư thừa. Ví dụ dưới đây hoàn thành trong khoảng ba phút trên hệ thống của tôi.

Ví dụ chạy cho tất cả 85 ô:

nhập mô tả hình ảnh ở đây

Ảnh chụp màn hình giao diện người dùng web:

nhập mô tả hình ảnh ở đây


Ưu tiên vị trí trong hình chữ nhật hiện tại là một ý tưởng tốt. Tôi đã nhận thấy rằng nó có xu hướng rắn nếu bạn đi theo con đường dễ dàng.
BMac

không phải là điểm số chiến thắng, nhưng bạn nhận được tiền thưởng cho một vài đổi mới tốt đẹp.
JSH

9

DarkBASIC Pro: 2078 1932 1744 byte

CẬP NHẬT: Chỉ cần nỗ lực chơi golf nhiều hơn

CẬP NHẬT: Bây giờ đáp ứng đầy đủ thông số kỹ thuật, bao gồm cả việc lựa chọn không đóng.

Tôi đã chọn DarkBASIC vì mặc dù khá dài dòng, nó cung cấp một bộ lệnh cực kỳ đơn giản và đơn giản để thao tác với hình ảnh.

Tôi đã tải lên một EXE cho những người không có trình biên dịch DarkBASIC ( Windows ).

Sản lượng mẫu

#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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.