home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / xreversi / xreversi.frm (.txt) < prev    next >
Encoding:
Visual Basic Form  |  1995-12-10  |  29.3 KB  |  908 lines

  1. VERSION 2.00
  2. Begin Form XReversi 
  3.    BackColor       =   &H0000FF00&
  4.    Caption         =   "Extended Reversi"
  5.    ClientHeight    =   3960
  6.    ClientLeft      =   1470
  7.    ClientTop       =   1845
  8.    ClientWidth     =   7425
  9.    Height          =   4650
  10.    Icon            =   XREVERSI.FRX:0000
  11.    Left            =   1410
  12.    LinkMode        =   1  'Source
  13.    LinkTopic       =   "Form1"
  14.    ScaleHeight     =   3960
  15.    ScaleWidth      =   7425
  16.    Top             =   1215
  17.    Width           =   7545
  18.    Begin CommandButton buttonHumanForfeit 
  19.       Caption         =   "Forfeit Move"
  20.       Height          =   495
  21.       Left            =   5760
  22.       TabIndex        =   7
  23.       Top             =   2160
  24.       Width           =   1215
  25.    End
  26.    Begin CommandButton buttonComputerMove 
  27.       Caption         =   "Make Move"
  28.       Height          =   495
  29.       Left            =   4200
  30.       TabIndex        =   6
  31.       Top             =   2160
  32.       Width           =   1215
  33.    End
  34.    Begin PictureBox MoveMsg 
  35.       BackColor       =   &H00FFFF00&
  36.       Height          =   975
  37.       Left            =   3960
  38.       ScaleHeight     =   945
  39.       ScaleWidth      =   3225
  40.       TabIndex        =   8
  41.       Top             =   960
  42.       Width           =   3255
  43.    End
  44.    Begin PictureBox Board 
  45.       BackColor       =   &H000000FF&
  46.       Height          =   3680
  47.       Left            =   120
  48.       MousePointer    =   2  'Cross
  49.       ScaleHeight     =   3645
  50.       ScaleWidth      =   3645
  51.       TabIndex        =   0
  52.       Top             =   120
  53.       Width           =   3680
  54.    End
  55.    Begin Label HumanScore 
  56.       BorderStyle     =   1  'Fixed Single
  57.       Caption         =   "   0"
  58.       FontBold        =   -1  'True
  59.       FontItalic      =   0   'False
  60.       FontName        =   "MS Sans Serif"
  61.       FontSize        =   24
  62.       FontStrikethru  =   0   'False
  63.       FontUnderline   =   0   'False
  64.       Height          =   615
  65.       Left            =   5760
  66.       TabIndex        =   1
  67.       Top             =   3120
  68.       Width           =   1215
  69.    End
  70.    Begin Label ComputerScore 
  71.       BorderStyle     =   1  'Fixed Single
  72.       Caption         =   "   0"
  73.       FontBold        =   -1  'True
  74.       FontItalic      =   0   'False
  75.       FontName        =   "MS Sans Serif"
  76.       FontSize        =   24
  77.       FontStrikethru  =   0   'False
  78.       FontUnderline   =   0   'False
  79.       Height          =   615
  80.       Left            =   4200
  81.       TabIndex        =   2
  82.       Top             =   3120
  83.       Width           =   1215
  84.    End
  85.    Begin Label Label2 
  86.       BackColor       =   &H0000FF00&
  87.       Caption         =   "Human"
  88.       FontBold        =   -1  'True
  89.       FontItalic      =   0   'False
  90.       FontName        =   "MS Sans Serif"
  91.       FontSize        =   12
  92.       FontStrikethru  =   0   'False
  93.       FontUnderline   =   0   'False
  94.       Height          =   375
  95.       Left            =   5880
  96.       TabIndex        =   5
  97.       Top             =   2760
  98.       Width           =   855
  99.    End
  100.    Begin Label Label1 
  101.       BackColor       =   &H0000FF00&
  102.       Caption         =   "Computer"
  103.       FontBold        =   -1  'True
  104.       FontItalic      =   0   'False
  105.       FontName        =   "MS Sans Serif"
  106.       FontSize        =   12
  107.       FontStrikethru  =   0   'False
  108.       FontUnderline   =   0   'False
  109.       Height          =   375
  110.       Left            =   4200
  111.       TabIndex        =   4
  112.       Top             =   2760
  113.       Width           =   1215
  114.    End
  115.    Begin Label FeedbackMsg 
  116.       BackColor       =   &H0000FFFF&
  117.       BorderStyle     =   1  'Fixed Single
  118.       Caption         =   " "
  119.       FontBold        =   -1  'True
  120.       FontItalic      =   0   'False
  121.       FontName        =   "MS Sans Serif"
  122.       FontSize        =   9.75
  123.       FontStrikethru  =   0   'False
  124.       FontUnderline   =   0   'False
  125.       Height          =   615
  126.       Left            =   3960
  127.       TabIndex        =   3
  128.       Top             =   120
  129.       Width           =   3255
  130.    End
  131.    Begin Menu menuGame 
  132.       Caption         =   "&Game"
  133.       Begin Menu menubarNewGame 
  134.          Caption         =   "&New Game"
  135.       End
  136.       Begin Menu menusepG1 
  137.          Caption         =   "-"
  138.       End
  139.       Begin Menu menubarModern 
  140.          Caption         =   "&Modern Opening"
  141.       End
  142.       Begin Menu menubarRandom 
  143.          Caption         =   "&Random Opening"
  144.       End
  145.       Begin Menu menusepG2 
  146.          Caption         =   "-"
  147.       End
  148.       Begin Menu menubar8x8 
  149.          Caption         =   "&8 x 8 Board"
  150.       End
  151.       Begin Menu menubar10x10 
  152.          Caption         =   "&10 x 10 Boad"
  153.       End
  154.       Begin Menu menubar16x16 
  155.          Caption         =   "1&6 x 16 Board"
  156.       End
  157.       Begin Menu menubar20x20 
  158.          Caption         =   "&20 x 20 Board"
  159.       End
  160.       Begin Menu menusepG3 
  161.          Caption         =   "-"
  162.       End
  163.       Begin Menu menubarQuit 
  164.          Caption         =   "&Quit"
  165.       End
  166.    End
  167.    Begin Menu menuOptions 
  168.       Caption         =   "&Options"
  169.       Begin Menu menubarWhite 
  170.          Caption         =   "&White for Human"
  171.       End
  172.       Begin Menu menubarBlack 
  173.          Caption         =   "&Black for Human"
  174.       End
  175.       Begin Menu menusepO1 
  176.          Caption         =   "-"
  177.       End
  178.       Begin Menu menubarHuman 
  179.          Caption         =   "&Human 1st"
  180.       End
  181.       Begin Menu menubarComputer 
  182.          Caption         =   "&Computer 1st"
  183.       End
  184.    End
  185.    Begin Menu menuSkill 
  186.       Caption         =   "&Skill"
  187.       Begin Menu menubarSkill 
  188.          Caption         =   "&Expert Computer"
  189.          Index           =   0
  190.       End
  191.       Begin Menu menubarSkill 
  192.          Caption         =   "&Good Computer"
  193.          Index           =   1
  194.       End
  195.       Begin Menu menubarSkill 
  196.          Caption         =   "&Fair Computer"
  197.          Index           =   2
  198.       End
  199.       Begin Menu menubarSkill 
  200.          Caption         =   "&Poor Computer"
  201.          Index           =   3
  202.       End
  203.       Begin Menu menubarSkill 
  204.          Caption         =   "&Idiot Computer"
  205.          Index           =   4
  206.       End
  207.    End
  208. DefStr A-Z  ' Force numeric variables to be declared
  209. Dim CRLF$   ' CarriageReturn/LineFeed pair
  210. Dim CurrPlayer As Integer, ModernOpening As Integer  ' Boolean
  211. Dim MoveNoise As Integer
  212. Dim BoardGrid() As String * 1, BoardPc(HUMAN To COMPUTER) As String * 1
  213. Dim DescPc(HUMAN To COMPUTER) As String
  214. Dim Score(HUMAN To COMPUTER) As Integer
  215. Dim TurnNbr As Integer, NbrPcs As Integer
  216. Dim ForfeitCount As Integer
  217. Dim GameOver As Integer  ' Boolean
  218. Dim MaxRC As Integer, MaxIJ As Integer, MidRC As Integer
  219. Dim MaxPcs As Integer
  220. ' Raw position values
  221. Dim Rating(MIN_RC To MAX_RATING_RC, MIN_RC To MAX_RATING_RC) As Long
  222. ' Multiplier for # turned pieces in line opposite empty square
  223. Dim XEmpty(MIN_RC To MAX_RATING_RC, MIN_RC To MAX_RATING_RC) As Long
  224. ' "Neutralize" (neither + nor -) # turned pieces opposite border
  225. Dim XBorder(MIN_RC To MAX_RATING_RC, MIN_RC To MAX_RATING_RC) As Long
  226. ' Multiplier for # turned pieces opposite opponent's piece
  227. Dim XOpponent(MIN_RC To MAX_RATING_RC, MIN_RC To MAX_RATING_RC) As Long
  228. ' Translation of radial direction value into X and Y coordinate increments
  229. Dim RowIncr(MIN_DIR To MAX_DIR) As Integer
  230. Dim ColIncr(MIN_DIR To MAX_DIR) As Integer
  231. ' Adjust scores and total pieces after a move
  232. Sub AdjustScores (ByVal P%, ByVal N%)
  233.     SetScore P%, (Score(P%) + N% + 1)  ' Include new piece
  234.     SetScore (Not P%), (Score(Not P%) - N%)
  235.     NbrPcs = Score(HUMAN) + Score(COMPUTER)
  236. End Sub
  237. ' Trigger Human's move on "MouseUp" instead of "Click" to get X & Y
  238. Sub Board_MouseUp (Button As Integer, Shift As Integer, x As Single, y As Single)
  239.     Dim cs As Single
  240.     Dim r%, c%
  241.     cs = CellSize()
  242.     r% = 1 + Int(y / cs)
  243.     c% = 1 + Int(x / cs)
  244.     MoveForHuman r%, c%
  245. End Sub
  246. Sub Board_Paint ()
  247.     ShowGrid
  248.     ShowPcs
  249. End Sub
  250. Sub buttonComputerMove_Click ()
  251.     MoveForComputer
  252. End Sub
  253. Sub buttonHumanForfeit_Click ()
  254. If GameOver Then
  255.         Feedback "Game Already Over" + CRLF$ + " Select Game, New Game"
  256.         Exit Sub
  257.     End If
  258.     If CurrPlayer = COMPUTER Then
  259.         Feedback "Click 'Make Move'" + CRLF$ + " for Computer's Move"
  260.         Exit Sub
  261.     ElseIf ForfeitAllowed() Then
  262.         Feedback ""
  263.         ForfeitCount = ForfeitCount + 1
  264.         CurrPlayer = COMPUTER
  265.         MoveMsg_Paint
  266.         CheckGameOver
  267.     Else
  268.         Feedback "You have a valid move"
  269.     End If
  270. End Sub
  271. Function CellSize () As Single
  272.     CellSize = Board.Height / ((MaxRC - MIN_RC) + 1)
  273. End Function
  274. ' See if game termination conditions have been met
  275. Sub CheckGameOver ()
  276.     Dim WhyDone As String, Winner As String
  277.     Dim reply%
  278.     If GameOver Then
  279.         Feedback "(Game already over)"
  280.         Exit Sub
  281.     End If
  282.     If ForfeitCount >= 2 Then
  283.         GameOver = True
  284.         WhyDone = "Double Forfeit"
  285.     End If
  286.     If NbrPcs = MaxPcs Then
  287.         GameOver = True
  288.         WhyDone = "Board Full"
  289.     End If
  290.     If GameOver Then
  291.         If Score(HUMAN) > Score(COMPUTER) Then
  292.             Winner = "You Won!"
  293.             CurrPlayer = COMPUTER  ' Setup 1st player for next game
  294.         ElseIf Score(COMPUTER) > Score(HUMAN) Then
  295.             Winner = "The Computer is the Winner"
  296.             CurrPlayer = HUMAN
  297.         Else
  298.             Winner = "Tie Game"
  299.         End If
  300.         reply% = MsgBox(Winner, (mb_OK + mb_IconInformation), WhyDone)
  301.         Feedback "Game Over"
  302.         MoveMsg_Paint
  303.     End If
  304. End Sub
  305. ' Simulate a random outcome of Reversi's original player opening protocol
  306. Sub DoRandomOpening ()
  307.     Dim m As Integer
  308.     Dim p1$, p2$
  309.     If Rnd > .5 Then
  310.         p1$ = WHITE_PC
  311.         p2$ = BLACK_PC
  312.     Else
  313.         p1$ = BLACK_PC
  314.         p2$ = WHITE_PC
  315.     End If
  316.     m = MidRC
  317.     BoardGrid(m, m) = p1$
  318.     If Rnd > .5 Then
  319.         BoardGrid(m, m + 1) = p1$
  320.         BoardGrid(m + 1, m) = p2$
  321.         BoardGrid(m + 1, m + 1) = p2$
  322.     Else
  323.         BoardGrid(m, m + 1) = p2$
  324.         If Rnd > .5 Then
  325.             BoardGrid(m + 1, m) = p1$
  326.             BoardGrid(m + 1, m + 1) = p2$
  327.         Else
  328.             BoardGrid(m + 1, m) = p2$
  329.             BoardGrid(m + 1, m + 1) = p1$
  330.         End If
  331.     End If
  332. End Sub
  333. Sub DrawPc (ByVal pc$, ByVal r%, ByVal c%)
  334.     Dim x As Single, y As Single
  335.     Dim cs As Single, hc As Single, cr As Single
  336.     Dim color As Long
  337.     Select Case pc$
  338.     Case BLACK_PC
  339.         color = COLOR_BLACK
  340.     Case WHITE_PC
  341.         color = COLOR_WHITE
  342.     Case Else
  343.         Exit Sub
  344.     End Select
  345.     cs = CellSize()
  346.     hc = cs * .5
  347.     cr = hc * .9
  348.     x = ((c% - MIN_RC) * cs) + hc
  349.     y = ((r% - MIN_RC) * cs) + hc
  350.     Board.FillStyle = SOLID
  351.     Board.FillColor = color
  352.     Board.Circle (x, y), cr, color
  353. End Sub
  354. ' Display a feedback message to the user
  355. Sub Feedback (ByVal s$)
  356.     FeedbackMsg.Caption = "  " + s$
  357.     If s$ = "" Then
  358.         FeedbackMsg.Visible = False
  359.     Else
  360.         FeedbackMsg.Visible = True
  361.         Beep
  362.     End If
  363. End Sub
  364. ' See if the current player must forfeit
  365. Function ForfeitAllowed () As Integer  ' Boolean
  366.     Dim ok%, r%, c%, v&
  367.     ok% = True
  368.     ''Debug.Print "Forfeit?"
  369.     For r% = MIN_RC To MaxRC
  370.         For c% = MIN_RC To MaxRC
  371.             v& = MoveValue(r%, c%, False)
  372.             ''Debug.Print " "; v&;
  373.             If v& > INVALID_MOVE Then ok% = False
  374.         Next c%
  375.         ''Debug.Print
  376.     Next r%
  377.     ForfeitAllowed = ok%
  378. End Function
  379. ' For debugging, a Click on the form background repaints key controls
  380. Sub Form_Click ()
  381.     Board_Paint
  382.     MoveMsg_Paint
  383. End Sub
  384. ' Initialize the program upon startup
  385. Sub Form_Load ()
  386.     CRLF$ = Chr$(13) + Chr$(10)
  387.     Randomize
  388.     MaxRC = MIN_RC  ' No board exists
  389.     ' Setup the special arrays used to evaluate board positions for
  390.     ' Computer moves.
  391.     ' Note that XReversi plays on a par with Microsoft's Reversi (as "Expert")
  392.     ' but WITHOUT using move lookahead.  XReversi plays by POSITION only!
  393.     ' Raw position values
  394.     ' ((999, -20,+15,+15),
  395.     Rating(MIN_RC + 0, MIN_RC + 0) = 999
  396.     Rating(MIN_RC + 1, MIN_RC + 0) = -20
  397.     Rating(MIN_RC + 2, MIN_RC + 0) = 15
  398.     Rating(MIN_RC + 3, MIN_RC + 0) = 15
  399.     '  (-20,-333,-20,-20),
  400.     Rating(MIN_RC + 0, MIN_RC + 1) = -20
  401.     Rating(MIN_RC + 1, MIN_RC + 1) = -333
  402.     Rating(MIN_RC + 2, MIN_RC + 1) = -20
  403.     Rating(MIN_RC + 3, MIN_RC + 1) = -20
  404.     '  (+15, -20, +6,  0),
  405.     Rating(MIN_RC + 0, MIN_RC + 2) = 15
  406.     Rating(MIN_RC + 1, MIN_RC + 2) = -20
  407.     Rating(MIN_RC + 2, MIN_RC + 2) = 6
  408.     Rating(MIN_RC + 3, MIN_RC + 2) = 0
  409.     '  (+15, -20,  0,  0));
  410.     Rating(MIN_RC + 0, MIN_RC + 3) = 15
  411.     Rating(MIN_RC + 1, MIN_RC + 3) = -20
  412.     Rating(MIN_RC + 2, MIN_RC + 3) = 0
  413.     Rating(MIN_RC + 3, MIN_RC + 3) = 0
  414.     ' Multiplier for # turned pieces in line opposite an empty square
  415.     ' (Used to favor "unflankable" move directionss over raw piece count.)
  416.     ' ((+3, +3, +3, +3),
  417.     XEmpty(MIN_RC + 0, MIN_RC + 0) = 3
  418.     XEmpty(MIN_RC + 1, MIN_RC + 0) = 3
  419.     XEmpty(MIN_RC + 2, MIN_RC + 0) = 3
  420.     XEmpty(MIN_RC + 3, MIN_RC + 0) = 3
  421.     '  (+3, +1, +3, +3),
  422.     XEmpty(MIN_RC + 0, MIN_RC + 1) = 3
  423.     XEmpty(MIN_RC + 1, MIN_RC + 1) = 1
  424.     XEmpty(MIN_RC + 2, MIN_RC + 1) = 3
  425.     XEmpty(MIN_RC + 3, MIN_RC + 1) = 3
  426.     '  (+3, +3, +3, +3),
  427.     XEmpty(MIN_RC + 0, MIN_RC + 2) = 3
  428.     XEmpty(MIN_RC + 1, MIN_RC + 2) = 3
  429.     XEmpty(MIN_RC + 2, MIN_RC + 2) = 3
  430.     XEmpty(MIN_RC + 3, MIN_RC + 2) = 3
  431.     '  (+3, +3, +3, +3));
  432.     XEmpty(MIN_RC + 0, MIN_RC + 3) = 3
  433.     XEmpty(MIN_RC + 1, MIN_RC + 3) = 3
  434.     XEmpty(MIN_RC + 2, MIN_RC + 3) = 3
  435.     XEmpty(MIN_RC + 3, MIN_RC + 3) = 3
  436.     ' Multiplier for # turned pieces opposite opponent's piece
  437.     ' (Prevents creating a line of our pieces, just to be re-flanked
  438.     '  by the opponent.  Works by creating negative value in this
  439.     '  direction.  Note, however, that if we land between two opponent
  440.     '  pieces, the two negatives multiple to positive;  this yields
  441.     '  XReversi's powerful "divide and conquer" behavior!)
  442.     ' ((  0,-40,-30,-30),
  443.     XOpponent(MIN_RC + 0, MIN_RC + 0) = 0
  444.     XOpponent(MIN_RC + 1, MIN_RC + 0) = -40
  445.     XOpponent(MIN_RC + 2, MIN_RC + 0) = -30
  446.     XOpponent(MIN_RC + 3, MIN_RC + 0) = -30
  447.     '  (-40, -9, -5, -5),
  448.     XOpponent(MIN_RC + 0, MIN_RC + 1) = -40
  449.     XOpponent(MIN_RC + 1, MIN_RC + 1) = -9
  450.     XOpponent(MIN_RC + 2, MIN_RC + 1) = -5
  451.     XOpponent(MIN_RC + 3, MIN_RC + 1) = -5
  452.     '  (-30, -5, -3, -3),
  453.     XOpponent(MIN_RC + 0, MIN_RC + 2) = -30
  454.     XOpponent(MIN_RC + 1, MIN_RC + 2) = -5
  455.     XOpponent(MIN_RC + 2, MIN_RC + 2) = -3
  456.     XOpponent(MIN_RC + 3, MIN_RC + 2) = -3
  457.     '  (-30, -5, -3, -3));
  458.     XOpponent(MIN_RC + 0, MIN_RC + 3) = -30
  459.     XOpponent(MIN_RC + 1, MIN_RC + 3) = -5
  460.     XOpponent(MIN_RC + 2, MIN_RC + 3) = -3
  461.     XOpponent(MIN_RC + 3, MIN_RC + 3) = -3
  462.     ' "Neutralize" (neither + nor -) # turned pieces opposite border
  463.     ' (Causes harmless opponents near border to be ignored.)
  464.     For i% = MIN_RC To MAX_RATING_RC
  465.         For j% = MIN_RC To MAX_RATING_RC
  466.             XBorder(i%, j%) = 0
  467.         Next j%
  468.     Next i%
  469.     ' ( 0, -1, -1, -1,  0, +1, +1, +1);
  470.     RowIncr(MIN_DIR + 0) = 0
  471.     RowIncr(MIN_DIR + 1) = -1
  472.     RowIncr(MIN_DIR + 2) = -1
  473.     RowIncr(MIN_DIR + 3) = -1
  474.     RowIncr(MIN_DIR + 4) = 0
  475.     RowIncr(MIN_DIR + 5) = 1
  476.     RowIncr(MIN_DIR + 6) = 1
  477.     RowIncr(MIN_DIR + 7) = 1
  478.     ' (+1, +1,  0, -1, -1, -1,  0, +1);
  479.     ColIncr(MIN_DIR + 0) = 1
  480.     ColIncr(MIN_DIR + 1) = 1
  481.     ColIncr(MIN_DIR + 2) = 0
  482.     ColIncr(MIN_DIR + 3) = -1
  483.     ColIncr(MIN_DIR + 4) = -1
  484.     ColIncr(MIN_DIR + 5) = -1
  485.     ColIncr(MIN_DIR + 6) = 0
  486.     ColIncr(MIN_DIR + 7) = 1
  487.     ' Now setup for the first game
  488.     Feedback ""
  489.     SetHumanPc WHITE_PC
  490.     SetFirstPlayer HUMAN
  491.     SetModernOpening True
  492.     SetSkill MIN_SKILL
  493.     SetBoardSize 8  ' Will, in turn, call InitializeBoard
  494. End Sub
  495. ' Fold general board coordinates into upper-left corner of 8x8 board
  496. Function HalfRC (ByVal RC%) As Integer
  497.     If (RC% <= MAX_RATING_RC) Then
  498.         HalfRC = RC%
  499.     ElseIf (RC% >= (1 + (MaxRC - MAX_RATING_RC))) Then
  500.         HalfRC = 1 + (MaxRC - RC%)
  501.     Else
  502.         HalfRC = MAX_RATING_RC
  503.     End If
  504. End Function
  505. ' Set up the board (of arbritrary size) for a new game
  506. Sub InitializeBoard (ByVal Size%)
  507.     Dim i%, j%
  508.     Feedback ""
  509.     MaxRC = Size%
  510.     MidRC = MaxRC \ 2
  511.     MaxIJ = MaxRC + 1
  512.     MaxPcs = MaxRC * MaxRC
  513.     ReDim BoardGrid(MIN_IJ To MaxIJ, MIN_IJ To MaxIJ)  As String
  514.     For i% = MIN_IJ To MaxIJ
  515.         For j% = MIN_IJ To MaxIJ
  516.             BoardGrid(i%, j%) = BORDER
  517.         Next j%
  518.     Next i%
  519.     For i% = MIN_RC To MaxRC
  520.         For j% = MIN_RC To MaxRC
  521.             BoardGrid(i%, j%) = EMPTY
  522.         Next j%
  523.     Next i%
  524.     If ModernOpening Then  ' Modern Othello opening
  525.         BoardGrid(MidRC + 0, MidRC + 0) = BLACK_PC
  526.         BoardGrid(MidRC + 1, MidRC + 1) = BLACK_PC
  527.         BoardGrid(MidRC + 0, MidRC + 1) = WHITE_PC
  528.         BoardGrid(MidRC + 1, MidRC + 0) = WHITE_PC
  529.     Else  ' Original Reversi had special opening player "protocol",
  530.           ' simply choose a random outcome from this opening
  531.         DoRandomOpening
  532.     End If
  533.     SetScore HUMAN, 2
  534.     SetScore COMPUTER, 2
  535.     ForfeitCount = 0
  536.     TurnNbr = 1
  537.     GameOver = False
  538.     MoveMsg_Paint
  539.     Board_Paint
  540. End Sub
  541. Sub menubar10x10_Click ()
  542.     SetBoardSize 10
  543. End Sub
  544. Sub menubar16x16_Click ()
  545.     SetBoardSize 16
  546. End Sub
  547. Sub menubar20x20_Click ()
  548.     SetBoardSize 20
  549. End Sub
  550. Sub menubar8x8_Click ()
  551.     SetBoardSize 8
  552. End Sub
  553. Sub menubarBlack_Click ()
  554.     SetHumanPc BLACK_PC
  555. End Sub
  556. Sub menubarComputer_Click ()
  557.     SetFirstPlayer COMPUTER
  558. End Sub
  559. Sub menubarHuman_Click ()
  560.     SetFirstPlayer HUMAN
  561. End Sub
  562. Sub menubarModern_Click ()
  563.     SetModernOpening True
  564. End Sub
  565. Sub menubarNewGame_Click ()
  566.     InitializeBoard MaxRC
  567. End Sub
  568. Sub menubarQuit_Click ()
  569.     End
  570. End Sub
  571. Sub menubarRandom_Click ()
  572.     SetModernOpening False
  573. End Sub
  574. Sub menubarSkill_Click (Index As Integer)
  575.     SetSkill (Index)
  576. End Sub
  577. Sub menubarWhite_Click ()
  578.     SetHumanPc WHITE_PC
  579. End Sub
  580. Sub menuGame_Click ()
  581.     Dim e%
  582.     e% = (GameOver) Or (TurnNbr = 1)  ' See if a game is in progress
  583.     menubarModern.Enabled = e%
  584.     menubarRandom.Enabled = e%
  585.     menubar8x8.Enabled = e%
  586.     menubar10x10.Enabled = e%
  587.     menubar16x16.Enabled = e%
  588.     menubar20x20.Enabled = e%
  589. End Sub
  590. Sub menuOptions_Click ()
  591.     Dim e%
  592.     e% = (GameOver) Or (TurnNbr = 1)  ' See if a game is in progress
  593.     menubarHuman.Enabled = e%
  594.     menubarComputer.Enabled = e%
  595. End Sub
  596. Sub MoveForComputer ()
  597.     Dim r%, c%, value%, found%
  598.     If GameOver Then
  599.         Feedback "Game Already Over" + CRLF$ + " Select Game, New Game"
  600.         Exit Sub
  601.     End If
  602.     If CurrPlayer = HUMAN Then
  603.         Feedback "It's your turn"
  604.         Exit Sub
  605.     End If
  606.     best% = MIN_INTEGER
  607.     found% = False
  608.     For r% = MIN_RC To MaxRC
  609.         For c% = MIN_RC To MaxRC
  610.             If BoardGrid(r%, c%) = EMPTY Then
  611.                 value% = MoveValue(r%, c%, False)  ' Don't actually move
  612.                 If value% > INVALID_MOVE Then
  613.                     value% = value% + Int(Rnd * MoveNoise)
  614.                     If (value% > best%) Or ((value% = best%) And (Rnd > .5)) Then
  615.                         best% = value%
  616.                         br% = r%
  617.                         bc% = c%
  618.                         found% = True
  619.                     End If
  620.                 End If
  621.             End If
  622.         Next c%
  623.     Next r%
  624.     If found% Then
  625.         Feedback ""
  626.         value% = MoveValue(br%, bc%, True)  ' Actually make the move
  627.         BoardGrid(br%, bc%) = BoardPc(COMPUTER)
  628.         DrawPc BoardPc(COMPUTER), br%, bc%
  629.     Else
  630.         Feedback "Computer forfeits!" + CRLF$ + " Move again"
  631.         ForfeitCount = ForfeitCount + 1
  632.     End If
  633.     CurrPlayer = HUMAN
  634.     MoveMsg_Paint
  635.     CheckGameOver
  636. End Sub
  637. Sub MoveForHuman (ByVal Row%, ByVal Col%)
  638.     Dim N%
  639.     If GameOver Then
  640.         Feedback "Game Already Over" + CRLF$ + " Select Game, New Game"
  641.         Exit Sub
  642.     End If
  643.     If CurrPlayer = COMPUTER Then
  644.         Feedback "Click 'Make Move'" + CRLF$ + " for Computer's Move"
  645.         Exit Sub
  646.     End If
  647.     If ForfeitAllowed() Then
  648.         Feedback "Forfeit!" + CRLF$ + " You have no legal move"
  649.         ForfeitCount = ForfeitCount + 1
  650.         CurrPlayer = COMPUTER
  651.         MoveMsg_Paint
  652.         CheckGameOver
  653.         Exit Sub
  654.     End If
  655.     If MoveValue(Row%, Col%, False) = INVALID_MOVE Then
  656.         Feedback "Invalid move!" + CRLF$ + " Try another square"
  657.         Exit Sub
  658.     End If
  659.     Feedback ""
  660.     N% = MoveValue(Row%, Col%, True)
  661.     BoardGrid(Row%, Col%) = BoardPc(HUMAN)
  662.     DrawPc BoardPc(HUMAN), Row%, Col%
  663.     CurrPlayer = COMPUTER
  664.     MoveMsg_Paint
  665.     CheckGameOver
  666.     If GameOver Then Exit Sub
  667.     If ForfeitAllowed() Then
  668.         Feedback "Computer forfeits!" + CRLF$ + " Move again"
  669.         ForfeitCount = ForfeitCount + 1
  670.         CurrPlayer = HUMAN
  671.         MoveMsg_Paint
  672.         CheckGameOver
  673.     End If
  674. End Sub
  675. Sub MoveMsg_Paint ()
  676.     MoveMsg.Cls
  677.     If GameOver Then
  678.         MoveMsg.Print
  679.         MoveMsg.Print
  680.         MoveMsg.Print " Score Difference = "; Abs(Score(HUMAN) - Score(COMPUTER))
  681.         Exit Sub
  682.     End If
  683.     MoveMsg.Print "Turn # "; TurnNbr
  684.     MoveMsg.Print
  685.     If CurrPlayer = HUMAN Then
  686.         MoveMsg.Print " Your move for "; DescPc(HUMAN)
  687.         MoveMsg.Print " (point and click on desired square)"
  688.     Else
  689.         MoveMsg.Print " Computer's move for "; DescPc(COMPUTER)
  690.         MoveMsg.Print " (click 'Make Move' button)"
  691.     End If
  692. End Sub
  693. ' Calculate the legality and value of a given square
  694. ' Also used to make actual moves if "MakingMove" is TRUE
  695. ' This is the "nerve center" of XReversi's Computer player
  696. ' The square evaluation algorithm was designed/written by Rick Rutt in 1984
  697. Function MoveValue (ByVal Row%, ByVal Col%, ByVal MakingMove%) As Long
  698.     Static DirScore(MIN_DIR To MAX_DIR) As Integer
  699.     Dim ok%, i%, j%, ii%, jj%, d%, temp%, pvalue%
  700.     ' First, see if the current square touches an opponent
  701.     ok% = False
  702.     If BoardGrid(Row%, Col%) = EMPTY Then
  703.         For ii% = -1 To 1
  704.             For jj% = -1 To 1
  705.                 If BoardGrid(Row% + ii%, Col% + jj%) = BoardPc(Not CurrPlayer) Then
  706.                     ok% = True
  707.                 End If
  708.             Next jj%
  709.         Next ii%
  710.     End If
  711.     If Not ok% Then
  712.         MoveValue = INVALID_MOVE
  713.     Else
  714.         ' Next, see if any pieces will be reversed; also assign a value
  715.         reversed% = 0
  716.         For d% = MIN_DIR To MAX_DIR  ' Examine all neighboring squares
  717.             ii% = RowIncr(d%)
  718.             jj% = ColIncr(d%)
  719.             i% = Row% + ii%
  720.             j% = Col% + jj%
  721.             temp% = 0
  722.             Select Case BoardGrid(i%, j%)
  723.             Case EMPTY
  724.                 DirScore(d%) = XEmpty(HalfRC(Row%), HalfRC(Col%))
  725.             Case BORDER
  726.                 DirScore(d%) = XBorder(HalfRC(Row%), HalfRC(Col%))
  727.             Case BoardPc(CurrPlayer)
  728.                 ' No pieces to reverse, but see if we put "friends" at risk
  729.                 ' if we bump up against an opponent on the opposite side
  730.                 Do
  731.                     i% = i% + ii%
  732.                     j% = j% + jj%
  733.                 Loop Until BoardGrid(i%, j%) <> BoardPc(CurrPlayer)
  734.                 Select Case BoardGrid(i%, j%)  ' What is beyond our friends
  735.                 Case EMPTY
  736.                     DirScore(d%) = XEmpty(HalfRC(Row%), HalfRC(Col%))
  737.                 Case BORDER
  738.                     DirScore(d%) = XBorder(HalfRC(Row%), HalfRC(Col%))
  739.                 Case Else
  740.                     DirScore(d%) = XOpponent(HalfRC(Row%), HalfRC(Col%))
  741.                 End Select
  742.             Case BoardPc(Not CurrPlayer)
  743.                 ' Scan down a line of opponents, to see what is past them
  744.                 Do
  745.                     temp% = temp% + 1
  746.                     i% = i% + ii%
  747.                     j% = j% + jj%
  748.                 Loop Until BoardGrid(i%, j%) <> BoardPc(Not CurrPlayer)
  749.                 Select Case BoardGrid(i%, j%)
  750.                 Case EMPTY, BORDER
  751.                     DirScore(d%) = XOpponent(HalfRC(Row%), HalfRC(Col%))
  752.                 Case Else  ' Current Player, we have a legal flanking move
  753.                     reversed% = reversed% + temp%
  754.                     Do  ' Find what is beyond the flanking "friend"
  755.                         i% = i% + ii%
  756.                         j% = j% + jj%
  757.                     Loop Until BoardGrid(i%, j%) <> BoardPc(CurrPlayer)
  758.                     Select Case BoardGrid(i%, j%)
  759.                     Case EMPTY
  760.                         DirScore(d%) = XEmpty(HalfRC(Row%), HalfRC(Col%))
  761.                     Case BORDER
  762.                         DirScore(d%) = XBorder(HalfRC(Row%), HalfRC(Col%))
  763.                     Case Else
  764.                         DirScore(d%) = XOpponent(HalfRC(Row%), HalfRC(Col%))
  765.                     End Select
  766.                     If MakingMove% Then  ' Actually reverse the pieces
  767.                         i% = Row% + ii%
  768.                         j% = Col% + jj%
  769.                         Do While BoardGrid(i%, j%) = BoardPc(Not CurrPlayer)
  770.                             BoardGrid(i%, j%) = BoardPc(CurrPlayer)
  771.                             DrawPc BoardPc(CurrPlayer), i%, j%
  772.                             i% = i% + ii%
  773.                             j% = j% + jj%
  774.                         Loop
  775.                     End If
  776.                 End Select
  777.             End Select
  778.         Next d%
  779.         If MakingMove Then
  780.             AdjustScores CurrPlayer, reversed%
  781.             ForfeitCount = 0
  782.             TurnNbr = TurnNbr + 1
  783.         End If
  784.         If reversed% = 0 Then
  785.             MoveValue = INVALID_MOVE
  786.         Else
  787.             pvalue% = 0
  788.             For d% = MIN_DIR To MID_DIR
  789.                 pvalue% = pvalue% + (DirScore(d%) * DirScore(d% + MID_DIR))
  790.             Next d%
  791.             ' Add up all "components" of the square's value
  792.             MoveValue = reversed% + pvalue% + Rating(HalfRC(Row%), HalfRC(Col%))
  793.         End If
  794.     End If
  795. End Function
  796. Sub SetBoardSize (ByVal Size%)
  797.     menubar8x8.Checked = False
  798.     menubar10x10.Checked = False
  799.     menubar16x16.Checked = False
  800.     menubar20x20.Checked = False
  801.     Select Case Size%
  802.     Case 8
  803.         menubar8x8.Checked = True
  804.     Case 10
  805.         menubar10x10.Checked = True
  806.     Case 16
  807.         menubar16x16.Checked = True
  808.     Case 20
  809.         menubar20x20.Checked = True
  810.     End Select
  811.     If (MaxRC <> Size%) Then InitializeBoard Size%
  812. End Sub
  813. Sub SetFirstPlayer (ByVal P%)
  814.     If P% = HUMAN Then
  815.         menubarHuman.Checked = True
  816.         menubarComputer.Checked = False
  817.     Else
  818.         menubarHuman.Checked = False
  819.         menubarComputer.Checked = True
  820.     End If
  821.     CurrPlayer = P%
  822.     MoveMsg_Paint
  823. End Sub
  824. Sub SetHumanPc (ByVal P$)
  825.     Dim s1%, s2%
  826.     If P$ = BoardPc(HUMAN) Then  ' No change
  827.         Exit Sub
  828.     Else
  829.         CurrPlayer = Not CurrPlayer  ' Trade places, even in mid-game
  830.         s1% = Score(HUMAN)
  831.         s2% = Score(COMPUTER)
  832.         SetScore HUMAN, s2%
  833.         SetScore COMPUTER, s1%
  834.     End If
  835.     If P$ = BLACK_PC Then
  836.         menubarBlack.Checked = True
  837.         menubarWhite.Checked = False
  838.         BoardPc(HUMAN) = BLACK_PC
  839.         BoardPc(COMPUTER) = WHITE_PC
  840.         
  841.         DescPc(HUMAN) = "Black"
  842.         DescPc(COMPUTER) = "White"
  843.     Else
  844.         menubarBlack.Checked = False
  845.         menubarWhite.Checked = True
  846.         BoardPc(HUMAN) = WHITE_PC
  847.         BoardPc(COMPUTER) = BLACK_PC
  848.         DescPc(HUMAN) = "White"
  849.         DescPc(COMPUTER) = "Black"
  850.     End If
  851.     If TurnNbr = 1 Then
  852.         SetFirstPlayer CurrPlayer
  853.     End If
  854.     MoveMsg_Paint
  855. End Sub
  856. Sub SetModernOpening (ByVal Modern%)
  857.     If Modern% Then
  858.         menubarModern.Checked = True
  859.         menubarRandom.Checked = False
  860.     Else
  861.         menubarModern.Checked = False
  862.         menubarRandom.Checked = True
  863.     End If
  864.     ModernOpening = Modern%
  865.     InitializeBoard MaxRC
  866. End Sub
  867. ' Set a given player's score, and make related adjustments
  868. Sub SetScore (ByVal P%, ByVal s%)
  869.     Score(P%) = s%
  870.     NbrPcs = Score(HUMAN) + Score(COMPUTER)
  871.     If P% = HUMAN Then
  872.         HumanScore.Caption = Format$(s%, " ##0")
  873.     Else
  874.         ComputerScore.Caption = Format$(s%, " ##0")
  875.     End If
  876. End Sub
  877. Sub SetSkill (ByVal Idx%)
  878.     Dim i%
  879.     For i% = MIN_SKILL To MAX_SKILL
  880.         menubarSkill(i%).Checked = False
  881.     Next i%
  882.     menubarSkill(Idx%).Checked = True
  883.     MoveNoise = NOISE_GAIN * Idx%
  884. End Sub
  885. ' Draw grid lines on the board area
  886. Sub ShowGrid ()
  887.     Dim cs As Single
  888.     Dim x As Single
  889.     Dim i%
  890.     Board.Cls
  891.     cs = CellSize()
  892.     For i% = 1 To (MaxRC - 1)
  893.         x = i% * cs
  894.         Board.Line (x, 0)-(x, Board.Height)
  895.         Board.Line (0, x)-(Board.Width, x)
  896.     Next i%
  897. End Sub
  898. ' Refresh all pieces in the board area
  899. Sub ShowPcs ()
  900.     Dim i%, j%, pc$
  901.     For i% = MIN_RC To MaxRC
  902.         For j% = MIN_RC To MaxRC
  903.             pc$ = BoardGrid(i%, j%)
  904.             DrawPc pc$, i%, j%
  905.         Next j%
  906.     Next i%
  907. End Sub
  908.