mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 07:10:42 -08:00
Removed spaces from top-level directory names.
Spaces tend to cause annoyances in a Unix-style shell environment. This change fixes that.
This commit is contained in:
315
23_Checkers/checkers.annotated.bas
Normal file
315
23_Checkers/checkers.annotated.bas
Normal file
@@ -0,0 +1,315 @@
|
||||
# Annotated version of CHECKERS.BAS, modified to improve readability.
|
||||
#
|
||||
# I've made the following changes:
|
||||
#
|
||||
# 1. Added many comments and blank lines.
|
||||
# 2. Separated each statement into its own line.
|
||||
# 3. Indented loops, conditionals and subroutines.
|
||||
# 4. Turned *SOME* conditionals and loops into
|
||||
# structured-BASIC-style if/endif and loop/endloop blocks.
|
||||
# 5. Switched to using '#' to delimit comments.
|
||||
# 6. Subroutines now begin with "Sub_Start"
|
||||
# 7. All non-string text has been converted to lower-case
|
||||
# 8. All line numbers that are not jump destinations have been removed.
|
||||
#
|
||||
# This has helped me make sense of the code. I hope it will also help you.
|
||||
#
|
||||
|
||||
# Print the banner
|
||||
print tab(32);"CHECKERS"
|
||||
print tab(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"
|
||||
print
|
||||
print
|
||||
print
|
||||
print "THIS IS THE GAME OF CHECKERS. THE COMPUTER IS X,"
|
||||
print "AND YOU ARE O. THE COMPUTER WILL MOVE FIRST."
|
||||
print "SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM."
|
||||
print "(0,0) IS THE LOWER LEFT CORNER"
|
||||
print "(0,7) IS THE UPPER LEFT CORNER"
|
||||
print "(7,0) IS THE LOWER RIGHT CORNER"
|
||||
print "(7,7) IS THE UPPER RIGHT CORNER"
|
||||
print "THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER"
|
||||
print "JUMP. TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP."
|
||||
print
|
||||
print
|
||||
print
|
||||
|
||||
# Declare the "globals":
|
||||
|
||||
# The current move: (rating, current x, current y, new x, new y)
|
||||
# 'rating' represents how good the move is; higher is better.
|
||||
dim r(4)
|
||||
r(0)=-99 # Start with minimum score
|
||||
|
||||
# The board. Pieces are represented by numeric values:
|
||||
#
|
||||
# - 0 = empty square
|
||||
# - -1,-2 = X (-1 for regular piece, -2 for king)
|
||||
# - 1,2 = O (1 for regular piece, 2 for king)
|
||||
#
|
||||
# This program's player ("me") plays X.
|
||||
dim s(7,7)
|
||||
|
||||
g=-1 # constant holding -1
|
||||
|
||||
# Initialize the board. Data is 2 length-wise strips repeated.
|
||||
data 1,0,1,0,0,0,-1,0,0,1,0,0,0,-1,0,-1,15
|
||||
for x=0 to 7
|
||||
for y=0 to 7
|
||||
read j
|
||||
if j=15 then 180
|
||||
s(x,y)=j
|
||||
goto 200
|
||||
180 restore
|
||||
read s(x,y)
|
||||
200 next y,x
|
||||
|
||||
230 # Start of game loop. First, my turn.
|
||||
|
||||
# For each square on the board, search for one of my pieces
|
||||
# and if it can make the best move so far, store that move in 'r'
|
||||
for x=0 to 7
|
||||
for y=0 to 7
|
||||
|
||||
# Skip if this is empty or an opponent's piece
|
||||
if s(x,y) > -1 then 350
|
||||
|
||||
# If this is one of my ordinary pieces, analyze possible
|
||||
# forward moves.
|
||||
if s(x,y) = -1 then
|
||||
for a=-1 to 1 step 2
|
||||
b=g
|
||||
gosub 650
|
||||
next a
|
||||
endif
|
||||
|
||||
# If this is one of my kings, analyze possible forward
|
||||
# and backward moves.
|
||||
if s(x,y) = -2 then
|
||||
for a=-1 to 1 step 2
|
||||
for b=-1 to 1 step 2
|
||||
gosub 650
|
||||
next b,a
|
||||
endif
|
||||
|
||||
350 next y,x
|
||||
goto 1140 # Skip the subs
|
||||
|
||||
|
||||
# Analyze a move from (x,y) to (x+a, y+b) and schedule it if it's
|
||||
# the best candidate so far.
|
||||
650 Sub_Start
|
||||
u=x+a
|
||||
v=y+b
|
||||
|
||||
# Done if it's off the board
|
||||
if u<0 or u>7 or v<0 or v>7 then 870
|
||||
|
||||
# Consider the destination if it's empty
|
||||
if s(u,v) = 0 then
|
||||
gosub 910
|
||||
goto 870
|
||||
endif
|
||||
|
||||
# If it's got an opponent's piece, jump it instead
|
||||
if s(u,v) > 0
|
||||
|
||||
# Restore u and v, then return if it's off the board
|
||||
u=u+a
|
||||
v=v+b
|
||||
if u<0 or v<0 or u>7 or v>7 then 870
|
||||
|
||||
# Otherwise, consider u,v
|
||||
if s(u,v)=0 then gosub 910
|
||||
endif
|
||||
870 return
|
||||
|
||||
# Evaluate jumping (x,y) to (u,v).
|
||||
#
|
||||
# Computes a score for the proposed move and if it's higher
|
||||
# than the best-so-far move, uses that instead by storing it
|
||||
# and its score in array 'r'.
|
||||
910 Sub_Start
|
||||
|
||||
# q is the score; it starts at 0
|
||||
|
||||
# +2 if it promotes this piece
|
||||
if v=0 and s(x,y)=-1 then q=q+2
|
||||
|
||||
# +5 if it takes an opponent's piece
|
||||
if abs(y-v)=2 then q=q+5
|
||||
|
||||
# -2 if the piece is moving away from the top boundary
|
||||
if y=7 then q=q-2
|
||||
|
||||
# +1 for putting the piece against a vertical boundary
|
||||
if u=0 or u=7 then q=q+1
|
||||
|
||||
for c=-1 to 1 step 2
|
||||
if u+c < 0 or u+c > 7 or v+g < 0 then 1080
|
||||
|
||||
# +1 for each adjacent friendly piece
|
||||
if s(u+c, v+g) < 0 then
|
||||
q=q+1
|
||||
goto 1080
|
||||
endif
|
||||
|
||||
# Prevent out-of-bounds testing
|
||||
if u-c < 0 or u-c > 7 or v-g > 7 then 1080
|
||||
|
||||
# -2 for each opponent piece that can now take this piece here
|
||||
if s(u+c,v+g) > 0 and(s(u-c,v-g)=0 or(u-c=x and v-g=y))then q=q-2
|
||||
1080 next c
|
||||
|
||||
# Use this move if it's better than the previous best
|
||||
if q>r(0) then
|
||||
r(0)=q
|
||||
r(1)=x
|
||||
r(2)=y
|
||||
r(3)=u
|
||||
r(4)=v
|
||||
endif
|
||||
|
||||
q=0 # reset the score
|
||||
return
|
||||
|
||||
1140 if r(0)=-99 then 1880 # Game is lost if no move could be found.
|
||||
|
||||
# Print the computer's move. (Note: chr$(30) is an ASCII RS
|
||||
# (record separator) code; probably no longer relevant.)
|
||||
print chr$(30)"FROM"r(1);r(2)"TO"r(3);r(4);
|
||||
r(0)=-99
|
||||
|
||||
# Make the computer's move. If the piece finds its way to the
|
||||
# end of the board, crown it.
|
||||
1240 if r(4)=0 then
|
||||
s(r(3),r(4))=-2
|
||||
goto 1420
|
||||
endif
|
||||
s(r(3),r(4))=s(r(1),r(2))
|
||||
s(r(1),r(2))=0
|
||||
|
||||
# If the piece has jumped 2 squares, it means the computer has
|
||||
# taken an opponents' piece.
|
||||
if abs(r(1)-r(3)) == 2 then
|
||||
s((r(1)+r(3))/2,(r(2)+r(4))/2)=0 # Delete the opponent's piece
|
||||
|
||||
# See if we can jump again. Evaluate all possible moves.
|
||||
x=r(3)
|
||||
y=r(4)
|
||||
for a=-2 to 2 step 4
|
||||
if s(x,y)=-1 then
|
||||
b=-2
|
||||
gosub 1370
|
||||
endif
|
||||
if s(x,y)=-2 then
|
||||
for b=-2 to 2 step 4
|
||||
gosub 1370
|
||||
next b
|
||||
endif
|
||||
next a
|
||||
|
||||
# If we've found a move, go back and make that one as well
|
||||
if r(0) <> -99 then
|
||||
print "TO" r(3); r(4);
|
||||
r(0)=-99
|
||||
goto 1240
|
||||
endif
|
||||
|
||||
goto 1420 # Skip the sub
|
||||
|
||||
# If (u,v) is in the bounds, evaluate it as a move using
|
||||
# the sub at 910
|
||||
1370 Sub_Start
|
||||
u=x+a
|
||||
v=y+b
|
||||
if u<0 or u>7 or v<0 or v>7 then 1400
|
||||
if s(u,v)=0 and s(x+a/2,y+b/2)>0 then gosub 910
|
||||
1400 return
|
||||
|
||||
1420 endif
|
||||
|
||||
# Now, print the board
|
||||
print
|
||||
print
|
||||
print
|
||||
for y=7 to 0 step-1
|
||||
for x=0 to 7
|
||||
i=5*x
|
||||
print tab(i);
|
||||
if s(x,y)=0 then print".";
|
||||
if s(x,y)=1 then print"O";
|
||||
if s(x,y)=-1 then print"X";
|
||||
if s(x,y)=-2 then print"X*";
|
||||
if s(x,y)=2 then print"O*";
|
||||
next x
|
||||
print" "
|
||||
print
|
||||
next y
|
||||
print
|
||||
|
||||
# Check if either player is out of pieces. If so, announce the
|
||||
# winner.
|
||||
for l=0 to 7
|
||||
for m=0 to 7
|
||||
if s(l,m)=1 or s(l,m)=2 then z=1
|
||||
if s(l,m)=-1 or s(l,m)=-2 then t=1
|
||||
next m
|
||||
next l
|
||||
if z<>1 then 1885
|
||||
if t<>1 then 1880
|
||||
|
||||
# Prompt the player for their move.
|
||||
z=0
|
||||
t=0
|
||||
1590 input "FROM";e,h
|
||||
x=e
|
||||
y=h
|
||||
if s(x,y)<=0 then 1590
|
||||
1670 input "TO";a,b
|
||||
x=a
|
||||
y=b
|
||||
if s(x,y)=0 and abs(a-e)<=2 and abs(a-e)=abs(b-h)then 1700
|
||||
print chr$(7)chr$(11); # bell, vertical tab; invalid move
|
||||
goto 1670
|
||||
|
||||
1700 i=46 # Not used; probably a bug
|
||||
1750 loop
|
||||
# Make the move and stop unless it might be a jump.
|
||||
s(a,b) = s(e,h)
|
||||
s(e,h) = 0
|
||||
if abs(e-a) <> 2 then break
|
||||
|
||||
# Remove the piece jumped over
|
||||
s((e+a)/2,(h+b)/2) = 0
|
||||
|
||||
# Prompt for another move; -1 means player can't, so I've won.
|
||||
# Keep prompting until there's a valid move or the player gives
|
||||
# up.
|
||||
1802 input "+TO";a1,b1
|
||||
if a1 < 0 then break
|
||||
if s(a1,b1) <> 0 or abs(a1-a) <>2 or abs(b1-b) <> 2 then 1802
|
||||
|
||||
# Update the move variables to correspond to the next jump
|
||||
e=a
|
||||
h=b
|
||||
a=a1
|
||||
b=b1
|
||||
|
||||
i=i+15 # Not used; probably a bug
|
||||
endloop
|
||||
|
||||
# If the player has reached the end of the board, crown this piece
|
||||
1810 if b=7 then s(a,b)=2
|
||||
|
||||
# And play the next turn.
|
||||
goto 230
|
||||
|
||||
# Endgame:
|
||||
1880 print
|
||||
print "YOU WIN."
|
||||
end
|
||||
|
||||
1885 print
|
||||
print "I WIN."
|
||||
end
|
||||
Reference in New Issue
Block a user