#include "ti-85.h"
#ifndef CALL_ROM
#define CALL_ROM ROM_CALL
#endif

; Copyright 1995, Philip Montgomery
; pgm@cgmsun.physics.utoledo.edu

; Well, I just wrote some great comments and explination for this file, but
; they mysteriously dissappeared.  *growls*   Anyway, here's the source to
; simple othello game.  The computer player is a little mindless, and I've
; got to implement the technique below sometime, it ought to make it quite
; a bit more challenging.   All my friends are terrible othello players 
; anyway so I've been lax in actually doing it.  ;)

; I haven't tested it all that thoroughly with the new Zshell, but I can't 
; think of anything that would make it behave differently then under 3.1

; Some of this code is UGLY.  It might send some programmers into convulsions.

; goodness = structure_val*(64-n)  + flips*k
; gotta implement that sometime...
; WeightMap:
; .db 16, -4, 4, 2
; .db -4, -12, -2, -2
; .db 4, -2, 4, 2
; .db 2, -2, 2, 0

DownKey = 1
UpKey = 4
LeftKey = 2
RightKey = 3

BoxX = 80e0h
BoxY = 80dfh
BoxCoords = 80dfh

CurColor = 80e1h
FlipFlag = 80e2h
CompMove = 80e3h
BestMove = 80e4h
TotalFlipped = 80e6h
MovesLeft = 80e7h
BoardPtr = 80e8h

.org 0
ProgName:
.db "Othello v0.4a", 0

	ROM_CALL(CLEARLCD)

	set 3, (iy+05)
	sub a
	ld (CURSOR_COL), a
	ld a, 3
	ld (CURSOR_ROW), a

	ld hl, IntroText1
	CALL_(StringAdj)
	ROM_CALL(D_ZT_STR)

	sub a
	ld (CURSOR_COL), a
	ld a, 4
	ld (CURSOR_ROW), a

	ld hl, IntroText2
	CALL_(StringAdj)
	ROM_CALL(D_ZT_STR)

	res 3, (iy+05)

	CALL_(Waitforkey)
	ROM_CALL(CLEARLCD)

	ld de, 8
	ld hl, 0fc08h
	ld c, 64
	ld a, 10101010b
d01:
	ld b, 8
d02:
	ld (hl), a
	inc hl
	dec b
	jr nz, d02
	add hl, de
	cpl
	dec c
	jr nz, d01

	ld a, 74
	ld (CURSOR_X), a
	ld a, 18
	ld (CURSOR_Y), a
	ld hl, ProgName
	CALL_(StringAdj)
	ROM_CALL(D_ZM_STR)

	ld a, 1
	ld (CurColor), a
	sub a
	ld (BoxX), a
	ld (BoxY), a
	ld b, a
	ld c, a

	ld bc, 0303h
	CALL_(RawPutPiece)
	ld bc, 0403h
	CALL_(RawPutPiece)
	ld bc, 0404h
	CALL_(RawPutPiece)
	ld bc, 0304h
	CALL_(RawPutPiece)
	ld a, 60
	ld (MovesLeft), a

MoveBox:
	push bc
	ld bc, (BoxCoords)
	ld de, BoxBM
	CALL_(RemoveBitmap)
	pop de

	ld a, b
	add a, d
	and 7
	ld (BoxX), a
	ld b, a

	ld a, c
	add a, e
	and 7
	ld (BoxY), a
	ld c, a

	ld de, BoxBM
	CALL_(PutBitmap)

NextPoll:
	call GET_KEY
	cp $37
	ret z

	ld bc, 0

	cp DownKey
	jr nz, NotDown
	inc c
	jr MoveBox
NotDown:
	cp UpKey
	jr nz, NotUp
	dec c
	jr MoveBox

NotUp:
	cp LeftKey
	jr nz, NotLeft
	dec b
	jr MoveBox

NotLeft:
	cp RightKey
	jr nz, NotRight
	inc b
	jr MoveBox

NotRight:
	cp $36		; check for 2nd key
	jr nz, NotSelect
	ld bc, (BoxCoords)
	CALL_(PutPiece)
	jr nc, NotSelect

	ld a, (MovesLeft)
	dec a
	jr z, GameOver
	ld (MovesLeft), a
	CALL_(MovePossible)
	jr nc, SkipComputer

SkippedHuman:
	CALL_(ComputerMove)
	ld a, (MovesLeft)
	dec a
	jr z, GameOver
	ld (MovesLeft), a
	CALL_(MovePossible)
	jr nc, SkipHuman

SkippedComputer:
	ld bc, 0
	JUMP_(MoveBox)
NotSelect:
	jr NextPoll

GameOver:
	ld a, 68
	ld (CURSOR_X), a
	ld a, 38
	ld (CURSOR_Y), a
	ld hl, GameOverStr
	CALL_(StringAdj)
	ROM_CALL(D_ZM_STR)

	ld hl, BoardPtr
	ld c, 0
	ld b, 64
NextBoxTally:
	ld a, (hl)
	inc hl
	cp 1
	jr z, ComputerPoint
	inc c
	jr TalliedPoint
ComputerPoint:
	dec c
TalliedPoint:
	dec b
	jr nz, NextBoxTally

	ld a, c
	or a
	jr nz, SomeOne
	ld hl, NooneName
	jr PrintAndEnd
SomeOne:
	bit 7, c
	jr nz, ComputerWon
	ld hl, ComputerName
	jr PrintAndEnd
ComputerWon:
	ld hl, HumanName
PrintAndEnd:
	CALL_(StringAdj)
	ROM_CALL(D_ZM_STR)
	CALL_(Waitforkey)
	ret


SkipHuman:
	ld a, (CurColor)
	xor 3
	ld (CurColor), a
	jr SkippedHuman

SkipComputer:
	ld a, (CurColor)
	xor 3
	ld (CurColor), a
	jr SkippedComputer

CalcOffset:		; (b, c) -> coords (8 by 8 blocks) y=0..8
			; hl -> destination
			; corrects address in de
;	ld bc, 0
	ld hl, (PROGRAM_ADDR)
	add hl, de
	ld d, h
	ld e, l		; corrected address
	ld h, 0
	sla c		; *2
	sla c		; *4
	sla c		; *8
	sla c		; *16
	sla c		; *32
	ld l, c
	add hl, hl	; *64
	add hl, hl	; *128  multiply y by 128
	ld c, b
	ld b, 0
	add hl, bc	; add x component
	ld bc, VIDEO_MEM
	add hl, bc
	ret

PutBitmap:		; de -> src
			; bc -> coords
	push de
	push bc
	CALL_(CalcOffset)
	ld c, 8
pbNextLine:
	push bc
	ld a, (de)
	inc de
	or (hl)
	ld (hl), a
	ld bc, 16
	add hl, bc
	pop bc
	dec c
	jr nz, pbNextLine
	pop bc
	pop de
	ret

BlitBitmap:		; de -> src
			; bc -> coords
	push de
	push bc
	CALL_(CalcOffset)
	ld c, 8
bbNextLine:
	push bc
	ld a, (de)
	inc de
	ld (hl), a
	ld bc, 16
	add hl, bc
	pop bc
	dec c
	jr nz, bbNextLine
	pop bc
	pop de
	ret

RemoveBitmap:		; de -> src
	push de
	push bc
	CALL_(CalcOffset)
	ld c, 8
rbNextLine:
	push bc
	ld a, (de)
	inc de
	cpl
	and (hl)
	ld (hl), a
	ld bc, 16
	add hl, bc
	pop bc
	dec c
	jr nz, rbNextLine
	pop bc
	pop de
	ret

;ToggleBitmap:		; de -> src
;	push de
;	push bc
;	CALL_(CalcOffset)
;	ld c, 8
;xbNextLine:
;	push bc
;	ld a, (de)
;	inc de
;	xor (hl)
;	ld (hl), a
;	ld bc, 16
;	add hl, bc
;	pop bc
;	dec c
;	jr nz, xbNextLine
;	pop bc
;	pop de
;	ret

CalcBoardPtr:		; (b, c) coordinate
			; output: hl ptr
	push bc
	sla c
	sla c
	sla c
	ld a, c
	or b
	ld b, 0
	ld c, a
	ld hl, BoardPtr
	add hl, bc
	pop bc
	ret

ScanDir:		; (d, e) delta x, delta y
			; (b, c) x, y of start
	push ix
	push bc
	push hl
	ld ix, CurColor
NextScanInc:
	ld a, b
	add a, d
	ld b, a
	and 7
	cp b
	jr nz, HitEnd		; Hit End

	ld a, c
	add a, e
	ld c, a
	and 7
	cp c
	jr nz, HitEnd

	CALL_(CalcBoardPtr)
	ld a, (hl)
	or a
	jr z, HitEnd

	cp (ix)
	jr nz, NextScanInc

	pop hl
	pop bc
	pop ix
	
	CALL_(FlipDir)
	ret
HitEnd:
	sub a
ReturnScan:
	pop hl
	pop bc
	pop ix
	ret

FlipDir:		; (d, e) delta x, delta y
			; (b, c) x, y of start
	push ix
	push bc
	push hl
	ld ix, CurColor
fNextScanInc:

	ld a, b
	add a, d
	ld b, a
	and 7
	cp b
	jr nz, fHitEnd		; Hit End

	ld a, c
	add a, e
	ld c, a
	and 7
	cp c
	jr nz, fHitEnd

	CALL_(CalcBoardPtr)
	ld a, (hl)
	cp (ix)
	jr z, fHitEnd
	bit 1, (ix+2)
	jr nz, JustCount
	xor 3
	ld (hl), a
JustCount:
	inc (ix+1)		; Increment Flipflag
	jr fNextScanInc
fHitEnd:
	pop hl
	pop bc
	pop ix
	ret

RawPutPiece:
	push hl
	push de
	push bc
	CALL_(CalcBoardPtr)
	jr PieceEntry

BlockFull:
	scf
	ccf			; set CY to zero
	pop bc
	pop de
	pop hl
	ret

PutPiece:		; (b, c) coordinate
	push hl
	push de
	push bc

	CALL_(CalcBoardPtr)
	ld a, (hl)
	or a			; see if block is full
	jr nz, BlockFull

	sub a
	ld (FlipFlag), a

	push hl
	ld hl, (PROGRAM_ADDR)
	ld de, DirMap
	add hl, de		; point to start of mapping

NextDirection:
	ld e, (hl)
	inc hl
	ld d, (hl)
	inc hl
	ld a, e
	or d
	jr z, DoneDirs

	CALL_(ScanDir)
	jr NextDirection
DoneDirs:
	pop hl
	ld a, (FlipFlag)
	or a
	jr z, BlockFull

PieceEntry:
	ld a, (CompMove)
	or a
	jr nz, DontDoItJim

	ld a, (CurColor)

	ld (hl), a
	xor 3
	ld (CurColor), a

DontDoItJim:
	ld b, 8
NextBRow:
	ld c, 8
NextBCol:
	push bc
	dec b
	dec c
	CALL_(CalcBoardPtr)
	ld a, (hl)
	cp 1
	jr nz, NotWhite
	ld de, WhiteBM
	jr bitmapc
NotWhite:
	cp 2
	jr nz, NoBitmap
	ld de, BlackBM
bitmapc:
	CALL_(BlitBitmap)
NoBitmap:
	pop bc
	dec c
	jr nz, NextBCol
	dec b
	jr nz, NextBRow

	scf
PieceRet:
	pop bc
	pop de
	pop hl
	ret


BlackBM:
.db	00000000b
.db	00111100b
.db	01111110b
.db	01111110b
.db	01111110b
.db	01111110b
.db	00111100b
.db	00000000b

WhiteBM:
.db	00000000b
.db	00111100b
.db	01000010b
.db	01000010b
.db	01000010b
.db	01000010b
.db	00111100b
.db	00000000b

BoxBM:
.db	11111111b
.db	10000001b
.db	10000001b
.db	10000001b
.db	10000001b
.db	10000001b
.db	10000001b
.db	11111111b

DirMap:
.dw	0ffffh, 0ff01h, 001ffh, 0101h, 000ffh, 0ff00h, 00001h, 00100h, 0

GameOverStr:
.db "The Winner: ", 0

HumanName:
.db "Human",0
ComputerName:
.db "TI-85",0
NooneName:
.db "Draw",0

Waitforkey:
	call GET_KEY
	or a
	ret nz
	jr Waitforkey

MovePossible:
	push de
	push hl
	push bc

	ld c, 0
	ld a, 7
	ld (CompMove), a

NextScanCol:
	ld b, 0
NextScanRow:
	CALL_(CalcBoardPtr)
	ld a, (hl)
	or a
	jr nz, incNextScanRow

	ld hl, (PROGRAM_ADDR)
	ld de, DirMap
	add hl, de		; point to start of mapping

NextDirectionc:
	ld e, (hl)
	inc hl
	ld d, (hl)
	inc hl
	ld a, e
	or d
	jr z, incNextScanRow

	sub a
	ld (FlipFlag), a
	CALL_(ScanDir)
	ld a, (FlipFlag)
	or a
	jr z, NextDirectionc
	jr PossibleScanRet
	
incNextScanRow:
	ld a, 8
	inc b
	cp b
	jr nz, NextScanRow
	inc c
	cp c
	jr nz, NextScanCol

PossibleScanFail:
	scf
	ccf
	jr cfpophlpopderet

PossibleScanRet:
	scf

cfpophlpopderet:
	ld a, 0
	ld (CompMove), a
	pop bc
	pop hl
	pop de
	ret

ComputerMove:
	push de
	push bc

	ROM_CALL(BUSY_ON)

	ld a, -1
	ld (CompMove), a

	sub a
	ld (TotalFlipped), a
ScanEntry:
	ld c, 0
CompCol:
	ld b, 0
CompRow:
	CALL_(PutPiece)
	jr nc, MoveInvalid
	ld a, (CompMove)

	ld a, (FlipFlag)
	ld d, a
	ld a, (TotalFlipped)
	cp d
	jr nc, MoveStillGood
	ld a, d

;	ld a, (FlipFlag)
;	ld d, (TotalFlipped)
;	cp d
;	jr nc, MoveStillGood	 ; This is just plain wrong

	ld (BestMove), bc
	ld (TotalFlipped), a

MoveStillGood:

MoveInvalid:
	inc b
	ld a, 8
	cp b
	jr nz, CompRow
	
	inc c
	cp c
	jr nz, CompCol

	sub a
	ld (CompMove), a

	ld bc, (BestMove)
	CALL_(PutPiece)

	ROM_CALL(BUSY_OFF)
popbcpopderet:
	pop bc
	pop de
	ret
	
StringAdj:
	push de
	ld de, (PROGRAM_ADDR)
	add hl, de
	pop de
	ret


IntroText1:
.db " Othello v.04 alpha  ",0
;     012345678901234567890
IntroText2:
.db "        *swank*      ", 0
.end
