        .nolist

        #include "ion.inc"		;tells TASM--the compiler--what file to read from to define rom call memory addresses and such
        .list
empty	.equ	0
oh	.equ	1
ohwin	.equ	3	;oh * 3!
ex	.equ	4
exwin	.equ	12	;ex * 3!
false	.equ	0
true	.equ	1

keyquit	.equ	$40
keyins	.equ	$0B
keyup	.equ	$03
keydn	.equ	$04
keyrght	.equ	$01
keyleft	.equ	$02
keyentr	.equ	$05

#define B_CALL(xxxx)  rst 28h \ .dw xxxx	;We'll only be using B_CALL


#ifdef TI83P			;a check for TASM to see whether it is making an 83 program--if so, do the next two commands
        .org    progstart-2
        .db     $BB,$6D
#else				;if it isn't an 83 program, then do something [#]else--the next line
        .org    progstart
#endif				;simply ends the #ifdef command
        ret				

        jr      nc,begin 		;Jumps to the beginning of the program (this line and the below three will be 
        .db     "TicTacToe",0		;The title displayed by ION--anything you want
begin: 				;defines where label begin is, program code follows this label


	B_CALL(_IndicatorOff)	; Turning off the Run Indicator
	B_CALL(_grbufclr)		; clear the buffer
	ld	hl,picture		; get address of splash screeen
	ld	de,plotsscreen  	; get address of TI graphic buffer
	ld	bc,768          	; set number of bytes to copy (96*64)/8
	ldir			; copy the bytes
	call IonFastCopy		; bind the graphic image

; set the flip-flip flag
	ld	a,false
	ld	(flag),a
	ld	(skip),a
				; start of game
newgme	B_CALL(_getkey)		; wait for a key to be pressed
	cp	keyquit
	jp	z,bye		; exit
newgme2 ld	a,empty		; clear the playing grid
	ld	(grid0),a
	ld	hl,grid0
	ld	de,grid0+1
	ld	bc,8
	ldir
	ld	a,true		; preset the cursor grid
	ld	(cur0),a
	ld	a,false
	ld	(cur0+1),a
	ld	hl,cur0+1
	ld	de,cur0+2
	ld	bc,8
	ldir
				; pick symbol for person and ti
	ld	a,(flag)
	cp	true
	jr	z,new1

	ld	a,true
	ld	(flag),a
	ld	a,ex
	ld	(person),a
	ld	a,oh
	ld	(tisymb),a
	ld	a,false
	ld	(skip),a
	ld	hl,youex
	jr	main2
new1	ld	a,false
	ld	(flag),a
	ld	a,oh
	ld	(person),a
	ld	a,ex
	ld	(tisymb),a
	ld	a,true
	ld	(skip),a
	ld	hl,youoh
	jr	main2
				; main processing loop	
main	ld	hl,nomsg
main2	call show			; show the current grid
	ld	a,(skip)
	cp	true
	jp	z,aihere		; let the ti go first
	B_CALL(_getkey)		; get the next key input
	cp	keyquit
	jp	z,bye		; exit
	cp	keyins
	jp	z,newgme2

	cp	keyup
	jr	nz,trydn		; up pushed
	call	up3
	jp	main	
trydn	cp	keydn
	jr	nz,tryrght		; down pushed
	call	dn3
	jp	main
tryrght cp	keyrght
	jr	nz,tryleft		; right pushed
	call	rght3
	jp	main
tryleft	cp	keyleft	
	jr	nz,tryentr		; left pushed
	call	left3
	jp	main
tryentr       cp	keyentr
	ld	hl,badmsg
	jp	nz,main2		; enter pushed, other keys ignored
				; find the current cursor location
	ld	hl,cur0
	ld	b,9
fdloop	ld	a,(hl)
	cp	true

	jr	nz,fdnext
				; found cursor location!
	ld	bc,-9
	add	hl,bc		; back into the grid
				; see if empty
	ld	a,(hl)
	cp	empty
	jr	nz,fderr
				; if so, insert symbol 
	ld	a,(person)
	ld	(hl),a	
	call	chkwin
	cp	true
	jp	z,newgme
	jr	aihere
fderr	ld	hl,badloc
	jp	main2
				; CAUTION -- AI at work here!!!
aihere	ld	a,false
	ld	(skip),a
	call	timove
	call	chkwin
	cp	true
	jp	z,newgme
	ld	a,(flag)
	cp	true
	jr	z,fdmsg
	ld	hl,youoh		;show oh msg

	jp	main2	
fdmsg	ld	hl,youex		;show ex msg
	jp	main2
fdnext  inc	hl
	djnz    fdloop
	jp	z,main		; something is wrong...
				; ignore error
	jp	main
				; main exit point
bye
	call	clrhme		; clear screen
	ld	hl,byemsg
	B_CALL(_puts)
	B_CALL(_newline)
	ret			; return to being a mere calculator
;
clrhme	set	appTextSave,(iy+appFlags) ; get text shadow too
	B_CALL(_clrlcdf)		; clear lcd
	B_CALL(_homeup)		; home the cursor
	ret
;TI GAME STRATEGY
; ti makes a move
; strategy:

; 1) Can ti win, if so then do it
; 2) Can "wet-ware" win, if so then take it the square first
; 3) Can ti take the center, if so then take it
; 4) Can ti take a corner, if so then take it
; 5) else, take an open spot
timove       ld	b,9
	ld	hl,grid0
tiloop1	ld	a,(hl)
	cp	empty
	jr	nz,tinext1
	push	hl
	push	bc
	ld	a,(tisymb)
	ld	(hl),a
	call	chkwin
	pop	bc
	pop	hl
	cp	true
	jr	z,tifnd		; winning move!	
	ld	a,empty
	ld	(hl),a		; remove trial move
tinext1 inc	hl
	djnz	tiloop1  

;check for defensive move
	ld	b,9
	ld	hl,grid0
tiloop2	ld	a,(hl)
	cp	empty
	jr	nz,tinext2
	push	hl
	push	bc
	ld	a,(person)
	ld	(hl),a
	call	chkwin
	pop	bc
	pop	hl
	ld	d,a
	ld	a,empty
	ld	(hl),a
	ld	a,d
	cp	true
	jr	z,tifnd		; good defensive move!
tinext2	inc	hl
	djnz	tiloop2
				;check the center
	ld	hl,grid0+4
	ld	a,(hl)
	cp	empty
	jr	z,tifnd
				;check the corners (and center again)
	ld	b,5
	ld	hl,grid0
tiloop4 ld	a,(hl)
	cp	empty
	jr	z,tifnd
	inc	hl		; +2 goes corner to corner ...

	inc	hl
	djnz	tiloop4
				;try anyplace (could optimize, but....)
	ld	b,9
	ld	hl,grid0
tiloop5	ld	a,(hl)
	cp	empty
	jr	z,tifnd
	inc	hl
	djnz	tiloop5
	jr	tiexit
tifnd	ld	a,(tisymb)
	ld	(hl),a
tiexit	ret
				; check for a winner, return true in a if so, else false
chkwin	ld	hl,chktab
	push	hl
	pop	ix		;table addr -> ix
				;start outer loop
chkloop	ld	a,(hl)		;are we done?
	cp	0
	jr	z,chknaw		;yes, then no winner!
	inc	hl		;get to address
	ld	e,(hl)		;woaw!!!  (hl) -> hl

	inc	hl		; woaw!!!
	ld	d,(hl)		;  woaw!!!
	push	de		;   woaw!! 
	pop	hl		; de -> hl
	ld	d,0
	ld	e,a		;de is increment value
	ld	b,3		;b is loop count				
	ld	a,0		;a is sum	add	hl,de
				;start inner loop
chk1 	add	a,(hl)
	add	hl,de
	djnz	chk1
	cp	ohwin
	jr	nz,chk1n
	ld	hl,ohwins	; O wins!
	jr	chkwinr
chk1n	cp	exwin
	jr	nz,chkno
	ld	hl,exwins	; X wins
	jr	chkwinr
;end inner	
chkno	push	ix	
	pop	hl		; ix -> hl
	inc	hl		; add 3

	inc	hl
	inc	hl
	push	hl
	pop	ix		; hl -> ix
	jr	chkloop		;no win this line
				;end outer
				; exit outer loop early, crow about success and mark win
chkwinr	call	show
	ld	a,true
	jr	chkbye
chknaw	ld	hl,grid0		;See about the cat
	ld	b,9
chklop	ld	a,(hl)
	cp	empty
	jr	z,chkncat
	inc	hl
	djnz	chklop
	ld	hl,catmsg		;Darn cat!
	call	show
	ld	a,true
	jr	chkbye
chkncat	ld	a,false
chkbye	ret
				; this routine works by summing values in grid, 8 possible cases

chktab	.db	1		;covers the 8 cases!
	.dw	grid0
	.db	1
	.dw	grid1
	.db	1
	.dw	grid2
	.db	3
	.dw	grid0
	.db	3
	.dw	grid0+1
	.db	3
	.dw	grid0+2
	.db	4
	.dw	grid0
	.db	2
	.dw	grid0+2
	.db	0		;end of table marker

				; move "cursor" up
up3	ld	hl,cur0
	ld	de,curx
	call	mov3
	ld	hl,cur1
	ld	de,cur0
	call	mov3
	ld	hl,cur2
	ld      de,cur1
	call    mov3
	ld	hl,curx
	ld	de,cur2
	call	mov3
	ret
				; move "cursor" down
dn3	ld	hl,cur0
	ld	de,curx
	call	mov3

	ld	hl,cur2
	ld	de,cur0
	call	mov3
	ld	hl,cur1
	ld      de,cur2
	call    mov3
	ld	hl,curx
	ld	de,cur1
	call	mov3
	ret
				; helper routine
mov3	ld	bc,3
	ldir
	ret
				; move "cursor" right
rght3	ld	hl,cur0
	call	shtr3
	ld	hl,cur1
	call	shtr3
	ld	hl,cur2
	call	shtr3
	ret
				; helper routine
shtr3 	push	hl
	ld	a,(hl)
	inc	hl
	ld	b,(hl)
	inc	hl
	ld	c,(hl)
	pop	hl
	ld	(hl),c
	inc	hl
	ld	(hl),a
	inc	hl
	ld	(hl),b
	ret
				; move "cursor" left
left3	ld	hl,cur0
	call	shtl3
	ld	hl,cur1
	call	shtl3

	ld	hl,cur2
	call	shtl3
	ret
				; helper routine
shtl3	push	hl
	ld	a,(hl)
	inc	hl
	ld	b,(hl)
	inc	hl
	ld	c,(hl)
	pop	hl
	ld	(hl),b
	inc	hl
	ld	(hl),c
	inc	hl
	ld	(hl),a
	ret
				; show the tic-tac-toe grid on the screen
show	push	hl		; keep possible message	
	call	clrhme		; clear/home screen
	ld	hl,grid0		; process row 0
	call	showrow
	ld	hl,dashs
	B_CALL(_puts)
	B_CALL(_newline)
	ld	hl,grid1		; process row 1
	call	showrow
	ld	hl,dashs
	B_CALL(_puts)
	B_CALL(_newline)
	ld	hl,grid2		; process row 2
	call	showrow
	pop	hl		; process message if there

	ld	a,(hl)
	cp	0
	jr	z,showby
	push	hl
	B_CALL(_newline)
	B_CALL(_newline)
	pop	hl
	B_CALL(_puts)

showby	ret

showrow
	push	hl
	call	showspot	; show first spot
	ld	a,(bar)
	B_CALL(_putc)
	pop	hl
	inc	hl
	push	hl
	call	showspot	; show 2nd spot
	ld	a,(bar)
	B_CALL(_putc)
	pop	hl
	inc	hl
	call	showspot	; show 3rd spot
	B_CALL(_newline)
	ret

				; show the symbol at (hl), and handle cursor
showspot
	push	hl		; need this later
	ld	bc,9
	add	hl,bc
	ld	a,(hl)		; load cursor flag
	pop	hl
	cp	false
	res	textInverse,(iy+textflags)

	jr	z,shownch
	set	textInverse,(iy+textflags)
shownch				; load actual item in spot
	ld	a,(hl)
	cp	empty
	jr	nz,shownot1
	ld	a,(space)
	jr	showgun
shownot1
	cp	oh
	jr	nz,shownot2
	ld	a,(leto)
	jr	showgun
shownot2
	ld	a,(letx)
showgun:
	bcall(_putc)
	res	textInverse,(iy+textflags)
	ret
				; these are really variables
grid	.equ	*
grid0   .db	empty,empty,empty
grid1	.db	empty,empty,empty
grid2	.db	empty,empty,empty
				; this must be 9 bytes past grid0 or else it will fail
cur0	.db	true,false,false
cur1	.db	false,false,false
cur2	.db	false,false,false
curx	.db	0,0,0
person	.db	0

tisymb	.db	0
flag	.db	0
skip	.db	0
				; basically, these are constants
nine	.db	9
space	.db	" "
leto	.db	"O"
letx	.db	"X" 
bar	.db	"|"
dashs	.db	"-----",0
; youmsg	.db	"Your move!",0











youex	.db	"Your move 'X'!",0
youoh	.db	"Your move 'O'!",0
ohwins	.db	"** O ** Wins!",0
exwins	.db	"** X ** Wins!",0
catmsg	.db	"* Cat got it *",0
nomsg	.db	0
badmsg	.db	"Invalid key!",0
badloc	.db	"Place taken!",0
byemsg	.db	"Game over.",0

picture:
	#include "title.asm"    ; graphic image from file poets.asm

.end
END
