spinsim/pfth103_p2/chess.fth

609 lines
12 KiB
Forth
Executable File

\ This program was written by Lennart Benschop and converted to ANS Forth by
\ by Jeff Fox. It was further modified by Dave Hein to run under pfth. The
\ orignal source is available at http://www.ultatechnology.com/chess.html.
HEX
: scroll cr ;
: cls page ;
: key? 1 ;
: off false swap ! ;
: >defer 2 + w@ 4 - ;
3 constant maxlevel
create bp0
maxlevel 1 + c0 * allot
variable bpv
: bp bpv @ ;
: b@ bpv @ + c@ ;
: b! bpv @ + c! ;
: boardvar create ,
does> c@ bpv @ + ;
0c boardvar start
0d boardvar castlew
0e boardvar castleb
0f boardvar ep
1c boardvar starting
1d boardvar piece
1e boardvar best
1f boardvar farther?
2c boardvar wlcastle?
2d boardvar blcastle?
2e boardvar check
2f boardvar pawnmove
3c boardvar kingw
3d boardvar kingb
3e boardvar inpassing
3f boardvar advance
4c boardvar valuew
5c boardvar alfa
6c boardvar beta
7c boardvar (eval)
8c boardvar highest
9c boardvar cutoff
ac boardvar valueb
bc boardvar played
variable level
variable lastcnt
: +level
bp dup c0 + c0 cmove
c0 bpv +! 1 level +! ;
: -level
-c0 bpv +! -1 level +! ;
create symbols
CHAR . , CHAR p , CHAR k , CHAR b ,
CHAR r , CHAR q , CHAR K ,
create values
0 , 40 , c0 , c0 , 140 , 240 , 3000 ,
: .board
cls
0 0 at-xy 20 spaces
cr 2 spaces
[CHAR] H 1 + [CHAR] A do i emit 2 spaces loop
bp 20 + 8 0 do
cr 20 spaces
cr [CHAR] 8 i - emit
0a 2 do space
dup i + c@ dup
07 and cells symbols + 1 type
dup 80 and if ." W" drop else
if ." B" else ." ." then
then
loop
10 +
loop cr drop ;
: .pos
10 /mod
swap 2 - [CHAR] A + emit
[CHAR] 8 2 + swap - emit ;
\ constants that indicate the directions on the board
-11 constant nw -0f constant no
0f constant zw 11 constant zo
-10 constant n 10 constant z
-1 constant w 1 constant o
create spring
-12 , -21 , -1f , -0e , 12 , 21 , 1f , 0e ,
defer tmove
defer attacktest
: mine?
b@ dup 0= 0= swap 80 and start c@ = and ;
variable movits
: moveit
starting c@ best c! 1 farther? c!
begin
best c@ over + dup best c!
dup mine? over b@ 87 = or 0=
farther? c@ and while
tmove
b@ 0= farther? c!
repeat
drop drop
1 movits +! ;
: Bishop
no nw zo zw moveit moveit moveit moveit ;
: Rook
n o z w moveit moveit moveit moveit ;
: Queen
n o z w no nw zo zw 8 0 do moveit loop ;
: Knight
8 0 do
i cells spring + @
starting c@ + dup best c!
dup mine? swap b@ 87 = or 0=
if tmove then
loop ;
: ?castle
start c@ 80 = if castlew else castleb then c@ check c@ 0= and ;
: ?lcastle
start c@ 80 = if wlcastle? else blcastle? then c@ check c@ 0= and ;
: king
n o z w no nw zo zw 8 0 do
starting c@ + dup best c!
dup mine? swap b@ 87 = or 0=
if tmove then
loop
?castle if 28 start c@ if 70 + then
dup bp + 1- @ 0=
if
dup 1- attacktest 0=
if
best c! tmove
else drop then
else drop then
then
?lcastle if 24 start c@ if 70 + then
dup bp + @ over bp + 1- @ or 0=
if
dup 1 + attacktest 0=
if
best c! tmove
else drop then
else drop then
then ;
: Pawnrow
start c@ if negate then ;
: Pawnz
dup best c!
f0 and start c@ if 20 else 90 then =
if 6 2 do i advance c! tmove loop
else tmove then
0 pawnmove c! 0 inpassing c! 0 advance c! ;
: Pawn
starting c@ z Pawnrow +
dup b@ if
drop
else
dup Pawnz
z Pawnrow + dup b@ if
drop
else
starting c@ f0 and
start c@ if 80 else 30 then =
if starting c@ 0f and pawnmove c!
Pawnz
else drop
then
then
then
zw zo 2 0 do
Pawnrow starting c@ +
dup f0 and start c@ if 40 else 70 then =
over 0f and ep c@ = and
if 1 inpassing c!
dup Pawnz
then
dup b@ dup 0= 2 pick mine? or
swap 87 = or
if drop else Pawnz then
loop ;
create pieces
' noop , ' Pawn , ' Knight , ' Bishop , ' Rook , ' Queen , ' king ,
: piecemove
\ using above jump table for each type of piece - jump table uses , (CELLS)
piece c@ cells pieces + @ execute ;
: ?piecemove
starting c@ dup mine? if
b@ 07 and piece c!
0 pawnmove c! 0 inpassing c! 0 advance c!
piecemove
else drop then ;
: allmoves
[char] . emit
start c@ 0= if
22 starting c!
8 0 do
8 0 do
?piecemove starting c@ 1 + starting c!
loop
starting c@ 8 + starting c!
loop
else
92 starting c!
8 0 do
8 0 do
?piecemove starting c@ 1 + starting c!
loop
starting c@ 18 - starting c!
loop
then ;
variable attack
: ?attack
best c@ dup mine? 0=
swap b@ 07 and piece c@ = and
attack @ or attack ! ;
: attacked?
attack off 0 7 1 do
i piece c!
piecemove
attack @ if drop 1 leave then
loop ;
variable starting'
variable best'
variable start'
variable tmove'
: settest
starting c@ starting' c!
best c@ best' c!
start c@ start' c!
['] tmove >defer tmove' !
['] ?attack is tmove ;
: po@
starting' c@ starting c!
best' c@ best c!
start' c@ start c!
tmove' @ is tmove ;
: changecolor
start c@ 80 xor start c! ;
variable endf
variable playlevel
variable #legal
variable selected
variable compcolor
variable move#
create bp1 c0 allot
: endgame?
start c@ if valueb else valuew then @ c1 < ;
: evalboard
valueb @ valuew @ - start c@ if negate then
55 mine? 1 and + 56 mine? 1 and + 65 mine? 1 and + 66 mine? 1 and +
changecolor 55 mine? + 56 mine? + 65 mine? + 66 mine? + changecolor
endgame? if
start c@ if kingb else kingw then c@
dup f0 and dup 20 = swap 90 = or 7 and
swap 0f and dup 2 = swap 9 = or 7 and + +
then ;
: ?check
settest
start c@ if kingw else kingb then c@
starting c! attacked? check c!
po@ ;
: (attacktest)
['] tmove >defer ['] ?attack <> if
settest
starting c!
attacked?
po@
else drop true
then ;
' (attacktest) is attacktest
variable seed
: rnd
seed @ 743 * 43 + dup seed ! ;
\ 1 ;
: domove
best c@ b@ 7 and cells values + @ negate start c@
if valueb else valuew then +!
starting c@ b@ best c@ b!
0 starting c@ b!
advance c@ if
advance c@ dup cells values + @ 40 - start c@
if valueb else valueb then +!
start c@ or best c@ b!
then
piece c@ 4 = if
starting c@ 0f and 2 =
if
0 start c@ if wlcastle? else blcastle? then c!
then
starting c@ 0f and 9 =
if
0 start c@ if castlew else castleb then c!
then
then
piece c@ 6 = if
0 0 start c@ if castlew else castleb then dup >r c!
r> 1f + c!
best c@ starting c@ - 2 =
if
4 start c@ or best c@ 1- b!
0 best c@ 1 + b!
then
best c@ starting c@ - -2 =
if
4 start c@ or best c@ 1 + b!
0 best c@ 2 - b!
then
best c@ start c@ if kingw else kingb then c!
then
inpassing c@ if
0 best c@ n Pawnrow + b!
-40 start c@ if valueb else valuew then +!
then
pawnmove c@ ep c! ;
: deeper
cutoff @
invert if
+level
domove
?check check c@ if -level exit then
-1 played c0 - !
level @ playlevel @ = if
evalboard
(eval) c0 - !
else
alfa @ highest !
alfa @ negate beta @ negate alfa ! beta !
changecolor
0 played !
allmoves
played @ 0= if
?check check c@ if -2000 highest ! else 0 highest ! then
then
highest @ negate
(eval) c0 - !
then
-level
(eval) @ highest @ max
highest !
highest @ beta @ > if TRUE cutoff ! then
then ;
: analyse
+level
domove
?check check c@ 0= if
1 #legal +!
changecolor
['] tmove >defer
['] deeper is tmove
0 played !
allmoves
is tmove
played @ 0= if
?check check c@ if -2000 highest ! else 0 highest ! then
then
highest @ beta c0 - @ = if
rnd 2000 > if #legal @ selected ! then
then
highest @ beta c0 - @ < if
#legal @ selected !
highest @ beta c0 - !
then
then
-level ;
: select
+level
domove
?check check c@ 0= if
1 #legal +!
#legal @ selected @ = if
bp bp1 c0 cmove
starting c@ .pos ." -" best c@ .pos space
then
then
-level ;
: against
+level
domove
?check check c@ 0= if
1 #legal +!
then
-level ;
: compmove
.board
['] analyse is tmove
0 #legal !
-4000 alfa ! 4000 beta !
\ 0 18 at-xy cr
scroll
\ 28 spaces
start c@ if 1 move# +! move# @ 3 .r space else 4 spaces then
?check check c@ if ." Check" then
1 selected !
allmoves
#legal @ 0= if
check c@ if
." mate"
else
." Pat"
then
TRUE endf !
else
['] select is tmove
0 #legal !
allmoves
bp1 bp0 c0 cmove
changecolor
['] against is tmove
0 #legal !
allmoves
?check check c@ if ." Check" then
#legal @ 0= if
check c@ if
." mate"
else
." Pat"
then
TRUE endf !
then
then
.board ;
variable startingm
variable bestm
variable personmove
: legal
startingm @ starting c@ =
bestm @ best c@ = and
personmove @ advance c@ = and
if
+level
domove
?check check c@ 0= if
1 #legal !
bp bp1 c0 cmove
then
-level
then ;
create inputbuf 6 allot
: inpos
dup inputbuf + c@ [CHAR] A -
dup 8 u<
rot inputbuf + 1 + c@ [CHAR] 1 -
dup 8 u< rot and
swap 7 swap - 10 * rot + 22 + ;
: promote
0 6 2 do over symbols i cells + c@ = if drop i then loop ;
: person
begin
.board
scroll
\ 28 spaces
start c@ if 1 move# +! move# @ 3 .r else 3 spaces then
inputbuf 5 expect cr
\ [char] X emit inputbuf 5 type [char] X emit
inputbuf c@ [CHAR] Q = if quit then
0 inpos startingm !
2 inputbuf + c@ [CHAR] - = and
3 inpos bestm !
and
bestm @ f0 and start c@ if 20 else 90 then =
startingm b@ 07 and 1 = and
if
." What piece? " 0 0 begin drop drop key promote dup until
personmove ! emit
else
0 personmove !
then
if
['] legal is tmove
0 #legal !
startingm c@ starting c! ?piecemove
#legal @
else
0
then
dup 0= start c@ and if -1 move# +! then
until
bp1 bp0 c0 cmove
changecolor
cr
.board ;
: setmove
compcolor @ 0< start c@ 80 = = if compmove else person then ;
variable manVsMachine
: askcolor
manVSmachine @
if ." Do you want White Y/N"
key dup [CHAR] Y = swap [CHAR] y = or
if 1 else -1 then compcolor !
then ;
: asklevel
cr ." Level? 2-"
maxlevel . key [CHAR] 0 - 2 max maxlevel min playlevel !
cls ;
: init
0 level ! bp0 bpv !
bp c0 87 fill
4 2 3 6 5 3 2 4 8 0 do bp 22 + i + c! loop
bp 32 + 8 01 fill
bp 42 + 8 00 fill bp 52 + 8 00 fill
bp 62 + 8 00 fill bp 72 + 8 00 fill
bp 82 + 8 81 fill
84 82 83 86 85 83 82 84 8 0 do bp 92 + i + c! loop
1 castlew c! 1 castleb c! 0 ep c! 1 wlcastle? c! 1 blcastle? c! 0 advance c!
80 start c! 96 kingw c! 26 kingb c!
askcolor cr asklevel
0 move# ! 0 endf !
0 check c! 9c0 valuew ! 9c0 valueb ! ;
: play
begin setmove endf @ until ;
: games
begin init play again ;
: autoplay
begin setmove compcolor @ negate compcolor ! key? if quit then endf @ until ;
: auto
init -1 compcolor ! autoplay ;
: chess
cls
." ANS Forth Chess" cr
." Do you want to play against the computer? Y/N" cr
begin rnd drop key? until key
dup [CHAR] Y = swap [CHAR] y = or dup manVsMachine !
if games else auto then ;
decimal