Marking a Win
When we have a winner, we want to draw a line. This word "win.line"
will draw a line between two points to indicate a win.
| Editor |
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 |
Simple enough, now let's test it (you should see three O's and a line through
them):
| Commander |
init place 0 place 1 place 2 win.line pos.from.index 0 pos.from.index 2 |
Have I Won?
We'll split up the win checking into two words "check.win.row" and
"check.win". This way, we can put most of the work on how the computer
determines if a row has won, and then proceed to check all the possible winning
combinations. Remember the grid earlier? A simple winning row would be through
boxes 0, 1 and 2. Let's write the code to check a row of three boxes, and
draw the line if we detect a win:
| Editor |
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 |
Notice the word "AND"? This word will return the word
"true" if (and only if) all the values specified are considered true.
For example, if a teacher asks, "did you all do your homework?" then
the answer is yes only if each and every person did his or her homework. In this
case, we determine a win if all three squares have our piece. We determine if a
square has the same game piece as "turn" using the word "grid.me".
If you want to understand how "AND" works, try the following in the
commander:
| Commander |
show AND "false "false false show AND "true "false false show AND "false "true false show AND "true "true true |
Check to see if "check.win.row" works:
| Commander |
init show :turn O place 0 place 1 place 2 show check.win.row 0 1 2 true show check.win.row 3 4 5 false show check.win.row 0 3 6 false |
You should see a line through the winning row. We'll use this word for each
winning sequence of 3 squares. In this case, we use the word "OR",
meaning, "If any of the cases are true". Type the following to
understand how "OR" differs from "AND":
| Commander |
show OR "false "false false show OR "true "false true show OR "false "true true show OR "true "true true |
Enter the definition for "check.win" using the editor:
| Editor |
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 |
And check it:
| Commander |
init show check.win false place 3 place 4 place 5 show check.win true |
If you wish, try specifying other squares using the place command.
Can I Move?
After each turn, we need to see if the current player has won or not. If they
haven't won, we need to check for a draw. We can check for a draw by seeing if
there are any "?" in the grid. If there are not, then it's a draw.
Checking for a win is easy, using the "check.win" word. If we want to
ask, "have we not won" then we can use the word "NOT" as
follows:
| Commander |
show "true true show "false false show not "true false show not "false true show AND "true (not "false) true init show check.win false show not check.win true |
Another word we'll use is "memberp" (meaning member predicate).
This is a fancy way of us to ask, "are there any words in 'grid' that are
'?' ?" If there are, it will return "true" (yes) otherwise
"false" (no).
| Editor |
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 |
Once you have written the "canmove" word, you can test it:
| Commander |
init show canmove true place 6 place 7 show canmove true place 8 show canmove false |
|