Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- implement TicTacToe;
- 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;
- TicTacToe : module
- {
- init: fn(ctxt: ref Draw->Context, argv: list of string);
- };
- PORT : con "2000";
- WINBUT : con Hide;
- BSZ : con 20;
- BSZI : con BSZ + 2;
- EMPTY, PLAYER1, PLAYER2 : con iota;
- # board[frame][button]
- board := array[BSZI] of { * => array[BSZI] of {* => EMPTY} };
- ctxt: ref Draw->Context;
- mainwin : ref Tk->Toplevel;
- workerpid : int;
- cmd : chan of string;
- gamecmd : chan of string;
- localcmd : chan of string;
- remotecmd : chan of string;
- init(xctxt: ref Draw->Context, nil: list of string)
- {
- sys = load Sys Sys->PATH;
- if (xctxt == nil) {
- sys->fprint(sys->fildes(2), "Tic-Tac-Toe: no window context\n");
- raise "fail:bad context";
- }
- ctxt = xctxt;
- 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);
- tkclient->init();
- dialog->init();
- wmctl : chan of string;
- (mainwin, wmctl) = tkclient->toplevel(ctxt, nil, "Tic-Tac-Toe", WINBUT);
- if(mainwin == nil)
- {
- sys->fprint(sys->fildes(2), "Tic_Tac-Toe: creation of toplevel window failed\n");
- raise "fail:creation of toplevel window failed";
- }
- gamecmd = chan of string;
- cmd = chan of string;
- tk->namechan(mainwin, cmd, "cmd");
- localcmd = chan of string;
- tk->namechan(mainwin, localcmd, "pcmd");
- remotecmd = chan of string;
- display_board();
- center(mainwin);
- tkclient->onscreen(mainwin, "exact");
- tkclient->startinput(mainwin, "kbd"::"ptr"::nil);
- 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 := <- cmd =>
- case menucmd {
- "host" =>
- reset_board();
- (n, conn) := sys->announce("tcp!*!" + PORT);
- if (n < 0)
- {
- tk->cmd(mainwin,".ft.ls configure -text {Hosting of a game failed}");
- tk->cmd(mainwin, "update");
- }
- else
- {
- spawn listenthread(conn);
- tk->cmd(mainwin,".f.menu.gm entryconfigure 0 -state disabled");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 1 -state disabled");
- tk->cmd(mainwin,".ft.ls configure -text {Waiting for opponent}");
- tk->cmd(mainwin, "update");
- }
- "join" =>
- reset_board();
- address := "tcp!" + dialog->getstring(ctxt,mainwin.image, "Enter host's address") + "!" + PORT;
- (ok, conn) := sys->dial(address, "");
- if (ok < 0)
- {
- tk->cmd(mainwin,".ft.ls configure -text {Connection failed}");
- tk->cmd(mainwin, "update");
- }
- else
- {
- tk->cmd(mainwin,".f.menu.gm entryconfigure 0 -state disabled");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 1 -state disabled");
- tk->cmd(mainwin,".ft.ls configure -text {Opponent's turn}");
- tk->cmd(mainwin, "update");
- spawn workerthread(conn);
- spawn runclient(conn);
- }
- }
- }
- }
- runserver(conn : Connection)
- {
- absorb(localcmd);
- localch := localcmd;
- dummych := chan of string;
- moves := 0;
- for(;;)
- {
- alt
- {
- game := <- gamecmd =>
- case game {
- "close" =>
- tk->cmd(mainwin,".ft.ls configure -text {Opponent closed the connection}");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 0 -state normal");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 1 -state normal");
- tk->cmd(mainwin, "update");
- exit;
- }
- local := <-localch =>
- localch = dummych;
- (n, tokens) := sys->tokenize(local, " ");
- if(n >= 3)
- case hd tokens {
- "b" =>
- row := int hd tl tokens;
- column := int hd tl tl tokens;
- if(board[row][column] == EMPTY)
- {
- message := local + "\r\n";
- wdfd := sys->open(conn.dir + "/data", Sys->OWRITE);
- sys->write(wdfd, array of byte message, len array of byte message);
- board[row][column] = PLAYER1;
- moves ++;
- tk->cmd(mainwin, sys->sprint(".f%d.b%d configure -text {X}", row, column));
- if(testrows(row, column, 5, PLAYER1) == 1)
- {
- tk->cmd(mainwin,".ft.ls configure -text {You won!}");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 0 -state normal");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 1 -state normal");
- tk->cmd(mainwin, "update");
- fd := sys->open("#p/" + string workerpid +"/ctl", sys->OWRITE);
- if(fd != nil)
- sys->fprint(fd, "kill");
- exit;
- }
- tk->cmd(mainwin,".ft.ls configure -text {Opponent's turn}");
- tk->cmd(mainwin, "update");
- }
- else
- localch = localcmd;
- * =>
- localch = localcmd;
- }
- else
- localch = localcmd;
- remote := <-remotecmd =>
- (n, tokens) := sys->tokenize(remote, " ");
- if(n >= 3)
- case hd tokens {
- "b" =>
- row := int hd tl tokens;
- column := int hd tl tl tokens;
- board[row][column] = PLAYER2;
- moves ++;
- tk->cmd(mainwin, sys->sprint(".f%d.b%d configure -text {0}", row, column));
- if (testrows(row, column, 5, PLAYER2) == 1)
- {
- tk->cmd(mainwin,".ft.ls configure -text {Opponent won!}");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 0 -state normal");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 1 -state normal");
- tk->cmd(mainwin, "update");
- fd := sys->open("#p/" + string workerpid +"/ctl", sys->OWRITE);
- if(fd != nil)
- sys->fprint(fd, "kill");
- exit;
- }
- tk->cmd(mainwin,".ft.ls configure -text {Your turn}");
- tk->cmd(mainwin, "update");
- absorb(localcmd);
- localch = localcmd;
- }
- }
- if (moves >= BSZ * BSZ)
- {
- tk->cmd(mainwin,".ft.ls configure -text {Draw!}");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 0 -state normal");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 1 -state normal");
- tk->cmd(mainwin, "update");
- fd := sys->open("#p/" + string workerpid +"/ctl", sys->OWRITE);
- if(fd != nil)
- sys->fprint(fd, "kill");
- exit;
- }
- }
- }
- runclient(conn : Connection)
- {
- dummych := chan of string;
- localch := dummych;
- moves := 0;
- for(;;)
- {
- alt
- {
- game := <- gamecmd =>
- case game {
- "close" =>
- tk->cmd(mainwin,".ft.ls configure -text {Opponent closed the connection}");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 0 -state normal");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 1 -state normal");
- tk->cmd(mainwin, "update");
- exit;
- }
- local := <-localch =>
- localch = dummych;
- (n, tokens) := sys->tokenize(local, " ");
- if(n >= 3)
- case hd tokens {
- "b" =>
- row := int hd tl tokens;
- column := int hd tl tl tokens;
- if(board[row][column] == EMPTY)
- {
- message := local + "\r\n";
- sys->write(conn.dfd, array of byte message, len array of byte message);
- board[row][column] = PLAYER2;
- moves ++;
- tk->cmd(mainwin, sys->sprint(".f%d.b%d configure -text {0}", row, column));
- if(testrows(row, column, 5, PLAYER2) == 1)
- {
- tk->cmd(mainwin,".ft.ls configure -text {You won!}");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 0 -state normal");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 1 -state normal");
- tk->cmd(mainwin, "update");
- fd := sys->open("#p/" + string workerpid +"/ctl", sys->OWRITE);
- if(fd != nil)
- sys->fprint(fd, "kill");
- exit;
- }
- tk->cmd(mainwin, sys->sprint(".f%d.b%d configure -text {0}", row, column));
- tk->cmd(mainwin,".ft.ls configure -text {Opponent's turn}");
- tk->cmd(mainwin, "update");
- }
- else
- localch = localcmd;
- * =>
- localch = localcmd;
- }
- else
- localch = localcmd;
- remote := <-remotecmd =>
- (n, tokens) := sys->tokenize(remote, " ");
- if(n >= 3)
- case hd tokens {
- "b" =>
- row := int hd tl tokens;
- column := int hd tl tl tokens;
- board[row][column] = PLAYER1;
- moves ++;
- tk->cmd(mainwin, sys->sprint(".f%d.b%d configure -text {X}", row, column));
- if(testrows(row, column, 5, PLAYER1) == 1)
- {
- tk->cmd(mainwin,".ft.ls configure -text {Opponent won!}");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 0 -state normal");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 1 -state normal");
- tk->cmd(mainwin, "update");
- fd := sys->open("#p/" + string workerpid +"/ctl", sys->OWRITE);
- if(fd != nil)
- sys->fprint(fd, "kill");
- exit;
- }
- tk->cmd(mainwin, sys->sprint(".f%d.b%d configure -text {X}", row, column));
- tk->cmd(mainwin,".ft.ls configure -text {Your turn}");
- tk->cmd(mainwin, "update");
- absorb(localcmd);
- localch = localcmd;
- }
- }
- if (moves >= BSZ * BSZ)
- {
- tk->cmd(mainwin,".ft.ls configure -text {Draw!}");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 0 -state normal");
- tk->cmd(mainwin,".f.menu.gm entryconfigure 1 -state normal");
- tk->cmd(mainwin, "update");
- fd := sys->open("#p/" + string workerpid +"/ctl", sys->OWRITE);
- if(fd != nil)
- sys->fprint(fd, "kill");
- exit;
- }
- }
- }
- center(t: ref Tk->Toplevel)
- {
- org: Point;
- ir := tk->rect(t, ".", Tk->Border|Tk->Required);
- org.x = t.screenr.dx() / 2 - ir.dx() / 2;
- org.y = t.screenr.dy() / 2 - ir.dy() / 2;
- if (org.y < 0)
- {
- org.y = 0;
- }
- tk->cmd(t, ". configure -x " + string org.x + " -y " + string org.y);
- }
- display_board()
- {
- i, j: int;
- pack: string;
- tk->cmd(mainwin, "frame .f");
- tk->cmd(mainwin, "pack .f -fill x");
- tk->cmd(mainwin, "menubutton .f.menu -text Game -menu .f.menu.gm");
- tk->cmd(mainwin, "menu .f.menu.gm");
- tk->cmd(mainwin, ".f.menu.gm add command -label {host game} -command {send cmd host}");
- tk->cmd(mainwin, ".f.menu.gm add command -label {join game} -command {send cmd join}");
- tk->cmd(mainwin, "pack .f.menu -side left");
- for (i = 1; i <= BSZ; i++)
- {
- tk->cmd(mainwin, sys->sprint("frame .f%d", i));
- pack = "";
- for (j = 1; j <= BSZ; j++)
- {
- pack += sys->sprint(" .f%d.b%d", i, j);
- tk->cmd(mainwin, sys->sprint("button .f%d.b%d -text { } -width 14 -command {send pcmd b %d %d}", i, j, i, j));
- }
- tk->cmd(mainwin, sys->sprint("pack %s -side left", pack));
- tk->cmd(mainwin, sys->sprint("pack .f%d -side top -fill x", i));
- }
- tk->cmd(mainwin, "frame .ft");
- tk->cmd(mainwin, "label .ft.li -text {Status: }");
- tk->cmd(mainwin, "label .ft.ls -text {Not connected}");
- tk->cmd(mainwin, "pack .ft.li .ft.ls -side left -fill x");
- tk->cmd(mainwin, "pack .ft -side bottom -fill x");
- tk->cmd(mainwin, "update");
- }
- listenthread(conn : Connection)
- {
- (ok, c) := sys->listen(conn);
- if (ok < 0)
- {
- sys->fprint(sys->fildes(2), "Server: listen failed\n");
- raise "fail:listen failed";
- }
- tk->cmd(mainwin,".ft.ls configure -text {Your turn}");
- tk->cmd(mainwin, "update");
- spawn runserver(c);
- spawn workerthread(c);
- }
- workerthread(conn : Connection)
- {
- 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")
- {
- remotecmd <- = output[:len output - 2];
- output = "";
- }
- }
- }
- gamecmd <- = "close";
- }
- absorb(ch : chan of string)
- {
- for(;;)
- {
- alt
- {
- <- ch =>
- ;
- * =>
- return;
- }
- }
- }
- length(row, column, drow, dcolumn, item: int): int
- {
- l := 0;
- while(board[row][column] == item)
- {
- row += drow;
- column += dcolumn;
- l++;
- }
- return l;
- }
- testrows(row, column, items, item: int) : int
- {
- horizontal := (length(row, column, 0, -1, item) + length(row, column, 0, 1, item) - 1);
- if(horizontal >= items)
- {
- mark_board(row, column, 0, -1, item);
- mark_board(row, column, 0, 1, item);
- return 1;
- }
- vertical := (length(row, column, -1, 0, item) + length(row, column, 1, 0, item) - 1);
- if(vertical >= items)
- {
- mark_board(row, column, -1, 0, item);
- mark_board(row, column, 1, 0, item);
- return 1;
- }
- dir1 := (length(row, column, -1, -1, item) + length(row, column, 1, 1, item) - 1);
- if(dir1 >= items)
- {
- mark_board(row, column, -1, -1, item);
- mark_board(row, column, 1, 1, item);
- return 1;
- }
- dir2 := (length(row, column, -1, 1, item) + length(row, column, 1, -1, item) - 1);
- if(dir2 >= items)
- {
- mark_board(row, column, -1, 1, item);
- mark_board(row, column, 1, -1, item);
- return 1;
- }
- return 0;
- }
- mark_board(row, column, drow, dcolumn, item : int)
- {
- while(board[row][column] == item)
- {
- tk->cmd(mainwin, sys->sprint(".f%d.b%d configure -bg olive -activebackground olive", row, column));
- row += drow;
- column += dcolumn;
- }
- }
- reset_board()
- {
- for (i := 0; i < BSZI; i++)
- for (j := 0; j < BSZI; j++)
- board[i][j] = EMPTY;
- for (i = 1; i <= BSZ; i++)
- for (j = 1; j <= BSZ; j++)
- tk->cmd(mainwin, sys->sprint(".f%d.b%d configure -text { } -bg #dddddd -activebackground #eeeeee", i, j));
- tk->cmd(mainwin, "update");
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement