# Logic from Tim Hartnell's Giant Book of Computer Games, p. 133
# Jerry Stratton hoboes.com/coco

gosub initialize
if %firstMover$="human" gosub humanMove

loop
	gosub computerMove
	gosub humanMove
endloop

//is the game over?
sub gameStatus
	gosub printBoard

	#computer or human has no pieces
	if %humanScore% = 0 or %computerScore% = 0 then gosub gameOver

	#all spaces full
	if %humanScore%+%computerScore% = 64 then gosub gameOver

	#during last two moves, both computer and human were blocked
	if %humanBlocked% = 1 and %computerBlocked% = 1 then gosub gameOver
endsub

//print the playing board and tally the score
sub printBoard
	%computerScore%=0
	%humanScore%=0

	print@0,""
	print tab(8);"1 2 3 4 5 6 7 8"
	for %row%=2 to 9
		print tab(4);%row%-1;" ";
		for %column%=2 to 9
			print chr$(%board%(%row%, %column%));" ";
			if %board%(%row%, %column%)=%computer% then %computerScore%++
			if %board%(%row%, %column%)=%human% then %humanScore%++
		next %column%
		print %row%-1
	next %row%
	print tab(8);"1 2 3 4 5 6 7 8"
	print
	print using "Computer (X): ##   Human (O): ##";%computerScore%,%humanScore%
	print
endsub

sub humanMove
	%mover% = %human%
	%opponent% = %computer%
	loop
		loop
			loop
				print@%moveTextStart%, "Your move? ";
				gosub inputMove
				%humanMove% = val(%humanMove$)
			endloop unless (%humanMove$<>"pass" and %humanMove$<>"help" and (%humanMove%<11 or %humanMove%>88))
	
			if (%humanMove$="pass") then
				%flashText$ = "checking"
				%flashPosition% = %moveTextStart%+11
				gosub findMove
				if (%flipQuality%=0) then
					%humanBlocked% = 1
					gosub gameStatus
					return
				else
					gosub beep
					print@%moveTextStart%,"You must move"
					pause 4
					continue
				endif
			endif
			if (%humanMove$="help") then
				gosub help
				wrap-center \^Lpress key to continue game\^Q
				pause
				cls
				gosub printBoard
				%humanMove$ = ""
				continue
			endif

			%humanMove%+=11
			%rowChoice%=int(%humanMove%/10)
			%columnChoice%=%humanMove%-10*%rowChoice%
		endloop unless (%board%(%rowChoice%,%columnChoice%)<>%blank%)

		gosub flipCells
	endloop unless (%flipCount%=0)
	%humanBlocked% = 0

	gosub gameStatus
endsub

sub computerMove
	print@%moveTextStart%, "My move...";

	%opponent%=%human%
	%mover%=%computer%
	%flashText$ = "thinking"
	%flashPosition% = %moveTextStart%+11
	gosub findMove

	if (%flipQuality% <> 0) then
		%computerBlocked% = 0
		print@%flashPosition%, (%rowChoice%-1)*10+(%columnChoice%-1)
		gosub flipCells
	else
		print@%flashPosition%, " pass"
		%computerBlocked% = 1
	endif

	gosub gameStatus
endsub

//choose a move for the computer
//or discover if moves exist for the human
//requires %mover% and %opponent%
//sets %flipQuality%, %rowChoice%, %columnChoice%
sub findMove
	%flipQuality%=0
	for %row%=2 to 9
		for %column%=2 to 9
			if (%board%(%row%, %column%)=%blank%) then
				%currentQuality%=0
				for %rowOffset%=-1 to 1
					for %columnOffset%=-1 to 1
						%flipCount%=0
						%currentRow%=%row%
						%currentColumn%=%column%
						loop while (%board%(%currentRow%+%rowOffset%, %currentColumn%+%columnOffset%)=%opponent%)
							%flipCount%+=1
							%currentRow%+=%rowOffset%
							%currentColumn%+=%columnOffset%
						endloop

						if (%board%(%currentRow%+%rowOffset%, %currentColumn%+%columnOffset%)=%mover%) then
							%currentQuality%+=%flipCount%
							/*
							//if this was the human, all we care about is that there is a possible move
							if (%mover% = %human% and %flipCount% > 0) then
								%flipQuality% = 1
								return
							endif
							*/
						endif
					next %columnOffset%
					print@%flashPosition%, "";
					if %rowOffset%/2 = int(%rowOffset%/2) then print %flashText$ else print string$(len(%flashText$)," ")
				next %rowOffset%

				if (%mover% = %human%) then
					//highlight the potential move
					if (%currentQuality% > 0) then
						if (%moveLocation% > 0) then
							print@%moveLocation%, chr$(%blank%);
						endif
						%moveLocation% = %row%*32 + 4+%column%*2
						print@%moveLocation%, chr$(%mover%+32);
					endif
				else
					//adjust the desirability of the current potential move
					switch
						//if the number of flips is the number of human pieces, take it
						case (%currentQuality% = %humanScore%)
							%currentQuality% *= 100
						//edges are more desirable
						case (%row%=2 or %row%=9 or %column%=2 or %column%=9)
							%currentQuality% *= 2
						//next to the edges are less desirable
						case (%row%=3 or %row%=8 or %column%=3 OR %column%=8)
							%currentQuality% /= 2
						//next to corners are less desirable yet
						case ((%row%=2 or %row%=9) and (%column%=3 or %column%=8) or (%row%=3 or %row%=8) and (%column%=2 or %column%=9))
							%currentQuality% /= 2
					endswitch
				endif

				//choose this move if the quality is better or choose randomnly if the quality is the same
				if (not(%currentQuality%<%flipQuality% or (rnd(0)<.3 and %currentQuality%=%flipQuality%))) then
					%flipQuality%=%currentQuality%
					%rowChoice%=%row%
					%columnChoice%=%column%
				endif

			endif
		next %column%
	next %row%

	//clear out highlighted potential move
	if (%moveLocation% > 0) then
		pause 1
		print@%moveLocation%, chr$(%blank%);
		%moveLocation% = 0
	endif
endsub

//accepts %rowChoice%, %columnChoice%, %mover%, %opponent%
//returns %flipCount%
sub flipCells
	%flipCount% = 0
	for %rowOffset%=-1 to 1
		for %columnOffset%=-1 to 1
			%currentRow%=%rowChoice%
			%currentColumn%=%columnChoice%

			//find the end of the opponent's line
			loop while (%board%(%currentRow%+%rowOffset%, %currentColumn%+%columnOffset%)=%opponent%)
				%currentRow%+=%rowOffset%
				%currentColumn%+=%columnOffset%
			endloop

			//flip the opponent's lines if %mover% was found on the other end of the line
			if (%board%(%currentRow%+%rowOffset%,%currentColumn%+%columnOffset%)=%mover%) then
				loop while (%rowChoice%<>%currentRow% or %columnChoice%<>%currentColumn%)
					if (%board%(%currentRow%, %currentColumn%)<>%mover%) then
						%board%(%currentRow%,%currentColumn%)=%mover%
						%flipCount%++
					endif
					%currentRow%-=%rowOffset%
					%currentColumn%-=%columnOffset%
				endloop

				//add the end piece
				if (%flipCount% > 0) then
					%board%(%currentRow%, %currentColumn%)=%mover%
				endif
			endif
		next %columnOffset%
	next %rowOffset%

	if (%flipCount% = 0) then
		gosub beep
	endif
endsub

sub initialize
	gosub help

	#create starting board
	%computer% = asc("X")
	%human% = asc("O")
	%blank% = asc(".")
	dim %board%(10,10)
	for %row%=1 to 10
		for %column%=1 to 10
			if %row%<>1 and %column%<>1 and %row%<>10 and %column%<>10 then %board%(%row%, %column%)=%blank%
		next %column%
	next %row%
	%board%(5,5)=%computer%
	%board%(6,6)=%computer%
	%board%(6,5)=%human%
	%board%(5,6)=%human%
	%moveTextStart% = 32*14

	#randomize
	wrap-center \^Lpress any key to start\^Q
	pause
	a=rnd(-TIMER)

	#first move
	if rnd(2)=1 then %firstMover$="human" else %firstMover$="computer"
	print
	print "The ";%firstMover$;" will go first."
	pause 4

	cls
	gosub printBoard
endsub

//input player move without accidental scrolling
sub inputMove
	%humanMove$ = ""
	%spacing$ = string$(8,32)
	%cursor% = 128+16*7+15
	%cursor$ = chr$(%cursor%)
	%backspace$ = string$(len(%spacing$)+1,8)
	loop
		print %cursor$;%spacing$;
		loop
			print %backspace$;%cursor$;%spacing$;
			a$=inkey$
			pause .15
			if %cursor$ = " " then %cursor$=chr$(%cursor%) else %cursor$=" "
		endloop unless (a$="")

		print %backspace$;
		switch
			case (a$=chr$(8))
				if len(%humanMove$)>0 then %humanMove$=left$(%humanMove$, len(%humanMove$)-1):print a$; else gosub beep
				break
			case (a$=chr$(13))
				break
			case (len(%humanMove$)>=4)
				gosub beep
				break
			case ((asc(a$)>=asc("a") and asc(a$)<=asc("s")) or (asc(a$)>=asc("1") and asc(a$)<=asc("8")))
				%humanMove$ += a$
				print a$;
				break
			case (default)
				gosub beep
		endswitch
	endloop unless (a$<>chr$(13))
endsub

sub help
	cls

	wrap-center \^Lreversi\^Q
	print
	wrap The object of \^Lreversi\^Q is to surround your enemy. Every turn, place an O to sandwich at least one X between an existing O and your new O.
	print
	wrap Enter moves as two-digit numbers. The first digit is the row and the second the column. If you have no move, enter \^Lpass\^Q.
	print
endsub

sub beep
	sound 100,1
endsub

sub gameOver
	print@%moveTextStart%,"";
	switch
		case (%computerScore%>%humanScore%)
			print "I'm the champ!"
		case (%humanScore%>%computerScore%)
			print "You're the champ!"
		case (%humanScore%=%computerScore%)
			print "It's a draw!"
	endswitch
	pause 10

	print
	input "play again? (y/n)";%playAgain$
	if %playAgain$ = "y" then run else run "autoexec:1"
endsub
