(strategy mea)
(watch 0)


(literalize task
	actor)
(literalize position
	row column value identity)
(literalize opposite
	of is)
(literalize player
	with-mark is)
(literalize move
	status whose-turn input)
(vector-attribute input)



(p start
;	 generate the wm-elements defining the "board" and find out whether
;	 the human wants his mark to be x or o
	 (ready)
	-->
	 (make task ^actor referee)
	 (make position ^row 1 ^column 1 ^value | | ^identity top-left)
	 (make position ^row 1 ^column 2 ^value | | ^identity top-middle)
	 (make position ^row 1 ^column 3 ^value | | ^identity top-right)
	 (make position ^row 2 ^column 1 ^value | | ^identity middle-left)
	 (make position ^row 2 ^column 2 ^value | | ^identity center)
	 (make position ^row 2 ^column 3 ^value | | ^identity middle-right)
	 (make position ^row 3 ^column 1 ^value | | ^identity bottom-left)
	 (make position ^row 3 ^column 2 ^value | | ^identity bottom-middle)
	 (make position ^row 3 ^column 3 ^value | | ^identity bottom-right)
	 (make opposite ^of x ^is o)
	 (make opposite ^of o ^is x)
	 (write (crlf) Do you want to be x or "o?  " )
	 (make player ^with-mark (accept) ^is human) )

(make ready)

(p pop
	 ; if there is nothing more to do in the most recently generated task,
	 ; delete the task
	 (task)
	-->
	 (remove 1) )


(p referee--display-the-board
	 ; after each move, display the board
	 (task ^actor referee)
	 (move ^status made ^whose-turn <mark>)
	 (opposite ^of <mark> ^is <opponent-mark>)
	 (position ^row 1 ^column 1 ^value <l1>)
	 (position ^row 1 ^column 2 ^value <m1>)
	 (position ^row 1 ^column 3 ^value <r1>)
	 (position ^row 2 ^column 1 ^value <l2>)
	 (position ^row 2 ^column 2 ^value <m2>)
	 (position ^row 2 ^column 3 ^value <r2>)
	 (position ^row 3 ^column 1 ^value <l3>)
	 (position ^row 3 ^column 2 ^value <m3>)
	 (position ^row 3 ^column 3 ^value <r3>)
	-->
	 (modify 2 ^status unmade ^whose-turn <opponent-mark>)
	 (write (crlf) (crlf) (crlf)
		(tabto 12) <l1> (tabto 15) "|" (tabto 18) <m1>
		(tabto 21) "|" (tabto 24) <r1>
		(tabto 10) -----------------
		(tabto 12) <l2> (tabto 15) "|" (tabto 18) <m2>
		(tabto 21) "|" (tabto 24) <r2>
		(tabto 10) -----------------
		(tabto 12) <l3> (tabto 15) "|" (tabto 18) <m3>
		(tabto 21) "|" (tabto 24) <r3>) )

(p referee--prepare-for-first-move
;	 identify the mark of the computer and create the move wm-element that
;	 will drive the game
	 (task ^actor referee)
	 (player ^with-mark <mark> ^is human)
	 (opposite ^of <mark> ^is <other-mark>)
	-->
	 (write (crlf) (crlf) When you are asked where you want your |mark,|
		enter two |numbers.|
		(crlf) The first number should be the row you |want,| the
		second |number, the column.|)
	 (make player ^with-mark <other-mark> ^is computer)
	 (make move ^status unmade ^whose-turn x) )

(p referee--get-a-good-mark
;	 if the human says he wants to be something other than x or o, make
;	 him x
	 (task ^actor referee)
	 (player ^with-mark <mark> ^is human)
	 - (opposite ^of <mark>)
	-->
	 (modify 2 ^with-mark x)
	 (write (crlf) (crlf) Try to remember that |you're x.|) )

(p referee--next-move
;	 if it's time for the next move to be made, generate the appropriate
;	 subtask
	 (task ^actor referee)
	 (move ^status unmade ^whose-turn <mark>)
	 (player ^with-mark <mark> ^is <who>)
	-->
	 (make task ^actor <who>) )

(p referee--recognize-column-win
;	 if someone has filled a column, note that fact
	 (task ^actor referee)
	 (move ^status unmade ^whose-turn <mark>)
	 (opposite ^of <mark> ^is <other-mark>)
	 (player ^with-mark <other-mark>)
	 (position ^column <c> ^value <other-mark>)
	 - (position ^column <c> ^value <> <other-mark>)
	-->
	 (remove 2)
	 (make player ^with-mark <other-mark> ^is winner) )

(p referee--recognize-row-win
;	 if someone has filled a row, note that fact
	 (task ^actor referee)
	 (move ^status unmade ^whose-turn <mark>)
	 (opposite ^of <mark> ^is <other-mark>)
	 (player ^with-mark <other-mark>)
	 (position ^row <r> ^value <other-mark>)
	 - (position ^row <r> ^value <> <other-mark>)
	-->
	 (remove 2)
	 (make player ^with-mark <other-mark> ^is winner) )

(p referee--recognize-diagonal-win
;	 if someone has filled a diagonal, note that fact
	 (task ^actor referee)
	 (move ^status unmade ^whose-turn <mark>)
	 (opposite ^of <mark> ^is <other-mark>)
	 (player ^with-mark <other-mark>)
	 (position ^row 2 ^column 2 ^value <other-mark>)
	 (position ^row {<r> <> 2} ^column {<c> <> 2}
		   ^identity <id> ^value <other-mark>)
	 (position ^row <c> ^column <r>
		   ^identity <> <id> ^value <other-mark>)
	-->
	 (remove 2)
	 (make player ^with-mark <other-mark> ^is winner) )

(p referee--human-wins
;	 if the human won, let him know
	 (task ^actor referee)
	 (player ^with-mark <other-mark> ^is winner)
	 (player ^with-mark <other-mark> ^is human)
	-->
	 (write (crlf) (crlf) You |win.| (crlf) (crlf)) )

(p referee--computer-wins
;	 if the computer won, let the human know
	 (task ^actor referee)
	 (player ^with-mark <other-mark> ^is winner)
	 (player ^with-mark <other-mark> ^is computer)
	-->
	 (write (crlf) (crlf) I |win.| (crlf) (crlf)) )

(p referee--draw
;	 if there are no empty spaces, the game is a draw
	 (task ^actor referee)
	 (move ^status unmade ^whose-turn <mark>)
	 (player ^with-mark <mark>)
	 - (position ^value | |)
	-->
	 (write (crlf) (crlf) We |drew.| (crlf) (crlf))
	 (remove 2) )

(p referee--cleanup
;	 if the game is over, delete all of the wm-elements
	 (task ^actor referee)
	 - (move)
	 (<> task)
	-->
	 (remove 2) )


(p human--ask-for-next-move
	 ; get the position (row and column) where the human wants his mark
	 (task ^actor human)
	 (move ^status unmade ^input nil)
	-->
 	 (write (crlf) (crlf) Where do you want your "mark?  ")
	 (modify 2 ^input (acceptline)) )

(p human--accept-move
	 ; if the move is legal, accept it
	 ; the move wm-element is remade so that the value of ^input becomes
	 ; nil (there are 2 simpler but less educational ways of achieving
	 ; this same end)
	 (task ^actor human)
	 (move ^status unmade ^whose-turn <mark>
	       ^input {<row> >= 0 <= 3} {<column> >= 0 <= 3} nil)
	 (position ^row <row> ^column <column> ^value | |)
	-->
	 (remove 2)
	 (make move (substr 2 2 input) ^status made ^input nil)
	 (modify 3 ^value <mark>) )

(p human--reject-attempt-to-overwrite
	 ; if the position specified is not empty, complain
	 ; the move condition element in this rule differs from the move
	 ; condition in the previous rule only so you can see two equivalent
	 ; ways of expressing the same condition
	 (task ^actor human)
	 (move ^status unmade
	       ^input <row> <column> nil ^input << 1 2 3 >> << 1 2 3 >>)
	 (position ^row <row> ^column <column> ^value {<mark> <> | |})
	-->
	 (write (crlf) (crlf) There is already an <mark> in <row> <column>)
	 (modify 2 ^input nil nil) )

(p human--reject-out-of-bounds-move
	 ; if the row or column specified is not within bounds or if more than
	 ; two numbers have been entered, complain
	 ; the move wm-element is remade so that the value of ^input becomes
	 ; nil (there is a simpler but less educational way of achieving this
	 ; same end)
	 (task ^actor human)
	 (move ^status unmade ^input <> nil)
	-->
	 (write (crlf) (crlf) (substr 2 input inf) is not a legal |move.|)
	 (remove 2)
	 (make move (substr 2 2 input) ^input nil) )


(p computer--select-move
	 ; select any empty position
	 (task ^actor computer)
	 (move ^status unmade ^whose-turn <mark>)
	 - (position ^row 2 ^column 2 ^value | |)
	 (position ^row <r> ^column <c> ^value | |)
	-->
	 (modify 2 ^status made)
	 (modify 3 ^value <mark>) )

(p computer--select-center
	 ; select the center if it's available
	 (task ^actor computer)
	 (move ^status unmade ^whose-turn <mark>)
	 (position ^row 2 ^column 2 ^value | |)
	-->
	 (modify 2 ^status made)
	 (modify 3 ^value <mark>) )

(p computer--block-column-win
	 ; if the human has two in a column, block
	 (task ^actor computer)
	 (move ^status unmade ^whose-turn <mark>)
	 (position ^row <r> ^column <c>
		   ^value {<other-mark> <> <mark> <> | |})
	 (position ^column <c> ^value | |)
	 (position ^row <> <r> ^column <c> ^value <other-mark>)
	-->
	 (modify 2 ^status made)
	 (modify 4 ^value <mark>) )

(p computer--block-row-win
	 ; if the human has two in a row, block
	 (task ^actor computer)
	 (move ^status unmade ^whose-turn <mark>)
	 (position ^row <r> ^column <c>
		   ^value {<other-mark> <> <mark> <> | |})
	 (position ^row <r> ^value | |)
	 (position ^row <r> ^column <> <c> ^value <other-mark>)
	-->
	 (modify 2 ^status made)
	 (modify 4 ^value <mark>) )

(p computer--block-diagonal-win
	 ; if the human has two on a diagonal, block
	 (task ^actor computer)
	 (move ^status unmade ^whose-turn <mark>)
	 (position ^row 2 ^column 2
		   ^value {<other-mark> <> <mark> <> | |})
	 (position ^row {<r> <> 2} ^column {<c> <> 2} ^value | |)
	 (position ^row <c> ^column <r> ^value <other-mark>)
	-->
	 (modify 2 ^status made)
	 (modify 4 ^value <mark>) )

(p computer--possible-column
	 ; if the computer has one mark in an otherwise empty column, put
	 ; another mark in that column
	 (task ^actor computer)
	 (move ^status unmade ^whose-turn <mark>)
	 (position ^row <r> ^column <c> ^value <mark>)
	 - (position ^row <> <r> ^column <c> ^value <> | |)
	 (position ^row <> <r> ^column <c> ^value | |)
	-->
	 (modify 2 ^status made)
	 (modify 4 ^value <mark>) )

(p computer--possible-row
	 ; if the computer has one mark in an otherwise empty row, put
	 ; another mark in that row
	 (task ^actor computer)
	 (move ^status unmade ^whose-turn <mark>)
	 (position ^row <r> ^column <c> ^value <mark>)
	 - (position ^row <r> ^column <> <c> ^value <> | |)
	 (position ^row <r> ^column <> <c> ^value | |)
	-->
	 (modify 2 ^status made)
	 (modify 4 ^value <mark>) )
