implement Connect; ## Copyright © 2000 Vita Nuova Limited. All rights reserved.# include "sys.m"; sys: Sys;include "draw.m"; draw: Draw; Point, Rect, Image, Font, Context, Screen, Display: import draw;include "tk.m"; tk: Tk; Toplevel: import tk;include "tkclient.m"; tkclient: Tkclient;include "daytime.m"; daytime: Daytime;include "rand.m"; rand: Rand; # adtize and modularize stderr: ref Sys->FD; Connect: module { init: fn(ctxt: ref Draw->Context, argv: list of string);}; nosleep, printout, auto: int;display: ref Draw->Display; init(ctxt: ref Draw->Context, argv: list of string){ sys = load Sys Sys->PATH; draw = load Draw Draw->PATH; tk = load Tk Tk->PATH; tkclient = load Tkclient Tkclient->PATH; daytime = load Daytime Daytime->PATH; rand = load Rand Rand->PATH; argv = tl argv; while(argv != nil){ s := hd argv; if(s != nil && s[0] == '-'){ for(i := 1; i < len s; i++){ case s[i]{ 'a' => auto = 1; 'p' => printout = 1; 's' => nosleep = 1; } } } argv = tl argv; } stderr = sys->fildes(2); rand->init(daytime->now()); daytime = nil; if(ctxt == nil) fatal("wm not running"); display = ctxt.display; tkclient->init(); (win, wmcmd) := tkclient->toplevel(ctxt, "", "Connect", Tkclient->Resize | Tkclient->Hide); mainwin = win; sys->pctl(Sys->NEWPGRP, nil); cmdch := chan of string; tk->namechan(win, cmdch, "cmd"); for(i := 0; i < len win_config; i++) cmd(win, win_config[i]); pid := -1; sync := chan of int; mvch := chan of (int, int); initboard(); setimage(); spawn game(sync, mvch); pid = <- sync; tkclient->onscreen(win, nil); tkclient->startinput(win, "kbd"::"ptr"::nil); for(;;){ alt{ s := <-win.ctxt.kbd => tk->keyboard(win, s); s := <-win.ctxt.ptr => tk->pointer(win, *s); c := <-win.ctxt.ctl or c = <-win.wreq or c = <-wmcmd => case c{ "exit" => if(pid != -1) kill(pid); exit; * => e := tkclient->wmctl(win, c); if(e == nil && c[0] == '!'){ setimage(); drawboard(); } } c := <- cmdch => (nil, toks) := sys->tokenize(c, " "); case hd toks{ "b1" or "b2" or "b3" => alt{ mvch <-= (int hd tl toks, int hd tl tl toks) => ; * => ; } "bh" or "bm" or "wh" or "wm" => colour := BLACK; knd := HUMAN; if((hd toks)[0] == 'w') colour = WHITE; if((hd toks)[1] == 'm') knd = MACHINE; kind[colour] = knd; "blev" or "wlev" => colour := BLACK; e := "be"; if((hd toks)[0] == 'w'){ colour = WHITE; e = "we"; } sk := int cmd(win, ".f0." + e + " get"); if(sk > MAXPLIES) sk = MAXPLIES; if(sk >= 0) skill[colour] = sk; * => ; } <- sync => pid = -1; # exit; spawn game(sync, mvch); pid = <- sync; } }} WIDTH: con 400;HEIGHT: con 400; SZW: con 7;SZH: con 6;SZC: con 4;SZS: con 1024;PIECES: con SZW*SZH; BLACK, WHITE, EMPTY: con iota;MACHINE, HUMAN: con iota;SKILLB : con 8;SKILLW : con 0;MAXPLIES: con 10; board: array of array of int; # for displaybrd: array of array of int; # for calculationscol: array of int;pieces: array of int;val: array of int;kind: array of int;skill: array of int;name: array of string;lines: array of array of int;line: array of array of list of int; mainwin: ref Toplevel;brdimg: ref Image;brdr: Rect;brdx, brdy: int; black, white, bg: ref Image; movech: chan of (int, int); setimage(){ brdw := int tk->cmd(mainwin, ".p cget -actwidth"); brdh := int tk->cmd(mainwin, ".p cget -actheight"); brdr = Rect((0,0), (brdw, brdh)); brdimg = display.newimage(brdr, display.image.chans, 0, Draw->White); if(brdimg == nil) fatal("not enough image memory"); tk->putimage(mainwin, ".p", brdimg, nil);} game(sync: chan of int, mvch: chan of (int, int)){ sync <-= sys->pctl(0, nil); movech = mvch; initbrd(); play(); sync <-= 0;} initboard(){ i, j, k: int; board = array[SZW] of array of int; brd = array[SZW] of array of int; line = array[SZW] of array of list of int; col = array[SZW] of int; for(i = 0; i < SZW; i++){ board[i] = array[SZH] of int; brd[i] = array[SZH] of int; line[i] = array[SZH] of list of int; } pieces = array[2] of int; val = array[2] of int; kind = array[2] of int; kind[BLACK] = MACHINE; if(auto) kind[WHITE] = MACHINE; else kind[WHITE] = HUMAN; skill = array[2] of int; skill[BLACK] = SKILLB; skill[WHITE] = SKILLW; name = array[2] of string; name[BLACK] = "black"; name[WHITE] = "white"; black = display.color(Draw->Black); white = display.color(Draw->White); bg = display.color(Draw->Yellow); n := SZW*(SZH-SZC+1)+SZH*(SZW-SZC+1)+2*(SZH-SZC+1)*(SZW-SZC+1); lines = array[n] of array of int; for(i = 0; i < n; i++) lines[i] = array[2] of int; m := 0; for(i = 0; i < SZW; i++){ for(j = 0; j <= SZH-SZC; j++){ for(k = 0; k < SZC; k++){ line[i][j+k] = m :: line[i][j+k]; } m++; } } for(i = 0; i < SZH; i++){ for(j = 0; j <= SZW-SZC; j++){ for(k = 0; k < SZC; k++){ line[j+k][i] = m :: line[j+k][i]; } m++; } } for(i = 0; i <= SZW-SZC; i++){ for(j = 0; j <= SZH-SZC; j++){ for(k = 0; k < SZC; k++){ line[i+k][j+k] = m :: line[i+k][j+k]; } m++; } } for(i = 0; i <= SZW-SZC; i++){ for(j = 0; j <= SZH-SZC; j++){ for(k = 0; k < SZC; k++){ line[SZW-1-i-k][j+k] = m :: line[SZW-1-i-k][j+k]; } m++; } } if(m != n) fatal(sys->sprint("%d != %d\n", m, n)); } initbrd(){ i, j: int; for(i = 0; i < SZW; i++){ col[i] = 0; for(j = 0; j < SZH; j++) board[i][j] = brd[i][j] = EMPTY; } pieces[BLACK] = pieces[WHITE] = 0; val[BLACK] = val[WHITE] = 0; drawboard(); n := len lines; for(i = 0; i < n; i++) lines[i][0] = lines[i][1] = 0;} plays := 0;bwins := 0;wwins := 0; play(){ if(plays&1) (first, second) := (WHITE, BLACK); else (first, second) = (BLACK, WHITE); for(;;){ if(pieces[BLACK]+pieces[WHITE] == PIECES) break; m1 := move(first, second); if(printout) sys->print("%s: %d %d %d\n", name[first], m1, val[BLACK], val[WHITE]); if(win(first)) break; if(pieces[BLACK]+pieces[WHITE] == PIECES) break; m2 := move(second, first); if(printout) sys->print("%s: %d %d %d\n", name[second], m2, val[BLACK], val[WHITE]); if(win(second)) break; } if(win(BLACK)){ bwins++; puts("black wins"); highlight(BLACK); } else if(win(WHITE)){ wwins++; puts("white wins"); highlight(WHITE); } else puts("draw"); sleep(2500); plays++; puts(sys->sprint("black %d:%d white", bwins, wwins)); sleep(2500); if(printout) sys->print("\n");} move(me: int, you: int): int{ if(kind[me] == MACHINE){ puts("machine " + name[me] + " move"); return genmove(me, you); } else{ m, n: int; # mvs := findmoves(); for(;;){ puts("human " + name[me] + " move"); m = getmove(); if(m < 0 || m >= SZW) continue; n = col[m]; valid := n >= 0 && n < SZH; if(valid && brd[m][n] != EMPTY) fatal("! EMPTY"); if(valid) break; puts("illegal move"); sleep(2500); } makemove(m, n, me, you, 0); return m*SZS+n; }} genmove(me: int, you: int): int{ m, n, v: int; mvs := findmoves(); if(skill[me] == 0){ l := len mvs; r := rand->rand(l); # r = 0; while(--r >= 0) mvs = tl mvs; (m, n) = hd mvs; } else{ plies := skill[me]; left := PIECES-(pieces[BLACK]+pieces[WHITE]); if(left < plies) # limit search plies = left; else if(left < 2*plies) # expand search to end plies = left; else{ # expand search nearer end of game k := left/plies; if(k < 3) plies = ((k+2)*plies)/(k+1); } visits = leaves = 0; (v, (m, n)) = minimax(me, you, plies, ∞); if(0){ while(mvs != nil){ v0: int; (a, b) := hd mvs; makemove(a, b, me, you, 1); (v0, (m, n)) = minimax(you, me, plies-1, ∞); sys->print(" (%d, %d): %d\n", a, b, -v0); undomove(a, b, me, you); mvs = tl mvs; } sys->print("best move is %d, %d\n", m, n); kind[WHITE] = HUMAN; } if(auto) sys->print("eval = %d plies=%d goes=%d visits=%d\n", v, plies, len mvs, leaves); } makemove(m, n, me, you, 0); return m*SZS+n;} findmoves(): list of (int, int){ mvs: list of (int, int); for(i := 0; i < SZW; i++){ if((j := col[i]) < SZH) mvs = (i, j) :: mvs; } return mvs;} makemove(m: int, n: int, me: int, you: int, gen: int){ pieces[me]++; brd[m][n] = me; col[m]++; for(l := line[m][n]; l != nil; l = tl l){ i := hd l; a := lines[i][me]; b := lines[i][you]; lines[i][me]++; if(a+b >= SZC) fatal("makemove a+b"); if(b == 0){ val[me] += 2*a+1; if(a == SZC-1) val[me] += WIN; } else if(a == 0) val[you] -= b*b; } if(!gen){ board[m][n] = me; drawpiece(m, n, me); panelupdate(); # sleep(1000); }} undomove(m: int, n: int, me: int, you: int){ brd[m][n] = EMPTY; pieces[me]--; col[m]--; for(l := line[m][n]; l != nil; l = tl l){ i := hd l; a := lines[i][me]; b := lines[i][you]; lines[i][me]--; if(a == 0 || a+b > SZC) fatal("undomove a+b"); if(b == 0){ val[me] -= 2*a-1; if(a == SZC) val[me] -= WIN; } else if(a == 1) val[you] += b*b; }} win(me: int): int{ return val[me] > WIN/2;} highlight(me: int){ n := len lines; for(i := 0; i < n; i++){ if(lines[i][me] == SZC){ for(j := 0; j < SZW; j++){ for(k := 0; k < SZH; k++){ for(l := line[j][k]; l != nil; l = tl l){ if(i == hd l) highpiece(j, k, board[j][k]); } } } } }} getmove(): int{ (x, nil) := <- movech; return x/brdx;} drawboard(){ brdx = brdr.dx()/SZW; brdy = brdr.dy()/SZH;Lines 1–500 of 718. Load more
implement Connect; # # Copyright © 2000 Vita Nuova Limited. All rights reserved. # include "sys.m"; sys: Sys; include "draw.m"; draw: Draw; Point, Rect, Image, Font, Context, Screen, Display: import draw; include "tk.m"; tk: Tk; Toplevel: import tk; include "tkclient.m"; tkclient: Tkclient; include "daytime.m"; daytime: Daytime; include "rand.m"; rand: Rand; # adtize and modularize stderr: ref Sys->FD; Connect: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; nosleep, printout, auto: int; display: ref Draw->Display; init(ctxt: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; draw = load Draw Draw->PATH; tk = load Tk Tk->PATH; tkclient = load Tkclient Tkclient->PATH; daytime = load Daytime Daytime->PATH; rand = load Rand Rand->PATH; argv = tl argv; while(argv != nil){ s := hd argv; if(s != nil && s[0] == '-'){ for(i := 1; i < len s; i++){ case s[i]{ 'a' => auto = 1; 'p' => printout = 1; 's' => nosleep = 1; } } } argv = tl argv; } stderr = sys->fildes(2); rand->init(daytime->now()); daytime = nil; if(ctxt == nil) fatal("wm not running"); display = ctxt.display; tkclient->init(); (win, wmcmd) := tkclient->toplevel(ctxt, "", "Connect", Tkclient->Resize | Tkclient->Hide); mainwin = win; sys->pctl(Sys->NEWPGRP, nil); cmdch := chan of string; tk->namechan(win, cmdch, "cmd"); for(i := 0; i < len win_config; i++) cmd(win, win_config[i]); pid := -1; sync := chan of int; mvch := chan of (int, int); initboard(); setimage(); spawn game(sync, mvch); pid = <- sync; tkclient->onscreen(win, nil); tkclient->startinput(win, "kbd"::"ptr"::nil); for(;;){ alt{ s := <-win.ctxt.kbd => tk->keyboard(win, s); s := <-win.ctxt.ptr => tk->pointer(win, *s); c := <-win.ctxt.ctl or c = <-win.wreq or c = <-wmcmd => case c{ "exit" => if(pid != -1) kill(pid); exit; * => e := tkclient->wmctl(win, c); if(e == nil && c[0] == '!'){ setimage(); drawboard(); } } c := <- cmdch => (nil, toks) := sys->tokenize(c, " "); case hd toks{ "b1" or "b2" or "b3" => alt{ mvch <-= (int hd tl toks, int hd tl tl toks) => ; * => ; } "bh" or "bm" or "wh" or "wm" => colour := BLACK; knd := HUMAN; if((hd toks)[0] == 'w') colour = WHITE; if((hd toks)[1] == 'm') knd = MACHINE; kind[colour] = knd; "blev" or "wlev" => colour := BLACK; e := "be"; if((hd toks)[0] == 'w'){ colour = WHITE; e = "we"; } sk := int cmd(win, ".f0." + e + " get"); if(sk > MAXPLIES) sk = MAXPLIES; if(sk >= 0) skill[colour] = sk; * => ; } <- sync => pid = -1; # exit; spawn game(sync, mvch); pid = <- sync; } } } WIDTH: con 400; HEIGHT: con 400; SZW: con 7; SZH: con 6; SZC: con 4; SZS: con 1024; PIECES: con SZW*SZH; BLACK, WHITE, EMPTY: con iota; MACHINE, HUMAN: con iota; SKILLB : con 8; SKILLW : con 0; MAXPLIES: con 10; board: array of array of int; # for display brd: array of array of int; # for calculations col: array of int; pieces: array of int; val: array of int; kind: array of int; skill: array of int; name: array of string; lines: array of array of int; line: array of array of list of int; mainwin: ref Toplevel; brdimg: ref Image; brdr: Rect; brdx, brdy: int; black, white, bg: ref Image; movech: chan of (int, int); setimage() { brdw := int tk->cmd(mainwin, ".p cget -actwidth"); brdh := int tk->cmd(mainwin, ".p cget -actheight"); brdr = Rect((0,0), (brdw, brdh)); brdimg = display.newimage(brdr, display.image.chans, 0, Draw->White); if(brdimg == nil) fatal("not enough image memory"); tk->putimage(mainwin, ".p", brdimg, nil); } game(sync: chan of int, mvch: chan of (int, int)) { sync <-= sys->pctl(0, nil); movech = mvch; initbrd(); play(); sync <-= 0; } initboard() { i, j, k: int; board = array[SZW] of array of int; brd = array[SZW] of array of int; line = array[SZW] of array of list of int; col = array[SZW] of int; for(i = 0; i < SZW; i++){ board[i] = array[SZH] of int; brd[i] = array[SZH] of int; line[i] = array[SZH] of list of int; } pieces = array[2] of int; val = array[2] of int; kind = array[2] of int; kind[BLACK] = MACHINE; if(auto) kind[WHITE] = MACHINE; else kind[WHITE] = HUMAN; skill = array[2] of int; skill[BLACK] = SKILLB; skill[WHITE] = SKILLW; name = array[2] of string; name[BLACK] = "black"; name[WHITE] = "white"; black = display.color(Draw->Black); white = display.color(Draw->White); bg = display.color(Draw->Yellow); n := SZW*(SZH-SZC+1)+SZH*(SZW-SZC+1)+2*(SZH-SZC+1)*(SZW-SZC+1); lines = array[n] of array of int; for(i = 0; i < n; i++) lines[i] = array[2] of int; m := 0; for(i = 0; i < SZW; i++){ for(j = 0; j <= SZH-SZC; j++){ for(k = 0; k < SZC; k++){ line[i][j+k] = m :: line[i][j+k]; } m++; } } for(i = 0; i < SZH; i++){ for(j = 0; j <= SZW-SZC; j++){ for(k = 0; k < SZC; k++){ line[j+k][i] = m :: line[j+k][i]; } m++; } } for(i = 0; i <= SZW-SZC; i++){ for(j = 0; j <= SZH-SZC; j++){ for(k = 0; k < SZC; k++){ line[i+k][j+k] = m :: line[i+k][j+k]; } m++; } } for(i = 0; i <= SZW-SZC; i++){ for(j = 0; j <= SZH-SZC; j++){ for(k = 0; k < SZC; k++){ line[SZW-1-i-k][j+k] = m :: line[SZW-1-i-k][j+k]; } m++; } } if(m != n) fatal(sys->sprint("%d != %d\n", m, n)); } initbrd() { i, j: int; for(i = 0; i < SZW; i++){ col[i] = 0; for(j = 0; j < SZH; j++) board[i][j] = brd[i][j] = EMPTY; } pieces[BLACK] = pieces[WHITE] = 0; val[BLACK] = val[WHITE] = 0; drawboard(); n := len lines; for(i = 0; i < n; i++) lines[i][0] = lines[i][1] = 0; } plays := 0; bwins := 0; wwins := 0; play() { if(plays&1) (first, second) := (WHITE, BLACK); else (first, second) = (BLACK, WHITE); for(;;){ if(pieces[BLACK]+pieces[WHITE] == PIECES) break; m1 := move(first, second); if(printout) sys->print("%s: %d %d %d\n", name[first], m1, val[BLACK], val[WHITE]); if(win(first)) break; if(pieces[BLACK]+pieces[WHITE] == PIECES) break; m2 := move(second, first); if(printout) sys->print("%s: %d %d %d\n", name[second], m2, val[BLACK], val[WHITE]); if(win(second)) break; } if(win(BLACK)){ bwins++; puts("black wins"); highlight(BLACK); } else if(win(WHITE)){ wwins++; puts("white wins"); highlight(WHITE); } else puts("draw"); sleep(2500); plays++; puts(sys->sprint("black %d:%d white", bwins, wwins)); sleep(2500); if(printout) sys->print("\n"); } move(me: int, you: int): int { if(kind[me] == MACHINE){ puts("machine " + name[me] + " move"); return genmove(me, you); } else{ m, n: int; # mvs := findmoves(); for(;;){ puts("human " + name[me] + " move"); m = getmove(); if(m < 0 || m >= SZW) continue; n = col[m]; valid := n >= 0 && n < SZH; if(valid && brd[m][n] != EMPTY) fatal("! EMPTY"); if(valid) break; puts("illegal move"); sleep(2500); } makemove(m, n, me, you, 0); return m*SZS+n; } } genmove(me: int, you: int): int { m, n, v: int; mvs := findmoves(); if(skill[me] == 0){ l := len mvs; r := rand->rand(l); # r = 0; while(--r >= 0) mvs = tl mvs; (m, n) = hd mvs; } else{ plies := skill[me]; left := PIECES-(pieces[BLACK]+pieces[WHITE]); if(left < plies) # limit search plies = left; else if(left < 2*plies) # expand search to end plies = left; else{ # expand search nearer end of game k := left/plies; if(k < 3) plies = ((k+2)*plies)/(k+1); } visits = leaves = 0; (v, (m, n)) = minimax(me, you, plies, ∞); if(0){ while(mvs != nil){ v0: int; (a, b) := hd mvs; makemove(a, b, me, you, 1); (v0, (m, n)) = minimax(you, me, plies-1, ∞); sys->print(" (%d, %d): %d\n", a, b, -v0); undomove(a, b, me, you); mvs = tl mvs; } sys->print("best move is %d, %d\n", m, n); kind[WHITE] = HUMAN; } if(auto) sys->print("eval = %d plies=%d goes=%d visits=%d\n", v, plies, len mvs, leaves); } makemove(m, n, me, you, 0); return m*SZS+n; } findmoves(): list of (int, int) { mvs: list of (int, int); for(i := 0; i < SZW; i++){ if((j := col[i]) < SZH) mvs = (i, j) :: mvs; } return mvs; } makemove(m: int, n: int, me: int, you: int, gen: int) { pieces[me]++; brd[m][n] = me; col[m]++; for(l := line[m][n]; l != nil; l = tl l){ i := hd l; a := lines[i][me]; b := lines[i][you]; lines[i][me]++; if(a+b >= SZC) fatal("makemove a+b"); if(b == 0){ val[me] += 2*a+1; if(a == SZC-1) val[me] += WIN; } else if(a == 0) val[you] -= b*b; } if(!gen){ board[m][n] = me; drawpiece(m, n, me); panelupdate(); # sleep(1000); } } undomove(m: int, n: int, me: int, you: int) { brd[m][n] = EMPTY; pieces[me]--; col[m]--; for(l := line[m][n]; l != nil; l = tl l){ i := hd l; a := lines[i][me]; b := lines[i][you]; lines[i][me]--; if(a == 0 || a+b > SZC) fatal("undomove a+b"); if(b == 0){ val[me] -= 2*a-1; if(a == SZC) val[me] -= WIN; } else if(a == 1) val[you] += b*b; } } win(me: int): int { return val[me] > WIN/2; } highlight(me: int) { n := len lines; for(i := 0; i < n; i++){ if(lines[i][me] == SZC){ for(j := 0; j < SZW; j++){ for(k := 0; k < SZH; k++){ for(l := line[j][k]; l != nil; l = tl l){ if(i == hd l) highpiece(j, k, board[j][k]); } } } } } } getmove(): int { (x, nil) := <- movech; return x/brdx; } drawboard() { brdx = brdr.dx()/SZW; brdy = brdr.dy()/SZH;