'===========================================================================
' Subject: SMART CHECKERS                     Date: 02-24-97 (16:00)       
'  Author: Rich Geldreich                     Code: QB, QBasic, PDS        
'  Origin: harryst@castel.nl                Packet: GAMES.ABC
'===========================================================================
'-----------------------------------------------------------------------------
'A Checkers Game That Learns From Its Mistakes:By Rich Geldreich
'(Well, it should. I did my best, if you have any comments, please write!)
'410 Market Street
'Gloucester City, New Jersey 08030
'-----------------------------------------------------------------------------


DEFINT A-Z
'-----------------------------------------------------------------------------
'Subroutines for program
'-----------------------------------------------------------------------------
DECLARE FUNCTION Bttn ()
DECLARE FUNCTION Getkey$ ()
DECLARE FUNCTION SelectPiece (Flash)
DECLARE FUNCTION JumpWay (Start, Middle)
DECLARE FUNCTION Increment (A)
DECLARE FUNCTION IsTop (P)
DECLARE FUNCTION IsLeft (P)
DECLARE FUNCTION IsRight (P)
DECLARE FUNCTION IsBottom (P)
DECLARE FUNCTION TopLeft (Position)
DECLARE FUNCTION TopRight (Position)
DECLARE FUNCTION BottomLeft (Position)
DECLARE FUNCTION BottomRight (Position)
DECLARE FUNCTION SameRow (P1, P2)
DECLARE FUNCTION SameColumn (P1, P2)
DECLARE FUNCTION Scan (Position)
DECLARE FUNCTION Joystick (Flash)
DECLARE SUB HumansMove ()
DECLARE SUB PickMove ()
DECLARE SUB DeleteBlack (P%)
DECLARE SUB DeleteRed (P)
DECLARE SUB PutChecker (P, Rd, King)
DECLARE SUB EraseChecker (P)
DECLARE SUB ComputersTurn ()
DECLARE SUB DrawBord ()
DECLARE SUB TestComputersMoves ()
DECLARE SUB CalculatePoints ()
DECLARE SUB HumansMoves ()
DECLARE SUB ScanAround (Piece, Col)
DECLARE SUB PreparePieces ()
DECLARE SUB Allmoves (Piece, C, Jumps)
DECLARE SUB update ()

'-----------------------------------------------------------------------------
'Constants
'-----------------------------------------------------------------------------

CONST True = -1, False = NOT True
CONST Red = 0, Black = 1, Null = 2
CONST Sngl = 0, Jmp = 1, King = 2

'-----------------------------------------------------------------------------
'Data Types
'-----------------------------------------------------------------------------

TYPE Piece
    Pst AS INTEGER
    King AS INTEGER
END TYPE

TYPE M
    Pce AS INTEGER
    Move AS INTEGER
END TYPE

TYPE Co
    X AS INTEGER
    Y AS INTEGER
END TYPE


'-----------------------------------------------------------------------------
'Define Global Variables
'-----------------------------------------------------------------------------

CLEAR , , 5000
DIM SHARED Reds(12) AS Piece, Blacks(12) AS Piece, NumReds, NumBlacks
DIM SHARED PosMap(12, 4), Posmoves(12), Pty(12, 4), Typ(12, 4), M(12, 4)
DIM SHARED PosMapR(12, 4), PosMovesR(12), TypR(12, 4), MR(12, 4)
DIM SHARED TempPos(4), TempNum, Temp(4), Tempn, Good(4)
DIM SHARED Piece, Move, C
DIM SHARED Xy(32) AS Co, Game
DIM SHARED K$, Aa(15), Ag(90), Bg(90)
DIM SHARED Points(13) AS DOUBLE
DIM SHARED Mem(12, 12, 4), Used(12), NotUsed(12), In, GiveUp



'-----------------------------------------------------------------------------
'Set Global Vars(Some Vars will set themselve when they are first called via
'Subs)
'Set the Game var to True if you want the all-kings version
'-----------------------------------------------------------------------------

Al = 60: Bl = 60
Game = False
In = False
PreparePieces

SCREEN 1
COLOR 0, 0
CLS
VIEW PRINT 1 TO 25

RANDOMIZE TIMER

'-----------------------------------------------------------------------------
'Draw cursor for joystick pointing
'-----------------------------------------------------------------------------

GET (0, 0)-(26, 18), Bg
DRAW "Bm160,100h5nd3r3"
GET (160, 100)-(160 - 5, 100 - 5), Aa
CLS
'-----------------------------------------------------------------------------
'Scan for data files, if exists, use them. If not, play without(completely
'dumb)
'-----------------------------------------------------------------------------

Exists = True
ON ERROR GOTO NotExists
OPEN "I", #1, "Learn.Dat"
ON ERROR GOTO 0
IF Exists THEN
    FOR A = 1 TO 12
        INPUT #1, Points(A)
    NEXT
    CLOSE
END IF
PRINT
PRINT "Checkers By Rich Geldreich 1991"
PRINT "H.A.D Data Has ";
IF Exists THEN
    PRINT "Been Loaded"
ELSE
    PRINT "Not Been Loaded"
END IF
PRINT "Heuristic Application Data(H.A.D):"
FOR A = 1 TO 12
    PRINT "Rule "; MID$(STR$(A), 2); ":"; Points(A)
NEXT
PRINT
PRINT "Please Select Input Device:"
PRINT "1. Keyboard"
PRINT "2. Joystick"
ln = CSRLIN
DO
    LOCATE ln, 1
    LINE INPUT A$
    A = VAL(A$)
LOOP UNTIL A = 1 OR A = 2
IF A = 2 THEN
    In = False
ELSE
    In = True
END IF
CLS
IF In THEN
    PRINT "Keys to use:"
    PRINT
    PRINT "Left and Right Arrows Select"
    PRINT
    PRINT "Q Quits"
    PRINT
    PRINT "T Takes Back A Selected Piece"
ELSE
    PRINT "Use Joystick(Stick 0 and 1) to"
    PRINT "Select Pieces"
    PRINT
    PRINT "Q Quits"
    PRINT
    PRINT "T Takes Back A Selected Piece"
END IF
PRINT : PRINT
PRINT "NOTE: While making a multiple jump, go"
PRINT "to the place where you want to jump to,"
PRINT "otherwise, select any illegal block if"
PRINT "you don't want to jump."
IF In THEN
    LOCATE 24, 1
    PRINT "Press a key to play";
    A$ = INPUT$(1)
ELSE
    LOCATE 24, 1
    PRINT "Click joystick to play";
    DO
    LOOP UNTIL STRIG(1)
END IF
CLS
DrawBord
update
DO
    ComputersTurn
    LOCATE 1, 12: PRINT "Red:"; NumReds; "Black:"; NumBlacks; "  "

    IF NOT GiveUp AND NumReds <> 0 THEN
        HumansMove
    END IF
    LOCATE 1, 12: PRINT "Red:"; NumReds; "Black:"; NumBlacks; "  "
LOOP UNTIL GiveUp OR NumReds = 0 OR NumBlacks = 0
CLS
IF GiveUp THEN
    PRINT "It's a tie! Well, how about that!"
    PRINT "Learned data not updated."
    END
END IF

IF NumBlacks = 0 THEN
    PRINT "I Lost! Darn!"
    FOR A = 1 TO 12
        Points(A) = Points(A) - Used(A) * 3 + NotUsed(A)
    NEXT
END IF

IF NumReds = 0 THEN
    PRINT "I Won! Great!!"
END IF
PRINT "Rule Usage Statistics"
PRINT "Used", "NotUsed"
FOR A = 1 TO 12
    PRINT MID$(STR$(A), 2); ":"; Used(A), NotUsed(A)
NEXT
OPEN "O", #1, "Learn.Dat"
FOR A = 1 TO 12
    PRINT #1, Points(A)
NEXT
CLOSE #1
PRINT "Learned Data Stored"
SOUND 2600, 22
END

NotExists:
    Exists = False
RESUME NEXT

'-----------------------------------------------------------------------------'
'Calculates all legal moves for a piece and stores in an array
'-----------------------------------------------------------------------------'
SUB Allmoves (Piece, C, Jumps)
    Posmoves(Piece) = 0
    ScanAround Piece, C
    FOR A = 0 TO TempNum - 1
        Temp(A) = TempPos(A)
        Good(A) = True
    NEXT
    Tempn = TempNum
    FOR A = 0 TO Tempn - 1
        P = Temp(A)
        SELECT CASE C
        CASE Red
            IF NOT Reds(Piece).King AND (INT(P / 4) * 4) > INT(Reds(Piece).Pst / 4) * 4 THEN
                Good(A) = False
            END IF
            IF Scan(P) = Red THEN
                Good(A) = False
            END IF
        CASE Black
            IF NOT Blacks(Piece).King AND (INT(P / 4) * 4) < INT(Blacks(Piece).Pst / 4) * 4 THEN
                Good(A) = False
            END IF
            IF Scan(P) = Black THEN
                Good(A) = False
            END IF
        END SELECT
    NEXT
    FOR A = 0 TO Tempn - 1
        IF Good(A) THEN
            S = Scan(Temp(A))
            IF S = Null AND Jumps = False THEN
                PosMap(Piece, Posmoves(Piece)) = Temp(A)
                Typ(Piece, Posmoves(Piece)) = Sngl
                SELECT CASE C
                CASE Red
                    IF (INT(Temp(A) / 4) * 4) = 0 AND Reds(Piece).King = False THEN
                        Typ(Piece, Posmoves(Piece)) = King
                    END IF
                CASE Black
                    IF (INT(Temp(A) / 4) * 4) = 28 AND Blacks(Piece).King = False THEN
                        Typ(Piece, Posmoves(Piece)) = King
                    END IF
                END SELECT
                Posmoves(Piece) = Increment(Posmoves(Piece))
            ELSE
                IF S <> Null THEN
                    IF NOT (IsTop(Temp(A)) OR IsBottom(Temp(A)) OR IsLeft(Temp(A)) OR IsRight(Temp(A))) THEN
                        SELECT CASE C
                        CASE Red
                            J = JumpWay(Reds(Piece).Pst, Temp(A))
                        CASE Black
                            J = JumpWay(Blacks(Piece).Pst, Temp(A))
                        END SELECT
                        IF Scan(J) = Null THEN
                            PosMap(Piece, Posmoves(Piece)) = J
                            Typ(Piece, Posmoves(Piece)) = Jmp
                            M(Piece, Posmoves(Piece)) = Temp(A)
                            Posmoves(Piece) = Increment(Posmoves(Piece))
                        END IF
                    END IF
                END IF
            END IF
        END IF
    NEXT
END SUB

'-----------------------------------------------------------------------------'
'Returns square on the bottom left
'-----------------------------------------------------------------------------'
FUNCTION BottomLeft (Position)
    First = INT(Position / 4) * 4
    IF (First AND 4) = 0 THEN
        BottomLeft = Position + 4
    ELSE
        BottomLeft = Position + 3
    END IF
END FUNCTION

'-----------------------------------------------------------------------------'
'Returns square on the bottom right
'-----------------------------------------------------------------------------DEFINT A-Z
FUNCTION BottomRight (Position)
    First = INT(Position / 4) * 4
    IF (First AND 4) = 0 THEN
        BottomRight = Position + 5
    ELSE
        BottomRight = Position + 4
    END IF
END FUNCTION

'-----------------------------------------------------------------------------'
'Get joysticks button status(if the button is held down, only one signal
'will be sent, "bounceless")
'-----------------------------------------------------------------------------'
FUNCTION Bttn
    STATIC Bounce
    Bttn = False
    IF STRIG(1) THEN
        IF NOT Bounce THEN
            Bounce = True
            Bttn = True
        END IF
    ELSE
        Bounce = False
    END IF
END FUNCTION

'-----------------------------------------------------------------------------'
'Major routine: looks at all possible moves for each player;gives each piece
'a score. The piece with the higest score is used for computers move. Each
'move's value is adjusted every time the computer wins or losses depending on
'how many times the computer has used that move in the actual game.
'If the computer lost, the moves it used are punished(made lower in value).
'If the computer won, the moves it used are rewarded(made higher in value).
'Note that this subroutine only calculates the points!
'-----------------------------------------------------------------------------'
SUB CalculatePoints
    DIM PosJumps(60)
    DIM PosKing(60)
    DIM PosMapS(12, 4), PosMovesS(12), TypS(12, 4), MS(12, 4)
    DIM PosMapS1(12, 4), PosMovesS1(12), TypS1(12, 4), MS1(12, 4)
   
    HumansMoves
   
    TestComputersMoves
    GiveUp = True

    FOR A = 1 TO NumBlacks
        IF Posmoves(A) > 0 THEN
            GiveUp = False
            EXIT FOR
        END IF
    NEXT
    IF NOT GiveUp THEN
        FOR A = 1 TO NumBlacks
            FOR B = 0 TO Posmoves(A) - 1
                FOR C = 1 TO 12
                    Mem(C, A, B) = False
                NEXT
                Pty(A, B) = 0
            NEXT
        NEXT

        PosJumps = 0
        FOR A = 1 TO NumReds
            FOR B = 0 TO PosMovesR(A) - 1
                IF TypR(A, B) = Jmp THEN
                    PosJumps(PosJumps) = PosMapR(A, B)
                    PosJumps = Increment(PosJumps)
                END IF
            NEXT
        NEXT
   
        PosKings = 0
        FOR A = 1 TO NumReds
            FOR B = 0 TO PosMovesR(A) - 1
                IF TypR(A, B) = King THEN
                    PosKing(PosKings) = PosMapR(A, B)
                    PosKings = Increment(PosKings)
                END IF
            NEXT
        NEXT

        ' Start of Raster Scheme
   
        FOR A = 0 TO PosJumps - 1
            FOR B = 1 TO NumBlacks
                FOR C = 0 TO Posmoves(B) - 1
                    IF PosMap(B, C) = PosJumps(A) THEN
                        Pty(B, C) = Pty(B, C) + Points(1)
                        Mem(1, B, C) = True
                    END IF
                NEXT
            NEXT
        NEXT

        FOR A = 0 TO PosKings - 1
            FOR B = 1 TO NumBlacks
                FOR C = 0 TO Posmoves(B) - 1
                    IF PosMap(B, C) = PosKing(A) THEN
                        Pty(B, C) = Pty(B, C) + Points(2)
                        Mem(2, B, C) = True
                    END IF
                NEXT
            NEXT
        NEXT

        FOR A = 1 TO NumBlacks
            FOR B = 0 TO Posmoves(A) - 1
                SELECT CASE Typ(A, B)
                CASE King
                    Pty(A, B) = Pty(A, B) + Points(3)
                    Mem(3, A, B) = True
                CASE Jmp
                    Pty(A, B) = Pty(A, B) + Points(4)
                    Mem(4, A, B) = True
                CASE Sngl
                END SELECT
            NEXT
        NEXT
        FOR A = 1 TO NumReds
            FOR B = 0 TO PosMovesR(A) - 1
                IF TypR(A, B) = Jmp THEN
                    F = Scan(MR(A, B))
                    FOR C1 = 0 TO Posmoves(C) - 1
                        Pty(C, C1) = Pty(C, C1) + Points(6)
                        Mem(6, C, C1) = True
                    NEXT
                END IF
            NEXT
        NEXT
       
        FOR A = 1 TO NumBlacks
            FOR B = 0 TO Posmoves(A) - 1
                PosMapS(A, B) = PosMap(A, B)
                TypS(A, B) = Typ(A, B)
                MS(A, B) = M(A, B)
            NEXT
            PosMovesS(A) = Posmoves(A)
        NEXT
        FOR A = 1 TO NumReds
            FOR B = 0 TO PosMovesR(A) - 1
                PosMapS1(A, B) = PosMapR(A, B)
                TypS1(A, B) = TypR(A, B)
                MS1(A, B) = MR(A, B)
            NEXT
            PosMovesS1(A) = PosMovesR(A)
        NEXT
   


        FOR A1 = 1 TO NumBlacks
            Last = Blacks(A1).Pst
            FOR B = 0 TO PosMovesS(A1) - 1
                Dest = PosMapS(A1, B)
                Blacks(A1).Pst = Dest
                IF TypS(A1, B) = Jmp THEN
                    F = Scan(MS(A1, B))
                    Mchecker = C
                    Mpos = Reds(Mchecker).Pst
                    Mking = Reds(Mchecker).King
                    DeleteRed Mchecker
                END IF
                   
                TestComputersMoves
                FOR D = 0 TO Posmoves(A1) - 1
                    SELECT CASE Typ(A1, D)
                    CASE Jmp
                        Pty(A1, D) = Pty(A1, D) + Points(11)
                        Mem(11, A1, B) = True
                    CASE King
                        Pty(A1, D) = Pty(A1, D) + Points(12)
                        Mem(12, A1, B) = True
                    CASE Sngl
                    END SELECT
               
                NEXT
                   
                HumansMoves
                FOR C1 = 1 TO NumReds
                    FOR D = 0 TO PosMovesR(C1) - 1
                        IF TypR(C1, D) = Jmp THEN
                            IF PosMapR(C1, D) = Last THEN
                                Pty(A1, B) = Pty(A1, B) + Points(8)
                                Mem(8, A1, B) = True
                            END IF
                            IF Scan(MR(C1, D)) = Black AND C = A1 THEN
                                Pty(A1, B) = Pty(A1, B) + Points(9)
                                Mem(9, A1, B) = True
                            END IF
                            IF PosMapR(C1, D) = Mpos THEN
                                Pty(A1, B) = Pty(A1, B) + Points(10)
                                Mem(10, A1, B) = True
                            END IF
                        END IF
                    NEXT D
                NEXT C1
                IF TypS(A1, B) = Jmp THEN
                    FOR Z = NumReds + 1 TO Mchecker + 1 STEP -1
                        Reds(Z).Pst = Reds(Z - 1).Pst
                        Reds(Z).King = Reds(Z - 1).King
                    NEXT Z
                    Reds(Mchecker).Pst = Mpos
                    Reds(Mchecker).King = Mking
                    NumReds = NumReds + 1
                END IF
                Blacks(A1).Pst = Last
            NEXT B
        NEXT A1
        FOR A = 1 TO NumBlacks
            FOR B = 0 TO PosMovesS(A) - 1
                SWAP PosMapS(A, B), PosMap(A, B)
                SWAP TypS(A, B), Typ(A, B)
                SWAP MS(A, B), M(A, B)
            NEXT
            SWAP PosMovesS(A), Posmoves(A)
        NEXT
        FOR A = 1 TO NumReds
            FOR B = 0 TO PosMovesS1(A) - 1
                SWAP PosMapS1(A, B), PosMapR(A, B)
                SWAP TypS1(A, B), TypR(A, B)
                SWAP MS1(A, B), MR(A, B)
            NEXT
            SWAP PosMovesS1(A), PosMovesR(A)
        NEXT
    END IF
END SUB

'-----------------------------------------------------------------------------'
'Computers turn:
'Calculates points for each piece, select piece, and handles multiple and
'single jumps
'-----------------------------------------------------------------------------'
SUB ComputersTurn
    LOCATE 24, 14: PRINT "Thinking...";
    CalculatePoints
    IF NOT GiveUp THEN
        PickMove
        LOCATE 24, 1: PRINT SPACE$(70);
        EraseChecker Blacks(Piece).Pst
        Blacks(Piece).Pst = PosMap(Piece, Move)
       
        IF NOT Blacks(Piece).King AND (INT(Blacks(Piece).Pst / 4) * 4) = 28 THEN
            Blacks(Piece).King = True
        END IF
       
       
        PutChecker Blacks(Piece).Pst, False, Blacks(Piece).King
        IF Typ(Piece, Move) = Jmp THEN
            P = Piece
            DO
                SLEEP 1
                EraseChecker Blacks(P).Pst
                T = Scan(M(P, Move))
                EraseChecker M(P, Move)
                DeleteRed C: SOUND 1000, 6
                Blacks(0).Pst = PosMap(P, Move)
                Blacks(0).King = Blacks(P).King
                PutChecker Blacks(0).Pst, False, Blacks(0).King
                IF NOT Blacks(0).King AND (INT(Blacks(0).Pst / 4) * 4) = 28 THEN
                    Blacks(0).King = True
                    PutChecker Blacks(0).Pst, False, True
                END IF
                Allmoves 0, Black, True
                IF Posmoves(0) <> 0 THEN
                    P = 0
                    Move = INT(RND(1) * Posmoves(0))
                    PutChecker Blacks(P).Pst, False, Blacks(P).King
                END IF
            LOOP UNTIL Posmoves(0) = 0
            Blacks(Piece).Pst = Blacks(0).Pst
            Blacks(Piece).King = Blacks(0).King
            PutChecker Blacks(Piece).Pst, False, Blacks(Piece).King
            IF NOT Blacks(Piece).King AND (INT(Blacks(Piece).Pst / 4) * 4) = 28 THEN
                Blacks(Piece).King = True
                PutChecker Blacks(Piece).Pst, False, True
            END IF
        END IF
    END IF
END SUB

'-----------------------------------------------------------------------------
'Deletes a black piece from piece array
'-----------------------------------------------------------------------------'
SUB DeleteBlack (P)
    FOR A = P + 1 TO NumBlacks
        Blacks(A - 1).Pst = Blacks(A).Pst
        Blacks(A - 1).King = Blacks(A).King
    NEXT
    NumBlacks = NumBlacks - 1
END SUB

'-----------------------------------------------------------------------------'
'Deletes a red piece from array
'-----------------------------------------------------------------------------'
SUB DeleteRed (P)
    FOR A = P + 1 TO NumReds
        Reds(A - 1).Pst = Reds(A).Pst
        Reds(A - 1).King = Reds(A).King
    NEXT
    NumReds = NumReds - 1
END SUB

'-----------------------------------------------------------------------------
'Draws checker board on screen
'-----------------------------------------------------------------------------
SUB DrawBord
    X = 0
    Z = 0
    FOR R = 16 TO 156 STEP 20
        FOR C = 48 TO 244 STEP 28
            LINE (C, R)-(C + 28, R + 20), 1, B
            IF X = 0 THEN
                PAINT (C + 1, R + 1), 2, 1
                X = 1
            ELSE
                X = 0
            END IF
        NEXT
        IF X = 0 THEN
            X = 1
        ELSE
            X = 0
        END IF
    NEXT
    X = 76
    W = 244
    Y = 16
    FOR Q = 0 TO 31
        Xy(Q).X = X
        Xy(Q).Y = Y
        X = X + 56
        IF X > W THEN
            Y = Y + 20
            IF Z = 0 THEN
                X = 48
                W = 216
                Z = 1
            ELSE
                Z = 0
                X = 76
                W = 244
            END IF
        END IF
    NEXT
END SUB

'-----------------------------------------------------------------------------'
'Erases(graphically) a piece off selected block
'-----------------------------------------------------------------------------'
SUB EraseChecker (P)
    X = Xy(P).X
    Y = Xy(P).Y
    LINE (X + 1, Y + 1)-(X + 27, Y + 19), 0, BF
END SUB

'-----------------------------------------------------------------------------'
'Gets a key from keyboard(turns to uppercase)
'-----------------------------------------------------------------------------'
FUNCTION Getkey$
    DO
        K$ = INKEY$
    LOOP UNTIL K$ <> ""
    Getkey$ = UCASE$(K$)
END FUNCTION

'-----------------------------------------------------------------------------'
'Handles humans move:
'Selects piece
'handles jumps and multiple jumps
'-----------------------------------------------------------------------------'
SUB HumansMove
    DO
        LOCATE 24, 14: PRINT "Select Piece";
        DO
            IF In THEN
                A = SelectPiece(-1)
            ELSE
                A = Joystick(-1)
            END IF
            IF K$ = "Q" OR K$ = "q" THEN CLS : END
            A = Scan(A)
            IF A <> Null THEN
                C1 = C
                Allmoves C1, Red, False
            END IF
        LOOP WHILE A = Null OR A <> Red OR Posmoves(C1) = 0
        LOCATE 24, 1: PRINT SPACE$(70);
        LOCATE 24, 16: PRINT "To Where?"
        DO
            IF In THEN
                A = SelectPiece(Reds(C1).Pst)
            ELSE
                A = Joystick(Reds(C1).Pst)
            END IF
            Found = False
            FOR R = 0 TO Posmoves(C1) - 1
                IF PosMap(C1, R) = A THEN
                    Found = True
                    EXIT FOR
                END IF
            NEXT
        LOOP UNTIL Found OR K$ = "T" OR K$ = "t"
    LOOP WHILE K$ = "T" OR K$ = "t"
    LOCATE 24, 1: PRINT SPACE$(70);
    EraseChecker Reds(C1).Pst
    Reds(C1).Pst = PosMap(C1, R)
    IF NOT Reds(C1).King AND (INT(Reds(C1).Pst / 4) * 4) = 0 THEN
        Reds(C1).King = True
    END IF
    PutChecker PosMap(C1, R), True, Reds(C1).King
   
    IF Typ(C1, R) = Jmp THEN
        EraseChecker M(C1, R)
        T = Scan(M(C1, R))
        DeleteBlack C: SOUND 1000, 4
        DO
            PutChecker Reds(C1).Pst, True, Reds(C1).King
            Allmoves C1, Red, True
            IF Posmoves(C1) <> 0 THEN
                LOCATE 24, 11: PRINT "Continue Your Jump";
                IF In THEN
                    A = SelectPiece(Reds(C1).Pst)
                ELSE
                    A = Joystick(Reds(C1).Pst)
                END IF
                Found = False
                FOR R1 = 0 TO Posmoves(C1) - 1
                    IF PosMap(C1, R1) = A THEN
                        Found = True
                        EXIT FOR
                    END IF
                NEXT
                IF Found THEN
                    EraseChecker Reds(C1).Pst
                    Reds(C1).Pst = A
                    IF NOT Reds(C1).King AND (INT(Reds(C1).Pst / 4) * 4) = 0 THEN
                        Reds(C1).King = True
                    END IF
                    EraseChecker M(C1, R1)
                    T = Scan(M(C1, R1))
                    DeleteBlack C: SOUND 1000, 4
                END IF
            END IF
        LOOP UNTIL NOT Found OR Posmoves(C1) = 0
        LOCATE 24, 1: PRINT SPACE$(70);
    END IF
    PutChecker Reds(C1).Pst, True, Reds(C1).King
    IF NOT Reds(C1).King AND (INT(Reds(C1).Pst / 4) * 4) = 0 THEN
        Reds(C1).King = True
        PutChecker Reds(C1).Pst, True, True
    END IF
END SUB

'-----------------------------------------------------------------------------'
'Calculates and stores all possible human moves
'-----------------------------------------------------------------------------'
SUB HumansMoves
    FOR A = 1 TO NumReds
        Allmoves A, Reds, False
    NEXT
    FOR A = 1 TO NumReds
        FOR B = 0 TO Posmoves(A) - 1
            PosMapR(A, B) = PosMap(A, B)
            TypR(A, B) = Typ(A, B)
            MR(A, B) = M(A, B)
        NEXT
        PosMovesR(A) = Posmoves(A)
    NEXT
END SUB

'simple increment function(cuts typing time for long vars)
FUNCTION Increment (A)
    Increment = A + 1
END FUNCTION

'-----------------------------------------------------------------------------'
'Calculates if block is on bottom row
'-----------------------------------------------------------------------------'
FUNCTION IsBottom (P)
    IF P > 27 THEN
        IsBottom = True
    ELSE
        IsBottom = False
    END IF
END FUNCTION

'-----------------------------------------------------------------------------'
'Sees if block is on the left most row
'-----------------------------------------------------------------------------'
FUNCTION IsLeft (P)
    SELECT CASE P
    CASE 4, 12, 20, 28
        IsLeft = True
    CASE ELSE
        IsLeft = False
    END SELECT
END FUNCTION

'-----------------------------------------------------------------------------'
'Sees if block is on the rightmost row
'-----------------------------------------------------------------------------'
FUNCTION IsRight (P)
    SELECT CASE P
    CASE 3, 11, 19, 27
        IsRight = True
    CASE ELSE
        IsRight = False
    END SELECT
END FUNCTION

'-----------------------------------------------------------------------------'
'Sees if block is on the uppermost row
'-----------------------------------------------------------------------------'
FUNCTION IsTop (P)
    IF P < 4 THEN
        IsTop = True
    ELSE
        IsTop = False
    END IF
END FUNCTION

'-----------------------------------------------------------------------------
'Joystick routine(auto calibrating)
'-----------------------------------------------------------------------------'
FUNCTION Joystick (Flash)
    STATIC HighestX, HighestY, FirstTime
    STATIC Al, Bl
    DIM Tstart AS SINGLE
    IF FirstTime = 0 THEN
        FirstTime = -1
        HighestX = 1
        HighestY = 1
    END IF


    IF Flash <> -1 THEN
        GET (Xy(Flash).X, Xy(Flash).Y)-(Xy(Flash).X + 28, Xy(Flash).Y + 20), Ag
        Tstart = TIMER: Switch = 0
    END IF
    DO
        New = True
        PUT (Al, Bl), Aa
        DO
            Ax = STICK(0): Bx = STICK(1)
            IF Ax > HighestX THEN
                HighestX = Ax
            END IF
            IF Bx > HighestY THEN
                HighestY = Bx
            END IF
            A2 = INT(Ax * (314 / HighestX))
            B2 = INT(Bx * (194 / HighestY))
            A2 = Al + (A2 - Al) / 12: B2 = Bl + (B2 - Bl) / 12
            IF New OR Al <> A2 OR Bl <> B2 THEN
                New = False
                PUT (Al, Bl), Aa
                PUT (A2, B2), Aa: Al = A2: Bl = B2
            END IF
            IF Flash <> -1 AND TIMER - Tstart > .3 THEN
                Switch = (Switch + 1) MOD 2
                PUT (Al, Bl), Aa
                IF Switch = 1 THEN
                    PUT (Xy(Flash).X + 1, Xy(Flash).Y + 1), Bg, PSET
                ELSE
                    PUT (Xy(Flash).X, Xy(Flash).Y), Ag, PSET
                END IF
                PUT (Al, Bl), Aa
                Tstart = TIMER
            END IF
            K$ = INKEY$
            Selected = Bttn
        LOOP UNTIL Selected OR K$ <> ""
        PUT (Al, Bl), Aa
        IF Flash <> -1 THEN
            PUT (Xy(Flash).X, Xy(Flash).Y), Ag, PSET
        END IF
        IF Selected AND Bl >= 16 AND Bl <= 176 AND Al >= 48 AND Al <= 272 THEN
            Am = Al - 48
            Bm = Bl - 16
            Am = INT(Am / 28) * 28
            Bm = INT(Bm / 20) * 20
            Am = Am + 48
            Bm = Bm + 16
            SOUND 200, 1
            FOR A = 0 TO 31
                IF Xy(A).X = Am AND Xy(A).Y = Bm THEN
                    Good = True
                    EXIT FOR
                ELSE
                    Good = False
                END IF
            NEXT
        END IF
    LOOP UNTIL Good OR K$ = "T" OR K$ = "t" OR K$ = "q" OR K$ = "Q" OR K$ = " " OR K$ = CHR$(13)
    IF Good THEN
        Joystick = A
    END IF
END FUNCTION

'-----------------------------------------------------------------------------'
'Given two blocks, this sub returns the only way a jump can
'be performed(the Middle block is the piece thats being jumped, the start
'block is the starting point, and the number returned is the ending point)
'-----------------------------------------------------------------------------'
FUNCTION JumpWay (Start, Middle)
    S = INT(Start / 4) * 4
    M = INT(Middle / 4) * 4
    IF (M AND 4) = 4 THEN
        IF S < M THEN
            IF ABS(Middle - Start) = 5 THEN
                JumpWay = Middle + 4
            ELSE
                JumpWay = Middle + 3
            END IF
        ELSE
            IF ABS(Start - Middle) = 4 THEN
                JumpWay = Middle - 5
            ELSE
                JumpWay = Middle - 4
            END IF
        END IF
    ELSE
        IF S < M THEN
            IF ABS(Middle - Start) = 3 THEN
                JumpWay = Middle + 4
            ELSE
                JumpWay = Middle + 5
            END IF
        ELSE
            IF ABS(Start - Middle) = 5 THEN
                JumpWay = Middle - 4
            ELSE
                JumpWay = Middle - 3
            END IF
        END IF
    END IF
END FUNCTION

'-----------------------------------------------------------------------------
'Looks at all of the pieces scores and find highest one. If there are two or
'more that have the same score, one at random is picked.
'-----------------------------------------------------------------------------'
SUB PickMove
    DIM Pick(60) AS M
    DIM Highest AS DOUBLE
    Picks = 0
    Highest = -32000
   
   
   
    FOR A = 1 TO NumBlacks
        FOR B = 0 TO Posmoves(A) - 1
            IF Pty(A, B) > Highest THEN
                Highest = Pty(A, B)
            END IF
        NEXT
    NEXT

   
    FOR A = 1 TO NumBlacks
        FOR B = 0 TO Posmoves(A) - 1
            IF Pty(A, B) = Highest THEN
                Pick(Picks).Pce = A
                Pick(Picks).Move = B
                Picks = Increment(Picks)
            END IF
        NEXT
    NEXT
    Rand = INT(RND(1) * Picks)
    Piece = Pick(Rand).Pce
    Move = Pick(Rand).Move
   
    FOR A = 1 TO 12
        IF Mem(A, Piece, Move) THEN
            Used(A) = Used(A) + 1
        ELSE
            NotUsed(A) = NotUsed(A) + 1
        END IF
    NEXT


END SUB

'-----------------------------------------------------------------------------'
'Prepare array of both players pieces
'-----------------------------------------------------------------------------'
SUB PreparePieces
    NumReds = 12
    NumBlacks = 12
   
    FOR A = 0 TO 11
        Blacks(A + 1).Pst = A
        Blacks(A + 1).King = Game
    NEXT
    FOR A = 20 TO 31
        Reds(A - 19).Pst = A
        Reds(A - 19).King = Game
    NEXT
END SUB

'-----------------------------------------------------------------------------'
'Puts a checker on the board(graphically)
'-----------------------------------------------------------------------------'
SUB PutChecker (P, Rd, King)
    X = Xy(P).X + 14
    Y = Xy(P).Y + 10
    CIRCLE (X, Y), 10, 1
    IF Rd THEN
        PAINT (X, Y), 2, 1
    END IF
    IF King THEN
        DRAW "C1BM" + STR$(X + 2) + "," + STR$(Y + 2) + "L8U6F4E2F2E4D6L8"
    END IF
END SUB

'-----------------------------------------------------------------------------'
'Tells if the position given contains a checker or not
'-----------------------------------------------------------------------------'
FUNCTION Scan (Position)
    FoundR = False
    FOR PN = 1 TO NumReds
        IF Reds(PN).Pst = Position THEN
            FoundR = True
            C = PN
            EXIT FOR
        END IF
    NEXT
    IF FoundR <> True THEN
        FoundB = False
        FOR PN = 1 TO NumBlacks
            IF Blacks(PN).Pst = Position THEN
                FoundB = True
                C = PN
                EXIT FOR
            END IF
        NEXT
    END IF
    IF FoundR THEN
        Scan = Red
    ELSEIF FoundB THEN
        Scan = Black
    ELSE
        Scan = Null
    END IF
END FUNCTION

'-----------------------------------------------------------------------------'
'Returns all surrounding blocks for a given piece in an array
'-----------------------------------------------------------------------------'
SUB ScanAround (Piece, C)
    SELECT CASE C
    CASE Red
        Position = Reds(Piece).Pst
    CASE Black
        Position = Blacks(Piece).Pst
    END SELECT
    TempNum = 0
    IF NOT IsTop(Position) THEN
        IF NOT IsLeft(Position) THEN
            TempPos(TempNum) = TopLeft(Position)
            TempNum = Increment(TempNum)
        END IF
        IF NOT IsRight(Position) THEN
            TempPos(TempNum) = TopRight(Position)
            TempNum = Increment(TempNum)
        END IF
    END IF
    IF NOT IsBottom(Position) THEN
        IF NOT IsLeft(Position) THEN
            TempPos(TempNum) = BottomLeft(Position)
            TempNum = Increment(TempNum)
        END IF
        IF NOT IsRight(Position) THEN
            TempPos(TempNum) = BottomRight(Position)
            TempNum = Increment(TempNum)
        END IF
    END IF
END SUB

'-----------------------------------------------------------------------------'
'Keyboard block select sub
'-----------------------------------------------------------------------------'
FUNCTION SelectPiece (Flash)
    STATIC LastChoice, FirstTime
    DIM Tstart AS SINGLE
    IF FirstTime = 0 THEN
        FirstTime = -1
        LastChoice = 22
    END IF

    IF Flash <> -1 THEN
        GET (Xy(Flash).X, Xy(Flash).Y)-(Xy(Flash).X + 28, Xy(Flash).Y + 20), Ag
        Tstart = TIMER: Switch = 0
    END IF
    DO
        X = Xy(LastChoice).X
        Y = Xy(LastChoice).Y
        DO
            LINE (X, Y)-(X + 28, Y + 20), 0, B
            IF Flash <> -1 AND TIMER - Tstart > .3 THEN
                Switch = (Switch + 1) MOD 2
                IF Switch = 1 THEN
                    PUT (Xy(Flash).X + 1, Xy(Flash).Y + 1), Bg, PSET
                ELSE
                    PUT (Xy(Flash).X, Xy(Flash).Y), Ag, PSET
                END IF
                Tstart = TIMER
            END IF
            LINE (X, Y)-(X + 28, Y + 20), 1, B
            K$ = INKEY$
        LOOP UNTIL K$ <> ""
        SELECT CASE ASC(RIGHT$(K$, 1))
        CASE 75
            LastChoice = LastChoice - 1
            IF LastChoice < 0 THEN
                LastChoice = 31
            END IF
        CASE 77
            LastChoice = LastChoice + 1
            IF LastChoice > 31 THEN
                LastChoice = 0
            END IF
        CASE 13, 32
            SelectPiece = LastChoice
        END SELECT
    LOOP UNTIL K$ = "T" OR K$ = "t" OR K$ = "q" OR K$ = "Q" OR K$ = " " OR K$ = CHR$(13)
    IF Flash <> -1 THEN
        PUT (Xy(Flash).X, Xy(Flash).Y), Ag, PSET
    END IF
END FUNCTION

'-----------------------------------------------------------------------------'
'Stores all possible computers moves in array
'-----------------------------------------------------------------------------'
SUB TestComputersMoves
    FOR A = 1 TO NumBlacks
        Allmoves A, Black, False
    NEXT
END SUB

'-----------------------------------------------------------------------------DEFINT A-Z
'Tells if block on the upper left of given block
'-----------------------------------------------------------------------------'
FUNCTION TopLeft (Position)
    First = INT(Position / 4) * 4
    IF (First AND 4) = 0 THEN
        TopLeft = Position - 4
    ELSE
        TopLeft = Position - 5
    END IF
END FUNCTION

'-----------------------------------------------------------------------------'
'Gives block on the lower right of given block
'-----------------------------------------------------------------------------'
FUNCTION TopRight (Position)
    First = INT(Position / 4) * 4
    IF (First AND 4) = 0 THEN
        TopRight = Position - 3
    ELSE
        TopRight = Position - 4
    END IF
END FUNCTION

'-----------------------------------------------------------------------------'
'Puts pieces on board graphically
'-----------------------------------------------------------------------------
SUB update
    FOR A = 0 TO 31
        EraseChecker A
    NEXT
    FOR A = 1 TO NumReds
        PutChecker Reds(A).Pst, True, Reds(A).King
    NEXT
    FOR A = 1 TO NumBlacks
        PutChecker Blacks(A).Pst, False, Blacks(A).King
    NEXT
END SUB
