Post by anthonyrbrown on Nov 25, 2023 10:44:55 GMT
This is the excellent Minimax Chess which for it's size plays a damn good game,it can be improved in many ways and is a great start to any Chess program project
REM DECLARATION OF SUBROUTINES
DECLARE SUB PRINTLOGO ()
DECLARE SUB INITIALIZE ()
DECLARE SUB COMMANDLOOP ()
DECLARE FUNCTION ALPHABETA% (ALPHA%, BETA%, DISTANCE%)
DECLARE SUB GENERATEMOVES (ALLMOVES%)
DECLARE SUB PERFORMMOVE (CURRMOVE%)
DECLARE SUB TAKEBACKMOVE (CURRMOVE%)
DECLARE SUB COPYMAINVARIANT (CURRMOVE%)
DECLARE FUNCTION ATTACKINGFIELD% (FELD%, SIDE%)
DECLARE FUNCTION ASSESSPOSITION% (ALPHA%, BETA%, SIDE%)
DECLARE SUB INITASSESSMENT ()
DECLARE SUB DISPLAYBOARD (BOARDONLY%)
DECLARE SUB COMPUTERMOVE ()
DECLARE SUB INITGAMETREE ()
DECLARE SUB DISPLAYMOVE (CURRMOVE%)
DECLARE SUB DISPLAYMVAR ()
DECLARE SUB PRINTMOVE (CURRMOVE%)
DECLARE SUB PRINTPOSITION ()
DECLARE SUB PRINTBACK ()
DECLARE FUNCTION FIELDNOTATION$ (FIELDNUM%)
DECLARE FUNCTION FIELDNUMBER% (FIELDNOTE$)
DECLARE SUB SAVEPROMOTION (FROM%, TOO%)
DECLARE SUB SAVEMOVE (FROM%, TOO%)
DECLARE SUB SAVECAPTUREMOVE (FROM%, TOO%)
DECLARE SUB SAVEEPMOVE (FROM%, TOO%, EP%)
DECLARE SUB FLIPBOARD ()
DECLARE SUB GAMEOVER ()
DECLARE SUB INPUTPOSITION ()
DECLARE SUB MOVELIST ()
DECLARE SUB MOVEBACK ()
DECLARE SUB COMPUTINGDEPTH ()
DECLARE SUB READPIECE (SIDE%)
DECLARE FUNCTION NEXTBESTMOVE% ()
DECLARE FUNCTION BPASSESSMENT% (FELD%, COLUMN%, ROW%, DEVELOPED%)
DECLARE FUNCTION WPASSESSMENT% (FELD%, COLUMN%, ROW%, DEVELOPED%)
DECLARE FUNCTION INPUTMOVE% (MOVE$)
REM -----------------------------------------------------------------------------------------
_SCREENHIDE
_SCREENSHOW
SCREEN 11
_DELAY 0.05
_SCREENMOVE _MIDDLE
CLS
'--------------------------------------------------------------------
' DEFINITION OF SYMBOLIC CONSTANTS.
'--------------------------------------------------------------------
CONST BOARDDIM% = 119 ' DIMENSION OF EXPANDED CHESS BOARD
CONST MAXDEPTH% = 19 ' MAXIMUM SEARCH DEPTH
CONST MOVEDIRECTIONS% = 15 ' NUMBER OF MOVE DIRECTIONS FOR ALL PIECE.
CONST PIECETYPES% = 6 ' NUMBER OF PIECETYPES - CONSIDERING
' THE MOVE DIRECTIONS (WQUEEN = BQUEEN)
CONST MOVESTACKDIM% = 1000 ' DIMENSION OF MOVE STACKS
' PIECE
CONST BK% = -6 ' BLACK PIECE
CONST BQ% = -5
CONST BN% = -4
CONST BB% = -3
CONST BR% = -2
CONST BP% = -1
CONST EMPTY% = 0 ' EMPTY FIELD
CONST WP% = 1 ' WHITE PIECE
CONST WR% = 2
CONST WB% = 3
CONST WN% = 4
CONST WQ% = 5
CONST WK% = 6
CONST EDGE% = 100 ' THE EDGE OF THE CHESS BOARD
' MATERIAL VALUE OF THE PIECES
CONST MATP% = 100
CONST MATR% = 500
CONST MATB% = 350
CONST MATN% = 325
CONST MATQ% = 900
CONST MATK% = 0 ' AS BOTH SIDES HAVE JUST ONE KING,
' THE VALUE CAN BE SET TO 0
' ASSESSMENT FOR MATE
CONST MATEVALUE% = 32000
CONST MAXPOS% = MATB% ' MAXIMUM OF THE POSITION ASSESSMENT
' BONUS FOR MAIN VARIANTS AND KILLER MOVES
' USED FOR THE SORTING OF MOVES
CONST MAINVARIANTBONUS% = 500
CONST KILLER1BONUS% = 250
CONST KILLER2BONUS% = 150
' TOTAL MATERIAL VALUE IN THE INITIAL POSITION
CONST MATERIALSUM% = 4 * (MATR% + MATB% + MATN%) + (2 * MATQ%)
CONST ENDGAMEMATERIAL% = 4 * MATR% + 2 * MATB%
' FIELD NUMBERS OF FREQUENTLY USED FIELDS
' ("IF BOARD(E1%)=WK%" MEANS "IF BOARD(25)=6")
CONST A1% = 21
CONST B1% = 22
CONST C1% = 23
CONST D1% = 24
CONST E1% = 25
CONST F1% = 26
CONST G1% = 27
CONST H1% = 28
CONST C2% = 33
CONST H2% = 38
CONST A3% = 41
CONST C3% = 43
CONST D3% = 44
CONST E3% = 45
CONST A6% = 71
CONST C6% = 73
CONST D6% = 74
CONST E6% = 75
CONST H6% = 78
CONST A7% = 81
CONST C7% = 83
CONST H7% = 88
CONST A8% = 91
CONST B8% = 92
CONST C8% = 93
CONST D8% = 94
CONST E8% = 95
CONST F8% = 96
CONST G8% = 97
CONST H8% = 98
' VALUES OF COLUMNS AND ROWS
CONST AROW% = 1
CONST BROW% = 2
CONST CROW% = 3
CONST DROW% = 4
CONST EROW% = 5
CONST FROW% = 6
CONST GROW% = 7
CONST HROW% = 8
CONST COLUMN1% = 2
CONST COLUMN2% = 3
CONST COLUMN3% = 4
CONST COLUMN4% = 5
CONST COLUMN5% = 6
CONST COLUMN6% = 7
CONST COLUMN7% = 8
CONST COLUMN8% = 9
' CASTLING NUMBERING (INDEX INTO CASTLING ARRAY)
' OF MOVE IS NOT A CASTLING MOVE
CONST NOCASTLINGMOVE% = 0
CONST SHORTCASTLINGMOVE% = 1
CONST LONGCASTLINGMOVE% = 2
' COLOR OF THE MAN WHO IS MOVING
CONST WHITE% = 1
CONST BLACK% = -1
' SYMBOLIC LOGICAL CONSTANTS
CONST TRUE% = 1
CONST FALSE% = 0
CONST LEGAL% = 1
CONST ILLEGAL% = 0
'-------------------------------------------------------------------
' DEFINITION OF DATA TYPES.
'-------------------------------------------------------------------
' INFORMATION FOR ONE MOVE, THE DATA TYPE OF THE MOVE STACKS
TYPE MOVETYPE
FROM AS INTEGER ' FROM FIELD
TOO AS INTEGER ' TO FIELD
CAPTUREDPIECE AS INTEGER ' CAPTURED PIECE
PROMOTEDPIECE AS INTEGER ' PROMOTED PIECE
CASTLINGNR AS INTEGER ' TYPE OF CASTLING MOVE
EPFIELD AS INTEGER ' ENPASSANT FIELD
VALUE AS INTEGER ' ASSESSMENT FOR THE SORTING OF MOVES
END TYPE
' INDEX OF THE PIECES IN THE OFFSET LIST AND LONG/SHORT PATHS
' (USED BY THE MOVE GENERATOR)
TYPE PIECEOFFSETTYPE
START AS INTEGER
ENDS AS INTEGER
LONGPATHS AS INTEGER
END TYPE
' INFORMATION ON PAWN/PIECE CONSTELLATIONS
TYPE BOTHCOLOURTYPES
WHITE AS INTEGER
BLACK AS INTEGER
END TYPE
' INFORMATION ON FROM/TOO FIELD (MOVES WITHOUT ADDITIONAL INFORMATION)
' USED FOR THE STORING PROMISING MOVES IN (MAIN VARIANTS,
' KILLER MOVES)
TYPE FROMTOOTYPE
FROM AS INTEGER
TOO AS INTEGER
END TYPE
' DATA STRUCTURE FOR STORING KILLER MOVES.
TYPE KILLERTYPE
KILLER1 AS FROMTOOTYPE
KILLER2 AS FROMTOOTYPE
END TYPE
'--------------------------------------------------------------------
' DEFINITION OF GLOBAL VARIABLES AND TABLES
'--------------------------------------------------------------------
DIM SHARED BOARD(BOARDDIM%) AS INTEGER
DIM SHARED EPFIELD(MAXDEPTH%) AS INTEGER
DIM SHARED MOVESTACK(MOVESTACKDIM%) AS MOVETYPE
DIM SHARED MOVECONTROL(H8%) AS INTEGER
' COUNTS HOW OFTEN A PIECE HAS MOVED FROM
' A FIELD. USED TO DETERMINE CASTLING
' RIGHTS (ALSO USEABLE FOR
' ASSESSMENT)
DIM SHARED CASTLING(2) AS INTEGER ' HAS WHITE/BLACK ALREADY CASTLED?
DIM SHARED INDEX AS INTEGER ' INDEX IN MOVESTACK
' SAVES THE POSITION IN THE MOVESTACK. MOVES OF DEPTH 'N' ARE STORED IN
' RANGE (STACKLIMIT(N), STACKLIMIT(N+1)) IN MOVESTACK.
DIM SHARED STACKLIMIT(MAXDEPTH%) AS INTEGER
DIM SHARED MVAR(MAXDEPTH%, MAXDEPTH%) AS FROMTOOTYPE ' MAIN VARIANTS TABLE
DIM SHARED KILLERTAB(MAXDEPTH%) AS KILLERTYPE ' KILLER MOVES TABLE
' TABLES FOR ASSESSMENT FUNCTION
DIM SHARED PAWNCONTROLLED(BOARDDIM%) AS BOTHCOLOURTYPES ' FIELDS THAT ARE
' CONTROLLED BY PAWNS
DIM SHARED PAWNS(HROW% + 1) AS BOTHCOLOURTYPES ' NUMBER OF PAWNS PER ROW
DIM SHARED ROOKS(HROW% + 1) AS BOTHCOLOURTYPES ' NUMBER OF ROOKS PER ROW
DIM SHARED MOBILITY(MAXDEPTH%) AS INTEGER ' MOBILITY OF BISHOPS AND ROOKS
DIM SHARED TOOFELD(MAXDEPTH%) AS INTEGER ' TOOFIELD OF THE MOVES`, USED FOR
' SORTING OF MOVES AND FOR EXTENSION
' OF SEARCHES
DIM SHARED WKING AS INTEGER ' POSITION OF THE WHITE KING
DIM SHARED BKING AS INTEGER ' POSITION OF THE BLACK KING
DIM SHARED MATERIALBALANCE(MAXDEPTH%) AS INTEGER ' MATERIAL BALANCE BETWEEN WHITE/BLACK
DIM SHARED MATERIALTOTAL(MAXDEPTH%) AS INTEGER ' TOTAL MATERIAL ON BOARD
DIM SHARED COLOUR AS INTEGER ' WHO IS TO MAKE A MOVE
DIM SHARED PLAYERPLAYER AS INTEGER ' PLAYER VS PLAYER (MEMO)MODE ON/OFF
DIM SHARED PRINTING AS INTEGER ' PRINTING MOVES OFF/ON
DIM SHARED MINDEPTH AS INTEGER ' GENERALLY SEARCHES ARE PERFORMED
' UNTIL MINDEPTH
DIM SHARED MAXEXTENSION AS INTEGER ' EXTENSIONS IN SEARCH TREE BECAUSE OF
' CHECKS AND CAPTURES ARE ONLY CARRIED OUT
' UNTIL MAXEXTENSION (OTHERIWSE THE
' SEARCH CAN EXPLODE)
DIM SHARED DEPTH AS INTEGER ' SEARCH DEPTH = THE NUMBER OF HALF MOVES
' FROM THE INITIAL POSITION
DIM SHARED NODECOUNT AS LONG ' NUMBER OF EXAMINED POSITIONS/NODES
DIM SHARED LASTMOVE AS INTEGER ' LAST PERFORMED MOVE
DIM SHARED INCHECK AS INTEGER ' PLAYER IS BEING CHECKED
DIM SHARED MOVECOUNT AS INTEGER ' NUMBER OF HALF MOVES DONE SO FAR
DIM SHARED ISWHITELAST AS INTEGER ' FOR PRINTING CONTROL
' INITIALPOSITION OF 10 BY 12 BOARD
DIM SHARED INITIALPOSITION(BOARDDIM%) AS INTEGER
FOR I% = 0 TO BOARDDIM%
READ INITIALPOSITION(I%)
NEXT I%
DATA 100,100,100,100,100,100,100,100,100,100
DATA 100,100,100,100,100,100,100,100,100,100
DATA 100,2,4,3,5,6,3,4,2,100
DATA 100,1,1,1,1,1,1,1,1,100
DATA 100,0,0,0,0,0,0,0,0,100
DATA 100,0,0,0,0,0,0,0,0,100
DATA 100,0,0,0,0,0,0,0,0,100
DATA 100,0,0,0,0,0,0,0,0,100
DATA 100,-1,-1,-1,-1,-1,-1,-1,-1,100
DATA 100,-2,-4,-3,-5,-6,-3,-4,-2,100
DATA 100,100,100,100,100,100,100,100,100,100
DATA 100,100,100,100,100,100,100,100,100,100
' MOVE GENERATOR TABLES
DIM SHARED OFFSET(MOVEDIRECTIONS%) AS INTEGER
OFFSET(0) = -9 ' DIAGONAL PATHS
OFFSET(1) = -11
OFFSET(2) = 9
OFFSET(3) = 11
OFFSET(4) = -1 ' STRAIGHT PATHS
OFFSET(5) = 10
OFFSET(6) = 1
OFFSET(7) = -10
OFFSET(8) = 19 ' KNIGHT PATHS
OFFSET(9) = 21
OFFSET(10) = 12
OFFSET(11) = -8
OFFSET(12) = -19
OFFSET(13) = -21
OFFSET(14) = -12
OFFSET(15) = 8
DIM SHARED FIGOFFSET(PIECETYPES%) AS PIECEOFFSETTYPE
FIGOFFSET(EMPTY%).START = 0 ' EMPTY FIELD
FIGOFFSET(EMPTY%).ENDS = 0
FIGOFFSET(EMPTY%).LONGPATHS = FALSE%
FIGOFFSET(WP%).START = -1 ' PAWN MOVES ARE PRODUCED SEPERATELY
FIGOFFSET(WP%).ENDS = -1
FIGOFFSET(WP%).LONGPATHS = FALSE%
FIGOFFSET(WR%).START = 4 ' ROOK
FIGOFFSET(WR%).ENDS = 7
FIGOFFSET(WR%).LONGPATHS = TRUE%
FIGOFFSET(WB%).START = 0 ' BISHOP
FIGOFFSET(WB%).ENDS = 3
FIGOFFSET(WB%).LONGPATHS = TRUE%
FIGOFFSET(WN%).START = 8 ' KNIGHT
FIGOFFSET(WN%).ENDS = 15
FIGOFFSET(WN%).LONGPATHS = FALSE%
FIGOFFSET(WQ%).START = 0 ' QUEEN
FIGOFFSET(WQ%).ENDS = 7
FIGOFFSET(WQ%).LONGPATHS = TRUE%
FIGOFFSET(WK%).START = 0 ' KING
FIGOFFSET(WK%).ENDS = 7
FIGOFFSET(WK%).LONGPATHS = FALSE%
' CENTRALIZATION TABLES. WE ONLY NEED FILES 0..H8, AS
' PIECE CAN'T STAND ON A FIELD OUTSIDE H8.
' THE LOWER EDGE IS PRESERVED AS WE WOULD OTHERWISE HAVE TO
' TRANSFORM BOARD COORDINATES INTO CENTRALITY COORDINATES.
' H1 IS IS FURTHER AWAY FROM THE CENTER THAN IS G1. IN SPITE OF THIS,
' H1 HAS A BETTER CENTER VALUE THAN G1.
' THIS TABLE IS USED I.E. FOR KING ASSESSMENT.
' THE VALUES OF G1,H1 IMPLY THAT THE KING REMAINS ON G1
' AFTER CASTLING AND DOESN'T PERFORM THE UNNECESSARY MOVE G1-H1.
' (THE KNIGHT IS NEITHER VERY WELL PLACED ON G1 NOR H1).
DIM SHARED CENTERTABLE(H8%) AS INTEGER
FOR I% = 0 TO H8%
READ CENTERTABLE(I%)
NEXT I%
' --- A B C D E F G H ---
DATA 0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0
DATA 0,4,0,8,12,12,8,0,4,0
DATA 0,4,8,12,16,16,12,8,4,0
DATA 0,8,12,16,20,20,16,12,8,0
DATA 0,12,16,20,24,24,20,16,12,0
DATA 0,12,16,20,24,24,20,16,12,0
DATA 0,8,12,16,20,20,16,12,8,0
DATA 0,4,8,12,16,16,12,8,4,0
DATA 0,4,0,8,12,12,8,0,4
' ASSESSMENT OF THE FIELDS FOR THE PAWNS.
' IS USED THE POSITION ASSESSMENT.
' CENTER PAWNS ON THE 2ND ROW IS BAD (THEY BELONG IN THE FRONT).
' F-H PAWNS SHOULD BE BEHIND FOR PROTECTION OF THE KING.
DIM SHARED WPFIELDVALUE(H7%) AS INTEGER ' WHITE PAWNS
FOR I% = 0 TO H7%
READ WPFIELDVALUE(I%)
NEXT I%
' --- A B C D E F G H ---
DATA 0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0
DATA 0,4,4,0,0,0,6,6,6,0
DATA 0,6,6,8,8,8,4,6,6,0
DATA 0,8,8,16,22,22,4,4,4,0
DATA 0,10,10,20,26,26,10,10,10,0
DATA 0,12,12,22,28,28,14,14,14,0
DATA 0,18,18,28,32,32,20,20,20
' NO PAWN CAN STAY ON THE 8TH ROW.
DIM SHARED BPFIELDVALUE(H7%) AS INTEGER ' BLACK PAWNS
FOR I% = 0 TO H7%
READ BPFIELDVALUE(I%)
NEXT I%
' --- A B C D E F G H ---
DATA 0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0
DATA 0,18,18,28,32,32,20,20,20,0
DATA 0,12,12,22,28,28,14,14,14,0
DATA 0,10,10,20,26,26,10,10,10,0
DATA 0,8,8,16,22,22,4,4,4,0
DATA 0,6,6,8,8,8,4,6,6,0
DATA 0,4,4,0,0,0,6,6,6,0
' NO PAWN CAN STAY ON THE 8TH ROW.
' MATERIAL VALUE OF THE PIECES
DIM SHARED PIECEMATERIAL(PIECETYPES%) AS INTEGER
PIECEMATERIAL(EMPTY%) = 0 ' EMPTYFIELD
PIECEMATERIAL(WP%) = MATP% ' PAWN
PIECEMATERIAL(WR%) = MATR% ' ROOK
PIECEMATERIAL(WB%) = MATB% ' BISHOP
PIECEMATERIAL(WN%) = MATN% ' KNIGHT
PIECEMATERIAL(WQ%) = MATQ% ' QUEEN
PIECEMATERIAL(WK%) = MATK% ' KING
' SYMBOLIC REPRESENTATION OF THE PIECES
DIM SHARED FIGSYMBOL(PIECETYPES%) AS STRING * 1
FIGSYMBOL(EMPTY%) = "." ' EMPTYFIELD
FIGSYMBOL(WP%) = "P" ' PAWN
FIGSYMBOL(WR%) = "R" ' ROOK
FIGSYMBOL(WB%) = "B" ' BISHOP
FIGSYMBOL(WN%) = "N" ' KNIGHT
FIGSYMBOL(WQ%) = "Q" ' QUEEN
FIGSYMBOL(WK%) = "K" ' KING
' SYMBOLIC REPRESENTATIONS OF THE PIECES FOR PRINTING
DIM SHARED PRINTSYMBOL(PIECETYPES%) AS STRING * 1
PRINTSYMBOL(EMPTY%) = " " ' EMPTYFIELD
PRINTSYMBOL(WP%) = " " ' PAWN
PRINTSYMBOL(WR%) = "R" ' ROOK
PRINTSYMBOL(WB%) = "B" ' BISHOP
PRINTSYMBOL(WN%) = "N" ' KNIGHT
PRINTSYMBOL(WQ%) = "Q" ' QUEEN
PRINTSYMBOL(WK%) = "K" ' KING
' COLOR SYMBOLS
DIM SHARED COLOURSYMBOL(2) AS STRING * 1
COLOURSYMBOL(0) = "." ' BLACK
COLOURSYMBOL(1) = "." ' EMPTY FIELD
COLOURSYMBOL(2) = "*" ' WHITE
'--------------------------------------------------------------------
' THE ACTUAL PROGRAM BEGINS HERE.
'--------------------------------------------------------------------
CLS
'CALL PRINTLOGO
CALL INITIALIZE
CALL COMMANDLOOP
'--------------------------------------------------------------------
' HERE ENDS THE PROGRAM
'--------------------------------------------------------------------
'--------------------------------------------------------------------
' ALPHABETA: FUNCTION
' ALPHA-BETA TREE SEARCH
' RETURNS ASSESSMENT FROM THE VIEWPOINT OF THE PLAYER WHO IS TO MAKE
' A MOVE. "ALPHA" IS LOWER LIMIT, "BETA" IS THE UPPER LIMIT AND "DISTANCE"
' THE NUMBER OF HALF-MOVES UNTIL THE HORIZON.
' IF "DISTANCE" POSITIVE, A NORMAL ALPHA-BETA SEARCH IS PERFORMED,
' IF LESS THAN 0 THE QUIESCENSE SEARCH.
' RETURNS THE NEGAMAX-VALUE FORM THE POINT OF VIEW OF THE PLAYER WHO IS
' TO MAKE A MOVE.
' THIS PROCEDURE IS CALLED RECURSIVELY.
' LOCALE VARIABLES: I%, VALUE%, BESTVALUE%, CHECK%
' CALLS: GENERATEMOVES; PERFORMMOVE; TAKEBACKMOVE;COPYMAINVARIANT;
' ASSESSPOSITION;NEXTBESTMOVE;
' CALLEDBY: COMPUTERMOVE
'---------------------------------------------------------------------
FUNCTION ALPHABETA% (ALPHA%, BETA%, DISTANCE%)
NODECOUNT = NODECOUNT + 1 ' ADDITIONAL POSITION EXAMINED
MVAR(DEPTH, DEPTH).FROM = 0 ' DELETE CURRENT MAIN VARIANT
' POSITION IS ALWAYS ASSESSED, I.E. ALSO INSIDE OF TREE.
' THIS IS NECESSARY TO RECOGNIZE CHECKMATE AND STALEMATE. ALSO,
' THE ASSESSMENT IS USED TO CONTROL SEARCH/EXTENSION.
' THE NUMBER OF NODES INSIDE THE TREE IS MUCH SMALLER THAN THAT AT
' THE HORIZON. I.E. THE PROGRAM DOES NOT BECOME SIGNIFICANTLY SLOWER
' BECAUSE OF THAT.
' ASSESSMENT FROM THE VIEWPOINT OF THE PLAYER WHO IS TO MAKE A MOVE
VALUE% = ASSESSPOSITION%(ALPHA%, BETA%, COLOUR)
' IN THE CASE OF CHECK, THE SEARCH IS EXTENDED, BY UP TO FOUR
' HALF MOVES TOTAL. OTHERWISE IT MAY HAPPEN THAT THE SEARCH TREE
' BECOMES EXTREMELY LARGE THRU MUTUAL CHECKS AND CAPTURE SEQUENCES.
' AS A RULE, THESE MOVE SEQUENCES ARE COMPLETELY MEANINGLESS.
CHECK% = INCHECK
' SIDE THAT IS MOVING IS IN CHECK, EXTEND THE SEARCH
CONDITION1% = (CHECK% = TRUE% AND DEPTH + DISTANCE% < MAXEXTENSION + 1)
' BY CAPTURE AND RE-CAPTURE ON THE SAME FIELD, THE SEARCH IS
' EXTENDED IF THE MATERIAL BALANCE REMAINS APPROXIMATELY
' THE SAME AND WE DIDN'T MAKE TOO MANY EXTENSIONS
' SO FAR.
CONDITION2% = (DEPTH >= 2 AND DEPTH + DISTANCE% < MAXEXTENSION)
CONDITION2% = CONDITION2% AND TOOFELD(DEPTH) = TOOFELD(DEPTH - 1)
CONDITION2% = CONDITION2% AND VALUE% >= ALPHA% - 150 AND VALUE% <= BETA% + 150
IF CONDITION1% OR CONDITION2% THEN DISTANCE% = DISTANCE% + 1
' IF MORE THAN 5 MOVES WERE ALREADY PERFORMED IN THE QUIESCENSE SEARCH
' OR THE OPPONENT IS CHECKMATED OR WE HAVE REACHED MAXIMUNM SEARCH
' DEPTH IMPOSED BY DATA STRUCTURES, END THE SEARCH.
IF DISTANCE% < -5 OR VALUE% = MATEVALUE% - DEPTH OR DEPTH >= MAXDEPTH% THEN
ALPHABETA% = VALUE%
EXIT FUNCTION
END IF
' IF DURING THE QUIESCENCE SEARCH - THE PLAYER WHO IS TO MOVE HAS A
' GOOD POSITION, THE SEARCH IS ABORTED SINCE BY DEFINITION THE VALUE
' CAN ONLY BECOME BETER DURING THE QUIESCENSE SEARCH.
' WARNING: ABORTS ALREADY AT DISTANCE 1, I.E. A HALF-MOVE BEFORE THE
' HORIZON, IN CASE THE PLAYER WHO IS TO MOVE IS NOT
' BEING CHECKED. THIS IS A SELECTIVE DEVIATION FROM
' THE BRUTE-FORCE-ALPHA-BETA SCHEME.
IF VALUE% >= BETA% AND DISTANCE% + CHECK% <= 1 THEN
ALPHABETA% = VALUE%
EXIT FUNCTION
END IF
' COMPUTE MOVES. IF DISTANCE <= 0 THEN (QUIESCENSE SEARCH) ONLY
' CAPTURE MOVES AND PROMOTION MOVES ARE COMPUTED.
CALL GENERATEMOVES(DISTANCE%) ' EXAMINE IF ANY MOVES ARE AVAILABLE
IF DISTANCE% > 0 THEN ' IS DIRECTLY DONE BY DETERMINING
BESTVALUE% = -MATEVALUE% ' BESTVALUE.
ELSE ' IN QUIESCENCE SEARCH, THE CURRENT
BESTVALUE% = VALUE% ' POSITION ASSESSMENT IS THE LOWER LIMIT
END IF ' OF THE SEARCH VALUE.
I% = NEXTBESTMOVE% ' EXAMINE ALL MOVES IN SORTED SEQUENCE.
DO WHILE I% >= 0 ' SO LONG AS ANY MOVES ARE LEFT.
CALL PERFORMMOVE(I%)
' NEGAMAX PRINCIPAL: THE SIGN IS REVERSED AND
' THE ROLES OF ALPHA AND BETA EXCHANGED.
VALUE% = -ALPHABETA(-BETA%, -ALPHA%, DISTANCE% - 1)
CALL TAKEBACKMOVE(I%)
IF VALUE% > BESTVALUE% THEN ' NEW BEST VALUE FOUND
BESTVALUE% = VALUE%
IF VALUE% >= BETA% THEN ' CUTOFF FOUND
' INSIDE THE TREE, THE MAIN VARIANTS ARE STILL SAVED
IF DISTANCE% > 0 THEN CALL COPYMAINVARIANT(I%)
GOTO DONE
END IF
IF VALUE% > ALPHA% THEN ' VALUE IS THE IMPROVED LOWER LIMIT
IF DISTANCE% > 0 THEN CALL COPYMAINVARIANT(I%) ' MAIN VARIANTS SAVED
ALPHA% = VALUE% ' IMPROVED ALPHA VALUE
END IF
END IF
I% = NEXTBESTMOVE%
LOOP
DONE:
' A GOOD MOVE SHOWING CUTOFF IS ENTERED INTO THE KILLER TABLE.
' KEEP THE BEST KILLER SO FAR AS THE 2ND BEST KILLER.
IF VALUE% >= BETA% AND I% >= 0 THEN
KILLERTAB(DEPTH).KILLER2 = KILLERTAB(DEPTH).KILLER1
KILLERTAB(DEPTH).KILLER1.FROM = MOVESTACK(I%).FROM
KILLERTAB(DEPTH).KILLER1.TOO = MOVESTACK(I%).TOO
END IF
' IF PLAYER HAS NO MORE LEGAL MOVES...
IF BESTVALUE% = -(MATEVALUE% - (DEPTH + 1)) THEN
IF CHECK% = FALSE% THEN ' ... BUT ISN'T BEING CHECKED
ALPHABETA% = 0 ' IT'S STALEMATE
EXIT FUNCTION
END IF
END IF
ALPHABETA% = BESTVALUE%
END FUNCTION
'--------------------------------------------------------------------
' ASSESSPOSITION: FUNCTION
' POSITIONSASSESSMENT
' RETURNS VALUE FROM THE VIEWPOINT OF "SIDE".
' IF MATERIAL VALUE DEVIATES TOO FAR FROM THE ALPHA-BETA WINDOW
' ONLY MATERIAL IS ASSESSED.
' IF "SIDE" IS CHECKMATING, RETURNS (CHECKMATEVALUE -DEPTH).
' IF "SIDE" IS BEING CHECKED, THE VARIABLE INCHECK IS CHANGED
' TO "TRUE".
' WARNING: THE FUNCTION ASSUMES, BOTH FOR CHECK/CHECKMATE AND FOR THE
' KING OPPOSITION, THAT "SIDE" IS THE PLAYER WHO IS TO MAKE MOVE.
'
' LOCAL VARIABLES:
' VALUE%, POSVALUE%, I%, J%, K%, FELD%, WBISHLOP%, BBISHLOP%
' PAWNCOUNT%, MATNUM%, WROOKON7%, BROOKON2%
' WDEVELOPED%, BDEVELOPED%
' CALLS: INITASSESSMENT; PERFORMMOVE; TAKEBACKMOVE; ATTACKINGFIELD;
' CALLEDBY: ATTACKINGFIELD; BPASSESSMENT; QPASSESSMENT; COMMANDLOOP;
' ALPHABETA; COMPUTERMOVE
'--------------------------------------------------------------------
FUNCTION ASSESSPOSITION% (ALPHA%, BETA%, SIDE%)
' FIRST EXAMINE IF OPPONENT IS CHECKMATED
' OF "SIDE" IS BEING CHECKED.
IF SIDE% = WHITE% THEN
IF ATTACKINGFIELD%(BKING, WHITE%) = TRUE% THEN
ASSESSPOSITION% = MATEVALUE% - DEPTH
EXIT FUNCTION
END IF
INCHECK = ATTACKINGFIELD%(WKING, BLACK%) ' IS WHITE BEING CHECKED?
ELSE
IF ATTACKINGFIELD%(WKING, BLACK%) = TRUE% THEN
ASSESSPOSITION% = MATEVALUE% - DEPTH
EXIT FUNCTION
END IF
INCHECK = ATTACKINGFIELD%(BKING, WHITE%) ' IS BLACK BEING CHECKED?
END IF
' POSITIONAL ASSESSMENTS FACTORS DO NOT OUTWIEGH A HEAVY MATERIAL
' IMBALANCE. HENCE, WE OMIT THE POSITION ASSESSMENT IN THIS CASE
' EXCEPTION: THE LATE ENDGAME. FREE PAWNS HAVE A HIGH VALUE.
' A MINOR PIECE WITHOUT PAWNS IS WITHOUT EFFECT.
VALUE% = MATERIALBALANCE(DEPTH)
MATNUM% = MATERIALTOTAL(DEPTH)
IF MATNUM% > MATB% + MATB% THEN
IF VALUE% < ALPHA% - MAXPOS% OR VALUE% > BETA% + MAXPOS% THEN
ASSESSPOSITION% = VALUE%
EXIT FUNCTION
END IF
END IF
' INITIALIZE THE LINES OF ROOKS AND PAWNS AS WELL AS THE PAWN CONTROLS.
' THIS COULD BE COMPUTED INCREMENTALLY SIGNIFICANTLY FASTER WHEN
' PERFORMING (AND TAKING BACK) THE MOVES. HOWEVER, THIS INCREMENTAL
' COMPUTATION IS DIFFICULT AND ERROR-PRONE DUE TO THE SPECIAL CASES
' CASTLING, ENPASSANT, AND PROMOTION.
' YOU COULD ALSO BUILD A LIST OF PIECES IN 'ININASSESSMENT' AND
' IN THE SECOND TURN GO THRU THIS LIST (AND NO LONGER THE ENTIRE
' BOARD).
' THE FASTEST SOLUTION CONSISTS OF COMPUTING THIS LIST OF PIECES
' INCREMENTALLY, TOO. THIS COMPLICATES, HOWEVER, THE FUNCTIONS
' "PERFORMMOVE" AND "TAKEBACKMOVE".
' FOLLOWING THE KISS PRINIPAL (KEEP IT SIMPLE STUPID) THIS
' SOLUTION WAS CHOSEN IN MINIMAX.
CALL INITASSESSMENT
POSVALUE% = 0
' USED FOR ASSESSING THE BISHOP PAIR.
BBISHLOP% = 0
WBISHLOP% = 0
' USED FOR DETERMINING INSUFFICIENT MATERIAL.
PAWNCOUNT% = 0
' WHITE ROOKS ON 7/8TH ROW, BLACK ROOKS ON THE 1/2ND
WROOKON7% = 0
BROOKON2% = 0
' DEVELOPEMENT STATE: CASTLED AND MINOR PIECE DEVELOPED.
WDEVELOPED% = CASTLING(WHITE% + 1)
BDEVELOPED% = CASTLING(BLACK% + 1)
' KNIGHT ON B1 DEVELOPED?
IF MOVECONTROL(B1%) > 0 THEN WDEVELOPED% = WDEVELOPED% + 1
' BISHOP ON C1 DEVELOPED?
IF MOVECONTROL(C1%) > 0 THEN WDEVELOPED% = WDEVELOPED% + 1
' BISHOP ON F1 DEVELOPED?
IF MOVECONTROL(F1%) > 0 THEN WDEVELOPED% = WDEVELOPED% + 1
' KNIGHT ON G1 DEVELOPED?
IF MOVECONTROL(G1%) > 0 THEN WDEVELOPED% = WDEVELOPED% + 1
' KNIGHT ON B8 DEVELOPED?
IF MOVECONTROL(B8%) > 0 THEN BDEVELOPED% = BDEVELOPED% + 1
' BISHOP ON C8 DEVELOPED?
IF MOVECONTROL(C8%) > 0 THEN BDEVELOPED% = BDEVELOPED% + 1
' BISHOP ON F8 DEVELOPED?
IF MOVECONTROL(F8%) > 0 THEN BDEVELOPED% = BDEVELOPED% + 1
' KNIGHT ON G8 DEVELOPED?
IF MOVECONTROL(G8%) > 0 THEN BDEVELOPED% = BDEVELOPED% + 1
' READ THE ENTIRE BOARD AND ASSESS EACH PIECE.
' THE ASSESSMENT TAKES WHITE'S POINT OF VIEW. FOR THE BLACK
' PIECES, A POSITIVE ASSESSMENT MEANS THAT THIS EVALUATION
' IS UNFAVORABLE FOR BLACK.
FOR I% = COLUMN1% TO COLUMN8%
FELD% = I% * 10
FOR J% = AROW% TO HROW%
FELD% = FELD% + 1
SELECT CASE BOARD(FELD%)
CASE BK%
IF MATNUM% < ENDGAMEMATERIAL% THEN ' ENDGAME ASSESSMENT FOR KING
' CENTRALISZE THE KING IN THE ENDGAME.
POSVALUE% = POSVALUE% - CENTERTABLE(FELD%)
ELSE
' NOT YET CASTLED, BUT CASTLING RIGHTS LOST
IF CASTLING(BLACK% + 1) = FALSE% THEN
IF MOVECONTROL(E8%) > 0 OR (MOVECONTROL(H8%) > 0 AND MOVECONTROL(A8%) > 0) THEN
POSVALUE% = POSVALUE% + 35
END IF
END IF
' KING PREFERABLY NOT IN THE CENTER
POSVALUE% = POSVALUE% + 4 * CENTERTABLE(FELD%)
FOR K% = -1 TO 1
' BONUS FOR PAWN SHIELD BEFORE THE KING
IF BOARD(FELD% - 10 + K%) = BP% THEN POSVALUE% = POSVALUE% - 15
' PAWN SHIELD 2 ROWS BEFORE THE KING
IF BOARD(FELD% - 20 + K%) = BP% THEN POSVALUE% = POSVALUE% - 6
' DEDUCT FOR HALF-OPEN LINE OCCUPIED BY
' ENEMY ROOK.
IF PAWNS(J% + K%).WHITE = 0 AND ROOKS(J% + K%).WHITE > 0 THEN
POSVALUE% = POSVALUE% + 12
END IF
NEXT K%
END IF
CASE BQ%
' AVOID QUEEN OUTINGS IN THE OPENING OF THE GAME.
IF BDEVELOPED% < 4 THEN
IF FELD% < A8% THEN POSVALUE% = POSVALUE% + 15
ELSE ' IF DEVELOPMENT IS COMPLETED, PLACE THE QUEEN NEAR
' THE ENEMY KING. COLUMN AND ROW DISTANCE.
' BETWEEN QUEEN AND ENEMY KING SHOULD BE SMALL.
COLUMNNDIFF% = ABS(WKING \ 10 - FELD% \ 10)
ROWNDIFF% = ABS(WKING MOD 10 - FELD% MOD 10)
POSVALUE% = POSVALUE% + 2 * (COLUMNNDIFF% + ROWNDIFF%)
END IF
CASE BN% ' BLACK KNIGHT
POSVALUE% = POSVALUE% - CENTERTABLE(FELD%) / 2 ' CENTRALIZE KNIGHT
CASE BB%
' BISHOP SHOULD NOT IMPEDE BLACK D7/E7 PAWNS
' BISHOP IS ALSO ASSESSED BY VARIABLE MOBILITY
' IN THE MOVE GENERATOR.
IF (FELD% = D6% OR FELD% = E6%) AND BOARD(FELD% + 10) = BP% THEN
POSVALUE% = POSVALUE% + 20
END IF
BBISHLOP% = BBISHLOP% + 1 ' NO. OF BISHOPS FOR THE BISHOP PAIR
CASE BR% ' ROOK INFLUENCES THE KING ASSESSMENT
' BLACK ROOK HAS PENETRATED ROW 1 OR 2
IF FELD% <= H2% THEN BROOKON2% = BROOKON2% + 1
' BRING ROOKS FROM A AND H COLUMNS INTO THE CENTER
IF J% >= CROW% AND J% <= EROW% THEN POSVALUE% = POSVALUE% - 4
' ROOKS ON HALF OPEN AND OPEN LINES
IF PAWNS(J%).WHITE = 0 THEN
POSVALUE% = POSVALUE% - 8 ' ROOK ON HALF OPEN LINE
' ROOK ON OPEN LINE
IF PAWNS(J%).BLACK = 0 THEN POSVALUE% = POSVALUE% - 5
END IF
CASE BP% ' PAWN ASSESSMENT IS RELATIVELY COMPLEX.
' THUS IT IS ACCOMPLISED IN A SEPERATE ROUTINE.
POSVALUE% = POSVALUE% - BPASSESSMENT%((FELD%), (I%), (J%), (BDEVELOPED%))
PAWNCOUNT% = PAWNCOUNT% + 1
CASE EMPTY%
' DO NOTHING
CASE WP% ' WHITE ASSESSMENT IS ANALOGOUS TO THE BLACK
POSVALUE% = POSVALUE% + WPASSESSMENT%((FELD%), (I%), (J%), (WDEVELOPED%))
PAWNCOUNT% = PAWNCOUNT% + 1
CASE WR%
' WHITE ROOK ON 7TH OR 8TH ROW
IF FELD% >= A7% THEN WROOKON7% = WROOKON7% + 1
' BRING ROOKS FROM A AND H COLUMNS INTO THE CENTER
IF J% >= CROW% AND J% <= EROW% THEN POSVALUE% = POSVALUE% + 4
' ROOKS ON HALF OPEN AND OPEN LINES
IF PAWNS(J%).BLACK = 0 THEN
POSVALUE% = POSVALUE% + 8 ' ROOK ON HALF OPEN LINE
' ROOK ON OPEN LINE
IF PAWNS(J%).WHITE = 0 THEN POSVALUE% = POSVALUE% + 5
END IF
CASE WB%
' BISHOP SHOULD NOT BLOCK PAWNS ON D3/E3.
IF (FELD% = D3% OR FELD% = E3%) AND BOARD(FELD% - 10) = WP% THEN
POSVALUE% = POSVALUE% - 20
END IF
WBISHLOP% = WBISHLOP% + 1
CASE WN%
POSVALUE% = POSVALUE% + CENTERTABLE(FELD%) \ 2
CASE WQ%
' AVOID QUEEN OUTINGS IN THE BEGINING OF THE GAME.
IF WDEVELOPED% < 4 THEN
IF FELD% > H1% THEN POSVALUE% = POSVALUE% - 15
ELSE ' PLACE THE QUEEN NEAR THE ENEMY KING.
' COLUMN AND ROW DISTANCE.
' BETWEEN QUEEN AND ENEMY KING SHOULD BE SMALL.
COLUMNNDIFF% = ABS(BKING \ 10 - FELD% \ 10)
ROWNDIFF% = ABS(BKING MOD 10 - FELD% MOD 10)
POSVALUE% = POSVALUE% - 2 * (COLUMNNDIFF% + ROWNDIFF%)
END IF
CASE WK%
IF MATNUM% < ENDGAMEMATERIAL% THEN ' ENDGAME ASSESSMENT FOR KING
' CENTRALIZE THE KING IN THE ENDGAME
POSVALUE% = POSVALUE% + CENTERTABLE(FELD%)
' NEAR OPPOSITION OF THE KINGS
IF ABS(FELD% - BKING) = 20 OR ABS(FELD% - BKING) = 2 THEN
K% = 10
' OPPOSITION IN THE PAWN ENDGAME
IF MATNUM% = 0 THEN K% = 30
IF COLOUR = WHITE% THEN
POSVALUE% = POSVALUE% - K%
ELSE
POSVALUE% = POSVALUE% + K%
END IF
END IF
ELSE
' NOT CASTLED YET, BUT CASTLING RIGHTS LOST.
IF CASTLING(WHITE% + 1) = FALSE% THEN
IF MOVECONTROL(E1%) > 0 OR (MOVECONTROL(H1%) > 0 AND MOVECONTROL(A1%) > 0) THEN
POSVALUE% = POSVALUE% - 35
END IF
END IF
' KING PREFERABLE NOT IN THE CENTER
POSVALUE% = POSVALUE% - 4 * CENTERTABLE(FELD%)
FOR K% = -1 TO 1
' BONUS FOR PAWN SHIELD BEFORE THE KING
IF BOARD(FELD% + 10 + K%) = WP% THEN POSVALUE% = POSVALUE% + 15
' PAWNS SHIELD 2 ROWS BEFORE THE KING
IF BOARD(FELD% + 20 + K%) = WP% THEN POSVALUE% = POSVALUE% + 6
' DEDUCT FOR HALF OPEN LINES OCCUPIED BY
' ENEMY ROOK.
IF PAWNS(J% + K%).BLACK = 0 AND ROOKS(J% + K%).BLACK > 0 THEN
POSVALUE% = POSVALUE% - 12
END IF
NEXT K%
END IF
END SELECT
NEXT J%
NEXT I%
' NO PAWNS LEFT ON BOARD AND INSUFFICIENT MATERIAL
' RECOGNIZED ALL ELEMENTARY DRAW SITUATIONS.
' KK, KLK, KSK, KSSK, KLKL, KSKL.
IF PAWNCOUNT% = 0 THEN
BED1% = MATNUM% <= MATB% ' LESS THAN A BISHOP
BED2% = MATNUM% = 2 * MATN% ' TWO KNIGHTS
' TWO BISHOPS, BUT MATERIAL DIFFERECE LESS THAN A PAWN
BED3% = MATNUM% <= 2 * MATB% AND ABS(MATERIALBALANCE(DEPTH)) < MATP%
IF BED1% OR BED2% OR BED3% THEN
ASSESSPOSITION% = 0
EXIT FUNCTION
END IF
END IF
' BISHOP PARE BONUS FOR WHITE
IF WBISHLOP% >= 2 THEN POSVALUE% = POSVALUE% + 15
' BISHOP PAIR BONUS FOR BLACK
IF BBISHLOP% >= 2 THEN POSVALUE% = POSVALUE% - 15
' WHITE ROOKS ON 7/8TH ROW AND BLACK KING ALSO
' ON THESE ROWS
IF WROOKON7% > 0 AND BKING >= A7% THEN
POSVALUE% = POSVALUE% + 10
' DOUBLE ROOKS EXTRA DANGEROUS
IF WROOKON7% > 1 THEN POSVALUE% = POSVALUE% + 25
END IF
' BLACK ROOKS ON 1/2ND ROW AND WHITE KING ALSO
' ON THESE ROWS
IF BROOKON2% > 0 AND WKING <= H2% THEN
POSVALUE% = POSVALUE% - 10
IF BROOKON2% > 1 THEN POSVALUE% = POSVALUE% - 25
END IF
IF SIDE% = BLACK% THEN ' ASSESSMENT WAS FROM WHITE'S POINT OF VIEW,
POSVALUE% = -POSVALUE% ' CHANGED SIGN FOR BLACK
END IF
' CONSIDER THE MOBILITY OF BISHOP AND ROOKS
' BY THE MOVE GENERATOR. MOBILITY(DEPTH) IS THE
' MOBILITY OF THE OPPENENT, MOBILITY(DEPTH-1) THAT OF
' "SIDE" (BEFORE THE OPPENENT HAS MADE A MOVE).
IF DEPTH >= 1 THEN
POSVALUE% = POSVALUE% - ((MOBILITY(DEPTH) - MOBILITY(DEPTH - 1)) / 16)
END IF
ASSESSPOSITION% = VALUE% + POSVALUE%
END FUNCTION
'--------------------------------------------------------------------
' ATTACKINGFIELD: FUNCTION
' EXAMINE WHETHER PLAYER "SIDE" IS ATTACKING THE FIELD "FIELD".
' RETURNS "TRUE" IF FIELD IS ATTACKED BY "SIDE", OTHERWISE "FALSE".
' ALGORITHM: IMAGINE "FIELD" OCCUPIED BY A SUPER PIECE, THAT CAN MOVE
' IN ANY DIRECTION. IF THIS SUPER PIECE 'CAPTURES' E.G.
' A ROOK BELONGING TO "SIDE" THEN THE ROOK IS ACTUALLY
' ATTACKING THE FIELD.
'
' LOCALE VARIABLES: I%, DIRECTION%, TOO%, PIECE%, SLIDE%
' CALLS:
' CALLEDBY: ASSESSPOSITION; GENERATEMOVES; INPUTMOVE; MOVELIST
'--------------------------------------------------------------------
FUNCTION ATTACKINGFIELD% (FELD%, SIDE%)
' FIRST TEST THE SPECIAL CASE OF PAWNS. THEY HAVE THE SAME DIRECTION
' AS BISHOPS BUT DON'T SLIDE.
IF SIDE% = WHITE% THEN
' MUST GO IN THE OPPOSITE DIRECTION OF PAWNS. D5 IS ATTACKED
' BY PAWN ON E4.
IF BOARD(FELD% - 9) = WP% OR BOARD(FELD% - 11) = WP% THEN
ATTACKINGFIELD% = TRUE%
EXIT FUNCTION
END IF
END IF
IF SIDE% = BLACK% THEN
IF BOARD(FELD% + 9) = BP% OR BOARD(FELD% + 11) = BP% THEN
ATTACKINGFIELD% = TRUE%
EXIT FUNCTION
END IF
END IF
' EXAMINE THE KNIGHT
FOR I% = 8 TO 15 ' KNIGHT DIRECTIONS
TOO% = FELD% + OFFSET(I%)
IF BOARD(TOO%) = EMPTY% OR BOARD(TOO%) = EDGE% THEN GOTO W1
IF SIDE% = WHITE% THEN
IF BOARD(TOO%) = WN% THEN
ATTACKINGFIELD% = TRUE%
EXIT FUNCTION
END IF
ELSEIF BOARD(TOO%) = BN% THEN
ATTACKINGFIELD% = TRUE%
EXIT FUNCTION
END IF
W1:
NEXT I%
' EXAMINE SLIDING PIECES AND KING.
FOR I% = 0 TO 7
TOO% = FELD%
DIRECTION% = OFFSET(I%)
SLIDE% = 0
SLIDEON1:
SLIDE% = SLIDE% + 1
TOO% = TOO% + DIRECTION%
IF BOARD(TOO%) = EMPTY% THEN
GOTO SLIDEON1
END IF
' WHEN THE EDGE IS REACHED THEN NEW DIRECTION
IF BOARD(TOO%) = EDGE% THEN GOTO W2
' HIT A PIECE. PIECE MUST BE COLOR SIDE.
' ALSO, THE CURRENT DIRECTION MUST BE A POSSIBLE MOVE DIRECTION
' OF THE PIECE. THE KING CAN ONLY DO ONE STEP.
PIECE% = BOARD(TOO%)
IF SIDE% = WHITE% THEN
IF PIECE% > 0 THEN ' WHITE PPECE
IF PIECE% = WK% THEN
IF SLIDE% <= 1 THEN ' KING IS SLOW PACED
ATTACKINGFIELD% = TRUE%
EXIT FUNCTION
END IF
ELSE
' AS FAR AS SLIDING PIECES ARE CONCERNED, THE CURRENT
' DIRECTION MUSE BE A POSSIBLE MOVE DIECTION OF THE PIECE.
IF FIGOFFSET(PIECE%).START <= I% THEN
IF FIGOFFSET(PIECE%).ENDS >= I% THEN
ATTACKINGFIELD% = TRUE%
EXIT FUNCTION
END IF
END IF
END IF
END IF
ELSE
IF PIECE% < 0 THEN ' BLACK PIECE
IF PIECE% = BK% THEN
IF SLIDE% <= 1 THEN
ATTACKINGFIELD% = TRUE%
EXIT FUNCTION
END IF
ELSE
IF FIGOFFSET(-PIECE%).START <= I% THEN
IF FIGOFFSET(-PIECE%).ENDS >= I% THEN
ATTACKINGFIELD% = TRUE%
EXIT FUNCTION
END IF
END IF
END IF
END IF
END IF
W2:
NEXT I%
' ALL DIRECTIONS EXHAUSTED, DIDN'T HIT A PIECE.
' I.E. SIDE IN NOT ATTACKING THE FIELD.
ATTACKINGFIELD% = FALSE%
END FUNCTION
'--------------------------------------------------------------------
' BPASSESSMENT: FUNCTION
' ASSESSMENT OF ONE BLACK PAWN. BESIDES PASSED PARAMETERS, THE
' PAWN CONTROLS, PAWN LINES, AND ROOK LINES MUST BE CORRECTLY
' ENGAGED.
' RETURNS THE ASSESSMENT FROM BLACK'S POINT OF VIEW.
' CALLS:
' CALLEDBY: ASSESSPOSITION
'--------------------------------------------------------------------
FUNCTION BPASSESSMENT% (FELD%, COLUMN%, ROW%, DEVELOPED%)
COLUMN% = (COLUMN8% + COLUMN1%) - COLUMN% ' FLIP ROW. THIS MAKES HIGHER
'ROW = BETTER AS FOR WHITE.
IF MATERIALTOTAL(DEPTH) > ENDGAMEMATERIAL% THEN ' OPENING OR MIDGAME
VALUE% = BPFIELDVALUE(FELD%)
' IF DEVELOPMENT INCOMPLETE, DON'T PUSH EDGE PAWNS FORWARD
IF DEVELOPED% < 4 THEN
IF (ROW% >= FROW% OR ROW% <= BROW%) AND COLUMN% > COLUMN3% THEN
VALUE% = VALUE% - 15
END IF
END IF
ELSE ' IN THE ENDGAME, ALL LINES ARE EQUALLY GOOD.
' BRING PAWNS FORWARD.
VALUE% = COLUMN% * 4
END IF
' IS THE PAWN ISOLATED?
' EDGE PAWNS DON'T REQUIRE EXTRA TREATMENT. PAWNS(AROW-1) IS
' THE LEFT EDGE, PAWNS(HROW+1) THE RIGHT EDGE. NO PAWN IS
' PLACED ON THESE EDGES.
IF PAWNS(ROW% - 1).BLACK = 0 AND PAWNS(ROW% + 1).BLACK = 0 THEN
VALUE% = VALUE% - 12 ' ISOLATED
' ISOLATED DOUBLE PAWN
IF PAWNS(ROW%).BLACK > 1 THEN VALUE% = VALUE% - 12
END IF
' DOUBLE PAWN
IF PAWNS(ROW%).BLACK > 1 THEN VALUE% = VALUE% - 15
' DUO OR GUARDED PAWNS GET A BONUS
' E.G. E5,D5 IS A DUO, D6 GUARDS E5
IF PAWNCONTROLLED(FELD%).BLACK > 0 OR PAWNCONTROLLED(FELD% - 10).BLACK > 0 THEN
VALUE% = VALUE% + COLUMN%
END IF
IF PAWNS(ROW%).WHITE = 0 THEN ' HALF-OPEN COLUMN
' PAWN LEFT BEHIND ON HALF-OPEN COLUMN:
' LEFT-BEHIND PAWN IS NOT GUARDED BY ITS FELLOW PAWNS..
CONDITION1% = PAWNCONTROLLED(FELD%).BLACK = 0
' ... AND CAN'T ADVANCE BECAUSE OF ENEMY PAWNS
' CONTROL THE FIELD IN FRONT OF HIM.
CONDITION2% = PAWNCONTROLLED(FELD% - 10).WHITE > PAWNCONTROLLED(FELD% - 10).BLACK
IF CONDITION1% AND CONDITION2% THEN
VALUE% = VALUE% - 10
' ROOK IMPEDED BY LEFT-BEHIND PAWN
IF ROOKS(ROW%).WHITE > 0 THEN VALUE% = VALUE% - 8
ELSE
' PAWN IS A FREE PAWN, ON AN HALF-OPEN COLUMN AND THE
' FIELDS AHEAD ON HIS COLUMN ARE NOT CONTROLLED BY
' ENEMY PAWNS.
FOR J% = FELD% TO A3% STEP -10 ' UNTIL 3RD ROW
IF PAWNCONTROLLED(J%).WHITE > 0 THEN
BPASSESSMENT% = VALUE%
EXIT FUNCTION
END IF
NEXT J%
' FOUND A FREE PAWN. IN THE ENDGAME, A FREE PAWN IS MORE IMPORTANT
' THAN IN MIDGAME.
IF MATERIALTOTAL(DEPTH) < ENDGAMEMATERIAL% THEN
VALUE% = VALUE% + COLUMN% * 16 ' THE MORE ADVANCED, THE BETTER
' ROOK GUARDS A FREE PAWN ON THE SAME COLUMN
IF ROOKS(ROW%).BLACK > 0 THEN VALUE% = VALUE% + COLUMN% * 2
' ENEMY ROOK ON THE SAME COLUMN
IF ROOKS(ROW%).WHITE > 0 THEN VALUE% = VALUE% - COLUMN% * 2
' PURE PAWN ENDGAME. FREE PAWN PARTICULARLY VALUABLE.
IF MATERIALTOTAL(DEPTH) = 0 THEN VALUE% = VALUE% + COLUMN% * 8
' GUARDED FREE PAWN
IF PAWNCONTROLLED(FELD%).BLACK > 0 OR PAWNCONTROLLED(FELD% - 10).BLACK > 0 THEN
VALUE% = VALUE% + COLUMN% * 4
END IF
' FREE PAWN BLOCKED BY A WHITE PIECE. THIS PIECE IS NOT
' THREATENED BY FELLOW PAWNS.
IF BOARD(FELD% - 10) < 0 AND PAWNCONTROLLED(FELD% - 10).BLACK = 0 THEN
VALUE% = VALUE% - COLUMN% * 4
END IF
ELSE ' FREE PAWN IN THE MIDGAME
VALUE% = VALUE% + COLUMN% * 8
' GUARDED FREE PAWN
IF PAWNCONTROLLED(FELD%).BLACK > 0 OR PAWNCONTROLLED(FELD% - 10).BLACK > 0 THEN
VALUE% = VALUE% + COLUMN% * 2
END IF
END IF
END IF
END IF
BPASSESSMENT% = VALUE%
END FUNCTION
'--------------------------------------------------------------------
' COMMANDLOOP:
' READS THE PLAYER'S COMMANDS IN A LOOP AND CALLS
' THE APPROPRIATE FUNCTIONS. THE LOOP IS TERMINATED BY
' THE "EN" COMMAND.
' IF THE INPUT IS NOT A COMMAND IT IS INTERPRETED AS A
' MOVE (ON THE FORM "E2E4" (FROM-FIELD,TO-FIELD).
' AND IGNORED AS A COMMAND. SEE ALSO: PRINTLOGO
' CALLS: GAMEOVER; INITIALIZE; DISPLAYBOARD; INPUTPOSITION;
' COMPUTERMOVE; FLIPBOARD; MOVELIST; MOVEBACK;
' COMPUTINGDEPTH; INITGAMETREE; ASSESSPOSITION;
' CALLEDBY: MAIN
'--------------------------------------------------------------------
SUB COMMANDLOOP
ENDS% = FALSE%
DO
CALL DISPLAYBOARD(FALSE%) ' MY NEW LINE
PRINT
INPUT "YOUR INPUT: ", COMMANDS$
COMMANDS$ = UCASE$(COMMANDS$) ' CHANGE TO UPPER CASE
SELECT CASE COMMANDS$
CASE "EN"
ENDS% = TRUE%
CALL GAMEOVER
CASE "NG"
PRINT " NEW GAME"
CALL INITIALIZE
CASE "DB"
CALL DISPLAYBOARD(FALSE%)
CASE "CP"
CALL INPUTPOSITION
CASE "PL"
CALL COMPUTERMOVE
CASE "FB"
CALL FLIPBOARD
CASE "PR"
PRINT " PRINTING ";
IF PRINTING = FALSE% THEN
PRINTING = TRUE%
PRINT "ON"
ELSE
PRINTING = FALSE%
PRINT "OFF"
END IF
CASE "MM"
PRINT " PLAYER-PLAYER ";
IF PLAYERPLAYER = FALSE% THEN
PLAYERPLAYER = TRUE%
PRINT "ON"
ELSE
PLAYERPLAYER = FALSE%
PRINT "OFF"
END IF
CASE "ML"
CALL MOVELIST
CASE "TB"
CALL MOVEBACK
CASE "SD"
CALL COMPUTINGDEPTH
CASE "DA"
CALL INITGAMETREE
PRINT " ASSESSMENT= "; ASSESSPOSITION%(-MATEVALUE%, MATEVALUE%, COLOUR)
CASE ELSE
IF INPUTMOVE%(COMMANDS$) = FALSE% THEN
PRINT " ILLEGAL MOVE OR UNKNOWN COMMAND"
ELSEIF PLAYERPLAYER = FALSE% THEN
CALL COMPUTERMOVE
END IF
END SELECT
LOOP WHILE ENDS% = FALSE%
END SUB
'--------------------------------------------------------------------
' COMPUTERMOVE:
' COMPUTES THE NEXT COMPUTER MOVE.
' THE SEARCH IS ITERATIVELY DEEPENED UNTIL MINDEPTH.
' THE SEARCH USES "ASPIRATION"-ALPHA-BETA.
' THE SEARCH PROCESS CAN BE INTERUPTED BY
' A KEYPRESS.
' IF THE SEARCH WASN'T INTERUPTED AND NO CHECKMATE/STALEMATE
' EXISTS, THE BEST MOVE IS PERFORMED.
' CALLS: INITGAMETREE; GENERATEMOVES; DISPLAYMOVE; TAKEBACKMOVE;
' PERFORMMOVE; COPYMAINVARIANT; DISPLAYMVAR; PRINTMOVE
' ASSESSPOSITION;
' CALLEDBY: COPYMAINVARIANT; ALPHABETA; ASSESSPOSITION; COMMANDLOOP
'--------------------------------------------------------------------
SUB COMPUTERMOVE
DIM TMP AS MOVETYPE ' TEMPORARY MOVETYPE VARIABLE
CALL INITGAMETREE
' ASSESS THE INITIAL POSITION. END SEARCH IF OPPONENT IS ALREADY CHECKMATE.
VALUE% = ASSESSPOSITION%(-MATEVALUE%, MATEVALUE%, COLOUR)
IF VALUE% = MATEVALUE% THEN
PRINT " CHECKMATE!"
EXIT SUB
END IF
' STORE "CHECKED STATE". REQUIRED TO RECOGNIZE
' STALEMATE AT THE END OF THE SEARCH.
CHECK% = INCHECK
NODECOUNT = 0
' START TIME OF THE COMPUTATION. USED FOR DISPLAYING NODES/SECOND.
STARTTIME = TIMER
' GENERATE ALL PSEUDO-LEGAL MOVES
CALL GENERATEMOVES(1)
' YOU SHOULD/COULD REMOVE ALL ILLEGAL MOVES FROM THE MOVESTACK
' HERE AND ONLY KEEP COMPUTING WITH LEGAL MOVES.
' (HAS ONLY AN OPTICAL EFFECT, HOWEVER, AS THE SEARCH IS ALWAYS ABORTED
' IMMEDIATELY AFTER PERFORMING AN ILLEGAL MOVE).
' ITERATIVE DEEPENING: DISTANCE IS THE NUMBER OF HALF-MOVES UNTIL THE
' HORIZON. IS NOT EQUAL TO THE DEPTH, HOWEVER, AS THE DISTANCE CAN
' INCREASED DURING THE SEARCH PROCESS (E.G. BY CHECKS).
FOR DISTANCE% = 1 TO MINDEPTH
IF DISTANCE% = 1 THEN ' ON DEPTH 1, WE COMPUTE WITH OPEN WINDOWS
ALPHA% = -MATEVALUE% ' WE HAVE NO GOOD ASSESSMENT VALUE FOR
BETA% = MATEVALUE% ' THE POSITION YET.
ELSE ' ON THE HIGHER LEVELS, THE RESULT SHOLD NOT
BETA% = ALPHA% + 100 ' DIFFER SIGNIFICANTLY FROM THE RESULT OF THE
ALPHA% = ALPHA% - 100 ' PREVIOUS DEPTH.
END IF
' FOR CAPTURE MOVES AND CHECKS, THE SEARCH IS EXTENDED.
' THIS VARIABLE LIMITS THE EXTENSIONS.
MAXEXTENSION = DISTANCE% + 3
' PRINT
' PRINT
LOCATE 0 + DISTANCE%, 52
PRINT DISTANCE%;
' PRINT " ALPHA-BETA WINDOW = ["; ALPHA%; ","; BETA%; "]"
MOVESINLINE% = 0
' PRINT " ";
' COMPUTE THE VALUE OF EACH MOVE
FOR I% = 0 TO STACKLIMIT(1) - 1
IF INKEY$ <> "" THEN
' STOP THE CALCULATION IF A KEY IS PRESSED.
PRINT " COMPUTATION INTERRUPTED!"
EXIT SUB
END IF
MOVESINLINE% = MOVESINLINE% + 1
' INITIALIZE THE MAIN VARIANT AND DISPLAY
' THE MOVE JUST EXAMINED.
MVAR(DEPTH, DEPTH).FROM = 0
CALL DISPLAYMOVE(I%)
IF MOVESINLINE% MOD 9 = 8 THEN ' EIGHT MOVES PER LINE
' PRINT
MOVESINLINE% = 0
' PRINT " ";
END IF
' PERFORM MOVE, COMPUTE VALUE, TAKE BACK MOVE.
CALL PERFORMMOVE((I%))
VALUE% = -ALPHABETA(-BETA%, -ALPHA%, DISTANCE% - 1)
CALL TAKEBACKMOVE((I%))
IF I% = 0 THEN ' WAS IT THE FIRST MOVE (THE BEST YET)?
' THIS MOVE REQUIRES AN EXACT VALUE.
IF VALUE% < ALPHA% THEN
' SEARCH FOR THE BEST MOVE UNTIL NOW 'FALLS DOWN' OUT THE
' WINDOW (THE PROGRAM UNDERSTANDS THE MISHAP). REQUIRES
' A RENEWED SEARCH WITH WINDOWS OPENED 'BELOW'.
ALPHA% = -MATEVALUE%
BETA% = VALUE%
' PRINT "? ["; ALPHA%; ","; BETA%; "]"
MOVESINLINE% = 0
' PRINT " ";
CALL PERFORMMOVE((I%))
VALUE% = -ALPHABETA(-BETA%, -ALPHA%, DISTANCE% - 1)
CALL TAKEBACKMOVE((I%))
ELSEIF VALUE% >= BETA% THEN ' FALLS UP
ALPHA% = VALUE%
BETA% = MATEVALUE%
' PRINT "! ["; ALPHA%; ","; BETA%; "]"
MOVESINLINE% = 0
' PRINT " ";
CALL PERFORMMOVE((I%))
VALUE% = -ALPHABETA(-BETA%, -ALPHA%, DISTANCE% - 1)
CALL TAKEBACKMOVE((I%))
END IF
' THERE IS JUST A SLIM CHANCE THAT A SUBSEQUENT MOVE IS T,
' EVEN BETTER. WE CONTINUE CALCULATING WITH A NULL WINDOW
' AS THIS EXPEDITES THE SEARCH.
ALPHA% = VALUE%
BETA% = ALPHA% + 1
' PRINT
LOCATE 15, 51
PRINT " BEST MOVE: ";
CALL DISPLAYMOVE(I%)
LOCATE 16, 51
PRINT "VALUE ="; VALUE%
CALL COPYMAINVARIANT(I%)
' LOCATE 0 + DISTANCE%, 58
CALL DISPLAYMVAR
MOVESINLINE% = 0
' PRINT " ";
ELSE ' ALREADY COMPUTED THE BEST MOVE YET TO SEARCHDEPTH
IF VALUE% > ALPHA% THEN
' NEW BEST MOVE FOUND. CURRENTLY, IT IS ONLY KNOWN
' THAT IT IS BETTER. THE EXACT VALUE MUST BE COMPUTED
' AGAIN WITH AN OPEN WINDOW.
BESTVALUE% = ALPHA%
ALPHA% = VALUE%
BETA% = MATEVALUE%
CALL PERFORMMOVE((I%))
VALUE% = -ALPHABETA(-BETA%, -ALPHA%, DISTANCE% - 1)
CALL TAKEBACKMOVE((I%))
' IS IT ALSO BETTER WITH THE OPEN WINDOW?
' SOLELY APPLYING ALPHA-BETA, THE MOVE MUST ALWAYS
' BE BETTER WITH THE OPEN WINDOW. SINCE THE WINDOW IS
' CONSIDERED BY THE EXTENSIONS AND IN THE SELECTIVITY,
'THE OUTCOME MAY BE DIFFERENT
' IN OUR CASE.
IF VALUE% > BESTVALUE% THEN
ALPHA% = VALUE%
BETA% = ALPHA% + 1
' PRINT
' PRINT " BEST MOVE: ";
' CALL DISPLAYMOVE(I%)
' PRINT "VALUE ="; VALUE%
CALL COPYMAINVARIANT(I%)
' LOCATE 0 + DISTANCE%, 54
CALL DISPLAYMVAR
MOVESINLINE% = 0
' PRINT " ";
' PLACE THE BEST MOVE AT THE START OF THE MOVELIST.
' PUSH THE OTHER MOVES ONE POSITION UP.
TMP = MOVESTACK(I%)
FOR J% = I% TO 1 STEP -1
MOVESTACK(J%) = MOVESTACK(J% - 1)
NEXT J%
MOVESTACK(0) = TMP
END IF
END IF
END IF
NEXT I%
NEXT DISTANCE%
ENDTIME = TIMER
IF ALPHA% > -(MATEVALUE% - 1) THEN
' PRINT
' PRINT
' PRINT " COMPUTER PLAYER: ";
CALL DISPLAYMOVE(0) ' BEST MOVE IS ALWAYS SORTED INTO
' POSITION 0 OF THE MOVESTACKS
' PRINT
' LOCATE 17, 51
' PRINT " VALUE ="; ALPHA%; ", POSITIONS ="; NODECOUNT;
TIME% = ENDTIME - STARTTIME
COMTIME% = COMTIME% + TIME%: LOCATE 20, 50: PRINT "TOT "; COMTIME%
' PREVENT DIVISION BY ZERO ON NODES/SECOND
IF TIME% = 0 THEN TIME% = 1
LOCATE 18, 51
PRINT ", TIME="; TIME%; "SEC., POSITIONS/SEC. ="; NODECOUNT \ TIME%
CALL PERFORMMOVE(0)
CALL PRINTMOVE(0)
IF ALPHA% >= MATEVALUE% - 10 THEN
' PRINT
PRINT " I CHECKMATE IN "; (MATEVALUE% - 2 - ALPHA%) \ 2; " MOVES "
ELSE
IF ALPHA% <= -MATEVALUE% + 10 THEN
' PRINT
PRINT " I'M CHECKMATE IN "; (ALPHA% + MATEVALUE% - 1) \ 2; " MOVES"
END IF
END IF
ELSE
IF CHECK% = TRUE% THEN
PRINT " CONGRATULATIONS: MINIMAX IS CHECKMATED!"
ELSE
PRINT " STALEMATE!"
END IF
END IF
END SUB
' -----------------------------------------------------------------
' COMPUTINGDEPTH:
' INPUT MINIMUM COMPUTING DEPTH
' CALLS: NONE
' CALLEDBY:
' -----------------------------------------------------------------
SUB COMPUTINGDEPTH
PRINT " COMPUTING DEPTH IS"; MINDEPTH
INPUT " NEW COMPUTING DEPTH: ", INPUTS$
TMP% = VAL(INPUTS$)
IF TMP% > 0 AND TMP% < MAXDEPTH% - 9 THEN
MINDEPTH = TMP%
ELSE
PRINT " INVALID COMPUTING DEPTH"
END IF
END SUB
'--------------------------------------------------------------------
' COPYMAINVARIANT:
' SAVES THE CURRENT MOVE IN THE MAIN VARIANT AND COPIES
' THE CONTINUATION THAT WAS FOUND ON THE NEXT DEPTH.
' CALLS:
' CALLEDBY: COMPUTERMOVE;
'--------------------------------------------------------------------
SUB COPYMAINVARIANT (CURRMOVE%)
' NEW MAIN VARIANT IS A CONTINUATION OF THIS VARIANT
MVAR(DEPTH, DEPTH).FROM = MOVESTACK(CURRMOVE%).FROM
MVAR(DEPTH, DEPTH).TOO = MOVESTACK(CURRMOVE%).TOO
I% = 0
DO
I% = I% + 1
MVAR(DEPTH, DEPTH + I%) = MVAR(DEPTH + 1, DEPTH + I%)
LOOP UNTIL MVAR(DEPTH + 1, DEPTH + I%).FROM = 0
END SUB
'--------------------------------------------------------------------
' DISPLAYBOARD:
' DISPLAY OF THE GAME BOARD AND THE GAME/BOARD STATE
' ONLY DISPLAYS GAME/BOARD STATE IF "BOARDONLY" IS FALSE
'
' THE SGN-FUNCTION (SIGN) RETURNS THE SIGN, I.E. -1 OR +1
' THE ABS-FUNCTION RETURNS THE ABSOLUTE VALUE (WITHOUT SIGN)
' CALLS: FIELDNOTATION
' CALLEDBY:
'--------------------------------------------------------------------
SUB DISPLAYBOARD (BOARDONLY%)
' DISPLAY BOARD
LOCATE 1, 1
FOR I% = COLUMN8% TO COLUMN1% STEP -1 ' FOR ALL ROWS
PRINT
PRINT I% - 1; " "; ' ROW COORDINATES
FOR J% = AROW% TO HROW% ' FOR ALL LINES
PIECE% = BOARD(I% * 10 + J%)
SIDE% = SGN(PIECE%) ' COMPUTE COLOR FROM PIECE.
' EMPTY FIELD HAS COLOR 0
PIECE% = ABS(PIECE%) ' PIECE TYPE
PRINT COLOURSYMBOL(SIDE% + 1); FIGSYMBOL(PIECE%); " ";
NEXT J%
NEXT I%
PRINT
PRINT " ";
FOR J% = AROW% TO HROW% ' LINE COORDINATES 'A'...'H'
PRINT " "; CHR$(ASC("A") - 1 + J%);
NEXT J%
PRINT ' EMPTY LINE
PRINT ' EMPTY LINE
EXIT SUB 'MY NEW LINE
IF BOARDONLY% THEN EXIT SUB
' REMAINING BOARD/GAME STATE
IF COLOUR = WHITE% THEN
PRINT " WHITE";
ELSE
PRINT " BLACK";
END IF
PRINT " IS TO MAKE A MOVE"
PRINT " MATERIAL BALANCE = "; MATERIALBALANCE(DEPTH)
PRINT " EN PASSANT FIELD = "; FIELDNOTATION$(EPFIELD(DEPTH))
' CASTLING IS IN PRINCIPLE POSSIBLE IF THE KING AND APPROPRIATE
' ROOK HAVE NOT MOVED.
PRINT " CASTLING STATE BLACK = ";
IF MOVECONTROL(E8%) + MOVECONTROL(H8%) = 0 THEN PRINT "0-0 ";
IF MOVECONTROL(E8%) + MOVECONTROL(A8%) = 0 THEN PRINT "0-0-0";
PRINT
PRINT " CASTLING STATE WHITE = ";
IF MOVECONTROL(E1%) + MOVECONTROL(H1%) = 0 THEN PRINT "0-0 ";
IF MOVECONTROL(E1%) + MOVECONTROL(A1%) = 0 THEN PRINT "0-0-0";
PRINT
END SUB
'--------------------------------------------------------------------
' DISPLAYMOVE:
' DISPLAY THE CURRENT MOVE IN CHESS NOTATION.
' CASTLING IS 'E1-G1' AND NOT O-O
' CURRMOVE% IS THE INDEX OF THE MOVE INTO MOVESTACK.
' CALLS:
' CALLEDBY:
'--------------------------------------------------------------------
SUB DISPLAYMOVE (CURRMOVE%)
FROM% = MOVESTACK(CURRMOVE%).FROM
TOO% = MOVESTACK(CURRMOVE%).TOO
' PRINT FIGSYMBOL(ABS(BOARD(FROM%))); ' TYPE OF PIECE
' PRINT FIELDNOTATION$(FROM%); ' INITIAL FIELD
IF MOVESTACK(CURRMOVE%).CAPTUREDPIECE = EMPTY% THEN
' PRINT "-"; ' NORMAL MOVE
ELSE
' PRINT "X"; ' CAPTURE MOVE
END IF
' PRINT FIELDNOTATION$(TOO%); ' TARGET FIELD
' IF PROMOTED, ADD PROMOTION PIECE
IF MOVESTACK(CURRMOVE%).PROMOTEDPIECE <> EMPTY% THEN
' PRINT FIGSYMBOL(MOVESTACK(CURRMOVE%).PROMOTEDPIECE);
END IF
' PRINT " ";
END SUB
'--------------------------------------------------------------------
' DISPLAYMVAR:
' DISPLAY THE CURRENT MAIN VARIANT, ONLY THE FROM-TO FIELDS
' ARE OUTPUT.
' CALLS: FIELDNOTATION;
' CALLEDBY:
'--------------------------------------------------------------------
SUB DISPLAYMVAR
'PRINT " MAIN VARIANTS: ";
I% = 0
DO WHILE MVAR(0, I%).FROM <> 0
LOCATE 1 + I%, 56
PRINT FIELDNOTATION$(MVAR(0, I%).FROM); "-";
PRINT FIELDNOTATION$(MVAR(0, I%).TOO); " ";
I% = I% + 1
LOOP
'PRINT
END SUB
'-----------------------------------------------------------------------
' FIELDNOTATION: FUNCTION
' CONVERTS INTERNAL FIELDNUMBER TO FIELDNOTATION.
' RETURNS '--' IF THE NUMBER IS NOT ON THE BOARD
'
' NOTES:
' THE \ OPERATOR IS INTEGER DIVISION.
' THE MOD (MODULO) OPERATOR RETURNS THE REMAINDER OF AN INTEGE DIVISION.
' CALLS:
' CALLEDBY:
'-----------------------------------------------------------------------
FUNCTION FIELDNOTATION$ (FIELDNUM%)
' SEE IF CORRECT
IF FIELDNUM% < A1% OR FIELDNUM% > H8% OR BOARD(FIELDNUM%) = EDGE% THEN
FIELDNOTATION$ = "--"
ELSE
S$ = CHR$(ASC("A") - 1 + FIELDNUM% MOD 10) ' LINE
S$ = S$ + CHR$(ASC("1") - 2 + FIELDNUM% \ 10) ' ROW
FIELDNOTATION$ = LCASE$(S$)
END IF
END FUNCTION
'--------------------------------------------------------------------
' FIELDNUMBER: FUNCTION
' CONVERTS FIELDNOTATION (E.G. "A1") TO INTERNAL FIELDNUMBER.
' RETURNS "ILLEGAL" IF INPUT IS INCORRECT
' LINE COORDINATES MUST BE PASSED AS UPPERCASE LETTERS.
' CALLS:
' CALLEDBY: FIELDNOTATION
'--------------------------------------------------------------------
FUNCTION FIELDNUMBER% (FIELDNOTE$)
ROW$ = LEFT$(FIELDNOTE$, 1)
COLUMN$ = MID$(FIELDNOTE$, 2, 1)
' SEE IF CORRECT
IF ROW$ < "A" OR ROW$ > "H" OR COLUMN$ < "1" OR COLUMN$ > "8" THEN
FIELDNUMBER% = ILLEGAL%
EXIT FUNCTION
END IF
FIELDNUMBER% = (ASC(ROW$) - ASC("A") + 1) + 10 * (ASC(COLUMN$) - ASC("1") + 2)
END FUNCTION
'---------------------------------------------------------------------
' FLIPBOARD:
' FLIPS THE REPRESENTATION OF THE BOARD ON THE MONITOR
' NOTE: NOT IMPLEMENTED IN VERSION 1.0
' CALLS:
' CALLEDBY:
'---------------------------------------------------------------------
SUB FLIPBOARD
END SUB
'--------------------------------------------------------------------
' GAMEOVER:
' STORES THE GAME AND GAME PARAMETERS ON THE HARDDISK.
' NOTE: NOT IMPLEMENTED IN VERSION 1.0
' CALLS:
' CALLEDBY:
'--------------------------------------------------------------------
SUB GAMEOVER
END SUB
'--------------------------------------------------------------------
' GENERATEMOVES:
' GENERATES MOVES AND PLACES THEM ON THE MOVESTACK
' RETURNS THE NUMBER OF MOVES.
' IF "ALLMOVES" IS GREATER THAN 0, ALL PSEUDO-LEGAL
' MOVES ARE PRODUCED, OTHERWISE ALL PSEUDO-LEGAL CAPTURE MOVES,
' PROMOTIONS, EN PASSANT, AND CASTLING MOVES.
' CALLS: SAVEPROMOTION; SAVEMOVE; SAVECAPTUREMOVE; SAVEEPMOVE
' ATTACKINGFIELD;
' CALLEDBY: ATTACKINGFIELD, INPUTMOVE, MOVELIST, ALPHABETA,COMPUTERMOVE
'--------------------------------------------------------------------
SUB GENERATEMOVES (ALLMOVES%)
INDEX = STACKLIMIT(DEPTH) ' START OF MOVELIST ON CURRENT DEPTH
MOBILITY(DEPTH) = 0
' SEARCH THE BOARD FOR PIECES
FOR FROM% = A1% TO H8%
PIECE% = BOARD(FROM%)
' EMPTY AND EDGE FIELDS MAKE NO MOVES
IF PIECE% = EMPTY% OR PIECE% = EDGE% THEN GOTO NEXTFIELD
' PIECE MUST ALSO BE OF CORRECT COLOR
IF COLOUR = WHITE% AND PIECE% < 0 THEN GOTO NEXTFIELD
IF COLOUR = BLACK% AND PIECE% > 0 THEN GOTO NEXTFIELD
PIECE% = ABS(PIECE%) ' TYPE OF PIECE. COLOR DOESN'T INFLUENCE
' (EXCEPT FOR PAWNS) THE MOVE DIRETION.
IF PIECE% = WP% THEN ' PAWNS MOVES
IF COLOUR = WHITE% THEN
IF BOARD(FROM% + 10) = EMPTY% THEN
IF FROM% >= A7% THEN
CALL SAVEPROMOTION(FROM%, FROM% + 10)
ELSEIF ALLMOVES% > 0 THEN
CALL SAVEMOVE(FROM%, FROM% + 10)
' DOUBLE-STEP POSSIBLE?
IF FROM% <= H2% AND BOARD(FROM% + 20) = EMPTY% THEN
CALL SAVEMOVE(FROM%, FROM% + 20)
' MOVE HAS ALREADY INCREASED INDEX
MOVESTACK(INDEX - 1).EPFIELD = FROM% + 10
END IF
END IF
END IF
IF BOARD(FROM% + 11) < 0 THEN ' PAWN CAN CAPTURE BLACK PIECE
IF FROM% >= A7% THEN
CALL SAVEPROMOTION(FROM%, FROM% + 11)
ELSE
CALL SAVECAPTUREMOVE(FROM%, FROM% + 11)
END IF
END IF
IF BOARD(FROM% + 9) < 0 THEN ' LIKEWISE IN OTHER CAPTURE DIRECTION
IF FROM% >= A7% THEN
CALL SAVEPROMOTION(FROM%, FROM% + 9)
ELSE
CALL SAVECAPTUREMOVE(FROM%, FROM% + 9)
END IF
END IF
ELSEIF COLOUR = BLACK% THEN ' SAME FOR BLACK PAWNS
IF BOARD(FROM% - 10) = EMPTY% THEN
IF FROM% <= H2% THEN
CALL SAVEPROMOTION(FROM%, FROM% - 10)
ELSEIF ALLMOVES% > 0 THEN
CALL SAVEMOVE(FROM%, FROM% - 10)
' DOUBLE-STEPS POSSIBLE?
IF FROM% >= A7% AND BOARD(FROM% - 20) = EMPTY% THEN
CALL SAVEMOVE(FROM%, FROM% - 20)
' MOVE HAS ALREADY INCREASED INDEX
MOVESTACK(INDEX - 1).EPFIELD = FROM% - 10
END IF
END IF
END IF
' FOR BLACK PAWNS ALSO EXAMINE THE EDGE,
' NOT FOR WHITE AS THE EDGE > 0.
IF BOARD(FROM% - 11) > 0 AND BOARD(FROM% - 11) <> EDGE% THEN
IF FROM% <= H2% THEN
CALL SAVEPROMOTION(FROM%, FROM% - 11)
ELSE
CALL SAVECAPTUREMOVE(FROM%, FROM% - 11)
END IF
END IF
IF BOARD(FROM% - 9) > 0 AND BOARD(FROM% - 9) <> EDGE% THEN
IF FROM% <= H2% THEN
CALL SAVEPROMOTION(FROM%, FROM% - 9)
ELSE
CALL SAVECAPTUREMOVE(FROM%, FROM% - 9)
END IF
END IF
END IF
GOTO NEXTFIELD ' EXAMINE NEXT FIELD
END IF
' MOVES FOR ALL OTHER PIECES ARE COMPUTED
' BY WAY OF MOVE OFFSET.
LONGPATHS% = FIGOFFSET(PIECE%).LONGPATHS
FOR I% = FIGOFFSET(PIECE%).START TO FIGOFFSET(PIECE%).ENDS
DIRECTION% = OFFSET(I%)
TOO% = FROM%
SLIDEON2:
TOO% = TOO% + DIRECTION%
IF BOARD(TOO%) = EMPTY% THEN
IF ALLMOVES% > 0 THEN
CALL SAVEMOVE(FROM%, TOO%)
END IF
IF LONGPATHS% THEN ' BISHOP, ROOK AND QUEEN
GOTO SLIDEON2
ELSE ' KNIGHT AND KING
GOTO NEXTDIRECTION
END IF
END IF
IF BOARD(TOO%) = EDGE% THEN ' HIT THE EDGE, KEEP SEARCHING
GOTO NEXTDIRECTION ' IN AN ANOTHER DIRECTION.
END IF
' HIT A PIECE. MUST BE OF THE CORRECT COLOR.
CAPTUREMOVE% = COLOUR = WHITE% AND BOARD(TOO%) < 0
CAPTUREMOVE% = CAPTUREMOVE% OR (COLOUR = BLACK% AND BOARD(TOO%) > 0)
IF CAPTUREMOVE% THEN CALL SAVECAPTUREMOVE(FROM%, TOO%)
NEXTDIRECTION:
NEXT I%
NEXTFIELD:
NEXT FROM%
' EN PASSANT MOVE
IF EPFIELD(DEPTH) <> ILLEGAL% THEN
EP% = EPFIELD(DEPTH)
IF COLOUR = WHITE% THEN
IF BOARD(EP% - 9) = WP% THEN
CALL SAVEEPMOVE(EP% - 9, EP%, EP% - 10)
END IF
IF BOARD(EP% - 11) = WP% THEN
CALL SAVEEPMOVE(EP% - 11, EP%, EP% - 10)
END IF
ELSE
IF BOARD(EP% + 9) = BP% THEN
CALL SAVEEPMOVE(EP% + 9, EP%, EP% + 10)
END IF
IF BOARD(EP% + 11) = BP% THEN
CALL SAVEEPMOVE(EP% + 11, EP%, EP% + 10)
END IF
END IF
END IF
' CASTLING IS ALSO PERFORMED IN THE QUIESCENCE SEARCH BECAUSE IT HAS A
' STRONG INFLUENCE ON THE ASSESSMENT. (WHETHER THIS IS APPROPRIATE,
' IS A MATTER OF DISPUTE EVEN AMOUNG LEADING PROGRAMMERS).
' COMPUTE CASTLING
IF COLOUR = WHITE% THEN
IF WKING = E1% AND MOVECONTROL(E1%) = 0 THEN
' IS SHORT CASTLING ALLOWED?
OK% = BOARD(H1%) = WR% AND MOVECONTROL(H1%) = 0
OK% = OK% AND BOARD(F1%) = EMPTY% AND BOARD(G1%) = EMPTY%
OK% = OK% AND ATTACKINGFIELD%(E1%, BLACK%) = FALSE%
OK% = OK% AND ATTACKINGFIELD%(F1%, BLACK%) = FALSE%
OK% = OK% AND ATTACKINGFIELD%(G1%, BLACK%) = FALSE%
IF OK% THEN
CALL SAVEMOVE(E1%, G1%) ' SAVE KING'S MOVE
MOVESTACK(INDEX - 1).CASTLINGNR = SHORTCASTLINGMOVE%
END IF
' IS LONG CASTLING ALLOWED?
OK% = BOARD(A1%) = WR% AND MOVECONTROL(A1%) = 0
OK% = OK% AND BOARD(D1%) = EMPTY%
OK% = OK% AND BOARD(C1%) = EMPTY%
OK% = OK% AND BOARD(B1%) = EMPTY%
OK% = OK% AND ATTACKINGFIELD%(E1%, BLACK%) = FALSE%
OK% = OK% AND ATTACKINGFIELD%(D1%, BLACK%) = FALSE%
OK% = OK% AND ATTACKINGFIELD%(C1%, BLACK%) = FALSE%
IF OK% THEN
CALL SAVEMOVE(E1%, C1%) ' SAVE KING'S MOVE
' SAVE TYPE OF CASTLING
MOVESTACK(INDEX - 1).CASTLINGNR = LONGCASTLINGMOVE%
END IF
END IF
ELSE ' BLACK IS TO MAKE A MOVE
IF BKING = E8% AND MOVECONTROL(E8%) = 0 THEN
' IS SHORT CASTLING ALLOWED?
OK% = BOARD(H8%) = BR% AND MOVECONTROL(H8%) = 0
OK% = OK% AND BOARD(F8%) = EMPTY% AND BOARD(G8%) = EMPTY%
OK% = OK% AND ATTACKINGFIELD%(E8%, WHITE%) = FALSE%
OK% = OK% AND ATTACKINGFIELD%(F8%, WHITE%) = FALSE%
OK% = OK% AND ATTACKINGFIELD%(G8%, WHITE%) = FALSE%
IF OK% THEN
CALL SAVEMOVE(E8%, G8%) ' SAVE KING'S MOVE
MOVESTACK(INDEX - 1).CASTLINGNR = SHORTCASTLINGMOVE%
END IF
' IS LONG CASTLING ALLOWED?
OK% = BOARD(A8%) = BR% AND MOVECONTROL(A8%) = 0
OK% = OK% AND BOARD(D8%) = EMPTY%
OK% = OK% AND BOARD(C8%) = EMPTY%
OK% = OK% AND BOARD(B8%) = EMPTY%
OK% = OK% AND ATTACKINGFIELD%(E8%, WHITE%) = FALSE%
OK% = OK% AND ATTACKINGFIELD%(D8%, WHITE%) = FALSE%
OK% = OK% AND ATTACKINGFIELD%(C8%, WHITE%) = FALSE%
IF OK% THEN
CALL SAVEMOVE(E8%, C8%) ' SAVE KING'S MOVE
' SAVE TYPE OF CASTLING
MOVESTACK(INDEX - 1).CASTLINGNR = LONGCASTLINGMOVE%
END IF
END IF
END IF
STACKLIMIT(DEPTH + 1) = INDEX ' MARK END OF MOVELIST
END SUB
'--------------------------------------------------------------------
' INITASSESSMENT:
' COMPUTE THE PAWN CONTROLS AND THE COLUMNS ON WHICH PAWNS AND
' ROOKS ARE PLACED. CALLED BY THE ASSESSMENT FUNCTION
' FOR INITIALIZATION.
' CALLS:
' CALLEDBY:
'--------------------------------------------------------------------
SUB INITASSESSMENT
' DELETE PAWN CONTROLS
FOR I% = A1% TO H8%
PAWNCONTROLLED(I%).WHITE = 0
PAWNCONTROLLED(I%).BLACK = 0
NEXT I%
' ALSO INITIALIZE EDGES. THIS ELIMINATES THE
' NEED TO EXAMINE EDGE COLUMNS.
FOR I% = AROW% - 1 TO HROW% + 1
PAWNS(I%).WHITE = 0
PAWNS(I%).BLACK = 0
ROOKS(I%).WHITE = 0
ROOKS(I%).BLACK = 0
NEXT I%
FOR I% = A1% TO H8%
IF BOARD(I%) = EMPTY% OR BOARD(I%) = EDGE% THEN GOTO NEXTFELD
SELECT CASE BOARD(I%)
CASE WP%
PAWNCONTROLLED(I% + 9).WHITE = PAWNCONTROLLED(I% + 9).WHITE + 1
PAWNCONTROLLED(I% + 11).WHITE = PAWNCONTROLLED(I% + 11).WHITE + 1
PAWNS(I% MOD 10).WHITE = PAWNS(I% MOD 10).WHITE + 1
CASE BP%
PAWNCONTROLLED(I% - 9).BLACK = PAWNCONTROLLED(I% - 9).BLACK + 1
PAWNCONTROLLED(I% - 11).BLACK = PAWNCONTROLLED(I% - 11).BLACK + 1
PAWNS(I% MOD 10).BLACK = PAWNS(I% MOD 10).BLACK + 1
CASE BR%
ROOKS(I% MOD 10).BLACK = ROOKS(I% MOD 10).BLACK + 1
CASE WR%
ROOKS(I% MOD 10).WHITE = ROOKS(I% MOD 10).WHITE + 1
CASE ELSE
END SELECT
NEXTFELD:
NEXT I%
END SUB
'--------------------------------------------------------------------
' INITGAMETREE:
' INITIALIZE THE GAMETREE
' CALLS:
' CALLEDBY:
'--------------------------------------------------------------------
SUB INITGAMETREE
' IN DEPTH 0 NOTHING HAS BEEN COMPUTED, GAME TREE ALREADY INITIALIZED
IF DEPTH = 0 THEN EXIT SUB
EPFIELD(0) = EPFIELD(1)
MATERIALBALANCE(0) = MATERIALBALANCE(1)
MATERIALTOTAL(0) = MATERIALTOTAL(1)
DEPTH = 0
END SUB
'--------------------------------------------------------------------
' INITIALIZE:
' INITIALIZE THE BOARD AND THE GAME STATUS
' CALLS: NONE
' CALLEDBY: MAIN
'--------------------------------------------------------------------
SUB INITIALIZE
' BOARD INITIALIZATION, BUILD INITIALPOSITION
MOVECOUNT = 0 ' COUNTS THE HALF-MOVES IN THE GAME
FOR I% = 0 TO BOARDDIM%
BOARD(I%) = INITIALPOSITION(I%)
NEXT I%
' POSITIONS OF THE KINGS IN THE INITIALPOSITION
WKING = E1%
BKING = E8%
' NO CASTLING YET
FOR I% = 0 TO 2
CASTLING(I%) = FALSE%
NEXT I%
FOR I% = A1% TO H8%
MOVECONTROL(I%) = 0 ' INITIALLY NO PIECE HAS MOVED
NEXT I%
EPFIELD(0) = ILLEGAL% ' EN PASSANT STATUS
MATERIALTOTAL(0) = MATERIALSUM% ' MATERIAL VALUE (OF PIECES) IN INITIALPOSITION
MATERIALBALANCE(0) = 0 ' MATERIAL BALANCE EVEN
PLAYERPLAYER = FALSE%
STACKLIMIT(0) = 0 ' LIMIT OF MOVESTACKS
MINDEPTH = 4 ' DEFAULT COMPUTINGDEPTH
DEPTH = 0 ' CURRENT DEPTH IN THE GAME TREE
COLOUR = WHITE% ' WHITE HAS THE FIRST MOVE
END SUB
'--------------------------------------------------------------------
' INPUTMOVE: FUNCTION
' ATTEMPTS TO INTERPRET THE PASSED STRING AS A MOVE.
' IF IT'S A LEGAL MOVE, THAT MOVE IS PERFORMED AND THE FUNCTION
' RETURNS THE VALUE "TRUE%". IF NO (LEGAL) MOVE CAN BE IDENTIFIED
' THE FUNCTION RETURNS THE VALUE 'FALSE%'.
' CALLS: GENERATEMOVES; INITGAMETREE; DISPLAYMOVE; PERFORMMOVE
' TAKEBACKMOVE; PRINTMOVE; ATTACKINGFIELD; FIELDNOTATION;
' FIELDNUMBER;
' CALLEDBY:
'--------------------------------------------------------------------
FUNCTION INPUTMOVE% (MOVE$)
IF LEN(MOVE$) < 4 THEN ' ONLY FROM-TO REPRESENTATION IS ALLOWED
INPUTMOVE% = FALSE%
EXIT FUNCTION
END IF
FROM% = FIELDNUMBER%(MOVE$)
TOO% = FIELDNUMBER%(MID$(MOVE$, 3, 2))
CALL GENERATEMOVES(1)
FOR I% = STACKLIMIT(DEPTH) TO STACKLIMIT(DEPTH + 1) - 1
IF MOVESTACK(I%).FROM = FROM% AND MOVESTACK(I%).TOO = TOO% THEN
IF MOVESTACK(I%).PROMOTEDPIECE <> EMPTY% THEN ' PROMOTIONS
IF MID$(MOVE$, 5, 1) = "N" THEN ' IN THE SEQUENCE QUEEN, KNIGHT
I% = I% + 1 ' BISHOP AND ROOK
ELSEIF MID$(MOVE$, 5, 1) = "B" THEN
I% = I% + 2
ELSEIF MID$(MOVE$, 5, 1) = "R" THEN
I% = I% + 3
END IF
END IF
CALL INITGAMETREE
PRINT " YOUR MOVE: ";
CALL DISPLAYMOVE(I%)
TMP% = LASTMOVE ' TEMP STORAGE FOR LAST MOVE SO FAR.
CALL PERFORMMOVE(I%) ' WARNING: PERFORMMOVE CHANGES
' THE COLOR. NEXT INQUIRY OF COLOR MUST
' COMPENSATE FOR THIS.
IF COLOUR = BLACK% THEN
IF ATTACKINGFIELD%(WKING, BLACK%) = TRUE% THEN
PRINT " WHITE KING ON "; FIELDNOTATION$(WKING); " IS BEING CHECKED"
CALL TAKEBACKMOVE((I%))
LASTMOVE = TMP% ' NO NEW MOVE MADE. RESTORE
INPUTMOVE% = FALSE% ' LAST MOVE.
EXIT FUNCTION
END IF
ELSEIF ATTACKINGFIELD%(BKING, WHITE%) = TRUE% THEN
PRINT " BLACKR KING ON "; FIELDNOTATION$(BKING); " IS BEING CHECKED"
CALL TAKEBACKMOVE((I%))
LASTMOVE = TMP%
INPUTMOVE% = FALSE%
EXIT FUNCTION
END IF
PRINT
CALL PRINTMOVE(I%)
INPUTMOVE% = TRUE%
EXIT FUNCTION
END IF
NEXT I%
INPUTMOVE% = FALSE% ' THE INPUT MOVE WAS NOT FOUND IN MOVELIST
END FUNCTION
'--------------------------------------------------------------------
' INPUTPOSITION:
' INPUT OF ANY POSITION
' CALLS: DISPLAYBOARD; PRINTPOSITION; READPIECE;
' CALLEDBY: COMMANDLOOP
'--------------------------------------------------------------------
SUB INPUTPOSITION
DEPTH = 0 ' POSITION BECOMES ROOT OF THE SEARCH TREE
PIECEINPUT:
INPUT " DELETE BOARD (Y/N) ", INPUTS$
INPUTS$ = UCASE$(INPUTS$) ' CHANGE TO UPPER CASE
IF INPUTS$ = "Y" THEN
FOR I% = COLUMN1% TO COLUMN8%
FOR J% = AROW% TO HROW%
BOARD(I% * 10 + J%) = EMPTY%
NEXT J%
NEXT I%
END IF
' DO NOT INTERPRET "Y" AS NO
PRINT " WHITE:"
READPIECE (WHITE%)
PRINT " BLACK:"
READPIECE (BLACK%)
' COMPUTE MATERIAL BALANCE AND EXAMINE IF EACH SIDE
' HAS JUST ONE KING.
MATERIALBALANCE(0) = 0
MATERIALTOTAL(0) = 0
WKINGS% = 0
BKINGS% = 0
FOR I% = A1% TO H8% ' READ EACH FIELD
IF BOARD(I%) = EMPTY% OR BOARD(I%) = EDGE% THEN
GOTO CONTINUE ' EMPTY OR EDGE FIELD FOUND, GO TO NEXT FIELD
END IF
' NEW MATERIAL BALANCE
' WHITE PIECE POSITIVELY AFFECTS THE BALANCE, BACK NEGATIVELY
MATERIALBALANCE(0) = MATERIALBALANCE(0) + SGN(BOARD(I%)) * PIECEMATERIAL(ABS(BOARD(I%)))
IF ABS(BOARD(I%)) <> WP% THEN
MATERIALTOTAL(0) = MATERIALTOTAL(0) + PIECEMATERIAL(ABS(BOARD(I%)))
END IF
IF BOARD(I%) = WK% THEN
WKINGS% = WKINGS% + 1 ' NUMBER AND POSITION OF WHITE KINGS
WKING = I%
END IF
IF BOARD(I%) = BK% THEN
BKINGS% = BKINGS% + 1 ' BLACK KINGS
BKING = I%
END IF
CONTINUE:
NEXT I%
IF BKINGS% <> 1 OR WKINGS% <> 1 THEN
PRINT "ILLEGAL POSITION, EACH SIDE MUST HAVE EXACTLY ONE KING"
CALL DISPLAYBOARD(TRUE%)
GOTO PIECEINPUT
END IF
REPEAT: ' THE ENTRY MUST BE COMPLETE WITH A LEGAL POSITION
' OTHERWISE THE MOVEGENERATOR DOESN'T WORK.
INPUT " WHOSE MOVE (W/B): "; INPUTS$
INPUTS$ = UCASE$(INPUTS$)
IF INPUTS$ = "W" THEN
COLOUR = WHITE%
ELSEIF INPUTS$ = "B" THEN
COLOUR = BLACK% ' MATERIAL BALANCE WAS COMPUTED FROM
MATERIALBALANCE(0) = -MATERIALBALANCE(0) 'WHITE'S VIEWPOINT UNTIL NOW.
ELSE
GOTO REPEAT
END IF
FOR I% = A1% TO H8% ' TO SIMPLIFY, WE ASSUME HERE THAT
MOVECONTROL(I%) = 1 ' ALL PIECES HAVE ALREADY MOVED ONCE.
NEXT I% ' OTHERWISE, THE ASSESSMENT FUNCTION
' BELIEVES THIS IS AN
' INITIAL POSITION.
MOVECONTROL(E1%) = 0
MOVECONTROL(A1%) = 0 ' SINGLE EXCEPTION: THE KING AND ROOK
MOVECONTROL(H1%) = 0 ' FIELDS REPRESENT THE CASTLING STATE
MOVECONTROL(E8%) = 0 ' AND MUST THEREFORE BE RESET
MOVECONTROL(A8%) = 0 ' TO ZERO.
MOVECONTROL(H8%) = 0
EPFIELD(0) = ILLEGAL%
INPUT " CHANGE THE STATUS (Y/N): "; INPUTS$
INPUTS$ = UCASE$(INPUTS$)
IF INPUTS$ = "Y" THEN
' INPUT THE ENPASSANT FIELD. IF FOLLOWING INPUT INS'T CORRECT,
' ENPASSANT IS NOT POSSIBLE.
INPUT " EN PASSANT COLUMN: "; INPUTS$
INPUTS$ = UCASE$(INPUTS$)
EP$ = LEFT$(INPUTS$, 1)
IF EP$ >= "A" AND EP$ <= "H" THEN
IF COLOUR = WHITE% THEN
EPFIELD(0) = A6% + ASC(EP$) - ASC("A")
ELSE
EPFIELD(0) = A3% + ASC(EP$) - ASC("A")
END IF
END IF
' BLACK SHORT CASTLING. BY DEFAULT, CASTLING IS POSSIBLE.
INPUT " BLACK 0-0 LEGAL (Y/N) : "; INPUTS$
INPUTS$ = UCASE$(INPUTS$)
IF INPUTS$ = "N" THEN
MOVECONTROL(H8%) = 1 ' MOVE THE ROOK. THIS ELIMINATES
' THE CASTLING.
END IF
INPUT " BLACK 0-0-0 LEGAL (Y/N): "; INPUTS$
INPUTS$ = UCASE$(INPUTS$)
IF INPUTS$ = "N" THEN
MOVECONTROL(A8%) = 1
END IF
INPUT " WHITE 0-0 LEGAL (Y/N) : "; INPUTS$
INPUTS$ = UCASE$(INPUTS$)
IF INPUTS$ = "N" THEN
MOVECONTROL(H1%) = 1
END IF
INPUT " WHITE 0-0-0 LEGAL (Y/N) : "; INPUTS$
INPUTS$ = UCASE$(INPUTS$)
IF INPUTS$ = "N" THEN
MOVECONTROL(A1%) = 1
END IF
END IF
MOVECOUNT = 0 ' RESET THE MOVE COUNT
CALL DISPLAYBOARD(FALSE%) ' DISPLAY THE NEW BOARD
CALL PRINTPOSITION
END SUB
' -----------------------------------------------------------------
' MOVEBACK:
' TAKES BACK A MOVE
' SINCE THE PLLAYER MOVES AAAAARE NOT STORED, A MIZIMUN OF
' ONE MOVE CAN BE TAKEN BACK.
' CALLS: TAKEBACKMOVE; DISPLAYBOARD; PRINTBACK
' CALLEDBY:
' -----------------------------------------------------------------
SUB MOVEBACK
IF DEPTH <> 1 THEN
PRINT " UNFORTUNATELY NOT POSSIBLE."
EXIT SUB
END IF
CALL TAKEBACKMOVE(LASTMOVE)
CALL DISPLAYBOARD(FALSE%)
CALL PRINTBACK
END SUB
' -----------------------------------------------------------------
' MOVELIST:
' GENERATE ALL MOVES AND DISPLAY THEM ON THE MONITOR
' CALLS: GENERATEMOVES; DISPLAYMOVE; ATTACKINGFIELD;
' CALLEDBY:
' -----------------------------------------------------------------
SUB MOVELIST
CALL GENERATEMOVES(1)
IF COLOUR = WHITE% THEN
CHECKMATED% = ATTACKINGFIELD%(BKING, WHITE%)
ELSE
CHECKMATED% = ATTACKINGFIELD%(WKING, BLACK%)
END IF
IF CHECKMATED% THEN
PRINT " THE KING CANNOT BE CAPTURED"
EXIT SUB
END IF
PRINT " "; INDEX - STACKLIMIT(DEPTH); "PSEUDO LEGAL MOVES`"
FOR I% = STACKLIMIT(DEPTH) TO INDEX - 1
CALL DISPLAYMOVE(I%)
IF (I% - STACKLIMIT(DEPTH)) MOD 9 = 8 THEN ' AFTER 8 MOVES START
PRINT ' A NEW LINE.
END IF
NEXT I%
PRINT ' CARRIAGE RETURN
END SUB
'--------------------------------------------------------------------
' NEXTBESTMOVE: FUNCTION
' FROM THE POSSIBLE MOVES OF A CERTAIN DEPTH THE BEST,
' NOT-YET-PLAYED MOVE IS SELECTED. RETURNS THE INDEX OF THE MOVE
' INTO MOVESTACK. IF ALL MOVES WERE ALREADY PLAYED, AN
' IMPOSSIBLE INDEX (-1) IS RETURNED.
' THE VALUE OF A MOVE IS DETERMINED BY THE MOVE GENERATOR.
' THIS FUNCTION FINISHES THE MOVE SORTING IN THE SEARCH.
' CALLS:
' CALLEDBY:
'--------------------------------------------------------------------
FUNCTION NEXTBESTMOVE%
BESTMOVE% = -1
BESTVALUE% = -MATEVALUE%
FOR I% = STACKLIMIT(DEPTH) TO STACKLIMIT(DEPTH + 1) - 1
IF MOVESTACK(I%).VALUE > BESTVALUE% THEN ' FOUND NEW BEST MOVE
BESTMOVE% = I%
BESTVALUE% = MOVESTACK(I%).VALUE
END IF
NEXT I%
' MARK THE SELECTED MOVE SO IT ISN'T SELECTED AGAIN
' ON THE NEXT CALL.
IF BESTMOVE% >= 0 THEN MOVESTACK(BESTMOVE%).VALUE = -MATEVALUE%
NEXTBESTMOVE% = BESTMOVE%
END FUNCTION
'--------------------------------------------------------------------
' PERFORMMOVE:
' PERFORMS A MOVE AT THE BOARD AND UPDATES THE STATUS AND
' THE SEARCH DEPTH.
' CURRMOVE% IS THE INDEX OF THE MOVE INTO MOVESTACK.
' CALLS:
' CALLEDBY:
'--------------------------------------------------------------------
SUB PERFORMMOVE (CURRMOVE%)
MOVECOUNT = MOVECOUNT + 1 ' INCREASE MOVE COUNT BY ONE HALF-MOVE
FROM% = MOVESTACK(CURRMOVE%).FROM
TOO% = MOVESTACK(CURRMOVE%).TOO
EP% = MOVESTACK(CURRMOVE%).EPFIELD
LASTMOVE = CURRMOVE%
DEPTH = DEPTH + 1 ' ONE STEP DEEPER IN THE TREE
TOOFELD(DEPTH) = TOO% ' USED FOR MOVE SORTING AND EXTENSION
' OF THE SEARCH.
EPFIELD(DEPTH) = ILLEGAL%
' MATERIAL BALANCE IS ALWAYS SEEN FROM THE VIEWPOINT OF THE PLAYER WHO IS
' TO MAKE A MOVE. THEREFORE, FLIP THE SIGN.
MATERIALBALANCE(DEPTH) = -MATERIALBALANCE(DEPTH - 1)
MATERIALTOTAL(DEPTH) = MATERIALTOTAL(DEPTH - 1)
' THE PIECE IS MOVING FROM THE 'FROM' FIELD TO THE 'TO' FIELD
MOVECONTROL(FROM%) = MOVECONTROL(FROM%) + 1
MOVECONTROL(TOO%) = MOVECONTROL(TOO%) + 1
IF EP% <> ILLEGAL% THEN
IF BOARD(EP%) = EMPTY% THEN ' PAWN MOVE FROM 2ND TO 4TH ROW
EPFIELD(DEPTH) = EP%
ELSE ' ENEMY PAWN IS CAPTURED ENPASSANT
BOARD(EP%) = EMPTY% ' REMOVE CAPTURED PAWN
MATERIALBALANCE(DEPTH) = MATERIALBALANCE(DEPTH) - MATP%
END IF
ELSE ' IF A PIECE IS CAPTURED, CHANGE THE MATERIAL BALANCE
IF MOVESTACK(CURRMOVE%).CAPTUREDPIECE <> EMPTY% THEN ' PIECE WAS CAPTURED
MATCHANGE% = PIECEMATERIAL(MOVESTACK(CURRMOVE%).CAPTUREDPIECE)
MATERIALBALANCE(DEPTH) = MATERIALBALANCE(DEPTH) - MATCHANGE%
' SUM UP ONLY THE OFFICER'S MATERIAL VALUE
IF MATCHANGE% <> MATP% THEN
MATERIALTOTAL(DEPTH) = MATERIALTOTAL(DEPTH) - MATCHANGE%
END IF
END IF
END IF
BOARD(TOO%) = BOARD(FROM%) ' PLACE ONTO BOARD
BOARD(FROM%) = EMPTY%
' NOW THE SPECIAL CASES PROMOTION AND CASTLING
IF MOVESTACK(CURRMOVE%).PROMOTEDPIECE <> EMPTY% THEN ' PAWN PROMOTION
BOARD(TOO%) = COLOUR * MOVESTACK(CURRMOVE%).PROMOTEDPIECE
MATCHANGE% = PIECEMATERIAL(MOVESTACK(CURRMOVE%).PROMOTEDPIECE) - MATP%
MATERIALBALANCE(DEPTH) = MATERIALBALANCE(DEPTH) - MATCHANGE%
' PAWNS ARE NOT INCLUDED IN MATERIALTOTAL.
MATERIALTOTAL(DEPTH) = MATERIALTOTAL(DEPTH) + MATCHANGE% + MATP%
ELSE
IF MOVESTACK(CURRMOVE%).CASTLINGNR = SHORTCASTLINGMOVE% THEN
BOARD(TOO% + 1) = EMPTY% ' 'TO' IS G1 OR G8 (DEPENDING ON COLOR)
BOARD(TOO% - 1) = COLOUR * WR% ' PUT WHITE/BLACK ROOK ON F1/F8
CASTLING(COLOUR + 1) = TRUE%
ELSEIF MOVESTACK(CURRMOVE%).CASTLINGNR = LONGCASTLINGMOVE% THEN
BOARD(TOO% - 2) = EMPTY% ' 'TO' IS C1 OR C8
BOARD(TOO% + 1) = COLOUR * WR%
CASTLING(COLOUR + 1) = TRUE%
END IF
END IF
' IF KING HAS MOVED, UPDATE THE KING'S POSITION
IF BOARD(TOO%) = WK% THEN
WKING = TOO%
ELSEIF BOARD(TOO%) = BK% THEN
BKING = TOO%
END IF
' FLIP THE COLOR (THE SIDE WHO IS TO MAKE THE MOVE)
COLOUR = -COLOUR
END SUB
'--------------------------------------------------------------------
' PRINTBACK:
' PRINT THE TAKE-BACK COMMAND
' CALLS:
' CALLEDBY:
'--------------------------------------------------------------------
SUB PRINTBACK
IF PRINTING = FALSE% THEN EXIT SUB ' ONLY IF PRINTING IS ON
IF COLOUR = WHITE% THEN
LPRINT " BACK"
ISWHITELAST = FALSE%
ELSE
LPRINT USING "###. BACK!"; MOVECOUNT \ 2 + 1; CHR$(9);
ISWHITELAST = TRUE%
END IF
END SUB
'--------------------------------------------------------------------
' PRINTLOGO:
' DISPLAYS THE PROGRAM LOGO/MENU ON THE MONITOR (SEE COMMANDLOOP
' CALLS: NONE
' CALLEDBY: MAIN;
'--------------------------------------------------------------------
SUB PRINTLOGO
CLS
PRINT "***********************************************************"
PRINT "* MINIMAX 1.0 (BASIC) *"
PRINT "* *"
PRINT "* BY DIETER STEINWENDER *"
PRINT "* AND CHRILLY DONNINGER *"
PRINT "* *"
PRINT "* INPUT A MOVE (E.G. G1F3) *"
PRINT "* OR ONE OT THE FOLLOWING COMMANDS: *"
PRINT "* *"
PRINT "* NG --> NEW GAME *"
PRINT "* EN --> END THE PROGRAM *"
PRINT "* DB --> DISPLAY BOARD ON THE MONITOR *"
PRINT "* CP --> INPUT POSITION (CHESS PROBLEM) *"
PRINT "* PL --> PLAY, COMPUTER MOVE *"
PRINT "* PR --> PRINTING ON/OFF *"
PRINT "* MM --> MULTI MOVES INPUT PLAYER-PLAYER *"
PRINT "* DL --> DISPLAY MOVE LIST *"
PRINT "* TB --> TAKE BACK ONE MOVE *"
PRINT "* SD --> SET COMPUTING DEPTH *"
PRINT "* DA --> DISPLAY ASSESSMENT *"
PRINT "***********************************************************"
END SUB
'--------------------------------------------------------------------
' PRINTMOVE:
' PRINTS THE CURRENT MOVE.
' WARNING: DON'T CHANGE THE FORMAT OF THIS OUTPUT AS IT WILL CAUSE
' MALFUNCTION OF THE NONAME DRIVER THE CHESS232 BOARD
' AND THE AUTOPLAYER AUTO232.
'
' NOTES:
' CHR$(9) IS THE TAB CHARACTER
' CALLS: FIELDNOTATION;
' CALLEDBY:
'--------------------------------------------------------------------
SUB PRINTMOVE (CURRMOVE%)
IF PRINTING = FALSE% THEN EXIT SUB ' ONLY IF PRINTING IS ON
IF COLOUR = BLACK% THEN ' IF BLACK IS TO MAKE A MOVE
' THE LAST MOVE WAS BY WHITE.
LPRINT USING "###. "; MOVECOUNT \ 2 + 1;
ISWHITELAST = TRUE%
ELSE ' BLACK MOVE
IF ISWHITELAST = TRUE% THEN
LPRINT " ";
ELSE
LPRINT USING "###. ... ! "; MOVECOUNT \ 2 + 1; CHR$(9);
END IF
ISWHITELAST = FALSE%
END IF
IF MOVESTACK(CURRMOVE%).CASTLINGNR = NOCASTLINGMOVE% THEN
LPRINT PRINTSYMBOL(ABS(BOARD(MOVESTACK(CURRMOVE%).TOO)));
FROM$ = LCASE$(FIELDNOTATION$(MOVESTACK(CURRMOVE%).FROM))
LPRINT FROM$;
IF MOVESTACK(CURRMOVE%).CAPTUREDPIECE <> EMPTY% THEN
LPRINT "X";
ELSE
LPRINT "-";
END IF
TOO$ = LCASE$(FIELDNOTATION$(MOVESTACK(CURRMOVE%).TOO))
LPRINT TOO$;
IF MOVESTACK(CURRMOVE%).PROMOTEDPIECE <> EMPTY% THEN
LPRINT PRINTSYMBOL(MOVESTACK(CURRMOVE%).PROMOTEDPIECE);
END IF
ELSEIF MOVESTACK(CURRMOVE%).CASTLINGNR = SHORTCASTLINGMOVE% THEN
LPRINT " 0-0 ";
ELSE
LPRINT " 0-0-0"
END IF
' FINISH WITH THE TAB CHARACTER FOR A WHITE MOVE
' OR A CHARRIAGE RETURN FOR A BLACK MOVE
IF COLOUR = BLACK% THEN
LPRINT CHR$(9);
ELSE
LPRINT
END IF
END SUB
'--------------------------------------------------------------------
' PRINTPOSITION:
' PRINTS THE CURRENT POSITION IM CHESSBASE / FRITZ FORMAT.
' WARNING: DON'T CHANGE THE FORMAT OF THIS OUTPUT AS IT WILL
' CAUSE MALFUNCTION OF THE CHESS332 DRIVER.
' CALLS: FIELDNOTATION;
' CALLEDBY:
'--------------------------------------------------------------------
SUB PRINTPOSITION
IF PRINTING = FALSE% THEN EXIT SUB
IF ISWHITELAST = TRUE% THEN
LPRINT
ISWHITELAST = FALSE%
END IF
LPRINT "(WK";
LPRINT FIELDNOTATION$(WKING); ' FIRST THE KING
FOR I% = A1% TO H8% ' REMAINING WHITE PIECES
IF BOARD(I%) > 0 AND BOARD(I%) < WK% THEN
LPRINT ","; FIGSYMBOL(BOARD(I%));
LPRINT FIELDNOTATION$(I%);
END IF
NEXT I%
LPRINT "; SK";
LPRINT FIELDNOTATION$(BKING); ' FIRST THE KING
FOR I% = A1% TO H8% ' REMAINING BLACK PIECES
IF BOARD(I%) < 0 AND BOARD(I%) > BK% THEN
LPRINT ","; FIGSYMBOL(ABS(BOARD(I%)));
LPRINT FIELDNOTATION$(I%);
END IF
NEXT I%
LPRINT ")"
END SUB
'--------------------------------------------------------------------
' READPIECE:
' READS THE PIECE FOR THE "SIDE"
' FORMAT IS: E.G. "KE1".
' "." IS "EMPTY FIELD", I.E. REMOVES ANY PIECE FROM THAT FIELD.
' CALLS: FIELDNUMBER;
' CALLEDBY:
'--------------------------------------------------------------------
SUB READPIECE (SIDE%)
NEXTPIECE:
INPUT INPUTS$
IF INPUTS$ = "" THEN EXIT SUB ' EXIT IF INPUT IS VOID
IF LEN(INPUTS$) < 3 THEN GOTO BADINPUT ' INPUT TO SHORT
INPUTS$ = UCASE$(INPUTS$) ' UPPERCASE
PIECE$ = LEFT$(INPUTS$, 1)
FELD$ = MID$(INPUTS$, 2, 2)
FOR I% = 0 TO PIECETYPES% ' FROM EMPTY FIELD TO KING
IF PIECE$ = FIGSYMBOL(I%) THEN
' CONVERTS CHESS NOTATION INTO FIELD VALUE
' FIRST CHARACTER OF INPUT WAS ALREADY USED FOR THE PIECE
FELD% = FIELDNUMBER%(FELD$)
IF FELD% = ILLEGAL% THEN GOTO BADINPUT
IF I% = WP% THEN ' PAWNS ONLY LEGAL ON 2ND THRU 7TH ROW
IF FELD% <= H1% OR FELD% >= A8% THEN GOTO BADINPUT
END IF
PIECE% = I% * SIDE% ' IF COLOR IS BLACK THE SIGN
' OF THE PIECE IS REVERSED.
BOARD(FELD%) = PIECE% ' PLACE PIECE ON THE BOARD
GOTO NEXTPIECE
END IF
NEXT I%
BADINPUT:
PRINT " BAD INPUT ENTERED "
GOTO NEXTPIECE
END SUB
'--------------------------------------------------------------------
' SAVECAPTUREMOVE:
' SAVE A CAPTURE MOVE IN MOVESTACK.
' CALLS:
' CALLEDBY:
'--------------------------------------------------------------------
SUB SAVECAPTUREMOVE (FROM%, TOO%)
' KING CANNOT BE CAPTURED
IF BOARD(TOO%) = WK% OR BOARD(TOO%) = BK% THEN EXIT SUB
FIGVALUE% = PIECEMATERIAL(ABS(BOARD(TOO%)))
MOVESTACK(INDEX).FROM = FROM%
MOVESTACK(INDEX).TOO = TOO%
MOVESTACK(INDEX).CAPTUREDPIECE = ABS(BOARD(TOO%))
' RULE FOR MOVE SORTING: CAPTUREE THE MOSE VALUABLE PIECE
' USING THE THE LEAST VALUABLE PIECE
MOVESTACK(INDEX).VALUE = FIGVALUE% - (PIECEMATERIAL(ABS(BOARD(FROM%))) \ 8)
' EXTRA BONUS FOR CAPTURING THE PIECE JUST MOVED
IF DEPTH > 0 THEN
IF TOO% = TOOFELD(DEPTH - 1) THEN
MOVESTACK(INDEX).VALUE = MOVESTACK(INDEX).VALUE + 300
END IF
END IF
' BONUS FOR MAIN VARIANT MOVES AND "KILLER" MOVES
KILLER1% = KILLERTAB(DEPTH).KILLER1.FROM = FROM%
KILLER1% = KILLER1% AND KILLERTAB(DEPTH).KILLER1.TOO = TOO%
KILLER2% = KILLERTAB(DEPTH).KILLER2.FROM = FROM%
KILLER2% = KILLER2% AND KILLERTAB(DEPTH).KILLER2.TOO = TOO%
MVARMOVE% = MVAR(0, DEPTH).FROM = FROM% AND MVAR(0, DEPTH).TOO = TOO%
IF MVARMOVE% THEN
MOVESTACK(INDEX).VALUE = MOVESTACK(INDEX).VALUE + MAINVARIANTBONUS%
ELSEIF KILLER1% THEN
MOVESTACK(INDEX).VALUE = MOVESTACK(INDEX).VALUE + KILLER1BONUS%
ELSEIF KILLER2% THEN
MOVESTACK(INDEX).VALUE = MOVESTACK(INDEX).VALUE + KILLER2BONUS%
END IF
MOVESTACK(INDEX).PROMOTEDPIECE = EMPTY%
MOVESTACK(INDEX).CASTLINGNR = NOCASTLINGMOVE%
MOVESTACK(INDEX).EPFIELD = ILLEGAL%
IF INDEX < MOVESTACKDIM% THEN ' PREVENT MOVESTACK OVERFLOW
INDEX = INDEX + 1
ELSE
PRINT " ERROR: MOVE STACK OVERFLOW"
SYSTEM ' EXIT TO DOS
END IF
END SUB
'--------------------------------------------------------------------
' SAVEEPMOVE:
' SAVE EN PASSANT MOVE IN THE MOVESTACK.
' CALLS:
' CALLEDBY:
'--------------------------------------------------------------------
SUB SAVEEPMOVE (FROM%, TOO%, EP%)
' KING CANNOT BE CAPTURED
IF BOARD(TOO%) = WK% OR BOARD(TOO%) = BK% THEN EXIT SUB
MOVESTACK(INDEX).FROM = FROM%
MOVESTACK(INDEX).TOO = TOO%
MOVESTACK(INDEX).CAPTUREDPIECE = WP%
MOVESTACK(INDEX).PROMOTEDPIECE = EMPTY%
MOVESTACK(INDEX).CASTLINGNR = NOCASTLINGMOVE%
MOVESTACK(INDEX).EPFIELD = EP%
MOVESTACK(INDEX).VALUE = MATP%
IF INDEX < MOVESTACKDIM% THEN ' PREVENT MOVESTACK OVERFLOW
INDEX = INDEX + 1
ELSE
PRINT " ERROR: MOVE STACK OVERFLOW"
SYSTEM ' EXIT TO DOS
END IF
END SUB
'---------------------------------------------------------------------
' SAVEMOVE:
' SAVE A NORMAL MOVE IN THE MOVESTACK.
' AS A SIDE EFFECT, THIS PROCEDURE PROVIDES THE MOBILITY OF BISHOP
' AND ROOK, AS WELL AS THE VALUE OF THE MOVE FOR THE PRE-SORTING.
' CALLS:
' CALLEDBY:
'---------------------------------------------------------------------
SUB SAVEMOVE (FROM%, TOO%)
' INCRESE THE MOBILITY OF THE BISHOP AND ROOK.
' MOBILITY IN THE CENTER IS RATED HIGHER
' THAN MOBILITY AT THE EDGE.
IF COLOUR = WHITE% THEN
IF BOARD(FROM%) = WB% OR BOARD(FROM%) = WR% THEN
MOBILITY(DEPTH) = MOBILITY(DEPTH) + CENTERTABLE(TOO%)
END IF
ELSE
IF BOARD(FROM%) = BB% OR BOARD(FROM%) = BR% THEN
MOBILITY(DEPTH) = MOBILITY(DEPTH) + CENTERTABLE(TOO%)
END IF
END IF
' ASSESS THE MOVE FOR MOVE SORTING. BONUS FOR MAIN VARIANT OR "KILLER"
KILLER1% = KILLERTAB(DEPTH).KILLER1.FROM = FROM%
KILLER1% = KILLER1% AND KILLERTAB(DEPTH).KILLER1.TOO = TOO%
KILLER2% = KILLERTAB(DEPTH).KILLER2.FROM = FROM%
KILLER2% = KILLER2% AND KILLERTAB(DEPTH).KILLER2.TOO = TOO%
MVARMOVE% = MVAR(0, DEPTH).FROM = FROM% AND MVAR(0, DEPTH).TOO = TOO%
IF MVARMOVE% THEN
MOVESTACK(INDEX).VALUE = MAINVARIANTBONUS%
ELSEIF KILLER1% THEN
MOVESTACK(INDEX).VALUE = KILLER1BONUS%
ELSEIF KILLER2% THEN
MOVESTACK(INDEX).VALUE = KILLER2BONUS%
ELSE
MOVESTACK(INDEX).VALUE = EMPTY%
END IF
MOVESTACK(INDEX).FROM = FROM%
MOVESTACK(INDEX).TOO = TOO%
MOVESTACK(INDEX).CAPTUREDPIECE = EMPTY%
MOVESTACK(INDEX).PROMOTEDPIECE = EMPTY%
MOVESTACK(INDEX).CASTLINGNR = NOCASTLINGMOVE%
MOVESTACK(INDEX).EPFIELD = ILLEGAL%
IF INDEX < MOVESTACKDIM% THEN ' PREVENT MOVESTACK OVERFLOW
INDEX = INDEX + 1
ELSE
PRINT " ERROR: MOVE STACK OVERFLOWED"
SYSTEM ' IN THIS CASE "EASE OUT" TO DOS
END IF
END SUB
'--------------------------------------------------------------------
' SAVEPROMOTION:
' PRODUCE ALL POSSIBLE PAWN PROMOTIONS
' CALLS: SAVEMOVE; SAVECAPTUREMOVE;
' CALLEDBY:
'--------------------------------------------------------------------
SUB SAVEPROMOTION (FROM%, TOO%)
IF BOARD(TOO%) = EMPTY% THEN
FOR I% = WQ% TO WR% STEP -1 ' SEQUENCE QUEEN,KNIGHT,BISHOP,ROOK
CALL SAVEMOVE(FROM%, TOO%)
MOVESTACK(INDEX - 1).PROMOTEDPIECE = I%
NEXT I%
ELSE ' PROMOTION WITH CAPTURE
FOR I% = WQ% TO WR% STEP -1
CALL SAVECAPTUREMOVE(FROM%, TOO%)
MOVESTACK(INDEX - 1).PROMOTEDPIECE = I%
NEXT I%
END IF
END SUB
'--------------------------------------------------------------------
' TAKEBACKMOVE:
' TAKES BACK A MOVE IN THE TREE.
' CURRMOVE% IS THE INDEX OF THE MOVE IN MOVESTACK.
' CALLS:
' CALLEDBY:
'--------------------------------------------------------------------
SUB TAKEBACKMOVE (CURRMOVE%)
MOVECOUNT = MOVECOUNT - 1
FROM% = MOVESTACK(CURRMOVE%).FROM
TOO% = MOVESTACK(CURRMOVE%).TOO
EP% = MOVESTACK(CURRMOVE%).EPFIELD
COLOUR = -COLOUR ' OTHER SIDE TO MOVE
DEPTH = DEPTH - 1 ' ONE LEVEL HIGHER IN TREE
BOARD(FROM%) = BOARD(TOO%) ' PUT BACK THE PIECE
BOARD(TOO%) = EMPTY%
IF EP% <> ILLEGAL% AND MOVESTACK(CURRMOVE%).CAPTUREDPIECE = WP% THEN
BOARD(EP%) = -COLOUR ' WP%=WHITE%, BP%=BLACK%
' PUT BACK CAPTURED PIECE
ELSEIF MOVESTACK(CURRMOVE%).CAPTUREDPIECE <> EMPTY% THEN
BOARD(TOO%) = (-COLOUR) * MOVESTACK(CURRMOVE%).CAPTUREDPIECE
END IF
' ADJUST MOVE COUNTER
MOVECONTROL(FROM%) = MOVECONTROL(FROM%) - 1
MOVECONTROL(TOO%) = MOVECONTROL(TOO%) - 1
' IF CASTLING PUT BACK ROOK
IF MOVESTACK(CURRMOVE%).CASTLINGNR = SHORTCASTLINGMOVE% THEN
BOARD(TOO% + 1) = COLOUR * WR%
BOARD(TOO% - 1) = EMPTY%
CASTLING(COLOUR + 1) = FALSE%
ELSEIF MOVESTACK(CURRMOVE%).CASTLINGNR = LONGCASTLINGMOVE% THEN
BOARD(TOO% - 2) = COLOUR * WR%
BOARD(TOO% + 1) = EMPTY%
CASTLING(COLOUR + 1) = FALSE%
END IF
IF MOVESTACK(CURRMOVE%).PROMOTEDPIECE <> EMPTY% THEN
BOARD(FROM%) = COLOUR ' TAKE BACK PAWN PROMOTION
END IF
' IF THE KING HAS MOVED, UPDATE THE KING'S POSITION
IF BOARD(FROM%) = WK% THEN
WKING = FROM%
ELSEIF BOARD(FROM%) = BK% THEN
BKING = FROM%
END IF
END SUB
'--------------------------------------------------------------------
' WPASSESSMENT: FUNCTION
' ASSESSMENT OF ONE WHITE PAWN.
' ANALOGOUS TO THE ASSESSMENT OF BLACK PAWNS.
' RETURNS THE ASSESSMENT FROM WHITE'S VIEWPOINT.
' CALLS:
' CALLEDBY: ASSESSPOSITION
'--------------------------------------------------------------------
FUNCTION WPASSESSMENT% (FELD%, COLUMN%, ROW%, DEVELOPED%)
IF MATERIALTOTAL(DEPTH) > ENDGAMEMATERIAL% THEN ' OPENING OF MIDGAME
VALUE% = WPFIELDVALUE(FELD%)
' IF DEVELOPMENT INCOMPLETE, DON'T PUSH EDGE PAWNS FORWARD
IF DEVELOPED% < 4 THEN
IF (ROW% >= FROW% OR ROW% <= BROW%) AND COLUMN% > COLUMN3% THEN
VALUE% = VALUE% - 15
END IF
END IF
ELSE ' IN THEN ENDGAME, ALL LINES ARE EQUALLY GOOD.
VALUE% = COLUMN% * 4 ' BRING PAWNS FORWARD.
END IF
' IS THE PAWN ISOLATED?
' EDGE PAWNS DON'T REQUIRE EXTRA TREATMENT. PAWNS(AROW-1) IS
' THE LEFT EDGE, PAWNS(HROW+1) THE RIGHT EDGE. NO PAWN IS
' PLACED ON THESE EDGES.
IF PAWNS(ROW% - 1).WHITE = 0 AND PAWNS(ROW% + 1).WHITE = 0 THEN
VALUE% = VALUE% - 12 ' ISOLATED
' ISOLATED DOUBLE PAWN
IF PAWNS(ROW%).WHITE > 1 THEN VALUE% = VALUE% - 12
END IF
' DOUBLE PAWNS
IF PAWNS(ROW%).WHITE > 1 THEN VALUE% = VALUE% - 15
' DUO OR GUARDED PAWN GETS A BONUS
IF PAWNCONTROLLED(FELD%).WHITE > 0 OR PAWNCONTROLLED(FELD% + 10).WHITE > 0 THEN
VALUE% = VALUE% + COLUMN%
END IF
IF PAWNS(ROW%).BLACK = 0 THEN ' HALF-OPEN COLUMN
' PAWN LEFT BEHIND ON HALF-OPEN COLUMN:
' LEFT BEHIND PAWN IS NOT GUARDED BY ITS FELLOW PAWNS..
CONDITION1% = PAWNCONTROLLED(FELD%).WHITE = 0
' ... AND CAN'T ADVANCE BECAUSE OF ENEMY PAWNS
' CONTROL THE FIELD IN FRONT OF HIM.
CONDITION2% = PAWNCONTROLLED(FELD% + 10).BLACK > PAWNCONTROLLED(FELD% + 10).WHITE
IF CONDITION1% AND CONDITION2% THEN
VALUE% = VALUE% - 10
' ROOK IMPEDED BY LEFT-BEHIND PAWN
IF ROOKS(ROW%).BLACK > 0 THEN VALUE% = VALUE% - 8
ELSE
' PAWN IS A FREE PAWN, ON A HALF-OPEN COLUMN AND THE
' FIELDS AHEAD ON HIS COLUMN ARE NOT CONTROLLED BY
' ENEMY PAWNS.
FOR J% = FELD% TO H6% STEP 10 ' UNTIL 6TH ROW
IF PAWNCONTROLLED(J%).BLACK > 0 THEN
WPASSESSMENT% = VALUE%
EXIT FUNCTION
END IF
NEXT J%
' FREE PAWN FOUND. IN THE ENDGAME, A FREE PAWN IS MORE IMPORTANT
' THAN IN MIDGAME.
IF MATERIALTOTAL(DEPTH) < ENDGAMEMATERIAL% THEN
VALUE% = VALUE% + COLUMN% * 16 ' THE MORE ADVANCED THE BETTER
' ROOK GUARDS FREE PAWN ON THE SAME COLUMN
IF ROOKS(ROW%).WHITE > 0 THEN VALUE% = VALUE% + COLUMN% * 2
' ENEMY ROOK ON THE SAME COLUMN.
IF ROOKS(ROW%).BLACK > 0 THEN VALUE% = VALUE% - COLUMN% * 2
' PURE PAWN ENDGAME. FREE PAWN PARTICULARLY VALUABLE.
IF MATERIALTOTAL(DEPTH) = 0 THEN VALUE% = VALUE% + COLUMN% * 8
' GUARDED FREE PAWN
IF PAWNCONTROLLED(FELD%).WHITE > 0 OR PAWNCONTROLLED(FELD% + 10).WHITE > 0 THEN
VALUE% = VALUE% + COLUMN% * 4
END IF
' FREE PAWN BLOCKED BY A BLACK PIECE. THIS PIECE IS NOT
' THREATENED BY FELLOW PAWNS.
IF BOARD(FELD% + 10) < 0 AND PAWNCONTROLLED(FELD% + 10).WHITE = 0 THEN
VALUE% = VALUE% - COLUMN% * 4
END IF
ELSE ' FREE PAWN IN THE MIDGAME
VALUE% = VALUE% + COLUMN% * 8
' GUARDED FREE PAWN
IF PAWNCONTROLLED(FELD%).WHITE > 0 OR PAWNCONTROLLED(FELD% + 10).WHITE > 0 THEN
VALUE% = VALUE% + COLUMN% * 2
END IF
END IF
END IF
END IF
WPASSESSMENT% = VALUE%
END FUNCTION