;	Othello v1.18 by Stuart Bain
;
;	Copyright © 1990 Amiga Computing
;
;	Assembled on Devpac 2, using a 1Mb Amiga 500 Kickstart 1.3

	opt	c+,d+
	 section othello,code_c
	incdir	"rad:"

;	load includes from rad: -  change to df0:include if necessary

	include	intuition/intuition.i
	include	intuition/intuition_lib.i
	include	exec/exec_lib.i
	include	graphics/graphics_lib.i
	include	exec/memory.i

	lea	grafname(pc),a1		open graphics library
	moveq	#0,d0
	CALLEXEC OpenLibrary
	tst.l	d0
	beq	goawayfast
	move.l	d0,_GfxBase

	lea	intname(pc),a1		open intuition library
	moveq	#0,d0
	CALLEXEC OpenLibrary
	tst.l	d0
	beq	closegraf
	move.l	d0,_IntuitionBase

	move.b	$bfe801,rndseed		use internal timer to get seed

;open the window
	lea	windowdef(pc),a0
	CALLINT OpenWindow
	tst.l	d0
	beq	closeall		escape if didn't open
	move.l	d0,windowptr

* * * * * * * * * * * * * * * * *
newgame:
	bsr	cleargrid	clears table + window
	moveq.l	#2,d0
	bsr	rnd		choose players' colours
	dbeq	d0,hu1st
	move.b	#1,col1
	move.b	#2,col2
	bra	titles
hu1st:	move.b	#2,col1
	move.b	#1,col2

titles:	lea	score1(pc),a1		print score line
	bsr	print
	lea	score2(pc),a1
	bsr	print
	lea	requestor(pc),a1
	bsr	print

;draw grid
	moveq	#3,d0
	move.l	windowptr(pc),a1
	move.l	wd_RPort(a1),a1
	CALLGRAF SetAPen
	moveq	#20,d4
gridhor:
	move.l	d4,d1
	moveq	#0,d0
	bsr	moveto
	move.l	#159,d0
	bsr	drawto
	add	#10,d4
	cmp	#100,d4
	ble	gridhor

	moveq	#113,d1			draws boxes round 'requestors'
	bsr	moveto
	moveq	#0,d0
	bsr	drawto
	moveq	#113,d1
	moveq	#80,d0
	bsr	moveto
	moveq	#125,d1
	bsr	drawto
	moveq	#20,d4
gridver:
	move.l	d4,d0
	moveq	#21,d1
	bsr	moveto
	move.l	#99,d1
	bsr	drawto
	add	#20,d4
	cmp	#140,d4
	ble	gridver

	moveq	#1,d0			puts 4 counters in centre
	move.l	#44,d4
	bsr	putoncounter
	moveq	#2,d0
	move.l	#45,d4
	bsr	putoncounter
	moveq	#1,d0
	move.l	#55,d4
	bsr	putoncounter
	moveq	#2,d0
	move.l	#54,d4
	bsr	putoncounter
	bsr	addscores

	lea	message2(pc),a1		waits for starting click
	bsr	print
start:	btst.b	#6,$bfe001
	bne.s	start
start2:	btst.b	#6,$bfe001
	beq.s	start2
	bsr	clearmessagebox

	move.b	#0,youpass		clear flags
	move.b	#0,mepass
	move.b	#0,gameover
	move.b	#0,newgameflag

	move.b	col1,d0			black first
	cmp.b	#2,d0
	beq	compfirst

;main loop starts here
mainloop:
	move.l	windowptr(pc),a1	pause execution while not
	move.l	86(a1),a0		being played
	CALLEXEC WaitPort
	move.l	windowptr(pc),a1
	move.l	wd_UserPort(a1),a0
	CALLEXEC GetMsg			get message if any
	tst.l	d0
	beq	mainloop
	move.l	d0,a0
	move.l	im_Class(a0),d6
	cmp.l	#CLOSEWINDOW,d6		find if clicked close window
	beq	closeclicked
	move	im_Code(a0),d6
	cmp	#SELECTUP,d6		check left button
	bne	mainloop
	move.l	d0,a1
	CALLEXEC ReplyMsg
	bsr	getmove			gets human's move
	tst.b	newgameflag		exit loop if new game
	bne	newgame
	tst	numturn
	beq	mainloop		do again if no move played
	bsr	checkgameover
	tst.b	youpass
	bne	compfirst
	move.b	$bfe801,d0		\
	add.b	#65,d0			 \
pause2:	move.b	$bfe801,d1		  >--short pause of 65/50 sec
	cmp.b	d0,d1			 /
	bne	pause2			/
compfirst:
	bsr	computer
	bsr	checkgameover
	bra	mainloop

checkgameover:
	bsr	addscores
	tst.b	schu			all your counters turned
	beq	showresults
	tst.b	scco			all my counters turned
	beq	showresults
	move.b	scco,d0
	add.b	schu,d0
	cmp.b	#64,d0			all squares filled
	beq	showresults
	tst.b	mepass
	beq	endcheck
	tst.b	youpass
	bne	showresults		both players pass (ie, stalemate)
endcheck:
	rts
showresults:
	move.b	#1,gameover
	move.b	scco,d0
	cmp.b	schu,d0
	bls	menotwin
	lea	result1(pc),a1		print 'I win'
	bra	print
menotwin:
	beq	mustbedraw
	lea	result2(pc),a1
	bra	print			print 'You win'
mustbedraw:
	lea	result3(pc),a1
	bra	print			print 'Draw'

* * * * * * * * * * * * * * *
closeclicked:
	move.l	d0,a1
	CALLEXEC ReplyMsg

closewin:
	move.l	windowptr(pc),a0
	CALLINT CloseWindow

closeall:				;close library
	move.l	_IntuitionBase,a1
	CALLEXEC	CloseLibrary
closegraf:
	move.l	_GfxBase,a1
	CALLEXEC	CloseLibrary
goawayfast:				;exit game
	moveq	#0,d0
	rts

* * * * * * * * * * * * * * *
moveto:	move.l	windowptr(pc),a1	move to a point d0,d1
	move.l	wd_RPort(a1),a1
	CALLGRAF Move
	rts
drawto:	move.l	windowptr(pc),a1	draw to a point d0,d1
	move.l	wd_RPort(a1),a1
	CALLGRAF Draw
	rts

cleargrid:				;clear window and grid
	lea	board(pc),a0
	move.l	#99,d0
clgr:	move.b	#0,(a0)+
	subq	#1,d0
	bpl	clgr
	move.l	windowptr(pc),a1
	move.l	wd_RPort(a1),a1
	moveq	#0,d0
	CALLGRAF SetAPen
	move	#1,d0
	move	#11,d1
	move	#159,d2
	move	#125,d3
	CALLGRAF RectFill
	rts

clearmessagebox:
	move.l	windowptr(pc),a1
	move.l	wd_RPort(a1),a1
	moveq	#0,d0
	CALLGRAF SetAPen
	move	#1,d0
	move	#102,d1
	move	#159,d2
	move	#111,d3
	CALLGRAF RectFill
	rts
	
print:	move.l	windowptr(pc),a0	Prints message at a1
	move.l	wd_RPort(a0),a0
	move	4(a1),d0
	move	6(a1),d1
	CALLINT PrintIText
	rts

rnd:	movem.l	d1,-(sp)		Rnd number in d0 from 0 to d0-1
	move.b	$bfe801,d1		Uses internal timer and
	ror	rndseed			initial seed
	eor.b	d1,rndseed
	move.b	rndseed,d1
	mulu	d1,d0
	lsr.l	#8,d0
	movem.l	(sp)+,d1
	rts

addscores:				;adds up current scores
	movem.l	d0-d1/a0-a1,-(sp)
	move	#0,schu
	lea	board(pc),a0
	move	#11,d1
addlp:	move.b	(a0)+,d0
	cmp.b	col2,d0			human counter
	bne	add3
	addq.b	#1,schu
	bra	add4
add3:	tst.b	d0			comp counter
	beq	add4
	addq.b	#1,scco
add4:	addq	#1,d1
	cmp	#100,d1
	bne	addlp

	move.b	scco,d0			print scores
	lea	compscore(pc),a0
	bsr	dectoasc
	move.b	schu,d0
	lea	humscore(pc),a0
	bsr	dectoasc
	lea	score1(pc),a1
	bsr	print
	lea	score2(pc),a1
	bsr	print
	movem.l	(sp)+,d0-d1/a0-a1
	rts

dectoasc:				;convert decimal to asc
	and.l	#$ff,d0			a0=destination buffer, d0=number
	divu	#10,d0			divides by 10 to get tens+units
	add.b	#$30,d0
	move.b	d0,(a0)+
	swap	d0
	add.b	#$30,d0
	move.b	d0,(a0)
	rts

putoncounter:				;places counter in position d4
	movem.l	d1-d3/a1,-(sp)		colour d0
	and.l	#$ff,d4
	lea	board(pc),a1
	add	d4,a1			find square address
	move.b	d0,(a1)			put in counter
	divu	#10,d4			perform: x=counter MOD 10
	move	d4,d3				 y=counter DIV 10
	swap	d4
	move	d4,d2
	mulu	#20,d2			exact window coords of counter
	sub	#16,d2
	mulu	#10,d3
	add	#12,d3

	and	#$f,d0			draw counter at d2,d3
	move.l	windowptr(pc),a1
	move.l	wd_RPort(a1),a1
	CALLGRAF SetAPen		set colour
	move	d2,d0
	move	d3,d1
	add	#12,d2
	add	#6,d3
	CALLGRAF RectFill		draw rectangle
	movem.l	(sp)+,d1-d3/a1
	rts

getmove:				;gets mouse coords for human move
	move.b	#0,youpass
	move	#0,numturn
	move.l	windowptr(pc),a1
	move.l	#0,d0
	move.l	#0,d1
	move	wd_MouseX(a1),d0	x pos in d0
	move	wd_MouseY(a1),d1	y pos in d1
	tst	d0
	bmi	nomove			off left side
	cmp	#159,d0
	bhi	nomove			off right side
	divu	#20,d0			get grid column
	addq	#1,d0

	cmp	#20,d1
	blt	nomove			above grid
	cmp	#112,d1
	bhs	checkrequest		below requestor level
	cmp	#99,d1
	bhi	nomove			below grid
	sub	#20,d1
	divu	#10,d1			get grid row
	addq	#1,d1

	moveq.l	#10,d4			convert to square number
	mulu	d1,d4			counter = y*10+x
	add	d0,d4
	move	d4,counter
	move	#0,dontturn
	move.b	col2,player
	bsr	turncounters		check counters will be turned
	tst	numturn
	beq	nomove			escape if none are
	move	#1,dontturn
	bra	turncounters		or turn them over

nomove:	rts

checkrequest:
	cmp	#124,d1			finds if within boxes
	bhs	nomove
	cmp	#5,d0
	bhs	chosenewgame
chosemissgo:				;choose Miss Go box
	move.b	col2,player		checks if you can play first
	bsr	findbestmove
	move	0,numturn
	tst	bestcounter		so no cheating
	bne	nomove
	move.b	#1,youpass
	move	#1,numturn
	rts


chosenewgame:				;chose Restart box
	move.b	#1,newgameflag
	rts


;The computer simply plays towards the strongest square according
;to the weights at the end of the program

computer:				;finds best move for computer
	tst.b	gameover
	bne	fincomp
	move.b	#0,mepass
	move.b	col1,player	
	bsr	findbestmove
	tst	bestcounter
	beq	cantplay		branches if no counters are turned
	move	bestcounter,counter
	move	#1,dontturn
	bra	turncounters
fincomp:
	rts

cantplay:
	lea	message1(pc),a1		prints pass message
	bsr	print
	move.b	#1,mepass
	move.b	$bfe801,d0
 	add.b	#50,d0
pause:	cmp.b	$bfe801,d0		pause for 1 sec
	bne	pause
	bra	clearmessagebox

;This finds the strongest square for the computer from weighting.
;Also used to check if human can actually play.

findbestmove:
	move	#0,numturn
	move	#0,bestcounter		sets best position to 0
	move	#$ff,best		sets lowest (strongest) score
	move	#0,dontturn
	move	#11,counter		first square
loop1:	move	#8,d2
loop2:	bsr	turncounters
	tst	numturn
	beq	endloop2
	lea	weights(pc),a0		gets weighting of square
	add	counter,a0
	move.b	(a0),d0
	and	#$ff,d0

	cmp	best,d0			less than best so end
	bhi	endloop2
	blo	notrnd			higher than best
	move	d0,d1
	moveq	#10,d0			equal to best so decide
	bsr	rnd			randomly which is best
	exg	d0,d1
	cmp	#4,d1
	bhi	notrnd
	addq	#6,d0
notrnd:	cmp	best,d0			compare weight to best
	bhi	endloop2
	move	d0,best			swap if better
	move	counter,bestcounter

endloop2:
	addq	#1,counter
	sub	#1,d2
	bne	loop2
endloop1:
	addq	#2,counter
	cmp	#91,counter
	blo	loop1
	rts	

;This turns the relevant counters from move in 'counter'

turncounters:				;grid address in a0
	move	#0,numturn		requires d0,d4,d5,d7
	lea	board(pc),a0		d1 is number turned in each direction
	add	counter,a0
	tst.b	(a0)			see if already counter there
	bne	illegal
	move	counter,pos
	moveq	#0,d3			look dirn pointer
	move.l	#8,d7
	tst	dontturn
	beq	lookloop
	move	pos,d4
	move.b	player,d0
	bsr	putoncounter
lookloop:
	moveq	#0,d1
	lea	dir(pc),a1		get direction into d5
	add	d3,a1
	move	(a1),d5

moveone:				;move along row in given dirn
	add	d5,pos
	lea	board(pc),a0
	add	pos,a0
	move.b	(a0),d0			get board position to test
	beq	endlookloop		stop if there isn't a counter
	cmp.b	player,d0
	beq	mypiece			end look if players counter
	addq	#1,d1			increase count and
	bra	moveone			continue if opponents counter
mypiece:
	add	d1,numturn
	tst	dontturn
	beq	endlookloop		don't turn if dontturn=0

	tst	d1
	beq	endlookloop
	move	counter,pos

turnover:				;flip over row of counters
	add	d5,pos			move along row
	move	pos,d4
	move.b	player,d0
	bsr	putoncounter
	dbne	d1,turnover

endlookloop:
	move	counter,pos
	addq	#2,d3			increase direction pointer
	dbeq	d7,lookloop

illegal:
	rts

	even
rndseed:	dc.w	0
newgameflag:	dc.b	0
gameover:	dc.b	0
youpass:	dc.b	0
mepass:		dc.b	0
numturn:	dc.w	0
dontturn:	dc.w	0
pos:		dc.w	0
counter:	dc.w	0
best:		dc.w	0
bestcounter:	dc.w	0
schu:		dc.b	0
scco:		dc.b	0
player:		dc.b	0
	even
dir:		dc.w	11,10,9,1,-1,-9,-10,-11


intname		INTNAME				name of intuition lib
grafname	GRAFNAME			name of graphics library

_IntuitionBase	dc.l	0			for int library
_GfxBase	dc.l	0			for graphics library
	even
windowdef:
	dc.w	10				x pos
	dc.w	20				y pos
	dc.w	161				width
	dc.w	127				height
	dc.b	1,3				colours
	dc.l	MOUSEBUTTONS!CLOSEWINDOW	;IDCMP flags
	dc.l	WINDOWDRAG!WINDOWDEPTH!WINDOWCLOSE!ACTIVATE!RMBTRAP
	dc.l	0
	dc.l	0
	dc.l	windowname
	dc.l	0				no screen
	dc.l	0				no bitmap
	dc.w	0,0,0,0				size not need
	dc.w	WBENCHSCREEN

windowname:	dc.b 'Othello',0
	even
windowptr:	dc.l	0

;messages to be printed

score1:
col1:		dc.b	1,0,1
	even
		dc.w	4,6
		dc.l	0,sco1,0
sco1:		dc.b 'Me   00',0
compscore = sco1+5

score2:
col2:		dc.b	2,0,1
	even
		dc.w	44,6
		dc.l	0,sco2,0
sco2:		dc.b 'You  00',0
humscore = sco2+5
	even

requestor:	dc.b	1,0,1
	even
		dc.w	7,58
		dc.l	0,reques,0
reques:		dc.b	'Miss Go   Restart',0
	even

message1:	dc.b	1,0,1
	even
		dc.w	16,52
		dc.l	0,mess1,0
mess1:		dc.b	'I can',39,'t play',0
	even
message2:	dc.b	2,0,1
	even
		dc.w	12,52
		dc.l	0,mess2,0
mess2:		dc.b	'Click to begin',0
	even

result1:	dc.b	1,0,1
	even
		dc.w	28,52
		dc.l	0,res1,0
res1:		dc.b	'I WIN!',0
	even
result2:	dc.b	1,0,1
	even
		dc.w	25,52
		dc.l	0,res2,0
res2:		dc.b	'YOU WIN!',0
	even
result3:	dc.b	1,0,1
	even
		dc.w	16,52
		dc.l	0,res3,0
res3:		dc.b	'IT',39,'S A DRAW!',0

	even
board:		dcb.b	100,0

weights:	dc.b	0,  0,  0,  0,  0,  0,  0,  0,  0,  0
		dc.b	0,  0,100,  4, 10, 10,  4,100,  0,  0
		dc.b	0,100,126,  3, 69, 69,  3,126,100,  0
		dc.b	0,  4, 50,  6, 11, 11,  6, 50,  4,  0
		dc.b	0, 10, 69, 11,  0,  0, 11, 69, 10,  0
		dc.b	0, 10, 69, 11,  0,  0, 11, 69, 10,  0
		dc.b	0,  4,  3,  6, 11, 11,  6,  3,  4,  0
		dc.b	0,100,126, 50, 69, 69, 50,126,100,  0
		dc.b	0,  0,100,  4, 10, 10,  4,100,  0,  0
		dc.b	0,  0,  0,  0,  0,  0,  0,  0,  0,  0

;The weightings make the computer play towards the counters
;The lower the value the stronger the square

