!***************************************************************************!
!                                                                           !
!                                  OTHELO                                   !
!                        Othello for the Alpha Micro                        !
!                                                                           !
!                         Author: David F. Pallmann                         !
!                                                                           !
!***************************************************************************!

STORAGE:
       MAP1 BOARD(8,8), F, 6           !board array
       MAP1 VALUE(8,8), F, 6           !positional value array
       MAP1 I, F, 6                    !temporary
       MAP1 J, F, 6                    !temporary
       MAP1 ROW, F, 6                  !current row
       MAP1 COL, F, 6                  !current column
       MAP1 FLAG, F, 6                 !flag used internally by subroutines
       MAP1 WARN, F, 6                 !flag used to warn of corner give-a-way
       MAP1 ROWDIR, F, 6               !vertical direction of travel
       MAP1 COLDIR, F, 6               !horizontal direction of travel
       MAP1 TESTROW, F, 6              !sample row
       MAP1 TESTCOL, F, 6              !sample column
       MAP1 NEWROW, F, 6               !new row
       MAP1 NEWCOL, F, 6               !new column
       MAP1 COLOR, F, 6                !current color (1=human, 2=alpha)
       MAP1 FLIPS, F, 6                !number of flips from move
       MAP1 TESTFLIPS, F, 6            !number of flips in one direction
       MAP1 MOVE, S, 10                !move text
       MAP1 HIGHFLIPS, F, 6            !highest #flips
       MAP1 BESTROW, F, 6              !row of best move encountered
       MAP1 BESTCOL, F, 6              !column of best move encountered
       MAP1 HDISCS, F, 6               !number of discs - human
       MAP1 ADISCS, F, 6               !number of discs - alpha
       MAP1 SCORE, F, 6                !score of move (flips + pos value)
       MAP1 HIGHSCORE, F, 6            !score of best move encountered

CONSTANTS:
       MAP1 EMPTY, F, 6, 0             !empty square
       MAP1 HUMAN, F, 6, 1             !human disc (O)
       MAP1 ALPHA, F, 6, 2             !alpha disc (@)

REM******************
REM*   INITIALIZE   *
REM******************
REM LOAD POSITIONAL VALUE ARRAY

INITIALIZE:
       FOR I = 1 TO 8
           FOR J = 1 TO 8
               READ VALUE(I,J)
           NEXT J
               NEXT I

       DATA 99,00,80,80,80,80,00,99
       DATA 00,00,00,00,00,00,00,00
       DATA 80,00,40,30,30,40,00,80
       DATA 80,00,30,00,00,30,00,80
       DATA 80,00,30,00,00,30,00,80
       DATA 80,00,40,30,30,40,00,80
       DATA 00,00,00,00,00,00,00,00
       DATA 99,00,80,80,80,80,00,99

REM**************
REM*   SCREEN   *
REM**************
REM SET UP SCREEN

SCREEN: PRINT TAB(-1,0);
       PRINT TAB(-1,12);
       PRINT TAB(1,12); "* OTHELLO *";
       PRINT TAB(-1,11);
       FOR I = 1 TO 8
           PRINT TAB(I*2+1,1); CHR(I+64);
           PRINT TAB(19,I*4); STR(I);
           NEXT I
       PRINT TAB(7,50); "HUMAN MOVE";
       PRINT TAB(10,50); "HUMAN DISCS";
       PRINT TAB(13,50); "ALPHA MOVE";
       PRINT TAB(16,50); "ALPHA DISCS";

REM**************
REM*  NEW'GAME  *
REM**************
REM SET UP SCREEN FOR NEW GAME

NEW'GAME:
       FOR I = 1 TO 8
           FOR J = 1 TO 8
               PRINT TAB(I*2+1,J*4); ".";
               BOARD(I,J) = EMPTY
               NEXT J
           NEXT I
       PRINT TAB(-1,12);
       PRINT TAB(9,16); "O   @"
       BOARD(4,4) = HUMAN : BOARD(4,5) = ALPHA
       PRINT TAB(11,16); "@   O";
       BOARD(5,4) = ALPHA : BOARD(5,5) = HUMAN
       HDISCS = 2
       ADISCS = 2
       PRINT TAB(11,55); SPACE(2);
       PRINT TAB(17,55); SPACE(2);

REM******************
REM*   HUMAN'MOVE   *
REM******************
REM GET, VERIFY, AND MAKE HUMAN MOVE

HUMAN'MOVE:
       IF HDISCS+ADISCS=64 THEN GOTO END'GAME
       PRINT TAB(8,55);
       INPUT LINE MOVE
       PRINT TAB(23,1); TAB(-1,9);
       IF UCS(MOVE)="PASS" THEN GOTO ALPHA'MOVE
       IF LEN(MOVE)<>2 THEN GOTO INVALID
       NEWROW = ASC(MOVE[1;1])-64
       IF NEWROW<1 OR NEWROW>8 THEN GOTO INVALID
       NEWCOL = MOVE[2;1]
       IF NEWCOL<1 OR NEWCOL>8 THEN GOTO INVALID
       IF BOARD(NEWROW,NEWCOL)<>EMPTY THEN GOTO INVALID
       COLOR = HUMAN
       ROW = NEWROW : COL = NEWCOL
       CALL CHECK'MOVE
       IF FLIPS=0 THEN GOTO INVALID
       PRINT TAB(NEWROW*2+1,NEWCOL*4); "O";
       BOARD(NEWROW,NEWCOL) = COLOR
       CALL MAKE'MOVE
       IF WARN=1 THEN PRINT TAB(23,1); "NOT YOUR BEST MOVE";
       HDISCS = HDISCS+FLIPS+1
       ADISCS = ADISCS-FLIPS
       PRINT TAB(11,55); STR(HDISCS); "  ";
       PRINT TAB(17,55); STR(ADISCS); "  ";
       GOTO ALPHA'MOVE

INVALID:
       PRINT TAB(23,1); "INVALID";
       GOTO HUMAN'MOVE

REM******************
REM*   ALPHA'MOVE   *
REM******************
REM MAKE COMPUTER'S MOVE

ALPHA'MOVE:
       PRINT TAB(23,1); "THINKING";
       HIGHFLIPS = 0
       HIGHSCORE = 0
       BESTROW = 0 : BESTCOL = 0
       COLOR = ALPHA
       FOR ROW = 1 TO 8
           FOR COL = 1 TO 8
               IF BOARD(ROW,COL)<>EMPTY THEN GOTO ALPHA'NEXT
               CALL CHECK'MOVE
               IF FLIPS=0 THEN SCORE = 0 : GOTO COMPARE

REASON:         SCORE = FLIPS+VALUE(ROW,COL)
               IF WARN=1 THEN SCORE = 1
               IF ROW=1 THEN CALL ROW'ADJUST
               IF ROW=8 THEN CALL ROW'ADJUST
               IF COL=1 THEN CALL COL'ADJUST
               IF COL=8 THEN CALL COL'ADJUST

COMPARE:        IF SCORE>HIGHSCORE THEN &
                  HIGHFLIPS = FLIPS : HIGHSCORE = SCORE :&
                  BESTROW = ROW : BESTCOL = COL

ALPHA'NEXT:
           NEXT COL
       NEXT ROW
       PRINT TAB(23,1); TAB(-1,9);
       IF HIGHSCORE=0 THEN PRINT TAB(23,1); "ALPHA CAN'T MOVE"; : GOTO HUMAN'MOVE
       ROW = BESTROW : COL = BESTCOL
       PRINT TAB(ROW*2+1,COL*4); "@";
       BOARD(ROW,COL) = COLOR
       PRINT TAB(14,55); CHR(ROW+64); STR(COL);
       CALL MAKE'MOVE
       ADISCS = ADISCS+FLIPS+1
       HDISCS = HDISCS-FLIPS
       PRINT TAB(11,55); STR(HDISCS); "  ";
       PRINT TAB(17,55); STR(ADISCS); "  ";
       PRINT TAB(23,1); "YOUR MOVE";
       GOTO HUMAN'MOVE

REM****************
REM*   END'GAME   *
REM****************
REM END OF GAME

END'GAME:
       PRINT TAB(23,1); TAB(-1,9);
       IF HDISCS<ADISCS THEN PRINT "LOST";
       IF HDISCS=ADISCS THEN PRINT "TIE";
       IF HDISCS>ADISCS THEN PRINT "WON";
       PRINT " GAME";
       PRINT TAB(23,50); "CARE FOR ANOTHER? ";
       INPUT LINE MOVE
       PRINT TAB(23,1); TAB(-1,9);
       IF UCS(LEFT(MOVE,1))="Y" THEN GOTO NEW'GAME
       END

REM******************
REM*   CHECK'MOVE   *
REM******************
REM ON ENTRY:  ROW = ROW TO TEST;  COL = COL TO TEST;  COLOR = MOVER'S COLOR
REM ON EXIT:   FLIPS = #FLIPS MOVE WILL RETURN

CHECK'MOVE:
       FLAG = 0
       GOTO MOVE

REM*****************
REM*   MAKE'MOVE   *
REM*****************
REM ON ENTRY:  ROW = ROW TO TEST;  COL = COL TO TEST;  COLOR = MOVER'S COLOR
REM ON EXIT:   FLIPS = #FLIPS MADE

MAKE'MOVE:
       FLAG = 1

MOVE:   FLIPS = 0
       WARN = 0
       FOR ROWDIR = -1 TO 1
           FOR COLDIR = -1 TO 1
               IF ROWDIR<>0 OR COLDIR<>0 THEN &
                  CALL LINEAR :&
                  FLIPS = FLIPS+TESTFLIPS
               NEXT COLDIR
           NEXT ROWDIR
       RETURN

REM*************
REM*   LINEAR  *
REM*************
REM SUBROUTINE USED BY CHECK'MOVE: AND MAKE'MOVE:
REM
REM ON ENTRY: ROW/COL = ROW/COL TO TEST;  ROWDIR/COLDIR = MOVE DIRECTION;
REM           COLOR = MOVER COLOR
REM ON EXIT:  TESTFLIPS = #FLIPS GENERATED

LINEAR:
       TESTROW = ROW
       TESTCOL = COL
       TESTFLIPS = 0

LINEAR'1:
       TESTROW = TESTROW + ROWDIR
       TESTCOL = TESTCOL + COLDIR
       IF TESTROW<1 THEN GOTO LINEAR'FAIL
       IF TESTROW>8 THEN GOTO LINEAR'FAIL
       IF TESTCOL<1 THEN GOTO LINEAR'FAIL
       IF TESTCOL>8 THEN GOTO LINEAR'FAIL
       IF BOARD(TESTROW,TESTCOL)=EMPTY THEN GOTO LINEAR'FAIL
       IF BOARD(TESTROW,TESTCOL)=COLOR THEN GOTO LINEAR'COLOR

LINEAR'OTHER:
       TESTFLIPS = TESTFLIPS+1
       IF ROW=2 AND COL=2 AND BOARD(1,1)=EMPTY THEN WARN = 1
       IF ROW=2 AND COL=7 AND BOARD(1,8)=EMPTY THEN WARN = 1
       IF ROW=7 AND COL=2 AND BOARD(8,1)=EMPTY THEN WARN = 1
       IF ROW=7 AND COL=7 AND BOARD(8,8)=EMPTY THEN WARN = 1
       GOTO LINEAR'1

LINEAR'FAIL:
       TESTFLIPS = 0
       RETURN

LINEAR'COLOR:
       IF FLAG=0 THEN RETURN
       IF TESTFLIPS=0 THEN RETURN
       ROWDIR = -ROWDIR
       COLDIR = -COLDIR
       FOR I = 1 TO TESTFLIPS
           TESTROW = TESTROW+ROWDIR
           TESTCOL = TESTCOL+COLDIR
           BOARD(TESTROW,TESTCOL) = COLOR
           PRINT TAB(TESTROW*2+1,TESTCOL*4); MID("O@",COLOR,1);
           NEXT I
       ROWDIR = -ROWDIR
       COLDIR = -COLDIR
       RETURN

ROW'ADJUST:     IF COL<2 OR COL>7 THEN RETURN
               IF (BOARD(ROW,COL-1)=(3-COLOR) AND BOARD(ROW,COL+1)=EMPTY) OR &
                  (BOARD(ROW,COL-1)=EMPTY AND BOARD(ROW,COL+1)=(3-COLOR)) THEN &
                  SCORE = 1
               RETURN

COL'ADJUST:     IF ROW<2 OR ROW>7 THEN RETURN
               IF (BOARD(ROW-1,COL)=(3-COLOR) AND BOARD(ROW+1,COL)=EMPTY) OR &
                  (BOARD(ROW-1,COL)=EMPTY AND BOARD(ROW+1,COL)=(3-COLOR)) THEN &
                  SCORE = 1
               RETURN

       END