Creating Sudoku in Flash

Tutorial parts

Source: Game.as

package Sudoku
{
        import flash.display.MovieClip;
        import flash.display.SimpleButton;
        import flash.display.Shape;
        import flash.display.Stage;
        import flash.events.MouseEvent;
        import flash.events.Event;

        public class Game extends MovieClip
        {
                public static var STAGE:Stage;
                public static var Playing:Boolean;
                private static var Grid:Array;
                private static var GridCells:Array;
                public static var CellHolder:MovieClip;
                private static var WinDialogue:Sudoku.WinDialogue;
                public static var Highlighter:Shape;

                public function Game()
                {
                        STAGE = this.stage;
                        loaderInfo.addEventListener(Event.COMPLETE, Initialise);
                }

                private function Initialise(e:Event):void
                {
                        // Set up our button click handlers
                        this.NewGameButton.addEventListener(MouseEvent.MOUSE_UP, NewGame);
                        this.HintButton.addEventListener(MouseEvent.MOUSE_UP, Hint);
                        this.SolveButton.addEventListener(MouseEvent.MOUSE_UP, Solve);

                        // Create the container movieclip for our cells
                        CellHolder = new MovieClip();
                        CellHolder.x = 10;
                        CellHolder.y = 50;
                        addChild(CellHolder);

                        // Initialise our grid of cells
                        Grid = new Array(9);
                        GridCells = new Array(81);

                        var gindex:int = 0;
                        var cell:Cell;

                        for(var x:int=0; x<9; x++)
                        {
                                Grid[x] = new Array(9);

                                for(var y:int=0; y<9; y++)
                                {
                                        cell = new Cell(x, y);
                                        Grid[x][y] = cell;
                                        GridCells[gindex] = cell;
                                        gindex++;
                                }
                        }

                        // Create our highlighter to indicate which cell is being edited
                        Highlighter = new Shape();
                        Highlighter.graphics.lineStyle(0.1, 0x999999);
                        Highlighter.graphics.moveTo(0, 0);
                        Highlighter.graphics.lineTo(0, 47);
                        Highlighter.graphics.lineTo(47, 47);
                        Highlighter.graphics.lineTo(47, 0);
                        Highlighter.graphics.lineTo(0, 0);
                        Highlighter.graphics.endFill();
                        Highlighter.visible = false;
                        STAGE.addChild(Highlighter);

                        // Create our win dialogue and hide it for later
                        WinDialogue = new Sudoku.WinDialogue();
                        WinDialogue.x = 10;
                        WinDialogue.y = 239;
                        WinDialogue.visible = false;
                        STAGE.addChild(WinDialogue);


                        NewGame();
                }

                // Starts a new game
                private static function NewGame(e:MouseEvent = null):void
                {
                        // Reset the grid
                        ResetGrid();

                        // Create a puzzle
                        GeneratePuzzle();

                        // Hide the win dialogue if it's visible
                        WinDialogue.visible = false;

                        var revealed:int = 28;

                        while(revealed > 0)
                        {
                                var y = Random(0, 8);
                                var x = Random(0, 8);

                                if(Grid[y][x].Revealed == false)
                                {
                                        Grid[y][x].Revealed = true;
                                        Cell.ShowAnswer(Grid[y][x]);
                                        revealed--;
                                }
                        }

                        // Set the status  to playing
                        Playing = true;
                }

                // Generates a Sudoku solution
                private static function GeneratePuzzle():void
                {
                        var index:int = 0;

                        while(index < 81)
                        {
                                var number:int = 0;
                                var values:Array = [1,2,3,4,5,6,7,8,9];

                                while(values.length > 0 && number == 0)
                                {
                                        var zindex:int = Random(0, values.length);
                                        var z:int = values[zindex];
                                        values.splice(zindex, 1);

                                        if(!Conflicts(z, GridCells[index]))
                                        {
                                                number = z;
                                        }
                                }

                                if(number == 0)
                                {
                                        var maxbacktrack:int = index > 10 ? 10 : index;
                                        var backtrack:int = Random(1, maxbacktrack);
                                        var backtracked:int = 0;

                                        while(backtracked < backtrack)
                                        {
                                                GridCells[index - backtracked].Answer = 0;
                                                backtracked++;
                                        }

                                        index -= backtrack;
                                }
                                else
                                {
                                        GridCells[index].Answer = number;
                                        index++;
                                }
                        }
                }

                // Resets the grid to it's original state
                private static function ResetGrid():void
                {
                        // Go through each cell
                        for(var i:int=0; i<81; i++)
                        {
                                // Reset it
                                Cell.Reset(GridCells[i]);
                        }
                }

                // Checks if there are any available cells
                private static function AvailableCells():Boolean
                {
                        // Go through each cell
                        for(var i:int=0; i<81; i++)
                        {
                                // Check if it's empty
                                if(Cell.GetAnswer(GridCells[i]) == "")
                                {
                                        return true;
                                }
                        }

                        return false;
                }

                // Check if there is a conflict between a cell and the row, column and
                // region it's on
                private static function Conflicts(number:int, cell:Sudoku.Cell):Boolean
                {
                        // Check the rows and columns
                        for(var i:int=0; i<9; i++)
                        {
                                if(Grid[cell.X][i].Answer == number || Grid[i][cell.Y].Answer == number)
                                {
                                        return true;
                                }
                        }

                        // Check the region it's in
                        for(var x:int=cell.RegionRowStart; x<cell.RegionRowStart+3; x++)
                        {
                                for(var y:int=cell.RegionColStart; y<cell.RegionColStart+3; y++)
                                {
                                        if(Grid[x][y].Answer == number)
                                        {
                                                return true;
                                        }
                                }
                        }

                        return false;
                }

                // Generates a random number between min and max inclusive
                private static function Random(min:int, max:int):int
                {
                        var number:int = min - 1;

                        while(number < min || number > max)
                        {
                                number = min + Math.round(Math.random() * (max - min));
                        }

                        return number;
                }

                // Reveals one correct answer for the player
                private static function Hint(e:MouseEvent):void
                {
                        if(!Playing)
                        return;

                        if(AvailableCells() == false)
                        return;

                        // Because we're not sure which cell to reveal we have to
                        // keep doing this till we find one
                        var done:Boolean = false;
                        var cell:Cell;

                        while(!done)
                        {
                                // Select a random cell
                                var row:int = Random(0, 8);
                                var column:int = Random(0, 8);
                                cell = Grid[row][column];

                                // If it's not revealed then we do so
                                if(cell.Revealed == false)
                                {
                                        Cell.ShowAnswer(cell);

                                        // Check if the game's over now
                                        CheckWin();

                                        return;
                                }
                        }
                }

                // Checks if all cells have been correctly filled out
                public static function CheckWin():void
                {
                        // Don't check if there are any empty cells
                        if(AvailableCells() == true)
                        return;

                        // Check the rows and columns
                        var rowcell:Cell;
                        var rowanswer:String;
                        var rowanswers:String;
                        var colcell:Cell;
                        var colanswer:String;
                        var colanswers:String;

                        for(var i:int=0; i<9; i++)
                        {
                                rowanswers = "";
                                colanswers = "";

                                for(var j=0; j<9; j++)
                                {
                                        rowcell = Grid[i][j];
                                        colcell = Grid[j][i];

                                        // Check the row answer, if it's blank or already been
                                        // entered we can return
                                        rowanswer = Cell.GetAnswer(rowcell);

                                        if(rowanswer == "" || rowanswers.indexOf(rowanswer) > -1)
                                        return;

                                        // Check the column answer
                                        colanswer = Cell.GetAnswer(colcell);

                                        if(colanswer == "" || colanswers.indexOf(colanswer) > -1)
                                        return;

                                        // Append these answers to our check lists
                                        rowanswers += rowanswer;
                                        colanswers += colanswer;
                                }
                        }

                        // Check the regions
                        var regionanswers:String;
                        var regionanswer:String;
                        var rowstart:int = 0;
                        var colstart:int = 0;

                        for(var k:int=1; k<10; k++)
                        {
                                // Work out what the x/y coordinates of the region we're in begin at
                                switch(k)
                                {
                                        case 1:
                                        rowstart = 0;
                                        colstart = 0;
                                        break;

                                        case 2:
                                        rowstart = 3;
                                        colstart = 0;
                                        break;

                                        case 3:
                                        rowstart = 6;
                                        colstart = 0;
                                        break;

                                        case 4:
                                        rowstart = 0;
                                        colstart = 3;
                                        break;

                                        case 5:
                                        rowstart = 3;
                                        colstart = 3;
                                        break;

                                        case 6:
                                        rowstart = 6;
                                        colstart = 3;
                                        break;

                                        case 7:
                                        rowstart = 0;
                                        colstart = 6;
                                        break;

                                        case 8:
                                        rowstart = 3;
                                        colstart = 6;
                                        break;

                                        case 9:
                                        rowstart = 6;
                                        colstart = 6;
                                        break;
                                }

                                // Check each cell in this region
                                regionanswers = "";

                                for(var x:int=rowstart; x<rowstart+3; x++)
                                {
                                        for(var y:int=colstart; y<colstart+3; y++)
                                        {
                                                rowcell = Grid[x][y];

                                                regionanswer = Cell.GetAnswer(rowcell);

                                                // If there's no answer
                                                if(regionanswer == "" || regionanswers.indexOf(regionanswer) > -1)
                                                return;

                                                // Append the answer to our check list
                                                regionanswers += regionanswer;
                                        }
                                }
                        }

                        Playing = false;
                        WinDialogue.visible = true;
                        STAGE.setChildIndex(WinDialogue, STAGE.numChildren - 1);
                }

                // Solves the puzzle
                private static function Solve(e:MouseEvent):void
                {
                        if(!Playing)
                        return;

                        // We're not playing any more
                        Playing = false;

                        // Go through each cell and show the answer
                        for(var i:int=0; i<81; i++)
                        {
                                if(GridCells[i].Revealed == false)
                                {
                                        Cell.ShowAnswer(GridCells[i]);
                                }
                        }
                }
        }
}

Tutorial parts