Международные шашки

Великолепный исходник 100 клеточных шашек. Программа имеет довольно неплохой AI . Вся графика выполнена средствами FbGfx. Управление мышью.

Платформы: Windows, Linux
Автор: badidea

checkers.png

' Autor: badidea
'-----------------------------------------------

'Option Explicit
'Option Byval
'OPTION DYNAMIC

#DEFINE CLEARCOLORS 0
#DEFINE MAX_MOVES 128
#DEFINE MAX_DEPTH 16
#DEFINE MAX_SEARCH_DEPTH 7
#DEFINE HIT_SEARCH_DEPTH 12

Type moveType
    x As Integer
    y As Integer
End Type

Type boardType
    occupied As Integer '0=empty, 1=black, 2=white
    discType As Integer '0=normal piece, 1=king
    tileType As Integer '0=brown/black, 1=yellow/white
End Type

Type boardPtrType
    board(9,9) As boardType
End Type

Type bufferType
    board(9,9) As boardType
    dummyMoveSeq(MAX_DEPTH-1) As moveType
    msl(MAX_MOVES-1,MAX_DEPTH-1) As moveType
    mdl(MAX_MOVES-1) As Integer
End Type

Declare Sub showIntro()
Declare Function intrnd(limit As Integer) As Integer
Declare Function xScreen(x As Integer) As Integer
Declare Function yScreen(y As Integer) As Integer
Declare Function getTileColour(pTile As moveType, inverted As Integer) As Integer
Declare Function getMousePos(MouseX As Integer, MouseY As Integer, Byref pTile As moveType) As Integer
Declare Sub drawTile(x As Integer, y As Integer, colour As Integer)
Declare Sub drawTileBorder(x As Integer, y As Integer, colour As Integer)
Declare Sub initBoardArray(bPtr As boardType Ptr)
Declare Sub initBoardRandom(bPtr As boardType Ptr)
Declare Sub drawBoard(bPtr As boardType Ptr)
Declare Sub showActiveColour(activeColour As Integer)
Declare Sub findForcedMoves(Byref moveCtr As Integer, Byref maxDepth As Integer,_
depth As Integer, hitColour As Integer, discType As Integer, bPtr As boardType Ptr,_
mdlPtr As Integer Ptr, mslPtr As moveType Ptr, cmsPtr As moveType Ptr)
Declare Sub findNormalMoves(Byref moveCtr As Integer, hitColour As Integer,_
bPtr As boardType Ptr, mdlPtr As Integer Ptr, mslPtr As moveType Ptr,_
cmsPtr As moveType Ptr)
Declare Sub showMoves(numMoves As Integer, colour As Integer,_
mdlPtr As Integer Ptr, mslPtr As moveType Ptr)
Declare Sub showSingleMove(moveNum As Integer, colour As Integer,_
mdlPtr As Integer Ptr, mslPtr As moveType Ptr)
Declare Sub doMove(p0 As moveType, p1 As moveType, bPtr As boardType Ptr)
Declare Sub doFullMove(localMoveSeq As moveType Ptr, localDepth As Integer,_
bPtr As boardType Ptr, animate As Integer)
Declare Function filterHitMoves(numMoves As Integer, maxDepth As Integer,_
bPtr As boardType Ptr, mdlPtr As Integer Ptr, mslPtr As moveType Ptr) As Integer
Declare Sub createMoveList(Byref moveCtr As Integer, Byref maxDepth As Integer,_
turnColour As Integer, bPtr As boardType Ptr, mdlPtr As Integer Ptr, mslPtr As moveType Ptr)
Declare Sub createHitList(Byref moveCtr As Integer, Byref maxDepth As Integer,_
turnColour As Integer, bPtr As boardType Ptr, mdlPtr As Integer Ptr, mslPtr As moveType Ptr)
Declare Function searchMove(p0 As moveType, p1 As moveType, moveDepth As Integer,_
moveCtr As Integer, mdlPtr As Integer Ptr, mslPtr As moveType Ptr) As Integer
Declare Function evalBoard(bPtr As boardType Ptr, turnColour As Integer) As Integer
Declare Sub copyBoard(bSrcPtr As boardType Ptr, bDstPtr As boardType Ptr)
Declare Sub saveBoard(bPtr As boardType Ptr)
Declare Sub loadBoard(bPtr As boardType Ptr)
Declare Function enemyColour(colour As Integer) As Integer
Declare Function findBestMove(bPtr As boardType Ptr, moveColour As Integer,_
evalColour As Integer, mdlPtr As Integer Ptr, mslPtr As moveType Ptr,_
searchDepth As Integer) As Integer


Const xOffset = 180 'horizontal offset board, centre of 1st tile
Const yOffset = 50 'vertical offset board, centre of 1st tile
Const rTile = 27 'tile radius, including borders
Const dTile = rTile*2
Const rDisc = 23 'disc radius, including borders

Const pressed = 1, released = -1, idle = 0
Const true = 1, false = 0
Const isEmpty = 0, isBlack = 1, isWhite = 2
Const isPiece = 0, isKing = 1
Const LMB = 1, RMB = 2, MMB = 4
Const isBrown = 0, isYellow = 1
Const isComputer = 0, isHuman = 1
Const noAnimate = 0, doAnimate = 1

#IF (CLEARCOLORS = 1)
Const cBlack = 0, cDarkBlue = 1, cGreen = 6, cBlue = 3
Const cRed = 4, cPurple = 5, cBrown = 2, cLightGrey = 7
Const cDarkGrey = 8, cXBlue = 9, cLightGreen = 10, cLightBlue = 11
Const cLightRed = 12, cLightPurple = 13, cYellow = 14, cWhite = 15
#ELSE
Const cBlack = 0, cDarkBlue = 1, cGreen = 2, cBlue = 3
Const cRed = 4, cPurple = 5, cBrown = 6, cLightGrey = 7
Const cDarkGrey = 8, cXBlue = 9, cLightGreen = 10, cLightBlue = 11
Const cLightRed = 12, cLightPurple = 13, cYellow = 14, cWhite = 15
#ENDIF

Dim As boardType board(9,9), tempBoard(9,9)
Dim As moveType moveSeqList(MAX_MOVES-1,MAX_DEPTH-1) 'move sequence list
Dim As moveType bestMoveSeq(MAX_DEPTH-1)
Dim As moveType p0, p1, pOld, pCur0, pCur1
Dim As Integer moveDepthList(MAX_MOVES-1)
Dim As Integer bestMoveDepth
Dim As Integer i, j, x, y 'Free to use
Dim As Integer MouseX, MouseY, mouseWheel, mouseButtons
Dim As Integer lmbChange, lmbStat, lmbPrev
Dim As Integer rmbChange, rmbStat, rmbPrev
Dim As Integer mmbChange, mmbStat, mmbPrev
Dim As Integer startSet, stopSet, forcedHit
Dim As Integer turnColour, moveCtr, moveDone, allowMove
Dim As Integer moveDepth, maxDepth, moveNum, player(3-1)
Dim As Integer evalScore, evalColour
Dim As Integer moveScore, bestScore, nBestScores, score(MAX_MOVES-1)
Dim As String keyString

'-----------------------------------------------

Dim Shared As bufferType global(HIT_SEARCH_DEPTH)
Dim Shared As Integer endOfGame, startTime
Dim Shared As Integer maxSearchDepth, hitSearchDepth
maxSearchDepth = MAX_SEARCH_DEPTH
hitSearchDepth = HIT_SEARCH_DEPTH

'-----------------------------------------------

maxDepth = 1
moveDepth = 0
endOfGame = 0
moveDone = 0
player(isBlack) = isComputer
player(isWhite) = isHuman
turnColour = isWhite 'wit begint
moveCtr=-1

Screen 19

initBoardArray(@board(0,0))
showIntro
Color cLightGrey, cDarkGrey
startTime = Timer
Randomize startTime
drawBoard(@board(0,0))
showActiveColour(turnColour)

Do
    If player(turnColour) = isHuman Then

        Getmouse MouseX, MouseY, mouseWheel, mouseButtons

        lmbPrev = lmbStat
        If ((mouseButtons And LMB) = LMB) And (mouseButtons <> -1) Then lmbStat = 1 Else lmbStat = 0
        lmbChange = lmbStat - lmbPrev '+1=pressed, -1=released

        rmbPrev = rmbStat
        If ((mouseButtons And RMB) = RMB) And (mouseButtons <> -1) Then rmbStat = 1 Else rmbStat = 0
        rmbChange = rmbStat - rmbPrev '+1=pressed, -1=released

        mmbPrev = mmbStat
        If ((mouseButtons And MMB) = MMB) And (mouseButtons <> -1) Then mmbStat = 1 Else mmbStat = 0
        mmbChange = mmbStat - mmbPrev '+1=pressed, -1=released

        If (lmbChange = idle) And (rmbChange = idle) And (mmbChange = idle) Then
            Sleep 10 'Do not stress CPU, when doing nothing
        End If

        If (keyString = "s") Then
            saveBoard(@board(0,0)) 'save to board.bin
            drawBoard(@board(0,0))
        End If

        If (keyString = "o") Then
            loadBoard(@board(0,0)) 'open from board.bin
            drawBoard(@board(0,0))
        End If

        If (rmbChange = pressed) Then '(debug)
            'show allowed moves
            If (moveDepth = 0) Then
                createMoveList(moveCtr,maxDepth,turnColour,@board(0,0),@moveDepthList(0),@moveSeqList(0,0))
            End If
            showMoves(moveCtr,cLightGreen,@moveDepthList(0),@moveSeqList(0,0))
        End If

        If (rmbChange = released) Then '(debug)
            drawBoard(@board(0,0)) 'clear help lines
            showActiveColour(turnColour)
        End If

        If (lmbChange = pressed) Then
            startSet = getMousePos(MouseX, MouseY, p0)
        End If

        'Show mouse position
        If (lmbStat = 1) Then
            getMousePos(MouseX, MouseY, pCur0)
            If (pCur0.x<>pCur1.x) Or (pCur0.y<>pCur1.y) Then
                drawTileBorder(pCur0.x, pCur0.y, getTileColour(pCur0,1))
                drawTileBorder(pCur1.x, pCur1.y, getTileColour(pCur1,0))
                pCur1 = pCur0
            End If
        End If

        If (lmbChange = released) Then
            stopSet = getMousePos(MouseX, MouseY, p1)
        End If

        If (lmbChange = released) And (startSet = 1) And (stopSet = 1) Then
            'New move/turn? Make new list.
            If (moveDepth = 0) Then
                createMoveList(moveCtr,maxDepth,turnColour,@board(0,0),@moveDepthList(0),@moveSeqList(0,0))
                pOld=p0 'clear old end positions
            End If

            allowMove = searchMove(p0, p1, moveDepth, moveCtr, @moveDepthList(0), @moveSeqList(0,0))
            If (allowMove) And (pOld.x=p0.x) And (pOld.y=p0.y) Then
                doMove(p0,p1,@board(0,0)) 'Do partial move from sequence
                drawBoard(@board(0,0))
                moveDepth+=1
                pOld=p1
            Else
                showActiveColour(-1) 'error
                showActiveColour(turnColour)
            End If
        End If

        If (moveDepth >= maxDepth) Then
            If (p1.y=0) And (board(p1.x,p1.y).occupied=isWhite) Then board(p1.x,p1.y).discType = isKing
            If (p1.y=9) And (board(p1.x,p1.y).occupied=isBlack) Then board(p1.x,p1.y).discType = isKing
            moveDone = 1
            moveDepth = 0 'reset
        End If

        If (moveCtr = 0) Then endOfGame = 1

    Else 'player = isComputer

        moveScore = findBestMove(@board(0,0), turnColour, turnColour, @bestMoveDepth, @bestMoveSeq(0), 0)
        If (endOfGame <> 1) Then
            Locate 8,2: Print "Best:";moveScore\10;" ";
            doFullMove(@bestMoveSeq(0), bestMoveDepth, @board(0,0), doAnimate)
        Endif
        moveDone = 1

    End If

    If (moveDone = 1) Then
        moveDone = 0
        drawBoard(@board(0,0)) 'Draw whenever we do or try to do a move
        turnColour = enemyColour(turnColour)
        showActiveColour(turnColour)
    End If

    keyString = Inkey$
Loop While (keyString <> Chr$(27)) And (endOfGame = 0)

'-----------------------------------------------

Color cWhite, cBlack
Locate 19,44: Print "End of Game!";
Locate 21,40: Print "Random seed was:";StartTime
Sleep 1000
While (Inkey$ <> Chr$(27)): Wend
End 0

'-----------------------------------------------

Sub showIntro
    Dim As Integer scrWidth, scrHeight
    Dim As Integer PlayerLevel

    Locate 12,35: Print " Checkers game by BadIdea";
    Locate 13,35: Print "    with 'Dutch' rules";
    Sleep 200
    Locate 15,35: Print " Version 1.8 / 25 May 2007";
    Locate 16,35: Print " very_bad_idea@hotmail.com";
    Sleep 200
    Locate 18,35: Print " <Escape> to exit program!";
    Sleep 200

    While ((PlayerLevel < 2) Or (PlayerLevel > 6))
        Locate 25,35: Print "                              "
        Locate 25,35: Input "   Dificulty (2...6): ", PlayerLevel
    Wend
    maxSearchDepth = PlayerLevel
    hitSearchDepth = PlayerLevel*2-1

    'draw dark grey window background
    Screeninfo scrWidth, scrHeight
    Line (0, 0)-(scrWidth-1, scrHeight-1), cDarkGrey, BF
End Sub

'-----------------------------------------------

Function intrnd(limit As Integer) As Integer
    Return Int(Rnd*limit)
End Function

'-----------------------------------------------

Function xScreen(x As Integer) As Integer
    Return x * dTile + xOffset
End Function

'-----------------------------------------------

Function yScreen(y As Integer) As Integer
    Return y * dTile + yOffset
End Function

'-----------------------------------------------

Function getTileColour(pTile As moveType, inverted As Integer) As Integer
    'Strange code, but works
    If (((pTile.x+pTile.y) And 1) = inverted) Then
        Return cYellow
    Else
        Return cBrown
    End If
End Function

'-----------------------------------------------

Function getMousePos(MouseX As Integer, MouseY As Integer, Byref pTile As moveType) As Integer
    Dim validPos As Integer
    validPos = 0
    If (MouseX > xOffset - rTile And MouseX < xOffset + rTile * 19) Then
        If (MouseY > yOffset - rTile And MouseY < yOffset + rTile * 19) Then
            pTile.x = (MouseX - xOffset + rTile) \ (dTile)
            pTile.y = (MouseY - yOffset + rTile) \ (dTile)
            validPos = 1
        End If
    End If
    Return validPos
End Function

'-----------------------------------------------

Sub drawTile(x As Integer, y As Integer, colour As Integer)
    Dim sz As Integer 'sz = size to edge, half of square tile
    sz = rTile - 1
    Line (xScreen(x)-sz, yScreen(y)-sz)-(xScreen(x)+sz, yScreen(y)+sz), colour, BF
End Sub

'-----------------------------------------------

Sub drawTileBorder(x As Integer, y As Integer, colour As Integer)
    'for debugging
    Dim As Integer sz1, sz2 'sz = size to edge, half of square tile
    sz1 = rTile - 1
    sz2 = rTile - 2
    Line (xScreen(x)-sz1, yScreen(y)-sz1)-(xScreen(x)+sz1, yScreen(y)+sz1), colour, B
    Line (xScreen(x)-sz2, yScreen(y)-sz2)-(xScreen(x)+sz2, yScreen(y)+sz2), colour, B
End Sub

'-----------------------------------------------

Sub initBoardArray(bPtr As boardType Ptr)
    'Initiate: board().tileType & board().occupied
    Dim As Integer x, y
    For y = 0 To 9
        For x = 0 To 9
            If ((y+x) And 1) Then
                bPtr[x*10+y].tileType = isBrown
                If (y<4) Then
                    bPtr[x*10+y].occupied = isBlack
                    bPtr[x*10+y].discType = isPiece
                Elseif (y>5) Then
                    bPtr[x*10+y].occupied = isWhite
                    bPtr[x*10+y].discType = isPiece
                Else
                    bPtr[x*10+y].occupied = isEmpty
                End If
            Else
                bPtr[x*10+y].tileType = isYellow
            End If
        Next
    Next
End Sub

'-----------------------------------------------

Sub initBoardRandom(bPtr As boardType Ptr)
    'Initiate: board().tileType & board().occupied
    Dim As Integer x, y

    For y = 0 To 9
        For x = 0 To 9
            If ((y+x) And 1) Then
                bPtr[x*10+y].tileType = isBrown
                If Int(Rnd(1) * 10) > 7 Then
                    If Int(Rnd(1) * 2) = 1 Then
                        bPtr[x*10+y].discType = isPiece
                    Else
                        'bPtr[x*10+y].discType = isKing
                    End If
                    If Int(Rnd(1) * 2) = 1 Then
                        bPtr[x*10+y].occupied = isBlack
                    Else
                        bPtr[x*10+y].occupied = isWhite
                    End If
                Else
                    bPtr[x*10+y].occupied = isEmpty
                End If
            Else
                bPtr[x*10+y].tileType = isYellow
            End If
        Next
    Next

End Sub

'-----------------------------------------------

Sub drawBoard(bPtr As boardType Ptr)
    Dim As Integer x, y, colour, edge
    Dim As Integer whiteCtr, blackCtr
    Dim As Integer whiteKingCtr, blackKingCtr
    Dim As Integer discHeight, discYoffset, discXoffset
    'XXX Theoretical bug! No king if no pieces hit

    'draw light grey board background
    edge = rTile + 1
    Line (xScreen(0)-edge, yScreen(0)-edge)-(xScreen(9)+edge, yScreen(9)+edge), cLightGrey, BF

    'draw square tiles & discs
    For y = 0 To 9
        For x = 0 To 9
            If (bPtr[x*10+y].tileType = isYellow) Then
                drawTile(x,y,cYellow)
            Else
                drawTile(x,y,cBrown)
                If (bPtr[x*10+y].occupied = isWhite) Then
                    Circle (xScreen(x),yScreen(y)),rDisc,8,,,,f      'white disc
                    Circle (xScreen(x),yScreen(y)),rDisc-1,15,,,,f   'white disc border
                    If (bPtr[x*10+y].discType = isKing) Then
                        Circle (xScreen(x),yScreen(y)),rDisc-8,7,,,,f    'white disc king!
                        whiteKingCtr+=1
                    End If
                    whiteCtr+=1
                Elseif (bPtr[x*10+y].occupied = isBlack) Then
                    Circle (xScreen(x),yScreen(y)),rDisc,7,,,,f      'black disc
                    Circle (xScreen(x),yScreen(y)),rDisc-1,0,,,,f    'black disc border
                    If (bPtr[x*10+y].discType = isKing) Then
                        Circle (xScreen(x),yScreen(y)),rDisc-8,8,,,,f    'black disc king!
                        blackKingCtr+=1
                    End If
                    blackCtr+=1
                Else
                    'Empty square
                End If
            End If
        Next
    Next

    discHeight = 12
    discYoffset = 550
    discXoffset = 20
    For y = 0 To 19-(whiteCtr+whiteKingCtr)
        Line (discXoffset, discYoffset-y*(discHeight+1))-Step(rDisc*2, discHeight), cBlack, b
        Line (discXoffset+1, discYoffset-y*(discHeight+1)+1)-Step(rDisc*2-2, discHeight-2), cWhite, bf
    Next
    Line (discXoffset, discYoffset-y*(discHeight+1))-Step(rDisc*2, discHeight), cDarkGrey, bf

    discXoffset = 80
    For y = 0 To 19-(blackCtr+blackKingCtr)
        Line (discXoffset, discYoffset-y*(discHeight+1))-Step(rDisc*2, discHeight), cLightGrey, b
        Line (discXoffset+1, discYoffset-y*(discHeight+1)+1)-Step(rDisc*2-2, discHeight-2), cBlack, bf
    Next
    Line (discXoffset, discYoffset-y*(discHeight+1))-Step(rDisc*2, discHeight), cDarkGrey, bf


    Locate 2,2: Print "Black:";blackCtr;" ";
    Locate 3,2: Print "White:";whiteCtr;" ";
    Locate 5,2: Print "Time:";Int(Timer)-startTime;" ";
    Locate 6,2: Print "Eval:";evalBoard(bPtr, isWhite)\10;" ";

    If (blackCtr = 0) Or (whiteCtr = 0) Then endOfGame = 1
End Sub

'-----------------------------------------------

Sub showActiveColour(activeColour As Integer)
    Dim As Integer scrWidth, scrHeight
    Screeninfo scrWidth, scrHeight
    If (activeColour=isWhite) Then
        Circle (scrWidth-50,scrHeight\2),rDisc,8,,,,f
        Circle (scrWidth-50,scrHeight\2),rDisc-1,15,,,,f
    Elseif (activeColour=isBlack) Then
        Circle (scrWidth-50,scrHeight\2),rDisc,7,,,,f
        Circle (scrWidth-50,scrHeight\2),rDisc-1,0,,,,f
    Else 'unknown color
        Circle (scrWidth-50,scrHeight\2),rDisc,cRed,,,,f
        Circle (scrWidth-50,scrHeight\2),rDisc-1,cLightRed,,,,f
        Sleep 250
    End If
End Sub

'-----------------------------------------------

Sub showMoves(numMoves As Integer, colour As Integer,_
    mdlPtr As Integer Ptr, mslPtr As moveType Ptr)

    Dim As Integer i
    For i = 0 To numMoves-1
        showSingleMove(i,colour,mdlPtr,mslPtr)
    Next
End Sub

'-----------------------------------------------

Sub showSingleMove(moveNum As Integer, colour As Integer,_
    mdlPtr As Integer Ptr, mslPtr As moveType Ptr)

    Dim As Integer i, j, pitch
    Dim As moveType p0, p1
    i = moveNum
    pitch = i * MAX_DEPTH
    For j = 0 To mdlPtr[i]-1
        'Lines between steps
        p0 = mslPtr[pitch+j]
        p1 = mslPtr[pitch+j+1]
        Line(xScreen(p0.x)-1, yScreen(p0.y))-(xScreen(p1.x)-1, yScreen(p1.y)),colour
        Line(xScreen(p0.x), yScreen(p0.y))-(xScreen(p1.x), yScreen(p1.y)),colour
        Line(xScreen(p0.x)+1, yScreen(p0.y))-(xScreen(p1.x)+1, yScreen(p1.y)),colour
    Next
    drawTileBorder(mslPtr[pitch+j].x, mslPtr[pitch+j].y, colour)
End Sub

'-----------------------------------------------

Sub doMove(p0 As moveType, p1 As moveType, bPtr As boardType Ptr)
    Dim As Integer x, y, xSign, ySign
    'do move
    bPtr[p1.x*10+p1.y].occupied = bPtr[p0.x*10+p0.y].occupied
    bPtr[p1.x*10+p1.y].discType = bPtr[p0.x*10+p0.y].discType
    bPtr[p0.x*10+p0.y].occupied = isEmpty
    'Remove all discs between x0,y0 and x1,y1; Works for kings as well
    If Abs(p1.x-p0.x) > 1 Then 'not a normal move?
        xSign = Sgn(p1.x-p0.x)
        ySign = Sgn(p1.y-p0.y)
        y = p0.y + ySign
        For x = p0.x+xSign To p1.x-xSign Step xSign
            bPtr[x*10+y].occupied = isEmpty
            y+=ySign
        Next
    End If
End Sub

'-----------------------------------------------

Sub doFullMove(localMoveSeq As moveType Ptr, localDepth As Integer,_
    bPtr As boardType Ptr, animate As Integer)

    Dim As Integer i
    Dim As moveType p0, p1

    For i = 0 To localDepth-1
        p0 = localMoveSeq[i]
        p1 = localMoveSeq[i+1]
        If (animate = doAnimate) Then
            showSingleMove(0,cGreen,@localDepth,localMoveSeq)
            Sleep 750
            doMove(p0, p1, bPtr) 'deel v/d move
            drawBoard(bPtr)
            Sleep 250
        Else
            doMove(p0, p1, bPtr) 'deel v/d move
        End If
    Next
    If (p1.y=0) And (bPtr[p1.x*10+p1.y].occupied=isWhite) Then bPtr[p1.x*10+p1.y].discType = isKing
    If (p1.y=9) And (bPtr[p1.x*10+p1.y].occupied=isBlack) Then bPtr[p1.x*10+p1.y].discType = isKing
End Sub

'-----------------------------------------------

Function filterHitMoves(numMoves As Integer, maxDepth As Integer,_
    bPtr As boardType Ptr, mdlPtr As Integer Ptr, mslPtr As moveType Ptr) As Integer

    Dim As Integer i,j,k
    Dim kingFound As Integer
    j = 0
    'Filter to get highest depths
    For i = 0 To numMoves-1
        If (mdlPtr[i] = maxDepth) Then
            If (i<>j) Then 'Equal? copy is nonsense
                mdlPtr[j] = mdlPtr[i]
                For k = 0 To maxDepth
                    mslPtr[j*MAX_DEPTH+k] = mslPtr[i*MAX_DEPTH+k]
                Next
            End If
            j+=1
        End If
    Next
    'King present in hit-list?
    numMoves = j-1
    kingFound = 0
    For i = 0 To numMoves
        If bPtr[mslPtr[i*MAX_DEPTH+0].x * 10 + mslPtr[i*MAX_DEPTH+0].y].discType = isKing Then
            kingFound = 1
            Exit For
        End If
    Next
    'Filter to get king moves
    If (kingFound = 1) Then
        j = 0
        For i = 0 To numMoves
            If bPtr[mslPtr[i*MAX_DEPTH+0].x * 10 + mslPtr[i*MAX_DEPTH+0].y].discType = isKing Then
                If (i<>j) Then 'Equal? copy is nonsense
                    mdlPtr[j] = mdlPtr[i]
                    For k = 0 To maxDepth
                        mslPtr[j*MAX_DEPTH+k] = mslPtr[i*MAX_DEPTH+k]
                    Next
                End If
                j+=1
            End If
        Next
    End If

    Return j
End Function

'-----------------------------------------------

Sub createMoveList(Byref moveCtr As Integer, Byref maxDepth As Integer,_
    turnColour As Integer, bPtr As boardType Ptr, mdlPtr As Integer Ptr, mslPtr As moveType Ptr)

    'Prioriteit:
    ' 1. Meerslag gaat voor
    ' 2. Damslag gaat voor
    ' 3. Slag gaat voor

    'createMoveList:
    ' 1. findForcedMoves (recursive function)
    ' 2. findNormalMoves
    ' 3. filterHitMoves

    Dim As Integer x, y, xs
    Dim As Integer hitColour, hitForced, discType
    Dim As moveType curMoveSeq(MAX_DEPTH-1) 'current move sequence
    Dim cmsPtr As moveType Ptr

    moveCtr = 0
    maxDepth = 0
    hitForced = 1
    cmsPtr = @curMoveSeq(0)
    hitColour = enemyColour(turnColour)

    'search for forced moves
    For y = 0 To 9
        If (y And 1) Then xs = 0 Else xs = 1 'skip yellow squares
        For x = xs To 9 Step 2
            If bPtr[x*10+y].occupied = turnColour Then
                cmsPtr[0].x = x 'start position disc
                cmsPtr[0].y = y 'start position disc
                discType = bPtr[x*10+y].discType
                findForcedMoves(moveCtr, maxDepth, 0, hitColour, discType, bPtr, mdlPtr, mslPtr, cmsPtr)
            End If
        Next
    Next

    'no forced moves found, now find normal moves
    If (moveCtr = 0) Then
        hitForced = 0
        maxDepth = 1
        For y = 0 To 9
            If (y And 1) Then xs = 0 Else xs = 1 'skip yellow squares
            For x = xs To 9 Step 2
                If bPtr[x*10+y].occupied = turnColour Then
                    cmsPtr[0].x = x 'start position disc
                    cmsPtr[0].y = y 'start position disc
                    findNormalMoves(moveCtr, hitColour, bPtr, mdlPtr, mslPtr, cmsPtr)
                End If
            Next
        Next
    End If

    If (hitForced = 1) Then
        moveCtr = filterHitMoves(moveCtr, maxDepth, bPtr, mdlPtr, mslPtr)
    End If

End Sub

'-----------------------------------------------

Sub createHitList(Byref moveCtr As Integer, Byref maxDepth As Integer,_
    turnColour As Integer, bPtr As boardType Ptr, mdlPtr As Integer Ptr, mslPtr As moveType Ptr)

    Dim As Integer x, y, xs
    Dim As Integer hitColour, discType
    Dim As moveType curMoveSeq(MAX_DEPTH-1) 'current move sequence
    Dim cmsPtr As moveType Ptr

    moveCtr = 0
    maxDepth = 0
    cmsPtr = @curMoveSeq(0)
    hitColour = enemyColour(turnColour)

    'search for forced moves
    For y = 0 To 9
        If (y And 1) Then xs = 0 Else xs = 1 'skip yellow squares
        For x = xs To 9 Step 2
            If bPtr[x*10+y].occupied = turnColour Then
                cmsPtr[0].x = x 'start position disc
                cmsPtr[0].y = y 'start position disc
                discType = bPtr[x*10+y].discType
                findForcedMoves(moveCtr, maxDepth, 0, hitColour, discType, bPtr, mdlPtr, mslPtr, cmsPtr)
            End If
        Next
    Next

End Sub

'-----------------------------------------------

Sub findForcedMoves(Byref moveCtr As Integer, Byref maxDepth As Integer,_
    depth As Integer, hitColour As Integer, discType As Integer, bPtr As boardType Ptr,_
    mdlPtr As Integer Ptr, mslPtr As moveType Ptr, cmsPtr As moveType Ptr)
    'Todo: change xCur, yCur to curPos.x, curPos.y, etc.

    Dim As moveType pCur, pHit, pNew 'current, hit & new position
    Dim As Integer xi, yi, i, enemyFound
    Static As Integer boardHit(9,9)

    pCur = cmsPtr[depth]
    'if (depth=0) then erase boardHit
    depth+=1

    If discType = isPiece Then

        For xi = -1 To +1 Step 2
            For yi = -1 To +1 Step 2
                pHit.x = pCur.x - xi
                pHit.y = pCur.y - yi
                pNew.x = pCur.x - xi*2
                pNew.y = pCur.y - yi*2:
                If (pNew.x<10) And (pNew.x>=0) And (pNew.y>=0) And (pNew.y<10) Then
                    If (bPtr[pNew.x*10+pNew.y].occupied=isEmpty) Then
                        If bPtr[pHit.x*10+pHit.y].occupied=hitColour And boardHit(pHit.x,pHit.y)=0 Then
                            If depth > maxDepth Then maxDepth = depth 'one level deeper
                            cmsPtr[depth] = pNew
                            mdlPtr[moveCtr] = depth
                            For i = 0 To depth
                                mslPtr[moveCtr*MAX_DEPTH+i] = cmsPtr[i] 'store current move sequence
                            Next
                            moveCtr+=1
                            boardHit(pHit.x,pHit.y)=1 'mark jumped
                            findForcedMoves(moveCtr, maxDepth, depth, hitColour, discType, bPtr, mdlPtr, mslPtr, cmsPtr)
                            boardHit(pHit.x,pHit.y)=0 'unmark jumped
                        End If
                    End If
                End If
            Next
        Next

    Elseif discType = isKing Then

        For xi = -1 To +1 Step 2
            For yi = -1 To +1 Step 2
                pNew.x = pCur.x + xi
                pNew.y = pCur.y + yi
                enemyFound = 0

                'look for enemy
                While (pNew.x<10) And (pNew.x>=0) And (pNew.y>=0) And (pNew.y<10)
                    If (bPtr[pNew.x*10+pNew.y].occupied <> isEmpty) Then 'white or black
                        If (bPtr[pNew.x*10+pNew.y].occupied = hitColour) And (boardHit(pNew.x,pNew.y) = 0) Then
                            enemyFound = 1
                            pHit = pNew
                        End If
                        Exit While
                    End If
                    pNew.x += xi
                    pNew.y += yi
                Wend

                'look for empty places after enemy
                If (enemyFound = 1) Then
                    pNew.x += xi
                    pNew.y += yi
                    While (pNew.x<10) And (pNew.x>=0) And (pNew.y>=0) And (pNew.y<10)
                        If (bPtr[pNew.x*10+pNew.y].occupied = isEmpty) Then

                            If depth > maxDepth Then maxDepth = depth 'one level deeper
                            cmsPtr[depth] = pNew
                            mdlPtr[moveCtr] = depth
                            For i = 0 To depth
                                mslPtr[moveCtr*MAX_DEPTH+i] = cmsPtr[i] 'store current move sequence
                            Next
                            moveCtr+=1
                            boardHit(pHit.x,pHit.y)=1 'mark jumped
                            findForcedMoves(moveCtr, maxDepth, depth, hitColour, discType, bPtr, mdlPtr, mslPtr, cmsPtr)
                            boardHit(pHit.x,pHit.y)=0 'unmark jumped

                        Else
                            Exit While
                        End If
                        pNew.x += xi
                        pNew.y += yi
                    Wend
                End If

            Next
        Next

    Else
        Print "Error: findForcedMoves": Sleep 100
    End If

    depth-=1
End Sub

'-----------------------------------------------

Sub findNormalMoves(Byref moveCtr As Integer, hitColour As Integer,_
    bPtr As boardType Ptr, mdlPtr As Integer Ptr, mslPtr As moveType Ptr,_
    cmsPtr As moveType Ptr)

    'Todo: change xCur, yCur to curPos.x, curPos.y, etc.
    Dim As moveType pCur, pNew  'current & new position
    Dim As Integer xi, yi, i, pitch  'move increment

    pCur = cmsPtr[0]
    'Deze twee Piece/King kunnen (in principe) samen gevoegd worden.
    If bPtr[pCur.x*10+pCur.y].discType = isPiece Then
        If hitColour = isBlack Then yi = +1
        If hitColour = isWhite Then yi = -1
        For xi = -1 To +1 Step 2
            pNew.x = pCur.x-xi
            pNew.y = pCur.y-yi
            If (pNew.x<10) And (pNew.x>=0) And (pNew.y>=0) And (pNew.y<10) Then
                If (bPtr[pNew.x*10+pNew.y].occupied=isEmpty) Then
                    mdlPtr[moveCtr] = 1
                    pitch = moveCtr * MAX_DEPTH
                    mslPtr[pitch] = pCur
                    mslPtr[pitch+1] = pNew
                    moveCtr+=1
                End If
            End If
        Next
    Elseif bPtr[pCur.x*10+pCur.y].discType = isKing Then
        For xi = -1 To +1 Step 2
            For yi = -1 To +1 Step 2
                pNew.x = pCur.x + xi
                pNew.y = pCur.y + yi
                While (pNew.x<10) And (pNew.x>=0) And (pNew.y>=0) And (pNew.y<10)
                    If (bPtr[pNew.x*10+pNew.y].occupied = isEmpty) Then
                        mdlPtr[moveCtr] = 1
                        pitch = moveCtr * MAX_DEPTH
                        mslPtr[pitch] = pCur
                        mslPtr[pitch+1] = pNew
                        moveCtr+=1
                    Else
                        Exit While 'Oject encountered
                    End If
                    pNew.x += xi
                    pNew.y += yi
                Wend
            Next
        Next
    Else
        Print "Error: findNormalMoves": Sleep 100
    End If

End Sub

'-----------------------------------------------

Function searchMove(p0 As moveType, p1 As moveType, moveDepth As Integer,_
    moveCtr As Integer, mdlPtr As Integer Ptr, mslPtr As moveType Ptr) As Integer

    Dim As Integer i, moveFound, pitch
    moveFound = 0
    'Search for move in list: moveFound
    For i = 0 To moveCtr-1
        pitch = i * MAX_DEPTH
        If mdlPtr[i] > moveDepth Then
            'May this disc (x0,y0) move to (x1,y1) ?
            If p0.x = mslPtr[pitch+moveDepth].x And p0.y = mslPtr[pitch+moveDepth].y Then
                If p1.x = mslPtr[pitch+moveDepth+1].x And p1.y = mslPtr[pitch+moveDepth+1].y Then
                    moveFound = 1
                    Exit For
                End If
            End If
        End If
    Next
    Return moveFound
End Function

'-----------------------------------------------

Function evalBoard(bPtr As boardType Ptr, turnColour As Integer) As Integer
    Dim As Integer x, y, xs, score, hitColour
    Dim As Integer moveCtr, maxDepth

    hitColour = enemyColour(turnColour)
    score = intrnd(19)-9 'Choice between: -9...+9
    ' if bPtr[x*10+y].occupied = turnColour then
    '  cmsPtr[0].x = x 'start position disc
    '  cmsPtr[0].y = y 'start position disc
    '  discType = bPtr[x*10+y].discType
    '  findForcedMoves(moveCtr, maxDepth, 0, hitColour, discType, bPtr, mdlPtr, mslPtr, cmsPtr)
    ' end if

    For y = 0 To 9
        If (y And 1) Then xs = 0 Else xs = 10 'skip yellow squares
        For x = xs To 90 Step 20
            If bPtr[x+y].occupied = turnColour Then
                If bPtr[x+y].discType = isPiece Then
                    score+=30
                    If (x=0) Or (x=90) Or (y=0) Or (y=9) Then score+=10
                Else
                    score+=70
                    If (y=9) And (turnColour=isWhite) Then score+=10
                    If (y=0) And (turnColour=isBlack) Then score+=10
                End If
            Elseif bPtr[x+y].occupied = hitColour Then
                If bPtr[x+y].discType = isPiece Then
                    score-=30
                    If (x=0) Or (x=90) Or (y=0) Or (y=9) Then score-=10
                Else
                    score-=70
                    If (y=0) And (hitColour=isWhite) Then score-=10
                    If (y=9) And (hitColour=isBlack) Then score-=10
                End If
            Else
                'empty
            End If
        Next
    Next

    Return score
End Function

'-----------------------------------------------

Sub copyBoard(bSrcPtr As boardType Ptr, bDstPtr As boardType Ptr)
    'Quick and dirty!
    Dim As boardPtrType Ptr scrPtr, dstPtr
    scrPtr = Cptr(boardPtrType Ptr, bSrcPtr)
    dstPtr = Cptr(boardPtrType Ptr, bDstPtr)
    *dstPtr = *scrPtr
End Sub

'-----------------------------------------------

Sub saveBoard(bPtr As boardType Ptr)
    Dim As Integer filePtr
    Dim As boardPtrType Ptr bufferPtr
    bufferPtr = Cptr(boardPtrType Ptr, bPtr)
    filePtr = Freefile
    Open "board.bin" For Binary As #filePtr
    Put #filePtr, , bufferPtr[0]
    Close #filePtr
    Locate 20,41: Print "board --> board.bin";
    Sleep 500
End Sub

'-----------------------------------------------

Sub loadBoard(bPtr As boardType Ptr)
    Dim As Integer filePtr
    Dim As Byte Ptr bufferPtr
    bufferPtr = Cptr(Byte Ptr, bPtr)
    filePtr = Freefile
    Open "board.bin" For Binary As #filePtr
    Get #filePtr, ,bufferPtr[0], Sizeof(boardPtrType)
    Close #filePtr
End Sub

'-----------------------------------------------

Function enemyColour(colour As Integer) As Integer
    If colour = isWhite Then
        Return isBlack
    Elseif colour = isBlack Then
        Return isWhite
    Else
        Return -1
    End If
End Function

'-----------------------------------------------

Function findBestMove(bPtr As boardType Ptr, moveColour As Integer,_
    evalColour As Integer, mdlPtr As Integer Ptr, mslPtr As moveType Ptr,_
    searchDepth As Integer) As Integer

    Dim As boardType Ptr tempBoardPtr
    Dim As moveType Ptr tempMslPtr
    Dim As moveType Ptr dummyMsPtr
    Dim As Integer Ptr tempMdlPtr
    Dim As Integer dummyMoveDepth, DummyMaxDepth
    Dim As Integer bestMoveScore, bestMoveIndex, moveScore
    Dim As Integer i, moveCtr, hitColour

    hitColour = enemyColour(moveColour)
    searchDepth+=1
    tempMdlPtr = @global(searchDepth).mdl(0)
    tempMslPtr = @global(searchDepth).msl(0,0)
    tempBoardPtr = @global(searchDepth).board(0,0)
    dummyMsPtr = @global(searchDepth).dummyMoveSeq(0)

    If (searchDepth > maxSearchDepth And searchDepth <= hitSearchDepth) Then
        createHitList(moveCtr, dummyMoveDepth, moveColour, bPtr, tempMdlPtr, tempMslPtr)
    End If

    If ((searchDepth <= maxSearchDepth) Or (moveCtr<>0)) Then

        If ((searchDepth And 1) = 1) Then bestMoveScore = -999 Else bestMoveScore = 999
        bestMoveIndex = -1
        createMoveList(moveCtr, dummyMoveDepth, moveColour, bPtr, tempMdlPtr, tempMslPtr)

        If (moveCtr <> 0) Then

            For i = 0 To moveCtr-1

                copyBoard(bPtr, tempBoardPtr)
                doFullMove(tempMslPtr+i*MAX_DEPTH, tempMdlPtr[i], tempBoardPtr, noAnimate)
                moveScore = findBestMove(tempBoardPtr, hitColour, evalColour, @dummyMoveDepth, dummyMsPtr, searchDepth)

                If ((searchDepth And 1) = 1) Then 'even
                    If (moveScore > bestMoveScore) Then
                        bestMoveScore = moveScore
                        bestMoveIndex = i
                    End If
                Else
                    If (moveScore < bestMoveScore) Then
                        bestMoveScore = moveScore
                        bestMoveIndex = i
                    End If
                End If

                If (searchDepth = 1) Then
                    If (i < moveCtr-1) Then
                        Locate 37,2: Print Using "Searching: ## % ";(i*100)\(moveCtr-1);
                    Else
                        Locate 37,2: Print "Searching: Ready";
                    End If
                End If

            Next
            *mdlPtr = tempMdlPtr[bestMoveIndex]
            For i = 0 To *mdlPtr
                mslPtr[i] = tempMslPtr[bestMoveIndex*MAX_DEPTH+i]
            Next

        Else

            If (moveColour = evalColour) Then
                If (searchDepth = 1) Then
                    endOfGame = 1 'no move to start with...
                Else
                    bestMoveScore = -900 'E.g.: white plays & white can not move: bad thing
                End If
            Else
                bestMoveScore = +900 'E.g.: white plays & black can not move: good thing
            End If

        End If

    Else
        bestMoveScore = evalBoard(bPtr, evalColour)
    End If

    Return bestMoveScore
End Function

'-----------------------------------------------