From 3d6267433adee03bc64da9dfe58db8ecff3ebf68 Mon Sep 17 00:00:00 2001 From: Dave LeCompte Date: Mon, 1 Mar 2021 09:08:03 -0800 Subject: [PATCH] WIP Begin Porting HEXAPAWN to Python So far, have printed out instructions and parsed player moves. Submitting pull request to let folks know I'm working on this. --- 46 Hexapawn/python/hexapawn.py | 320 +++++++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 46 Hexapawn/python/hexapawn.py diff --git a/46 Hexapawn/python/hexapawn.py b/46 Hexapawn/python/hexapawn.py new file mode 100644 index 00000000..232bb782 --- /dev/null +++ b/46 Hexapawn/python/hexapawn.py @@ -0,0 +1,320 @@ +""" +HEXAPAWN + +A machine learning game, an interpretation of HEXAPAWN game as +presented in Martin Gardner's "The Unexpected Hanging and Other +Mathematical Diversions", Chapter Eight: A Matchbox Game-Learning +Machine. + +Original version for H-P timeshare system by R.A. Kaapke 5/5/76 +Instructions by Jeff Dalton +Conversion to MITS BASIC by Steve North + + +Port to Python by Dave LeCompte +""" + +PAGE_WIDTH = 64 + +def print_centered(msg): + spaces = " " * ((PAGE_WIDTH - len(msg)) // 2) + print(spaces + msg) + +def print_header(title): + print_centered(title) + print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() + +def print_instructions(): + print(""" +THIS PROGRAM PLAYS THE GAME OF HEXAPAWN. +HEXAPAWN IS PLAYED WITH CHESS PAWNS ON A 3 BY 3 BOARD. +THE PAWNS ARE MOVED AS IN CHESS - ONE SPACE FORWARD TO +AN EMPTY SPACE OR ONE SPACE FORWARD AND DIAGONALLY TO +CAPTURE AN OPPOSING MAN. ON THE BOARD, YOUR PAWNS +ARE 'O', THE COMPUTER'S PAWNS ARE 'X', AND EMPTY +SQUARES ARE '.'. TO ENTER A MOVE, TYPE THE NUMBER OF +THE SQUARE YOU ARE MOVING FROM, FOLLOWED BY THE NUMBER +OF THE SQUARE YOU WILL MOVE TO. THE NUMBERS MUST BE +SEPERATED BY A COMMA. + +THE COMPUTER STARTS A SERIES OF GAMES KNOWING ONLY WHEN +THE GAME IS WON (A DRAW IS IMPOSSIBLE) AND HOW TO MOVE. +IT HAS NO STRATEGY AT FIRST AND JUST MOVES RANDOMLY. +HOWEVER, IT LEARNS FROM EACH GAME. THUS, WINNING BECOMES +MORE AND MORE DIFFICULT. ALSO, TO HELP OFFSET YOUR +INITIAL ADVANTAGE, YOU WILL NOT BE TOLD HOW TO WIN THE +GAME BUT MUST LEARN THIS BY PLAYING. + +THE NUMBERING OF THE BOARD IS AS FOLLOWS: + 123 + 456 + 789 + +FOR EXAMPLE, TO MOVE YOUR RIGHTMOST PAWN FORWARD, +YOU WOULD TYPE 9,6 IN RESPONSE TO THE QUESTION +'YOUR MOVE ?'. SINCE I'M A GOOD SPORT, YOU'LL ALWAYS +GO FIRST. + +""") + + +def prompt_yes_no(msg): + while True: + print(msg) + response = input().upper() + if response[0] == "Y": + return True + elif response[0] == "N": + return False + +def fnr(x): + score = {1: -3, + 2: -2, + 3: -1, + 4: -6, + 5: -5, + 6: -4, + 7: -9, + 8: -8, + 9: -7} + return score[x] + +def fnm(y): + return y % 10 + +def get_b(x, y): + data = [[-1, -1, -1, 1, 0, 0, 0, 1, 1], + [-1, -1, -1, 0, 1, 0, 1, 0, 1], + [-1, 0, -1, -1, 1, 0, 0, 0, 1], + [ 0, -1, -1, 1, -1, 0, 0, 0, 1], + [-1, 0, -1, 1, 1, 0, 0, 1, 0], + [-1, -1, 0, 1, 0, 1, 0, 0, 1], + [ 0, -1, -1, 0, -1, 1, 1, 0, 0], + [ 0, -1, -1, -1, 1, 1, 1, 0, 0], + [-1, 0, -1, -1, 0, 1, 0, 1, 0], + [ 0, -1, -1, 0, 1, 0, 0, 0, 1], + [ 0, -1, -1, 0, 1, 0, 1, 0, 0], + [-1, 0, -1, 1, 0, 0, 0, 0, 1], + [ 0, 0, -1, -1, -1, 1, 0, 0, 0], + [-1, 0, 0, 1, 1, 1, 0, 0, 0], + [ 0, -1, 0, -1, 1, 1, 0, 0, 0], + [-1, 0, 0, -1, -1, 1, 0, 0, 0], + [ 0, 0, -1, -1, 1, 0, 0, 0, 0], + [ 0, -1, 0, 1, -1, 0, 0, 0, 0], + [-1, 0, 0, -1, 1, 0, 0, 0, 0]] + + return data[x+1][y+1] + +def get_m(x, y): + data = [[24, 25,36,0], + [14,15,36,0], + [15,35,36,47], + [36,58,59,0], + [15,35,36,0], + [24,25,26,0], + [26,57,58,0], + [26,35,0,0], + [47,48,0,0], + [35,36,0,0], + [35,36,0,0], + [36,0,0,0], + [47,58,0,0], + [15,0,0,0], + [26,47,0,0], + [47,58,0,0], + [35,36,47,0], + [28,58,0,0], + [15,47,0,0]] + + return data[x+1][y+1] + +def init_board(): + return [-1] * 3 + [0] * 3 + [1] * 3 + +def print_board(board): + pieces = "X.O" + + space = " "*10 + print() + for i in range(3): + line = "" + for j in range(3): + line += space + space_number = i * 3 + j + space_contents = board[space_number] + line += pieces[space_contents + 1] + print(line) + print() + +def get_coordinates(): + while True: + try: + print ("YOUR MOVE?") + response = input() + m1, m2 = [int(c) for c in response.split(',')] + return m1, m2 + except ValueError as ve: + print("ILLEGAL MOVE.") + +def print_illegal(): + print("ILLEGAL MOVE.") + +def board_contents(board, space_number): + return board[space_number - 1] + +def set_board(board, space_number, new_value): + board[space_number - 1] = new_value + +def main(): + print_header("HEXAPAWN") + if prompt_yes_no("INSTRUCTIONS (Y-N)?"): + print_instructions() + + w = 0 + l = 0 + + x = 0 + y = 0 + + board = init_board() + + print_board(board) + + while True: + m1, m2 = get_coordinates() + + if board_contents(board, m1) != 1: + # Start space doesn't contain player's piece + print_illegal() + continue + if board_contents(board, m2) == 1: + # Destination space contains player's piece (can't capture your own piece) + print_illegal() + continue + # line 160 + is_capture = (m2-m1 != -3) + if is_capture and board_contents(board, m2) != -1: + # Destination does not contain computer piece + print_illegal() + continue + # line 170 + if m2 > m1: + # can't move backwards + print_illegal() + continue + # line 180 + if (not is_capture) and board_contents(board, m2) != 0: + # Destination is not open + print_illegal() + continue + # line 185 + if m2-m1 < -4: + # too far + print_illegal() + continue + # line 186 + if m1 == 7 and m2 == 3: + # can't jump corner to corner ?! + print_illegal() + continue + + # otherwise, acceptable move + break + + set_board(board, m1, 0) + set_board(board, m2, 1) + + # line 205 + print_board(board) + + +if __name__ == "__main__": + main() + +""" +210 IF S(1)=1 OR S(2)=1 OR S(3)=1 THEN 820 +220 FOR I=1 TO 9 +221 IF S(I)=-1 THEN 230 +222 NEXT I +223 GOTO 820 +230 FOR I=1 TO 9 +240 IF S(I)<>-1 THEN 330 +250 IF S(I+3)=0 THEN 350 +260 IF FNR(I)=I THEN 320 +270 IF I>3 THEN 300 +280 IF S(5)=1 THEN 350 +290 GOTO 330 +300 IF S(8)=1 THEN 350 +310 GOTO 330 +320 IF S(I+2)=1 OR S(I+4)=1 THEN 350 +330 NEXT I +340 GOTO 820 +350 FOR I=1 TO 19 +360 FOR J=1 TO 3 +370 FOR K=3 TO 1 STEP -1 +380 T((J-1)*3+K)=B(I,(J-1)*3+4-K) +390 NEXT K +400 NEXT J +410 FOR J=1 TO 9 +420 IF S(J)<>B(I,J) THEN 460 +430 NEXT J +440 R=0 +450 GOTO 540 +460 FOR J=1 TO 9 +470 IF S(J)<>T(J) THEN 510 +480 NEXT J +490 R=1 +500 GOTO 540 +510 NEXT I +511 REMEMBER THE TERMINATION OF THIS LOOP IS IMPOSSIBLE +512 PRINT "ILLEGAL BOARD PATTERN." +530 STOP +540 X=I +550 FOR I=1 TO 4 +560 IF M(X,I)<>0 THEN 600 +570 NEXT I +580 PRINT "I RESIGN." +590 GOTO 820 +600 Y=INT(RND(1)*4+1) +601 IF M(X,Y)=0 THEN 600 +610 IF R<>0 THEN 630 +620 PRINT "I MOVE FROM ";STR$(INT(M(X,Y)/10));" TO ";STR$(FNM(M(X,Y))) +622 S(INT(M(X,Y)/10))=0 +623 S(FNM(M(X,Y)))=-1 +624 GOTO 640 +630 PRINT "I MOVE FROM ";STR$(FNR(INT(M(X,Y)/10)));" TO "; +631 PRINT STR$(FNR(FNM(M(X,Y)))) +632 S(FNR(INT(M(X,Y)/10)))=0 +633 S(FNR(FNM(M(X,Y))))=-1 +640 GOSUB 1000 +641 IF S(7)=-1 OR S(8)=-1 OR S(9)=-1 THEN 870 +650 FOR I=1 TO 9 +660 IF S(I)=1 THEN 690 +670 NEXT I +680 GOTO 870 +690 FOR I=1 TO 9 +700 IF S(I)<>1 THEN 790 +710 IF S(I-3)=0 THEN 120 +720 IF FNR(I)=I THEN 780 +730 IF I<7 THEN 760 +740 IF S(5)=-1 THEN 120 +750 GOTO 790 +760 IF S(2)=-1 THEN 120 +770 GOTO 790 +780 IF S(I-2)=-1 OR S(I-4)=-1 THEN 120 +790 NEXT I +800 PRINT "YOU CAN'T MOVE, SO "; +810 GOTO 870 +820 PRINT "YOU WIN." +830 M(X,Y)=0 +840 L=L+1 +850 PRINT "I HAVE WON";W;"AND YOU";L;"OUT OF";L+W;"GAMES." +851 PRINT +860 GOTO 100 +870 PRINT "I WIN." +880 W=W+1 +890 GOTO 850 +"""