OctoWords is an original word puzzle game. To play, drag letters to form words. You can drag a letter in any straight line (horizontally, vertically, or diagonally), as long as the straight line path is clear. The game won't allow you to make an invalid move, but it can't force you to play a valid move, so the onus is on you.

As each newly formed word is recognized it disappears from the grid, and your score is incremented. each word you form is worth the length of the word multiplied by the length of the word minus one. Words entirely contained in the green octagon are worth 3x as much as words partially or completely outside of the octagon.

Most words recognized by the game are two, three, or four character words, but more skillful players can create longer words, and also creating situations where two or more words are formed by placing one character will earn you extra points.

Theoretically, words that will be recognized range from two to twenty characters, but as you'll see it's difficult to build a long word without the smaller words contained within your longer word being recognized first, so there is a large amount of skill necessary to become a proficient player.

The Game Class code

The Game class is used for creating each new game, and also for checking if there are any possible words left to find in the grid after each move at every stage of the game.

Public Class Game
    Private Shared vowels1() As String = {"A", "E", "I", "O"}
    Private Shared vowels2() As String = {"A", "E", "I", "O", "U"}
    Private Shared consonants1() As String = {"B", "C", "D", "F", "G", "L", "M", "N", "P", "R", "S", "T"}
    Private Shared consonants2() As String = Enumerable.Range(Asc("A"), 26).Select(Function(x) Chr(x).ToString).Except(vowels2).ToArray
    Private Shared chars(231) As String
    Public Shared Sub getLetters(ByVal r As Random)
        '90 vowels
        '142 consonants
        For x As Integer = 0 To 89
            Dim choice As Integer = r.Next(1, 4)
            If choice < 3 Then
                chars(x) = vowels1(r.Next(0, 4))
                chars(x) = vowels2(r.Next(0, 5))
            End If
        For x As Integer = 90 To 231
            Dim choice As Integer = r.Next(1, 6)
            If choice < 5 Then
                chars(x) = consonants1(r.Next(0, 12))
                chars(x) = consonants2(r.Next(0, 21))
            End If
    End Sub
    Private Shared Function getCells(ByVal r As Random) As Integer()
        Dim indices(231) As Integer
        Dim allIndices As List(Of Integer) = Enumerable.Range(0, 484).ToList
        For x As Integer = 0 To 231
            Dim i As Integer = allIndices(r.Next(0, allIndices.Count))
            indices(x) = i
        Return indices
    End Function
    Public Shared Function newGame(ByVal r As Random, ByVal grid()() As String) As String()()
        chars = chars.OrderBy(Function(x) r.NextDouble).ToArray
        Dim indices() As Integer = getCells(r)
        Dim counter As Integer = 0
        For y As Integer = 0 To 21
            For x As Integer = 0 To 21
                If indices.Contains(y * 22 + x) Then
                    grid(y)(x) = chars(counter)
                    counter += 1
                    grid(y)(x) = ""
                End If
        Return grid
    End Function
    Public Shared Function GameOver(ByVal grid()() As String) As PlayState
        Dim letters As New List(Of String)
        For y As Integer = 0 To 21
            letters.AddRange(grid(y).Where(Function(c) c <> "").ToArray)
        If letters.Any(Function(s) vowels2.Contains(s)) Then
            For x As Integer = 2 To 20
                For Each word As String In Words.getWords(x)
                    Dim newLetters As New List(Of String)(letters)
                    Dim match As Boolean = True
                    For c As Integer = 0 To word.Length - 1
                        If newLetters.Contains(word.Substring(c, 1)) Then
                            newLetters.Remove(word.Substring(c, 1))
                            If c = word.Length - 1 Then
                                Return New PlayState(False, 0)
                            End If
                            match = False
                            Exit For
                        End If
        End If
        Return New PlayState(True, 484 - letters.Count)
    End Function
End Class

frmHighScores code

frmHighScores displays the five highest scores, which are saved in a Settings Specialized.StringCollection. The Form shows at the end of each game, and also has a TreeView (in a slideOutPanel) that shows how many words of which length were found in that game.

Public Class frmHighScores
    Private newScore As Integer
    Private dt As New DataTable
    Private dtIndex As Integer
    Public Sub New(ByVal score As Integer, ByVal wordsFound As Dictionary(Of Integer, List(Of String)))
        Me.newScore = score
        If My.Settings.highScores Is Nothing Then
            My.Settings.highScores = New Specialized.StringCollection
            For x As Integer = 1 To 5
                My.Settings.highScores.Add("Player" & x.ToString & "|" & "0")
        End If
        dt.Columns.Add("score", GetType(Integer))
        For x As Integer = 1 To 5
            dt.Rows.Add(My.Settings.highScores(x - 1).Split("|"c))
        ExDGV1.AutoGenerateColumns = False
        ExDGV1.Columns(0).DataPropertyName = "name"
        ExDGV1.Columns(1).DataPropertyName = "score"
        ExDGV1.DataSource = dt
        Dim keys() As Integer = wordsFound.Keys.ToArray
        Dim node As TreeNode = TreeView1.Nodes.Add("Words (" & keys.Sum(Function(x) wordsFound(x).Count) & ")")
        For Each x As Integer In keys
            Dim allWords() As String = Words.getWords(x)
            Dim secondNode As TreeNode = node.Nodes.Add(x.ToString & " letter words (" & wordsFound(x).Count & ")")
            For Each s As String In wordsFound(x)
                If allWords.Contains(StrReverse(s)) And Not allWords.Contains(s) Then
                End If
        Label5.Text = "Longest word found was " & keys.Last.ToString & " letters"
    End Sub
    Private Sub frmHighScores_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        For x As Integer = 0 To dt.Rows.Count - 1
            My.Settings.highScores.Add(String.Join("|", Array.ConvertAll(dt.Rows(x).ItemArray, Function(o) o.ToString)))
    End Sub
    Private Sub frmHighScores_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ExDGV1.isEnabled = False
        Me.BackColor = Color.FromArgb(255, 255, 128)
        Button1.BackColor = Color.FromArgb(255, 255, 128)
        Button2.BackColor = Color.FromArgb(255, 255, 128)
        Button3.BackColor = Color.FromArgb(255, 255, 128)
        GroupBox1.BackColor = Color.FromArgb(255, 255, 128)
        SlideOutPanel1.BackColor = Color.FromArgb(255, 255, 128)
        TreeView1.BackColor = Color.FromArgb(255, 255, 128)
        TreeView1.ForeColor = Color.DarkGray
    End Sub
    Private Sub ExDGV1_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles ExDGV1.CellValueChanged
        If e.RowIndex > -1 Then
            ExDGV1.Rows(e.RowIndex).Height = 50
            ExDGV1.Rows(e.RowIndex).Cells(0).Style.BackColor = Color.FromArgb(164, 255, 164)
            ExDGV1.Rows(e.RowIndex).Cells(1).Style.BackColor = Color.FromArgb(164, 255, 164)
        End If
    End Sub
    ''' <summary>
    ''' Necessary to handle user selections in the dgv.
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub ExDGV1_SelectionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ExDGV1.SelectionChanged
    End Sub
    Private Sub ExDGV1_CellFormatting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) Handles ExDGV1.CellFormatting
        If e.ColumnIndex = 1 Then
            ExDGV1(e.ColumnIndex, e.RowIndex).Value = CInt(ExDGV1(e.ColumnIndex, e.RowIndex).Value).ToString("0000000")
        End If
    End Sub
    Private Sub frmHighScores_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
        For x As Integer = 0 To dt.Rows.Count - 1
            If newScore > dt.Rows(x).Field(Of Integer)(1) Then
                Dim row As DataRow = dt.NewRow
                row.ItemArray = New Object() {"", newScore}
                dt.Rows.InsertAt(row, x)
                dtIndex = x
                GroupBox1.Enabled = True
                Exit For
            End If
    End Sub
    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        dt.Rows(dtIndex).Item(0) = TextBox1.Text
    End Sub
End Class


Nowadays more than ever, the average person can invent, create, and market their ideas through the use of a desktop computer.
This game is a simple idea, and the code involved is easily written with a little experience. All of the controls used are standard VB controls, manipulated slightly to give the necessary functionality and overall appearance.
If you can dream it, you can code it...

Other Resources

Download here... (VB.Net | C#)

See Also

C# version

Articles related to game programming

VB.Net - Perspective
VB.Net - Vertex
VB.Net - WordSearch
VB.Net - MasterMind
VB.Net - OOP BlackJack
VB.Net - Numbers Game
VB.Net - HangMan
Console BlackJack - VB.Net | C#
TicTacToe - VB.Net | C#
OOP Conway's Game of Life - VB.Net | C#
OOP Sudoku - VB.Net | C#
OOP Buttons Guessing Game VB.Net | C#
OOP Tangram Shapes Game VB.Net | C#
VB.Net - Three-card Monte
VB.Net - Split Decisions
VB.Net - Pascal's Pyramid
VB.Net - Random Maze Games
(Office) Wordsearch Creator
VB.Net - Event Driven Programming - LockWords Game
C# - Crack the Lock