Microchess

microchess
6502 Microchess

Many years ago, when a 6502 and a few k or RAM were cutting edge in home computing, I tried, and failed, to get the KIM version of MicroChess to run on my Compukit UK101.

I recently found the source and, in a fit of nostalgia, made this version which runs on Michal Kowalski’s 6502 simulator.
This version is posted with the permission of Peter Jennings.

The program
Once you have the source (see later) you will need to load it into the simulator, assemble it, and the run it in the debugger.

The game

Notation

Each square on the chess board is identified by a two digit number as shown here. The first digit specifies the rank (0x to 7x) from the computer’s end of the board. The second digit specifies the file (x0 to x7) from the player’s left. Moves are made by the FROM square and the TO square using this notation.
rowncol

Command keys

Few keys are needed to play. The original KIM had only a hex kaypad and a few command keys. This version has code to interpret standard ASCII codes in their place. Alpha keys can be used in either upper or lower case, both have the same effect.

[C] This key [C]lears the internal chessboard and resets it to begin another game. The board is set up with the computer playing white.
? Reset    00 00‘ is displayed instead of a move to indicate that the board has been reset.
[E] This key [E]xchanges the two sets of pieces without the actual
position of the board being changed.
? Exchange 00 00‘ is displayed instead of a move to indicate that the exchange has been made.
If [C] then [E] is pressed, the board will be set up to begin a game with the computer playing black.
If [P] followed by [E] followed by [P], and so on, is pressed the computer will play a game against itself.
[P] This key tells the computer to [P]lay its move. While the computer decides on the best move it will flash the ‘?’ character on the move line and, sometimes, display the move it’s deciding on.
[ENTER] This key is used to register the player’s move. It moves the piece on the FROM square to the TO square. This can be used to move one of the computer’s men if desired.

status
Entering moves

Your moves are entered into the game numerically using the notation described above. You do not enter piece being moved, just the FROM and TO square locations.

As move numbers are entered they scroll from right to left through the TO and FROM digits, the FROM square piece is updated after every key. Should you make an error while entering the move just re-enter the move and the display will scroll to the left until the correct move is displayed.

While you are entering your move the piece located on the FROM square is displayed on the left of the status line after the ‘?‘ character. There is no indication of the pieces colour, it is up to you to move only your own pieces.

When you are sure the move you’ve entered is the correct one press the [ENTER] key to register the move on the board. Once you have pressed [ENTER] the display confirms the move by showing the piece now in the TO square and the FROM and TO squares.

You may make as many moves like this as you wish and may move either your own men or the computer’s. No check on the legality of the move is carried out. Illegal moves will be executed just as legal moves, so you should be carefull that you do not accidentally make an illegal move. There is no warning if your king is in check, you must be careful not to leave this situation after your move. If you do the computer will usually take your king on its next move if possible.

The source.

The source is changed from the original source to use the ASCII input/output of the simulator. This roughly follows the suggestions in the KIM MicroChess programmers manual on teletype I/O.

Where code has been added it has lower case comments and where code has been changed the original code has usually been commented out, but otherwise left in place. The main strategy and computer play routines are essentially unchanged from the original.

The OCRed source that I worked from had some transcription errors. Though I found and corrected some, others may remain.

You can either view the source as html or download the source as a zip archive.

; MicroChess (c) 1976-2002 Peter Jennings, peterj@benlo.com

; this version for the integrated macroassembler, simulator and debugger for
; 650x microprocessor family by Michal Kowalski 
; additions and changes by Lee Davison 
; from suggested ASCII routines in the KIM MicroChess programmers notes

; this version is posted with the permission of Peter Jennings

; display flash during compute move replaced by '?' prompt flash
; piece display changed to display piece at 'to' square after each move

; Simulator I/O base addresse is $F000
; Simulator window size is 64 columns x 20 rows

IO_AREA	= $F000

ACIAsimwr	= IO_AREA+$01
ACIAsimrd	= IO_AREA+$04
DispPosX	= IO_AREA+$05
DispPosY	= IO_AREA+$06

; page zero variables

BOARD		= $50
BK		= $60
PIECE		= $B0
SQUARE		= $B1
SP2		= $B2
SP1		= $B3
INCHEK		= $B4
STATE		= $B5
MOVEN		= $B6
OMOVE		= $DC
WCAP0		= $DD
COUNT		= $DE
BCAP2		= $DE
WCAP2		= $DF
BCAP1		= $E0
WCAP1		= $E1
BCAP0		= $E2
MOB		= $E3
MAXC		= $E4
CC		= $E5
PCAP		= $E6
BMOB		= $E3
BMAXC		= $E4
_BCC		= $E5 			; was BCC
BMAXP		= $E6
XMAXC		= $E8
WMOB		= $EB
WMAXC		= $EC
WCC		= $ED
WMAXP		= $EE
PMOB		= $EF
PMAXC		= $F0
PCC		= $F1
PCP		= $F2
OLDKY		= $F3
BESTP		= $FB
BESTV		= $FA
BESTM		= $F9
DIS1		= $FB
DIS2		= $FA
DIS3		= $F9

prompt		= $FC			; prompt character, '?' or ' '
reverse		= $FD			; which way round is the display board

		*=$1000			; load into RAM @ $1000 onwards

CHESS
	CLD				; INITIALIZE
	LDX	#$FF			; TWO STACKS
	TXS	
	LDX	#$C8
	STX	SP2

;	ROUTINES TO LIGHT LED
;	DISPLAY AND GET KEY
;	FROM KEYBOARD

OUT
	JSR	DrawBoard		; draw board
	LDA	#'?'			; prompt character
	STA	prompt			; save it
GetKey
	JSR	UpdateDisp		; update prompt & display
	JSR	asciiin			; get key press

	CMP	#'C'			; is it "C"
	BNE	NOSET			; branch if not

					; else set up board
	LDX	#$1F			; 32 pieces to do
WHSET
	LDA	SETW,X			; FROM
	STA	BOARD,X			; SETW
	DEX	
	BPL	WHSET

	LDA	#$00			; no reverse
	STA	reverse			; set it

	LDX	#$1B			; *ADDED
	STX	OMOVE			; INITS TO $FF
	LDA	#$CC			; Display CCC
	BNE	CLDSP

NOSET
	CMP	#'E'			; [E]
	BNE	NOREV			; REVERSE

	JSR	REVERSE			; BOARD IS

	LDA	reverse			; get reversed flag
	EOR	#$01			; toggle reverse bit
	STA	reverse			; save flag

	LDA	#$EE			; IS
	BNE	CLDSP

NOREV
	CMP	#'P'			; [P]
	BNE	NOGO			; PLAY CHESS

	JSR	GO
CLDSP
	STA	DIS1			; DISPLAY
	LDA	#$00
	STA	DIS2			; ACROSS
	STA	DIS3			; DISPLAY
	BEQ	CHESS

NOGO
	CMP	#$0D			; [Enter]
	BNE	NOMV			; MOVE MAN

	JSR	MOVE			; AS ENTERED
;	JSR	DISP2			; piece into display
	JSR	DISP3			; piece into display
	JMP	CHESS			; main loop

NOMV
;	CMP	#'Q'			; [Q] ***Added to allow game exit***
;	BEQ	DONE			; quit the game, exit back to system.

; removed from simulator version as no system!

	JMP	INPUT			; process move
;DONE
;	JMP	$FF00			; *** MUST set this to YOUR OS starting address

;	THE ROUTINE JANUS DIRECTS THE
;	ANALYSIS BY DETERMINING WHAT
;	SHOULD OCCUR AFTER EACH MOVE
;	GENERATED BY GNM

JANUS
	LDX	STATE
	BMI	NOCOUNT

;	THIS ROUTINE COUNTS OCCURRENCES
;	IT DEPENDS UPON STATE TO INDEX
;	THE CORRECT COUNTERS

COUNTS
	LDA	PIECE
	BEQ	OVER			; IF STATE=8
	CPX 	#$08			; DO NOT COUNT
	BNE	OVER			; BLK MAX CAP
	CMP	BMAXP			; MOVES FOR
	BEQ	XRT			; WHITE

OVER
	INC	MOB,X			; MOBILITY
	CMP 	#$01			;	+ QUEEN
	BNE	NOQ			; FOR TWO
	INC	MOB,X

NOQ
	BVC	NOCAP
	LDY	#$0F			; CALCULATE
	LDA	SQUARE			; POINTS
ELOOP
	CMP	BK,Y			; CAPTURED
	BEQ	FOUN			; BY THIS
	DEY				; MOVE
	BPL	ELOOP
FOUN
	LDA	POINTS,Y
	CMP	MAXC,X
	BCC	LESS			; SAVE IF
	STY	PCAP,X			; BEST THIS
	STA	MAXC,X			; STATE

LESS
	CLC
	PHP				; ADD TO
	ADC	CC,X			; CAPTURE
	STA	CC,X			; COUNTS
	PLP

NOCAP
	CPX	#$04
	BEQ	ON4
	BMI	TREE			; (=00 ONLY)
XRT
	RTS

;	GENERATE FURTHER MOVES FOR COUNT
;	AND ANALYSIS

ON4
	LDA	XMAXC			; SAVE ACTUAL
	STA	WCAP0			; CAPTURE
	LDA	#$00			; STATE=0
	STA	STATE
	JSR	MOVE			; GENERATE
	JSR	REVERSE			; IMMEDIATE
	JSR	GNMZ			; REPLY MOVES
	JSR	REVERSE

	LDA	#$08			; STATE=8
	STA	STATE			; GENERATE
	JSR	GNM			; CONTINUATION
	JSR	UMOVE			; MOVES

	JMP	STRATGY			; FINAL EVALUATION
NOCOUNT
	CPX	#$F9
	BNE	TREE

;	DETERMINE IF THE KING CAN BE
;	TAKEN, USED BY CHKCHK

	LDA	BK			; IS KING
	CMP	SQUARE			; IN CHECK?
	BNE	RETJ			; SET INCHEK=0
	LDA	#$00			; IF IT IS
	STA	INCHEK
RETJ
	RTS

;	IF A PIECE HAS BEEN CAPTURED BY
;	A TRIAL MOVE, GENERATE REPLIES &
;	EVALUATE THE EXCHANGE GAIN/LOSS

TREE
	BVC	RETJ			; NO CAP
	LDY	#$07			; (PIECES)
	LDA	SQUARE
LOOPX
	CMP	BK,Y
	BEQ	FOUNX
	DEY	
	BEQ	RETJ			; (KING)
	BPL	LOOPX			; SAVE
FOUNX
	LDA	POINTS,Y		; BEST CAP
	CMP	BCAP0,X			; AT THIS
	BCC	NOMAX			; LEVEL
	STA	BCAP0,X
NOMAX
	DEC	STATE
	LDA	#$FB			; IF STATE=FB
	CMP	STATE			; TIME TO TURN
	BEQ	UPTREE			; AROUND
	JSR	GENRM			; GENERATE FURTHER
UPTREE
	INC	STATE			; CAPTURES
	RTS

;	THE PLAYER'S MOVE IS INPUT

INPUT
	SEC				; set for subtract
	SBC	#'0'			; convert ASCII # to binary

	CMP	#$08			; NOT A LEGAL
	BCS	ERROR			; SQUARE #

	JSR	DISMV
	JSR	DISP2			; put piece into display
ERROR
	JMP	GetKey			; go update move display and wait for next key
;	JMP	CHESS

DISP3
	LDA	DIS3			; get position
	.byte	$2C			; make next LDA into BIT xxxx
DISP2
	LDA	DIS2			; get position
	LDX	#$1F
SEARCH
	CMP	BOARD,X			; compare with this piece's position
;	LDA	BOARD,X
;	CMP	DIS2
	BEQ	HERE			; DISPLAY
	DEX				; PIECE AT
	BPL	SEARCH			; FROM
	LDX	#$BB			; blank square if no matching piece
HERE
	STX	DIS1			; SQUARE
	STX	PIECE
	RTS

;	GENERATE ALL MOVES FOR ONE
;	SIDE, CALL JANUS AFTER EACH
;	ONE FOR NEXT STE?

GNMZ
	LDX	#$10			; CLEAR
GNMX
	LDA	#$00			; COUNTERS
CLEAR
	STA	COUNT,X
	DEX
	BPL	CLEAR

GNM
	LDA	#$10			; SET UP
	STA	PIECE			; PIECE
NEWP
	DEC	PIECE			; NEW PIECE
	BPL	NEX			; ALL DONE?
	RTS				; #NAME?

NEX
	JSR	RESET			; READY
	LDY	PIECE			; GET PIECE
	LDX	#$08
	STX	MOVEN			; COMMON START
	CPY	#$08			; WHAT IS IT?
	BPL	PAWN			; PAWN
	CPY	#$06
	BPL	KNIGHT			; KNIGHT
	CPY	#$04
	BPL	BISHOP			; BISHOP
	CPY	#$01
	BEQ	QUEEN			; QUEEN
	BPL	ROOK			; ROOK

KING
	JSR	SNGMV			; MUST BE KING!
	BNE	KING			; MOVES
	BEQ	NEWP			; 8 TO 1
QUEEN
	JSR	LINE
	BNE	QUEEN			; MOVES
	BEQ	NEWP			; 8 TO 1

ROOK
	LDX	#$04
	STX	MOVEN			; MOVES
AGNR
	JSR	LINE			; 4 TO 1
	BNE	AGNR
	BEQ	NEWP

BISHOP
	JSR	LINE
	LDA	MOVEN			; MOVES
	CMP	#$04			; 8 TO 5
	BNE	BISHOP
	BEQ	NEWP

KNIGHT
	LDX	#$10
	STX	MOVEN			; MOVES
AGNN
	JSR	SNGMV			; 16 TO 9
	LDA	MOVEN
	CMP	#$08
	BNE	AGNN
	BEQ	NEWP

PAWN
	LDX	#$06
	STX	MOVEN
P1
	JSR	CMOVE			; RIGHT CAP?
	BVC	P2
	BMI	P2
	JSR	JANUS			; YES
P2
	JSR	RESET
	DEC	MOVEN			; LEFT CAP?
	LDA	MOVEN
	CMP	#$05
	BEQ	P1
P3
	JSR	CMOVE			; AHEAD
	BVS	NEWP			; ILLEGAL
	BMI	NEWP
	JSR	JANUS
	LDA	SQUARE			; GETS TO
	AND	#$F0			; 3RD RANK?
	CMP	#$20
	BEQ	P3			; DO DOUBLE
	JMP	NEWP

;	CALCULATE SINGLE STEP MOVES
;	FOR K,N

SNGMV
	JSR	CMOVE			; CALC MOVE
	BMI	ILL1			; -IF LEGAL
	JSR	JANUS			; -EVALUATE
ILL1
	JSR	RESET
	DEC	MOVEN
	RTS

;	CALCULATE ALL MOVES DOWN A
;	STRAIGHT LINE FOR Q,B,R

LINE
	JSR	CMOVE			; CALC MOVE
	BCC	OVL			; NO CHK
	BVC	LINE			; NOCAP
OVL
	BMI	ILL			; RETURN
	PHP
	JSR	JANUS			; EVALUATE POSN
	PLP
	BVC	LINE			; NOT A CAP
ILL
	JSR	RESET			; LINE STOPPED
	DEC	MOVEN			; NEXT DIR
	RTS

;	EXCHANGE SIDES FOR REPLY
;	ANALYSIS

REVERSE
	LDX	#$0F
ETC
	SEC
	LDY	BK,X			; SUBTRACT
	LDA 	#$77			; POSITION
	SBC	BOARD,X			; FROM 77
	STA	BK,X
	STY	BOARD,X			; AND
	SEC
	LDA	#$77			; EXCHANGE
	SBC 	BOARD,X			; PIECES
	STA	BOARD,X
	DEX
	BPL	ETC
	RTS

;	CMOVE CALCULATES THE TO SQUARE
;	USING SQUARE AND THE MOVE
;	TABLE	FLAGS SET AS FOLLOWS:
;	N#NAME?	MOVE
;	V#NAME?	(LEGAL UNLESS IN CR)
;	C#NAME?	BECAUSE OF CHECK
;	[MY &THANKS TO JIM BUTTERFIELD
;	WHO WROTE THIS MORE EFFICIENT
;	VERSION OF CMOVE)

CMOVE
	LDA	SQUARE			; GET SQUARE
	LDX	MOVEN			; MOVE POINTER
	CLC
	ADC	MOVEX,X			; MOVE LIST
	STA	SQUARE			; NEW POS'N
	AND	#$88
	BNE	ILLEGAL			; OFF BOARD
	LDA	SQUARE

	LDX	#$20
LOOP
	DEX				; IS TO
	BMI	NO			; SQUARE
	CMP	BOARD,X			; OCCUPIED?
	BNE	LOOP

	CPX	#$10			; BY SELF?
	BMI	ILLEGAL

	LDA	#$7F			; MUST BE CAP!
	ADC	#$01			; SET V FLAG
	BVS	SPX 			; (JMP)

NO
	CLV				; NO CAPTURE

SPX
	LDA	STATE			; SHOULD WE
	BMI	RETL			; DO THE
	CMP	#$08 			; CHECK CHECK?
	BPL	RETL

;	CHKCHK REVERSES SIDES
;	AND LOOKS FOR A KING
;	CAPTURE TO INDICATE
;	ILLEGAL MOVE BECAUSE OF
;	CHECK	SINCE THIS IS
;	TIME CONSUMING, IT IS NOT
;	ALWAYS DONE	

CHKCHK
	PHA				; STATE	#392
	PHP
	LDA	#$F9
	STA	STATE			; GENERATE
	STA	INCHEK			; ALL REPLY
	JSR	MOVE			; MOVES TO
	JSR	REVERSE			; SEE IF KING
	JSR	GNM			; IS IN
	JSR	RUM			; CHECK
	PLP
	PLA
	STA	STATE
	LDA	INCHEK
	BMI	RETL			; NO - SAFE
	SEC				; YES - IN CHK
	LDA	#$FF
	RTS

RETL
	CLC				; LEGAL
	LDA	#$00			; RETURN
	RTS

ILLEGAL
	LDA	#$FF
	CLC				; ILLEGAL
	CLV				; RETURN
	RTS

;	REPLACE PIECE ON CORRECT SQUARE

RESET
	LDX	PIECE			; GET LOGAT
	LDA	BOARD,X			; FOR PIECE
	STA	SQUARE			; FROM BOARD
	RTS

GENRM
	JSR	MOVE			; MAKE MOVE
GENR2
	JSR	REVERSE			; REVERSE BOARD
	JSR	GNM			; GENERATE MOVES
RUM
	JSR	REVERSE			; REVERSE BACK

;	ROUTINE TO UNMAKE A MOVE MADE BY
;	MOVE

UMOVE
	TSX				; UNMAKE MOVE
	STX	SP1
	LDX	SP2			; EXCHANGE
	TXS				; STACKS
	PLA				; MOVEN
	STA	MOVEN
	PLA				; CAPTURED
	STA	PIECE			; PIECE
	TAX
	PLA				; FROM SQUARE
	STA	BOARD,X
	PLA				; PIECE
	TAX
	PLA				; TO SOUARE
	STA	SQUARE
	STA	BOARD,X
	JMP	STRV

;	THIS ROUTINE MOVES PIECE
;	TO SQUARE, PARAMETERS
;	ARE SAVED IN A STACK TO UNMAKE
;	THE MOVE LATER

MOVE
	TSX	
	STX	SP1			; SWITCH
	LDX	SP2			; STACKS
	TXS	
	LDA	SQUARE
	PHA				; TO SQUARE
	TAY	
	LDX	#$1F
CHECK
	CMP	BOARD,X			; CHECK FOR
	BEQ	TAKE			; CAPTURE
	DEX	
	BPL	CHECK
TAKE
	LDA	#$CC
	STA	BOARD,X
	TXA				; CAPTURED
	PHA				; PIECE
	LDX	PIECE
	LDA	BOARD,X
	STY	BOARD,X			; FROM
	PHA				; SQUARE
	TXA
	PHA				; PIECE
	LDA	MOVEN
	PHA				; MOVEN
STRV
	TSX
	STX	SP2			; SWITCH
	LDX	SP1			; STACKS
	TXS				; BACK
	RTS

;	CONTINUATION OF SUB STRATGY
;	-CHECKS FOR CHECK OR CHECKMATE
;	AND ASSIGNS VALUE TO MOVE

CKMATE
	LDY	BMAXC			; CAN BLK CAP
	CPX	POINTS			; MY KING?
	BNE	NOCHEK
	LDA	#$00			; GULP!
	BEQ	RETV			; DUMB MOVE!

NOCHEK
	LDX	BMOB			; IS BLACK
	BNE	RETV			; UNABLE TO
	LDX	WMAXP			; MOVE AND
	BNE	RETV			; KING IN CH?
	LDA	#$FF			; YES! MATE

RETV
	LDX	#$04			; RESTORE
	STX	STATE			; STATE=4

;	THE VALUE OF THE MOVE (IN ACCU)
;	IS COMPARED TO THE BEST MOVE AND
;	REPLACES IT IF IT IS BETTER

PUSH
	CMP	BESTV			; IS THIS BEST
	BCC	RETP			; MOVE SO FAR?
	BEQ	RETP
	STA	BESTV			; YES!
	LDA	PIECE			; SAVE IT
	STA	BESTP
	LDA	SQUARE
	STA	BESTM			; FLASH DISPLAY
RETP
	LDA	prompt			; get prompt character
	EOR	#$1F			; toggle between [SPACE] and '?'
	STA	prompt			; save it back			
	JMP	UpdateDisp		; update prompt & display

;	MAIN PROGRAM TO PLAY CHESS
;	PLAY FROM OPENING OR THINK

GO
	LDX	OMOVE			; OPENING?
	BMI	NOOPEN			; -NO	*ADD CHANGE FROM BPL
	LDA	DIS3			; -YES WAS
	CMP	OPNING,X		; OPPONENT'S
	BNE	END			; MOVE OK?
	DEX
	LDA	OPNING,X		; GET NEXT
	STA	DIS1			; CANNED
	DEX				; OPENING MOVE
	LDA	OPNING,X
	STA	DIS3			; DISPLAY IT
	DEX
	STX	OMOVE			; MOVE IT
	BNE	MV2			; (JMP)

END
	LDA	#$FF			; *ADD - STOP CANNED MOVES
	STA	OMOVE			; FLAG OPENING
NOOPEN
	LDX	#$0C			; FINISHED
	STX	STATE			; STATE=C
	STX	BESTV			; CLEAR BESTV
	LDX	#$14			; GENERATE P
	JSR	GNMX			; MOVES

	LDX	#$04			; STATE=4
	STX	STATE			; GENERATE AND
	JSR	GNMZ			; TEST AVAILABLE
;
;	MOVES

	LDX	BESTV			; GET BEST MOVE
	CPX	#$0F			; IF NONE
	BCC	MATE			; OH OH!

MV2
	LDX	BESTP			; MOVE
	LDA	BOARD,X			; THE
	STA	BESTV			; BEST
	STX	PIECE			; MOVE
	LDA	BESTM
	STA	SQUARE			; AND DISPLAY
	JSR	MOVE			; IT

	JSR	DISP3			; piece into display

	JMP	CHESS

MATE
	LDA	#$FF			; RESIGN
	RTS				; OR STALEMATE

;	SUBROUTINE TO ENTER THE
;	PLAYER'S MOVE

DISMV
	LDX	#$04			; ROTATE
DROL
	ASL	DIS3			; KEY
	ROL	DIS2			; INTO
	DEX				; DISPLAY
	BNE	DROL			;

	ORA	DIS3
	STA	DIS3
	STA	SQUARE
	RTS

;	THE FOLLOWING SUBROUTINE ASSIGNS
;	A VALUE TO THE MOVE UNDER
;	CONSIDERATION AND RETURNS IT IN
;	THE ACCUMULATOR


STRATGY
	CLC
	LDA	#$80
	ADC	WMOB			; PARAMETERS
	ADC	WMAXC			; WITH WHEIGHT
	ADC	WCC			; OF O25
	ADC	WCAP1
	ADC	WCAP2
	SEC
	SBC	PMAXC
	SBC	PCC
	SBC	BCAP0
	SBC	BCAP1
	SBC	BCAP2
	SBC	PMOB
	SBC	BMOB
	BCS	POS			; UNDERFLOW
	LDA	#$00			; PREVENTION
POS
	LSR
	CLC				; **************
	ADC	#$40
	ADC	WMAXC			; PARAMETERS
	ADC	WCC			; WITH WEIGHT
	SEC				; OF 05
	SBC	BMAXC
	LSR				; **************
	CLC
	ADC	#$90
	ADC	WCAP0			; PARAMETERS
	ADC	WCAP0			; WITH WEIGHT
	ADC	WCAP0			; OF 10
	ADC	WCAP0
	ADC	WCAP1
	SEC				; [UNDER OR OVER-
	SBC	BMAXC			; FLOW MAY OCCUR
	SBC	BMAXC			; FROM THIS
	SBC	_BCC			; SECTION]
	SBC	_BCC
	SBC	BCAP1
	LDX	SQUARE			; ***************
	CPX	#$33
	BEQ	POSN			; POSITION
	CPX	#$34			; BONUS FOR
	BEQ	POSN			; MOVE TO
	CPX	#$22			; CENTRE
	BEQ	POSN			; OR
	CPX	#$25			; OUT OF
	BEQ	POSN			; BACK RANK
	LDX	PIECE
	BEQ	NOPOSN
	LDY	BOARD,X
	CPY	#$10
	BPL	NOPOSN
POSN
	CLC
	ADC	#$02
NOPOSN
	JMP	CKMATE			; CONTINUE

; most new code from here on

; update move display, do prompt, piece, 'FROM' and 'TO' squares

UpdateDisp
	LDA	#$26			; set cursor X
	STA	DispPosX		; set cursor X
	LDA	#$08			; set cursor Y
	STA	DispPosY		; set cursor Y
	LDA	prompt			; prompt
	JSR	asciiout		; byte out to display
	JSR	space			; [SPACE] out to display

	JSR	DisPiece		; display piece (from byte in DIS1)

	JSR	space			; [SPACE] out to display
	LDA	DIS2			; 2nd display byte
	JSR	PSquare			; Print square
	JSR	space			; [SPACE] out to display
	LDA	DIS3			; 3rd display byte
	JMP	PSquare			; Print square

; draw board on an ASCII character display
; the display in the simulator has cursor
; positioning. Other displays may use escape
; codes to the same ends.

DrawBoard
	JSR	Print_c_		; print copyright
	LDA	#$00			; set initial position (0,0) is top left
	STA	DispPosX		; set cursor X
	STA	DispPosY		; set cursor Y
	JSR	PColNum			; print column labels
	JSR	Hline			; print horizontal line
	LDY	#$00			; init board location
PNewVert
	JSR	PRowNum			; print row number
PVert
	LDA	#'|'			; print vertical edge
	JSR	asciiout		; byte out to display

	LDX	#$1F			; for each piece
	TYA				; copy square #
PPiece
	CMP	BOARD,X			; this piece in this square?
	BEQ	PieceOut		; if so print the piece's color and type

	DEX				; else try next piece
	BPL	PPiece			; if not done then loop

	TYA				; copy square #
	ASL				; shift column LSB into Cb
	ASL				;
	ASL				;
	ASL				;
	TYA				; copy square # again
	ADC	#$00			; add column LSB
	LSR				; result into carry	
	LDA	#' '			; assume white square
	BCS	Iswhite 		; branch if white

	LDA	#'#'			; else make square black
Iswhite
	JSR	asciiout		; byte out to display
	JSR	asciiout		; byte out to display
PNextCol
	INY				; next column
	TYA				; get square #
	AND	#$08			; have we completed the row?
	BEQ	PVert			; if not go do next column

	LDA	#'|'			; yes, put the right edge on
	JSR	asciiout		; byte out to display
	JSR	PRowNum			; print row number
	JSR	CRLF			; print CRLF
	JSR	Hline			; print horizontal line
	TYA				; copy square #
	CLC				; clear for add
	ADC	#$08			; increment to beginning of next row
	BMI	PColNum			; done so go finish board

	TAY				; else copy new square #
	BPL	PNewVert		; go do next row

; output piece's color & type

PieceOut
	LDA	#'W'			; assume white
	CPX	#$10			; compare with breakpoint (result in Cb)
	BIT	reverse			; test reverse byte
	BEQ	Noflip			; branch if not reverse

					; else toggle Cb state
	ROL				; Cb into D0		
	EOR	#$01			; toggle bit
	ROR				; D0 into Cb
Noflip
	BCC	NotBlack		; branch if white

	LDA	#'B'			; else make black
NotBlack
	JSR	asciiout		; byte out to display
	TXA				; copy piece
	AND	#$0F			; mask black/white
	TAX				; back to index
	LDA	P_piece,x		; get current piece 2nd byte
	JSR	asciiout		; byte out to display
	BNE	PNextCol		; branch always

; print "  ", line of -'s then [CR][LF]

Hline
	JSR	space			; [SPACE] out to display
	JSR	asciiout		; byte out to display (2nd [SPACE])
	LDA	#'-'			; line of -'s
	LDX	#$19			; 25 -'s to do
HlineL
	JSR	asciiout		; byte out to display
	DEX				; decrement count
	BNE	HlineL			; loop if not all done

; do newline

CRLF
	LDA	#$0D			; [CR]
	JSR	asciiout		; byte out to display
	LDA	#$0A			; [LF]
	JMP	asciiout		; byte out to display & return

; print the column labels

PColNum
	JSR	space			; [SPACE] out to display
	JSR	asciiout		; byte out to display (2nd [SPACE])
	LDX	#$00			; clear index
PNextCNum
	JSR	space			; [SPACE] out to display
	TXA				; get column number
	JSR	hexout			; A out as hex
	INX				; next column
	CPX	#$08			; is it done?
	BNE	PNextCNum		; loop if not

	BEQ	CRLF			; else do newline and return

; print (c) message

; text lines are ...
; Xpos,Ypos,"text",0
; .. for lines with following lines and ...
; Xpos,Ypos,"text",255
; for the last line

Print_c_
	LDX	#$FF			; initial -1
Print_c_n
	INX				; increment index
	LDA	_c_,X			; get cursor X
	STA	DispPosX		; set cursor X
	INX				; increment index
	LDA	_c_,X			; get cursor Y
	STA	DispPosY		; set cursor Y
	INX				; increment index
Print_c_l
	LDA	_c_,X			; get byte
	BEQ	Print_c_n		; do next line if $00 [EOL]

	BMI	Print_c_e		; exit if $FF [EOT]

	JSR	asciiout		; byte out to display
	INX				; increment index
	BNE	Print_c_l		; loop

Print_c_e
	RTS	

; wait for key

asciiin
	LDA	ACIAsimrd		; get chr
	BEQ	asciiin			; no char to get

	CMP	#'a'			; lowe case ASCII
	BCC	asciirts		; skip if not >=

	AND	#$DF			; # and upper case alpha only
asciirts
	RTS

PRowNum
	TYA				; copy row number
PSquare
	AND 	#$77			; mask unused bits

; output A as two hex digits

hexout
	PHA				; save for lower digit
	LSR				; shift upper ..
	LSR				; .. nibble to ..
	LSR				; .. lower nibble ..
	LSR				; .. and clear upper
	JSR	PrintDig		; output hex digit
	PLA				; get byte back
	AND	#$0F			; clear upper nibble
PrintDig
	SED				; set for hex convert
	CMP	#$0A			; compare with breakpoint
	ADC	#'0'			; add to "0"
	CLD				; clear again

; byte out to display

asciiout
	STA	ACIAsimwr		; byte out to port
	RTS

space
	LDA	#$20			; [SPACE]
	BNE	asciiout		; print and return

; display piece byte in DIS1 as ASCII string

DisPiece
	LDA	DIS1			; get piece for this move
	BMI	DisSpecial		; branch if not piece

	AND	#$0F			; don't care black or white
	ASL				; *2
	ASL				; *4
	ASL				; *8
	TAX				; copy index
DisString
	LDY	#$08			; character count
DisLoop
	LDA	PieceName,X		; get byte
	JSR	asciiout		; out to display
	INX				; increment index
	DEY				; decrement count
	BNE	DisLoop			; loop if not done

	RTS

; set X for 'special' $CC, $EE and $FF piece codes, else set null

DisSpecial
	CMP	#$CC			; compare with reset
	BNE	NotReset		; branch if not reset

	LDX	#PRes-PieceName		; set pointer
	BNE	DisString		; go print it

NotReset
	CMP	#$EE			; compare with exchange
	BNE	NotExcg			; branch if not exchange

	LDX	#PExg-PieceName		; set pointer
	BNE	DisString		; go print it

NotExcg					; else null
	CMP	#$FF			; compare with check mate
	BNE	NotChkm			; branch if not check mate

	LDX	#PCkm-PieceName		; set pointer
	BNE	DisString		; go print it

NotChkm					; else null
	LDX	#PNul-PieceName		; set pointer
	BNE	DisString		; go print it

; text descriptions for the byte in DIS1

PieceName
	.byte	"King    "
	.byte	"Queen   "
	.byte	"K Rook  "
	.byte	"Q Rook  "
	.byte	"K Bishop"
	.byte	"Q Bishop"
	.byte	"K Knight"
	.byte	"Q Knight"
	.byte	"K R Pawn"
	.byte	"Q R Pawn"
	.byte	"K N Pawn"
	.byte	"Q N Pawn"
	.byte	"K B Pawn"
	.byte	"Q B Pawn"
	.byte	"Q Pawn  "
	.byte	"K Pawn  "
PRes
	.byte	"Reset   "
PExg
	.byte	"Exchange"
PCkm
	.byte	"Mate"
PNul
	.byte	"        "

; copyright banner

_c_
	.byte	$24,$01,"+--------------------+",$00
	.byte	$24,$02,"|     MicroChess     |",$00
	.byte	$24,$03,"|   (c) 1976-2002    |",$00
	.byte	$24,$04,"|   Peter Jennings   |",$00
	.byte	$24,$05,"|                    |",$00
	.byte	$24,$06,"+--------------------+",$FF

; piece character table

P_piece
	.byte	"KQCCBBkkPPPPPPPP"

; end of new code

; BLOCK DATA
;		*= $1580

; initial positions

SETW
	.byte	$03, $04, $00, $07, $02, $05, $01, $06
	.byte	$10, $17, $11, $16, $12, $15, $14, $13
	.byte	$73, $74, $70, $77, $72, $75, $71, $76
	.byte	$60, $67, $61, $66, $62, $65, $64, $63

MOVEX
	.byte	$00, $F0, $FF, $01, $10, $11, $0F, $EF, $F1
	.byte	$DF, $E1, $EE, $F2, $12, $0E, $1F, $21

POINTS
	.byte	$0B, $0A, $06, $06, $04, $04, $04, $04
	.byte	$02, $02, $02, $02, $02, $02, $02, $02

OPNING
	.byte	$99, $25, $0B, $25, $01, $00, $33, $25
	.byte	$07, $36, $34, $0D, $34, $34, $0E, $52
	.byte	$25, $0D, $45, $35, $04, $55, $22, $06
	.byte	$43, $33, $0F, $CC

This version is posted with the kind permission of Peter Jennings