Microsoft Small Basic

Program Listing:
Embed this in your website
' Go Simulator 0.4
' Copyright (c) 2009-2012 Nonki Takahashi. All right reserved.
'
' History:
' 0.4 2012/11/04 Changed to speed up and draw stars. (PTB804-2)
' 0.3 2012/11/02 Speed up and make board size 9x9. (PTB804-1)
' 0.2 2012/11/01 Changed to make SGF always. (PTB804-0)
' 0.1 2012/11/01 Created by Goban 0.4 and Igo v0.95. (PTB804)
'
' Reference:
' [1] 清愼一, 山下宏, 佐々木宣介: 『コンピュータ囲碁の入門』, 共立出版, 2005.
' [2] Anders Kierulf: File Format FF[1], http://www.red-bean.com/sgf/, 1990.
' [3] Arno Hollosi: SGF File Format FF[4], http://www.red-bean.com/sgf/, 2006.
' [4] Karl Baker: The Way to Go, American Go Association, 1986.
' [5] 美添一樹: モンテカルロ木検索, 情報処理, Vol.49 No.6, pp.686-693 (2008).
' [6] 山下宏: 『強豪囲碁ソフト「彩」について』,http://www32.ocn.ne.jp/~yss/index_j.html, 2009.
'
' ---------------------------------
' Main Program
' ---------------------------------
' work bInProgram - program running
' work bInGame - in game
' work iMove - number of moves
' work bDebug - in debug
sProgram = "Go Simulator" ' program name
sVersion = "0.4"      ' program version
bDebug = "False"      ' in debug
bSound = "False"      ' sound effect on (slow)
bNewRo = "False"      ' number of ro (lines) changed
bTime = "False"       ' display time
bAuto = "True"        ' auto playout
bDumpWL = "True"      ' dump win and lose
InitProgram()         ' initialize program
InitRoDepend()        ' initialize variables if number of ro (lines) changed
InitControls()        ' initialize controls
InitBoard()           ' initilaize board
InitGBoard()          ' initilaize graphics board
' while in program repeat in {}
While bInProgram
  ' {
  ' new game mode
  ResetControls()     ' reset controls
  ClearBoard()        ' clear board
  ClearGBoard()       ' clear graphics board
  lRetry:
  InputGameInfo()     ' input player name (or game record name)
  StartClock()
  ' play mode (or read game record)
  If bOpen Then
    Rec_ReadRecord()  ' read game record
    If bError Then
      Goto lRetry
    EndIf
    If bNewRo Then
      Shapes.HideShape(oPrisoner[BLACK])
      Shapes.HideShape(oPrisoner[WHITE])
      GraphicsWindow.BrushColor = "Silver"
      GraphicsWindow.FillRectangle(0, 0, GraphicsWindow.Width, GraphicsWindow.Height)
      InitRoDepend()  ' initialize variables if number of ro (lines) changed
      InitBoard()     ' initialize board
      InitGBoard()    ' initialize graphics board
      iLastRo = iRo
      ResetControls() ' reset controls
      ClearBoard()    ' clear board
      ClearGBoard()   ' clear graphics board
      bNewRo = "False"
    EndIf
    Rec_ReplayGame()  ' replay game record
  Else  ' play mode
    Shapes.SetText(oPrisoner[BLACK], 0) ' clear prisoner
    Shapes.SetText(oPrisoner[WHITE], 0) ' clear prisoner
    Rec_InitRecord()  ' initialize game record
    CreateRdmArray()  ' initialize random space array
    Rec_SaveGameDate()  ' save game date
    iMove = 0         ' clear number of moves
    ' game - repeat in {} until game end
    While bInGame
      ' {
      EachTurn()      ' black turn
      If bInGame Then
        EachTurn()    ' white turn
      EndIf
      ' }
    EndWhile
  EndIf
  If bTime Then
    TextWindow.Write("iMove=" + iMove + " " + sScore + " ")
  EndIf
  StopClock()
  If bTime Then
    PrintTime()
  EndIf
  ' game end mode (replay or save game record)
  Rec_GenSGFName()    ' generate SGF file name
  If bAuto Then
    Rec_WriteRecord() ' save game record
  EndIf
  bInGame = "True"
  While bInGame
    InputGameEndInfo()  ' input player name (or game record name)
    If bReplay Then
      Rec_ReplayGame()  ' replay game record
    ElseIf bSave Then
      Rec_WriteRecord() ' save game record
    EndIf
  EndWhile
  ' }
EndWhile

Sub EachTurn
  ' each turn
  ' param bReplay - "True" if replay
  ' param iMove - number of moves
  ' work iET
  ' return iPass - pass times
  ' return bResign - "True" if resign
  ' return bInGame - "True" if in game
  iMove = iMove + 1
  iColor = Math.Remainder((iMove - 1), 2) + 1
  ' show black turn lamp
  iX = iBLX
  iY = iBLY
  If iColor = BLACK Then
    bOn = "True"
  Else
    bOn = "False"
  EndIf
  DrawLamp()
  ' show white turn lamp
  iX = iWLX
  iY = iWLY
  If iColor = WHITE Then
    bOn = "True"
  Else
    bOn = "False"
  EndIf
  DrawLamp()
  ' next move
  If bReplay Then
    Replay()
  Else
    If sPlayer[iColor] = "Random" Or sPlayer[iColor] = "CPU" Or sPlayer[iColor] = "Easy" Then
      bEyes = "True"
    Else
      bEyes = "False"
    EndIf
    If sPlayer[iColor] = "Random" Then
      bEasy = "False"
      Random()
    ElseIf sPlayer[iColor] = "Easy" Then
      bEasy = "True"
      Random()
    Else
      Human()
    EndIf
  EndIf
  ' game end if resigned
  If bResign Then
    bInGame = "False"
    If (Math.Remainder(iMove, 2) = 1) Then
      sScore = "W+R"  ' resigned by black
      GraphicsWindow.Title = sProgram + " " + sVersion + " - White wins by a wide margin "  '" - 白の中押し勝ち"
    Else
      sScore = "B+R"  ' resigned by white
      GraphicsWindow.Title = sProgram + " " + sVersion + " - Black wins by a wide margin "  '" - 黒の中押し勝ち"
    EndIf
  Else
    ' count up pass times if pass
    If bPass Then
      iPass = iPass + 1
    Else
      iPass = 0
    EndIf
    ' record game record
    If bReplay = "False" Then
      Rec_Record()
    EndIf
    ' show stone and process for capture
    bShow = "True" ' show result
    If bPass = "False" Then
      DrawStone()
      If bSound Then
        Sound.PlayClickAndWait()
      EndIf
      ' remove stones if captured
      RemoveStonesIfCaptured()
      If iRemoved > 0 Then
        Shapes.SetText(oPrisoner[iColor], iPrisoner[iColor])
      EndIf
    EndIf
    ' game end judgement
    Judge()
  EndIf
EndSub
'
Sub RemoveStonesIfCaptured
  ' Remove Stones If Captured
  ' param iColor - stone color
  ' param iX, iY - last move
  ' param iBoard[][] - board
  ' param iRo - number of ro (lines)
  ' param iMove - number of moves
  ' param bShow - to show used in RemoveUnit()
  ' work iCTurn, iXTurn, iYTurn
  ' work bEnclosed - enclosed
  ' return iRemoved - number of removed stones
  ' param/return iKo, iKX, iKY - ko
  ' param/return iPrisoner[] - prisoner
  iRemoved = 0
  bEnclosed = "True"  ' enclosed from four direction
  iCTurn = iColor
  If iColor = BLACK Then
    iColor = WHITE
  ElseIf iColor = WHITE Then
    iColor = BLACK
  ElseIf iColor = SPACE Then
    Goto lSkipRemove
  EndIf
  iXTurn = iX
  iYTurn = iY
  For iET = 1 To 4
    iX = iXTurn + idX4[iET]
    iY = iYTurn + idY4[iET]
    If iBoard[iX][iY] = iCTurn Or iBoard[iX][iY] = SPACE Then
      bEnclosed = "False"
    EndIf
    If iX >= 1 And iX <= iRo And iY >= 1 And iY <= iRo Then
      InitLiberty()
      CountLiberty()
      If iLiberty = 0 Then
        RemoveUnit()
        iRemoved = iRemoved + iUnit
        iRX = iX
        iRY = iY
        iPrisoner[iCTurn] = iPrisoner[iCTurn] + iUnit
      EndIf
    EndIf
  EndFor
  iColor = iCTurn
  iX = iXTurn
  iY = iYTurn
  If bEnclosed And iRemoved = 1 Then
    iKo = iMove
    iKX = iRX
    iKY = iRY
  EndIf
  lSkipRemove:
EndSub

' ---------------------------------
' Program
' ---------------------------------
Sub InitProgram
  ' Initialize Program
  ' return SPACE, BLACK, WHITE, OB - stone color
  ' return UPPERA, UPPERZ, LOWERA, LOWERZ - character code
  ' return CR, LF, TAB - character code
  ' return iRo - number of ro (lines)
  ' return iPass - pass times
  ' return rCX, rCY - character width and height
  ' return iMove - number of moves
  ' return real rKomi - komi
  ' return sBoardColor - board color
  ' return sAlpha[] - alphabet for SGF game record
  ' return sStone[] - name of stone
  ' return sNew, sOpen, sPass - string: New, Open, Pass
  ' return sReplay, sResign, sSave - string: Replay, Resign, Save
  ' return bInProgram - program running
  SPACE = 0 ' space
  BLACK = 1 ' black
  WHITE = 2 ' white
  OB = 3    ' out of board
  BANDW = 4 ' black and white used in CheckSpaceUnit() etc.
  InitFigure() ' for debug
  UPPERA = Text.GetCharacterCode("A")   ' character code of "A"
  UPPERZ = Text.GetCharacterCode("Z")   ' character code of "Z"
  LOWERA = Text.GetCharacterCode("a")   ' character code of "a"
  LOWERZ = Text.GetCharacterCode("z")   ' character code of "z"
  CR = 13 ' character code of carriage return
  LF = 10 ' character code of line feed
  TAB = 9 ' character code of tab
  cCR = Text.GetCharacter(CR)
  cLF = Text.GetCharacter(LF)
  cTab = Text.GetCharacter(TAB)
  sNL = cCR + cLF
  iLastRo = 0
  iRo = 9
  sPlayer[BLACK] = "Random"   ' default black player
  If bAuto Then
    sPlayer[WHITE] = "Random" ' default white player
  Else
    sPlayer[WHITE] = "Human"  ' default white player
  EndIf
  sSGF = "temp.sgf"           ' default SGF file name
  rCX = 13.2
  rCY = 22
  If bDebug Then
    Debug_DrawGrid()  ' display grid for graphics design
  EndIf
  rKomi = 0.0
  GraphicsWindow.FontSize = rCY
  sBoardColor = "#F0C88C"   ' RGB(240, 200, 140)
  sWhiteColor = "#EEEEEE"   ' RGB(238, 238, 238)
  iGW = GraphicsWindow.Width
  iGH = GraphicsWindow.Height
  iPass = 0
  sStone[SPACE] = "SPACE"
  sStone[BLACK] = "BLACK"
  sStone[WHITE] = "WHITE"
  sStone[OB] = "OB"
  sGame = "Play"      '"対局"
  sOpen = "Open"      '"開く"
  sIsNotExist = "not exists."               '"は存在しません。"
  sIsNotGoFormat = "is not Go game record." '"は囲碁の棋譜ではありません。"
  sSave = "="         ' Windings save mark
  sSave2 = "Save"     '"保存"
  sAlreadyExists = "already exists."        '"はすでに存在します。"
  sNew = "New"        '"新規"
  sReplay = "4"       ' Windings replay mark
  sPause = ";"        ' Windings pause mark
  sPass = "Pass"      '"パス"
  sResign = "Resign"  '"投了"
  GraphicsWindow.Title = sProgram + " " + sVersion
  bInProgram = "True"
  InitEffect()  ' Initialize effect area
  Init4()       ' Initialize four direction
EndSub

Sub InitRoDepend
  ' Initialize Variables If Ro (Number of Lines) Changed
  ' work i
  For i = 0 To iRo
    sAlpha[i] = Text.GetSubText(" abcdefghijklmnopqrs", i + 1, 1)
  EndFor
  sAlpha[iRo + 1] = ""  ' pass
  idLX = rCX * 3        ' duration between lines
  iSR = idLX / 2 - 2    ' radius of stone
  idLY = rCY * 2        ' duration between lines
  iLX0 = rCX * 6.5      ' left end of line
  iLY0 = rCY * 4.5      ' top end of line
  iLX1 = iLX0 + idLX * (iRo - 1)  ' right end of line
  iLY1 = iLY0 + idLY * (iRo - 1)  ' bottom end of line
  If iRo > 9 Then
    iBX0 = iLX0 - idLX * 2        ' left of board
  Else
    iBX0 = iLX0 - idLX * 1.5      ' left of board
  EndIf
  iBY0 = iLY0 - idLY * 1.5        ' top of board
  iBX1 = iLX1 + idLX              ' right of board
  iBY1 = iLY1 + idLY              ' bottom of board
EndSub

Sub InitControls
  ' Initialize Controls
  ' param real rCX, rCY - character width, character height
  ' param idLX, idLY - distance between lines
  ' param iSR - radius of stone
  ' param iBX0, iBY0, iBX1, iBY1 - left, top, right and bottom of board
  ' param sNew, sReplay, sPass, sResign - text for button
  ' work iBHX, iBHY - position to display black prisoner
  ' work iWHX, iWHX - position to display white prisoner
  ' return oPlayer[] - textbox for player name
  ' return oPass, oResign - [Pass] [Resign] button
  ' return oSave, oReplay - [Save] [Replay] button
  ' return oPrisoner[] - text for prisoner
  ' return oSGF - textbox for SGF game record file name
  ' return iBLX, iBLY - position of black turn lamp
  ' return iWLX, iWLY - position of white turn lamp
  GraphicsWindow.BackgroundColor = "Silver"
  GraphicsWindow.BrushColor = "Black"
  'GraphicsWindow.FillEllipse(iBX1 + rCX, iBY0 + idLY, iSR * 2, iSR * 2)
  iBHX = iBX1 + rCX * 2 + iSR * 2.5
  iBHY = iBY0 + rCY * 2.5
  oPrisoner[BLACK] = Shapes.AddText(0)
  Shapes.Move(oPrisoner[BLACK], iBHX, iBHY)
  iBLX = iBHX + rCX * 5
  iBLY = iBHY
  bOn = "True"
  iX = iBLX
  iY = iBLY
  'DrawLamp()
  oPlayer[BLACK] = Controls.AddTextBox(iBX1 + rCX, iBY0)
  Controls.SetTextBoxText(oPlayer[BLACK], sPlayer[BLACK])
  oPlayer[WHITE] = Controls.AddTextBox(iBX1 + rCX, iBY0 + idLY * iRo / 2)
  Controls.SetTextBoxText(oPlayer[WHITE], sPlayer[WHITE])
  oPass = Controls.AddButton(sPass, iBX1 + rCX, iBY0 + idLY * iRo)
  oResign = Controls.AddButton(sResign, iBX1 + rCX * 6, iBY0 + idLY * iRo)
  Controls.HideControl(oPass)
  Controls.HideControl(oResign)
  oSGF = Controls.AddTextBox(iBX1 + rCX, iBY0 + idLY * iRo)
  Controls.SetTextBoxText(oSGF, sSGF)
  oGame = Controls.AddButton(sGame, iBX1 + rCX, iBY0 + idLY * iRo + rCY * 2)
  oOpen = Controls.AddButton(sOpen, iBX1 + rCX * 6, iBY0 + idLY * iRo + rCY * 2)
  oNew = Controls.AddButton(sNew, iBX1 + rCX, iBY0 + idLY * iRo + rCY * 2)
  Controls.HideControl(oNew)
  GraphicsWindow.FontName = "Webdings"
  oReplay = Controls.AddButton(sReplay, iBX1 + rCX * 6, iBY0 + idLY * iRo + rCY * 2)
  GraphicsWindow.BrushColor = "Red"
  oSave = Controls.AddButton(sSave, iBX1 + rCX * 9, iBY0 + idLY * iRo + rCY * 2)
  GraphicsWindow.BrushColor = "Black"
  GraphicsWindow.FontName = "Tahoma"
  Controls.HideControl(oReplay)
  Controls.HideControl(oSave)
  iWHX = iBX1 + rCX + iSR * 2.5
  iWHY = iBY0 + idLY * (iRo / 2) + rCY * 2.5
  oPrisoner[WHITE] = Shapes.AddText(0)
  Shapes.Move(oPrisoner[WHITE], iWHX, iWHY)
  iWLX = iWHX + rCX * 5
  iWLY = iWHY
  bOn = "False"
  iX = iWLX
  iY = iWLY
  'DrawLamp()
  'GraphicsWindow.BrushColor = "White"
  'GraphicsWindow.FillEllipse(iBX1 + rCX, iBY0 + idLY * (iRo / 2 + 1), iSR * 2, iSR * 2)
  Controls.TextTyped = OnTextTyped
EndSub

Sub ResetControls
  ' Reste Contorls
  ' param rCX, rCY - character width, height
  ' param idLX, idLY - distance between lines
  ' param iSR - radius of stone
  ' param iBX0, iBY0, iBX1, iBY1 - left, top, right, bottom of board
  ' param sNew, sReplay, sPass, sResign - text for button
  ' work iBHX, iBHY - position for black prisoner
  ' work iWHX, iWHX - position for white prisoner
  ' return oPlayer[] - textbox for player name
  ' return oPass, oResign - [Pass] [Resign] button
  ' return oSave, oReplay - [Save] [Replay] button
  ' return oPrisoner[] - text for prisoner
  ' return oSGF - textbox for SGF game record file name
  ' return iBLX, iBLY - position for black turn lamp
  ' return iWLX, iWLY - position for white turn lamp
  GraphicsWindow.BackgroundColor = "Silver"
  idS = 3
  GraphicsWindow.BrushColor = "#606060"
  GraphicsWindow.FillEllipse(iBX1 + rCX * 2 + idS, iBY0 + idLY + idS, iSR * 2, iSR * 2)
  GraphicsWindow.BrushColor = "Black"
  GraphicsWindow.FillEllipse(iBX1 + rCX * 2, iBY0 + idLY, iSR * 2, iSR * 2)
  GraphicsWindow.BrushColor = "DimGray"
  GraphicsWindow.FillEllipse(iBX1 + rCX * 2 + iSR / 2, iBY0 + idLY + iSR / 2, iSR / 2, iSR / 2)
  iBHX = iBX1 + rCX * 2 + iSR * 2.5
  iBHY = iBY0 + rCY * 2.5
  Shapes.Move(oPrisoner[BLACK], iBHX, iBHY)
  Shapes.ShowShape(oPrisoner[BLACK])
  iBLX = iBHX + rCX * 6
  iBLY = iBHY
  bOn = "True"
  iX = iBLX
  iY = iBLY
  DrawLamp()
  Controls.Move(oPlayer[BLACK], iBX1 + rCX * 2, iBY0)
  Controls.Move(oPlayer[WHITE], iBX1 + rCX * 2, iBY0 + idLY * iRo / 2)
  Controls.ShowControl(oPlayer[BLACK])
  Controls.ShowControl(oPlayer[WHITE])
  Controls.Move(oPass, iBX1 + rCX * 2, iBY0 + idLY * iRo)
  Controls.Move(oResign, iBX1 + rCX * 7, iBY0 + idLY * iRo)
  Controls.HideControl(oPass)
  Controls.HideControl(oResign)
  Controls.Move(oSGF, iBX1 + rCX * 2, iBY0 + idLY * iRo)
  Controls.ShowControl(oSGF)
  Controls.Move(oGame, iBX1 + rCX * 2, iBY0 + idLY * iRo + rCY * 2)
  Controls.Move(oOpen, iBX1 + rCX * 7, iBY0 + idLY * iRo + rCY * 2)
  Controls.Move(oNew, iBX1 + rCX * 2, iBY0 + idLY * iRo + rCY * 2)
  Controls.ShowControl(oGame)
  Controls.ShowControl(oOpen)
  Controls.HideControl(oNew)
  Controls.Move(oReplay, iBX1 + rCX * 7, iBY0 + idLY * iRo + rCY * 2)
  Controls.Move(oSave, iBX1 + rCX * 10, iBY0 + idLY * iRo + rCY * 2)
  Controls.HideControl(oReplay)
  Controls.HideControl(oSave)
  iWHX = iBX1 + rCX * 2 + iSR * 2.5
  iWHY = iBY0 + idLY * (iRo / 2) + rCY * 2.5
  Shapes.Move(oPrisoner[WHITE], iWHX, iWHY)
  Shapes.ShowShape(oPrisoner[WHITE])
  iWLX = iWHX + rCX * 6
  iWLY = iWHY
  bOn = "False"
  iX = iWLX
  iY = iWLY
  DrawLamp()
  GraphicsWindow.BrushColor = "#606060"
  GraphicsWindow.FillEllipse(iBX1 + rCX * 2 + idS, iBY0 + idLY * (iRo / 2 + 1) + idS, iSR * 2, iSR * 2)
  GraphicsWindow.BrushColor = sWhiteColor
  GraphicsWindow.FillEllipse(iBX1 + rCX * 2, iBY0 + idLY * (iRo / 2 + 1), iSR * 2, iSR * 2)
  GraphicsWindow.BrushColor = "White"
  GraphicsWindow.FillEllipse(iBX1 + rCX * 2 + iSR / 2, iBY0 + idLY * (iRo / 2 + 1) + iSR / 2, iSR / 2, iSR / 2)
  Controls.TextTyped = OnTextTyped
  Controls.HideControl(oSGF)
  Controls.HideControl(oGame)
  Controls.HideControl(oOpen)
  Controls.ShowControl(oPass)
  Controls.ShowControl(oResign)
EndSub

Sub DrawLamp
  ' Draw Lamp
  ' param iX, iY - position of lamp
  ' param bOn - lamp on
  sSavedColor = GraphicsWindow.BrushColor
  GraphicsWindow.BrushColor = "White"
  GraphicsWindow.FillRectangle(iX + 1, iY + 1, 21, 7)
  GraphicsWindow.BrushColor = "DimGray"
  GraphicsWindow.FillRectangle(iX - 2, iY - 2, 21, 7)
  If bOn Then
    GraphicsWindow.BrushColor = "Lime"
  Else
    GraphicsWindow.BrushColor = "Black"
  EndIf
  GraphicsWindow.FillRectangle(iX, iY, 20, 6)
  GraphicsWindow.BrushColor = sSavedColor
EndSub

' ---------------------------------
' AI (Artificial Intelligence)
' ---------------------------------
Sub CreateRdmArray
  ' Create Random Space Array
  ' param iBoard[][], iRo - board and number of ro (lines)
  ' work iRdmSeq, iX, iY - random sequence, stone position
  ' return iRdm[] - random space array
  ClearRdmArray()
  For iY = 1 To iRo
    For iX = 1 To iRo
      If iBoard[iX][iY] = SPACE Then
        iRdmSeq = (iY - 1) * iRo + iX
        AddNumToRdmArray()
      EndIf
    EndFor
  EndFor
EndSub

Sub AddNumToRdmArray
  ' Add Random Point to Random Space Array
  ' param iRdmSeq
  ' param/return iRdm[]
  ' work iCnt, iRdmIdx
  iRdmNum = Math.GetRandomNumber(iRdmSeq)
  iRdmIdx = 0
  For iCnt = 1 To iRdmNum - 1
    iRdmIdx = iRdm[iRdmIdx]
  EndFor
  iRdm[iRdmSeq] = iRdm[iRdmIdx]
  iRdm[iRdmIdx] = iRdmSeq
EndSub

Sub ClearRdmArray
  ' Clear Random Space Array
  ' return iRdm[]
  iRdm[0] = 0
EndSub

Sub CheckPossiblePut
  ' Check If Possible Move
  ' param iColor - stone color to check
  ' param iX, iY, iBoard[][] - check point and board
  ' param iKo, iKX, iKY - number of moves and point for ko
  ' param bEyes - save eyes (don't fill by self)
  ' return bPossiblePut - possible move
  bPossiblePut = "False"
  If iBoard[iX][iY] <> SPACE Then
    Goto lNotPossible ' stone already exists
  EndIf
  If iMove > 1 And iKo = iMove - 1 And iKX = iX And iKY = iY Then
    Goto lNotPossible ' need ko-date
  EndIf
  CheckSuiside()      ' check suiside
  If bSuiside Then
    Goto lNotPossible
  EndIf
  If bEyes Then       ' save eyes
    CheckMyEye()      ' check self eye
    If bMyEye Then    ' don't move into eye (except point to fill ko)
      If iMove = 1 Or iKo <> iMove - 2 Or iKX <> iX Or iKY <> iY Then
        Goto lNotPossible
      EndIf
    EndIf
  EndIf
  bPossiblePut = "True"
  lNotPossible:
EndSub

Sub CheckSuiside
  ' Check Suiside
  ' param iColor - stone color
  ' param iX, iY - check point
  ' param iBoard[][] - board
  ' param iRo, idX4[], idY4[] - number of ro (lines)、adjacent four points
  ' work iXSave, iYSave, iCSave
  ' return bSuiside - suiside move
  bSuiside = "False"
  iBoard[iX][iY] = iColor ' tempraly move
  iXSave = iX
  iYSave = iY
  InitLiberty()
  CountLiberty()          ' count liberty
  If iLiberty = 0 Then    ' may be suiside
    iCSave = iColor
    iColor = 3 - iColor   ' opposite stone
    For i = 1 To 4        ' if any stone adjacent can be captured
      iX = iXSave + idX4[i]
      iY = iYSave + idY4[i]
      If iX >= 1 And iX <= iRo And iY >= 1 And iY <= iRo And iBoard[iX][iY] = iColor Then
        InitLiberty()
        CountLiberty()    ' count liberty
        If iLiberty = 0 Then
          Goto lNotSuiside
        EndIf
      EndIf
    EndFor
    bSuiside = "True"
    lNotSuiside:
    iColor = iCSave
  EndIf
  iX = iXSave
  iY = iYSave
  iBoard[iX][iY] = SPACE  ' restore
EndSub

Sub Random
  ' Player | Next Move - Player Random (Computer)
  ' param iRdm[] - random space array
  ' param iMove - number of moves
  ' work iLast, iXY - last move, next Move
  ' return iX, iY - next move on board
  ' return iColor - stone color
  ' return iBoard[][] - board
  ' return bPass - pass
  ' return bResign - resign
  bPass = "False"
  bResign = "False"
  iLast = 0
  If iMove > iRo * iRo * 3 Then
    Goto lPassRandom
  EndIf
  While iRdm[iLast] > 0
    iXY = iRdm[iLast]
    iX = Math.Remainder(iXY - 1, iRo) + 1
    iY = Math.Floor((iXY - 1) / iRo) + 1
    iColor = Math.Remainder((iMove - 1), 2) + 1
    CheckPossiblePut()
    If bPossiblePut Then
      iBoard[iX][iY] = iColor
      iRdm[iLast] = iRdm[iXY] ' remove a pointe from random space array
      Goto lExitRandom
    EndIf
    iLast = iXY
  EndWhile
  lPassRandom:
  bPass = "True"
  lExitRandom:
EndSub

Sub RemoveRdmEntry
  ' Remove a point iXY from Random Space Array (when last move iLast is unknown)
  ' param iXY- index to remove entry
  ' work iCP
  iCPRRE = 0
  While iRdm[iCPRRE] > 0
    If iRdm[iCPRRE] = iXY Then
      iRdm[iCPRRE] = iRdm[iXY] ' remove a point from random space array
      Goto lRRE2Exit
    EndIf
    iCPRRE = iRdm[iCPRRE]
  EndWhile
  lRRE2Exit:
EndSub

Sub Human
  ' Player | Next Move by Human
  ' param/return iRdm[] - random space array
  ' param iMove - number of moves
  ' work iMX, iMY - mouse coordinate
  ' work bNotClicked - mouse / button not clicked
  ' return iX, iY - next move on board
  ' param/return iColor - stone color
  ' return iBoard[][] - board
  ' return bPass - pass
  ' return bResign - resign
  bPass = "False"
  bResign = "False"
  GraphicsWindow.MouseDown = OnMouseDown
  Controls.ButtonClicked = OnButtonClicked
  iColor = Math.Remainder((iMove - 1), 2) + 1
  While "True"
    bOutOfBoard = "True"
    While bOutOfBoard
      bNotClicked = "True"
      While bNotClicked
        Program.Delay(200)
      EndWhile
      If bPass Or bResign Then
        Goto lPossiblePut
      EndIf
      GetPosition()
    EndWhile
    CheckPossiblePut()
    If bPossiblePut Then
      Goto lPossiblePut
    EndIf
    If bSound Then
      Sound.PlayChimeAndWait()
    EndIf
  EndWhile
  lPossiblePut:
  GraphicsWindow.MouseDown = DoNothing
  Controls.ButtonClicked = DoNothing
  If bPass = "False" And bResign = "False" Then
    iBoard[iX][iY] = iColor
    iXY = (iY - 1) * iRo + iX
    RemoveRdmEntry()  ' remove a point from random space array
  EndIf
EndSub

Sub OnMouseDown
  ' Mouse Down Event Handler
  ' return iMX, iMY - mouse coordinate
  ' return bNotClicked - mouse / button not clicked
  iMX = GraphicsWindow.MouseX
  iMY = GraphicsWindow.MouseY
  bNotClicked = "False"
EndSub

Sub OnButtonClicked
  ' Button Clicked Event Handler
  ' return bPass, bResign - pass, resign
  ' return bNotClicked - mouse / button not clicked
  If Controls.LastClickedButton = oResign Then
    bResign = "True"
    bNotClicked = "False"
  ElseIf Controls.LastClickedButton = oPass Then
    bPass = "True"
    bNotClicked = "False"
  EndIf
EndSub

Sub GetPosition
  ' Get Board Point from Mouse Clicked Coordinate
  ' param iMX, iMY - mouse coodinate
  ' return iX, iY - point on board
  ' return bOutOfBoard - "True" if clicked out of board
  iX = Math.Floor((iMX - iLX0 + idLX / 2) / idLX) + 1
  iY = Math.Floor((iMY - iLY0 + idLY / 2) / idLY) + 1
  If iX < 1 Or iX > iRo Or iY < 1 Or iY > iRo Then
    bOutOfBoard = "True"
  Else
    bOutOfBoard = "False"
  EndIf
EndSub

Sub DoNothing
  ' Do Nothing for Event
EndSub

Sub Replay
  ' Player | Next Move by Game Record - Replay
  ' param iMove - number of moves
  ' param iRecord - game record
  ' param iNumRec - number of moves in game record
  ' return iX, iY - next move on board
  ' return iColor - stone color
  ' return iBoard[][] - board
  ' return bPass - pass
  ' return bResign - resign
  If iMove > iNumRec Then
    bResign = "True"
  Else
    iColor = iRecord[iMove]["turn"]
    iX = iRecord[iMove]["x"]
    iY = iRecord[iMove]["y"]
    If iX = iRo + 1 Then
      bPass = "True"
    Else
      iBoard[iX][iY] = iColor
      bPass = "False"
    EndIf
  EndIf
  Program.Delay(200)
EndSub

' ---------------------------------
' Game
' ---------------------------------
Sub InputGameInfo
  ' New Game Mode - Input Player Name (or Game Record Name)
  ' return bShowMove - show number of moves
  ' return bInGame - in game
  ' return bReplay - replay mode
  ' work bNotClicked
  bShowMove = "False"
  bInGame = "True"
  bReplay = "False"
  bResign = "False"
  GraphicsWindow.Title = sProgram + " " + sVersion
  Controls.ShowControl(oGame)
  Controls.ShowControl(oOpen)
  Controls.ShowControl(oSGF)
  Controls.HideControl(oPass)
  Controls.HideControl(oResign)
  Controls.ButtonClicked = OnButtonClicked1
  bNotClicked = "True"
  If bAuto Then
    bNotClicked = "False" ' for automatic game
    bOpen = "False"       ' for automatic game
  EndIf
  While bNotClicked
    Program.Delay(200)
  EndWhile
  Controls.HideControl(oGame)
  Controls.HideControl(oOpen)
  Controls.HideControl(oSGF)
  Controls.ShowControl(oPass)
  Controls.ShowControl(oResign)
EndSub

Sub OnTextTyped
  ' TextBox Event Handler
  ' return sPlayer[BLACK] - black player name
  ' return sPlayer[WHITE] - white player name
  ' return sSGF - SGF file name
  If Controls.LastTypedTextBox = oPlayer[BLACK] Then
    sPlayer[BLACK] = Controls.GetTextBoxText(oPlayer[BLACK])
  ElseIf Controls.LastTypedTextBox = oPlayer[WHITE] Then
    sPlayer[WHITE] = Controls.GetTextBoxText(oPlayer[WHITE])
  ElseIf Controls.LastTypedTextBox = oSGF Then
    sSGF = Controls.GetTextBoxText(oSGF)
  EndIf
EndSub

Sub OnButtonClicked1
  ' Button Clicked Event for New Game Mode
  ' return bNotClicked
  ' return bOpen
  If Controls.LastClickedButton = oGame Then
    bNotClicked = "False"
    bOpen = "False"
  ElseIf Controls.LastClickedButton = oOpen Then
    bNotClicked = "False"
    bOpen = "True"
  EndIf
EndSub

Sub InputGameEndInfo
  ' Game End Mode - Replay, Save or New Button Input
  ' return bShowMove - show number of moves
  ' return bInGame - in game
  ' return bReplay - replay mode
  ' return bSave - save
  ' return bResign - resign
  bShowMove = "True"
  bInGame = "True"
  bReplay = "False"
  bSave = "False"
  bResign = "False"
  Controls.HideControl(oPass)
  Controls.HideControl(oResign)
  Controls.ShowControl(oNew)
  Controls.ShowControl(oReplay)
  Controls.ShowControl(oSave)
  Controls.ShowControl(oSGF)
  Controls.ButtonClicked = OnButtonClicked2
  bNotClicked = "True"
  If bAuto Then
    bNotClicked = "False" ' for automatic game
    bOpen = "False"       ' for automatic game
    bSave = "False"       ' for automatic game
    bReplay = "False"     ' for automatic game
    bInGame = "False"     ' for automatic game
  EndIf
  While bNotClicked
    Program.Delay(200)
  EndWhile
  Controls.HideControl(oNew)
  Controls.HideControl(oReplay)
  Controls.HideControl(oSave)
  Controls.HideControl(oSGF)
EndSub

Sub OnButtonClicked2
  ' Button Event Handler for Game End Mode
  ' return bInGame - in game
  ' return bReplay - replay mode
  ' return bSave - Save
  ' return bNotClicked
  If Controls.LastClickedButton = oNew Then
    bNotClicked = "False"
    bSave = "False"
    bReplay = "False"
    bInGame = "False"
  ElseIf Controls.LastClickedButton = oSave Then
    bNotClicked = "False"
    bSave = "True"
    bReplay = "False"
    bInGame = "True"
  ElseIf Controls.LastClickedButton = oReplay Then
    If iNumRec > 0 Then
      bNotClicked = "False"
      bReplay = "True"
      bSave = "False"
      bInGame = "True"
    Else
      If bSound Then
        Sound.PlayChimeAndWait()
      EndIf
    EndIf
  EndIf
EndSub

Sub RemoveUnit
  ' Remove Unit
  ' param iUnit, iUX[], iUY[] - unit
  ' param bShow - show
  ' work i, iX, iY - stone position
  ' return iBoard[][] - board
  For i = 1 To iUnit
    iX = iUX[i]
    iY = iUY[i]
    iBoard[iX][iY] = SPACE
    iRdmSeq = (iY - 1) * iRo + iX
    AddNumToRdmArray()  ' add unit to random space array
    If bShow Then
      EraseStone()
    EndIf
  EndFor
EndSub

Sub InitLiberty
  ' Initialization to prepare counting liberty
  ' return iLiberty - number of liberty
  ' return bNotChecked[][] - not checked point
  ' return iUnit - number of stones in unit
  ' work iXL, iYL
  For iXL = 0 To iRo + 1
    For iYL = 0 To iRo + 1
      bNotChecked[iXL][iYL] = "True"
    EndFor
  EndFor
  iLiberty = 0
  iUnit = 0
EndSub

Sub CountLiberty
  ' Count Liberty in Unit
  ' param iBoard[][] - board
  ' param iColor - start point stone color in unit
  ' param/return bNotChecked[][] - flag not checked point
  ' param/return iX, iY - start point in unit
  ' param/return iLiberty - number of liberty
  ' work iXSave, iYSave, i
  ' return iUX[], iUY[] - unit
  ' return iUnit - number of stones in unit
  Stack.PushValue("liberty", iXSave)
  Stack.PushValue("liberty", iYSave)
  Stack.PushValue("liberty", i)
  iXSave = iX
  iYSave = iY
  If bNotChecked[iX][iY] Then
    bNotChecked[iX][iY] = "False"
    If iBoard[iX][iY] = SPACE Then
      iLiberty = iLiberty + 1
    ElseIf iBoard[iX][iY] = iColor Then
      iUnit = iUnit + 1
      iUX[iUnit] = iX
      iUY[iUnit] = iY
      For i = 1 To 4
        iX = iXSave + idX4[i]
        iY = iYSave + idY4[i]
        CountLiberty()
      EndFor
    EndIf
  EndIf
  i = Stack.PopValue("liberty")
  iYSave = Stack.PopValue("liberty")
  iXSave = Stack.PopValue("liberty")
EndSub

Sub CheckSpaceUnitInTerritory
  ' Check Space Unit In Territory
  ' param iTerritory[][] - territory
  ' param/return bNotChecked[][] - not checked point flag
  ' param/return iX, iY - start point in unit
  ' param/return iColor - enclosing stones color
  ' work iXSave, iYSave
  ' return iUX[], iUY[] - unit
  ' return iUnit - number of stones in unit
  Stack.PushValue("space", iXSave)
  Stack.PushValue("space", iYSave)
  Stack.PushValue("space", i)
  iXSave = iX
  iYSave = iY
  If bNotChecked[iX][iY] Then
    bNotChecked[iX][iY] = "False"
    If iTerritory[iX][iY] = SPACE Then
      iUnit = iUnit + 1
      iUX[iUnit] = iX
      iUY[iUnit] = iY
      For i = 1 To 4
        iX = iXSave + idX4[i]
        iY = iYSave + idY4[i]
        CheckSpaceUnitInTerritory()
      EndFor
    ElseIf iTerritory[iX][iY] = BLACK Then
      If iColor = SPACE Then
        iColor = BLACK
      ElseIf iColor = WHITE Then
        iColor = BANDW
      EndIf
    ElseIf iTerritory[iX][iY] = WHITE Then
      If iColor = SPACE Then
        iColor = WHITE
      ElseIf iColor = BLACK Then
        iColor = BANDW
      EndIf
    EndIf
  EndIf
  i = Stack.PopValue("space")
  iYSave = Stack.PopValue("space")
  iXSave = Stack.PopValue("space")
EndSub

Sub CheckSpaceUnit
  ' Check Space Unit
  ' param iBoard[][] - board
  ' param/return bNotChecked[][] - not checked point flag
  ' param/return iX, iY - start point in unit
  ' param/return iColor - enclosing stones color (default = SPACE)
  ' work iXSave, iYSave
  ' return iUX[], iUY[] - unit
  ' return iUnit - number of stones in unit
  Stack.PushValue("space", iXSave)
  Stack.PushValue("space", iYSave)
  Stack.PushValue("space", i)
  iXSave = iX
  iYSave = iY
  If bNotChecked[iX][iY] Then
    bNotChecked[iX][iY] = "False"
    If iBoard[iX][iY] = SPACE Then
      iUnit = iUnit + 1
      iUX[iUnit] = iX
      iUY[iUnit] = iY
      For i = 1 To 4
        iX = iXSave + idX4[i]
        iY = iYSave + idY4[i]
        CheckSpaceUnit()
      EndFor
    ElseIf iBoard[iX][iY] = BLACK Then
      If iColor = SPACE Then
        iColor = BLACK
      ElseIf iColor = WHITE Then
        iColor = BANDW
      EndIf
    ElseIf iBoard[iX][iY] = WHITE Then
      If iColor = SPACE Then
        iColor = WHITE
      ElseIf iColor = BLACK Then
        iColor = BANDW
      EndIf
    EndIf
  EndIf
  i = Stack.PopValue("space")
  iYSave = Stack.PopValue("space")
  iXSave = Stack.PopValue("space")
EndSub

Sub CheckMyEye
  ' Check (Single) Self Eye
  ' param iBoard[][] - board
  ' param iX, iY - check point
  ' param iColor - stone color
  ' param idX4[], idY4[] - four direction
  ' work iX1, iY1, iC1 - one of four adjacent stones
  ' return bMyEye - is self eye
  bMyEye = "False"
  If iBoard[iX][iY] = SPACE Then
    For i = 1 To 4
      iX1 = iX + idX4[i]
      iY1 = iY + idY4[i]
      iC1 = iBoard[iX1][iY1]
      If iC1 = 3 - iColor Or iC1 = SPACE Then ' opposite stone or space
        Goto lNotMyEye
      EndIf
    EndFor
  EndIf
  bMyEye = "True"
  lNotMyEye:
EndSub

Sub CheckEye
  ' Check (Single) Eye
  ' param iBoard[][] - board
  ' param iX, iY - check point
  ' param idX4[], idY4[] - four direction
  ' work iX1, iY1, iC1 - one of four adjacent stones
  ' return iColor - stone color
  If iBoard[iX][iY] = SPACE Then
    iColor = SPACE
    For i = 1 To 4
      iX1 = iX + idX4[i]
      iY1 = iY + idY4[i]
      iC1 = iBoard[iX1][iY1]
      If iC1 = SPACE Then
        iColor = SPACE
        Goto lCExit
      ElseIf iC1 <> OB Then
        If iColor = 3 - iC1 Then
          iColor = SPACE
          Goto lCExit
        EndIf
        iColor = iC1
      EndIf
    EndFor
  EndIf
  lCExit:
EndSub

Sub Judge
  ' Game End Judgement
  ' param iPass - pass times
  ' param bShow - show result
  ' return bInGame - in game
  ' return sScore - score
  bInGame = "True"
  If iPass >= 2 Then
    bInGame = "False"
    CountScore()            ' judge win or lose
    If bEasy = "False" Then
      AdjustTerritory()     ' adjust territory
    EndIf
    iScore = iScore + rKomi ' calculate komi
    If bShow Then
      DrawTerritory()       ' draw territory
      XDeadStones()         ' mark x on dead stones
      If iScore > 0 Then
        sScore = "B+" + iScore
        GraphicsWindow.Title = sProgram + " " + sVersion + " - Black wins by " + iScore + " points"  '" - 黒の" + iScore + "目勝ち"
      ElseIf iScore < 0 Then
        sScore = "W+" + (-iScore)
        GraphicsWindow.Title = sProgram + " " + sVersion + " - White wins by " + iScore + " points"  '" - 白の" + (-iScore) + "目勝ち"
      Else  ' iScore = 0
        sScore = "0"
        GraphicsWindow.Title = sProgram + " " + sVersion + " - Draw (jigo)"  '" - 引き分け(持碁)"
      EndIf
    EndIf
  EndIf
EndSub

Sub CountScore
  ' Judgement Win or Lose
  ' param iPrisoner[] - number of prisoners
  ' work iBlackScore, iWhiteScore - number of territory
  ' return iTerritory[][] - territory
  ' return iScore - returns black stones - white stones
  EvalBoard()     ' recognize territory
  iBlackScore = iBlackScore + iPrisoner[BLACK]  ' add prisoners
  iWhiteScore = iWhiteScore + iPrisoner[WHITE]  ' add prisoners
  iBlackScore = iBlackScore + iDead[WHITE]      ' add dead stones
  iWhiteScore = iWhiteScore + iDead[BLACK]      ' add dead stones
  iScore = iBlackScore - iWhiteScore
EndSub

Sub AdjustTerritory
  ' Adjust Territory
  ' param/return iTerritory[][] - territory
  ' param/return iBlackScore, iWhiteScore - number of territory
  ' return iScore - returns black stones - white stones
  ' add space enclosed by one's stones to iTerritory[][]
  For iY = 1 To iRo
    For iX = 1 To iRo
      If iTerritory[iX][iY] = SPACE Then
        InitLiberty()
        iColor = SPACE
        iXSave = iX
        iYSave = iY
        CheckSpaceUnitInTerritory()
        iX = iXSave
        iY = iYSave
        If iColor = BLACK Then
          For i = 1 To iUnit
            iTerritory[iUX[i]][iUY[i]] = BLACK
          EndFor
          iBlackScore = iBlackScore + iUnit
        ElseIf iColor = WHITE Then
          For i = 1 To iUnit
            iTerritory[iUX[i]][iUY[i]] = WHITE
          EndFor
          iWhiteScore = iWhiteScore + iUnit
        EndIf
      EndIf
    EndFor  ' iX
  EndFor  ' iY
  iScore = iBlackScore - iWhiteScore
EndSub

Sub EvalBoard
  ' Evaluate Board
  ' work iX, iY, i - stone position, index of unit
  ' work iBlackEffect[][] - black effective region
  ' work iWhiteEffect[][] - white effective region
  ' return iDead[], iDeadSum - number of dead stones
  ' return iDX[], iDY[] - dead stones
  ' return iTerritory[][] - territory
  ' return iBlackScore - black territory
  ' return iWhiteScore - white territory
  iCSave = iColor
  If bEasy Then
    For iY = 1 To iRo
      For iX = 1 To iRo
        If iBoard[iX][iY] = SPACE Then
          ' add single eye into score as territory
          CheckEye()
          If iColor = BLACK Then
            iBlackScore = iBlackScore + 1
          ElseIf iColor = WHITE Then
            iWhiteScore = iWhiteScore + 1
          EndIf
        EndIf
      EndFor  ' iX
    EndFor  ' iY
  Else
    iDead[BLACK] = 0
    iDead[WHITE] = 0
    iDeadSum = 0
    For iY = 1 To iRo
      For iX = 1 To iRo
        iBlackEffect[iX][iY] = 0
        iWhiteEffect[iX][iY] = 0
        iTerritory[iX][iY] = SPACE
      EndFor
    EndFor
    SaveBoard()
    ' remove unit which iLiberty = 1 from iBoard[][], and momory as dead stones
    For iY = 1 To iRo
      For iX = 1 To iRo
        If iBoard[iX][iY] <> SPACE Then
          iColor = iBoard[iX][iY]
          iXSave = iX
          iYSave = iY
          InitLiberty()
          CountLiberty()
          If iLiberty = 1 Then
            For i = 1 To iUnit
              iX = iUX[i]
              iY = iUY[i]
              iBoard[iX][iY] = SPACE
              iDeadSum = iDeadSum + 1
              iDX[iDeadSum] = iX
              iDY[iDeadSum] = iY
            EndFor
            iDead[iColor] = iDead[iColor] + iUnit
          EndIf
          iX = iXSave
          iY = iYSave
        EndIf
      EndFor  ' iX
    EndFor  ' iY
    ' calculate stone effective region
    For iY = 1 To iRo
      For iX = 1 To iRo
        If iBoard[iX][iY] = BLACK Then
          SetBlackEffect()
        ElseIf iBoard[iX][iY] = WHITE Then
          SetWhiteEffect()
        EndIf
      EndFor
    EndFor
    iBlackScore = 0 ' to count black territory
    iWhiteScore = 0 ' to count white territory
    For iY = 1 To iRo
      For iX = 1 To iRo
        If iBoard[iX][iY] = BLACK Then
          iTerritory[iX][iY] = BLACK
        ElseIf iBoard[iX][iY] = WHITE Then
          iTerritory[iX][iY] = WHITE
        Else
          If iBlackEffect[iX][iY] > iWhiteEffect[iX][iY] Then
            iTerritory[iX][iY] = BLACK
            iBlackScore = iBlackScore + 1
          ElseIf iBlackEffect[iX][iY] < iWhiteEffect[iX][iY] Then
            iTerritory[iX][iY] = WHITE
            iWhiteScore = iWhiteScore + 1
          EndIf
        EndIf
      EndFor
    EndFor
    RestoreBoard()
  EndIf
  iColor = iCSave
EndSub

Sub SaveBoard
  ' Save Board for Evaluating Board
  ' param iRo - number of ro (lines)
  ' param iBoard[][] - board
  ' work iX, iY - stone position
  ' return iSaved[][] - saved board
  For iY = 1 To iRo
    For iX = 1 To iRo
      iSaved[iX][iY] = iBoard[iX][iY]
    EndFor
  EndFor
EndSub

Sub RestoreBoard
  ' Restore Board for Evaluating Board
  ' param iRo - number of ro (lines)
  ' param iSaved[] - saved board
  ' work iX, iY - stone position
  ' return iBoard[] - (restored) board
  For iY = 1 To iRo
    For iX = 1 To iRo
      iBoard[iX][iY] = iSaved[iX][iY]
    EndFor
  EndFor
EndSub

Sub SaveGameProperties
  ' Save Game Properties
  ' param iKo, iKX, iKY - ko
  ' param iPrisoner[] - prisoner
  ' param iPass - pass times
  ' return iSKo, iSKX, iSKY - saved ko
  ' return iSPrisoner[] - saved prisoner
  ' return iSPass - saved pass times
  iSKo = iKo
  iSKX = iKX
  iSKY = iKY
  iSPrisoner[BLACK] = iPrisoner[BLACK]
  iSPrisoner[WHITE] = iPrisoner[WHITE]
  iSPass = iPass
EndSub

Sub RestoreGameProperties
  ' Restore Game Properties
  ' param iSKo, iSKX, iSKY - saved ko
  ' param iSPrisoner[] - saved prisoner
  ' param iSPass - saved pass times
  ' return iKo, iKX, iKY - ko
  ' return iPrisoner[] - prisoner
  ' return iPass - pass times
  iKo = iSKo
  iKX = iSKX
  iKY = iSKY
  iPrisoner[BLACK] = iSPrisoner[BLACK]
  iPrisoner[WHITE] = iSPrisoner[WHITE]
  iPass = iSPass
EndSub

Sub Init4
  ' Initialize delta of four direction
  ' return idX4[] - four delta of coordinate
  idX4[1] =  1  ' right
  idY4[1] =  0
  idX4[2] =  0  ' up
  idY4[2] = -1
  idX4[3] = -1  ' left
  idY4[3] =  0
  idX4[4] =  0  ' down
  idY4[4] =  1
EndSub

Sub InitEffect
  ' Initialize Coodinate Delta for Effective Region (Distance 2)
  ' return idXE[], idYE[] - coodinate delta for effective region
  idXE[1] =  0  ' top most
  idYE[1] = -2
  idXE[2] = -1  ' left top
  idYE[2] = -1
  idXE[3] =  0  ' top
  idYE[3] = -1
  idXE[4] =  1  ' right top
  idYE[4] = -1
  idXE[5] = -2  ' left most
  idYE[5] =  0
  idXE[6] = -1  ' left
  idYE[6] =  0
  idXE[7] =  0  ' center
  idYE[7] =  0
  idXE[8] =  1  ' right
  idYE[8] =  0
  idXE[9] =  2  ' right most
  idYE[9] =  0
  idXE[10] = -1 ' left bottom
  idYE[10] =  1
  idXE[11] =  0 ' bottom
  idYE[11] =  1
  idXE[12] =  1 ' right bottom
  idYE[12] =  1
  idXE[13] =  0 ' bottom most
  idYE[13] =  2
EndSub

Sub SetBlackEffect
  For i = 1 To 13
    iXE = iX + idXE[i]
    iYE = iY + idYE[i]
    If iXE > 0 And iXE <= iRo And iYE > 0 And iYE <= iRo Then
      iBlackEffect[iXE][iYE] = iBlackEffect[iXE][iYE] + 1
    EndIf
  EndFor
EndSub
'
Sub SetWhiteEffect
  For i = 1 To 13
    iXE = iX + idXE[i]
    iYE = iY + idYE[i]
    If iXE > 0 And iXE <= iRo And iYE > 0 And iYE <= iRo Then
      iWhiteEffect[iXE][iYE] = iWhiteEffect[iXE][iYE] + 1
    EndIf
  EndFor
EndSub

Sub InitBoard
  ' Initialize Board
  ' param iRo - number of ro (lines)
  ' param rCX - character width
  ' param rCY - character height
  ' work i, iX, iY - stone position
  ' return iBoard[][] - board
  ' return idLX, idLY - duration between lines
  ' return iSR - radius of stone
  ' return iLX0, iLY0, iLX1, iLY1 - left, top, right, bottom of lines
  ' return iBX0, iBY0, iBX1, iBY1 - left, top, right, bottom of board
  ' return iPrisoner[] - prisoner
  For i = 0 To iRo + 1
    iBoard[0][i] = OB
    iBoard[iRo + 1][i] = OB
    iBoard[i][0] = OB
    iBoard[i][iRo + 1] = OB
  EndFor
  For iY = 1 To iRo
    For iX = 1 To iRo
      If oShadow[iX][iY] <> "" Then
        Shapes.Remove(oShadow[iX][iY])
      EndIf
      If oBlack[iX][iY] <> "" Then
        Shapes.Remove(oBlack[iX][iY])
      EndIf
      If oWhite[iX][iY] <> "" Then
        Shapes.Remove(oWhite[iX][iY])
      EndIf
      If oHiLite[iX][iY] <> "" Then
        Shapes.Remove(oHiLite[iX][iY])
      EndIf
      If oMove[iX][iY] <> "" Then
        Shapes.Remove(oMove[iX][iY])
      EndIf
      If oX1[iX][iY] <> "" Then
        Shapes.Remove(oX1[iX][iY])
      EndIf
      If oX2[iX][iY] <> "" Then
        Shapes.Remove(oX2[iX][iY])
      EndIf
      If oRect[iX][iY] <> "" Then
        Shapes.Remove(oRect[iX][iY])
      EndIf
    EndFor
  EndFor
  oShadow = ""            ' shadow shape
  oBlack = ""             ' black stone shape
  oWhite = ""             ' white stone shape
  oHiLite = ""            ' stone high light shape
  oMove = ""              ' stone shape
  oX1 = ""                ' one of line in X for dead stone
  oX2 = ""                ' one of line in X for dead stone
  oRect = ""              ' territory rectangle
  idS = 3                 ' offset of shadow
  GraphicsWindow.PenWidth = 0
  For iY = 1 To iRo
    For iX = 1 To iRo
      bd[x][y] = SPACE
      iSX = iLX0 + (iX - 1) * idLX - iSR
      iSY = iLY0 + (iY - 1) * idLY - iSR
      GraphicsWindow.BrushColor = "Black"     ' shadow color
      oShadow[iX][iY] = Shapes.AddEllipse(2 * iSR, 2 * iSR)
      Shapes.Move(oShadow[iX][iY], iSX + idS, iSY + idS)
      Shapes.SetOpacity(oShadow[iX][iY], 50)
      Shapes.HideShape(oShadow[iX][iY])
      GraphicsWindow.BrushColor = "Black"     ' black stone color
      oBlack[iX][iY] = Shapes.AddEllipse(2 * iSR, 2 * iSR)
      Shapes.Move(oBlack[iX][iY], iSX, iSY)
      Shapes.HideShape(oBlack[iX][iY])
      GraphicsWindow.BrushColor = sWhiteColor ' white stone color
      oWhite[iX][iY] = Shapes.AddEllipse(2 * iSR, 2 * iSR)
      Shapes.Move(oWhite[iX][iY], iSX, iSY)
      Shapes.HideShape(oWhite[iX][iY])
      GraphicsWindow.BrushColor = "White"     ' high light color
      oHilite[iX][iY] = Shapes.AddEllipse(iSR / 2, iSR / 2)
      Shapes.Move(oHilite[iX][iY], iSX + iSR / 2, iSY + iSR / 2)
      Shapes.HideShape(oHilite[iX][iY])
    EndFor
  EndFor
  GraphicsWindow.PenWidth = 2
EndSub

Sub ClearBoard
  ' Clear Board
  ' param iRo - number of ro (lines)
  ' work i, iX, iY - stone position
  ' return iBoard[][] - board
  ' return iPrisoner[] - prisoner
  For iX = 1 To iRo
    For iY = 1 To iRo
      iBoard[iX][iY] = SPACE
    EndFor
  EndFor
  iPrisoner[BLACK] = 0
  iPrisoner[WHITE] = 0
  Controls.SetTextBoxText(oPrisoner[BLACK], 0)
  Controls.SetTextBoxText(oPrisoner[WHITE], 0)
EndSub

' ---------------------------------
' Graphics
' ---------------------------------
Sub ClearGBoard
  ' Clear Graphics Board
  ' param idLX, idLY - duration between lines
  ' param iSR - radius of stone
  ' param iLX0, iLY0, iLX1, iLY1 - left, top, right, bottom of lines
  ' param iBX0, iBY0, iBX1, iBY1 - left, top, right, bottom of board
  ' work iX, iY - stone position

  For iY = 1 To iRo
    For iX = 1 To iRo
      If oShadow[iX][iY] <> "" Then
        Shapes.HideShape(oShadow[iX][iY])
      EndIf
      If oBlack[iX][iY] <> "" Then
        Shapes.HideShape(oBlack[iX][iY])
      EndIf
      If oWhite[iX][iY] <> "" Then
        Shapes.HideShape(oWhite[iX][iY])
      EndIf
      If oHiLite[iX][iY] <> "" Then
        Shapes.HideShape(oHiLite[iX][iY])
      EndIf
      If oMove[iX][iY] <> "" Then
        Shapes.Remove(oMove[iX][iY])
      EndIf
      If oX1[iX][iY] <> "" Then
        Shapes.Remove(oX1[iX][iY])
      EndIf
      If oX2[iX][iY] <> "" Then
        Shapes.Remove(oX2[iX][iY])
      EndIf
      If oRect[iX][iY] <> "" Then
        Shapes.Remove(oRect[iX][iY])
      EndIf
    EndFor
  EndFor
  oMove = ""              ' stone shape
  oX1 = ""                ' one of line in X for dead stone
  oX2 = ""                ' one of line in X for dead stone
  oRect = ""              ' territory rectangle
EndSub

Sub InitGBoard
  ' Initialize Graphics Board
  ' param idLX, idLY - duration between lines
  ' param iSR - radius of stone
  ' param iLX0, iLY0, iLX1, iLY1 - left, top, right, bottom of lines
  ' param iBX0, iBY0, iBX1, iBY1 - left, top, right, bottom of board
  ' work iX, iY - stone position

  ClearGBoard()

  ' resize GraphicsWindow
  If iBX1 + 5.3 * idLX < iGW And GraphicsWindow.Width <> iGW Then
    GraphicsWindow.Width = iGW
  ElseIf GraphicsWindow.Width <> iBX1 + 5.3 * idLX Then
    GraphicsWindow.Width = iBX1 + 5.3 * idLX
  EndIf
  If iBY1 + idLY < iGH And GraphicsWindow.Height <> iGH Then
    GraphicsWindow.Height = iGH
  ElseIf GraphicsWindow.Height <> iBY1 + idLY Then
    GraphicsWindow.Height = iBY1 + idLY
  EndIf

  ' fill board color
  GraphicsWindow.BrushColor = sBoardColor
  GraphicsWindow.FillRectangle(iBX0, iBY0, iBX1 - iBX0, iBY1 - iBY0)

  ' draw board shadow
  iPW = GraphicsWindow.PenWidth
  GraphicsWindow.BrushColor = "Black"
  GraphicsWindow.PenWidth = 0
  idS = 10
  If oSh1 <> "" Then
    Shapes.Remove(oSh1)
  EndIf
  oSh1 = Shapes.AddTriangle(0, 0, 0, idS, idS, idS)
  Shapes.SetOpacity(oSh1, 50)
  Shapes.Move(oSh1, iBX1, iBY0)
  If oSh2 <> "" Then
    Shapes.Remove(oSh2)
  EndIf
  oSh2 = Shapes.AddTriangle(0, 0, idS, 0, idS, idS)
  Shapes.SetOpacity(oSh2, 50)
  Shapes.Move(oSh2, iBX0, iBY1)
  If oSh3 <> "" Then
    Shapes.Remove(oSh3)
  EndIf
  oSh3 = Shapes.AddRectangle(idS, iBY1 - iBY0)
  Shapes.SetOpacity(oSh3, 50)
  Shapes.Move(oSh3, iBX1, iBY0 + idS)
  If oSh4 <> "" Then
    Shapes.Remove(oSh4)
  EndIf
  oSh4 = Shapes.AddRectangle(iBX1 - iBX0 - idS, idS)
  Shapes.SetOpacity(oSh4, 50)
  Shapes.Move(oSh4, iBX0 + idS, iBY1)

  ' draw wood grain
  rgb = GraphicsWindow.GetColorFromRGB(192, 153, 86)
  GraphicsWindow.PenColor = rgb   ' wood grain color
  GraphicsWindow.PenWidth = 1
  xc = iBX0 + Math.Floor((iBX1 - iBX0) * 5 / 7)  ' center of wood grain
  yc = iBY0 + Math.Floor((iBY1 - iBY0) * 5 / 4)
  For rw = 5 To 460 Step 5
    xo = xc + rw
    yo = yc
    For theta = 0 To 2 * Math.Pi / 19 * 19 Step 2 * Math.Pi / 19
      xw = xc + Math.Floor(rw * Math.Cos(theta))
      yw = yc + 13 * Math.Floor(rw * Math.Sin(theta))
      xw0 = xo
      xw1 = xw
      yw0 = yo
      yw1 = yw
      If (yw1 < iBY0) And (iBY0 < yw0) Then     ' clipping on top edge
        xw1 = xw0 + Math.Floor((xw1 - xw0) * (iBY0 - yw0) / (yw1 - yw0))
        yw1 = iBY0
      ElseIf (yw0 < iBY0) And (iBY0 < yw1) Then ' clipping on top edge
        xw0 = xw1 + Math.Floor((xw0 - xw1) * (iBY0 - yw1) / (yw0 - yw1))
        yw0 = iBY0
      EndIf
      If (yw1 < iBY1) And (iBY1 < yw0) Then     ' clipping on bottom edge
        xw0 = xw1 + Math.Floor((xw0 - xw1) * (iBY1 - yw1) / (yw0 - yw1))
        yw0 = iBY1
      ElseIf (yw0 < iBY1) And (iBY1 < yw1) Then ' clipping on bottom edge
        xw1 = xw0 + Math.Floor((xw1 - xw0) * (iBY1 - yw0) / (yw1 - yw0))
        yw1 = iBY1
      EndIf
      If (xw1 < iBX0) And (iBX0 < xw0) Then     ' clipping on left edge
        xw1 = iBX0
        yw1 = yw0 + Math.Floor((yw1 - yw0) * (iBX0 - xw0) / (xw1 - xw0))
      ElseIf (xw0 < iBX0) And (iBX0 < xw1) Then ' clipping on left edge
        xw0 = iBX0
        yw0 = yw1 + Math.Floor((yw0 - yw1) * (iBX0 - xw1) / (xw0 - xw1))
      EndIf
      If (xw1 < iBX1) And (iBX1 < xw0) Then     ' clipping on rigt edge
        xw0 = iBX1
        yw0 = yw1 + Math.Floor((yw0 - yw1) * (iBX1 - xw1) / (xw0 - xw1))
      ElseIf (xw0 < iBX1) And (iBX1 < xw1) Then ' clipping on right edge
        xw1 = iBX1
        yw1 = yw0 + Math.Floor((yw1 - yw0) * (iBX1 - xw0) / (xw1 - xw0))
      EndIf
      If (iBX0 <= xw0) And (xw0 <= iBX1) And (iBX0 <= xw1) And (xw1 <= iBX1) And (iBY0 <= yw0) And (yw0 <= iBY1) And (iBY0 <= yw1) And (yw1 <= iBY1) Then
        GraphicsWindow.DrawLine(xw0, yw0, xw1, yw1)
      EndIf
      xo = xw
      yo = yw
    EndFor
  EndFor

  ' draw frame
  GraphicsWindow.PenWidth = 4
  GraphicsWindow.DrawRectangle(iLX0, iLY0, idLX * (iRo - 1), idLY * (iRo - 1))
  GraphicsWindow.PenWidth = iPW

  ' draw lines
  GraphicsWindow.PenColor = "Black"
  For iX = iLX0 To iLX1 Step idLX
    GraphicsWindow.DrawLine(iX, iLY0, iX, iLY1)
  EndFor
  For iY = iLY0 To iLY1 Step idLY
    GraphicsWindow.DrawLine(iLX0, iY, iLX1, iY)
  EndFor

  ' draw stars
  If Math.Remainder(iRo, 2) = 1 Then  ' tengen (center)
    GraphicsWindow.BrushColor = "Black"
    GraphicsWindow.PenWidth = 0
    iRadius = 4
    iPos["col"] = Math.Floor(iRo / 2) + 1
    iPos["row"] = Math.Floor(iRo / 2) + 1
    DrawStar()
  EndIf
  If iRo = 9 Then                     ' 3-3 stars
    iPos = "col=3;row=3;"
    DrawStar()
    iPos["col"] = iRo - 2
    DrawStar()
    iPos["row"] = iRo - 2
    DrawStar()
    iPos["col"] = 3
    DrawStar()
  EndIf
  If iRo = 13 Or iRo = 19 Then        ' 4-4 stars
    iPos = "col=4;row=4;"
    DrawStar()
    iPos["col"] = iRo - 3
    DrawStar()
    iPos["row"] = iRo - 3
    DrawStar()
    iPos["col"] = 4
    DrawStar()
  EndIf
  If iRo = 19 Then                    ' center of 4th line stars
    iPos = "col=" + (Math.Floor(iRo / 2) + 1) + ";row=4;"
    DrawStar()
    iPos = "col=4;row=" + (Math.Floor(iRo / 2) + 1) + ";"
    DrawStar()
    iPos = "col=" + (iRo - 3) + ";row=" + (Math.Floor(iRo / 2) + 1) + ";"
    DrawStar()
    iPos = "col=" + (Math.Floor(iRo / 2) + 1) + ";row=" + (iRo - 3) + ";"
    DrawStar()
  EndIf
  GraphicsWindow.PenWidth = iPW

  ' draw numbers
  GraphicsWindow.BrushColor = "Black"
  For iX = 1 To iRo
    If iX < 10 Then
      GraphicsWindow.DrawText(iLX0 + (iX - 1.2) * idLX, iLY0 - idLY - 3, iX)
    Else
      GraphicsWindow.DrawText(iLX0 + (iX - 1.2) * idLX - rCX / 2, iLY0 - idLY - 3, iX)
    EndIf
  EndFor
  For iY = 1 To iRo
    If iY < 10 Then
      GraphicsWindow.DrawText(iLX0 - idLX, iLY0 + (iY - 1.25) * idLY - 3, iY)
    Else
      GraphicsWindow.DrawText(iLX0 - idLX - rCX, iLY0 + (iY - 1.25) * idLY - 3, iY)
    EndIf
  EndFor
EndSub

Sub DrawStar
  ' Draw Star
  ' param iPos[] - star position
  ' param iLX0 - x coordinate of left most vertical line
  ' param iLY0 - y coordinate of top most horizontal line
  ' param idLX - distance between vertical lines
  ' param idLY - distance between horizontal lines
  ' param iRadius - radius of star
  iSX = iLX0 + (iPos["col"] - 1) * idLX - iRadius
  iSY = iLY0 + (iPos["row"] - 1) * idLY - iRadius
  GraphicsWindow.FillEllipse(iSX, iSY, iRadius * 2, iRadius * 2)
EndSub

Sub DrawStone
  ' Draw Stone
  ' param iX, iY - stone position
  ' param iColor - stone color
  ' param bShowMove - show number of moves
  ' param iMove - number of moves
  ' param iLX0 - x coordinate of left most vertical line
  ' param iLY0 - y coordinate of top most horizontal line
  ' param idLX - distance between vertical lines
  ' param idLY - distance between horizontal lines
  ' param iSR - radius of stone
  ' work iNX, iNY - coordinate for number of moves
  ' work iND - digit count for number of moves
  If iColor = WHITE Then
    iNumColor = "Black"
  ElseIf iColor = BLACK Then
    iNumColor = "White"
  EndIf
  If iColor = BLACK Or iColor = WHITE Then
    Shapes.ShowShape(oShadow[iX][iY])
    If iColor = BLACK Then
      Shapes.ShowShape(oBlack[iX][iY])
      Shapes.SetOpacity(oHilite[iX][iY], 30)
    ElseIf iColor = WHITE THen
      Shapes.ShowShape(oWhite[iX][iY])
      Shapes.SetOpacity(oHilite[iX][iY], 100)
    EndIf
    Shapes.ShowShape(oHilite[iX][iY])
    If bShowMove Then
      rNY = rCY * 0.8
      GraphicsWindow.FontSize = rNY
      If iMove > 99 Then
        iND = 3
      ElseIf iMove > 9 Then
        iND = 2
      Else
        iND = 1
      EndIf
      iNX = iLX0 + (iX - 1) * idLX - rNY * iND / 3
      iNY = iLY0 + (iY - 1) * idLY - rNY / 2 - 2
      GraphicsWindow.BrushColor = iNumColor
      oMove[iX][iY] = Shapes.AddText(iMove)
      Shapes.Move(oMove[iX][iY], iNX, iNY)
      GraphicsWindow.FontSize = rCY
    EndIf
  EndIf
EndSub

Sub EraseStone
  ' Erase Stone
  ' param iX, iY - stone position
  Shapes.HideShape(oShadow[iX][iY])
  Shapes.HideShape(oBlack[iX][iY])
  Shapes.HideShape(oWhite[iX][iY])
  Shapes.HideShape(oHilite[iX][iY])
  If oMove[iX][iY] <> "" Then
    Shapes.Remove(oMove[iX][iY])
    oMove[iX][iY] = ""
  EndIf
EndSub

Sub XDeadStones
  ' Mark X on Dead Stones
  ' param iDeadSum, iDX[], iDY[] - dead stones
  ' work iX, iY - stone position
  ' work i, iPW, sPC
  If iDeadSum > 0 Then
    sPC = GraphicsWindow.PenColor
    GraphicsWindow.PenColor = "Red"
    iPW = GraphicsWindow.PenWidth
    GraphicsWindow.PenWidth = 4
    For i = 1 To iDeadSum
      iX = iDX[i]
      iY = iDY[i]
      oX1[iX][iY] = Shapes.AddLine(iLX0 + (iX - 1) * idLX - iSR / 2, iLY0 + (iY - 1) * idLY - iSR / 2, iLX0 + (iX - 1) * idLX + iSR / 2, iLY0 + (iY - 1) * idLY + iSR / 2)
      oX2[iX][iY] = Shapes.AddLine(iLX0 + (iX - 1) * idLX + iSR / 2, iLY0 + (iY - 1) * idLY - iSR / 2, iLX0 + (iX - 1) * idLX - iSR / 2, iLY0 + (iY - 1) * idLY + iSR / 2)
    EndFor
    GraphicsWindow.PenColor = sPC
    GraphicsWindow.PenWidth = iPW
  EndIf
EndSub

Sub DrawTerritory
  ' Draw Rectangle on Territory
  ' work iX, iY - stone position
  ' param iBoard[][] - board
  ' param iTerritory[][] - territory
  ' param iLX0 - x coordinate of left most vertical line
  ' param iLY0 - y coordinate of top most horizontal line
  ' param idLX - distance between vertical lines
  ' param idLY - distance between horizontal lines
  ' param iSR - radius of stone
  GraphicsWindow.PenWidth = 0
  For iY = 1 To iRo
    For iX = 1 To iRo
      If iBoard[iX][iY] = SPACE And iTerritory[iX][iY] = BLACK Then
        GraphicsWindow.BrushColor = "Black"
        oRect[iX][iY] = Shapes.AddRectangle(iSR, iSR)
        Shapes.Move(oRect[iX][iY], iLX0 + (iX - 1) * idLX - iSR / 2, iLY0 + (iY - 1) * idLY - iSR / 2)
      ElseIf iBoard[iX][iY] = SPACE And iTerritory[iX][iY] = WHITE Then
        GraphicsWindow.BrushColor = "White"
        oRect[iX][iY] = Shapes.AddRectangle(iSR, iSR)
        Shapes.Move(oRect[iX][iY], iLX0 + (iX - 1) * idLX - iSR / 2, iLY0 + (iY - 1) * idLY - iSR / 2)
      EndIf
    EndFor
  EndFor
  GraphicsWindow.PenWidth = 2
EndSub

' ---------------------------------
' Game Record File
' ---------------------------------
Sub Rec_GenSGFName
  ' Game Record | Generate SGF File Name
  sSGF = Text.GetSubText(sDate, 1, 4)
  sSGF = Text.Append(sSGF, Text.GetSubText(sDate, 6, 2))
  sSGF = Text.Append(sSGF, Text.GetSubText(sDate, 9, 2))
  sSGF = sSGF + "_"
  iEms = iBeginTime
  ConvertEmsToTime()
  If Text.GetLength(iTime["Hour"]) = 1 Then
    sSGF = sSGF + "0"
  EndIf
  sSGF = sSGF + iTime["Hour"]
  If Text.GetLength(iTime["Minute"]) = 1 Then
    sSGF = sSGF + "0"
  EndIf
  sSGF = sSGF + iTime["Minute"]
  If Text.GetLength(iTime["Second"]) = 1 Then
    sSGF = sSGF + "0"
  EndIf
  sSGF = sSGF + iTime["Second"]
  sSGF = sSGF + "_"
  sSGF = sSGF + iRo
  sSGF = sSGF + Text.GetSubText(sPlayer[BLACK], 1, 1)
  sSGF = sSGF + Text.GetSubText(sPlayer[WHITE], 1, 1)
  sSGF = sSGF + iMove
  If sScore = "0" Then
    sSGF = sSGF + "D"
  Else
    sSGF = sSGF + Text.GetSubText(sScore, 1, 1)
    sSGF = sSGF + Text.GetSubTextToEnd(sScore, 3)
  EndIf
  sSGF = sSGF + ".sgf"
  Controls.SetTextBoxText(oSGF, sSGF)
EndSub

Sub Rec_InitRecord
  ' Game Record | Initialize
  ' return iNumRec - number of moves in game record
  iNumRec = 0
EndSub

Sub Rec_Record
  ' Game Record | Record
  ' param iX, iY - next move (on board)
  ' param iColor - stone color
  ' param bPass - pass
  ' return iRecord[][] - game record
  ' return iNumRec - number of moves in game record
  iNumRec = iNumRec + 1
  If bPass Then
    iX = iRo + 1
    iY = iRo + 1
  EndIf
  iRecord[iNumRec]["x"] = iX
  iRecord[iNumRec]["y"] = iY
  iRecord[iNumRec]["turn"] = iColor
EndSub

Sub Rec_ReplayGame
  ' Game Record | Replay Game
  bShowMove = "True"
  ClearBoard()    ' clear board
  ClearGBoard()   ' clear graphics board
  Shapes.SetText(oPrisoner[BLACK], 0) ' clear prisoner
  Shapes.SetText(oPrisoner[WHITE], 0) ' clear prisoner
  iMove = 0       ' clear number of moves
  bInGame = "True"
  bReplay = "True"
  While bInGame
    '{
    EachTurn()    ' black turn
    If bInGame Then
      EachTurn()  ' white turn
    EndIf
    '}
  EndWhile
  bInGame = "True"
EndSub

Sub Rec_WriteRecord
  ' Game Record | Write File (Save)
  ' param iNumRec - number of moves for game record
  ' param iRecord[][] - game record
  ' work i, iX, iY, iColor
  ' work sBuf - buffer
  sBuf = "" ' for Silverlight
' The following line could be harmful and has been automatically commented.
' sBuf = File.ReadContents(sSGF)
  If Text.GetLength(sBuf) > 0 Then
    GraphicsWindow.ShowMessage("'" + sSGF + "'" + sAlreadyExists, sSave2)
  Else
    iSGFLine = 1
    sBuf = sBuf + "(;GM[1]FF[1]SZ[" + iRo + "]PB[" + sPlayer[BLACK] + "]PW[" + sPlayer[WHITE] + "]RE[" + sScore + "]" + sNL
    iSGFLine = 2
    sBuf = sBuf + "DT[" + sDate + "]KM[0.0]RU[Japanese]" + sNL
    iSGFLine = 3
    sBuf = sBuf + "AP[" + sProgram + ":" + sVersion + "]CA[UTF-8]" + sNL
    iSGFLine = 4
    sLine = ""
    For i = 1 To iNumRec
      iX = iRecord[i]["x"]
      iY = iRecord[i]["y"]
      iColor = iRecord[i]["turn"]
      If (iColor = BLACK) Then
        sLine = sLine + ";B[" + sAlpha[iX] + sAlpha[iY] + "]"
      ElseIf (iColor = WHITE) Then
        sLine = sLine + ";W[" + sAlpha[iX] + sAlpha[iY] + "]"
      EndIf
      If Math.Remainder(i, 10) = 0 Then
        sBuf = sBuf + sLine + sNL
        iSGFLine = iSGFLine + 1
        sLine = ""
      EndIf
    EndFor
    sBuf = sBuf + sLine + ")" + sNL
    iSGFLine = iSGFLine + 1
    sLine = ""
' The following line could be harmful and has been automatically commented.
' File.WriteContents(sSGF, sBuf)
  EndIf
EndSub

Sub Rec_ReadRecord
  ' Read Game Record File (Open)
  ' work sBuf - buffer
  ' return iNumRec - number of moves for Game Record
  ' return iRecord[][] - game record
  ' our: bError - read error
  Rec_InitRecord()
  sBuf = ""         ' for Silverlight
' The following line could be harmful and has been automatically commented.
' sBuf = File.ReadContents(sSGF)
  iBufPtr = 1
  iBufLen = Text.GetLength(sBuf)
  If iBufLen = 0 Then
    GraphicsWindow.ShowMessage("'" + sSGF + "'" + sIsNotExist, sOpen)
    bMatched = "False"
    bError = "True"
  Else
    SGF_ParseCollection()
  EndIf
EndSub

Sub Rec_SaveGameDate
  ' Save Date for Game Record
  ' return sDate - date for SGF Game Record
  sDate = Clock.Year + "-"
  If Clock.Month <= 9 Then
    sDate = sDate + "0"
  EndIf
  sDate = sDate + Clock.Month + "-"
  If Clock.Day <= 9 Then
    sDate = sDate + "0"
  EndIf
  sDate = sDate + Clock.Day
EndSub

Sub SGF_ParseCollection
  ' Smart Game Format | Parse Collection
  ' return bMatched - "True" if matched
  SGF_ParseGameTree()
  While bMatched
    SGF_ParseSpace()
    SGF_ParseGameTree()
  EndWhile
EndSub

Sub SGF_ParseGameTree
  ' Smart Game Format | Parse GameTree
  ' return bMatched - "True" if matched
  Stack.PushValue("gametree", iBufPtr)
  cChar = "("
  Lex_Char()
  If bMatched = "False" Then
    Goto lNotGameTree
  EndIf
  SGF_ParseSpace()
  SGF_ParseSequence()
  If bMatched = "False" Then
    Goto lNotGameTree
  EndIf
  While bMatched
    SGF_ParseSpace()
    SGF_ParseGameTree()
  EndWhile
  SGF_ParseSpace()
  cChar = ")"
  Lex_Char()
  lNotGameTree:
  iSavedPtr = Stack.PopValue("gametree")
  If bMatched = "False" Then
    iBufPtr = iSavedPtr
  EndIf
EndSub

Sub SGF_ParseSequence
  ' Smart Game Format | Parse Sequence
  ' return bMatched - "True" if matched
  SGF_ParseNode()
  While bMatched
    SGF_ParseSpace()
    SGF_ParseNode()
  EndWhile
EndSub

Sub SGF_ParseNode
  ' Smart Game Format | Parse Node
  ' return bMatched - "True" if matched
  bNode = "False"
  cChar = ";"
  Lex_Char()
  If bMatched = "False" Then
    Goto lNotNode
  EndIf
  While bMatched
    SGF_ParseSpace()
    SGF_ParseProperty()
    If bMatched Then
      bNode = "True"
    EndIf
  EndWhile
  bMatched = bNode
  lNotNode:
EndSub

Sub SGF_ParseProperty
  ' Smart Game Format | Parse ID[value] - property property
  ' return sID - given ID
  ' return sValue - value of property
  ' return bMatched - property if matched
  ' return bError - parse error
  ' TODO process if there is no "]"
  bError = "False"
  iSavedPtr = iBufPtr
  SGF_ParseGame()     ' GM[1]
  If bMatched Or bError Then
    Goto lExitProperty
  EndIf
  SGF_ParseSize()     ' SZ[6]
  If bMatched Then
    Goto lExitProperty
  EndIf
  SGF_ParsePB()       ' PB[black player name]
  If bMatched Then
    Goto lExitProperty
  EndIf
  SGF_ParsePW()       ' PW[white player name]
  If bMatched Then
    Goto lExitProperty
  EndIf
  SGF_ParseHA()       ' HA[handy]
  If bMatched Then
    Goto lExitProperty
  EndIf
  SGF_ParseKomi()     ' KM[0.0]
  If bMatched Then
    Goto lExitProperty
  EndIf
  SGF_ParseBlack()    ' B[xy]
  If bMatched Then
    Goto lExitProperty
  EndIf
  SGF_ParseWhite()    ' W[xy]
  If bMatched Then
    Goto lExitProperty
  EndIf
  Lex_Upper()    ' other property ID[value]
  If bMatched = "False" Then
    Goto lExitProperty
  EndIf
  sID = c
  Lex_Upper()
  If bMatched Then
    sID = sID + c
  EndIf
  cChar = "["
  Lex_Char()
  If bMatched = "False" Then
    Goto lExitProperty
  EndIf
  iBROffset = Text.GetIndexOf(Text.GetSubTextToEnd(sBuf, iBufPtr), "]")
  If iBROffset = 0 Then
    bMatched = "False"
  Else
    bMatched = "True"
    sValue = Text.GetSubText(sBuf, iBufPtr, iBROffset - 1)
    iBufPtr = iBufPtr + iBROffset
  EndIf
  lExitProperty:
  If bMatched = "False" Then
    iBufPtr = iSavedPtr
  EndIf
EndSub

Sub SGF_ParseSpace
  ' Smart Game Format | Parse Space (blank, tab, carriage return, line feed etc.)
  ' work bSpace
  bSpace = "False"
  bMatched = "True"
  While bMatched
    cChar = " "   ' blank
    Lex_Char()
    If bMatched Then
      bSpace = "True"
      Goto lWhiteSpace
    EndIf
    cChar = cTab  ' tab
    Lex_Char()
    If bMatched Then
      bSpace = "True"
      Goto lWhiteSpace
    EndIf
    cChar = cCR   ' carriage return
    Lex_Char()
    If bMatched Then
      bSpace = "True"
      Goto lWhiteSpace
    EndIf
    cChar = cLF   ' line feed
    Lex_Char()
    If bMatched Then
      bSpace = "True"
    EndIf
    lWhiteSpace:
  EndWhile
  bMatched = bSpace
EndSub

Sub SGF_ParseGame
  ' Smart Game Format | Parse GM[1] - game
  sID = "GM"
  SGF_ParseGivenProperty()
  If bMatched Then
    If sValue <> "1" Then
      GraphicsWindow.ShowMessage("'" + sSGF + "'" + sIsNotGoFormat +" GM[" + sValue + "]", sOpen)
      bMatched = "False"
      bError = "True"
    EndIf
  EndIf
EndSub

Sub SGF_ParseSize
  ' Smart Game Format | Parse SZ[6] - size
  sID = "SZ"
  SGF_ParseGivenProperty()
  If bMatched Then
    iValue = sValue
    iLastRo = iRo
    iRo = iValue
    If iLastRo <> iRo Then
      bNewRo = "True"
    Else
      bNewRo = "False"
    EndIf
  EndIf
EndSub

Sub SGF_ParsePB
  ' Smart Game Format | Parse PB[black player name]
  sID = "PB"
  SGF_ParseGivenProperty()
  If bMatched Then
    sPlayer[BLACK] = sValue
    Controls.SetTextBoxText(oPlayer[BLACK], sPlayer[BLACK])
  EndIf
EndSub

Sub SGF_ParsePW
  ' Smart Game Format | Parse PW[white player name]
  sID = "PW"
  SGF_ParseGivenProperty()
  If bMatched Then
    sPlayer[WHITE] = sValue
    Controls.SetTextBoxText(oPlayer[WHITE], sPlayer[WHITE])
  EndIf
EndSub

Sub SGF_ParseKomi
  ' Smart Game Format | Parse KM[0.0] - komi
  sID = "KM"
  SGF_ParseGivenProperty()
  If bMatched Then
    rKomi = sValue
  EndIf
EndSub

Sub SGF_ParseHA
  ' Smart Game Format | Parse HA[0] - handicap stones
  sID = "HA"
  SGF_ParseGivenProperty()
EndSub

Sub SGF_ParseBlack
  ' Smart Game Format | Parse B[xy] - black move
  ' return bPass - pass
  cChar = "B"
  Lex_Char()
  If bMatched Then
    iColor = BLACK
    SGF_ParsePoint()
    If bMatched Then
      iX = Text.GetIndexOf("abcdefghijklmnopqrst", cX)
      iY = Text.GetIndexOf("abcdefghijklmnopqrst", cY)
      If iX = 20 Or iX = 0 Then
        bPass = "True"
      Else
        bPass = "False"
      EndIf
      Rec_Record()
    Else
      iBufPtr = iBufPtr - 1 ' back one for "B"
    EndIf
  EndIf
EndSub

Sub SGF_ParseWhite
  ' Smart Game Format | Parse W[xy] - white move
  ' return bPass - pass
  cChar = "W"
  Lex_Char()
  If bMatched Then
    iColor = WHITE
    SGF_ParsePoint()
    If bMatched Then
      iX = Text.GetIndexOf("abcdefghijklmnopqrst", cX)
      iY = Text.GetIndexOf("abcdefghijklmnopqrst", cY)
      If iX = 20 Or iX = 0 Then
        bPass = "True"
      Else
        bPass = "False"
      EndIf
      Rec_Record()
    Else
      iBufPtr = iBufPtr - 1 ' back one for "W"
    EndIf
  EndIf
EndSub

Sub SGF_ParsePoint
  ' Smart Game Format | Parse [xy] - point
  ' return character cX, cY
  iSavedPtr = iBufPtr
  cChar = "["
  Lex_Char()
  If bMatched = "False" Then
    Goto lNotPoint
  EndIf
  Lex_Lower()
  If bMatched = "False" Then
    Goto lNotPoint
  EndIf
  cX = c
  Lex_Lower()
  If bMatched = "False" Then
    Goto lNotPoint
  EndIf
  cY = c
  cChar = "]"
  Lex_Char()
  lNotPoint:
  If bMatched = "False" Then
    iBufPtr = iSavedPtr
  EndIf
EndSub

Sub SGF_ParseGivenProperty
  ' Smart Game Format | Parse ID[value] - property
  ' param sID - given ID
  ' return sValue - value of property
  ' return bMatched - "True" if matched
  SGF_ParseID()
  If bMatched = "False" Then
    Goto lNotGivenProperty
  EndIf
  cChar = "["
  Lex_Char()
  If bMatched Then
    iBROffset = Text.GetIndexOf(Text.GetSubTextToEnd(sBuf, iBufPtr), "]")
    If iBROffset = 0 Then
      bMatched = "False"
    Else
      bMatched = "True"
      sValue = Text.GetSubText(sBuf, iBufPtr, iBROffset - 1)
      iBufPtr = iBufPtr + iBROffset
    EndIf
  EndIf
  lNotGivenProperty:
EndSub

Sub SGF_ParseID
  ' Smart Game Format | Parse ID
  ' param sID
  ' work iPtr
  ' return bMatched - ID if matched
  iPtrSaved = iBufPtr
  For iPtr = 1 To Text.GetLength(sID)
    cChar = Text.GetSubText(sID, iPtr, 1)
    Lex_Char()
    If bMatched = "False" Then
      iBufPtr = iPtrSaved
      Goto lNotID
    EndIf
  EndFor
  lNotID:
EndSub

Sub Lex_Upper
  ' Lexical Analysis | Upper Case Character
  ' param sBuf - buffer
  ' param/return iBufPtr - buffer pointer
  ' return c - upper case character
  ' return bMatched - "True" if matched
  c = Text.GetSubText(sBuf, iBufPtr, 1)
  iCode = Text.GetCharacterCode(c)
  If iCode >= UPPERA And iCode <= UPPERZ Then
    bMatched = "True"
    iBufPtr = iBufPtr + 1
  Else
    bMatched = "False"
  EndIf
EndSub

Sub Lex_Lower
  ' Lexical Analysis | Lower Case Character
  ' param sBuf - buffer
  ' param/return iBufPtr - buffer pointer
  ' return c - lower case character
  ' return bMatched - "True" if matched
  c = Text.GetSubText(sBuf, iBufPtr, 1)
  iCode = Text.GetCharacterCode(c)
  If iCode >= LOWERA And iCode <= LOWERZ Then
    bMatched = "True"
    iBufPtr = iBufPtr + 1
  Else
    bMatched = "False"
  EndIf
EndSub

Sub Lex_Char
  ' Lexical Analysis | Given Character
  ' param character cChar - given character
  ' param sBuf - buffer
  ' param/return iBufPtr - buffer pointer
  ' return bMatched - "True" if matched
  c = Text.GetSubText(sBuf,iBufPtr, 1)
  If c = cChar Then
    bMatched = "True"
    iBufPtr = iBufPtr + 1
  Else
    bMatched = "False"
  EndIf
EndSub

' ---------------------------------
' Debug
' ---------------------------------
Sub Debug_DrawGrid
  ' Debug | Draw Grid for Graphics Design
  cx = rCX
  cy = rCY
  GraphicsWindow.FontSize = cy
  GraphicsWindow.FontName = "Courier New"
  GraphicsWindow.BrushColor = "SlateBlue"
  GraphicsWindow.PenColor = "Cyan"
  GraphicsWindow.Clear()
  x = 0
  y = 0
  sRuler = "----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8"
  GraphicsWindow.DrawText(x, y - 3, sRuler)
  For i = 0 To 19
    GraphicsWindow.DrawText(x, y - 3, i)
    y = y + cy
  EndFor
  w = GraphicsWindow.Width
  h = GraphicsWindow.Height
  sRange = w + "," + h + " "
  GraphicsWindow.DrawText(x + cx * 4, cy * 17 - 3, sRange)
  For i = 0 To 624 Step cx
    GraphicsWindow.DrawLine(i, 0, i, 443)
  EndFor
  For i = 0 To 443 Step cy
    GraphicsWindow.DrawLine(0, i, 624, i)
  EndFor
  GraphicsWindow.FontName = "Tahoma"
EndSub

Sub Debug_DumpRecord
  For i = 1 To iNumRec
    TextWindow.WriteLine(sStone[iRecord[i]["turn"]] + "(" + iRecord[i]["x"] + "," + iRecord[i]["y"] + ")")
  EndFor
EndSub

Sub Debug_DumpUnit
  For i = 1 To iUnit
    TextWindow.WriteLine("(" + iUX[i]+ "," + iUY[i] + ")")
  EndFor
  TextWindow.WriteLine("")
EndSub

Sub Debug_DumpPoint
  TextWindow.Write("(" + iX + "," + iY + ")")
EndSub

Sub Debug_DumpNewLine
  TextWindow.WriteLine("")
EndSub

Sub Debug_DumpLiberty
  TextWindow.WriteLine("iLiberty = " + iLiberty)
EndSub

Sub Debug_DumpColor
  TextWindow.WriteLine("iColor = " + iColor)
EndSub

Sub Debug_DumpMove
  TextWindow.Write(iMove)
EndSub

Sub Debug_DumpScore
  TextWindow.WriteLine("iScore = " + iScore)
EndSub

Sub Debug_DumpEffect
  For iY = 1 To iRo
    For iX = 1 To iRo
      TextWindow.Write(iBlackEffect[iX][iY] + " ")
    EndFor
    TextWindow.WriteLine("")
  EndFor
  TextWindow.WriteLine("")
  For iY = 1 To iRo
    For iX = 1 To iRo
      TextWindow.Write(iWhiteEffect[iX][iY] + " ")
    EndFor
    TextWindow.WriteLine("")
  EndFor
EndSub

Sub InitFigure
  sFigure[SPACE] = "+"
  sFigure[BLACK] = "@"
  sFigure[WHITE] = "O"
  sFigure[OB] = "#"
EndSub

Sub Debug_DumpBoard
  For iYDB = 1 To iRo
    For iXDB = 1 To iRo
      TextWindow.Write(sFigure[iBoard[iXDB][iYDB]])
    EndFor
    TextWindow.WriteLine("")
  EndFor
  TextWindow.WriteLine("")
EndSub

Sub Debug_DumpBoard2
  ' Dump Board Including Out of Board
  For iYDB = 0 To iRo + 1
    For iXDB = 0 To iRo + 1
      TextWindow.Write(sFigure[iBoard[iXDB][iYDB]])
    EndFor
    TextWindow.WriteLine("")
  EndFor
  TextWindow.WriteLine("")
EndSub

Sub StartClock
  ' Start Clock
  ' return iBeginTime
  ' work iEms
  iBeginTime = Clock.ElapsedMilliseconds
  iEms = iBeginTime
  If bTime Then
    TextWindow.Write("Start: ")
    PrintClock()
    TextWindow.Write(" ")
  EndIf
EndSub

Sub StopClock
  ' Stop Clock
  ' return iEndTime
  ' work iEms
  iEndTime = Clock.ElapsedMilliseconds
  iEms = iEndTime
  If bTime Then
    TextWindow.Write("Stop: ")
    PrintClock()
    TextWindow.Write(" ")
  EndIf
EndSub

Sub PrintTime
  ' Print Time
  ' param iBeginTime
  ' param iEndTime
  ' work iEms
  iEms = iEndtime - iBeginTime
  TextWindow.Write("Time: ")
  PrintClock()
  TextWindow.WriteLine("")
EndSub

Sub PrintClock
  ' Print Clock
  ' param iEms
  ' work iTime[]
  ConvertEmsToTime()
  TextWindow.Write(iTime["Hour"] + ":" + iTime["Minute"] + ":" + iTime["Second"])
EndSub

Sub ConvertEmsToTime
  ' Convert Ems To Hour Minute Second
  ' param iEms - elapsed milliseconds
  ' work iHMSMs - hour minute second millisecond
  ' work iMSMs - minute second millisecond
  ' work iSMs - second millisecond
  ' return iTime[] - hour minute second
  iHMSMs = Math.Remainder(iEms, 24 * 60 * 60 * 1000)
  iTime["Hour"] = Math.Floor(iHMSMs / (60 * 60 * 1000))
  iMSMs = Math.Remainder(iHMSMs, 60 * 60 * 1000)
  iTime["Minute"] = Math.Floor(iMSMs / (60 * 1000))
  iSMs = Math.Remainder(iMSMs, 60 * 1000)
  iTime["Second"] = Math.Floor(iSMs / 1000)
EndSub

Sub Debug_DumpRdmArray
  iIdx = 0
  iCntDR = 0
  While iRdm[iIdx] > 0
    If iRdm[iIdx] < 10 Then
      TextWindow.Write(" ")
    EndIf
    TextWindow.Write(iRdm[iIdx] + " ")
    iIdx = iRdm[iIdx]
    iCntDR = iCntDR + 1
    If iCntDR > 50 Then
      TextWindow.WriteLine("")
      TextWindow.WriteLine("Error: iRdm[>50] ?")
      TextWindow.Read()
    EndIf
  EndWhile
  TextWindow.WriteLine("")
EndSub

Sub Debug_DumpRdmArray2
  For iYDR = 1 To iRo
    For iXDR = 1 To iRo
      sTemp[iXDR][iYDR] = "?"
    EndFor
  EndFor
  iIdx = 0
  While iRdm[iIdx] > 0
    iIdx = iRdm[iIdx]
    iXDR = Math.Remainder(iIdx - 1, iRo) + 1
    iYDR = Math.Floor((iIdx - 1) / iRo) + 1
    sTemp[iXDR][iYDR] = "+"
  EndWhile
  For iYDR = 1 To iRo
    For iXDR = 1 To iRo
      TextWindow.Write(sTemp[iXDR][iYDR])
    EndFor
    TextWindow.WriteLine("")
  EndFor
  TextWindow.WriteLine("")
EndSub

Sub Debug_DumpRdmLast
  TextWindow.WriteLine("iRdm[iLast(" + iLast + ")]=" + iRdm[iLast])
EndSub

Sub Debug_DumpRdmXY
  TextWindow.WriteLine("iRdm[iXY(" + iXY + ")]=" + iRdm[iXY])
EndSub

Sub Debug_DumpKomi
  TextWindow.Write(rKomi)
EndSub
Copyright (c) Microsoft Corporation. All rights reserved.