Small Basic: Code Conversion From Visual Basic (MasterMind Game)

This article shows how to convert Visual Basic program to Small Basic manually.  As an example, a Visual Basic program [[articles:MasterMind Game]] is used to show them here.

Introduction

Small Basic is a program language for beginners.  Compared with Visual Basic, Small Basic has only primitive functions.  There are no form functions, no combo box, no ability to write class and no events will be added.  Following picture shows the main form and message box of MasterMind.  Small Basic has message box function so the main form is the only window to code with GraphicsWindow functions.  This article shows how to convert Visual Basic program to Small Basic along with converted MasterMind Game program.  Please confer original source code in a TechNet Wiki article [[articles:MasterMind Game]].

Message Loop

Following code is the main routine in Small Basic.  In Visual Basic, most of subroutines are called by event.  Visual Basic runtime handles many kind of events and dispatch them to the subroutines (event handlers).  Small Basic events are limited, and sometimes it is needed to write dispatch code as follows.  At first Form_Load subroutine is called and after that main loop dispatches events to Controls_Proc and Form_SelectedIndexChanged for combo box, Form_btnCheck_Click for [Check] button, Form_btnCheck_Click for [New Game] button, and Peg_Click_Check for mouse click. 

' MasterMind Game
' Original by _paul_ (Visual Basic Version)
' Modified by Nonki Takahashi (Small Basic Version)
' Last update 2019-10-06
' Program ID GMV958-0
 
Form_Load()
While "True"
  If Controls_triggered Then
    Controls_Proc()
    If selectedIndexChanged Then
      Form_SelectedIndexChanged()
    EndIf
  ElseIf btnCheck_Clicked Then
    Form_btnCheck_Click()
    btnCheck_Clicked = "False"
  ElseIf btnNew_Clicked Then
    Form_btnNew_Click()
    btnNew_Clicked = "False"
  ElseIf Controls_mouseDown Then
    Peg_Click_Check()
    Controls_mouseDown = "False"
  Else
    Program.Delay(200)
  EndIf
EndWhile
 

Dummy Code

Following subroutine is actually not be called. But to avoid syntax error in Small Basic, variable cms is set.  This kind of dummy code may help rapid conversion.

Sub Dummy
  cms = "Not Used" 
EndSub
 

Combo Box

Small Basic doesn't have combo box control (only has button and text box).  So following subroutines are for the control.  Small Basic users wrote cods for many kind of  controls.  Some of them are described in a TechNet Wiki article Small Basic: Controls.  Small Basic also doesn't have ability to create new class.  So in this case the prefix Controls_ for these subroutine names is used as pseudo class definition.

Sub Controls_AddComboBox
  ' param item - array of items
  ' param left - the x co-ordinate of the combo box
  ' param top - the y co-ordinate of the combo box
  ' return cbox - the combo box
  Stack.PushValue("local", i)
  nCBox = nCBox  + 1
  fs = GraphicsWindow.FontSize
  cbProp[nCBox]["height"] = fs  * 1.8
  nItem = Array.GetItemCount(item)
  cbProp[nCBox]["nItem"] = nItem
  cbProp[nCBox]["item"] = item
  widthMax = 0
  For i =  1 To nItem
    len = Text.GetLength(item[i])
    width = 0
    For j =  1 To len
      width = width  + Math.Floor(luw[Text.GetSubText(item[i], j, 1)] * fs  / 100)
    EndFor
    If widthMax <  width Then
      widthMax = width
    EndIf
  EndFor
  tboxWidth = widthMax  ' + fs
  cbProp[nCBox]["width"] = tboxWidth
  cbProp[nCBox]["x"] = left
  cbProp[nCBox]["y"] = Top
  cbProp[nCBox]["tbox"] = Controls.AddTextBox(left, Top)
  Controls.SetSize(cbProp[nCBox]["tbox"], tboxWidth,  cbProp[nCBox]["height"])
  selectedIndex = 1
  Controls.SetTextBoxText(cbProp[nCBox]["tbox"], cbProp[nCBox]["item"][selectedIndex])
  cbProp[nCBox]["btn"] = Controls.AddButton("?", left +  tboxWidth -  1, Top)
  Controls.SetSize(cbProp[nCBox]["btn"], fs *  1.8, cbProp[nCBox]["height"])
  cbox = "ComboBox" + nCBox
  Controls.ButtonClicked = Controls_OnButtonClicked
  GraphicsWindow.MouseMove = Controls_OnMouseMove
  GraphicsWindow.MouseDown = Controls_OnMouseDown
  i = Stack.PopValue("local")
EndSub
 
Sub Controls_Proc
  ' 
  selectedIndexChanged = "False"
  For i =  1 To nCBox
    If Controls.LastClickedButton = cbProp[i]["btn"] Then
      GraphicsWindow.PenColor = "Gray"
      GraphicsWindow.PenWidth = 1
      GraphicsWindow.BrushColor = "White"
      rect = Shapes.AddRectangle(cbProp[i]["width"], cbProp[i]["height"] * cbProp[i]["nItem"])
      Shapes.Move(rect, cbProp[i]["x"], cbProp[i]["y"] + cbProp[i]["height"] - 1)
      GraphicsWindow.BrushColor = "Black"
      For j =  1 To cbProp[i]["nItem"]
        it[j] = Shapes.AddText(cbProp[i]["item"][j])
        Shapes.Move(it[j], cbProp[i]["x"] + cbProp[i]["height"] * 0.3, cbProp[i]["y"] + (j + 0.2) * cbProp[i]["height"])
      EndFor
      Controls_mouseDown = "False"
      While Not[Controls_mouseDown]
        If Controls_mouseMove Then
          Controls_Select()
          Controls_mouseMove = "False"
        Else
          Program.Delay(200)
        EndIf
      EndWhile
      Controls_Select()
      Shapes.Remove(cbSelect)
      cbSelect = ""
      For j =  1 To cbProp[i]["nItem"]
        Shapes.Remove(it[j])
      EndFor
      Shapes.Remove(rect)
      If selected <> 0 Then
        lastItem = Controls.GetTextBoxText(cbProp[i]["tbox"])
        If lastItem <> cbProp[i]["item"][selected] Then
          Controls.SetTextBoxText(cbProp[i]["tbox"],cbProp[i]["item"][selected])
          selectedIndexChanged = "True"
          selectedIndex = selected
        EndIf
      EndIf
    EndIf
  EndFor
  Controls_triggered = "False"
EndSub
 
Sub Controls_Init
  Not = "False=True;True=False;"
  GraphicsWindow.FontName = "Lucida UI"
  GraphicsWindow.BrushColor = "Black"
  WQ = Text.GetCharacter(34)
  ' Lucida UI font width [px] table while the size (height) 100 [px]
  luw = " =60;!=65;" + WQ  + "=82;#=92;$=90;%=119;&=117;'=62;(=69;)=69;"
  luw = luw  + "*=78;+=103;,=59;-=73;.=59;/=77;0=90;1=90;2=90;3=90;4=90;"
  luw = luw  + "5=90;6=90;7=90;8=90;9=90;:=59;\;=59;<=103;\==103;>=103;"
  luw = luw  + "?=76;@=128;A=86;B=94;C=80;D=94;E=86;F=71;G=94;H=93;I=61;"
  luw = luw  + "J=61;K=88;L=61;M=124;N=93;O=94;P=94;Q=94;R=72;S=76;T=71;"
  luw = luw  + "U=93;V=87;W=112;X=88;Y=86;Z=80;[=69;\\=76;]=69;^=103;_=74;"
  luw = luw  + "`=64;{=69;|=65;}=69;~=103;?=60;!=65;¢=90;£=90;?=88;\=90;"
  luw = luw  + "|=65;§=81;¨=79;c=120;a=73;≪=90;¬=103;-=32;R=120; ̄=74;°=70;"
  luw = luw  + "±=103;2=73;3=73;´=63;μ=94;¶=83;・=59;,=54;1=72;o=78;≫=90;"
  luw = luw  + "?=128;?=129;?=130;?=76;A=86;A=86;A=86;A=86;A=86;A=86;A=115;"
  luw = luw  + "C=80;E=86;E=86;E=86;E=86;I=61;I=61;I=61;I=61;D=92;N=93;O=93;"
  luw = luw  + "O=93;O=93;O=93;O=93;×=103;O=94;U=93;U=93;U=93;U=93;Y=86;"
  luw = luw  + "T=94;s=95;÷=103;y=86;"
  Controls_triggered = "False"
EndSub
 
Sub Controls_OnButtonClicked
  ' button handler for [Check] and [New Game] buttons and combo box
  btn = Controls.LastClickedButton
  If btn =  btnCheck Then
    btnCheck_Clicked = "True"
  ElseIf btn =  btnNew Then
    btnNew_Clicked = "True"
  Else
    Controls_triggered = "True"
  EndIf
EndSub
 
Sub Controls_OnMouseMove
  ' mouse move handler for combo box
  Controls_mx = GraphicsWindow.MouseX
  Controls_my = GraphicsWindow.MouseY
  Controls_mouseMove = "True"
EndSub
 
Sub Controls_OnMouseDown
  ' mouse down handler for combo box and peg
  Controls_mx = GraphicsWindow.MouseX
  Controls_my = GraphicsWindow.MouseY
  Controls_mouseDown = "True"
EndSub
 
Sub Controls_Select
  ' select an item from combo box menu
  ' return selected - item
  selected = 0
  If cbProp[i]["x"] <= Controls_mx And Controls_mx <= cbProp[i]["x"] + cbProp[i]["width"] Then
    For j =  1 To cbProp[i]["nItem"]
      y1 = cbProp[i]["y"] + j  * cbProp[i]["height"]
      y2 = y1  + cbProp[i]["height"]
      If y1 <= Controls_my And Controls_my <= y2 Then
        GraphicsWindow.BrushColor = "#663399FF"
        GraphicsWindow.PenWidth = 0
        If cbSelect =  "" Then
          cbSelect = Shapes.AddRectangle(cbProp[i]["width"], cbProp[i]["height"])
        EndIf
        Shapes.Move(cbSelect, cbProp[i]["x"], y1 -  1)
        selected = j
      EndIf
    EndFor
  EndIf
EndSub
 

Custom Control

Original program in Visual Basic defines a peg as a custom control.  Small Basic doesn't have a such feature.  So, especially, it is needed to write invalidate code e.g. Peg_Invalidate.  The invalidate code should call paint subroutine. 

' ----------------------------------------------------------------
' Code (The pegPlace custom control):
' ----------------------------------------------------------------
' The rows of ellipses are actually controls derived from the Control Class with a 
' pegColor Property (which is initially set to Empty), and a Boolean property: 
' CMSEnabled:
 
Sub Peg_Init
  pegColor = ""
  CMSEnabled = ""
EndSub
 
' ...an overridden OnPaint event. (I eventually decided regular Green and Blue were 
' too dark, so I chose Lime and RoyalBlue instead):
 
Sub Peg_OnPaint
  If visible[peg] Then
    GraphicsWindow.BrushColor = bg
    GraphicsWindow.FillRectangle(pegX[peg] - 1, pegY[peg] - 1, 17,  17)
    If pegColor[peg] = "Green"  Then
      GraphicsWindow.BrushColor = "Lime"
    ElseIf pegColor[peg] = "Blue"  Then
      GraphicsWindow.BrushColor = "RoyalBlue"
    Else
      GraphicsWindow.BrushColor = pegColor[peg]
    EndIf
    GraphicsWindow.FillEllipse(pegX[peg], pegY[peg], 15,  15)
    GraphicsWindow.PenWidth = 1
    GraphicsWindow.PenColor = black
    GraphicsWindow.DrawEllipse(pegX[peg], pegY[peg], 15,  15)
  EndIf
EndSub 
 
' ...a reset method:
 
Sub Peg_Reset
  pegColor[peg] = bg
  Peg_Invalidate()
EndSub
 
' ...a ContextMenuStrip and some handlers and a public event:
 
'Public Event colorSelected(sender As Object)
'Private WithEvents cms As New ContextMenuStrip
 
Sub Peg_ItemClicked
  ' param sender As Object
  ' param e As EventArgs
  peg = sender
  c = ToolStripMenuItem[peg][1]
  pegColor[peg] = c
  Peg_Invalidate()
  Form_ColorSelected()
EndSub
 
Sub Peg_CMS_Opening
  ' param sender As Object
  ' param e As System_ComponentModel_CancelEventArgs
  ' Handles cms_Opening
  e_Cancel = Not[CMSEnabled]
EndSub 
 
' Notice how the ContextMenuStrip only opens for controls in the current line?
' In the itemClicked event, I raised an event to inform the parent control (Form1) 
' that color had been set for the pegPlace. On receiving that event notification, 
' the code in the form checks whether to enable btnCheck or not.
' This code is duplicated in the control’s MouseDown event, where you can click to 
' cycle through the colors:
 
Sub Peg_OnMouseDown
  ' param e As MouseEventArgs
  If CMSEnabled[peg] Then 'And Mouse.IsLeftButtonDown Then
    colors = "1=Red;2=Green;3=Blue;4=Yellow;"
    Color_FromName = "Red=1;Green=2;Blue=3;Yellow=4;"
    index = 0
    For i =  1 To 4
      If pegColor[peg] = colors[i] Then
        index = i
        i = 4  ' exit For
      EndIf
    EndFor
    index = Math.Remainder(index, 4) + 1
    pegColor[peg] = colors[index]
    Peg_Invalidate()
    Form_ColorSelected()
  EndIf
EndSub
 
Sub Peg_Click_Check
  y = lineIndex
  For x =  1 To 6
    peg = lines[y][x]
    If visible[peg] Then
      x1 = pegX[peg]
      x2 = x1  + size[peg]["x"]
      y1 = pegY[peg]
      y2 = y1  + size[peg]["y"]
      mx = Controls_mx
      my = Controls_my
      If (x1  <= mx) And (mx <= x2) And (y1 <= my) And (my <= y2) Then
        sender = peg
        Peg_OnMouseDown()
      EndIf
    EndIf
  EndFor
EndSub
 
' In the control’s constructor, I set the size, and setup the ContextMenuStrip:
'
' A ContextMenuStrip_Items property contains objects of type: ToolStripMenuItem.
' In the code I added an array of ToolStripMenuItem, created from an array of 
' Strings, using the Array_ConvertAll Generic Method with a Lambda Function to 
' convert each string to a ToolStripMenuItem, using the ToolStripMenuItem 
' OverLoad that takes a String (the text), an Image (unused in my implementation),
' and an EventHandler (the common itemClicked Sub-Procedure):
 
Sub Peg_New
  size[peg] = "x=16;y=16;"
  contextMenuStrip[peg] = cms
  ToolStripMenuItem[peg] = "1=Red;2=Green;3=Blue;4=Yellow;"
EndSub
 
Sub Peg_Invalidate
  Peg_OnPaint()
EndSub
 

Form

Original game pane is defined as Form1.  This Small Basic code uses Form_ prefix to show pseudo class for these subroutines.  There is no form editor, so the form should be coded here.  Detail game pane such as peg structures is defined in Form_Load subroutine.  As like original, Form_Paint draws feedback small circles.

Small Basic doesn't have ability to enable/disable buttons.  So, transparent rectangles (as Shapes) are overridden on the buttons to enable/disable them. 

' ----------------------------------------------------------------
' Code (The Form):
' ----------------------------------------------------------------
' In the Load event, I load some arrays (which are reference types ) and add the 
' pegPlace colorSelected event handler, which enables or disables btnCheck. Setting 
' the ToolStripComboBox_SelectedIndex sets up the UI and the call to newGame() 
' initializes the variables for gameplay:
'
' The winning line array is a string array, which contains the current random 
' winning sequence of colors. Colors are assigned with a Form level Random object, 
' ensuring maximum randomness (see: Random Class and: Random Constructor (Int32) ):
 
Sub Form_Load
  ' param sender As Object
  ' param e As EventArgs
  ' Handles MyBase_Load
  title = "mastermind"
  GraphicsWindow.Title = title
  black = "#CC000000"
  bg = "#EEEEEE"
  GraphicsWindow.BackgroundColor = bg
  Controls_Init()
  gw = 154
  gh = 329
  GraphicsWindow.Width = gw
  GraphicsWindow.Height = gh
  item = "1=Beginner;2=Intermediate;3=Advanced;"
  left = 12
  Top = 10
  Controls_AddComboBox()
  scoreLine = "1=1;2=2;3=3;4=4;5=37;6=38;"
  lines[1] = "1=5;2=6;3=7;4=8;5=39;6=40;"
  lines[2] = "1=9;2=10;3=11;4=12;5=41;6=42;"
  lines[3] = "1=13;2=14;3=15;4=16;5=43;6=44;"
  lines[4] = "1=17;2=18;3=19;4=20;5=45;6=46;"
  lines[5] = "1=21;2=22;3=23;4=24;5=47;6=48;"
  lines[6] = "1=25;2=26;3=27;4=28;5=49;6=50;"
  lines[7] = "1=29;2=30;3=31;4=32;5=51;6=52;"
  lines[8] = "1=33;2=34;3=35;4=36;5=53;6=54;"
  lines[9] = "1=55;2=56;3=57;4=58;5=59;6=60;"
  lines[10] = "1=61;2=62;3=63;4=64;5=65;6=66;"
  lines[11] = "1=67;2=68;3=69;4=70;5=71;6=72;"
  lines[12] = "1=73;2=74;3=75;4=76;5=77;6=78;"
  gx = left
  gy = Top  + 32
  For x =  1 To 6
    peg = scoreLine[x]
    Peg_New()
    pegX[peg] = gx
    pegY[peg] = gy
    gx = gx  + size[peg]["x"] * 1.5
  EndFor
  gy = gy  + size[peg]["y"] * 2
  For y =  1 To 12
    gx = left
    For x =  1 To 6
      peg = lines[y][x]
      Peg_New()
      pegX[peg] = gx
      pegY[peg] = gy
      gx = gx  + size[peg]["x"] * 1.5
    EndFor 
    gy = gy  + size[peg]["y"] * 1.5
  EndFor
  GraphicsWindow.BrushColor = "Black"
  btnCheck = Controls.AddButton("Check", left,  gy)
  GraphicsWindow.PenWidth = 0
  GraphicsWindow.BrushColor = "#99"  + Text.GetSubText(bg, 2, 6)
  btnCheckDisabled = Shapes.AddRectangle(100, 26)
  Shapes.Move(btnCheckDisabled, left,  gy)
  gy = gy  + 30
  GraphicsWindow.BrushColor = "Black"
  btnNew = Controls.AddButton("New Game", left,  gy)
  GraphicsWindow.PenWidth = 0
  GraphicsWindow.BrushColor = "#99"  + Text.GetSubText(bg, 2, 6)
  btnNewDisabled = Shapes.AddRectangle(100, 26)
  Shapes.Move(btnNewDisabled, left,  gy)
  Form_SelectedIndexChanged()
EndSub
 
Sub Form_ColorSelected
  ' param sender As Object
  For y =  1 To 12
    For x =  1 To 6
      If sender =  lines[y][x] Then
        containsAll = "True"
        For i =  1 To level
          _peg = lines[y][i]
          If pegColor[_peg] = bg  Then
            containsAll = "False"
          EndIf
        EndFor
        If containsAll Then
          Shapes.HideShape(btnCheckDisabled)
        EndIf
      EndIf
    EndFor
  EndFor
EndSub
 
Sub Form_SelectedIndexChanged
  ' param sender As Object
  ' param e As EventArgs
  ' Handles ToolStripComboBox1_SelectedIndexChanged
  level = selectedIndex + 3
  levelSizes[1] = "x=154;y=329;"
  levelSizes[2] = "x=176;y=373;"
  levelSizes[3] = "x=192;y=416;"
  gw = levelSizes[selectedIndex]["x"]
  GraphicsWindow.Width = gw
  gh = levelSizes[selectedIndex]["y"]
  GraphicsWindow.Height = gh
  GraphicsWindow.BrushColor = bg
  GraphicsWindow.FillRectangle(0, 0, gw, gh)
  
  For x =  1 To 6
    peg = scoreLine[x]
    If x <= level Then
      visible[peg] = "True"
    Else
      visible[peg] = "False"
    EndIf
  EndFor 
  For y =  1 To 12
    For x =  1 To 6
      peg = lines[y][x]
      If (y <= level *  2) And (x <= level)  Then
        visible[peg] = "True"
      Else
        visible[peg] = "False"
      EndIf
    EndFor
    If y <= level *  2 Then
      gy = pegY[peg] + size[peg]["y"] * 1.5
    EndIf
  EndFor
  Controls.Move(btnCheck, left,  gy)
  Shapes.Move(btnCheckDisabled, left,  gy)
  gy = gy  + 30
  Controls.Move(btnNew, left,  gy)
  Shapes.Move(btnNewDisabled, left,  gy)
  Form_NewGame()
EndSub  
 
Sub Form_NewGame
  colors = "1=Red;2=Green;3=Blue;4=Yellow;"
  winningLine = ""
  For x =  1 To level
    winningLine[x] = colors[Math.GetRandomNumber(4)]
  EndFor
  lineIndex = level  * 2
  Form_broadcastCMSEnabled()
  clues = ""
  For x =  1 To 6
    peg = scoreLine[x]
    Peg_Reset()
  EndFor 
  For y =  1 To 12
    For x =  1 To 6
      peg = lines[y][x]
      Peg_Reset()
    EndFor 
  EndFor 
  Shapes.ShowShape(btnCheckDisabled)
  Shapes.ShowShape(btnNewDisabled)
  Form_Invalidate()
EndSub 
 
'...The feedback scores are stored in an array of structure (again a Reference Type 
' array, although each element is a Value Type), with one element for each row of 
' pegPlaces. This array is used in the Form’s Paint event, where the feedback 
' ellipses are drawn directly on the form:
 
Sub Form_Paint
  ' param sender As Object
  ' param e As PaintEventArgs
  ' Handles Me_Paint
  GraphicsWindow.PenWidth = 3
  GraphicsWindow.PenColor = black
  GraphicsWindow.DrawLine(12, 65,  gw - 12, 65)
  If level =  6 Then
    positions[1] = "x=8;y=2;"
    positions[2] = "x=13;y=2;"
    positions[3] = "x=18;y=2;"
    positions[4] = "x=8;y=7;"
    positions[5] = "x=13;y=7;"
    positions[6] = "x=18;y=7;"
  ElseIf level =  5 Then
    positions[1] = "x=8;y=2;"
    positions[2] = "x=13;y=2;"
    positions[3] = "x=18;y=5;"
    positions[4] = "x=8;y=7;"
    positions[5] = "x=13;y=7;"
  Else
    positions[1] = "x=8;y=2;"
    positions[2] = "x=13;y=2;" 
    positions[3] = "x=8;y=7;"
    positions[4] = "x=13;y=7;"
  EndIf
  For y =  12 To 1 Step -1
    peg = lines[y][1]
    If visible[peg] Then 
      For x =  1 To level
        fillColor = "" 
        If x <= clues[y]["black"] Then 
          fillColor = "Black"
        Else 
          If x <= clues[y]["black"] + clues[y]["red"] Then 
            fillColor = "Red"
          EndIf 
        EndIf 
        peg = lines[y][level]
        right = pegX[peg] + size[peg]["x"]
        Top = pegY[peg]
        If x =  1 Then
          GraphicsWindow.BrushColor = bg
          GraphicsWindow.FillRectangle(right, Top +  2, 22, 11) 
        EndIf
        If fillColor <> "" Then
          GraphicsWindow.BrushColor = fillColor
          GraphicsWindow.FillEllipse(right + positions[x]["x"], Top +  positions[x]["y"] + 2, 3, 3)
        EndIf 
        GraphicsWindow.PenColor = black
        GraphicsWindow.PenWidth =  1
        GraphicsWindow.DrawEllipse(right + positions[x]["x"], Top +  positions[x]["y"] + 2, 3, 3)
      EndFor 
    EndIf
  EndFor 
EndSub
 
' ...The btnCheck Click event checks the guessed sequence of colors against the 
' winning sequence of colors. During this checking, the feedback for the row being 
' checked is calculated, then the Paint event is invoked (Control_Invalidate Method) 
' to draw the feedback on the form.
' Also in this event, the app. checks if the game is over, either as a result of a 
' correct guess, or because the eight, ten, or twelve guesses have been unsuccessful. 
' The two Buttons, btnCheck, and btnNew are enabled or disabled in this event, 
' depending on the state of play:
 
Sub Form_btnCheck_Click
  ' param sender As Object
  ' param e As EventArgs
  ' Handles btnCheck_Click
  line = ""
  clues[lineIndex] = "black=0;red=0;"
  countB = 0
  countR = 0
  For x =  1 To level
    peg = lines[lineIndex][x]
    lineColors[x] = pegColor[peg]
    If winningLine[x] = lineColors[x] Then
      countB = countB  + 1
    EndIf
  EndFor
  For x =  1 To level
    If winningLine[x] <> lineColors[x] Then
      For x2 =  1 To level
        If (winningLine[x2] <> lineColors[x2]) And (winningLine[x] = lineColors[x2]) Then 
          temp = lineColors[x]
          lineColors[x] = lineColors[x2]
          countR = countR  + 1
          lineColors[x2] = temp
          If winningLine[x2] = lineColors[x2] Then 
            countR = countR  + 1
          EndIf 
        EndIf 
      EndFor 
    EndIf
  EndFor
  clues[lineIndex]["black"] = countB
  clues[lineIndex]["red"] = countR
  Form_Invalidate()
  If clues[lineIndex]["black"] = level  Then 
    GraphicsWindow.ShowMessage("You've won!", title)
    lineIndex = 0
    Form_broadcastCMSEnabled()
    Shapes.HideShape(btnNewDisabled)
    Shapes.ShowShape(btnCheckDisabled)
  Else
    Shapes.ShowShape(btnCheckDisabled)
    lineIndex = lineIndex - 1
    Form_broadcastCMSEnabled()
    If lineIndex = 0 Then 
      GraphicsWindow.ShowMessage("You've lost!", title)
      Shapes.HideShape(btnNewDisabled)
    Else 
      Goto FbCC_Return
    EndIf 
  EndIf 
  For x =  1 To level
    peg = scoreLine[x]
    pegColor[peg] = winningLine[x]
    Peg_Invalidate()
  EndFor
  FbCC_Return:
EndSub
 
Sub Form_Invalidate
  Form_Paint()
EndSub
 
' ...This method is used after each line is checked to change all of the pegPlaces’ 
' CMSEnabled property:
 
Sub Form_broadcastCMSEnabled
  ' param lineIndex
  For y =  1 To 12
    For x =  1 To 6
      peg = lines[y][x]
      If y =  lineIndex Then
        CMSEnabled[peg] = "True"
      Else
        CMSEnabled[peg] = "False"
      EndIf
    EndFor 
  EndFor 
EndSub
 
' ...The btnNew Click event calls newGame() which puts a new random sequence
' of colors in the winningLine array, then resets all of the Class level variables 
' back to their original state, for a fresh start:
 
Sub Form_btnNew_Click
  ' param sender As Object
  ' param e As EventArgs
  ' Handles btnNew_Click
  Form_NewGame()
EndSub

Other Tips

  • Variables in Small Basic are always global.  So, be careful not to destroy local use variables.  In this program, some variables are converted to arrays to avoid broken.
  • Notation for array is different between in Small Basic and Visual Basic.  Small Basic uses [] but Visual Basic uses () to refer an array element.  And array index origin is one (1) in Small Basic but zero (0) in Visual Basic.
  • Small Basic doesn't have ability to define function with parameters.  So parameters are given as global variables for subroutines.

Conclusion

Small Basic has only primitive functionality.  So, converting Visual Basic program to Small Basic needs some new codes to complement Visual Basic features like above.  But this article shows the conversion is able.  This means that Small Basic has ability to create practical programs, games or tools.

Appendix

How To Play MasterMind Game

  1. Select a level from the combo box first.
  2. Guess colors and select them by clicking circles.
  3. Push [Check] button to see the feedback - small circles.  The feedback means:
    black - both color/position correct
    red - color correct/position incorrect
    empty - both color/position incorrect
  4. Repeat instructions 2 and 3 until getting winning or losing message.
  5. Push [New Game] for new game.

See Also

  • [[articles:Wiki: Small Basic Portal]]
  • [[articles:MasterMind Game]] (original Visual Basic version)