Microsoft Small Basic

Program Listing: GCS192
' Igo094.smallbasic - 囲碁 Igo v0.94 - Copyright (c) 2010 NonkiTakahashi
'
' 履歴:
' v0.1 2010/07/21 初版:碁盤の表示 (243行 NBK992)
' v0.2 2010/07/23 手数の表示 (265行 JVR185)
' v0.3 2010/07/24 人による次の手の処理 (378行 HHF931)
' v0.4 2010/07/31 棋譜の再生 (706行 HHF931-0)
' v0.5 2010/08/03 棋譜ファイルの入出力 (1088行 HHF931-1)
' v0.6 2010/08/08 勝敗の表示 、自動的に石を取る (1312行 HHF931-2)
' v0.7 2010/08/19 地の認識、着手禁止の判定、Territory (1801行 HHF931-3)
' v0.8 2010/09/05 bEyes、モンテカルロ法 (1945行 TLW572)
' v0.94 2010/10/08 棋譜の字句解析見直し、自動運転 、高速化 (1600行)
'
' 参考文献:
' [1]清愼一, 山下宏, 佐々木宣介: 『コンピュータ囲碁の入門』, 共立出版, 2005.
' [2]石倉昇, 梅沢由香里, 黒瀧正憲, 兵頭俊夫: 『東大教養囲碁講座』, 光文社新書, 2007.
' [3]Anders Kierulf: File Format FF[1], http://www.red-bean.com/sgf/, 1990.
' [4]Arno Hollosi: SGF File Format FF[4], http://www.red-bean.com/sgf/, 2006.
' [5]Karl Baker: The Way to Go, American Go Association, 1986.
' [6]美添一樹: モンテカルロ木検索, 情報処理, Vol.49 No.6, pp.686-693 (2008).
' [7]山下宏:『強豪囲碁ソフト「彩」について』,http://www32.ocn.ne.jp/~yss/index_j.html, 2009.
'
' メインプログラム:
sVersion = "v0.94" ' プログラムバージョン
bDebug = "False" ' デバッグ中
bSound = "False" ' 石を置いたときの音を出す
bNewRo = "False" ' 路数が変更になった
bTime = "True" ' 時間表示
bAuto = "False" ' 自動運転
bDumpWL = "True" ' 勝敗のダンプ
InitProgram() ' プログラムの初期化
InitRoDepend() ' 路数に依存する変数の初期化
InitControls() ' コントロール部の初期化
' プログラム終了が指定されるまで{}内繰り返し
While bInProgram
'{
' 新規モード
InitBoard() ' 盤の初期化
ResetControls() ' コントロール部の初期化
ClearBoard() ' 盤面のクリア
ShowBoard() ' 盤の表示
lRetry:
InputGameInfo() ' 対戦者名(または棋譜名)の入力
If bTime Then
StartClock()
EndIf
If bOpen Then ' 対局モード(または棋譜入力)
ReadRecord() ' 棋譜の読み込み
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() ' 路数に依存する変数の初期化
InitBoard() ' 盤の初期化
ResetControls() ' コントロール部のリセット
ClearBoard() ' 盤面のクリア
ShowBoard() ' 盤の表示
bNewRo = "False"
EndIf
ReplayGame() ' 棋譜の再生
Else ' 対局モード
Shapes.SetText(oPrisoner[BLACK], 0) ' アゲハマのクリア
Shapes.SetText(oPrisoner[WHITE], 0) ' アゲハマのクリア
InitRecord() ' 棋譜の初期化
CreateRdmArray() ' 乱空点列の初期化
SaveGameDate() ' 対局日の保存
iMove = 0 ' 手数のクリア
' 対局 - 終局になるまで{}内繰り返し
While bInGame
'{
EachTurn() ' 黒番
If bInGame Then
EachTurn() ' 白番
EndIf
' }
EndWhile
EndIf
If bTime Then
TextWindow.Write("iMove=" + iMove + " " + sScore + " ")
StopClock()
PrintTime()
EndIf
bInGame = "True" ' 終了モード(再生または棋譜出力)
While bInGame
InputGameEndInfo() ' 対戦者名(または棋譜名)の入力
If bReplay Then
ReplayGame() ' 棋譜の再生
ElseIf bSave Then
WriteRecord() ' 棋譜の保存
EndIf
EndWhile
' }
EndWhile
'
Sub EachTurn ' それぞれの手番
iMove = iMove + 1
iColor = Math.Remainder((iMove - 1), 2) + 1
iX = iBLX ' 黒番ランプ表示
iY = iBLY
If iColor = BLACK Then
bOn = "True"
Else
bOn = "False"
EndIf
DrawLamp()
iX = iWLX ' 白番ランプ表示
iY = iWLY
If iColor = WHITE Then
bOn = "True"
Else
bOn = "False"
EndIf
DrawLamp()
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()
ElseIf sPlayer[iColor] = "CPU" Then
Montecarlo() ' モンテカルロ法で次の手を決める
Else
Human()
EndIf
EndIf
If bResign Then ' 投了なら終局
bInGame = "False"
If (Math.Remainder(iMove, 2) = 1) Then
sScore = "W+R" ' 黒の投了
GraphicsWindow.Title = "Igo " + sVersion + " - 白の中押し勝ち"
Else
sScore = "B+R" ' 白の投了
GraphicsWindow.Title = "Igo " + sVersion + " - 黒の中押し勝ち"
EndIf
Else
If bPass Then ' パスならパス回数をカウントアップ
iPass = iPass + 1
Else
iPass = 0
EndIf
If bReplay = "False" Then ' 棋譜の記録
Record()
EndIf
' 石の表示と取りの処理
bShow = "True" ' 結果を表示する
If bPass = "False" Then
DrawStone()
If bSound Then
Sound.PlayClickAndWait()
EndIf
RemoveCapturedStones() ' 四方の石が囲まれたら取り除く
If iRemoved > 0 Then
Shapes.SetText(oPrisoner[iColor], iPrisoner[iColor])
EndIf
EndIf
Judge() ' 終局の判定
EndIf
EndSub
'
Sub RemoveCapturedStones ' 四方の石が囲まれたら取り除く
iRemoved = 0
bEnclosed = "True" ' 四方を囲われている
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
'
' プログラム関連:
Sub InitProgram ' プログラムの初期化
SPACE = 0 ' 空点
BLACK = 1 ' 黒
WHITE = 2 ' 白
OB = 3 ' 盤外
BANDW = 4 ' 黒と白(CheckSpaceUnit()等で使用)
UPPERA = Text.GetCharacterCode("A") ' Aの文字コード
UPPERZ = Text.GetCharacterCode("Z") ' Zの文字コード
LOWERA = Text.GetCharacterCode("a") ' aの文字コード
LOWERZ = Text.GetCharacterCode("z") ' zの文字コード
CR = 13 ' キャリッジリターン(復改)の文字コード
LF = 10 ' ラインフィード(行送り)の文字コード
TAB = 9 ' タブの文字コード
cCR = Text.GetCharacter(CR)
cLF = Text.GetCharacter(LF)
cTab = Text.GetCharacter(TAB)
sNL = cCR + cLF
iRo = 5
sPlayer[BLACK] = "Random" ' 黒プレイヤー初期値
sPlayer[WHITE] = "CPU" ' 白プレイヤー初期値
sSGF = "temp.sgf" ' SGFファイル名初期値
rCX = 14
rCY = 22
rKomi = 0.0
GraphicsWindow.FontSize = rCY
sBoardColor = "Wheat"
iPass = 0
sStone[SPACE] = "SPACE"
sStone[BLACK] = "BLACK"
sStone[WHITE] = "WHITE"
sStone[OB] = "OB"
sGame = "対局"
sOpen = "開く"
sIsNotExist = "は存在しません。"
sIsNotGoFormat = "は囲碁の棋譜ではありません。"
sSave = "=" ' Windings 保存マーク
sSave2 = "保存"
sAlreadyExists = "はすでに存在します。"
sNew = "新規"
sReplay = "4" ' Windings 再生マーク
sPause = ";" ' Windings ポーズマーク
sPass = "パス"
sResign = "投了"
GraphicsWindow.Title = "Igo " + sVersion
bInProgram = "True"
InitEffect() ' 影響範囲座標の初期化
Init4() ' 四方の座標の初期化
iPlayOut = 1 ' モンテカルロ法のプレイアウト回数
EndSub
'
Sub InitRoDepend ' 路数に依存する変数の初期化
For i = 0 To iRo
sAlpha[i] = Text.GetSubText(" abcdefghijklmnopqrs", i + 1, 1)
EndFor
sAlpha[iRo + 1] = "t" ' パス
EndSub
'
Sub InitControls ' コントロール部の初期化
GraphicsWindow.BackgroundColor = "Silver"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillEllipse(iBX1 + rCX, iBY0 + idLY, iSR * 2, iSR * 2)
iBHX = iBX1 + rCX + 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()
oBlack = Controls.AddTextBox(iBX1 + rCX, iBY0)
Controls.SetTextBoxText(oBlack, sPlayer[BLACK])
oWhite = Controls.AddTextBox(iBX1 + rCX, iBY0 + idLY * iRo / 2)
Controls.SetTextBoxText(oWhite, 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 ' コントロール部のリセット
GraphicsWindow.BackgroundColor = "Silver"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillEllipse(iBX1 + rCX, iBY0 + idLY, iSR * 2, iSR * 2)
iBHX = iBX1 + rCX + iSR * 2.5
iBHY = iBY0 + rCY * 2.5
Shapes.Move(oPrisoner[BLACK], iBHX, iBHY)
Shapes.ShowShape(oPrisoner[BLACK])
iBLX = iBHX + rCX * 5
iBLY = iBHY
bOn = "True"
iX = iBLX
iY = iBLY
DrawLamp()
Controls.Move(oBlack, iBX1 + rCX, iBY0)
Controls.Move(oWhite, iBX1 + rCX, iBY0 + idLY * iRo / 2)
Controls.ShowControl(oBlack)
Controls.ShowControl(oWhite)
Controls.Move(oPass, iBX1 + rCX, iBY0 + idLY * iRo)
Controls.Move(oResign, iBX1 + rCX * 6, iBY0 + idLY * iRo)
Controls.HideControl(oPass)
Controls.HideControl(oResign)
Controls.Move(oSGF, iBX1 + rCX, iBY0 + idLY * iRo)
Controls.ShowControl(oSGF)
Controls.Move(oGame, iBX1 + rCX, iBY0 + idLY * iRo + rCY * 2)
Controls.Move(oOpen, iBX1 + rCX * 6, iBY0 + idLY * iRo + rCY * 2)
Controls.Move(oNew, iBX1 + rCX, iBY0 + idLY * iRo + rCY * 2)
Controls.ShowControl(oGame)
Controls.ShowControl(oOpen)
Controls.HideControl(oNew)
Controls.Move(oReplay, iBX1 + rCX * 6, iBY0 + idLY * iRo + rCY * 2)
Controls.Move(oSave, iBX1 + rCX * 9, iBY0 + idLY * iRo + rCY * 2)
Controls.HideControl(oReplay)
Controls.HideControl(oSave)
iWHX = iBX1 + rCX + iSR * 2.5
iWHY = iBY0 + idLY * (iRo / 2) + rCY * 2.5
Shapes.Move(oPrisoner[WHITE], iWHX, iWHY)
Shapes.ShowShape(oPrisoner[WHITE])
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
Controls.HideControl(oSGF)
Controls.HideControl(oGame)
Controls.HideControl(oOpen)
Controls.ShowControl(oPass)
Controls.ShowControl(oResign)
EndSub
'
Sub DrawLamp ' ランプの表示
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
'
' 思考ルーチン関連:
Sub CreateRdmArray ' 乱空点列の作成
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 ' 乱空点列への空点の追加
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 ' 乱空点列のクリア
iRdm[0] = 0
EndSub
'
Sub CheckPossiblePut ' 着手可能かどうかのチェック
bPossiblePut = "False"
If iBoard[iX][iY] <> SPACE Then
Goto lNotPossible ' すでに石がある
EndIf
If iMove > 1 And iKo = iMove - 1 And iKX = iX And iKY = iY Then
Goto lNotPossible ' コウダテが必要
EndIf
CheckSuiside() ' 自殺手のチェック
If bSuiside Then
Goto lNotPossible
EndIf
If bEyes Then ' 眼を守る
CheckMyEye() ' 眼かどうか調べる
If bMyEye Then ' 眼なら打たない(ただしコウを埋める手を除く)
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 ' 自殺手のチェック
bSuiside = "False"
iBoard[iX][iY] = iColor ' 仮に置く
iXSave = iX
iYSave = iY
InitLiberty()
CountLiberty() ' 活路を数える
If iLiberty = 0 Then ' 自殺手かもしれない
iCSave = iColor
iColor = 3 - iColor ' 相手の石
For i = 1 To 4 ' 接点の石が取れるか
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() ' 活路を数える
If iLiberty = 0 Then
Goto lNotSuiside
EndIf
EndIf
EndFor
bSuiside = "True"
lNotSuiside:
iColor = iCSave
EndIf
iX = iXSave
iY = iYSave
iBoard[iX][iY] = SPACE ' 元に戻す
EndSub
'
Sub Random ' 次の手を打つ - Random (コンピューター)
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] ' 乱空点列から空点を削除
Goto lExitRandom
EndIf
iLast = iXY
EndWhile
lPassRandom:
bPass = "True"
lExitRandom:
EndSub
'
Sub RemoveRdmEntry ' 乱空点列から空点 iXY を削除(前の手 iLast が不明な場合)
iCPRRE = 0
While iRdm[iCPRRE] > 0
If iRdm[iCPRRE] = iXY Then
iRdm[iCPRRE] = iRdm[iXY] ' 乱空点列から空点を削除
Goto lRRE2Exit
EndIf
iCPRRE = iRdm[iCPRRE]
EndWhile
lRRE2Exit:
EndSub
'
Sub Montecarlo ' モンテカルロ法によりコンピューターが次の手を打つ
SaveBoard2() ' 碁盤を保存
rSKomi = rKomi ' コミを保存
iCP = 0
While iRdm[iCP] > 0
iXY = iRdm[iCP]
iX = Math.Remainder(iXY - 1, iRo) + 1
iY = Math.Floor((iXY - 1) / iRo) + 1
CheckPossiblePut() ' iColor を参照
If bPossiblePut Then
Goto lNextPut
EndIf
iCP = iXY
EndWhile
bPass = "True"
Goto lPass
lNextPut:
SaveRdmArray() ' 乱空点列を保存(iCnt ← 空点の数)
If iCnt = 0 Then
bPass = "True"
Goto lPass
ElseIf iCnt > 35 Then
iPlayOut = 6
ElseIf iCnt > 30 Then
iPlayOut = 5
ElseIf iCnt > 20 Then
iPlayOut = 4
ElseIf iCnt > 10 Then
iPlayOut = 3
ElseIf iCnt > 5 Then
iPlayOut = 2
Else
iPlayOut = 1
EndIf
SaveGameProperties() ' コウ、アゲハマ、パスを保存
iSMove = iMove ' 手数を保存
DumpMove()
TextWindow.Write(":")
iSColor = iColor ' 石の色を保存
If Math.Floor(rKomi) = 0.0 Then
If iColor = BLACK Then
rKomi = rKomi - 0.5
ElseIf iColor = WHITE Then
rKomi = rKomi + 0.5
EndIf
EndIf
i = 0
While iSRdm[i] > 0 ' 空点に対し
rWin[i] = 0.0 ' 勝ち数をクリア
rLose[i] = 0.0 ' 負け数をクリア
i = iSRdm[i]
EndWhile
bEyes = "True" ' 着手可能な手に自分の眼を含めない
bShow = "False" ' 終局判定で結果を表示しない
' 盤面のダンプポイント - モンテカルロの手を決める直前
' すべての乱空点列に対し、
rWMax = 0.0 ' 最大勝ち数
While iSRdm[iCP] > 0
iXY = iSRdm[iCP]
iSXY = iXY
iX = Math.Remainder(iXY - 1, iRo) + 1
iY = Math.Floor((iXY - 1) / iRo) + 1
CheckPossiblePut()
If bPossiblePut = "False" Then
DumpPoint() ' PlayOut の1手目 (iX, iY) を表示
TextWindow.Write("X ")
Goto lNextPoint
EndIf
' 着手可能な手について、
If bDumpWL Then
DumpPoint() ' PlayOut の1手目 (iX, iY) を表示
EndIf
For iG = 1 To iPlayOut
' 指定された回数、プレイアウトを行う
iMove = iSMove - 1 ' 手数を1つ戻す
RestoreBoard2() ' 碁盤を元に戻す
CreateRdmArray() ' 碁盤を基に乱空点列を作り直す
RestoreGameProperties() ' コウ、アゲハマ、パスを元に戻す
PlayOut() ' 終局までプレイアウト
' 盤面のダンプポイント - プレイアウトの結果を見たいとき
If iScore > 0 And iSColor = BLACK Or iScore < 0 And iSColor = WHITE Then
rWin[iCP] = rWin[iCP] + 1.0
If bDumpWL Then
TextWindow.Write("W")
EndIf
ElseIf iScore = 0 then
rWin[iCP] = rWin[iCP] + 0.5
rLose[iCP] = rLose[iCP] + 0.5
If bDumpWL Then
TextWindow.Write("D")
EndIf
Else
rLose[iCP] = rLose[iCP] + 1.0
If bDumpWL Then
TextWindow.Write("L")
EndIf
EndIf
If bDumpWL Then
TextWindow.Write(" ")
EndIf
If rWin[iCP] > rWMax Then
rWMax = rWin[iCP] ' 最大勝ち数の更新
EndIf
' プレイアウト後、残り(iPlayOut - iG)すべて勝っても
' 最大勝ち数(rWMax)を超えられない場合は、
' この初手によるプレイアウトは中止
If rWin[iCP] + iPlayOut - iG < rWMax + 1Then
Goto lNextPoint
EndIf
EndFor
lNextPoint:
' 最大勝ち数がプレイアウト回数(全勝)ならその手に打つ
If rWin[iCP] = iPlayOut Then
Goto lThisPoint
EndIf
iCP = iSXY
iColor = iSColor
iMove = iSMove
RestoreBoard2()
EndWhile
lThisPoint:
If bDumpWL Then
DumpNewLine()
EndIf
'
rMax = 0.0
i = 0
While iSRdm[i] > 0
rAve[i] = rWin[i] / (rWin[i] + rLose[i])
If rAve[i] > rMax Then
rMax = rAve[i]
EndIf
i = iSRdm[i]
EndWhile
i = 0
iS = 0
While iSRdm[iS] > 0
If rAve[iS] = rMax Then
iRdm[i] = iSRdm[iS]
i = iRdm[i]
EndIf
iS = iSRdm[iS]
EndWhile
iRdm[i] = 0
RestoreBoard2() ' 碁盤を元に戻す
rKomi = rSKomi ' コミを元に戻す
RestoreGameProperties() ' コウ、アゲハマ、パスを元に戻す
iMove = iSMove ' 手数を元に戻す
iColor = iSColor ' 石の色を元に戻す
Random() ' 同じ勝率の手からランダムに選ぶ
RestoreRdmArray() ' 乱空点列を元に戻す
RemoveRdmEntry() ' 乱空点列からiXYを削除
lPass:
EndSub
'
Sub PlayOut ' 終局までプレイアウト
iColor = BLACK
If Math.Remainder(iSMove, 2) = 0 Then
iColor = WHITE
Goto lNextWhite
EndIf
lNextBlack:
' 黒番
iMove = iMove + 1
iColor = BLACK ' Random(), RemoveCaputuredStones()で参照
If iMove = iSMove Then
iXY = iSRdm[iCP]
iX = Math.Remainder(iXY - 1, iRo) + 1
iY = Math.Floor((iXY - 1) / iRo) + 1
iBoard[iX][iY] = iColor
RemoveRdmEntry() ' 乱空点列からiXYを削除
bPass = "False"
Else
Random()
EndIf
If bPass Then
iPass = iPass + 1
Else
iPass = 0
iColor = BLACK
RemoveCapturedStones() ' 取られた石を取り除く
EndIf
' デバッグヒント:ここで盤面をダンプするとプレイアウトを観戦できる
Judge()
If bInGame <> "True" Then
Goto lEndGame
EndIf
lNextWhite:
' 白番
iMove = iMove + 1
iColor = WHITE ' Random(), RemoveCaputuredStones()で参照
If iMove = iSMove Then
iXY = iSRdm[iCP]
iX = Math.Remainder(iXY - 1, iRo) + 1 ' 最初の手
iY = Math.Floor((iXY - 1) / iRo) + 1 ' 最初の手
iBoard[iX][iY] = iColor
RemoveRdmEntry() ' 乱空点列からiXYを削除
bPass = "False"
Else
Random()
EndIf
If bPass Then
iPass = iPass + 1
Else
iPass = 0
RemoveCapturedStones() ' 取られた石を取り除く
EndIf
' デバッグヒント:ここで盤面をダンプするとプレイアウトを観戦できる
Judge()
If bInGame Then
Goto lNextBlack
EndIf
'
lEndGame:
EndSub
'
Sub SaveRdmArray ' 乱空点列の保存
i = 0
iCnt = 0
While iRdm[i] > 0
iSRdm[i] = iRdm[i]
i = iRdm[i]
iCnt = iCnt + 1
EndWhile
iSRdm[i] = 0
EndSub
'
Sub RestoreRdmArray ' 乱空点列の復元
i = 0
While iSRdm[i] > 0
iRdm[i] = iSRdm[i]
i = iSRdm[i]
EndWhile
iRdm[i] = 0
EndSub
'
Sub Human ' 人が次の手を打つ
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() ' 乱空点列から空点を削除
EndIf
EndSub
'
Sub OnMouseDown ' マウスが押されたときの処理
iMX = GraphicsWindow.MouseX
iMY = GraphicsWindow.MouseY
bNotClicked = "False"
EndSub
'
Sub OnButtonClicked ' ボタンが押されたときの処理
If Controls.LastClickedButton = oResign Then
bResign = "True"
bNotClicked = "False"
ElseIf Controls.LastClickedButton = oPass Then
bPass = "True"
bNotClicked = "False"
EndIf
EndSub
'
Sub GetPosition ' マウスをクリックした座標から碁盤の座標を得る
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 ' なにもしない(イベント処理用)
EndSub
'
Sub Replay ' 次の手を打つ - Replay (棋譜の再生)
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
'
' ゲーム関連:
Sub InputGameInfo ' 新規モード - 対戦者名(または棋譜名)の入力
bShowMove = "False"
bInGame = "True"
bReplay = "False"
bResign = "False"
GraphicsWindow.Title = "Igo " + 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" ' 自動運転のため
bOpen = "False" ' 自動運転のため
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イベント処理
If Controls.LastTypedTextBox = oBlack Then
sPlayer[BLACK] = Controls.GetTextBoxText(oBlack)
ElseIf Controls.LastTypedTextBox = oWhite Then
sPlayer[WHITE] = Controls.GetTextBoxText(oWhite)
ElseIf Controls.LastTypedTextBox = oSGF Then
sSGF = Controls.GetTextBoxText(oSGF)
EndIf
EndSub
'
Sub OnButtonClicked1 ' 新規モードのボタンイベント処理
If Controls.LastClickedButton = oGame Then
bNotClicked = "False"
bOpen = "False"
ElseIf Controls.LastClickedButton = oOpen Then
bNotClicked = "False"
bOpen = "True"
EndIf
EndSub
'
Sub InputGameEndInfo ' 終了モード - 再生, 保存または新規ボタンの入力
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" ' 自動運転のため
bOpen = "False" ' 自動運転のため
bSave = "False" ' 自動運転のため
bReplay = "False" ' 自動運転のため
bInGame = "False" ' 自動運転のため
EndIf
While bNotClicked
Program.Delay(200)
EndWhile
Controls.HideControl(oNew)
Controls.HideControl(oReplay)
Controls.HideControl(oSave)
Controls.HideControl(oSGF)
EndSub
'
Sub OnButtonClicked2 ' 終了モードのボタンイベント処理
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 ' 連を取り除く
For i = 1 To iUnit
iX = iUX[i]
iY = iUY[i]
iBoard[iX][iY] = SPACE
iRdmSeq = (iY - 1) * iRo + iX
AddNumToRdmArray() ' 乱空点列に連を追加する
If bShow Then
EraseStone()
EndIf
EndFor
EndSub
'
Sub InitLiberty ' 活路を数える準備
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 ' 連の活路を数える
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 ' 地の空点の連を調べる
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 ' 空点の連を調べる
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 ' (単独の)眼かどうか調べる
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 ' 相手の石か空
Goto lNotMyEye
EndIf
EndFor
EndIf
bMyEye = "True"
lNotMyEye:
EndSub
'
Sub CheckEye ' (単独の)眼かどうか調べる
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 ' 終局の判定
bInGame = "True"
If iPass >= 2 Then
bInGame = "False"
CountScore() ' 勝敗の判定
If bEasy = "False" Then
AdjustTerritory() ' 地の調整
EndIf
iScore = iScore + rKomi ' コミの計算
If bShow Then
DrawTerritory() ' 地の描画
XDeadStones() ' 死に石に×を付ける
If iScore > 0 Then
sScore = "B+" + iScore
GraphicsWindow.Title = "Igo " + sVersion + " - 黒の" + iScore + "目勝ち"
ElseIf iScore < 0 Then
sScore = "W+" + (-iScore)
GraphicsWindow.Title = "Igo " + sVersion + " - 白の" + (-iScore) + "目勝ち"
Else ' iScore = 0
sScore = "0"
GraphicsWindow.Title = "Igo " + sVersion + " - 引き分け(持碁)"
EndIf
EndIf
EndIf
EndSub
'
Sub CountScore ' 勝敗の判定
EvalBoard() ' 地の認識
iBlackScore = iBlackScore + iPrisoner[BLACK] ' アゲハマを加える
iWhiteScore = iWhiteScore + iPrisoner[WHITE] ' アゲハマを加える
iBlackScore = iBlackScore + iDead[WHITE] ' 死に石を加える
iWhiteScore = iWhiteScore + iDead[BLACK] ' 死に石を加える
iScore = iBlackScore - iWhiteScore
EndSub
'
Sub AdjustTerritory ' 地の調整
' 一方の石に囲まれている空白は地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 ' 盤面の評価
iCSave = iColor
If bEasy Then
For iY = 1 To iRo
For iX = 1 To iRo
If iBoard[iX][iY] = SPACE Then
' 単独の眼を地として点数に加える
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()
' 活路 iLiberty =1 の連をiBoard[][]から消し、死に石として記憶する
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
' 石の影響範囲を計算する
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 ' 黒の地を数える
iWhiteScore = 0 ' 白の地を数える
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 ' 碁盤の保存(盤面の評価用)
For iY = 1 To iRo
For iX = 1 To iRo
iSaved[iX][iY] = iBoard[iX][iY]
EndFor
EndFor
EndSub
'
Sub RestoreBoard ' 碁盤の復元(盤面の評価用)
For iY = 1 To iRo
For iX = 1 To iRo
iBoard[iX][iY] = iSaved[iX][iY]
EndFor
EndFor
EndSub
'
Sub SaveBoard2 ' 碁盤の保存2(モンテカルロ用)
For iY = 1 To iRo
For iX = 1 To iRo
iSaved2[iX][iY] = iBoard[iX][iY]
EndFor
EndFor
EndSub
'
Sub RestoreBoard2 ' 碁盤の復元2(モンテカルロ用)
For iY = 1 To iRo
For iX = 1 To iRo
iBoard[iX][iY] = iSaved2[iX][iY]
EndFor
EndFor
EndSub
'
Sub SaveGameProperties ' ゲーム属性の保存
iSKo = iKo
iSKX = iKX
iSKY = iKY
iSPrisoner[BLACK] = iPrisoner[BLACK]
iSPrisoner[WHITE] = iPrisoner[WHITE]
iSPass = iPass
EndSub
'
Sub RestoreGameProperties ' ゲーム属性の復元
iKo = iSKo
iKX = iSKX
iKY = iSKY
iPrisoner[BLACK] = iSPrisoner[BLACK]
iPrisoner[WHITE] = iSPrisoner[WHITE]
iPass = iSPass
EndSub
'
Sub Init4 ' 四方の座標差分の初期化
' [1]=右 [2]=上 [3]=左 [4]=下
idX4 = "1=1;2=0;3=-1;4=0;"
idY4 = "1=0;2=-1;3=0;4=1;"
EndSub
'
Sub InitEffect ' 影響範囲(距離2)の座標差分の初期化
' [1]=一番上 [2]=左上 [3]=上 [4]=右上 [5]=一番左 [6]=左 [7]=中央 [8]=右 [9]=一番右 [10]=左下 [11]=下 [12]=右下 [13]=一番下
idXE = "1=0;2=-1;3=0;4=1;5=-2;6=-1;7=0;8=1;9=2;10=-1;11=0;12=1;13=0;"
idYE = "1=-2;2=-1;3=-1;4=-1;5=0;6=0;7=0;8=0;9=0;10=1;11=1;12=1;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 ' 盤の初期化
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
idLX = rCX * 3 ' 線の間隔
iSR = idLX / 2 - 2 ' 碁石の半径
idLY = rCY * 2 ' 線の間隔
iLX0 = rCX * 6.5 ' 左端の線
iLY0 = rCY * 4.5 ' 上端の線
iLX1 = iLX0 + idLX * (iRo - 1) ' 右端の線
iLY1 = iLY0 + idLY * (iRo - 1) ' 下端の線
If iRo > 9 Then
iBX0 = iLX0 - idLX * 2 ' 盤の左端
Else
iBX0 = iLX0 - idLX * 1.5 ' 盤の左端
EndIf
iBY0 = iLY0 - idLY * 1.5 ' 盤の上端
iBX1 = iLX1 + idLX ' 盤の右端
iBY1 = iLY1 + idLY ' 盤の下端
EndSub
'
Sub ClearBoard ' 盤面のクリア
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
'
' グラフィックス関連:
Sub ShowBoard ' 盤の表示
' 盤の色を塗る
GraphicsWindow.BrushColor = sBoardColor
GraphicsWindow.FillRectangle(iBX0, iBY0, iBX1 - iBX0, iBY1 - iBY0)
' 枠を描く
iPW = GraphicsWindow.PenWidth
GraphicsWindow.PenWidth = 4
GraphicsWindow.DrawRectangle(iLX0, iLY0, idLX * (iRo - 1), idLY * (iRo - 1))
GraphicsWindow.PenWidth = iPW
' 線を描く
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
' 数字を書く
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 DrawStone ' 碁石を描く
If iColor = WHITE Then
iStoneColor = "White"
iNumColor = "Black"
ElseIf iColor = BLACK Then
iStoneColor = "Black"
iNumColor = "White"
EndIf
If iColor = BLACK Or iColor = WHITE Then
GraphicsWindow.BrushColor = iStoneColor
GraphicsWindow.FillEllipse(iLX0 + (iX - 1) * idLX - iSR, iLY0 + (iY - 1) * idLY - iSR, iSR * 2, iSR * 2)
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
GraphicsWindow.DrawText(iNX, iNY, iMove)
GraphicsWindow.FontSize = rCY
EndIf
EndIf
EndSub
'
Sub EraseStone ' 碁石を消す
' 碁石を碁盤の色で消す
GraphicsWindow.BrushColor = sBoardColor
GraphicsWindow.FillRectangle(iLX0 + (iX - 1) * idLX - iSR, iLY0 + (iY - 1) * idLY - iSR, iSR * 2, iSR * 2)
GraphicsWindow.PenColor = "Black"
' 横線の引き直し
If iX = 1 Then
iEX0 = iLX0
Else
iEX0 = iLX0 + (iX - 1) * idLX - iSR
EndIf
If iX = iRo Then
iEX1 = iLX0 + (iX - 1) * idLX
Else
iEX1 = iLX0 + (iX - 1) * idLX + iSR
EndIf
iEY0 = iLY0 + (iY - 1) * idLY
iEY1 = iLY0 + (iY - 1) * idLY
iPW = GraphicsWindow.PenWidth
If iY = 1 Or iY = iRo Then
GraphicsWindow.PenWidth = 4
GraphicsWindow.DrawLine(iEX0 - 2, iEY0, iEX1 + 2, iEY1)
Else
GraphicsWindow.DrawLine(iEX0, iEY0, iEX1, iEY1)
EndIf
GraphicsWindow.PenWidth = iPW
' 縦線の引き直し
iEX0 = iLX0 + (iX - 1) * idLX
iEX1 = iLX0 + (iX - 1) * idLX
If iY = 1 Then
iEY0 = iLY0
Else
iEY0 = iLY0 + (iY - 1) * idLY - iSR
EndIf
If iY = iRo Then
iEY1 = iLY0 + (iY - 1) * idLY
Else
iEY1 = iLY0 + (iY - 1) * idLY + iSR
EndIf
If iX = 1 Or iX = iRo Then
GraphicsWindow.PenWidth = 4
GraphicsWindow.DrawLine(iEX0, iEY0 - 2, iEX1, iEY1 + 2)
Else
GraphicsWindow.DrawLine(iEX0, iEY0, iEX1, iEY1)
EndIf
GraphicsWindow.PenWidth = iPW
EndSub
'
Sub XDeadStones ' 碁石に×を付ける
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]
GraphicsWindow.DrawLine(iLX0 + (iX - 1) * idLX - iSR / 2, iLY0 + (iY - 1) * idLY - iSR / 2, iLX0 + (iX - 1) * idLX + iSR / 2, iLY0 + (iY - 1) * idLY + iSR / 2)
GraphicsWindow.DrawLine(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 ' 地に四角を描く
For iY = 1 To iRo
For iX = 1 To iRo
If iBoard[iX][iY] = SPACE And iTerritory[iX][iY] = BLACK Then
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(iLX0 + (iX - 1) * idLX - iSR / 2, iLY0 + (iY - 1) * idLY - iSR / 2, iSR, iSR)
ElseIf iBoard[iX][iY] = SPACE And iTerritory[iX][iY] = WHITE Then
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(iLX0 + (iX - 1) * idLX - iSR / 2, iLY0 + (iY - 1) * idLY - iSR / 2, iSR, iSR)
EndIf
EndFor
EndFor
EndSub
'
' 棋譜ファイル関連:
Sub InitRecord ' 棋譜の初期化
iNumRec = 0
EndSub
'
Sub 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 ReplayGame ' 棋譜による対局の再生
bShowMove = "True"
ClearBoard() ' 盤面のクリア
ShowBoard() ' 盤の表示
Shapes.SetText(oPrisoner[BLACK], 0) ' アゲハマのクリア
Shapes.SetText(oPrisoner[WHITE], 0) ' アゲハマのクリア
iMove = 0 ' 手数のクリア
bInGame = "True"
bReplay = "True"
While bInGame
EachTurn() ' 黒番
If bInGame Then
EachTurn() ' 白番
EndIf
EndWhile
bInGame = "True"
EndSub
'
' 以下の3つのサブルーチンはダミーです。棋譜の入出力を行うときは、
' 実際のプログラムはプログラムID DWG627として発行しましたので、
' そちらからインポートして組み込んでください。
'
Sub WriteRecord ' 棋譜ファイルの書き出し(保存)
EndSub
'
Sub ReadRecord ' 棋譜ファイルの読み込み(開く)
bError = "False"
EndSub
'
Sub SaveGameDate ' 棋譜出力用の日付を保存
EndSub
'
' デバッグ関連:
Sub DumpPoint
TextWindow.Write("(" + iX + "," + iY + ")")
EndSub
'
Sub DumpNewLine
TextWindow.WriteLine("")
EndSub
'
Sub DumpMove
TextWindow.Write(iMove)
EndSub
'
Sub StartClock ' サブルーチン StartClock - 時計を開始する
iBeginTime = Clock.ElapsedMilliseconds
iEms = iBeginTime
TextWindow.Write("Start: ")
PrintClock()
TextWindow.Write(" ")
EndSub
'
Sub StopClock ' サブルーチン StopClock - 時計を終了する
iEndTime = Clock.ElapsedMilliseconds
iEms = iEndTime
TextWindow.Write("Stop: ")
PrintClock()
TextWindow.Write(" ")
EndSub
'
Sub PrintTime ' サブルーチン PrintTime - 時間を出力する
iEms = iEndtime - iBeginTime
TextWindow.Write("Time: ")
PrintClock()
TextWindow.WriteLine("")
EndSub
'
Sub PrintClock ' サブルーチン PrintClock - 時刻を出力する
ConvertEmsToTime()
TextWindow.Write(iTime["Hour"] + ":" + iTime["Munite"] + ":" + iTime["Second"])
EndSub
'
Sub ConvertEmsToTime ' サブルーチン ConvertEmsToTime - Emsを時分秒に変換する
iHMSMs = Math.Remainder(iEms, 24 * 60 * 60 * 1000)
iTime["Hour"] = Math.Floor(iHMSMs / (60 * 60 * 1000))
iMSMs = Math.Remainder(iHMSMs, 60 * 60 * 1000)
iTime["Munite"] = Math.Floor(iMSMs / (60 * 1000))
iSMs = Math.Remainder(iMSMs, 60 * 1000)
iTime["Second"] = Math.Floor(iSMs / 1000)
EndSub