Share via


C# - OctoWords


Overview

octowards 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.



      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
   
      namespace OctoWords_cs.core
      {  
                    public class  Game  
                    {      
   
                        private static  string[] vowels1 = { "A", "E", "I", "O" };  
                        private static  string[] vowels2 = { "A", "E", "I", "O", "U" };  
                        private static  string[] consonants1 = { "B", "C", "D", "F", "G", "L", "M", "N", "P", "R", "S", "T" };  
                        private static  string[] consonants2 = Enumerable.Range((int)'A', 26).Select((x) => ((char)x).ToString()).Except(vowels2).ToArray();  
                        private static  string[] chars = new string[232];  
   
                        public static  void getLetters(Random r)  
                        {      
                            //90 vowels      
                            //142 consonants      
   
                            for (int x = 0; x <= 89; x++)  
                            {      
                                int choice = r.Next(1, 4);  
                                if (choice < 3)  
                                {      
                                    chars[x] = vowels1[r.Next(0, 4)];      
                                }      
                                else      
                                {      
                                    chars[x] = vowels2[r.Next(0, 5)];      
                                }      
                            }      
                            for (int x = 90; x <= 231; x++)  
                            {      
                                int choice = r.Next(1, 6);  
                                if (choice < 5)  
                                {      
                                    chars[x] = consonants1[r.Next(0, 12)];      
                                }      
                                else      
                                {      
                                    chars[x] = consonants2[r.Next(0, 21)];      
                                }      
                            }      
   
                        }      
   
                        private static  int[] getCells(Random r)  
                        {      
                            int      [] indices =       new  int[232];  
                            List<      int      > allIndices = Enumerable.Range(0, 484).ToList();      
   
                            for (int x = 0; x <= 231; x++)  
                            {      
                                int i = allIndices[r.Next(0, allIndices.Count)];  
                                allIndices.Remove(i);      
                                indices[x] = i;      
                            }      
   
                            return indices;  
   
                        }      
   
                        public static  string[][] newGame(Random r, string[][] grid)  
                        {      
   
                            chars = chars.OrderBy((x) => r.NextDouble()).ToArray();      
                            int      [] indices = getCells(r);      
   
                            int counter = 0;  
                            for (int y = 0; y <= 21; y++)  
                            {      
                                for (int x = 0; x <= 21; x++)  
                                {      
                                    if (indices.Contains(y * 22 + x))  
                                    {      
                                        grid[y][x] = chars[counter];      
                                        counter += 1;      
                                    }      
                                    else      
                                    {      
                                        grid[y][x] =       ""      ;      
                                    }      
                                }      
                            }      
   
                            return grid;  
   
                        }      
   
                        public static  PlayState GameOver(string[][] grid)  
                        {      
                            List<      string      > letters =       new  List<string>();  
                            for (int y = 0; y <= 21; y++)  
                            {      
                                letters.AddRange(grid[y].Where((c) => c !=       ""      ).ToArray());      
                            }      
   
                            if (letters.Any((s) => vowels2.Contains(s)))  
                            {      
                                for (int x = 2; x <= 20; x++)  
                                {      
                                    foreach (string word in Words.getWords(x))  
                                    {      
                                        List<      string      > newLetters =       new  List<string>(letters);  
                                        for (int c = 0; c < word.Length; c++)  
                                        {      
                                            if (newLetters.Contains(word.Substring(c, 1)))  
                                            {      
                                                newLetters.Remove(word.Substring(c, 1));      
                                                if (c == word.Length - 1)  
                                                {      
                                                    return new  PlayState(false, 0);  
                                                }      
                                            }      
                                            else      
                                            {      
                                                break      ;      
                                            }      
                                        }      
                                    }      
                                }      
                            }      
   
                            return new  PlayState(true, 484 - letters.Count);  
                        }      
   
                    }      
   
      }  

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.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using OctoWords_cs.core;
 
namespace OctoWords_cs
{
    public partial  class frmHighScores : Form
    {
 
        private int  newScore;
        private DataTable dt = new DataTable();
        private int  dtIndex;
 
        public frmHighScores(int score, Dictionary<int, List<string>> wordsFound)
        {
            InitializeComponent();
 
            this.FormClosing += frmHighScores_FormClosing;
            this.DataGridView1.CellValueChanged += DataGridView1_CellValueChanged;
            this.DataGridView1.SelectionChanged += DataGridView1_SelectionChanged;
            this.DataGridView1.CellFormatting += DataGridView1_CellFormatting;
            this.Shown += frmHighScores_Shown;
            this.Button3.Click += Button3_Click;
            this.slideOutPanel1.Resize += rePaintAll;
 
 
            this.newScore = score;
            if (Properties.Settings.Default.highScores == null)
            {
                Properties.Settings.Default.highScores = new  System.Collections.Specialized.StringCollection();
                for (int x = 1; x <= 5; x++)
                {
                    Properties.Settings.Default.highScores.Add("Player" + x.ToString() + "|" + "0");
                }
            }
            dt.Columns.Add("name");
            dt.Columns.Add("score", typeof(int));
            for (int x = 1; x <= 5; x++)
            {
                dt.Rows.Add(Properties.Settings.Default.highScores[x - 1].Split('|'));
            }
 
            DataGridView1.AutoGenerateColumns = false;
            DataGridView1.Columns[0].DataPropertyName = "name";
            DataGridView1.Columns[1].DataPropertyName = "score";
            DataGridView1.DataSource = dt;
            int[] keys = wordsFound.Keys.ToArray();
            Array.Sort(keys);
            TreeNode node = TreeView1.Nodes.Add("Words (" + keys.Sum((x) => wordsFound[x].Count) + ")");
            foreach (int x in keys)
            {
                string[] allWords = Words.getWords(x);
                TreeNode secondNode = node.Nodes.Add(x.ToString() + " letter words ("  + wordsFound[x].Count + ")");
                foreach (string s in wordsFound[x])
                {
                    if (allWords.Contains(StringHelper.StrReverse(s)) && !allWords.Contains(s))
                    {
                        secondNode.Nodes.Add(StringHelper.StrReverse(s));
                    }
                    else
                    {
                        secondNode.Nodes.Add(s);
                    }
                }
            }
 
            Label5.Text = "Longest word found was "  + keys.Last().ToString() + " letters";
            node.Expand();
        }
 
        private void  frmHighScores_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e)
        {
            Properties.Settings.Default.highScores.Clear();
            for (int x = 0; x < dt.Rows.Count; x++)
            {
                Properties.Settings.Default.highScores.Add(string.Join("|", Array.ConvertAll(dt.Rows[x].ItemArray, (o) => o.ToString())));
            }
            Properties.Settings.Default.Save();
        }
 
        private void  frmHighScores_Load(System.Object sender, System.EventArgs e)
        {
            DataGridView1.isEnabled = false;
            this.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;
        }
 
        private void  DataGridView1_CellValueChanged(object sender, System.Windows.Forms.DataGridViewCellEventArgs e)
        {
            if (e.RowIndex > -1)
            {
                DataGridView1.Rows[e.RowIndex].Height = 50;
                DataGridView1.Rows[e.RowIndex].Cells[0].Style.BackColor = Color.FromArgb(164, 255, 164);
                DataGridView1.Rows[e.RowIndex].Cells[1].Style.BackColor = Color.FromArgb(164, 255, 164);
            }
        }
 
        /// <summary>
        /// Necessary to handle user selections in the dgv.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks></remarks>
        private void  DataGridView1_SelectionChanged(object sender, System.EventArgs e)
        {
            DataGridView1.ClearSelection();
        }
 
        private void  DataGridView1_CellFormatting(object sender, System.Windows.Forms.DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 1)
            {
                DataGridView1[e.ColumnIndex, e.RowIndex].Value = Convert.ToInt32(DataGridView1[e.ColumnIndex, e.RowIndex].Value).ToString("0000000");
            }
        }
 
        private void  frmHighScores_Shown(object sender, System.EventArgs e)
        {
            rePaintAll(this, new  System.EventArgs());
 
            int tempVar = dt.Rows.Count;
            for (int x = 0; x < tempVar; x++)
            {
                if (newScore > dt.Rows[x].Field<int>(1))
                {
                    DataRow row = dt.NewRow();
                    row.ItemArray = new  object[] {"", newScore};
                    dt.Rows.InsertAt(row, x);
                    dt.Rows.RemoveAt(5);
                    dtIndex = x;
                    GroupBox1.Enabled = true;
                    TextBox1.Focus();
                    break;
                }
            }
        }
 
        private void  Button3_Click(System.Object sender, System.EventArgs e)
        {
            dt.Rows[dtIndex][0] = TextBox1.Text;
        }
 
        private void  rePaintAll(System.Object sender, System.EventArgs e)
        {
            foreach(Control c in  this.Controls) {
                c.Refresh();
            }
 
        }
 
    }
     
}

Conclusion

Nowadays more than ever, the average person can invent, create, and market their ideas through the use of the 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

VB.Net version


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
VB.Net - Totris