Microsoft Small Basic

Program Listing: RHV135
' Goban 0.3
' Copyright (c) 2009, 2010, 2012 Nonki Takahashi. All rights reserved.
'
' History :
' 0.3 2012/10/27 Rewrote in English.
' 0.2 2010/07/07 Minor changed (from [y][x] to [x][y]).
' 0.1 2010/06/29 Converted from goban.java written in 2009.
'
GraphicsWindow.Title = "Goban 0.3"

' constant
SPACE = 0 ' null point (no stone exists)
BLACK = 1 ' black stone
WHITE = 2 ' white stone
OB = 3 ' out of board

' initialize igo board (as tsume-go problem)
ro = 6 ' how much lines?
d19 = 19 - ro ' difference from 19 ro (lines)
base = 16
InitBoard()
turn = BLACK

GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 20
turnb = Shapes.AddText("Black (黒番)")
Shapes.HideShape(turnb)
turnw = Shapes.AddText("White (白番)")
Shapes.HideShape(turnw)
Shapes.Move(turnb, x1 + 2 * dx, y0 - dx / 3)
Shapes.Move(turnw, x1 + 2 * dx, y0 - dx / 3)
DrawBoard()

color = BLACK
rx = 1
ry = 14 - d19
PutStone()
rx = 2
ry = 14 - d19
PutStone()
rx = 3
ry = 14 - d19
PutStone()
rx = 4
ry = 14 - d19
PutStone()
rx = 1
ry = 15 - d19
PutStone()
rx = 4
ry = 15 - d19
PutStone()
rx = 5
ry = 16 - d19
PutStone()
rx = 5
ry = 17 - d19
PutStone()
rx = 6
ry = 18 - d19
PutStone()
rx = 7
ry = 18 - d19
PutStone()

color = WHITE
rx = 2
ry = 15 - d19
PutStone()
rx = 3
ry = 15 - d19
PutStone()
rx = 1
ry = 16 - d19
PutStone()
rx = 2
ry = 16 - d19
PutStone()
rx = 4
ry = 16 - d19
PutStone()
rx = 4
ry = 17 - d19
PutStone()
rx = 5
ry = 18 - d19
PutStone()

Paint()
GraphicsWindow.MouseUp = OnMouseUp
continue = "True"
While continue
If clicked Then
clicked = "False"
Sound.PlayClickAndWait()
' draw (or remove) stone on mouse click
GetPos()
If onboard Then
rx = pos[0]
ry = pos[1]
GetStone()
If (color = SPACE) Then
color = turn
PutStone()
If turn = BLACK Then
turn = WHITE
Else
turn = BLACK
EndIf
Else
color = SPACE
PutStone()
EndIf
Else
If turn = BLACK Then
turn = WHITE
Else
turn = BLACK
EndIf
EndIf
Paint()
Else
Program.Delay(100)
EndIf
EndWhile

Sub Paint
' draws current board and stones
' show next turn
GraphicsWindow.FontSize = 20
If (turn = BLACK) Then
Shapes.HideShape(turnw)
Shapes.ShowShape(turnb)
Else ' If (turn = WHITE) Then
Shapes.HideShape(turnb)
Shapes.ShowShape(turnw)
EndIf
EndSub

Sub OnMouseUp
x = GraphicsWindow.MouseX
y = GraphicsWindow.MouseY
clicked = "True"
EndSub

Sub InitBoard
' initializes igo board
' param ro - number of ro
' work x, y
' work i
' work ds - offset of shadow
' return ro0, ro1 - positions of stars
' return x0, x1, dx - offset of first line, duration between lines
' return y0, y1, dy - offset of first line, duration between lines
' return bd[][] - igo board
' return mv[] - alphabet for game record
' return rs - radius of stone
ro0 = (ro + 1) / 4 ' position of star
ro1 = (ro + 1) / 2 ' position of star
x0 = 70 ' offset of first line
dx = 30 ' duration between lines
x1 = x0 + (ro - 1) * dx
y0 = 70 ' offset of first line
dy = 30 ' duration between lines
y1 = y0 + (ro - 1) * dy

rs = dx / 2 - 1 ' radius of stone
ds = 2 ' offset of shadow
stone = "" ' stone shape
shadow = "" ' shadow shape
For y = 1 To ro
For x = 1 To ro
bd[x][y] = SPACE
sx = x0 + (x - 1) * dx - rs
sy = y0 + (y - 1) * dy - rs
GraphicsWindow.PenWidth = 0
GraphicsWindow.BrushColor = "Black" ' shadow color
shadow[x][y] = Shapes.AddEllipse(2 * rs, 2 * rs)
Shapes.Move(shadow[x][y], sx + ds, sy + ds)
Shapes.SetOpacity(shadow[x][y], 50)
Shapes.HideShape(shadow[x][y])
EndFor
EndFor

For i = 0 To ro + 1
bd[i][0] = OB
bd[i][ro + 1] = OB
bd[0][i] = OB
bd[ro + 1][i] = OB
EndFor

For i = 0 To ro
' alphabet for SGF game record
mv[i] = Text.GetSubText(" abcdefghijklmnopqrs", i + 1, 1)
EndFor
EndSub

Sub PutStone
' puts stone on board
' param rx - row
' param ry - column
' param color - stone color
' param mv[] - alphabet for SGF game record
If (rx>0 And rx<=ro And ry>0 And ry<=ro) Then
bd[rx][ry] = color
If (color = BLACK) Then
TextWindow.WriteLine(";B[" + mv[rx] + mv[ry] + "]C[Black(" + rx + "," + ry + ")]")
DrawStone()
ElseIf (color = WHITE) Then
TextWindow.WriteLine(";W[" + mv[rx] + mv[ry] + "]C[White(" + rx + "," + ry + ")]")
DrawStone()
ElseIf (color = SPACE) Then
TextWindow.WriteLine(";E[" + mv[rx] + mv[ry] + "]C[×(" + rx + "," + ry + ")]")
RemoveStone()
EndIf
EndIf
EndSub

Sub GetStone
' returns color of stone
' param rx - row
' param ry - column
' return color - stone color
If (rx >= 1 And rx <= ro And ry >= 1 And ry <= ro) Then
color = bd[rx][ry]
Else
color = OB
EndIf
EndSub

Sub DrawStone
' draws stone on board
' param rx - row
' param ry - colomn
' param color - stone color
' param rs - radius of stone
' work ds - offset of shadow
' work sx, sy - left top coordinate of stone

' draw stone
sx = x0 + (rx - 1) * dx - rs
sy = y0 + (ry - 1) * dy - rs
Shapes.ShowShape(shadow[rx][ry])
If stone[rx][ry] = "" Then
GraphicsWindow.PenWidth = 0
If (color = BLACK) Then
GraphicsWindow.BrushColor = "Black" ' black stone color
ElseIf (color = WHITE) Then
rgb = GraphicsWindow.GetColorFromRGB(240, 240, 240)
GraphicsWindow.BrushColor = rgb ' white stone color
EndIf
stone[rx][ry] = Shapes.AddEllipse(2 * rs, 2 * rs)
Shapes.Move(stone[rx][ry], sx, sy)
If (color = BLACK) Then
GraphicsWindow.BrushColor = "Gray" ' high light color
ElseIf (color = WHITE) Then
GraphicsWindow.BrushColor = "White" ' high light color
EndIf
hilite[rx][ry] = Shapes.AddEllipse(rs / 2, rs / 2)
Shapes.Move(hilite[rx][ry], sx + rs / 2, sy + rs / 2)
Else
Shapes.ShowShape(stone[rx][ry])
Shapes.ShowShape(hilite[rx][ry])
EndIf
EndSub

Sub RemoveStone
' draws stone on board
' param rx - row
' param ry - colomn
Shapes.HideShape(shadow[rx][ry])
If stone[rx][ry] <> "" Then
Shapes.Remove(stone[rx][ry])
Shapes.Remove(hilite[rx][ry])
stone[rx][ry] = ""
hilite[rx][ry] = ""
EndIf
EndSub

Sub Dec2Base
' Convert decimal to b base system (2<=b<=16)
' param n10 - decimal number
' param base - base of the numeral system
' work d - one digit of b base system number
' return nb - string of b base system number
digits="0123456789ABCDEF"
nb = ""
While n10 > 0
d = n10 - Math.Floor(n10 / base) * base
nb = Text.Append(Text.GetSubText(digits, d + 1, 1), nb)
n10 = Math.Floor(n10 / base)
EndWhile
EndSub

Sub DrawBoard
' param x0, y0 - left and top
' work xb0, yb0 - left and top coordinate of board
' work xb1, yb1 - right and botton coordinate of board
' work i
' work xo, yo, xw, yw, xc, yc, rw, theta, xw0, xw1, yw0, yw1, x, y
' work r, g, b, rs
xb0 = x0 - 2 * dx ' left
yb0 = y0 - 2 * dy ' top
xb1 = x1 + dx ' right
yb1 = y1 + dy ' bottom
If GraphicsWindow.Width < xb1 + dx * 4 Then
GraphicsWindow.Width = xb1 + dx * 4
EndIf
If GraphicsWindow.Height < yb1 + dy / 3 Then
GraphicsWindow.Height = yb1 + dy / 3
EndIf
For i = 0 To 19
' arabic numbers
an[i] = Text.GetSubText(" 0 1 2 3 4 5 6 7 8 910111213141516171819", i * 2 + 1, 2)
EndFor
For i = 0 To 19
' kanji numbers
kn[i] = Text.GetSubText(" 〇 一 二 三 四 五 六 七 八 九 十十一十二十三十四十五十六十七十八十九", i * 2 + 1, 2)
EndFor

' draw board
rgb = GraphicsWindow.GetColorFromRGB(240, 200, 140)
GraphicsWindow.BrushColor = rgb ' board color
GraphicsWindow.FillRectangle(xb0, yb0, xb1-xb0+1, yb1-yb0+1)

' draw wood grain
rgb = GraphicsWindow.GetColorFromRGB(192, 153, 86)
GraphicsWindow.PenColor = rgb ' wood grain color
GraphicsWindow.PenWidth = 1
xc = xb0 + Math.Floor((xb1 - xb0) * 5 / 7) ' center of wood grain
yc = yb0 + Math.Floor((yb1 - yb0) * 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 xw1 = xw0+Math.Floor((xw1-xw0)*(yb0-yw0)/(yw1-yw0))
yw1 = yb0
ElseIf (yw0 xw0 = xw1+Math.Floor((xw0-xw1)*(yb0-yw1)/(yw0-yw1))
yw0 = yb0
EndIf
If (yw1 xw0 = xw1+Math.Floor((xw0-xw1)*(yb1-yw1)/(yw0-yw1))
yw0 = yb1
ElseIf (yw0 xw1 = xw0+Math.Floor((xw1-xw0)*(yb1-yw0)/(yw1-yw0))
yw1 = yb1
EndIf
If (xw1 xw1 = xb0
yw1 = yw0+Math.Floor((yw1-yw0)*(xb0-xw0)/(xw1-xw0))
ElseIf (xw0 xw0 = xb0
yw0 = yw1+Math.Floor((yw0-yw1)*(xb0-xw1)/(xw0-xw1))
EndIf
If (xw1 xw0 = xb1
yw0 = yw1+Math.Floor((yw0-yw1)*(xb1-xw1)/(xw0-xw1))
ElseIf (xw0 xw1 = xb1
yw1 = yw0+Math.Floor((yw1-yw0)*(xb1-xw0)/(xw1-xw0))
EndIf
If (xb0<=xw0 And xw0<=xb1 And xb0<=xw1 And xw1<=xb1 And yb0<=yw0 And yw0<=yb1 And yb0<=yw1 And yw1<=yb1) Then
GraphicsWindow.DrawLine(xw0, yw0, xw1, yw1)
EndIf
xo = xw
yo = yw
EndFor
EndFor

' draw lines
GraphicsWindow.PenColor = "Black" ' color of lines
For x = x0 To x1 Step dx
GraphicsWindow.DrawLine(x, y0, x, y1) ' vertical line
EndFor
For y = y0 To y1 Step dy
GraphicsWindow.DrawLine(x0, y, x1, y) ' horizontal line
EndFor
GraphicsWindow.DrawLine(x0 - 1, y0 - 1, x1 + 1, y0 - 1) ' bold top first line
GraphicsWindow.DrawLine(x0 - 1, y1 + 1, x1 + 1, y1 + 1) ' bold bootom first line
GraphicsWindow.DrawLine(x0 - 1, y0 - 1, x0 - 1, y1 + 1) ' bold left first line
GraphicsWindow.DrawLine(x1 + 1, y0 - 1, x1 + 1, y1 + 1) ' bold write first line

' draw numbers
GraphicsWindow.FontSize = 20
GraphicsWindow.BrushColor = "Black" ' color of star and number
i = 1
For x = x0 To x1 Step dx
GraphicsWindow.DrawText(x - dx / 2, y0 - 4 * dy / 3, an[i]) ' column number
i = i + 1
EndFor
i = 1
For y = y0 To y1 Step dy
If i < 11 Then
GraphicsWindow.FontSize = 20
GraphicsWindow.DrawText(x0 - 5 * dx / 4, y - dy / 3, Text.GetSubText(kn[i], 2, 1)) ' row number
Else
GraphicsWindow.FontSize = 18
GraphicsWindow.DrawText(x0 - 5 * dx / 4, y - 7 * dy / 12, Text.GetSubText(kn[i], 1, 1)) ' row number
GraphicsWindow.DrawText(x0 - 5 * dx / 4, y - 1 * dy / 12, Text.GetSubText(kn[i], 2, 1)) ' row number
EndIf
i = i + 1
EndFor

' draw stars
Stack.PushValue("local", rs)
rs = 3 ' radius of star
If (ro > 6) Then
If (ro = 9) Then
ro0 = 3
ro1 = 5
ElseIf (ro = 13) Then
ro0 = 4
ro1 = 7
ElseIf (ro = 19) Then
ro0 = 4
ro1 = 10
GraphicsWindow.FillEllipse(x0 + (ro1 - 1) * dx - rs, y0 + (ro0 - 1) * dy - rs, 2 * rs, 2 * rs) ' top edge
GraphicsWindow.FillEllipse(x0 + (ro0 - 1) * dx - rs, y0 + (ro1 - 1) * dy - rs, 2 * rs, 2 * rs) ' left edge
GraphicsWindow.FillEllipse(x0 + (ro - ro0) * dx - rs, y0 + (ro1 - 1) * dy - rs, 2 * rs, 2 * rs) ' right edge
GraphicsWindow.FillEllipse(x0 + (ro1 - 1) * dx - rs, y0 + (ro - ro0) * dy - rs, 2 * rs, 2 * rs) ' bottom edge
EndIf
GraphicsWindow.FillEllipse(x0 + (ro0 - 1) * dx - rs, y0 + (ro0 - 1) * dy - rs, 2 * rs, 2 * rs) ' left top corner
GraphicsWindow.FillEllipse(x0 + (ro0 - 1) * dx - rs, y0 + (ro - ro0) * dy - rs, 2 * rs, 2 * rs) ' left bottom corner
GraphicsWindow.FillEllipse(x0 + (ro - ro0) * dx - rs, y0 + (ro - ro0) * dy - rs, 2 * rs, 2 * rs) ' right bottom corner
GraphicsWindow.FillEllipse(x0 + (ro - ro0) * dx - rs, y0 + (ro0 - 1) * dy - rs, 2 * rs, 2 * rs) ' right top corner
GraphicsWindow.FillEllipse(x0 + (ro1 - 1) * dx - rs, y0 + (ro1 - 1) * dy - rs, 2 * rs, 2 * rs) ' tengen (center)
EndIf
rs = Stack.PopValue("local")
EndSub

Sub GetPos
' gets column and row from mouse coordinate
' param x - mouse x coordinate
' param y -mouse y coordinate
' work rs - radius of stone
' return pos[] - column and row on board
' return onboard - "True" if on board
rs = Math.Floor(dx / 2) - 1 ' radius of stone

pos[0] = Math.Floor((x - (x0 - rs)) / dx) + 1
pos[1] = Math.Floor((y - (y0 - rs)) / dx) + 1

If (pos[0] >= 1 And pos[0] <= ro And pos[1] >= 1 And pos[1] <= ro) Then
onboard = "True"
Else
onboard = "False"
EndIf
EndSub