\input mftmac
$\9tttn.mf\par
$\2{if}\1{not}\1{known}\\{screen\_topleft}\?:$\par
\quad$\2{message}\7"screen_topleft undefined, (-50,screen_rows-100) used";$\par
\quad$\2{pair}\\{screen\_topleft};\ \\{screen\_topleft}:=(-50,\\{screen%
\_rows}-100);$\par
$\!\3{fi};$\par
$\\{currenttransform}:=\\{identity}\6{shifted}(20+\1{xpart}\\{screen%
\_topleft},$\par
\quad$20-\\{screen\_rows}+\1{ypart}\\{screen\_topleft});$\par
$\\{ttt}:=\1{min}(\\{screen\_rows},\\{screen\_cols})-40;$\par
$\2{message}\7"Boardsize? (3,...,9) ";\ \2{string}s;\ s:=\5{readstring};$\par
\BL
We won't insure that the user in fact inputs a number. However, we
do round it to an integer. Then, if it's too small, we replace it
with 3 and if too big, we replace it with 9.
\BL
$\\{boardsize}:=\1{min}(9,\1{max}(3,\1{round}(\2{scantokens}s)));$\par
$\\{ss}:=\\{ttt}/\\{boardsize};$\par
\BL
If a larger boardsize were needed, it would probably be best to change
the input scheme.  In the following, we just have to replace {\tt
ttt/3} with {\tt ss},
the {\it squaresize\/} (use Emacs' {\tt query-replace}). There are a
few other places we have to change
also, such as the for loop for the board:
\BL
$m:=3/\\{boardsize};\ \2{pickup}\\{currentpen}\6{scaled}m;$\par
$\2{for}i=1\4{upto}\\{boardsize}-1\?:$\par
\quad$\2{draw}(0,i\ast \\{ss})\8{..}(\\{ttt},i\ast \\{ss});$\par
\quad$\2{draw}(i\ast \\{ss},0)\8{..}(i\ast \\{ss},\\{ttt});$\par
$\!\3{endfor};$\par
$\2{picture}\\{tttboard};\ \\{tttboard}:=\\{currentpicture};$\par
$\2{path}\\{ttto},\\{tttxa},\\{tttxb};$\par
$\9Changed shift; to keep size 3 board ratios, we scale with m.\]\par
$\\{ttto}:=\\{fullcircle}\6{scaled}(.8\ast \\{ss})\6{shifted}(\\{ss}/2,%
\\{ss}/2);$\par
$\\{tttxa}:=(20\ast m,20\ast m)\8{..}(\\{ss}-20\ast m,\\{ss}-20\ast m);$\par
$\\{tttxb}:=(20\ast m,\\{ss}-20\ast m)\8{..}(\\{ss}-20\ast m,20\ast m);$\par
$\2{message}\7"enter 00 to quit, 10 to start new game";$\par
$\2{message}\7"enter 11 to place mark at bottom left square";$\par
\quad$\\{tr}:=\\{boardsize}+10\ast \\{boardsize};$\par
$s:=\7" to erase mark just placed at top right square";$\par
$\2{message}\7"enter "\AM \1{decimal}-\\{tr}\AM s;$\par
$\2{boolean}\\{tttmarkx};\ \\{tttmarkx}:=\5{true};$\par
$\5{screenstrokes};\ \\{currentpicture}:=\\{tttboard};\ \5{showit};$\par
$\2{forever}\?:$\par
\quad$\2{forever}\?:$\par
\quad\quad$\2{message}\7"Move? ";\ s:=\5{readstring};\ \\{move}:=%
\2{scantokens}s;$\par
\quad\quad$\2{exitif}\1{known}\\{move};\ \2{message}\7"bad input, reenter";$\par
\quad$\!\3{endfor};$\par
\quad$\\{move}:=\1{round}\\{move};\ \2{exitif}\\{move}=0;$\par
\BL
To make sure that {\tt move} has
acceptable data, we round it if known. We've implicitly declared it as
numeric; however, {\tt known move} will be false  if it
contains a string token in which case ask for the move again. We
haven't prevented the players from placing a marker off the board. If
one wanted to do this, the input loop could be expanded to check this.
 Let's fix some of the redundancy:
\BL
\quad$\\{mx}:=(((\1{abs}\\{move})\6{div}10)-1)\ast \\{ss};\ \\{my}:=(((\1{abs}%
\\{move})\6{mod}10)-1)\ast \\{ss};$\par
\quad$\2{if}(\\{move}=10)\6{or}(\\{move}=1)\?:$\par
\quad\quad$\\{currentpicture}:=\\{tttboard};\ \5{showit};\ \\{tttmarkx}:=%
\5{false};$\par
\quad$\2{elseif}\\{move}>0\?:$\par
\quad\quad$\2{if}\\{tttmarkx}\?:$\par
\quad\quad\quad$\2{draw}\\{tttxa}\6{shifted}(\\{mx},\\{my});\ \2{draw}\\{tttxb}%
\6{shifted}(\\{mx},\\{my});$\par
\quad\quad$\2{else}\?:$\par
\quad\quad\quad$\2{draw}\\{ttto}\6{shifted}(\\{mx},\\{my});$\par
\quad\quad$\!\3{fi};$\par
\quad$\2{else}\?:$\par
\quad\quad$\2{if}\1{not}\\{tttmarkx}\?:$\par
\quad\quad\quad$\2{undraw}\\{tttxa}\6{shifted}(\\{mx},\\{my});\ \2{undraw}%
\\{tttxb}\6{shifted}(\\{mx},\\{my});$\par
\quad\quad$\2{else}\?:$\par
\quad\quad\quad$\2{undraw}\\{ttto}\6{shifted}(\\{mx},\\{my});$\par
\quad\quad$\!\3{fi};$\par
\quad$\!\3{fi};$\par
\quad$\\{tttmarkx}:=\1{not}\\{tttmarkx};$\par
$\!\3{endfor};$\par
$\!\3{end};$\par
