Der deutsche Education Blog

December, 2008

Blog - Title

December, 2008

  • Small Basic

    Tetris - Sample of the Week

    • 14 Comments

    Sample of this week is Small Basic Tetris, ported by Kenneth Kasajian.  In all, the program is just about 530 lines long, and is listed after the screenshot.

     

    GraphicsWindow.KeyDown = HandleKey
    GraphicsWindow.BackgroundColor = GraphicsWindow.GetColorFromRGB( 253, 252, 251 )
    
    While "True"
      BOXES = 4      ' number of boxes per piece
      BWIDTH = 25    ' box width in pixels
      XOFFSET = 40   ' Screen X offset in pixels of where the board starts
      YOFFSET = 40   ' Screen Y offset in pixels of where the board starts
      CWIDTH = 10    ' Canvas Width, in number of boxes
      CHEIGHT = 20   ' Canvas Height, in number of boxes.
      STARTDELAY = 800
      ENDDELAY = 175
      PREVIEW_xpos = 13
      PREVIEW_ypos = 2
      
      GraphicsWindow.Clear()
      GraphicsWindow.Title = "Small Basic Tetris"
      GraphicsWindow.Height = 580
      GraphicsWindow.Width = 700
      GraphicsWindow.Show()
    
      SetupTemplates()
      SetupCanvas()
      MainLoop()
      
      GraphicsWindow.ShowMessage( "Game Over", "Small Basic Tetris" )
    EndWhile
    
    Sub MainLoop
      template = Text.Append("template", Math.GetRandomNumber(7))
    
      CreatePiece() ' in: template  ret: h
      nextPiece = h
    
      end = 0
      sessionDelay = STARTDELAY
      While end = 0
        If sessionDelay > ENDDELAY Then
          sessionDelay = sessionDelay - 1
        EndIf
        
        delay = sessionDelay
        thisPiece = nextPiece
        template = Text.Append("template", Math.GetRandomNumber(7))
    
        CreatePiece() ' in: template  ret: h
        nextPiece = h
        DrawPreviewPiece()
        
        h = thisPiece    
        
        ypos = 0
        done = 0
        xpos = 3 ' always drop from column 3
        CheckStop() ' in: ypos, xpos, h  ret: done
        If done = 1 Then
          ypos = ypos - 1
          MovePiece()  'in: ypos, xpos, h
          end = 1
        EndIf
        
        yposdelta = 0
        While done = 0 Or yposdelta > 0
          MovePiece()  'in: ypos, xpos, h
          
          ' Delay, but break if the delay get set to 0 if the piece gets dropped
          delayIndex = delay      
          While delayIndex > 0 And delay > 0
            Program.Delay(10)
            delayIndex = delayIndex - 10
          EndWhile  
    
          If yposdelta > 0 Then
            yposdelta = yposdelta - 1  ' used to create freespin, when the piece is rotated
          Else
            ypos = ypos + 1            ' otherwise, move the piece down.
          EndIf
          
          ' Check if the piece should stop.
          CheckStop() ' in: ypos, xpos, h  ret: done            
        EndWhile
      EndWhile
    EndSub
    
    Sub HandleKey
      ' Stop game
      If GraphicsWindow.LastKey = "Escape" Then
        Program.End()
      EndIf
    
      ' Move piece left
      If GraphicsWindow.LastKey = "Left" Then
        moveDirection = -1
        ValidateMove()  ' in: ypos, xpos, h, moveDirection  ret: invalidMove = 1 or -1 or 2 if move is invalid, otherwise 0
        If invalidMove = 0 Then
          xpos = xpos + moveDirection
        EndIf
        MovePiece()  'in: ypos, xpos, h
      EndIf
      
      ' Move piece right
      If GraphicsWindow.LastKey = "Right" Then
        moveDirection = 1
        ValidateMove()  ' in: ypos, xpos, h, moveDirection  ret: invalidMove = 1 or -1 or 2 if move is invalid, otherwise 0
        If invalidMove = 0 Then
          xpos = xpos + moveDirection
        EndIf
        MovePiece()  'in: ypos, xpos, h
      EndIf
      
      ' Move piece down
      If GraphicsWindow.LastKey = "Down" or GraphicsWindow.LastKey = "Space" Then
        delay = 0
      EndIf
      
      ' Rotate piece
      If GraphicsWindow.LastKey = "Up" Then
        basetemplate = Array.GetValue(h, -1)  ' Array.GetValue(h, -1) = the template name
        template = "temptemplate"
        rotation = "CW"
        CopyPiece()  'in basetemplate, template, rotation
    
        Array.SetValue(h, -1, template) ' Array.GetValue(h, -1) = the template name
        moveDirection = 0
        ValidateMove()  ' in: ypos, xpos, h, moveDirection  ret: invalidMove = 1 or -1 or 2 if move is invalid, otherwise 0
        
        ' See if it can be moved so that it will rotate.
        xposbk = xpos
        yposdelta = 0
        While yposdelta = 0 And Math.Abs(xposbk - xpos) < 3 ' move up to 3 times only
          ' if the rotation move worked, copy the temp to "rotatedtemplate" and use that from now on
          If invalidMove = 0 Then
            basetemplate = template
            template = "rotatedtemplate"
            Array.SetValue(h, -1, template) ' Array.GetValue(h, -1) = the template name
            rotation = "COPY"
            CopyPiece()  'in basetemplate, template, rotation
            yposdelta = 1 ' Don't move down if we rotate
            MovePiece()  'in: ypos, xpos, h
          ElseIf invalidMove = 2 Then
            ' Don't support shifting piece when hitting another piece to the right or left.
            xpos = 99 ' exit the loop
          Else
            ' if the rotated piece can't be placed, move it left or right and try again.
            xpos = xpos - invalidMove
            ValidateMove()  ' in: ypos, xpos, h, moveDirection  ret: invalidMove = 1 or -1 or 2 if move is invalid, otherwise 0
          EndIf
        EndWhile
            
        If invalidMove <> 0 Then
          xpos = xposbk
          Array.SetValue(h, -1, basetemplate) ' Array.GetValue(h, -1) = the template name
          template = ""
        EndIf      
      EndIf
    EndSub
    
    
    Sub DrawPreviewPiece
      xpos = PREVIEW_xpos
      ypos = PREVIEW_ypos
      h = nextPiece
    
      XOFFSETBK = XOFFSET
      YOFFSETBK = YOFFSET
      XOFFSET = XOFFSET + Array.GetValue(Array.GetValue(h, -1), "pviewx") ' Array.GetValue(h, -1) = the template name
      YOFFSET = YOFFSET + Array.GetValue(Array.GetValue(h, -1), "pviewy") ' Array.GetValue(h, -1) = the template name
      MovePiece()  'in: ypos, xpos, h
    
      XOFFSET = XOFFSETBK
      YOFFSET = YOFFSETBK
    EndSub
    
    ' creates template that's a rotated basetemplate
    Sub CopyPiece  'in basetemplate, template, rotation  
      L = Array.GetValue(basetemplate, "dim")
      
      If rotation = "CW" Then
        For i = 0 to BOXES - 1 '      x' = y     y' = L - 1 - x
          v = Array.GetValue(basetemplate, i)
    
          'x = Math.Floor(v/10)
          'y = Math.Remainder(v, 10)
          
          ' new x and y
          x = (Math.Remainder(v, 10))
          y = (L - 1 - Math.Floor(v/10))
          Array.SetValue(template, i, x * 10 + y)
        EndFor
      ' Count-Cockwise is not currently used
      ElseIf rotation = "CCW" Then
        For i = 0 to BOXES - 1 '      x' = L - 1 - y     y' = x
          v = Array.GetValue(basetemplate, i)
          'x = Math.Floor(v/10)
          'y = Math.Remainder(v, 10)
    
          ' new x and y
          x = (L - 1 - Math.Remainder(v, 10))
          y = Math.Floor(v/10)
          Array.SetValue(template, i, x * 10 + y)
        EndFor
      ElseIf rotation = "COPY" Then
        For i = 0 to BOXES - 1
          Array.SetValue(template, i, Array.GetValue(basetemplate, i))
        EndFor
      Else
        GraphicsWindow.ShowMessage("invalid parameter", "Error")
        Program.End()
      EndIf
      
      ' Copy the remain properties from basetemplate to template.
      Array.SetValue(template, "color", Array.GetValue(basetemplate, "color"))
      Array.SetValue(template, "dim", Array.GetValue(basetemplate, "dim"))
      Array.SetValue(template, "pviewx", Array.GetValue(basetemplate, "pviewx"))
      Array.SetValue(template, "pviewy", Array.GetValue(basetemplate, "pviewy"))
    EndSub
        
    Sub CreatePiece ' in: template  ret: h
      ' Create a new handle, representing an arrayName, that will represent the piece
      hcount = hcount + 1
      h = Text.Append("piece", hcount)
      
      Array.SetValue(h, -1, template) ' Array.GetValue(h, -1) = the template name
    
      GraphicsWindow.PenWidth = 1
      GraphicsWindow.PenColor = "Black"
      GraphicsWindow.BrushColor = Array.GetValue(template, "color")
      
      For i = 0 to BOXES - 1
        s = GraphicsWindow.AddRectangle(BWIDTH, BWIDTH)
        GraphicsWindow.MoveShape(s, -BWIDTH, -BWIDTH) ' move off screen
        Array.SetValue(h, i, s)
      EndFor
    EndSub
    
    Sub MovePiece 'in: ypos, xpos, h.  ypos/xpos is 0-19, representing the top/left box coordinate of the piece on the canvas.  h returned by CreatePiece
      For i = 0 to BOXES - 1
        v = Array.GetValue(Array.GetValue(h, -1), i)  ' Array.GetValue(h, -1) = the template name
        x = Math.Floor(v/10)
        y = Math.Remainder(v, 10)
        
        ' Array.GetValue(h, i) = box for piece h.
        ' xpos/ypos = are topleft of shape.  x/y is the box offset within the shape.
        GraphicsWindow.MoveShape(Array.GetValue(h, i), XOFFSET + xpos * BWIDTH + x * BWIDTH, YOFFSET + ypos * BWIDTH + y * BWIDTH)
      EndFor
    EndSub
    
    Sub ValidateMove ' in: ypos, xpos, h, moveDirection  ret: invalidMove = 1 or -1 or 2 if move is invalid, otherwise 0
      i = 0
      invalidMove = 0
      While i < BOXES
        v = Array.GetValue(Array.GetValue(h, -1), i)  ' Array.GetValue(h, -1) = the template name
    
        'x/y is the box offset within the shape.
        x = Math.Floor(v/10)
        y = Math.Remainder(v, 10)
        
        If (x + xpos + moveDirection) < 0 Then
          invalidMove = -1
          i = BOXES ' force getting out of the loop
        EndIf
    
        If (x + xpos + moveDirection) >= CWIDTH Then
          invalidMove = 1
          i = BOXES ' force getting out of the loop
        EndIf
    
        If Array.GetValue("c", (x + xpos + moveDirection) + (y + ypos) * CWIDTH) <> "." Then
          invalidMove = 2
          i = BOXES ' force getting out of the loop
        EndIf
    
        i = i + 1
      EndWhile
    EndSub
    
    
    Sub CheckStop ' in: ypos, xpos, h  ret: done
      done = 0
      i = 0
      While i < BOXES
        v = Array.GetValue(Array.GetValue(h, -1), i)  ' Array.GetValue(h, -1) = the template name
    
        'x/y is the box offset within the shape.
        x = Math.Floor(v/10)
        y = Math.Remainder(v, 10)
        
        If y + ypos > CHEIGHT Or Array.GetValue("c", (x + xpos) + (y + ypos) * CWIDTH) <> "." Then
          done = 1
          i = BOXES ' force getting out of the loop
        EndIf
    
        i = i + 1
      EndWhile
    
      ' If we need to stop the piece, move the box handles to the canvas
      If done = 1 Then
        For i = 0 to BOXES - 1
          v = Array.GetValue(Array.GetValue(h, -1), i)	' Array.GetValue(h, -1) = the template name
          'x = Math.Floor(v/10)
          'y = Math.Remainder(v, 10)      
          Array.SetValue("c", (Math.Floor(v/10) + xpos) + (Math.Remainder(v, 10) + ypos - 1) * CWIDTH, Array.GetValue(h, i))
        EndFor
        
        ' 1 points for every piece successfully dropped
        score = score + 1
        PrintScore()
         
        ' Delete clared lines
        DeleteLines()
      EndIf
    EndSub
    
    
    Sub DeleteLines
      linesCleared = 0
      
      ' Iterate over each row, starting from the bottom
      For y = CHEIGHT - 1 to 0 Step -1  
        
        ' Check to see if the whole row is filled
        x = CWIDTH
        While x = CWIDTH
          x = 0
          While x < CWIDTH
            piece = Array.GetValue("c", x + y * CWIDTH)
            If piece = "." then
              x = CWIDTH
            EndIf
            x = x + 1
          EndWhile
          
          ' if non of them were empty (i.e "."), then remove the line.
          If x = CWIDTH Then
            
            ' Delete the line
            For x1 = 0 to CWIDTH - 1
              GraphicsWindow.RemoveShape(Array.GetValue("c", x1 + y * CWIDTH))
            EndFor
            linesCleared = linesCleared + 1
            
            ' Move everything else down one.
            For y1 = y To 1 Step -1
              For x1 = 0 to CWIDTH - 1
                piece = Array.GetValue("c", x1 + (y1 - 1) * CWIDTH)
                Array.SetValue("c", x1 + y1 * CWIDTH, piece)
                GraphicsWindow.MoveShape(piece, GraphicsWindow.GetLeftOfShape(piece), GraphicsWindow.GetTopOfShape(piece) + BWIDTH)
              EndFor
            EndFor
          EndIf
        EndWhile
      EndFor
      
      If linesCleared > 0 Then
        score = score + 100 * Math.Round(linesCleared * 2.15 - 1)
        PrintScore()
      EndIf
    EndSub
    
    Sub SetupCanvas
    '    GraphicsWindow.DrawResizedImage( Flickr.GetRandomPicture( "bricks" ), 0, 0, GraphicsWindow.Width, GraphicsWindow.Height)
    
      
      GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
      GraphicsWindow.FillRectangle(XOFFSET, YOFFSET, CWIDTH*BWIDTH, CHEIGHT*BWIDTH)
    
      Program.Delay(200)
      GraphicsWindow.PenWidth = 1
      GraphicsWindow.PenColor = "Pink"
      For x = 0 To CWIDTH-1
        For y = 0 To CHEIGHT-1
          Array.SetValue("c", x + y * CWIDTH, ".") ' "." indicates spot is free
          GraphicsWindow.DrawRectangle(XOFFSET + x * BWIDTH, YOFFSET + y * BWIDTH, BWIDTH, BWIDTH)
        EndFor
      EndFor
    
      GraphicsWindow.PenWidth = 4
      GraphicsWindow.PenColor = "Black"
      GraphicsWindow.DrawLine(XOFFSET, YOFFSET, XOFFSET, YOFFSET + CHEIGHT*BWIDTH)
      GraphicsWindow.DrawLine(XOFFSET + CWIDTH*BWIDTH, YOFFSET, XOFFSET + CWIDTH*BWIDTH, YOFFSET + CHEIGHT*BWIDTH)
      GraphicsWindow.DrawLine(XOFFSET, YOFFSET + CHEIGHT*BWIDTH, XOFFSET + CWIDTH*BWIDTH, YOFFSET + CHEIGHT*BWIDTH)
      
      GraphicsWindow.PenColor = "Lime"
      GraphicsWindow.DrawLine(XOFFSET - 4, YOFFSET, XOFFSET - 4, YOFFSET + CHEIGHT*BWIDTH + 6)
      GraphicsWindow.DrawLine(XOFFSET + CWIDTH*BWIDTH + 4, YOFFSET, XOFFSET + CWIDTH*BWIDTH + 4, YOFFSET + CHEIGHT*BWIDTH + 6)
      GraphicsWindow.DrawLine(XOFFSET - 4, YOFFSET + CHEIGHT*BWIDTH + 4, XOFFSET + CWIDTH*BWIDTH + 4, YOFFSET + CHEIGHT*BWIDTH + 4)
      
      GraphicsWindow.PenColor = "Black"
      GraphicsWindow.BrushColor = "Pink"
      x = XOFFSET + PREVIEW_xpos * BWIDTH - BWIDTH
      y = YOFFSET + PREVIEW_ypos * BWIDTH - BWIDTH
      GraphicsWindow.FillRectangle(x, y, BWIDTH * 5, BWIDTH * 6)
      GraphicsWindow.DrawRectangle(x, y, BWIDTH * 5, BWIDTH * 6)
      
      GraphicsWindow.FillRectangle(x - 20, y + 190, 310, 170)
      GraphicsWindow.DrawRectangle(x - 20, y + 190, 310, 170)
      
      GraphicsWindow.BrushColor = "Black"
      GraphicsWindow.FontItalic = "False"
      GraphicsWindow.FontName = "Comic Sans MS"
      GraphicsWindow.FontSize = 16
      GraphicsWindow.DrawText(x, y + 200, "Game control keys:")
      GraphicsWindow.DrawText(x + 25, y + 220, "Left Arrow = Move piece left")
      GraphicsWindow.DrawText(x + 25, y + 240, "Right Arrow = Move piece right")
      GraphicsWindow.DrawText(x + 25, y + 260, "Up Arrow = Rotate piece")
      GraphicsWindow.DrawText(x + 25, y + 280, "Down Arrow = Drop piece")
      GraphicsWindow.DrawText(x, y + 320, "Press  to stop game")
    
      Program.Delay(200) ' without this delay, the above text will use the fontsize of the score 
    
      GraphicsWindow.BrushColor = "Black"
      GraphicsWindow.FontName = "Georgia"
      GraphicsWindow.FontItalic = "True"
      GraphicsWindow.FontSize = 36
      GraphicsWindow.DrawText(x - 20, y + 400, "Small Basic Tetris")
      Program.Delay(200) ' without this delay, the above text will use the fontsize of the score 
      GraphicsWindow.FontSize = 16
      GraphicsWindow.DrawText(x - 20, y + 440, "ver.0.1")
    
      Program.Delay(200) ' without this delay, the above text will use the fontsize of the score 
      score = 0
      PrintScore() 
    EndSub
    
    
    Sub PrintScore
      GraphicsWindow.PenWidth = 4
      GraphicsWindow.BrushColor = "Pink"
      GraphicsWindow.FillRectangle(500, 65, 153, 50)
      GraphicsWindow.BrushColor = "Black"
      GraphicsWindow.DrawRectangle(500, 65, 153, 50)
      GraphicsWindow.FontItalic = "False"
      GraphicsWindow.FontSize = 32
      GraphicsWindow.FontName = "Impact"
      GraphicsWindow.BrushColor = "Black"
      GraphicsWindow.DrawText(505, 70, Text.Append(Text.GetSubText( "00000000", 0, 8 - Text.GetLength( score ) ), score))
    EndSub
    
    
    Sub SetupTemplates
      ' each piece has 4 boxes.
      ' the index of each entry within a piece represents the box number (1-4)
      ' the value of each entry represents to box zero-based box coordinate within the piece: tens place is x, ones place y
    
      '_X_
      '_X_
      '_XX
    
      Array.SetValue("template1", 0, 10)
      Array.SetValue("template1", 1, 11)
      Array.SetValue("template1", 2, 12)
      Array.SetValue("template1", 3, 22)
      Array.SetValue("template1", "color", "Yellow")
      Array.SetValue("template1", "dim", 3)
      Array.SetValue("template1", "pviewx", -12)
      Array.SetValue("template1", "pviewy", 12)
    
    
      '_X_
      '_X_
      'XX_
      Array.SetValue("template2", 0, 10)
      Array.SetValue("template2", 1, 11)
      Array.SetValue("template2", 2, 12)
      Array.SetValue("template2", 3, 02)
      Array.SetValue("template2", "color", "Magenta")
      Array.SetValue("template2", "dim", 3)
      Array.SetValue("template2", "pviewx", 12)
      Array.SetValue("template2", "pviewy", 12)
      
      
      '_X_
      'XXX
      '_
      Array.SetValue("template3", 0, 10)
      Array.SetValue("template3", 1, 01)
      Array.SetValue("template3", 2, 11)
      Array.SetValue("template3", 3, 21)
      Array.SetValue("template3", "color", "Gray")
      Array.SetValue("template3", "dim", 3)
      Array.SetValue("template3", "pviewx", 0)
      Array.SetValue("template3", "pviewy", 25)
      
      
      'XX_
      'XX_
      '_
      Array.SetValue("template4", 0, 00)
      Array.SetValue("template4", 1, 10)
      Array.SetValue("template4", 2, 01)
      Array.SetValue("template4", 3, 11)
      Array.SetValue("template4", "color", "Cyan")
      Array.SetValue("template4", "dim", 2)
      Array.SetValue("template4", "pviewx", 12)
      Array.SetValue("template4", "pviewy", 25)
      
      
      'XX_
      '_XX
      '_
      Array.SetValue("template5", 0, 00)
      Array.SetValue("template5", 1, 10)
      Array.SetValue("template5", 2, 11)
      Array.SetValue("template5", 3, 21)
      Array.SetValue("template5", "color", "Green")
      Array.SetValue("template5", "dim", 3)
      Array.SetValue("template5", "pviewx", 0)
      Array.SetValue("template5", "pviewy", 25)
      
      
      '_XX
      'XX_
      '_
      Array.SetValue("template6", 0, 10)
      Array.SetValue("template6", 1, 20)
      Array.SetValue("template6", 2, 01)
      Array.SetValue("template6", 3, 11)
      Array.SetValue("template6", "color", "Blue")
      Array.SetValue("template6", "dim", 3)
      Array.SetValue("template6", "pviewx", 0)
      Array.SetValue("template6", "pviewy", 25)
      
      
      '_X
      '_X
      '_X
      '_X
      Array.SetValue("template7", 0, 10)
      Array.SetValue("template7", 1, 11)
      Array.SetValue("template7", 2, 12)
      Array.SetValue("template7", 3, 13)
      Array.SetValue("template7", "color", "Red")
      Array.SetValue("template7", "dim", 4)
      Array.SetValue("template7", "pviewx", 0)
      Array.SetValue("template7", "pviewy", 0)
    EndSub
    
    
  • Small Basic

    Small Basic communities in Russian, Portuguese and Turkish

    • 1 Comments

    Community members around the world have put together blogs and forums in various languages.  It's great to see all the energy and enthusiasm around Small Basic.  Here's a list of links in languages other than English: 

    Russian: 
    http://www.smallbasic.ru/
    Forums: http://forum.smallbasic.ru/
    Blog: http://habrahabr.ru/blogs/smallbasic/

    Portuguese:
    Blog: http://smallbasicdicas.blogspot.com/
    API reference: http://www.smallbasic.com/wiki/documentacao-Api-portugues-br.ashx

    Turkish:
    Blog: http://tr.e-uzman.org/category/yazilim/small-basic

    If you know of more resources on the web for Small Basic, please do send me a pointer.

  • Small Basic

    Announcing Small Basic v0.2, again!

    • 4 Comments

    Some technical issues with the previous announcement - the blog ended up not showing on RSS feeds, etc.  So, here's another announcement! 

    As promised, we have a new release of Small Basic!  This version contains all the most requested features by the user community.  Thanks everyone for the great suggestions and for making Small Basic better and better!  Please keep the feedback flowing.  We're listening.

    For those that are new, Microsoft Small Basic is a project that aims at bringing the fun back to programming and encourages everyone, from kids to adults to take their first step into the wondeful world of programming!

    At a high level, this release includes the following updates:

    • Bug fixes on the IDE
    • A smarter compiler with better language service features, including auto-indent
    • Inclusion of ElseIf keyword in the language
    • Better File access operations
    • Access to position and angle of Turtle

    Check out the latest version here!

  • Small Basic

    Announcing Small Basic v0_2!

    • 8 Comments

    As promised, we have a new release of Small Basic!  This version contains all the most requested features by the user community.  Thanks everyone for the great suggestions and for making Small Basic better and better!  Please keep the feedback flowing.  We're listening.

    For those that are new, Microsoft Small Basic is a project that aims at bringing the fun back to programming and encourages everyone, from kids to adults to take their first step into the wondeful world of programming!

    At a high level, this release includes the following updates:

    • Bug fixes on the IDE
    • A smarter compiler with better language service features, including auto-indent
    • Inclusion of ElseIf keyword in the language
    • Better File access operations
    • Access to position and angle of Turtle

    Check out the latest version here.

    Here's a complete list of all the updates

    Language and Editor
    • Several Crash fixes
    • Support for non-US regional OS settings
    • Auto-indent 
    • Parentheses for conditional expressions are now optional
    • Added ElseIf keyword to the language
    • Support for inline comments
    • Fixed bug with negative step value in For..EndFor

    Library API Additions

    • Array
      • GetItemCount
      • ContainsIndex
      • ContainsValue
      • RemoveValue
    • Desktop
      • Get ScreenWidth and ScreenHeight
    • File
      • CreateDirectory
      • DeleteFile
      • GetFiles
      • GetDirectories
      • WriteContents Fix: Now works even if the file doesn't already exist.
    • GraphicsWindow
      • Performance Improvements
      • Width/Height Fix: No need to set these twice
      • Hide Fixed crash
      • Add/FillTriangle
      • RotateShape
      • CanResize You now have the option of changing the resize mode
      • Left/Top You can now position the window
      • GetColorFromRGB Construct a valid color value from the color components
    • Math
      • Power
      • GetRandomNumber Fix: Is one based and includes the max-number in range. [Breaking Change]
    • Program
      • Fixes for End()
      • ProgramDirectory Gets the directory of the program
    • Text
      • Append For those times when you want a number to be treated as text
      • GetCharacter Unicode character code to Character
      • GetCharacterCode Character to Unicode Character code
    • TextWindow
      • Clear
      • Left/Top
    • Turtle
      • Angle
      • X, Y

     

  • Small Basic

    Snake in Small Basic

    • 8 Comments

    This week's featured sample is the arcade classic Snake!  And it comes from PlayDeez, who has also written other interesting Small Basic games (check out the Small Basic forums for more such hotness.)

    Here's the screenshot, followed by the source listing. 

    Initialize()
    While (GameState <> "")
        DoGameLoop()
    EndWhile
    Program.End()
    
    Sub Initialize
        InitializeVariables()
        InitializeScreen()
    EndSub
    
    Sub InitializeVariables
        Array.SetValue("DeltaX","North",0)
        Array.SetValue("DeltaX","East",1)
        Array.SetValue("DeltaX","South",0)
        Array.SetValue("DeltaX","West",-1)
        Array.SetValue("DeltaY","North",-1)
        Array.SetValue("DeltaY","East",0)
        Array.SetValue("DeltaY","South",1)
        Array.SetValue("DeltaY","West",0)
        Array.SetValue("NorthFlag","North",1)
        Array.SetValue("NorthFlag","East",0)
        Array.SetValue("NorthFlag","South",0)
        Array.SetValue("NorthFlag","West",0)
        Array.SetValue("SouthFlag","North",0)
        Array.SetValue("SouthFlag","East",0)
        Array.SetValue("SouthFlag","South",1)
        Array.SetValue("SouthFlag","West",0)
        Array.SetValue("EastFlag","North",0)
        Array.SetValue("EastFlag","East",1)
        Array.SetValue("EastFlag","South",0)
        Array.SetValue("EastFlag","West",0)
        Array.SetValue("WestFlag","North",0)
        Array.SetValue("WestFlag","East",0)
        Array.SetValue("WestFlag","South",0)
        Array.SetValue("WestFlag","West",1)
        Array.SetValue("DirectionInput","N","North")
        Array.SetValue("DirectionInput","E","East")
        Array.SetValue("DirectionInput","S","South")
        Array.SetValue("DirectionInput","W","West")
        GameDelay = 100
        Score = 0
        HighScore = 0
        GameState = "TitleScreen"
        ScreenDirty = 1
        CurrentDirectory = Text.GetSubText(File.GetSettingsFilePath(),0,Text.GetLength(File.GetSettingsFilePath())-26)
    EndSub
    
    Sub InitializeScreen
        GraphicsWindow.Show()
        GraphicsWindow.Width = 640
        GraphicsWindow.Height = 480
        'TODO: remove hack when able to do so
        GraphicsWindow.Width = 640
        GraphicsWindow.KeyDown = HandleKeyPress
    EndSub
    
    Sub HandleTitleScreenKeyPress
        Key = GraphicsWindow.LastKey
        If (Key = "Escape") Then
            GameState=""
        Else
            If (Key="F2") Then
                GameState = "Play"
                ScreenDirty = 1
            Else
                If (Key="F1") Then
                    GameState = "Instructions"
                    ScreenDirty = 1
                    DoInstructionLoop()
                EndIf
            EndIf
        EndIf
    EndSub
    
    Sub HandleInstructionsKeyPress
        Key = GraphicsWindow.LastKey
        If (Key = "Escape") Then
            GameState = "TitleScreen"
            ScreenDirty = 1
            DoTitleScreenLoop()
        EndIf
    EndSub
    
    Sub HandlePlayKeyPress
        Key = GraphicsWindow.LastKey
        If (Key = "Left") Then
            DirectionInput = DirectionInput + "W"
        Else
            If (Key = "Right") Then
                DirectionInput = DirectionInput + "E"
            Else
                If (Key = "Up") Then
                    DirectionInput = DirectionInput + "N"
                Else
                    If (Key = "Down") Then
                        DirectionInput = DirectionInput + "S"
                    EndIf
                EndIf
            EndIf
        EndIf
    EndSub
    
    Sub HandleGameOverKeyPress
        Key = GraphicsWindow.LastKey
        If (Key = "Escape") Then
            GameState=""
        Else
            If (Key="F2") Then
                GameState = "Play"
                ScreenDirty = 1
                DoPlayLoop()
            Else
                If (Key="F1") Then
                    GameState = "Instructions"
                    ScreenDirty = 1
                    DoInstructionLoop()
                EndIf
            EndIf
        EndIf
    EndSub
    
    Sub HandleKeyPress
        If (GameState="TitleScreen") Then
          HandleTitleScreenKeyPress()
        Else 
            If (GameState="Instructions") Then
                HandleInstructionsKeyPress()
            Else
                If (GameState="Play") Then
                    HandlePlayKeyPress()
                Else
                    If (GameState="GameOver") Then
                        HandleGameOverKeyPress()
                    Else
                    EndIf
                EndIf
            EndIf
        EndIf    
    EndSub
    
    Sub DoTitleScreenLoop
        If (ScreenDirty = 1) Then
            ScreenDirty = 0
            GraphicsWindow.Clear()
            GraphicsWindow.BrushColor = "#000000"
            GraphicsWindow.FontSize = 32
            GraphicsWindow.DrawText(0,0,"SBSnake!")
            GraphicsWindow.FontSize = 16
            GraphicsWindow.DrawText(0,64," for instructions")
            GraphicsWindow.DrawText(0,80," for a new game")
            GraphicsWindow.DrawText(0,96," to exit")
        EndIf
    EndSub
    
    Sub DoInstructionLoop
        If (ScreenDirty = 1) Then
            ScreenDirty = 0
            GraphicsWindow.Clear()
            GraphicsWindow.BrushColor = "#000000"
            GraphicsWindow.FontSize = 32
            GraphicsWindow.DrawText(0,0,"How To Play SBSnake!")
            GraphicsWindow.FontSize = 16
            GraphicsWindow.DrawText(0,64,"Use arrow keyss to move the snake")
            GraphicsWindow.DrawText(0,80,"Avoid hitting your own tail")
            GraphicsWindow.DrawText(0,96,"Avoid hitting the wall")
            GraphicsWindow.DrawText(0,112,"Collect red pellets to accumulate score")
            GraphicsWindow.DrawText(0,128," to return to main menu")
        EndIf
    EndSub
    
    Sub AddPellet
        PickPellet:
        PelletX = Math.GetRandomNumber(40)
        PelletY = Math.GetRandomNumber(30)
        Color = GraphicsWindow.GetPixel(PelletX * 16 + 8, PelletY * 16 + 8)
        If (Color = "#00FF00" Or Color="#FF0000") Then 
            Goto PickPellet
        EndIf
        GraphicsWindow.PenWidth = 0
        GraphicsWindow.BrushColor = "#FF0000"
        GraphicsWindow.FillRectangle(PelletX* 16+3, PelletY * 16+3,10,10)
    EndSub
    
    Sub DrawHead
        GraphicsWindow.PenWidth = 0
        GraphicsWindow.BrushColor = "#00FF00"
        GraphicsWindow.FillRectangle(SnakeHeadX * 16+2, SnakeHeadY * 16+2,12,12)
        If (Direction="South") Then
            GraphicsWindow.FillRectangle(SnakeHeadX * 16+4, SnakeHeadY*16,8,4)
        EndIf
        If (Direction="North") Then
            GraphicsWindow.FillRectangle(SnakeHeadX * 16+4, SnakeHeadY*16+12,8,4)
        EndIf
        If (Direction="East") Then
            GraphicsWindow.FillRectangle(SnakeHeadX * 16, SnakeHeadY*16+4,4,8)
        EndIf
        If (Direction="West") Then
            GraphicsWindow.FillRectangle(SnakeHeadX * 16+12, SnakeHeadY*16+4,4,8)
        EndIf
    EndSub
    
    Sub EraseHead
        If (GraphicsWindow.GetPixel(SnakeHeadX*16+8,SnakeHeadY*16)="#00FF00") Then
            NorthFlag = 1
        Else
            NorthFlag = Array.GetValue("NorthFlag",Direction)
        EndIf
        If (GraphicsWindow.GetPixel(SnakeHeadX*16+8,SnakeHeadY*16+15)="#00FF00") Then
            SouthFlag = 1
        Else
            SouthFlag = Array.GetValue("SouthFlag",Direction)
        EndIf
        If (GraphicsWindow.GetPixel(SnakeHeadX*16,SnakeHeadY*16+8)="#00FF00") Then
            WestFlag = 1
        Else
            WestFlag = Array.GetValue("WestFlag",Direction)
        EndIf
        If (GraphicsWindow.GetPixel(SnakeHeadX*16+15,SnakeHeadY*16+8)="#00FF00") Then
            EastFlag = 1
        Else
            EastFlag = Array.GetValue("EastFlag",Direction)
        EndIf
        GraphicsWindow.BrushColor = "#FFFFFF"
        GraphicsWindow.FillRectangle(SnakeHeadX * 16, SnakeHeadY*16,16,16)
        GraphicsWindow.BrushColor = "#00FF00"
        If (AtePellet = 1) Then
            GraphicsWindow.FillRectangle(SnakeHeadX * 16+3, SnakeHeadY*16+3,10,10)
        Else
            GraphicsWindow.FillRectangle(SnakeHeadX * 16+4, SnakeHeadY*16+4,8,8)
        EndIf
        If (NorthFlag = 1) Then
            GraphicsWindow.FillRectangle(SnakeHeadX * 16+4, SnakeHeadY*16,8,4)
        EndIf
        If (SouthFlag = 1) Then
            GraphicsWindow.FillRectangle(SnakeHeadX * 16+4, SnakeHeadY*16+12,8,4)
        EndIf
        If (WestFlag = 1) Then
            GraphicsWindow.FillRectangle(SnakeHeadX * 16, SnakeHeadY*16+4,4,8)
        EndIf
        If (EastFlag = 1) Then
            GraphicsWindow.FillRectangle(SnakeHeadX * 16+12, SnakeHeadY*16+4,4,8)
        EndIf
    EndSub
    
    Sub EraseTail
        If (GraphicsWindow.GetPixel(SnakeTailX*16+8,SnakeTailY*16)="#00FF00") Then
            NorthFlag = 1
        Else
            NorthFlag = 0
        EndIf
        If (GraphicsWindow.GetPixel(SnakeTailX*16+8,SnakeTailY*16+15)="#00FF00") Then
            SouthFlag = 1
        Else
            SouthFlag = 0
        EndIf
        If (GraphicsWindow.GetPixel(SnakeTailX*16,SnakeTailY*16+8)="#00FF00") Then
            WestFlag = 1
        Else
            WestFlag = 0
        EndIf
        If (GraphicsWindow.GetPixel(SnakeTailX*16+15,SnakeTailY*16+8)="#00FF00") Then
            EastFlag = 1
        Else
            EastFlag = 0
        EndIf
        GraphicsWindow.BrushColor = "#FFFFFF"
        GraphicsWindow.FillRectangle(SnakeTailX * 16, SnakeTailY*16,16,16)
        
        If (NorthFlag = 1) Then
            TailDirection = "North"
        EndIf
        If (SouthFlag = 1) Then
            TailDirection = "South"
        EndIf
        If (EastFlag = 1) Then
            TailDirection = "East"
        EndIf
        If (WestFlag = 1) Then
            TailDirection = "West"
        EndIf
        SnakeTailX = SnakeTailX + Array.GetValue("DeltaX",TailDirection)
        SnakeTailY = SnakeTailY + Array.GetValue("DeltaY",TailDirection)
        If (GraphicsWindow.GetPixel(SnakeTailX*16+3,SnakeTail*16+3)="#00FF00") Then
            TailPellet = 1
        Else
            TailPellet = 0
        EndIf 
        If (GraphicsWindow.GetPixel(SnakeTailX*16+8,SnakeTailY*16)="#00FF00") Then
            NorthFlag = 1
        Else
            NorthFlag = 0
        EndIf
        If (GraphicsWindow.GetPixel(SnakeTailX*16+8,SnakeTailY*16+15)="#00FF00") Then
            SouthFlag = 1
        Else
            SouthFlag = 0
        EndIf
        If (GraphicsWindow.GetPixel(SnakeTailX*16,SnakeTailY*16+8)="#00FF00") Then
            WestFlag = 1
        Else
            WestFlag = 0
        EndIf
        If (GraphicsWindow.GetPixel(SnakeTailX*16+15,SnakeTailY*16+8)="#00FF00") Then
            EastFlag = 1
        Else
            EastFlag = 0
        EndIf
        If (TailDirection="North") Then
            SouthFlag = 0
        EndIf
        If (TailDirection="South") Then
            NorthFlag = 0
        EndIf
        If (TailDirection="East") Then
            WestFlag = 0
        EndIf
        If (TailDirection="West") Then
            EastFlag = 0
        EndIf
        GraphicsWindow.FillRectangle(SnakeTailX * 16, SnakeTailY*16,16,16)
        GraphicsWindow.BrushColor = "#00FF00"
        If (TailPellet = 1) Then
            GraphicsWindow.FillRectangle(SnakeTailX * 16+3, SnakeTailY*16+3,10,10)
        Else
            GraphicsWindow.FillRectangle(SnakeTailX * 16+4, SnakeTailY*16+4,8,8)
        EndIf
        If (NorthFlag = 1) Then
            GraphicsWindow.FillRectangle(SnakeTailX * 16+4, SnakeTailY*16,8,4)
        EndIf
        If (SouthFlag = 1) Then
            GraphicsWindow.FillRectangle(SnakeTailX * 16+4, SnakeTailY*16+12,8,4)
        EndIf
        If (WestFlag = 1) Then
            GraphicsWindow.FillRectangle(SnakeTailX * 16, SnakeTailY*16+4,4,8)
        EndIf
        If (EastFlag = 1) Then
            GraphicsWindow.FillRectangle(SnakeTailX * 16+12, SnakeTailY*16+4,4,8)
        EndIf
    EndSub
    
    Sub ProcessDirectionInput
        If (Text.GetLength(DirectionInput)>0) Then
            Temp = Text.GetSubText(DirectionInput,0,1)
            DirectionInput = Text.GetSubText(DirectionInput,1,Text.GetLength(DirectionInput)-1)
            Direction = Array.GetValue("DirectionInput",Temp)
        EndIf
    EndSub
    
    Sub StartGame
        Direction=""
        DirectionInput=""
        SnakeLength = 1
        SnakeMaximumLength = 4
        SnakeHeadX = 20
        SnakeHeadY = 15
        SnakeTailX = 20
        SnakeTailY = 15
        AtePellet = 0
        Score = 0
        GraphicsWindow.Clear()
        DrawHead()
        AddPellet()
        UpdateScore()
    EndSub
    
    Sub UpdateScore
        GraphicsWindow.Title = "SBSnake - "+Score
    EndSub
    
    Sub DoPlayLoop
        If (ScreenDirty = 1) Then
            ScreenDirty = 0
            StartGame()
        Else
            If (Direction <> "" Or DirectionInput<>"") Then
                ProcessDirectionInput()
                EraseHead()
                SnakeHeadX = SnakeHeadX + Array.GetValue("DeltaX",Direction)
                SnakeHeadY = SnakeHeadY + Array.GetValue("DeltaY",Direction)
                If (SnakeHeadX<0 Or SnakeHeadX>39 Or SnakeHeadY < 0 Or SnakeHeadY > 29) Then
                    GameState = "GameOver"
                    ScreenDirty = 1
                Else
                    If (GraphicsWindow.GetPixel(SnakeHeadX*16+8,SnakeHeadY*16+8)="#FF0000") Then
                        Score = Score + 1
                        UpdateScore()
                        AtePellet = 1
                        SnakeMaximumLength = SnakeMaximumLength + 2
                        AddPellet()
                    Else
                        AtePellet = 0
                    EndIf
                    If (GraphicsWindow.GetPixel(SnakeHeadX*16+8,SnakeHeadY*16+8)="#00FF00") Then
                        GameState = "GameOver"
                        DrawHead()
                        ScreenDirty = 1
                    Else
                        SnakeLength = SnakeLength + 1
                        DrawHead()
                        While (SnakeLength>SnakeMaximumLength)
                            EraseTail()
                            SnakeLength = SnakeLength - 1
                        EndWhile
                        Program.Delay(GameDelay)
                    EndIf
                EndIf
            EndIf
        EndIf
    EndSub
    
    Sub DoGameOverLoop
        If (ScreenDirty = 1) Then
            ScreenDirty = 0
            GraphicsWindow.BrushColor = "#000000"
            GraphicsWindow.FontSize = 32
            GraphicsWindow.DrawText(0,0,"Game Over!")
            GraphicsWindow.FontSize = 16
            GraphicsWindow.DrawText(0,64," for instructions")
            GraphicsWindow.DrawText(0,80," for a new game")
            GraphicsWindow.DrawText(0,96," to exit")
        EndIf
    EndSub
    
    Sub DoGameLoop
        If (GameState = "TitleScreen") Then
            DoTitleScreenLoop()
        Else
            If (GameState = "Instructions") Then
                DoInstructionLoop()
            Else
                If (GameState = "Play") Then
                    DoPlayLoop()
                Else
                    If (GameState = "GameOver") Then
                        DoGameOverLoop()
                    EndIf
                EndIf
            EndIf
        EndIf
    EndSub

    Do you want your samples to be featured here? Post them in our forums and we'll pick one each week.

Page 1 of 1 (5 items)