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.