# A simple Noughts and Crosses (Tic Tac Toe) game.
# This is to demonstrate that Avios isn't simply for standard server stuff. 
# A simple networked game like this wouldn't be worth the effort of writing 
# in C but in Avios its simple, just give it a port to run on in the init file.

&stdalias.inc

var @board pcnt cwon pwon
var @winlines @order @pieces

set winlines "123 456 789 147 258 369 159 357"
set order "5 1 3 7 9 2 4 6 8"

set pieces:"1" "..~FT00~RS.. .~FGX~RS..~FGX~RS."
set pieces:"2" ".~FTO~RS..~FTO~RS. ..~FGXX~RS.."
set pieces:"3" ".~FTO~RS..~FTO~RS. ..~FGXX~RS.."
set pieces:"4" "..~FTOO~RS.. .~FGX~RS..~FGX~RS."


#--- Main procedure contains main loop
proc main
while TRUE
	set board ". . . . . . . . ."
	set pcnt 0
	set cwon 0
	set pwon 0
	print [format "\n\n~BM-=-=-=*{ Noughts & Crosses }*=-=-=-\n\n"]

	# Computer goes first depending on rand
	if [rand 1]
		printnl "~FGI'll start..."
		set board#5 "X";  inc pcnt
	else
		printnl "~FTYou start..."
	endif

	# Mainloop
	call display_board
	while TRUE
		call player_move
		call end_game
		if $result; break; endif

		call computer_move
		call display_board
		call end_game
		if $result; break; endif
	wend
wend
endproc



#--- Display the board ---
proc display_board
var h i j el

# Go through positions
for h 1 to 7 step 3
	# Go through pieces array
	for i 1 to 4
		# Go through positions on line
		for j h to [math h+2]
			if board#j="O"; print [elements pieces#i 1]; endif
			if board#j="X"; print [elements pieces#i 2]; endif
			if board#j="."
				if i=2; print [format "..~OL%d~RS..." j]
				else; print "......"; endif
			endif
		next
		printnl
	next
next
printnl
endproc



#--- Get input from player ---
proc player_move
var pos

while TRUE
	print "~FTMove> ";  input pos
	if pos=""; continue; endif

	if [not [isnum pos]] or pos<1 or pos>9 
		printnl "~FR~OLIllegal input.";  continue
	endif
	if board#pos!="."
		printnl "~FR~OLPosition is occupied.";  continue
	endif
	break;
wend

set board#pos "O"
inc pcnt
call display_board
call check_player_win
endproc



#--- Computers turn ---
proc computer_move
var piece i s line a b c pos

# See if computer can win on next move then see if player can
set piece "X"
inc pcnt
for i 1 to 2
	foreach s line in winlines
		set a [midstr line 1]	
		set b [midstr line 2]	
		set c [midstr line 3]	

		if board#a="." and board#b=piece and board#c=piece
			call place_piece a
			if piece="O"; return; endif
			inc cwon
			return
		endif

		if board#a=piece and board#b="." and board#c=piece
			call place_piece b
			if piece="O"; return; endif
			inc cwon
			return
		endif

		if board#a=piece and board#b=piece and board#c="."
			call place_piece c
			if piece="O"; return; endif
			inc cwon
			return
		endif
	nexteach
	set piece "O"
next

# Look to create a pair
foreach s line in winlines
	set a [midstr line 1]	
	set b [midstr line 2]	
	set c [midstr line 3]	

	if board#a="X" and board#b="." and board#c="."
		call place_piece c;  return
	endif

	if board#a="." and board#b="X" and board#c="."
		call place_piece a;  return
	endif

	if board#a="." and board#b="." and board#c="X"
		call place_piece a;  return
	endif
nexteach

# Pick first free spot in a certain order
foreach s pos in order
	if board#pos="."
		call place_piece pos;  return
	endif
nexteach
endproc



#--- Place a piece for the computer ---
proc place_piece pos
set board:pos "X"
print [format "~FGMy move: ~FM%s\n\n" pos]
endproc



#--- See if player has won ---
proc check_player_win
var s line a b c

foreach s line in winlines
	set a [midstr line 1]	
	set b [midstr line 2]	
	set c [midstr line 3]	
	if board#a="O" and board#b="O" and board#c="O"
		inc pwon;  return
	endif
nexteach
endproc



#-- Display result and prompt for new game ---
proc end_game
var inp

if pwon; print [format "\n~FT~LI*** YOU WIN ***\n\n"]
else
	if cwon; print [format "\n~FG~LI*** I WIN ***\n\n"]
	else
		if pcnt=9; print [format "\n~FY*** GAME DRAWN ***\n\n"]
		else; return 0;
		endif
	endif
endif
print "Would you like another game? (y/n): "
input inp
if inp="y" or inp="Y"; return 1; endif
print [format "\n~LIOk, goodbye then...\n\n"]
exit 0
endproc