Microsoft Small Basic

Program Listing: RGR694
' SGF to CSV Converter 0.5
' Copyright (c) 2012, 2013 Nonki Takahashi. All right reserved.
'
' History:
' 0.5 2013/03/02 Changed to convert SGF to CSV. ()
' 0.41 2012/11/17 Changed to check third move.
' 0.4 2012/11/04 Changed to size 9x9 and to put CSV. (VVD450-1)
' 0.3 2012/11/02 Changed to show win, game, average. (VVD450-0)
' 0.2 2012/11/02 Changed to count black win for each first move. (VVD450)
' 0.1 2012/11/02 Created from Go Simulator 0.2 to make CSV.
'
' Refrence:
' [1]Anders Kierulf: File Format FF[1], http://www.red-bean.com/sgf/, 1990.
' [2]Arno Hollosi: SGF File Format FF[4], http://www.red-bean.com/sgf/, 2006.
' [3]Karl Baker: The Way to Go, American Go Association, 1986.
'
' ---------------------------------
' Main Program
' ---------------------------------
' work bInProgram - program running
' work bInGame - in game
' work bDebug - in debug
'
sProgram = "SGF to CSV Converter" ' program name
sVersion = "0.5" ' program version
bDebug = "False" ' in debug
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
path = Program.Directory ' gets the executing program's directory path
' The following line could be harmful and has been automatically commented.
' arry = File.GetFiles(path) ' this command returns array
count = Array.GetItemCount(arry) ' gets entry count in the array
sCSV = "" ' dummy
iFH = 12 ' font height
GraphicsWindow.BackgroundColor = "LightGray"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = iFH
oCSV = Controls.AddMultiLineTextBox(0, 0)
Controls.SetSize(oCSV, GraphicsWindow.Width, GraphicsWindow.Height)
CSV_AddTOC()
' The following line could be harmful and has been automatically commented.
' File.AppendContents("simulated.csv", buf)
bufCSV = buf + sNL
Controls.SetTextBoxText(oCSV, bufCSV)
For n = 1 To count
sSGF = arry[n]
If Text.EndsWith(Text.ConvertToLowerCase(sSGF), ".sgf") Then
Rec_ReadRecord() ' read game record
CSV_AddRecord()
' The following line could be harmful and has been automatically commented.
' File.AppendContents("simulated.csv", buf)
If n < 10 Then
bufCSV = bufCSV + buf + sNL
Controls.SetTextBoxText(oCSV, bufCSV)
EndIf
If n = 10 Then
bufCSV = bufCSV + "..."
Controls.SetTextBoxText(oCSV, bufCSV)
EndIf
EndIf
percent = Math.Floor(n / count * 100)
GraphicsWindow.Title = sProgram + " " + sVersion + " - " + percent + " %"
EndFor
GraphicsWindow.Title = sProgram + " " + sVersion + " - " + 100 + " %"

' ---------------------------------
' 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.
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 = 5
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 = GraphicsWindow.GetColorFromRGB(240, 200, 140)
iPass = 0
sStone[SPACE] = "SPACE"
sStone[BLACK] = "BLACK"
sStone[WHITE] = "WHITE"
sStone[OB] = "OB"
sOpen = "Open" '"開く"
sIsNotExist = "not exists." '"は存在しません。"
sIsNotGoFormat = "is not Go game record." '"は囲碁の棋譜ではありません。"
sSave2 = "Save" '"保存"
sAlreadyExists = "already exists." '"はすでに存在します。"
GraphicsWindow.Title = sProgram + " " + sVersion
bInProgram = "True"
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
EndSub

' ---------------------------------
' CSV (comma separated value)
' ---------------------------------
Sub CSV_AddTOC
buf = "File Name,Application,Size,Komi,Black,White,Result,#Move,Move"
EndSub

Sub CSV_AddRecord
CSV_AddFileName()
CSV_AddProgramName()
CSV_AddSize()
CSV_AddKomi()
CSV_AddBlackPlayer()
CSV_AddWhitePlayer()
CSV_AddResult()
CSV_AddNumMove()
CSV_AddMove()
EndSub

Sub CSV_AddBlackPlayer
buf = buf + sPlayer[BLACK] + ","
EndSub

Sub CSV_AddWhitePlayer
buf = buf + sPlayer[WHITE] + ","
EndSub

Sub CSV_AddFileName
buf = sSGF + ","
EndSub

Sub CSV_AddSize
buf = buf + iRo + ","
EndSub

Sub CSV_AddKomi
buf = buf + rKomi + ","
EndSub

Sub CSV_AddResult
buf = buf + sScore + ","
EndSub

Sub CSV_AddProgramName
buf = buf + sAP + ","
EndSub

Sub CSV_AddNumMove
buf = buf + iNumRec + ","
EndSub

Sub CSV_AddMove
For i = 1 To iNumRec
buf = buf + iRecord[i]["x"] + "_" + iRecord[i]["y"]
If i < iNumRec Then
buf = buf + ","
EndIf
EndFor
lines = lines + 1
EndSub

' ---------------------------------
' Game Record File
' ---------------------------------
Sub Rec_InitRecord
' Game Record | Initialize
' return iNumRec - number of moves in game record
iNumRec = 0
sAP = "N/A" ' program name
iRo = "N/A" ' size
rKomi = "N/A" ' komi
sPlayer[BLACK] = "N/A" ' black player
sPlayer[WHITE] = "N/A" ' white player
sScore = "N/A" ' result
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_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
SGF_ParseResult() ' RE[score]
If bMatched Then
Goto lExitProperty
EndIf
SGF_ParseApplication() ' AP[name:version]
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
EndIf
EndSub

Sub SGF_ParsePW
' Smart Game Format | Parse PW[white player name]
sID = "PW"
SGF_ParseGivenProperty()
If bMatched Then
sPlayer[WHITE] = sValue
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 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_ParseResult
' Smart Game Format | Parse RE[score] - result
sID = "RE"
SGF_ParseGivenProperty()
If bMatched Then
sScore = sValue
EndIf
EndSub

Sub SGF_ParseApplication
' Smart Game Format | Parse AP[name:version] - application
sID = "AP"
SGF_ParseGivenProperty()
If bMatched Then
sAP = sValue
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.Write(sStone[iRecord[i]["turn"]] + "(" + iRecord[i]["x"] + "," + iRecord[i]["y"] + ")")
EndFor
TextWindow.WriteLine("")
EndSub