to aaa ; ; tictactoe ; ; type "tictactoe" or "go" to start ; ; plays until either nobody can move ; or there's a winner ; end to draw.grid ; ; draw the tic-tac-toe screen ; setsc [255 255 255] setpc [0 0 0] setpensize [5 5] ht pu cs seth 0 setpos [-50 -150] pd fd 300 pu setpos [50 -150] pd fd 300 pu seth 90 setpos [-150 -50] pd fd 300 pu setpos [-150 50] pd fd 300 pu end to pos.from.index :i ; ; get x,y position from index ; local [x y] make "x ((remainder :i 3)-1)*100 make "y ((int :i/3)-1)*100 output (list :x :y) end to O :ind ; ; place O piece ; setpc [0 255 0] setpensize [3 3] pu setpos pos.from.index :ind pd circle 30 pu end to X :ind ; ; draw X piece ; local [pos x y] make "pos pos.from.index :ind make "x item 1 :pos make "y item 2 :pos setpc [255 0 0] setpensize [3 3] pu setpos (LIST :x-30 :y-30) pd setpos (LIST :x+30 :y+30) pu setpos (LIST :x-30 :y+30) pd setpos (LIST :x+30 :y-30) pu end to init ; ; initialization - create a grid of 9 entries (0-8) ; representing bottom-left to to-right ; ie ; 6 | 7 | 8 ; --+---+--- ; 3 | 4 | 5 ; --+---+--- ; 0 | 1 | 2 ; ; initialize them all to "? (empty) ; ; draw the empty grid ; make "grid (array 9 0) make "turn "O ; this must be capital letter O for [i 0 8 1] [setitem :i :grid "?] draw.grid end to grid.get :i ; ; output the grid item "X "O "? ; output item :i :grid end to grid.put :i :c ; ; sets the grid item to :c ; setitem :i :grid :c end to grid.empty :i ; ; output "true if specified position in grid is empty ; output (grid.get :i) = "? end to grid.me :i ; ; output "true if the grid item is current player ; output (grid.get :i) = :turn end to grid.other :i ; ; output "true if the grid item is opponent ; output not (OR grid.empty :i grid.me :i) end to flip ; ; change player ; these must be capital O and capital X ; ifelse (:turn = "O) [make "turn "X] [make "turn "O] end to place :i ; ; place current piece and mark it in grid ; grid.put :i :turn run (list :turn :i) end to win.line :f :t ; ; draw a line through winning pieces ; setpensize [1 1] setpc [0 0 0] pu setpos :f pd setpos :t pu end to check.win.row :a :b :c ; ; output "true if ; row is a winning row ; and draw a line through it (from :a to :c) ; localmake "win (AND grid.me :a grid.me :b grid.me :c) if :win [win.line pos.from.index :a pos.from.index :c] output :win end to check.win ; ; output "true if ; current player has any row's ; output (OR check.win.row 0 1 2 check.win.row 3 4 5 check.win.row 6 7 8 check.win.row 0 3 6 check.win.row 1 4 7 check.win.row 2 5 8 check.win.row 0 4 8 check.win.row 6 4 2) end to canmove ; ; output "true if ; 1) there are any spare slots, and ; 2) current player hasn't won ; output (AND (memberp "? :grid) (not check.win)) end to mousepressed ; ; hard stuff, look to see which grid item mouse is over, ; when it was pressed ; localmake "curpos mousepos localmake "x item 1 :curpos localmake "y item 2 :curpos localmake "suggest -1 if (AND :x>-150 :x<-50 :y>-150 :y<-50) [make "suggest 0] if (AND :x>-50 :x<50 :y>-150 :y<-50) [make "suggest 1] if (AND :x>50 :x<150 :y>-150 :y<-50) [make "suggest 2] if (AND :x>-150 :x<-50 :y>-50 :y<50) [make "suggest 3] if (AND :x>-50 :x<50 :y>-50 :y<50) [make "suggest 4] if (AND :x>50 :x<150 :y>-50 :y<50) [make "suggest 5] if (AND :x>-150 :x<-50 :y>50 :y<150) [make "suggest 6] if (AND :x>-50 :x<50 :y>50 :y<150) [make "suggest 7] if (AND :x>50 :x<150 :y>50 :y<150) [make "suggest 8] if (not :suggest<0) [ ; ; we don't want to do the test if :suggest is –1 ; so we do this in the part of if that only gets ; executed when :suggest is >= 0. ; if (grid.empty :suggest) [ make "selection :suggest ] ] end to yourturn ; ; don't need to understand this more than "it works" ; waits until the mouse is pressed that selects a valid ; empty position ; make "selection -1 mouseon [mousepressed] [] [] [] [] while [:selection < 0] [wait 1] mouseoff place :selection end to tictactoe2 ; ; play tic tac toe (two player) ; we flip first to counteract the flip in the loop ; init flip do.while [flip yourturn] [canmove] end to logoturn.random ; ; put a piece at random, must not be a piece already there ; localmake "sel 0 do.while [make "sel (random 9)] [not grid.empty :sel] place :sel end to l.or :lst ; ; list-or ; l.or [[cmd] [cmd] [cmd] ... ] ; execute each command in turn until the first cmd returns ; true ; ; returns "true if any returned "true, else returns "false ; localmake "flg "false foreach :lst [if (not :flg) [make "flg run ?]] output :flg end to logoturn.win.row :a :b :c ; ; winning row is if two pieces are down, ; and the third place is empty ; ; runresult ["true] will result in [true] ; first [true] will result in true ; first runresult ["true] will result in true ; We do this, since logo didn't like [(place :c) "true] ; directly in the command parts of ifelse. ; output l.or [ [ifelse (AND grid.me :a grid.me :b grid.empty :c) [first runresult [(place :c) "true]] ["false] ] [ifelse (AND grid.me :a grid.empty :b grid.me :c) [first runresult [(place :b) "true]] ["false] ] [ifelse (AND grid.empty :a grid.me :b grid.me :c) [first runresult [(place :a) "true]] ["false] ] ] end to logoturn.win ; ; if we're about to win, put the winning piece down ; output l.or [ [logoturn.win.row 0 1 2] [logoturn.win.row 3 4 5] [logoturn.win.row 6 7 8] [logoturn.win.row 0 3 6] [logoturn.win.row 1 4 7] [logoturn.win.row 2 5 8] [logoturn.win.row 0 4 8] [logoturn.win.row 2 4 6] ] end to logoturn.block.row :a :b :c ; ; like logoturn.win.row ; but checking for opponents pieces ; output l.or [ [ifelse (AND grid.other :a grid.other :b grid.empty :c) [first runresult [(place :c) "true]] ["false] ] [ifelse (AND grid.other :a grid.empty :b grid.other :c) [first runresult [(place :b) "true]] ["false] ] [ifelse (AND grid.empty :a grid.other :b grid.other :c) [first runresult [(place :a) "true]] ["false] ] ] end to logoturn.block ; ; if the other player is about to win, block them ; output l.or [ [logoturn.block.row 0 1 2] [logoturn.block.row 3 4 5] [logoturn.block.row 6 7 8] [logoturn.block.row 0 3 6] [logoturn.block.row 1 4 7] [logoturn.block.row 2 5 8] [logoturn.block.row 0 4 8] [logoturn.block.row 2 4 6] ] end to logoturn ; ; processes computers turn ; if not l.or [ ; ; add to this to make computer more clever ; logoturn.win logoturn.block ] [ ; ; if we didn't do anything clever, put a piece at random ; logoturn.random ] end to nextmove ; ; determine if next move is human or computer ; let that player move ; ifelse (equalp :turn "O) [yourturn] [logoturn] end to tictactoe ; ; play tic tac toe ; we flip first, as flip is the first thing we do in loop ; init flip do.while [flip nextmove] [canmove] end to go ; ; alternative word to tictactoe ; tictactoe end