Infernal Chess on kahden pelattava verkkopelitoteutus shakista Infernolle Limbo-ohjelmointikielellä.
Lataa koodipaketti grafiikkatiedostoineen täältä
Lisään tarvittaessa kommentteja, jos löytyy aiheesta kiinnostuneita.
# # Infernal Chess v. 0.1 # # Just another shitty game by jalski # # Send comments and insults to: jali.heinonen@gmail.com # # Written in a hurry, so it may not be that great yet... # But it's free... # So, stop whining about it... # implement Chess; include "sys.m"; sys: Sys; Dir: import sys; Connection : import Sys; include "draw.m"; draw: Draw; Screen, Display, Image, Context, Point, Rect: import draw; include "tk.m"; tk: Tk; Toplevel: import tk; include "tkclient.m"; tkclient: Tkclient; Hide: import tkclient; include "dialog.m"; dialog : Dialog; Chess : module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; PORT : con "2000"; WINBUT : con Hide; BSZ : con 8; BSZI : con BSZ + 2; TILEX : con 45; TILEY : con 45; EMPTY2, PLAYER1, PLAYER2 : con iota; WHITE : con 1; BLACK : con -1; EMPTY, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING, BORDER : con iota; # board[row][column] chessboard := array [BSZI] of { array [BSZI] of { BORDER, BORDER, BORDER, BORDER , BORDER, BORDER, BORDER , BORDER , BORDER, BORDER }, array [BSZI] of { BORDER, ROOK , KNIGHT, BISHOP , KING , QUEEN , BISHOP , KNIGHT , ROOK , BORDER }, array [BSZI] of { BORDER, PAWN , PAWN , PAWN , PAWN , PAWN , PAWN , PAWN , PAWN , BORDER }, array [BSZI] of { BORDER, EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , BORDER }, array [BSZI] of { BORDER, EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , BORDER }, array [BSZI] of { BORDER, EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , BORDER }, array [BSZI] of { BORDER, EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , EMPTY , BORDER }, array [BSZI] of { BORDER, -PAWN , -PAWN , -PAWN , -PAWN , -PAWN , -PAWN , -PAWN , -PAWN , BORDER }, array [BSZI] of { BORDER, -ROOK , -KNIGHT, -BISHOP, -KING , -QUEEN, -BISHOP, -KNIGHT, -ROOK , BORDER }, array [BSZI] of { BORDER, BORDER, BORDER, BORDER , BORDER, BORDER, BORDER , BORDER , BORDER, BORDER } }; ctxt: ref Draw->Context; mainwin : ref Tk->Toplevel; display : ref Display; buffer : ref Image; board_img : ref Image; colour := array [10] of ref Image; mark1, mark1m : ref Image; mark2, mark2m : ref Image; wpawn, wpawnm : ref Image; wknight, wknightm : ref Image; wking, wkingm : ref Image; wqueen, wqueenm : ref Image; wrook, wrookm : ref Image; wbishop, wbishopm : ref Image; bking, bkingm : ref Image; bqueen, bqueenm : ref Image; bbishop, bbishopm : ref Image; brook, brookm : ref Image; bpawn, bpawnm : ref Image; bknight, bknightm : ref Image; workerpid : int; cmdch : chan of string; gamecmdch : chan of string; localcmdch : chan of string; remotecmdch : chan of string; lambda := 1; init(xctxt: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; if(len argv != 2) { sys->fprint(sys->fildes(2), "usage: %s nickname\n", hd argv); raise "fail:bad usage"; } if (len hd tl argv > 12) { sys->fprint(sys->fildes(2), "error: nickname: %s too long, must be 12 characters max.\n", hd tl argv); raise "fail:nickname too long"; } if (xctxt == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: no window context\n"); raise "fail:bad context"; } ctxt = xctxt; display = ctxt.display; draw = load Draw Draw->PATH; tk = load Tk Tk->PATH; tkclient = load Tkclient Tkclient->PATH; dialog = load Dialog Dialog->PATH; sys->pctl(Sys->NEWPGRP, nil); board := array[BSZI] of { * => array[BSZI] of {* => EMPTY} }; init_board(board); tkclient->init(); dialog->init(); wmctl : chan of string; (mainwin, wmctl) = tkclient->toplevel(ctxt, nil, "Infernal Chess v. 0.1", WINBUT); if(mainwin == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: creation of toplevel window failed\n"); raise "fail:creation of toplevel window failed"; } gamecmdch = chan of string; cmdch = chan of string; tk->namechan(mainwin, cmdch, "cmd"); localcmdch = chan of string; tk->namechan(mainwin, localcmdch, "pcmd"); remotecmdch = chan of string; center(mainwin); tkclient->onscreen(mainwin, "exact"); tkclient->startinput(mainwin, "kbd"::"ptr"::nil); load_images(); display_board(); for(;;) alt { s := <- mainwin.ctxt.kbd => tk->keyboard(mainwin, s); s := <- mainwin.ctxt.ptr => tk->pointer(mainwin, *s); s := <- mainwin.ctxt.ctl or s = <- mainwin.wreq or s = <- wmctl => case s { "exit" => fd := sys->open("#p/" + string workerpid +"/ctl", sys->OWRITE); if(fd != nil) sys->fprint(fd, "kill"); tkclient->wmctl(mainwin, "exit"); * => tkclient->wmctl(mainwin, s); } menucmd := <- cmdch => case menucmd { "host" => (n, conn) := sys->announce("tcp!*!" + PORT); if (n < 0) { cmd(mainwin,".ft.ls configure -text {Hosting of a game failed}"); cmd(mainwin, "update"); } else { spawn listenthread(conn, board, hd tl argv); cmd(mainwin,".f.menu.gm entryconfigure 0 -state disabled"); cmd(mainwin,".f.menu.gm entryconfigure 1 -state disabled"); cmd(mainwin, ".p1name configure -text " + hd tl argv); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, WHITE); cmd(mainwin,".ft.ls configure -text {Waiting for black player}"); cmd(mainwin, ".p dirty;update"); } "join" => address := "tcp!" + dialog->getstring(ctxt,mainwin.image, "Enter host's address") + "!" + PORT; (ok, conn) := sys->dial(address, ""); if (ok < 0) { cmd(mainwin,".ft.ls configure -text {Connection failed}"); cmd(mainwin, "update"); } else { cmd(mainwin,".f.menu.gm entryconfigure 0 -state disabled"); cmd(mainwin,".f.menu.gm entryconfigure 1 -state disabled"); cmd(mainwin, ".p2name configure -text " + hd tl argv); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, BLACK); cmd(mainwin,".ft.ls configure -text {White player's turn. (OPPONENT)}"); cmd(mainwin, ".p dirty; update"); spawn workerthread(conn, BLACK); spawn runclient(conn, board); message := sys->sprint("NICK %s\r\n", hd tl argv); sys->write(conn.dfd, array of byte message, len array of byte message); } } } } runserver(conn : Connection, board : array of array of int) { dummych := chan of string; absorb(localcmdch); localch := localcmdch; a, b, c, d : Point; moves : list of Point; piece1 := EMPTY; piece2 := EMPTY; selected := 0; wklcf := 0; wkscf := 0; for(;;) alt { game := <- gamecmdch => case game { "close" => init_board(board); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, WHITE); cmd(mainwin,".ft.ls configure -text {Black player closed the connection}"); cmd(mainwin,".f.menu.gm entryconfigure 0 -state normal"); cmd(mainwin,".f.menu.gm entryconfigure 1 -state normal"); cmd(mainwin, ".p dirty;update"); lambda = 1; exit; } local := <- localch => localch = dummych; (nil, tokens) := sys->tokenize(local, " "); case hd tokens { "M" => if (selected == 0) { bx := int hd tl tokens / TILEX; by := int hd tl tl tokens / TILEY; p := Point(8 - bx, 8 - by); pt := Point(9, 9); if (lambda * board [p.y][p.x] > 0) { selected = 1; a = p; piece1 = board[a.y][a.x]; buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_mark(pt.sub(p), mark2, mark2m); m1 := movelist(p, board); # en passant if (piece1 == PAWN && a.y == 5) { if (c.y == 7 && d.y == 5 && d.x == a.x - 1 && board[a.y + 1][a.x - 1] == EMPTY && board [d.y][d.x] == -PAWN) m1 = Point(a.x - 1, a.y + 1) :: m1; else if (c.y == 7 && d.y == 5 && d.x == a.x + 1 && board[a.y + 1][a.x + 1] == EMPTY && board [d.y][d.x] == -PAWN) m1 = Point(a.x + 1, a.y + 1) :: m1; } else if (piece1 == KING && (wklcf == 0 || wkscf == 0) && in_check(board) == 0) { if (wklcf == 0) if (board [1][7] == EMPTY && board [1][6] == EMPTY && board [1][5] == EMPTY && board [1][8] == ROOK) { board [1][4] = EMPTY; board [1][6] = KING; if (in_check(board) == 0) m1 = a.add(Point(2, 0)) :: m1; board [1][6] = EMPTY; board [1][4] = KING; } if (wkscf == 0) if (board [1][2] == EMPTY && board [1][3] == EMPTY && board [1][1] == ROOK) { board [1][4] = EMPTY; board [1][2] = KING; if (in_check(board) == 0) m1 = a.sub(Point(2, 0)) :: m1; board [1][2] = EMPTY; board [1][4] = KING; } } m2 : list of Point; while (m1 != nil) { piece2 = board[(hd m1).y][(hd m1).x]; (board [a.y][a.x], board[(hd m1).y][(hd m1).x]) = (EMPTY, piece1); if (in_check(board) == 0) m2 = hd m1 :: m2; (board [a.y][a.x], board[(hd m1).y][(hd m1).x]) = (piece1, piece2); m1 = tl m1; } moves = m2; while (m2 != nil) { draw_mark(pt.sub(hd m2), mark1, mark1m); m2 = tl m2; } draw_pieces(board, WHITE); cmd(mainwin, ".p dirty; update"); localch = localcmdch; } else localch = localcmdch; } else if (selected == 1) { bx := int hd tl tokens / TILEX; by := int hd tl tl tokens / TILEY; p := Point(8 - bx, 8 - by); pt := Point(9, 9); if ( p.x == a.x && p.y == a.y) { selected = 0; buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, WHITE); cmd(mainwin, ".p dirty; update"); localch = localcmdch; break; } movelist := moves; while (moves != nil) { if ((hd moves).x == p.x && (hd moves).y == p.y) { # en passant and promotion if (piece1 == PAWN) { if (p.x == a.x - 1 || p.x == a.x + 1 && board [p.y][p.x] == EMPTY) board [d.y][d.x] = EMPTY; else if (p.y == 8) piece1 = QUEEN; } else if (piece1 == KING) { if (p.x == a.x - 2) { board [1][1] = EMPTY; board [1][3] = ROOK; } else if (p.x == a.x + 2) { board [1][8] = EMPTY; board [1][5] = ROOK; } wklcf = 1; wkscf = 1; } else if (piece1 == ROOK) { if (a.x == 1 && a.y == 1 && wklcf == 0) wklcf = 1; else if (a.x == 1 && a.y == 8 && wkscf == 0) wkscf = 1; } b = p; board[b.y][b.x] = piece1; board[a.y][a.x] = EMPTY; message := sys->sprint("M %d %d %d %d\r\n", a.x, a.y, b.x, b.y); wdfd := sys->open(conn.dir + "/data", Sys->OWRITE); sys->write(wdfd, array of byte message, len array of byte message); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, WHITE); draw_arrow(pt.sub(a), pt.sub(b)); cmd(mainwin, ".p dirty; update"); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, WHITE); sys->sleep(1000); cmd(mainwin, ".ft.ls configure -text {Black player's turn. (OPPONENT)}"); cmd(mainwin, ".p dirty; update"); selected = 0; (c, d) = (a, b); lambda = -lambda; if (in_check(board)) { cmd(mainwin, ".ft.ls configure -text {Check!}"); if (is_mate(board)) { cmd(mainwin, ".ft.ls configure -text {Check mate! White player won!}"); fd := sys->open("#p/" + string workerpid +"/ctl", sys->OWRITE); if(fd != nil) sys->fprint(fd, "kill"); cmd(mainwin, "update"); exit; } cmd(mainwin, "update"); } break; } moves = tl moves; } if (moves == nil) { moves = movelist; localch = localcmdch; } else localch = dummych; } * => localch = dummych; } remote := <-remotecmdch => (n, tokens) := sys->tokenize(remote, " "); if(n >= 5) case hd tokens { "M" => a.x = int hd tl tokens; a.y = int hd tl tl tokens; b.x = int hd tl tl tl tokens; b.y = int hd tl tl tl tl tokens; pt := Point(9, 9); piece1 = board[a.y][a.x]; if (piece1 == -PAWN && b.y == 1) piece1 = -QUEEN; # en passant else if (piece1 == -PAWN && a.y == 4) { if (c.y == 2 && d.y == 4 && d.x == a.x - 1 && board [d.y][d.x] == PAWN) board[d.y][d.x] = EMPTY; else if (c.y == 2 && d.y == 4 && d.x == a.x + 1 && board [d.y][d.x] == PAWN) board[d.y][d.x] = EMPTY;; } else if (piece1 == -KING && a.x == 4 && b.x == 2) (board[8][1], board[8][3]) = (EMPTY, -ROOK); else if (piece1 == -KING && a.x == 4 && b.x == 6) (board[8][8], board[8][5]) = (EMPTY, -ROOK); (board[a.y][a.x], board[b.y][b.x]) = (EMPTY, piece1); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, WHITE); draw_arrow(pt.sub(a), pt.sub(b)); cmd(mainwin, ".p dirty; update"); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, WHITE); sys->sleep(1000); cmd(mainwin,".ft.ls configure -text {White player's turn. (YOU)}"); cmd(mainwin, ".p dirty; update"); (c, d) = (a, b); lambda = -lambda; if (in_check(board)) { cmd(mainwin, ".ft.ls configure -text {Check!}"); if (is_mate(board)) { cmd(mainwin, ".ft.ls configure -text {Check mate! Black player won!}"); fd := sys->open("#p/" + string workerpid +"/ctl", sys->OWRITE); if(fd != nil) sys->fprint(fd, "kill"); cmd(mainwin, "update"); exit; } cmd(mainwin, "update"); } absorb(localcmdch); localch = localcmdch; } } } runclient(conn : Connection, board : array of array of int) { dummych := chan of string; localch := dummych; a, b, c, d : Point; moves : list of Point; piece1 := EMPTY; piece2 := EMPTY; selected := 0; bklcf := 0; bkscf := 0; for(;;) alt { game := <- gamecmdch => case game { "close" => init_board(board); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, BLACK); cmd(mainwin,".ft.ls configure -text {White player closed the connection}"); cmd(mainwin,".f.menu.gm entryconfigure 0 -state normal"); cmd(mainwin,".f.menu.gm entryconfigure 1 -state normal"); cmd(mainwin, ".p dirty;update"); lambda = 1; exit; } local := <- localch => localch = dummych; (nil, tokens) := sys->tokenize(local, " "); case hd tokens { "M" => if (selected == 0) { bx := int hd tl tokens / TILEX + 1; by := int hd tl tl tokens / TILEY + 1; p := Point(bx, by); if (lambda * board [p.y][p.x] > 0) { selected = 1; a = p; piece1 = board[p.y][p.x]; buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_mark(p, mark2, mark2m); m1 := movelist(p, board); # en passant if (piece1 == -PAWN && a.y == 4) { if (c.y == 2 && d.y == 4 && d.x == a.x - 1 && board[a.y - 1][a.x - 1] == EMPTY && board [d.y][d.x] == PAWN) m1 = Point(a.x - 1, a.y - 1) :: m1; else if (c.y == 2 && d.y == 4 && d.x == a.x + 1 && board[a.y - 1][a.x + 1] == EMPTY && board [d.y][d.x] == PAWN) m1 = Point(a.x + 1, a.y - 1) :: m1; } else if (piece1 == -KING && (bklcf == 0 || bkscf == 0) && in_check(board) == 0) { if (bklcf == 0) if (board [8][7] == EMPTY && board [8][6] == EMPTY && board [8][5] == EMPTY && board [8][8] == -ROOK) { board [8][4] = EMPTY; board [8][6] = -KING; if (in_check(board) == 0) m1 = a.add(Point(2, 0)) :: m1; board [8][6] = EMPTY; board [8][4] = -KING; } if (bkscf == 0) if (board [8][2] == EMPTY && board [8][3] == EMPTY && board [8][1] == -ROOK) { board [8][4] = EMPTY; board [8][2] = -KING; if (in_check(board) == 0) m1 = a.sub(Point(2, 0)) :: m1; board [8][2] = EMPTY; board [8][4] = -KING; } } m2 : list of Point; while (m1 != nil) { piece2 = board[(hd m1).y][(hd m1).x]; (board [p.y][p.x], board[(hd m1).y][(hd m1).x]) = (EMPTY, piece1); if (in_check(board) == 0) m2 = hd m1 :: m2; (board [p.y][p.x], board[(hd m1).y][(hd m1).x]) = (piece1, piece2); m1 = tl m1; } moves = m2; while (m2 != nil) { draw_mark(hd m2, mark1, mark1m); m2 = tl m2; } draw_pieces(board, BLACK); cmd(mainwin, ".p dirty; update"); localch = localcmdch; } else localch = localcmdch; } else if (selected == 1) { bx := int hd tl tokens / TILEX + 1; by := int hd tl tl tokens / TILEY + 1; p := Point(bx, by); if ( p.x == a.x && p.y == a.y) { selected = 0; buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, BLACK); cmd(mainwin, ".p dirty; update"); localch = localcmdch; break; } movelist := moves; while (moves != nil) { if ((hd moves).x == p.x && (hd moves).y == p.y) { # en passant and promotion if (piece1 == -PAWN) { if (p.x == a.x - 1 || p.x == a.x + 1 && board [p.y][p.x] == EMPTY) board [d.y][d.x] = EMPTY; else if (p.y == 1) piece1 = -QUEEN; } else if (piece1 == -KING) { if (p.x == a.x - 2) { board [8][1] = EMPTY; board [8][3] = -ROOK; } else if (p.x == a.x + 2) { board [8][8] = EMPTY; board [8][5] = -ROOK; } bklcf = 1; bkscf = 1; } else if (piece1 == -ROOK) { if (a.x == 1 && a.y == 8 && bklcf == 0) bklcf = 1; if (a.x == 8 && a.y == 8 && bkscf == 0) bkscf = 1; } b = p; board[b.y][b.x] = piece1; board[a.y][a.x] = EMPTY; message := sys->sprint("M %d %d %d %d\r\n", a.x, a.y, b.x, b.y); sys->write(conn.dfd, array of byte message, len array of byte message); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, BLACK); draw_arrow(a, b); cmd(mainwin, ".p dirty; update"); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, BLACK); sys->sleep(1000); cmd(mainwin, ".ft.ls configure -text {White player's turn. (OPPONENT)}"); cmd(mainwin, ".p dirty; update"); selected = 0; (c, d) = (a, b); lambda = -lambda; if (in_check(board)) { cmd(mainwin, ".ft.ls configure -text {Check!}"); if (is_mate(board)) { cmd(mainwin, ".ft.ls configure -text {Check mate! Black player won!}"); fd := sys->open("#p/" + string workerpid +"/ctl", sys->OWRITE); if(fd != nil) sys->fprint(fd, "kill"); cmd(mainwin, "update"); exit; } cmd(mainwin, "update"); } break; } moves = tl moves; } if (moves == nil) { localch = localcmdch; moves = movelist; } else localch = dummych; } * => localch = dummych; } remote := <-remotecmdch => (n, tokens) := sys->tokenize(remote, " "); if(n >= 5) case hd tokens { "M" => a.x = int hd tl tokens; a.y = int hd tl tl tokens; b.x = int hd tl tl tl tokens; b.y = int hd tl tl tl tl tokens; piece1 = board[a.y][a.x]; if (piece1 == PAWN && b.y == 8) piece1 = QUEEN; # en passant else if (piece1 == PAWN && a.y == 5) { if (c.y == 7 && d.y == 5 && d.x == a.x - 1 && board[d.y][d.x] == -PAWN) board[d.y][d.x] = EMPTY; else if (c.y == 7 && d.y == 5 && d.x == a.x + 1 && board[d.y][d.x] == -PAWN) board[d.y][d.x] = EMPTY; } else if (piece1 == KING && a.x == 4 && b.x == 2) (board[1][1], board[1][3]) = (EMPTY, ROOK); else if (piece1 == KING && a.x == 4 && b.x == 6) (board[1][8], board[1][5]) = (EMPTY, ROOK); (board[a.y][a.x], board[b.y][b.x]) = (EMPTY, piece1); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, BLACK); draw_arrow(a, b); cmd(mainwin, ".p dirty; update"); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); draw_pieces(board, BLACK); sys->sleep(1000); cmd(mainwin, ".ft.ls configure -text {Black player's turn. (YOU)}"); cmd(mainwin, ".p dirty; update"); (c, d) = (a, b); lambda = -lambda; if (in_check(board)) { cmd(mainwin, ".ft.ls configure -text {Check!}"); if (is_mate(board)) { cmd(mainwin, ".ft.ls configure -text {Check mate! White player won!}"); fd := sys->open("#p/" + string workerpid +"/ctl", sys->OWRITE); if(fd != nil) sys->fprint(fd, "kill"); cmd(mainwin, "update"); exit; } cmd(mainwin, "update"); } absorb(localcmdch); localch = localcmdch; } } } center(t: ref Tk->Toplevel) { org: Point; ir := tk->rect(t, ".", Tk->Border|Tk->Required); org.x = t.screenr.dx() / 2 - BSZ * TILEX / 2; org.y = (t.screenr.dy() / 2) - (ir.dy() + (BSZ * TILEY) / 2); if (org.y < 0) org.y = 0; tk->cmd(t, ". configure -x " + string org.x + " -y " + string org.y); } draw_mark(p : Point, img : ref Image, mask : ref Image) { p.x = (p.x - 1) * TILEX; p.y = (p.y - 1) * TILEY; buffer.draw(img.r.addpt(p), img, mask, Point(0, 0)); } draw_arrow(p1, p2 : Point) { p1.x = p1.x * TILEX - TILEX / 2; p1.y = p1.y * TILEY - TILEY / 2; p2.x = p2.x * TILEX - TILEX / 2; p2.y = p2.y * TILEY - TILEY / 2; buffer.line(p1, p2, Draw->Endsquare, Draw->Endarrow, 3, colour[2], Point(0,0)); } draw_pieces(board : array of array of int, player : int) { p := Point(0, 0); if (player == WHITE) { for (j := 8; j >= 1; j --) { for (i := 8; i >= 1; i --) { case board [j][i] { PAWN => buffer.draw(wpawn.r.addpt(p), wpawn, wpawnm, Point(0, 0)); KNIGHT => buffer.draw(wknight.r.addpt(p), wknight, wknightm, Point(0, 0)); KING => buffer.draw(wking.r.addpt(p), wking, wkingm, Point(0, 0)); QUEEN => buffer.draw(wqueen.r.addpt(p), wqueen, wqueenm, Point(0, 0)); ROOK => buffer.draw(wrook.r.addpt(p), wrook, wrookm, Point(0, 0)); BISHOP => buffer.draw(wbishop.r.addpt(p), wbishop, wbishopm, Point(0, 0)); -KING => buffer.draw(bking.r.addpt(p), bking, bkingm, Point(0, 0)); -QUEEN => buffer.draw(bqueen.r.addpt(p), bqueen, bqueenm, Point(0, 0)); -ROOK => buffer.draw(brook.r.addpt(p), brook, brookm, Point(0, 0)); -KNIGHT => buffer.draw(bknight.r.addpt(p), bknight, bknightm, Point(0, 0)); -BISHOP => buffer.draw(bbishop.r.addpt(p), bbishop, bbishopm, Point(0, 0)); -PAWN => buffer.draw(bpawn.r.addpt(p), bpawn, bpawnm, Point(0, 0)); } p.x += TILEX; } p.x = 0; p.y += TILEY; } } else { for (j := 1; j <= BSZ; j ++) { for (i := 1; i <= BSZ; i ++) { case board [j][i] { PAWN => buffer.draw(wpawn.r.addpt(p), wpawn, wpawnm, Point(0, 0)); KNIGHT => buffer.draw(wknight.r.addpt(p), wknight, wknightm, Point(0, 0)); KING => buffer.draw(wking.r.addpt(p), wking, wkingm, Point(0, 0)); QUEEN => buffer.draw(wqueen.r.addpt(p), wqueen, wqueenm, Point(0, 0)); ROOK => buffer.draw(wrook.r.addpt(p), wrook, wrookm, Point(0, 0)); BISHOP => buffer.draw(wbishop.r.addpt(p), wbishop, wbishopm, Point(0, 0)); -KING => buffer.draw(bking.r.addpt(p), bking, bkingm, Point(0, 0)); -QUEEN => buffer.draw(bqueen.r.addpt(p), bqueen, bqueenm, Point(0, 0)); -ROOK => buffer.draw(brook.r.addpt(p), brook, brookm, Point(0, 0)); -KNIGHT => buffer.draw(bknight.r.addpt(p), bknight, bknightm, Point(0, 0)); -BISHOP => buffer.draw(bbishop.r.addpt(p), bbishop, bbishopm, Point(0, 0)); -PAWN => buffer.draw(bpawn.r.addpt(p), bpawn, bpawnm, Point(0, 0)); } p.x += TILEX; } p.x = 0; p.y += TILEY; } } } display_board() { cmd(mainwin, "frame .f -bd 1 -relief raised"); cmd(mainwin, "menubutton .f.menu -text Game -menu .f.menu.gm"); cmd(mainwin, "menu .f.menu.gm"); cmd(mainwin, ".f.menu.gm add command -label {host game (White)} -command {send cmd host}"); cmd(mainwin, ".f.menu.gm add command -label {join game (Black)} -command {send cmd join}"); cmd(mainwin, "pack .f.menu -side left"); cmd(mainwin, "pack .f -fill x"); cmd(mainwin, "frame .fpinfo -bd 1 -relief flat"); cmd(mainwin, "label .p1 -background white -text ' "); cmd(mainwin, "label .p1name -foreground black"); cmd(mainwin, "label .p2 -background black -text ' "); cmd(mainwin, "label .p2name -foreground black"); cmd(mainwin, "pack .p1 .p1name -in .fpinfo -side left"); cmd(mainwin, "pack .p2 .p2name -in .fpinfo -side right"); cmd(mainwin, "pack .fpinfo -fill x"); cmd(mainwin, "panel .p -bd 3 -relief flat"); cmd(mainwin, "pack .p -fill both -expand 1"); buffer.draw(board_img.r, board_img, nil, Point(0, 0)); cmd(mainwin, "frame .ft"); cmd(mainwin, "label .ft.li -text {Status: }"); cmd(mainwin, "label .ft.ls -text {Not connected}"); cmd(mainwin, "pack .ft.li .ft.ls -side left -fill x"); cmd(mainwin, "pack .ft -side bottom -fill x"); cmd(mainwin, "bind .p <ButtonRelease> {send pcmd M %x %y}"); tk->putimage(mainwin, ".p", buffer, nil); cmd(mainwin, ".p dirty; update"); } is_mate(board : array of array of int) : int { piece1 := EMPTY; piece2 := EMPTY; for (j := 1 ; j <= BSZ; j ++) for (i := 1; i <= BSZ; i ++) if (lambda * board [j][i] > 0) { moves := movelist(Point(i, j), board); while (moves != nil) { piece1 = board [j][i]; piece2 = board[(hd moves).y][(hd moves).x]; (board [j][i], board[(hd moves).y][(hd moves).x]) = (EMPTY, piece1); if (in_check(board) == 0) { (board [j][i], board[(hd moves).y][(hd moves).x]) = (piece1, piece2); return 0; } (board [j][i], board[(hd moves).y][(hd moves).x]) = (piece1, piece2); moves = tl moves; } } return 1; } in_check(board : array of array of int) : int { moves : list of Point; for (j := 1 ; j <= BSZ; j ++) for (i := 1; i <= BSZ; i ++) { if (lambda * board [j][i] < 0) { lambda = -lambda; moves = movelist(Point(i, j), board); lambda = -lambda; while (moves != nil) { if (lambda * board [(hd moves).y][(hd moves).x] == KING) return 1; moves = tl moves; } } } return 0; } movelist(p : Point, board : array of array of int) : list of Point { piece := lambda * board[p.y][p.x]; case piece { PAWN => return pawn(p, board); ROOK => return rook(p, board); BISHOP => return bishop(p, board); KNIGHT => return knight(p, board); QUEEN => return queen(p, board); KING => return king(p, board); * => return nil; } } king(p : Point, board : array of array of int) : list of Point { up := Point(0, -1); down := Point(0, 1); left := Point(-1, 0); right := Point(1, 0); upleft := Point(-1, -1); upright := Point(1, -1); downleft := Point(-1, 1); downright := Point(1, 1); m : list of Point; pos := p.add(up); if (lambda * board[pos.y][pos.x] <= EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(down); if (lambda * board[pos.y][pos.x] <= EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(left); if (lambda * board[pos.y][pos.x] <= EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(right); if (lambda * board[pos.y][pos.x] <= EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(upleft); if (lambda * board[pos.y][pos.x] <= EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(upright); if (lambda * board[pos.y][pos.x] <= EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(downleft); if (lambda * board[pos.y][pos.x] <= EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(downright); if (lambda * board[pos.y][pos.x] <= EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; return m; } rook(p : Point, board : array of array of int) : list of Point { up := Point(0, -1); down := Point(0, 1); left := Point(-1, 0); right := Point(1, 0); m : list of Point; pos := p.add(down); while (board[pos.y][pos.x] == EMPTY) { m = pos :: m; pos = pos.add(down); } if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(up); while (board[pos.y][pos.x] == EMPTY) { m = pos :: m; pos = pos.add(up); } if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(right); while (board[pos.y][pos.x] == EMPTY) { m = pos :: m; pos = pos.add(right); } if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(left); while (board[pos.y][pos.x] == EMPTY) { m = pos :: m; pos = pos.add(left); } if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; return m; } bishop(p : Point, board : array of array of int) : list of Point { upleft := Point(-1, -1); upright := Point(1, -1); downleft := Point(-1, 1); downright := Point(1, 1); m : list of Point; pos := p.add(downright); while (board[pos.y][pos.x] == EMPTY) { m = pos :: m; pos = pos.add(downright); } if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(upleft); while (board[pos.y][pos.x] == EMPTY) { m = pos :: m; pos = pos.add(upleft); } if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(upright); while (board[pos.y][pos.x] == EMPTY) { m = pos :: m; pos = pos.add(upright); } if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(downleft); while (board[pos.y][pos.x] == EMPTY) { m = pos :: m; pos = pos.add(downleft); } if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; return m; } queen(p : Point, board : array of array of int) : list of Point { m1 := bishop(p, board); m2 := rook(p, board); while(m2 != nil) { m1 = hd m2 :: m1; m2 = tl m2; } return m1; } knight(p : Point, board : array of array of int) : list of Point { twouponeleft := Point(-1, -2); twouponeright := Point(1, -2); twodownoneleft := Point(-1, 2); twodownoneright := Point(1, 2); twoleftonedown := Point(-2, 1); twoleftoneup := Point(-2, -1); tworightonedown := Point(2, 1); tworightoneup := Point(2, -1); m : list of Point; pos : Point; if (p.y >= 3) { pos = p.add(twouponeleft); if (lambda * board[pos.y][pos.x] <= EMPTY) m = pos :: m; pos = p.add(twouponeright); if (lambda * board[pos.y][pos.x] <= EMPTY) m = pos :: m; } if (p.y <= 6) { pos = p.add(twodownoneleft); if (lambda * board[pos.y][pos.x] <= EMPTY) m = pos :: m; pos = p.add(twodownoneright); if (lambda * board[pos.y][pos.x] <= EMPTY) m = pos :: m; } if (p.x >= 3) { pos = p.add(twoleftoneup); if (lambda * board[pos.y][pos.x] <= EMPTY) m = pos :: m; pos = p.add(twoleftonedown); if (lambda * board[pos.y][pos.x] <= EMPTY) m = pos :: m; } if (p.x <= 6) { pos = p.add(tworightoneup); if (lambda * board[pos.y][pos.x] <= EMPTY) m = pos :: m; pos = p.add(tworightonedown); if (lambda * board[pos.y][pos.x] <= EMPTY) m = pos :: m; } return m; } pawn(p : Point, board : array of array of int) : list of Point { twoup := Point(0, -2); twodown := Point(0, 2); up := Point(0, -1); down := Point(0, 1); upright := Point(1, -1); upleft := Point(-1, -1); downright := Point(1, 1); downleft := Point(-1, 1); m : list of Point; pos : Point; case lambda { WHITE => pos = p.add(down); if (lambda * board[pos.y][pos.x] == EMPTY) { m = pos :: m; if (p.y == 2) { pos = p.add(twodown); if (lambda * board[pos.y][pos.x] == EMPTY) m = pos :: m; } } pos = p.add(downright); if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(downleft); if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; BLACK => pos = p.add(up); if (lambda * board[pos.y][pos.x] == EMPTY) { m = pos :: m; if (p.y == 7) { pos = p.add(twoup); if (lambda * board[pos.y][pos.x] == EMPTY) m = pos :: m; } } pos = p.add(upright); if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; pos = p.add(upleft); if (lambda * board[pos.y][pos.x] < EMPTY && board[pos.y][pos.x] != BORDER) m = pos :: m; } return m; } load_images() { r := Rect((0, 0), (BSZ * TILEX, BSZ * TILEY)); buffer = display.newimage(r, mainwin.image.chans, 0, Draw->Black); if (buffer == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } #colour [0] = display.white; #colour [1] = display.black; colour [0] = display.color(Draw->Greygreen); colour [1] = display.color(Draw->Palegreygreen); colour [2] = display.color(Draw->Red); colour [3] = display.color(Draw->Magenta); colour [4] = display.color(Draw->Paleyellow); colour [5] = display.color(Draw->Yellowgreen); colour [6] = display.color(Draw->Paleyellow); colour [7] = display.color(Draw->Grey); colour [8] = display.color(Draw->Greyblue); colour [9] = display.color(Draw->Palegreyblue); board_img = display.newimage(r, mainwin.image.chans, 0, Draw->Black); if (board_img == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } tiler := Rect((0,0), (TILEX, TILEY)); yscol := 0; col := 0; p := Point(0, 0); for (j := 1; j <= BSZ; j ++) { yscol ^= 1; col = yscol; for (i := 1; i <= BSZ; i ++) { board_img.draw(tiler.addpt(p), colour[col], nil, Point(0, 0)); p.x += TILEX; col ^= 1; } p.x = 0; p.y += TILEY; } mark1 = display.open("./data/mark1.bit"); if (mark1 == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } mark1m = display.open("./data/mark1m.bit"); if (mark1m == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } mark2 = display.open("./data/mark2.bit"); if (mark2 == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } mark2m = display.open("./data/mark2m.bit"); if (mark2m == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wpawn = display.open("./data/wpawn.bit"); if (wpawn == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wpawnm = display.open("./data/wpawnm.bit"); if (wpawnm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wknight = display.open("./data/wknight.bit"); if (wknight == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wknightm = display.open("./data/wknightm.bit"); if (wknightm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wking = display.open("./data/wking.bit"); if (wking == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wkingm = display.open("./data/wkingm.bit"); if (wkingm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wqueen = display.open("./data/wqueen.bit"); if (wqueen == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wqueenm = display.open("./data/wqueenm.bit"); if (wqueenm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wrook = display.open("./data/wrook.bit"); if (wrook == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wrookm = display.open("./data/wrookm.bit"); if (wrookm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wbishop = display.open("./data/wbishop.bit"); if (wbishop == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } wbishopm = display.open("./data/wbishopm.bit"); if (wbishopm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } bking = display.open("./data/bking.bit"); if (bking == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } bkingm = display.open("./data/bkingm.bit"); if (bkingm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } bqueen = display.open("./data/bqueen.bit"); if (bking == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } bqueenm = display.open("./data/bqueenm.bit"); if (bqueenm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } brook = display.open("./data/brook.bit"); if (brook == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } brookm = display.open("./data/brookm.bit"); if (brookm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } bknight = display.open("./data/bknight.bit"); if (bknight == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } bknightm = display.open("./data/bknightm.bit"); if (bknightm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } bbishop = display.open("./data/bbishop.bit"); if (bbishop == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } bbishopm = display.open("./data/bbishopm.bit"); if (bbishopm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } bpawn = display.open("./data/bpawn.bit"); if (bpawn == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } bpawnm = display.open("./data/bpawnm.bit"); if (bpawnm == nil) { sys->fprint(sys->fildes(2), "Infernal Chess: failed to allocate image\n"); exit; } } listenthread(conn : Connection, board : array of array of int, nick : string) { (ok, c) := sys->listen(conn); if (ok < 0) { sys->fprint(sys->fildes(2), "Server: listen failed\n"); raise "fail:listen failed"; } spawn workerthread(c, WHITE); spawn runserver(c, board); wdfd := sys->open(c.dir + "/data", Sys->OWRITE); message := sys->sprint("NICK %s\r\n", nick); sys->write(wdfd, array of byte message, len array of byte message); cmd(mainwin,".ft.ls configure -text {White player's turn. (YOU)}"); cmd(mainwin, "update"); } workerthread(conn : Connection, player : int) { workerpid = sys->pctl(0, nil); buf := array [1] of byte; rdfd := sys->open(conn.dir + "/data", Sys->OREAD); output := ""; while( (n := sys->read(rdfd, buf, len buf ) ) > 0 ) { output[len output] = int buf[0]; if(len output >= 2) { if(output[len output - 2:] == "\r\n") { if(len output > 7 && output[:5] == "NICK ") { (count, nil) := sys->tokenize(output[5:], " "); if(count == 1 && len output[5:len output - 2] < 10) { if (player == WHITE) cmd(mainwin, ".p2name configure -text " + output[5:len output - 2]); else cmd(mainwin, ".p1name configure -text " + output[5:len output - 2]); cmd(mainwin, "update"); output = ""; } } else { remotecmdch <- = output[:len output - 2]; output = ""; } } } if (len output >= 1024) # line getting a little too long? output = ""; } gamecmdch <- = "close"; } absorb(ch : chan of string) { for(;;) { alt { <- ch => ; * => return; } } } init_board(board : array of array of int) { for (i := 0; i < BSZI; i++) for (j := 0; j < BSZI; j++) board[i][j] = chessboard[i][j]; } cmd(win: ref Tk->Toplevel, s: string): string { r := tk->cmd(win, s); if (len r > 0 && r[0] == '!') { sys->print("error executing '%s': %s\n", s, r[1:]); } return r; }
Aihe on jo aika vanha, joten et voi enää vastata siihen.