king + rook เทียบกับ king


16

มันเป็นจุดจบของเกมหมากรุกที่เล่นได้ดีอีกเกมหนึ่ง คุณเป็นผู้เล่นผิวขาวและคุณยังมีนักเล่นเกมและราชาของคุณ ฝ่ายตรงข้ามของคุณมีเพียงกษัตริย์ของเขาที่เหลือ

เมื่อคุณเป็นคนผิวขาวมันเป็นตาของคุณ สร้างโปรแกรมเพื่อเล่นหมากรุกนี้ เอาต์พุตสามารถเป็นลำดับของการเคลื่อนไหวภาพเคลื่อนไหว gif ASCII art หรืออะไรก็ได้ที่คุณชอบ

ดูเหมือนจะค่อนข้างชัดเจน แต่ฉันจะระบุอย่างชัดเจนว่าคุณต้องชนะเกม (ในจำนวนที่ จำกัด ของการเคลื่อนไหว) เป็นไปได้เสมอที่จะชนะจากตำแหน่งนี้ อย่าเสียความเป็นไปได้ อย่าหยุดยั้ง

โปรแกรมของคุณอาจยอมรับหรือไม่ยอมรับอินพุตที่เป็นมนุษย์สำหรับตำแหน่งเริ่มต้นและสำหรับการเคลื่อนไหวแต่ละครั้งของ Black (คุณสามารถสันนิษฐานได้ว่านี่เป็นตำแหน่งทางกฎหมายเช่นกษัตริย์ไม่ได้สัมผัสกัน) หากไม่มีตำแหน่งเริ่มต้นแบบสุ่มและการเคลื่อนไหวแบบสุ่มสำหรับราชาดำจะพอเพียง

คะแนน

คะแนนของคุณจะมีความยาวเป็นไบต์ของรหัส + โบนัสของคุณ อนุญาตให้ใช้ภาษาใดก็ได้คะแนนต่ำสุดชนะ

โบนัส

-50 หากโปรแกรมของคุณอนุญาตทั้งตำแหน่งเริ่มต้นที่กำหนดโดยมนุษย์และตำแหน่งที่สุ่ม มนุษย์สามารถป้อนผ่าน stdin, ไฟล์, GUI ...

-100 ถ้าโปรแกรมของคุณอนุญาตทั้งมนุษย์และผู้เล่นสุ่มที่จะย้ายราชาดำ

+12345 ถ้าคุณพึ่งพาตัวแก้หมากรุกภายนอกหรือห้องสมุดหมากรุกในตัว

โชคดี!

Update!

กฎพิเศษ: การแข่งขันจะต้องเล่นจนกว่าจะรุกฆาต แบล็กไม่ยอมแพ้ไม่กระโดดนอกกระดานหมากรุกและไม่โดนคนต่างด้าวลักพาตัว

เปรย

คุณอาจจะได้รับความช่วยเหลือจากคำถามนี้ในchess.se


2
ใช้กฎการเลื่อน 50 ครั้งหรือไม่
Comintern

1
@Victor ฉันมีสองสามครั้ง แต่ยังไม่ได้ผล แรงเดรัจฉานช้าเกินไปอย่างเห็นได้ชัดอัลฟาเบต้าเกินไปเนื่องจากภูมิทัศน์ของการจัดอันดับตำแหน่งค่อนข้างแบน และมีแนวโน้มที่จะติดอยู่ในวง การวิเคราะห์ถอยหลังเข้าคลองจะทำงานได้ช้ามาก ความพยายามครั้งต่อไปของฉันจะใช้อัลกอริทึมของ Bratko สำหรับ KRK ซึ่งฉันหลีกเลี่ยงได้เพราะเป็นกรณีพิเศษซึ่งไม่เหมาะสำหรับการเล่นกอล์ฟ
bazzargh

1
@victor ฉันกำลังมองดูสิ่งนี้เช่นกัน สิ่งนี้น่าสนใจอย่างยิ่งเพราะง่ายต่อการกำหนดและยากที่จะทำ ในทางกลับกันโปรแกรมจะไม่สั้นดังนั้นแท็ก code-golf ทำให้มันดูยากขึ้นเป็นสองเท่า ถ้าโปรแกรมของฉันใช้งานได้คุณจะเห็นมันในไม่ช้า
เลเวลริเวอร์เซนต์

1
@Victor ปัญหาไม่ได้เกี่ยวกับการพยายามทำให้ดีที่สุดความพยายามใด ๆ ในการเลือกท่าที่ดีที่สุดโดยไม่คำนึงถึงประวัติของเกมทำให้เกิดการวนซ้ำ จำเป็นต้องทดสอบเกมยุติจากทุกตำแหน่ง Bratko + ตัวแปรไม่เหมาะสม แต่สิ้นสุดลงอย่างเหมาะสม ลองใช้การวิเคราะห์ถอยหลังเข้าคลองในขณะนี้ (เช่นสร้างตาราง endgame) ดูมีแนวโน้มและในความเป็นจริงซึ่งเป็นสิ่งที่ดี ยังเปิดออกสั้นพอสมควร
bazzargh

2
หากใครต้องการแรงบันดาลใจ (หรืออยากรู้อยากเห็น) คุณสามารถค้นหาเอ็นจิ้นหมากรุกสมบูรณ์แบบตัวละคร 1433 ตัวที่home.hccnet.nl/hgmuller/umax1_6.c
Comintern

คำตอบ:


11

Haskell 1463-100 = 1363

เพิ่งได้รับคำตอบระบบจะหาวิธีแก้ถอยหลังเข้าคลองทำงานจากรุกฆาตไปยังตำแหน่งที่เราอยู่ซึ่งแตกต่างจากคำอธิบายของการวิเคราะห์ถอยหลังเข้าคลองในการเขียนโปรแกรมหมากรุก - แทนที่จะเริ่มต้นด้วยชุดเริ่มต้นและขยายไปด้านหลัง จนกว่าจะไม่มีสี่เหลี่ยมที่ถูกย้ายไปยังไม่ได้เห็นมันจะเริ่มต้นด้วยสี่เหลี่ยมที่ไม่ได้ใช้ทั้งหมดและลดการตั้งค่านั้นโดยการลองไปข้างหน้า นี่จะประหยัดเวลาน้อยกว่าวิธีดั้งเดิม แต่การใช้หน่วยความจำระเบิดสำหรับฉันเมื่อฉันลองใช้

คอมไพล์ด้วยghc -O2เพื่อประสิทธิภาพที่ยอมรับได้สำหรับการคำนวณตาราง endgame; เล่นทันทีหลังจากย้ายครั้งแรก จัดหาราชาขาว, โกง, สแควร์คิงสีดำเป็นข้อโต้แย้ง สำหรับการย้ายมันแค่ต้องการสี่เหลี่ยมจัตุรัสและจะเลือกหนึ่งอันสำหรับคุณถ้าคุณกด return ตัวอย่างเซสชัน:

$ 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

รหัส:

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}

แก้ไข: แก้ไขรหัสเพื่อจำตาราง endgame และใช้อาร์กิวเมนต์ดังนั้นจึงเจ็บปวดน้อยกว่ามากในการทดสอบซ้ำ ๆ


2
รหัส haskell กับผลข้างเคียง? เป็นไปได้ไงที่คนนอกศาสนา! : p
Einacio

ในที่สุดก็เป็นคนที่จริงจัง!
izabera

ปริศนานั้นเป็นความชั่วร้าย @izabera!
bazzargh

ดี! ดีกว่าความพยายามของฉัน ฉันพยายามที่จะปรับปรุง El Ajedrecista ให้มากพอที่จะรับรองเพื่อนย้ายได้ 50 คน แต่เท่าที่อัลกอริธึมดำเนินไปมันก็แย่จริงๆ
Comintern

การแสดงที่น่าดึงดูดมากมายมาจากฉันที่ไม่จำตาราง endgame ( y) นี่เป็นสิ่งที่ชัดเจนมากในการย้ายครั้งที่สองที่ไม่เร็วนักเมื่อเราพิจารณาจบเกมทั้งหมดแล้ว ฉันออกไปผับในเย็นวันนี้ แต่ถ้าฉันมีโอกาสในวันพรุ่งนี้ฉันจะทำให้เรื่องนี้แย่ลง
bazzargh

7

C, ปัจจุบัน 2552 noncomment อักขระ nonwhitespace

การนับบ่งบอกถึงฉันว่าฉันสามารถตีมันลงต่ำกว่า 2552 ตัวอักษรทั้งหมด แต่เนื่องจากมีคำตอบที่เล็กกว่า (ซึ่งจะยากต่อการเอาชนะ) ฉันจะพิจารณาอย่างรอบคอบก่อนที่จะรบกวนมัน มันเป็นความจริงมีประมาณ 200 ตัวอักษรสำหรับการแสดงบอร์ดและอีก 200 ต่อการตรวจสอบการป้อนข้อมูลของผู้ใช้ทั้งตำแหน่งเริ่มต้นและการย้าย (ซึ่งฉันต้องการสำหรับการทดสอบ แต่สามารถกำจัดได้)

ไม่มีแผนผังเกมที่นี่เพียงอัลกอริธึมฮาร์ดโค้ดดังนั้นจึงเคลื่อนที่ได้ทันที

ตำแหน่งเริ่มจะถูกป้อนเป็นคอลัมน์แถว (1-8) (1-8) หมายเลขจากด้านบนขวาและโปรแกรมทำงานในรูปแบบเดียวกัน ดังนั้นหากคุณหมุนหน้าจอทวนเข็มนาฬิกาไป 90 องศามันจะเป็นไปตามสัญกรณ์หมากรุกมาตรฐานจดหมายโต้ตอบมาตรฐาน ตำแหน่งที่กษัตริย์สีดำอยู่ในเช็คได้ถูกปฏิเสธว่าผิดกฎหมาย

การเคลื่อนไหวสีดำจะถูกป้อนเป็นตัวเลขตั้งแต่ 0 ถึง 7 โดยที่ 0 เป็นการย้ายไปทางทิศเหนือ 1 ไปทางทิศตะวันออกเฉียงเหนือและตามเข็มนาฬิกา

มันไม่ได้ทำตามอัลกอริทึมที่รู้จักกันโดยทั่วไปว่าใช้ rook ภายใต้การคุ้มครองของราชาขาวเพื่อ จำกัด ราชาดำ โกงเท่านั้นที่จะ จำกัด กษัตริย์สีดำในแนวตั้ง (และจะวิ่งหนีในแนวนอนถ้าถูกล่า) กษัตริย์สีขาวจะ จำกัด กษัตริย์สีดำในการเคลื่อนไหวในแนวนอน ซึ่งหมายความว่าชิ้นส่วนสีขาวทั้งสองไม่เข้ากัน

ฉันดูเหมือนจะรีดข้อบกพร่องส่วนใหญ่และลูปที่ไม่มีที่สิ้นสุดที่เป็นไปได้มันทำงานได้ดีในตอนนี้ ฉันจะเล่นกับมันอีกครั้งในวันพรุ่งนี้และดูว่ามีอะไรที่ต้องแก้ไขไหม

#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();

}

นี่คือการเสร็จสิ้นทั่วไป (บางครั้งเพื่อนอาจเกิดขึ้นที่ใดก็ได้บนขอบด้านขวาหรือด้านซ้ายของกระดาน)

ป้อนคำอธิบายรูปภาพที่นี่


6

Bash, 18 (หรือ -32?)

โอเคนี่เป็นคำตอบที่ตลก เนื่องจาก Black เป็นผู้เล่นหมากรุกที่ดีและ Black รู้ว่า White เป็นผู้เล่นหมากรุกที่ดีเขาจึงตัดสินใจว่าสิ่งที่สมเหตุสมผลเพียงอย่างเดียวคือ:

echo Black resigns

ส่งผลให้ชนะขาวซึ่งตรงตามข้อกำหนด

ในทางเทคนิคคุณสามารถป้อนตำแหน่งปัจจุบันเป็นอาร์กิวเมนต์ได้เช่นกันโปรแกรมเพียงละเว้นมันดังนั้นเนื้อหานี้จึงมีสิทธิ์ได้รับโบนัส -50


ขำ ๆ แต่ฉันอัพเดทกฏแล้ว การเล่นจนกระทั่งรุกฆาตเป็นสิ่งจำเป็น
izabera

1
Btw คำถามเดิมระบุไว้อย่างชัดเจนว่าโปรแกรมของคุณอาจอนุญาตให้มนุษย์หรือผู้เล่นแบบสุ่มเป็นสีดำและคุณจะไม่สุ่ม
izabera

2
ใช้สัญลักษณ์มาตรฐานคุณสามารถส่งออก1-0ซึ่งสั้นกว่าเล็กน้อย
daniero

1
@Comintern ที่เกิดขึ้นจริงเมื่อการสูญเสียที่ดีที่สุดมักจะหมายถึงการออกที่ยาวที่สุด
PyRulez

@PyRulez ตามวิกิพีเดีย "ผู้เล่นทั้งสองคนอาจลาออกเมื่อใดก็ได้และคู่ต่อสู้ของพวกเขาชนะเกม" นอกจากนี้นี่เป็นเพียงคำตอบตลกไม่ได้ใช้มันอย่างจริงจัง
user12205
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.