'During his long sea voyages, Captain Cook was apparently often absent in the evenings and eventually
'the crew began to joke that he must have a mistress in his cabin. When they discovered that the Captain
'had simply been playing this game with the ship's scientists, the game was christened "The Captain's Mistress"
'Uses bitmaps for the board, iterative search deepening, alpha-beta pruning, and principal variation search.
'No positional evaluation is made at the leaves, it simply relies on search depth to find winning combinations.
'Search depth is about 10 to 12 with a 0.1 seconds time check (beginners level).
'The board looks like this using two orthogonal and two diagonal bitmaps for each color, and a bit is set for each
'piece at that location. This arrangement limits the number of (non-loop!)-tests for a connected quad to 13 or less.
' 1 2 4 8 16 32 64
' +---+---+---+---+---+---+---+
' | | | | o | | | | 32
' +---+---+---+---+---+---+---+
' | | | | o | | | | 16
' +---+---+---+---+---+---+---+
' | | | | o | | | | 8
' west-east --> +---+---+---+---+---+---+---+
' | | | | o | | | | 4
' +---+---+---+---+---+---+---+
' | | | | | | | | 2
' +---+---+---+---+---+---+---+
' | | | | | | | | 1
' +---+---+---+---+---+---+---+
' / ^ ^ ^ ^ ^ ^ ^ \
' / south-north \
' southwest-northeast southeast-northwest
'for example:
'The white quad shown above will show up in byte SNW(3) as b00111100 (d60) and can be tested with an appropriate AND-mask.
'Only those bitmaps are tested which were affected by the last move; this makes the search pretty fast.
'The Hint option shows the move which the computer has worked out for you during HER search, no search is made for YOU.
'+++++++++++++++++++++
' Development History
'+++++++++++++++++++++
'14Mar2009 - some speed improvements by eliminating duplicate calculations and using API functions for moving data
' and by arranging that moved data start at dword boundaries (7% improvement)
' the search has also been improved by altering the move ordering (16% improvement)
' eliminated a few dead variables
' taken care of different CPU clock frequencies and of running in IDE
'26Mar2009 - using GetTickCount instead of Timer
' some pimping up of the UI
' added balloon tooltips
' remove chip on click so you can't click twice
' changed timing control
' fixed bug with prediction and Draw detection
' changed chip dropping routine
' added flashing
' added quad marker
' added keyboard operation
' added TakeBack
' added Replay
' eliminated deadwood
Private Declare Function Beeper Lib "kernel32" Alias "Beep" (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long
Private Declare Sub CopyBoard Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, Optional ByVal Length As Long = 84)
Private Declare Sub CopyMoves Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, Optional ByVal Length As Long = 28)
Private Declare Function GetClassLong Lib "user32" Alias "GetClassLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As tPoint) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Declare Function InflateRect Lib "user32" (lpRect As tRECT, ByVal X As Long, ByVal Y As Long) As Long
Private Declare Sub InitCommonControls Lib "comctl32" () 'a manifest file, if present, may influence the popup balloons
Private Declare Function MessageBeep Lib "user32" (ByVal wType As VbMsgBoxStyle) As Long
Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Long
Private Declare Function Rectangle Lib "gdi32" (ByVal hDC As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function ReleaseCapture Lib "user32" () As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function SetClassLong Lib "user32" Alias "SetClassLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function SetCursorPos Lib "user32" (ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function SetRect Lib "user32" (lpRect As tRECT, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Type tPoint
X As Long
Y As Long
End Type
Private CP As tPoint 'cursor position
Private Type tRECT
LT As tPoint 'top left
RB As tPoint 'bot rite
End Type
Private WindowRect As tRECT 'for drawing the frame
'+++++++++++++++++
'The Board
'+++++++++++++++++
Private Type tBoard 'is moved rather frequently - so it is kept as short as possible (84 bytes)
Filled(0 To 6) As Byte 'column fill
SNW(0 To 6) As Byte 'south -> north white
SNB(0 To 6) As Byte 'south -> north black
WEW(0 To 5) As Byte 'east -> west white
WEB(0 To 5) As Byte 'east -> west black
SwNeW(-3 To 8) As Byte 'south-west -> north-east white
SwNeB(-3 To 8) As Byte 'south-west -> north-east black
SeNwW(-3 To 8) As Byte 'south-east -> north-west white
SeNwB(-3 To 8) As Byte 'south-east -> north-west black
SideToMove As Byte
Extra1 As Byte 'bring it up to 84 bytes so it will hopefully use dword moves only
Extra2 As Byte
End Type
Private Board As tBoard 'the board bitmaps
Private OrdMovs(0 To 6) As Long
Private Enum eConsts
Infinity = 99999 'value outside normal range
DepthLimit = 30 'max ply searchable
HTCAPTION = 2 'API
WM_NCLBUTTONDOWN = 161 'API
CS_DROPSHADOW = &H20000 'API
GCL_STYLE = -26 'API
OneStep = 795 'displayed board raster pitch in twips
TwoSteps = OneStep * 2
ThreeSteps = TwoSteps + OneStep
FourSteps = TwoSteps * 2
FiveSteps = FourSteps + OneStep
End Enum
#If False Then ':) Line inserted by Formatter
Private Infinity, DepthLimit, HTCAPTION, WM_NCLBUTTONDOWN, CS_DROPSHADOW, GCL_STYLE, OneStep, TwoSteps, ThreeSteps, FourSteps, FiveSteps ':) Line inserted by Formatter
#End If ':) Line inserted by Formatter
Private PV(0 To DepthLimit, _
0 To DepthLimit) As Long 'Principal Variation
Private TimeElapsed As Single 'during CPU speed assessment
Private HSCFreq As Currency
Private TenMicrosecs As Currency 'HscCount for 10 ╡secs
Private Result As Long 'The Search Result
Private Posns As Long '# of nodes in search tree visited
Private Cutoffs As Long '# of cutoffs
Private TimeStart As Long
Private TimeUp As Long 'in millisecs
Private IterDepth As Long 'controls iterative deepening
Private IndexW As Long 'controls the white drop-chips
Private IndexB As Long 'same for black
Private Origin As tPoint 'top left corner of matrix
Private Half As Long 'half width of chip image
Private CurrColumn As Long 'the current position of the mouse cursor
Private Tooltip As cTooltip
Private LastCtl As Control
Private InPV As Boolean 'true if search is in PV
Private SearchInProgress As Boolean 'what it says
Private Replay As Boolean 'true when replaying
Private Const White As Byte = 1 'black is 0
Private Const Signature As String = "TCM"
Private Sub btExit_Click()
Unload Me
End Sub
Private Sub btExit_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
CreateTooltip btExit
End Sub
Private Sub btReset_Click()
Dim i As Long
Dim j As Long
With Board
For i = 0 To 5 'reset the board
.SNW(i) = 0
.SNB(i) = 0
.WEW(i) = 0
.WEB(i) = 0
.SwNeB(i) = 0
.SwNeW(i) = 0
.SeNwB(i) = 0
.SeNwW(i) = 0
.Filled(i) = 0
imgWhite(i).Visible = True
imgBlack(i).Visible = False
Next i
.SNW(i) = 0 'one more for horizontal
.SNB(i) = 0
.Filled(i) = 0
lnQuad.Visible = False
imgWhite(i).Visible = True
imgBlack(i).Visible = False
lbHint.Enabled = True
lbTakeBack.Enabled = True
For i = 1 To 21
imgDropW(i).Visible = False
imgDropB(i).Visible = False
Next i
.SideToMove = White
End With 'BOARD
For i = 0 To DepthLimit
For j = 0 To DepthLimit
PV(i, j) = -1
Next j, i
lbWins.ForeColor = vbBlack
IndexW = 0
IndexB = 0
lbWins = vbNullString
imgSmile.Visible = False
lbWinIn = vbNullString
CurrColumn = 2
Form_KeyDown vbKeyRight, 0
pic.SetFocus
End Sub
Private Sub btReset_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
CreateTooltip btReset
End Sub
Private Function CheckForQuad(ByVal Bits As Long) As Boolean
CheckForQuad = ((Bits And 15) = 15) Or ((Bits And 30) = 30) Or ((Bits And 60) = 60)
If CheckForQuad Then
RemoveButtons
End If
End Function
Private Function CheckSeNwB(Board As tBoard, ByVal Which As Long) As Boolean
CheckSeNwB = CheckForQuad(Board.SeNwB(Which))
End Function
Private Function CheckSeNwW(Board As tBoard, ByVal Which As Long) As Boolean
CheckSeNwW = CheckForQuad(Board.SeNwW(Which))
End Function
Private Function CheckSNB(Board As tBoard, ByVal Which As Long) As Boolean
CheckSNB = CheckForQuad(Board.SNB(Which))
End Function
Private Function CheckSNW(Board As tBoard, ByVal Which As Long) As Boolean
CheckSNW = CheckForQuad(Board.SNW(Which))
End Function
Private Function CheckSwNeB(Board As tBoard, ByVal Which As Long) As Boolean
CheckSwNeB = CheckForQuad(Board.SwNeB(Which))
End Function
Private Function CheckSwNeW(Board As tBoard, ByVal Which As Long) As Boolean
CheckSwNeW = CheckForQuad(Board.SwNeW(Which))
End Function
Private Function CheckWEB(Board As tBoard, ByVal Which As Long) As Boolean
Dim Bits As Long
Bits = Board.WEB(Which)
CheckWEB = CheckForQuad(Bits) Or (Bits And 120) = 120 'one extra check because WE has 7 bits
If CheckWEB Then
RemoveButtons
End If
End Function
Private Function CheckWEW(Board As tBoard, ByVal Which As Long) As Boolean
Dim Bits As Long
Bits = Board.WEW(Which)
CheckWEW = CheckForQuad(Bits) Or (Bits And 120) = 120 'one extra check because WE has 7 bits
d looks lihLi)1ierline 'iiifil oEEE00000iiii FolarB(i) =S"k y)e12wwNeWWWWWhhhhyiiiE -- eyVal Y As 1S"kcElwBpihLis=o
Index hhhOidth ethro'Y As 1!kethrougdex hh boaOARDii con = "fConnece
Index ii con =) AsAe2 = 690sAe2 = 690sAe2 =wAs Long) As tPoi
Privam,earc4e Sub
Priv = U GetTickC h boaOARDii coTickC h boaOARDii 3aying Level"
Top = 4170
ickC h boaOARDii 3aying LeveBac4hhhhyiiiniert
Picture = "fConnectFour.frx":128E5
Top bx":128E5
Top 20"fConnec"
Top = 4170
nByte TBegin(n)iiE 20":o--+-,X/ Top 20"fConnec"
Top = 4170
nByte TBegin(n)iiE 20":o--+-,X/cRRR TVch As Long= = 615
End
Begin VB.Ima0iiiiiiii5
EnfiEEEE0hhhhhOop!)0'terDo5
End
Begin VB.Ima0ii | 'BOin VB.Ima0n( nnectua3'terDo5
End
Beas Boolean Lon l in VB.Ima0ii | 'BOin VB.ImVB.Ima0n( nnectua3'terDot
ma0nDo5
EDo5
EDo5
ED EE0iiiis
3'te =) AsAe2 = 690sAe2 = 690sAe2 k()eSize = 8.25
EndProperty
gin R = 693'te =) ((Bits nep = 4170
rDeimit = 30 'max ply searchable
HTCAPTION = 2 'API
WM = lAG 'API
WM Ae2 s ne,.frx":317B
ToB 4170
rDeimit = 30 made fori = &H000ce fori = 0
re 3'te = 3317B.frx":Otn)ii For = ity,╡
reor e sear e Ty )- | St = 0 'False
(nd 15) = 15) Or ((Bits And 30) = 30) Or ((Bits ACv-jl
'rc 5aaaaaaaae$e =) AsAe2
ED e St = jnd Function
Ty )- | wpClseo2boaOARDii 3aying LeveBac4 H3G d 15=G Left = 3990
MouseIcon = "fConnectAsAe,ME990 = 3990
.SideToMove = White
( nne 0 For = Eit = 30 made fo = Eit = 30 made fo G (ess =ins
.SideToMove0
MouseIcfo = TyVal ( 'top left
RB = nss =in(ess =ins
=Nd10
Picture 2c t dword boundar 2ras Long) As Boolean
rd b6
RRRRxxxxxo,tion CCCCC Size b(t
.SeNwB(i) = g
Sub
.SeNwB(i) = g
Sub
.Sb6
RRRRxxxxxo,tion e St =W0 t dwotFour' ( 'top r3dwFreq ateTooltip btExit
E
SSSSl2-BOARDlruo--+-,EEEt_STYec6Sl2-BOARDa7) = 15) Or ((Bits An(ess =ins
=Nd10
the search ws =inEEEt_r eacrogrW 6 9.75"ltTeF=Nd10
g) As Bor>bEs "SetClwyte d FB(i) = g
S Picturp
gA" (oDi Borr>bEs " Dim i Sear4
White el,wB s Picture 2c t dword boundar 2ras Long) As Boolean
rd b6
RRRRxxx Wnl TyVal ( 'top leaLim(e elo9.75"ltTeF=Nd10leftB s Picture
'False
Italic = 0 'False
6Na 'Fsdded TimeOio1 | LonsitureE ProtyD 6NmeOio1 |a7) = 15) t black r>bEs "5
4Whit = "Bdword boundy If c6Sl2-dth B9 r>bE"e0ef5
TimeUp'Fa
Ls79,(Bits And wordu0s Bor>bEs "SetClw4
White el,wB s Picture 2c t dword boundar R TVch As Long= = 615
End
s79,(Bits Aong= = 615
End
s
WM = lAGMectua3'terDo5
(( 're 2c t dword boundarrtt t dwooMove0
Mot End
Begin VB.Label DaEewsgbtAs Strine0
Mot Er)8isA WM ve0
ooMove0
Mot E0
ot dwooMove0
E
SSS dword bounda615
End
Beg4 Lonv
Top wotFBorr(ess= 30etClw4
White fnd wordonv
Top d 15) =ove0bel DaE St "fConnectFoiiiipthLim$ amits And wordu0s Bor>bEs "SetC- 20":o--+-,X/cRR Mous 0s Bor>bEsEr)8i,tf | St =0":o--+-,X/cRR Mous 0s Bor>bEsEr)8i,tf | H amits And worduiiiiiiiSt =0":o--+-,X/cRR
MC py26 CheckSwNeB =t =0"EEt_STYec6Sl2-BOARDa7) = 15t)Vin. vf 30 made fePoi1
MC py26 CheckSwNeB =t .e wh6=2 =0"EEt_STYecnd
r =0 MC py26 CheckSwNeB =t EEEEo4f c6Sl2-dth B9 'Zentrier) = g
Sub
.Sb6G8dexB = 0
lbWins = heckSwNeB =t EEEEo4f ndar R TV
lbWiWN, CS_DROPSHADOW,
ThreeSt As Lon SWiWN, CS_DROPSHAD.Sb6G8dexB Top 20"fConnec"
Top m(t0peclar e sear tAs Stri imor i s = heckSwNeB =t EEEEo4f ndar exB = 0EW = Che
tinity, Deptresaeoi 20"r has worked out for youge, |int 9vatresa Compufsu a2ircE0keev
E
tinity,Brlc u hs2iiiiiiin lnpn c=ccUrByVal nIndex As Long) As Long
Priv/cR = 2
a Functi" As SinOio1 |-0l Threeiiiiiiiiiiiiiiiiiii" eivamc Mocre oardcccccc&"
g
te Declare uatVarig =5)D /ie2ircE0kEXe-ardc'As ts-kSrile-ardc'=5)DDDDDDD o r-0l on = Declare urd boundar 2raing..aE Dzerdefi30) 9Declare-ardc'As ts-kSrile-ardc'ck eclaOrBy20"r hre-ardccM5>lare uaD= lschi
X M5>l | LonsitureE Protec4e Sub
6y,╡v re for holt ompufsu t.WEB(Which=ity, Infiva1)iE-+-YYYYYYYYiva1)iE-+-YYYSub
6yC
the search ws tWins YYYiva1)iE ':iaebBt. vf 30 made fePoi1 32.dllctu':iaIde fePoi1 c=ccU EPic=ccU)dar 2 As Long
Private TimeUp Orltg s SE/0 As Long
Pr = CAE 2= lAGM2e crew began to joke that he "x>
Pr = CAE 2= l
' AE eclaOr8 2= lAGMectua3's 5a
'Val nId5- imgBrM2e Ro3's h of cf Tir-0l oecl3's Wins = hecR0' the20"r hre-ardccM5>laSE/0ong))+++++++++hecl3's Wins = hecR0' the20"1"nlias "Beep of cf Tir-0l oecl3's Wi-d whi | | n -+--ae i joke Raaaaaaaaaa
WM Agan to joke that heivarthe20"r hre-ardccM5>laSE/0ong))+++++++++hecl3's Wins = hecR0' the20"1"nlias "Beep of cf Tir-0l'top left.|eep of cf Tir-0l'top left.|eep of cf Tir-0l'top lciS'top left.|eep Acf Tir-0l'top lciS'top leftC0earcEccM5>laSE/0ong))++++++++ s Long
Dim
X |1iva)esult tjciS'top leftC0earcEccM5>laSE/0ong))++++++++ s Long
Dim
X |1iva)esult tjciS'top leftC0earcEccM5>laSE/0ong))++++++++ ngle)
v++ d5 Pr 9vatresa Coma2ivatresa Compsa Coma2ivatresa Compsa Coma2ivatrtC0ear iva)ee> EPic re foR = a CAE 2= l
' AE ecla1^ctiocture =(Which)
CheckWEB (Which)
Che0erM Agan to jok For i = 1 To 21
Ba Compsa Coma2ivat To 21
Bang))++++++g=wsR1iv.rice
' v joke Raaaaaach(Board, Xing =
v++ ws Cci am AsY = FAL Cordc'As ts-fsu t.WEB(Which=ity, Infivaesa i = Orlt eean
eoByVal M5>l gin R ioAnd IterDte ieRtuaCAE Coml FivaeaCAE Coml FivaeaCAE CeRtu = lAGMectua 6 2c > Iter,Er 0 Integer,,,,,,,,,,,,,L( Thr1 | Lo)>le)iE Ping. o Lonpf cfL per,,,,,,, AsY = FA g
BPrivate C'ter
' or 6 A nISE/*Private C'ter
' or 6 A nISE/*Private C'ter
' or 6 A n Pi0BFtCheckSwNeB(BoarANvPi0BFtCheckSwNeB(BoarANDi((((((S=8te C'ter gin R ioAnd IterDte ieRtuaCAE Coml FivaeaCAE Coml F0earcEccM5>laSE/0ong))++++tlAGMectua 6 2c >icreol
n QueryPerformanceCou"****3's Wins = hecR0' the2m"6(| ts-fsu t.NarANvPi0BFtCheckSw$nceCou"***'s WiCouvcEccM5>l"oma2 690 2c u"****3's Wins = hecR0' sufsuaaSE/0ong))l 6 A nISEa
2 CoreF=Nd1 r 0&"""""""""""""""1nAso)+npfb0 """""""""1nAso)+npfRRRRR.=B .lo -+-YYa5(2?t o(, X As 5) Or ie" b -+-YYa5(2?R ' Compsa Coma2iva(ong, ByVal nIndlNCjpDC
4=2>ggg6) As String =re ++++++ 6 tevate CP hufs 1!kRmn"fCo'rw=b=,arc(se
oAI=el DaMm AsY = FALSWSrd, jitureE Pa el DaMThM =,"ckSwNer)8iLong hufs 1!kRng =l DaMs . ++ ten. 6 Uggggg6*3'tEms =2>ggg6))+++AgLBUTTONDOWN = 161 ++ite t r gin 8tEms 3ufsu*3'tEms =1s 5) Or E'l0EPa el DsY =_7+LmgEEEEE . ++ ten. 6 Ui7AnouCAE zerdefi30) Orl om" =I= ('hhhh' hn =i=Nd10, ByVal u a2ircE0keev
EAicE0keev
EAicE0keev
EAicE0keev
EAicE0keev
EAicE0keev
EAicE0keev
EAicE0keev
EAicE0keev
EcE0keevNvkeevtep = 795 'displayed board raster pitch in twips
TwoSteps = OneStep * 2
ThreeStes Log A8Vv clare madAXppppAe2mn =iW", |int=ove0bel DaEa2P .=B .lo B o, |int".so)+AGMMMMM .=B 0 IndeC.=B .lo l B o, |in o, |int".so)+AGMMMMM .=i +npfb=wici +npfb=wici +npfb=wal ue(i):=
ore ',es L it A im Sso)+AGMMMMM .=i +npfb=wic)+AGMMMMM .=i +npfb=wic)+AGM7-BOARDa7) = 15t)Vin. vf 30 made fePoi1
A&H u s+d g) As=sFagoggg eSi Y)r 9 Thr+++ Forir-0l'toDr Integer, X nIndl+Lpo M))795 Y)w rTiCm X |1iva)esult l,r )f0 nne,DhR
P 3aying Le"'oggg eSi Y)r 9 Thr+++ Forir-0l'toDr I ScrerLpo M))795 Y)w fCo VB.Immmmmmmmmmmmm Y)w fCo V M))795 Y)w rTiC ir-0l'toDr I ScrerLpor )fce 9a0
oundarp tedk al
T'
2zer c0R2h++++++++++++Sre search deepening
t d7ahor XbEmmmmi p) As (+++ h
EA
E P( Long s -ggg eSwr M5>As 5) Or Aoooooooooooooooooooooo3G fCo ng hufs 1!kRng =l c0R2h+++++++++++ veU aap1xiompuoooo3G EE00000iiii FolarB(i) =S | "eim i Y)w fCo V M))',rt
e',rt
e'- ted 3 xxivate Cy,) ,Ls+ite ,BA6 =a l2-B+ 1).l As Lo (+, WMRn2iIce 9,(B(nd = Shth = ScrerchInr-0l Threeivnectits
If aco(h = As Lo (+, WMRn2iIce 9,(B(nd = Shoooooooo 15)(+, WMRn2iIce 9,(B(nd = Shoooooooo 15)(+, WMRn2iIce 9,(B(nd = Shoooooooo 15)(+, WMRn2iIts
If MRn2iIce 9,(B(n 2iv3 sBggg6*3 ce 9 | | - g) As +AsFagoggg6*3eWag e'o lgM'oSiAch))