Creating Sudoku in Flash
Tutorial parts
Part 3: Programming the cells
Set up your file
This file controls an actual cell in the game. A cell consists of two textfields, one for the big number and a 'scratch' field for people to put notes in, like "1,3,5" if those are possible combinations for a cell.
There are also three different TextFormats for the cell, one for a cell where the game has given the answer, one for a cell where the user gives the answer, and one for the scratch field. Finally there are some Events that we need to create so when people click on, tab to or write in a cell we can run some checks.
In your Cell.as the first thing we need to do is set it up so that it is in the right package and class.
package Sudoku
{
import flash.display.MovieClip;
public class Cell extends MovieClip
{
}
}
Properties
Some of the properties cells need is common, that is used by every instance. When we have this scenario the best thing to do is create 'shared' properties that they will all use. The alternative is every instance (81 cells) has their own private copy (3 textformats), which adds up to a lot of overhead (not so much in Sudoku, but imagine 1000 missiles with 20 properties).
Text Formatting
Our text formats are shared by every instance. They control the way the text looks when you have entered an answer, when the game provides or reveals an answer, and for the scratch textfield.
private static const HintFormat:TextFormat = new TextFormat(); HintFormat.size = 25; HintFormat.color = 0x666666; HintFormat.font = "Arial"; HintFormat.align = TextFormatAlign.CENTER; private static const AnswerFormat:TextFormat = new TextFormat(); AnswerFormat.size = 25; AnswerFormat.color = 0x000000; AnswerFormat.font = "Arial"; AnswerFormat.align = TextFormatAlign.CENTER; private static const ScratchFormat:TextFormat = new TextFormat(); ScratchFormat.size = 10; ScratchFormat.color = 0x666666; ScratchFormat.font = "Arial"; ScratchFormat.align = TextFormatAlign.LEFT;
Our cell-specific data
Every cell has its own copy of this data.
// The cell state information public var Answer:int; public var Revealed:Boolean; // The grid and region information public var X:int; public var Y:int; public var Region:int; public var RegionRowStart:int; public var RegionColStart:int; // The text fields private var TextBox:TextField; private var ScratchBox:TextField;
Our methods
For cells we have only a small number of simple methods that handle the behaviour of each cell. Like the text formatting above, wherever possible we use a static method so that the single method is shared by all cells.
The constructor
This is the code that is run when we create an instance of a Cell. In Sudoku.Game.Initialise we call this constructur 81 times to generate our cells.
public function Cell(x:int, y:int) { // Set up our cell this.Answer = 0; this.Revealed = false; this.X = x; this.Y = y; // Set up the main text field this.TextBox = new TextField(); this.TextBox.maxChars = 1; this.TextBox.type = "input"; this.TextBox.x = (x * 50); this.TextBox.y = 7 + (y * 50); this.TextBox.multiline = false; this.TextBox.width = 49; this.TextBox.height = 30; this.TextBox.defaultTextFormat = AnswerFormat; this.TextBox.addEventListener(KeyboardEvent.KEY_UP, ValueChanged); this.TextBox.addEventListener(FocusEvent.FOCUS_IN, this.Highlight); this.TextBox.addEventListener(FocusEvent.FOCUS_OUT, UnHighlight); // Set up the 'scratch' text field which is for notes this.ScratchBox = new TextField(); this.ScratchBox.maxChars = 9; this.ScratchBox.type = "input"; this.ScratchBox.x = (x * 50); this.ScratchBox.y = 7 + (y * 50) + 28; this.ScratchBox.defaultTextFormat = ScratchFormat; this.ScratchBox.height = 15; this.ScratchBox.addEventListener(FocusEvent.FOCUS_IN, this.Highlight); this.ScratchBox.addEventListener(FocusEvent.FOCUS_OUT, UnHighlight); Game.CellHolder.addChild(this.TextBox); Game.CellHolder.addChild(this.ScratchBox); // Work out what region this cell is in if(y < 3) // Region 1, 2 or 3 { if(x < 3) { this.Region = 1; this.RegionRowStart = 0; this.RegionColStart = 0; } else if(x >= 3 && x < 6) { this.Region = 2; this.RegionRowStart = 3; this.RegionColStart = 0; } else if(x >= 6) { this.Region = 3; this.RegionRowStart = 6; this.RegionColStart = 0; } } else if(y >= 3 && y < 6) // Region 4, 5 or 6 { if(x < 3) { this.Region = 4; this.RegionRowStart = 0; this.RegionColStart = 3; } else if(x >= 3 && x < 6) { this.Region = 5; this.RegionRowStart = 3; this.RegionColStart = 3; } else if(x >= 6) { this.Region = 6; this.RegionRowStart = 6; this.RegionColStart = 3; } } else if(y >= 6) // Region 7, 8 or 9 { if(x < 3) { this.Region = 7; this.RegionRowStart = 0; this.RegionColStart = 6; } else if(x >= 3 && x < 6) { this.Region = 8; this.RegionRowStart = 3; this.RegionColStart = 6; } else if(x >= 6) { this.Region = 9; this.RegionRowStart = 6; this.RegionColStart = 6; } } }
Highlight and unhighlighting cells
When a user clicks on or tabs to a cell we want to show that they're on that cell. For that reason in the constructor above we added event listeners for FOCUS_IN and FOCUS_OUT. These methods are called when the cell is focused.
Our highlight method first makes sure that the cell hasn't been revealed by the game. If it has we don't want the user to be able to click on it and write. Then is positions the Highlighter rectangle we drew in Game.as over the cell and sets it to be visible.
private function Highlight(e:Object):void { if(this.Revealed == true) { Game.Highlighter.visible = false; return; } Game.Highlighter.x = 11 + (this.X * 50); Game.Highlighter.y = 51 + (this.Y * 50); Game.Highlighter.visible = true; }
The UnHighlight method simply hides the Highlighter rectangle:
private static function UnHighlight(e:FocusEvent):void { Game.Highlighter.visible = false; }
When the user enters a number
Each time the user types a number in a cell we need to check if they've completed the game. To do that we use our ValueChanged method:
private static function ValueChanged(e:KeyboardEvent):void { Game.CheckWin(); }
Resetting cells
When a new game is begun we have to reset each cell back to its default blank, enabled state.
public static function Reset(cell:Cell):void { cell.Answer = 0; cell.Revealed = false; cell.TextBox.type = "input"; cell.TextBox.selectable = true; cell.TextBox.text = ""; cell.TextBox.setTextFormat(cell.TextBox.defaultTextFormat); cell.ScratchBox.text = ""; cell.ScratchBox.selectable = true; }
Revealing an answer
When the game initialises 28 answers are revealed. Each time a user clicks the Hint button an answer is revealed as well. This is done using our ShowAnswer method.
public static function ShowAnswer(cell:Cell):void { cell.Revealed = true; cell.TextBox.type = "dynamic"; cell.TextBox.selectable = false; cell.TextBox.text = String(cell.Answer); cell.TextBox.setTextFormat(HintFormat); cell.ScratchBox.text = ""; cell.ScratchBox.selectable = false; }
Getting an answer
Our final method retrieves the answer from the cell, whether the user has specified it or the game has revealed it:
public static function GetAnswer(cell:Cell):String { if(cell.Revealed) { return String(cell.Answer); } else { return cell.TextBox.text; } }
Again, this is a lot of code to digest and it might be easier and make more sense by checking the source file in it's entirety.
The good news is that's all of the code, and if you've made it this far you should have a complete Sudoku game!
Tutorial parts
