vua + tân binh vs vua


16

Đó là kết thúc của một ván cờ khác cũng chơi. Bạn là người chơi trắng, và bạn vẫn có một tân binh và vua của bạn. Đối thủ của bạn chỉ còn lại vua của mình.

Vì bạn là người da trắng, đến lượt bạn. Tạo một chương trình để chơi trận đấu cờ vua này. Đầu ra của nó có thể là một chuỗi các bước di chuyển, hoạt hình gif, nghệ thuật ASCII hoặc bất cứ điều gì bạn thích.

Điều này có vẻ khá rõ ràng, nhưng tôi sẽ nói rõ điều đó: bạn phải thắng trò chơi (với số lần di chuyển hữu hạn). Luôn luôn có thể giành chiến thắng từ vị trí này. ĐỪNG MẤT ROOK ROOK. KHÔNG PHÂN TÍCH.

Chương trình của bạn có thể hoặc không thể chấp nhận đầu vào của con người cho vị trí bắt đầu và cho mỗi lần di chuyển màu đen (bạn có thể cho rằng đây là vị trí hợp pháp, tức là các vị vua không chạm vào nhau). Nếu không, một vị trí bắt đầu ngẫu nhiên và các chuyển động ngẫu nhiên cho vua đen sẽ đủ.

Ghi bàn

Điểm của bạn sẽ là độ dài tính theo byte của mã + phần thưởng của bạn. Bất kỳ ngôn ngữ nào được cho phép, điểm thấp nhất sẽ thắng.

Tặng kem

-50 nếu chương trình của bạn cho phép cả vị trí bắt đầu do con người xác định và vị trí ngẫu nhiên. Con người có thể nhập nó thông qua stdin, tập tin, GUI ...

-100 nếu chương trình của bạn cho phép cả người và người chơi ngẫu nhiên di chuyển vua đen

+12345 nếu bạn dựa vào bộ giải cờ vua bên ngoài hoặc thư viện cờ vua tích hợp

Chúc may mắn!

Cập nhật!

Quy tắc bổ sung: Trận đấu phải được chơi cho đến khi checkmate. Đen không từ chức, không nhảy ra ngoài bàn cờ và không bị người ngoài hành tinh bắt cóc.

Dấu

Bạn có thể có thể nhận được sự giúp đỡ từ câu hỏi này trên Chess.se .


2
Có quy tắc rút thăm di chuyển 50 áp dụng?
Comitern

1
@Victor Tôi đã có một vài lần đi, nhưng nó vẫn chưa thành công. Brute force rõ ràng là quá chậm, alpha-beta cũng vậy vì bối cảnh xếp hạng vị trí khá bằng phẳng; và có xu hướng bị mắc kẹt trong một vòng lặp. Phân tích ngược sẽ làm việc nhưng rất chậm lên phía trước. Nỗ lực tiếp theo của tôi sẽ sử dụng thuật toán của Bratko cho KRK, điều mà tôi đã tránh vì đó là một đống các trường hợp đặc biệt, không tuyệt vời cho golf.
bazzargh

1
@victor Tôi cũng đang xem cái này Điều này là chính xác thú vị bởi vì nó đơn giản để xác định và khó làm. Đổi lại, chương trình sẽ không ngắn, vì vậy thẻ golf-code khiến nó có vẻ khó gấp đôi. Nếu chương trình của tôi hoạt động, bạn sẽ thấy nó sớm thôi.
Cấp sông St

1
@Victor vấn đề không nằm ở việc cố gắng tối ưu, bất kỳ nỗ lực nào để chọn một nước đi 'tốt nhất' mà không xem xét lịch sử trò chơi đều dẫn đến các vòng lặp. Cần kiểm tra chấm dứt trò chơi từ mọi vị trí. Các biến thể Bratko + không tối ưu nhưng có thể chấm dứt. Thử phân tích ngược lại ngay bây giờ (ví dụ: xây dựng bảng kết thúc), có vẻ đầy hứa hẹn và thực sự tối ưu, điều này là tốt. Cũng hóa ra hợp lý ngắn.
bazzargh

2
Nếu có ai cần nguồn cảm hứng (hoặc chỉ là tò mò), bạn có thể tìm thấy một nhân vật 1433 động cơ cờ hoàn chỉnh tại home.hccnet.nl/hgmuller/umax1_6.c
Quốc tế cộng sản

Câu trả lời:


11

Haskell 1463-100 = 1363

Chỉ cần nhận được câu trả lời. Điều này tìm ra giải pháp theo cách thụt lùi, hoạt động trở lại từ người kiểm tra đến vị trí chúng ta đang ở. Nó khác với mô tả phân tích ngược về lập trình cờ vua - thay vì bắt đầu với một bộ ban đầu và mở rộng nó bằng các động tác lùi cho đến khi không có hình vuông nào được chuyển đến chưa được nhìn thấy, nó bắt đầu với tất cả các hình vuông không được sử dụng và giảm tập hợp đó bằng cách thử di chuyển về phía trước. Điều này sẽ ít hiệu quả về thời gian hơn so với cách truyền thống, nhưng việc sử dụng bộ nhớ đã bùng nổ đối với tôi khi tôi thử nó.

Biên dịch với ghc -O2hiệu suất chấp nhận được để tính toán bảng kết thúc; chơi là ngay sau khi di chuyển đầu tiên. Cung vua trắng, tân binh, vua đen vuông làm đối số. Đối với một di chuyển, nó chỉ muốn một hình vuông, và sẽ chọn một hình vuông cho bạn nếu bạn nhấn return. Phiên ví dụ:

$ time  printf "\n\n\n\n\n\n\n\n"|./rook8 e1 a1 e8
("e1","a7","e8")[d8]?
("d2","a7","d8")[c8]?
("d2","h7","c8")[b8]?
("c3","h7","b8")[a8]?
("b4","h7","a8")[b8]?
("c5","h7","b8")[a8]?
("b6","h7","a8")[b8]?
("b6","h8","b8") mate

real    0m8.885s
user    0m8.817s
sys 0m0.067s

Mã số:

import System.Environment
import qualified Data.Set as S
sp=S.partition
sf=S.fromList
fl=['a'..'h']
rk=[0..7]
lf=filter
m=map
ln=notElem
lh=head
pl=putStrLn
pa[a,b]=(lh[i|(i,x)<-zip[0..]fl,a==x],read[b]-1)
pr(r,c)=fl!!r:show(c+1)
t f(w,r,b)=(f w,f r,f b)
km(a,b)=[(c,d)|c<-[a-1..a+1],d<-[b-1..b+1],0<=c,c<=7,0<=d,d<=7]
vd (w,r,b)=b`ln`km w&&w/=r&&b/=w&&b/=r
vw p@(_,r,b)=vd p&&r`ln`km b&&(ck p||[]/=bm p)
vb p=vd p&&(not.ck)p
rm (w@(c,d),(j,k),b@(u,x))=[(w,(j,z),b)|z<-rk,z/=k,j/=c||(k<d&&z<d)||(d<k&&d<z),j/=u||(k<x&&z<x)||(x<k&&x<z)]
kw(w,r,b)=m(\q->(q,r,b))$km w
xb(w,r,_)b=(w,r,b)
wm p=lf(\q->q/=p&&vw q)$rm p++(m(t f)$rm$t f p)++kw p
bm p@(_,_,b)=lf(\q->q/=p&&vb q)$m(xb p)$km b
c1((c,d),(j,k),(u,x))=j==u&&(c/=j||(k<x&&d<k)||(k>x&&d>k))
ck p=c1 p||(c1$t f p)
mt p=ck p&&[]==bm p
h(x,y)=(7-x,y)
v=f.h.f
f(x,y)=(y,x)
n p@((c,d),_,_)|c>3=n$t h p|d>3=n$t v p|c>d=n$t f p|True=p
ap=[((c,d),(j,k),(u,x))|c<-[0..3],d<-[c..3],j<-rk,k<-rk,u<-rk,x<-rk]
fr s p=S.member(n p)s
eg p=ef(sp mt$sf$lf vw ap)(sf$lf vb ap)
ps w mv b0=sp(\r->any(fr b0)$mv r)w
ef(b0,b1)w=let(w1,w2)=ps w wm b0 in(w1,b0):(if S.null w2 then[]else ef(f$ps b1 bm w2)w2)
lu((w1,b0):xs)p=if fr w1 p then lh$lf(fr b0)$wm p else lu xs p
th(_,_,b)=b
cd tb q=do{let{p=lu tb q};putStr$show$t pr p;if mt p then do{pl" mate";return()}else do{let{b1=pr$th$lh$bm p};pl("["++b1++"]?");mv<-getLine;cd tb$xb p (pa$if""==mv then b1 else mv)}}
main=do{p1<-getArgs;let{p2=m pa p1;p=(p2!!0,p2!!1,p2!!2)};cd(eg p)p}

Đã chỉnh sửa: Đã sửa lỗi mã để nhớ bảng kết thúc và sử dụng các đối số, do đó ít đau đớn hơn để kiểm tra nhiều lần.


2
Mã haskell có tác dụng phụ? Làm thế nào bạn có thể, dị giáo! : p
Einacio

cuối cùng là một nghiêm túc!
izabera

câu đố đó thật ác @izabera!
bazzargh

Đẹp! Tốt hơn nhiều so với nỗ lực tôi đang làm việc. Tôi đã cố gắng cải thiện El Ajedrecista đủ để đảm bảo 50 người bạn di chuyển, nhưng theo như thuật toán thì điều đó thực sự tồi tệ.
Comitern

Rất nhiều hiệu suất sucky đến từ tôi không ghi nhớ bảng kết thúc ( y). Điều này thực sự rõ ràng ở chỗ bước thứ hai không nhanh khi chúng ta đã xem xét toàn bộ cuộc chiến. Tôi sẽ đến quán rượu tối nay nhưng nếu tôi có cơ hội vào ngày mai tôi sẽ làm cho điều này bớt khủng khiếp hơn.
bazzargh

7

C, Hiện tại 2552 ký tự không phải khoảng trắng

Số đếm cho tôi biết rằng tôi có thể đánh golf xuống dưới 2552 tổng số ký tự, nhưng được đưa ra đã có một câu trả lời nhỏ hơn (sẽ rất khó để đánh bại) tôi sẽ xem xét cẩn thận trước khi bận tâm làm điều đó. Đúng là có khoảng 200 ký tự để hiển thị bảng và 200 ký tự khác để kiểm tra đầu vào của người dùng về cả vị trí bắt đầu và di chuyển (mà tôi cần để thử nghiệm, nhưng có thể loại bỏ.)

Không có cây trò chơi ở đây, chỉ là thuật toán mã hóa cứng, vì vậy nó di chuyển ngay lập tức.

Các vị trí bắt đầu được nhập dưới dạng hàng (1-8) cột (1-8) được đánh số từ trên cùng bên phải và chương trình hoạt động trên cùng một sơ đồ. Vì vậy, nếu bạn xoay màn hình 90 độ ngược chiều kim đồng hồ, nó sẽ tuân theo ký hiệu hình vuông số Tương ứng tiêu chuẩn. Các vị trí mà vua đen đã kiểm tra bị từ chối là bất hợp pháp.

Di chuyển màu đen được nhập dưới dạng số từ 0 đến 7, với 0 là di chuyển về phía bắc, 1 về phía đông bắc và cứ tiếp tục theo chiều kim đồng hồ.

Nó không tuân theo thuật toán thường được biết đến mà chỉ sử dụng rook dưới sự bảo vệ của vua trắng để hạn chế vua đen. Các tân binh chỉ hạn chế vua đen theo nghĩa dọc (và sẽ chạy trốn theo chiều ngang nếu bị truy đuổi.) Vua trắng hạn chế vua đen trong chuyển động ngang. Điều này có nghĩa là hai mảnh trắng không vướng vào nhau.

Tôi dường như đã giải quyết được hầu hết các lỗi và các vòng lặp vô hạn có thể, hiện tại nó đang hoạt động khá tốt. Tôi sẽ chơi với nó một lần nữa vào ngày mai và xem nếu có gì khác cần sửa chữa.

#include "stdafx.h"
#include "stdlib.h"
#include "string.h"

int b[2], w[2], r[2], n[2],s,t,i,nomate;
int v[2][8] = { {-1,-1,0,1,1,1,0,-1}, {0,1,1,1,0,-1,-1,-1} };
int u[5] = { 0, 1, -1, 2, -2 };
char empty[82] = "        \n--------\n--------\n--------\n--------\n--------\n--------\n--------\n--------\n";
char board[82];

int distance(int p[2], int q[2]){
    return __max(abs(p[0]-q[0]),abs(p[1]-q[1]));
}

int sign(int n){
    return (n>0)-(0>n); 
}

// from parameters p for white king and q for rook, determines if rook is/will be safe
int rsafe(int p[2],int q[2]){
    return  distance(p, q)<2 | distance(q,b)>1;
}

void umove(){
    t=0;
    while (t != 100){
        printf("Enter number 0 to 7 \n");
        scanf_s("%d", &t); t %= 8;
        n[0] = b[0] + v[0][t];
        n[1] = b[1] + v[1][t];
        if (distance(w, n) < 2 | (n[0] == r[0] & (n[1]-w[1])*(r[1]-w[1])>0) 
            | ((n[1] == r[1]) & (n[0]-w[0])*(r[0]-w[0])>0) | n[0] % 9 == 0 | n[1] % 9 == 0)
            printf("illegal move");
        else{ b[0] = n[0]; b[1] = n[1]; t = 100; };
    }
}

void imove(){
    t=0;
    // mate if possible
    if (distance(b, w) == 2 & b[0] == w[0] & (b[1] == 1 | b[1] == 8) & r[0]!=w[0]){
        n[0] = r[0]; n[1] = b[1];
        if (rsafe(w, n)){
            r[1] = n[1]; 
            printf("R to %d %d mate!\n", r[0], r[1]);
            nomate=0;
            return;
        }
    }

    //avoid stalemate
    if ((b[0] == 1 | b[0] == 8) & (b[1] == 1 | b[1] == 8) & abs(b[0] - r[0]) < 2 & abs(b[0]-w[0])<2){
        r[0] = b[0]==1? 3:6;
        printf("R to %d %d \n", r[0], r[1]);
        return;
    }

    // dont let the rook be captured. 
    if(!rsafe(w,r)) 
    {
        if (w[0] == r[0]) r[1] = w[1] + sign(r[1]-w[1]);
        else r[1] = r[1]>3? 2:7;
        printf("R to %d %d \n", r[0], r[1]);
        return;
    }

    // if there's a gap between the kings and the rook, move rook towards them. we only want to do this when kings on same side of rook, and not if the black king is already on last row.
    if (abs(w[0]-r[0])>1 & abs(b[0] - r[0]) > 1 & (b[0]-r[0])*(w[0]-r[0])>0 & b[0]!=1 & b[0]!=8){
        n[0] = r[0] + sign(b[0] - r[0]); n[1] = r[1];
        if (rsafe(w, n)) r[0] = n[0]; 
        else r[1] = r[1]>3? 2:7;
        printf("R to %d %d \n", r[0], r[1]);
        return;

    }
    // if kings are far apart, or if they not on the same row (except if b 1 row from r and w 2 rows from r), move king
    if ((w[0]-r[0])!=2*(b[0]-r[0]) | abs(b[0]-w[0])>1 | distance(w,b)>2){
        for (i = 0; i<8; i++) if (v[0][i] == sign(b[0] - w[0]) & v[1][i] == sign(b[1] - w[1])) t = i;
        s = 1 - 2 * (w[0]>3 ^ w[1] > 3);
        for (i = 0; i < 5; i++){
            n[0] = w[0] + v[0][(t + s*u[i] + 8) % 8];
            n[1] = w[1] + v[1][(t + s*u[i] + 8) % 8] *(1-2*(abs(w[0]-b[0])==2));
            if (distance (n,b)>1 & distance(n, r)>0 & rsafe(n,r) & n[0]%9!=0 & n[1]%9!=0
                & !(n[0]==r[0] & (w[0]-r[0])*(b[0]-r[0])>0)) i = 5;
        }
        if (i == 6) {
            w[0] = n[0]; w[1] = n[1]; printf("K to %d %d \n", w[0], w[1]); return;
        }
    }

    //if nothing else to do, perform a waiting move with the rook. Black is forced to move his king.
    t = r[1]>3? -1:1;
    for (i = 1; i < 5; i++){
        n[0] = r[0]; n[1] = r[1] + t*i;
        if (rsafe(w, n)){ r[1] = n[1]; i=5; }
    }
    printf("R to %d %d \n", r[0], r[1]);
}

int _tmain(){

    do{ 
        t=0;
        printf("enter the row and col of the black king ");
        scanf_s("%d%d", &b[0], &b[1]);
        printf("enter the row and col of the white king ");
        scanf_s("%d%d", &w[0], &w[1]);
        printf("enter the row and col of the rook");
        scanf_s("%d%d", &r[0], &r[1]);
        for (i = 0; i < 2; i++) if (b[i]<1 | b[i]>8 | w[i]<1 | w[i]>8 | w[i]<1 | w[i]>8)t=1;
        if (distance(b,w)<2)t+=2;
        if ((b[0] == r[0] & (b[1]-w[1])*(r[1]-w[1])>0) | ((b[1] == r[1]) & (b[0]-w[0])*(r[0]-w[0])>0)) t+=4;
        printf("error code (0 if OK) %d \n",t);
    } while(t);

    nomate=1;
    while (nomate){
        imove();
        strncpy_s(board, empty, 82);
        board[b[0] * 9 + b[1] - 1] = 'B'; board[w[0] * 9 + w[1] - 1] = 'W'; board[r[0] * 9 + r[1] - 1] = 'R'; printf("%s", board);      
        if(nomate)umove();
    }
    getchar(); getchar();

}

Đây là một kết thúc điển hình (đôi khi bạn đời có thể xảy ra bất cứ nơi nào ở cạnh phải hoặc trái của bảng.)

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


6

Bash, 18 (hoặc -32?)

Được rồi, đây là một câu trả lời đùa. Vì Đen là một người chơi cờ giỏi và Đen biết rằng Trắng cũng là một người chơi cờ giỏi, anh ta quyết định rằng điều hợp lý duy nhất để làm là:

echo Black resigns

Điều này dẫn đến chiến thắng trắng, đáp ứng các đặc điểm kỹ thuật.

Về mặt kỹ thuật, bạn cũng có thể nhập các vị trí hiện tại dưới dạng đối số, chương trình chỉ cần bỏ qua chúng, vì vậy có thể cho rằng điều này có thể đủ điều kiện nhận phần thưởng -50.


Hài hước, nhưng tôi đã cập nhật các quy tắc. Chơi cho đến khi checkmate bây giờ là bắt buộc.
izabera

1
Btw câu hỏi ban đầu nêu rõ rằng chương trình của bạn có thể cho phép một người hoặc một người chơi ngẫu nhiên cho màu đen và của bạn không phải là ngẫu nhiên.
izabera

2
Sử dụng ký hiệu chuẩn, bạn có thể xuất ra 1-0ngắn hơn một chút.
daniero

1
@Comi INTERN thực tế tốt khi mất tối ưu thường có nghĩa là kéo dài lâu nhất.
PyRulez

@PyRulez theo wikipedia , "Hoặc người chơi có thể từ chức bất cứ lúc nào và đối thủ của họ thắng trò chơi." Thêm vào đó, đây chỉ là một câu trả lời đùa, đừng quá nghiêm túc.
dùng12205
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.