Microsoft Small Basic

Program Listing: RHV135-0
' Goban 0.4
' Copyright (c) 2009, 2010, 2012 Nonki Takahashi. All rights reserved.
'
' History :
' 0.4 2012/10/31 Rewrote in English. (RHV135-0)
' 0.3 2012/10/27 Rewrote in English. (RHV135)
' 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.4"

' constant
SPACE = 0 ' null point (no stone exists)
BLACK = 1 ' black stone
WHITE = 2 ' white stone
OB = 3 ' out of board
CRLF = Text.GetCharacter(13) + Text.GetCharacter(10) ' carriage return and line feed

' initialize go board
ro = 5 ' how much lines?
InitBoard()
turn = BLACK
DrawBoard()

' initialize turn
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)
ShowTurn()

' initialize game record
GraphicsWindow.FontSize = 12
GraphicsWindow.FontBold = "False"
record = Controls.AddMultiLineTextBox(xb0, yb1 + dy)
Controls.SetSize(record, GraphicsWindow.Width - xb0 * 2, dy * 7)
GraphicsWindow.FontBold = "True"

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
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
sgf = sgf + ";B[]"
moves = moves + 1
If Math.Remainder(moves, 10) = 0 Then
sgf = sgf + CRLF
EndIf
Controls.SetTextBoxText(record, sgf)
Else
turn = BLACK
sgf = sgf + ";W[]"
moves = moves + 1
If Math.Remainder(moves, 10) = 0 Then
sgf = sgf + CRLF
EndIf
Controls.SetTextBoxText(record, sgf)
EndIf
EndIf
ShowTurn()
Else
Program.Delay(100)
EndIf
EndWhile

Sub ShowTurn
' shows 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 = 40 ' offset of first line
dx = 30 ' duration between lines
x1 = x0 + (ro - 1) * dx
y0 = 40 ' offset of first line
dy = 30 ' duration between lines
y1 = y0 + (ro - 1) * dy

rs = dx / 2 - 1 ' radius of stone
ds = 3 ' 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 col - column
' param row - row
' param color - stone color
' param mv[] - alphabet for SGF game record
If (0 < col) And (col <= ro) And (0 < row) And (row <= ro) Then
bd[col][row] = color
If color = BLACK Then
sgf = sgf + ";B[" + mv[col] + mv[row] + "]"
moves = moves + 1
If Math.Remainder(moves, 10) = 0 Then
sgf = sgf + CRLF
EndIf
Controls.SetTextBoxText(record, sgf)
DrawStone()
ElseIf color = WHITE Then
sgf = sgf + ";W[" + mv[col] + mv[row] + "]"
moves = moves + 1
If Math.Remainder(moves, 10) = 0 Then
sgf = sgf + CRLF
EndIf
Controls.SetTextBoxText(record, sgf)
DrawStone()
ElseIf color = SPACE Then
RemoveStone()
EndIf
EndIf
EndSub

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

Sub DrawStone
' draws stone on board
' param col - row
' param row - 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 + (col - 1) * dx - rs
sy = y0 + (row - 1) * dy - rs
Shapes.ShowShape(shadow[col][row])
If stone[col][row] = "" 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[col][row] = Shapes.AddEllipse(2 * rs, 2 * rs)
Shapes.Move(stone[col][row], sx, sy)
If (color = BLACK) Then
GraphicsWindow.BrushColor = "Gray" ' high light color
ElseIf (color = WHITE) Then
GraphicsWindow.BrushColor = "White" ' high light color
EndIf
hilite[col][row] = Shapes.AddEllipse(rs / 2, rs / 2)
Shapes.Move(hilite[col][row], sx + rs / 2, sy + rs / 2)
Else
Shapes.ShowShape(stone[col][row])
Shapes.ShowShape(hilite[col][row])
EndIf
EndSub

Sub RemoveStone
' draws stone on board
' param col - row
' param row - colomn
Shapes.HideShape(shadow[col][row])
If stone[col][row] <> "" Then
Shapes.Remove(stone[col][row])
Shapes.Remove(hilite[col][row])
stone[col][row] = ""
hilite[col][row] = ""
EndIf
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 - dx ' left
yb0 = y0 - 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

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

' draw board shadow
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.PenWidth = 0
ds = 10
sh1 = Shapes.AddTriangle(0, 0, 0, ds, ds, ds)
Shapes.SetOpacity(sh1, 50)
Shapes.Move(sh1, xb1, yb0)
sh2 = Shapes.AddTriangle(0, 0, ds, 0, ds, ds)
Shapes.SetOpacity(sh2, 50)
Shapes.Move(sh2, xb0, yb1)
sh3 = Shapes.AddRectangle(ds, xb1 - xb0)
Shapes.SetOpacity(sh3, 50)
Shapes.Move(sh3, xb1, yb0 + ds)
sh4 = Shapes.AddRectangle(yb1 - yb0 - ds, ds)
Shapes.SetOpacity(sh4, 50)
Shapes.Move(sh4, xb0 + ds, yb1)

' 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 < yb0) And (yb0 < yw0) Then ' clipping on top edge
xw1 = xw0 + Math.Floor((xw1 - xw0) * (yb0 - yw0) / (yw1 - yw0))
yw1 = yb0
ElseIf (yw0 < yb0) And (yb0 < yw1) Then ' clipping on top edge
xw0 = xw1 + Math.Floor((xw0 - xw1) * (yb0 - yw1) / (yw0 - yw1))
yw0 = yb0
EndIf
If (yw1 < yb1) And (yb1 < yw0) Then ' clipping on bottom edge
xw0 = xw1 + Math.Floor((xw0 - xw1) * (yb1 - yw1) / (yw0 - yw1))
yw0 = yb1
ElseIf (yw0 < yb1) And (yb1 < yw1) Then ' clipping on bottom edge
xw1 = xw0 + Math.Floor((xw1 - xw0) * (yb1 - yw0) / (yw1 - yw0))
yw1 = yb1
EndIf
If (xw1 < xb0) And (xb0 < xw0) Then ' clipping on left edge
xw1 = xb0
yw1 = yw0 + Math.Floor((yw1 - yw0) * (xb0 - xw0) / (xw1 - xw0))
ElseIf (xw0 < xb0) And (xb0 < xw1) Then ' clipping on left edge
xw0 = xb0
yw0 = yw1 + Math.Floor((yw0 - yw1) * (xb0 - xw1) / (xw0 - xw1))
EndIf
If (xw1 < xb1) And (xb1 < xw0) Then ' clipping on rigt edge
xw0 = xb1
yw0 = yw1 + Math.Floor((yw0 - yw1) * (xb1 - xw1) / (xw0 - xw1))
ElseIf (xw0 < xb1) And (xb1 < xw1) Then ' clipping on right edge
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.BrushColor = "Black" ' color of lines
GraphicsWindow.FillRectangle(x0 - 1, y0 - 1, 1, y1 - y0 + 3) ' bold left first line
For x = x0 To x1 Step dx
GraphicsWindow.FillRectangle(x, y0, 1, y1 - y0 + 1) ' vertical line
EndFor
GraphicsWindow.FillRectangle(x1 + 1, y0 - 1, 1, y1 - y0 + 3) ' bold right first line
GraphicsWindow.FillRectangle(x0 - 1, y0 - 1, x1 - x0 + 3, 1) ' bold top first line
For y = y0 To y1 Step dy
GraphicsWindow.FillRectangle(x0, y, x1 - x0 + 1, 1) ' horizontal line
EndFor
GraphicsWindow.FillRectangle(x0 - 1, y1 + 1, x1 - x0 + 3, 1) ' bold bootom first line

' draw stars
Stack.PushValue("local", rs)
rs = 3 ' radius of star
If 6 < ro 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 col, row - column and row on board
' return onboard - "True" if on board
rs = Math.Floor(dx / 2) - 1 ' radius of stone

col = Math.Floor((x - (x0 - rs)) / dx) + 1
row = Math.Floor((y - (y0 - rs)) / dx) + 1

If (1 <= col) And (col <= ro) And (1 <= row) And (row <= ro) Then
onboard = "True"
Else
onboard = "False"
EndIf
EndSub