Files
basic-computer-games/23_Checkers/checkers.annotated.bas
Martin Thoma e64fb6795c MAINT: Apply pre-commit
Remove byte-order-marker pre-commit check as there would be
many adjustments necessary
2022-03-05 09:29:23 +01:00

316 lines
8.3 KiB
QBasic

# 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