USING: arrays sequences kernel io prettyprint generalizations namespaces math math.parser math.order splitting combinators combinators.short-circuit ; IN: tic-tac-toe SYMBOLS: X O ; : at ( n n g -- x ) nth nth ; : draw ( grid -- grid ) dup [ . ] each ; : row ( e -- seq ) 3 swap ; : create-grid ( -- grid ) 3 [ f row ] replicate ; : outside? ( x y -- ? ) [ 0 2 between? ] both? not ; : taken? ( grid x y -- ? ) rot at f = not ; : invalid-pos? ( g x y -- ? ) { { [ 2dup outside? ] [ 3drop "Invalid pos." . t ] } { [ taken? ] [ "Occupied zone." . t ] } [ f ] } cond ; : read-tuple ( -- n n ) readln "," split [ string>number ] map first2 ; : ask ( -- n n ) "Enter a position: " write read-tuple ; : read-pos ( g -- g n n ) [ ask 3dup invalid-pos? ] [ 2drop ] while ; : update-case ( a x y g -- ) nth set-nth ; : play ( p g -- p g ) 2dup read-pos rot update-case ; : diag ( grid -- seq ) [ swap nth ] map-index ; : diags ( grid -- seq ) [ diag ] [ reverse diag ] bi 2array ; : complete? ( seq -- ? ) X row O row 2array member? ; : full? ( g -- ? ) concat f swap member? not ; : game-over? ( g -- ? ) { [ full? ] [ dup flip dup diags append append [ complete? ] any? ] } 1|| ; : game ( -- ) X create-grid ! push the initial values on the stack [ dup game-over? ] [ draw [ X = O X ? ] dip play ] until "Game over." print 2drop ;