flash on 2013-8-20

by marcsali
HOMEWORK:
1. Repetitium mater studiorum :) Change the background color of grid 
cells to blue.
2. Fix the defect in the Grid class.
3. (Bonus) Add a class Computer to calculate computer moves. The computer
must not loose. (Hint) You will also need to modify mouseDownHandler
function so that it only plays for one side, while computer plays for 
another side. Computer starts second.
@author wvxvw
♥0 | Line 354 | Modified 2013-08-20 02:19:09 | MIT License
play

ActionScript3 source code

/**
 * Copyright marcsali ( http://wonderfl.net/user/marcsali )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/mRwv
 */


package
{
        import flash.display.BitmapData;
        import flash.display.Graphics;
        import flash.display.Shape;
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        import flash.geom.Matrix;
        import flash.geom.Point;
        import flash.geom.Rectangle;
        
        [SWF(width="600", height="600")]
        
        /**
         * HOMEWORK:
         * 1. Repetitium mater studiorum :) Change the background color of grid 
         * cells to blue.
         * 2. Fix the defect in the Grid class.
         * 3. (Bonus) Add a class Computer to calculate computer moves. The computer
         * must not loose. (Hint) You will also need to modify mouseDownHandler
         * function so that it only plays for one side, while computer plays for 
         * another side. Computer starts second.
         * @author wvxvw
         */
        public class TickTackToe extends Sprite
        {
                private static const BLACK:uint = 0xFF000000;
                private static const WHITE:uint = 0x00FFFFFF;
                private static const RED:uint = 0x80FF0000;
                
                private const _grid:Grid = new Grid();
                private const _eraser:Rectangle = new Rectangle();
                private const _line:Rectangle = new Rectangle();
                private const _canvas:Shape = new Shape();
                private const _position:Matrix = new Matrix();
                private const _destination:Point = new Point();
                private const _computer:Computer = new Computer();
                
                private var _image:BitmapData;
                private var _xImage:BitmapData;
                private var _oImage:BitmapData;
                private var _winnerImage:BitmapData;
                private var _gameOver:Boolean;
                
                public function TickTackToe() 
                {
                        super();
                        this.init();
                }
                
                private function init():void
                {
                        this.drawGrid();
                        super.stage.addEventListener(
                                MouseEvent.MOUSE_DOWN, this.mouseDownHandler);
                }
                
                private function mouseDownHandler(event:MouseEvent):void
                {
                        var positionX:uint = 
                                Math.floor(super.mouseX / (super.stage.stageWidth / 3));
                        var positionY:uint = 
                                Math.floor(super.mouseY / (super.stage.stageHeight / 3));
                        var cell:String;
                        var winner:Vector.<uint>;
                        
                        if (this._gameOver)
                        {
                                this._gameOver = false;
                                this._grid.clean();
                                this.drawGrid();
                        }
                        cell = this._grid.get(positionX, positionY);
                        if (!cell)
                        {
                                this._grid.set(positionX, positionY, "x");
                                winner = this._grid.winner();
                                if (!winner)
                                {
                                        this._computer.makeTurn(this._grid);
                                        winner = this._grid.winner();
                                }
                                this.drawGrid();
                                if (winner)
                                {
                                        this.drawWin(winner);
                                        this._gameOver = true;
                                }
                        }
                }
                
                private function drawGrid():void
                {
                        var mustRedraw:Boolean = 
                                !this._image || this._image.width != this._eraser.height * 3;
                        var canvas:Graphics = super.graphics;
                        
                        this._eraser.height = this._eraser.width = 
                                Math.min(super.stage.stageHeight, super.stage.stageWidth) / 3;
                        
                        if (mustRedraw)
                        {
                                this._image = 
                                        new BitmapData(
                                                this._eraser.height * 3, 
                                                this._eraser.height * 3, 
                                                true, 
                                                WHITE);
                                this.populateBitmapData();
                        }
                        
                        for (var i:uint; i < 9; i++)
                        {
                                this.drawChar(
                                        this._grid.get(i / 3, i % 3), 
                                        uint(i / 3) * this._eraser.height, 
                                        uint(i % 3) * this._eraser.height);
                        }
                        this.drawCrossing();
                        if (mustRedraw)
                        {
                                canvas.clear();
                                canvas.beginBitmapFill(this._image);
                                canvas.drawRect(0, 0, this._image.width, this._image.height);
                        }
                }
                
                private function drawCrossing():void
                {
                        this._line.width = this._image.width;
                        this._line.height = 2;
                        this._line.x = 0;
                        this._line.y = this._eraser.height - 1;
                        this._image.fillRect(this._line, BLACK);
                        this._line.y += this._eraser.height - 1;
                        this._image.fillRect(this._line, BLACK);
                        this._line.y = 0;
                        this._line.x = this._eraser.width - 1;
                        this._line.height = this._image.height;
                        this._line.width = 2;
                        this._image.fillRect(this._line, BLACK);
                        this._line.x += this._eraser.width - 1;
                        this._image.fillRect(this._line, BLACK);
                }
                
                private function drawWin(line:Vector.<uint>):void
                {
                        if (this._winnerImage) this._winnerImage.dispose();
                        this._winnerImage = 
                                new BitmapData(this._eraser.width, 
                                        this._eraser.height, true, RED);
                        this._eraser.x = this._eraser.y = 0;
                        for each (var i:uint in line)
                        {
                                this._destination.x = this._eraser.width * uint(i / 3);
                                this._destination.y = this._eraser.height * uint(i % 3);
                                this._image.merge(
                                        this._winnerImage, 
                                        this._eraser, 
                                        this._destination, 
                                        0xFF, 0xFF, 0xFF, 0x80);
                        }
                }
                
                private function drawChar(character:String, 
                        positionX:uint, positionY:uint):void
                {
                        var characterPixels:BitmapData;
                        
                        this._eraser.x = positionX;
                        this._eraser.y = positionY;
                        this._image.fillRect(this._eraser, WHITE);
                        if (character)
                        {
                                characterPixels = 
                                        (character == "x") ? this._xImage : this._oImage;
                                this._position.tx = positionX;
                                this._position.ty = positionY;
                                this._image.draw(characterPixels, this._position);
                        }
                }
                
                private function populateBitmapData():void
                {
                        var canvas:Graphics = this._canvas.graphics;
                        var xSide:uint;
                        
                        if (!this._xImage || this._xImage.width != this._eraser.width)
                        {
                                if (this._xImage) this._xImage.dispose();
                                if (this._oImage) this._oImage.dispose();
                                this._xImage = 
                                        new BitmapData(
                                                this._eraser.width, 
                                                this._eraser.width, 
                                                true, 
                                                WHITE);
                                this._oImage = 
                                        new BitmapData(
                                                this._eraser.width, 
                                                this._eraser.width, 
                                                true, 
                                                WHITE);
                                canvas.clear();
                                canvas.lineStyle(5, BLACK);
                                canvas.moveTo(5, 5);
                                xSide = this._eraser.width - 5;
                                canvas.lineTo(xSide, xSide);
                                canvas.moveTo(xSide, 5);
                                canvas.lineTo(5, xSide);
                                this._xImage.draw(this._canvas);
                                canvas.clear();
                                canvas.lineStyle(5, BLACK);
                                xSide = (this._eraser.width - 10) * 0.5;
                                canvas.drawCircle(xSide + 5, xSide + 5, xSide);
                                this._oImage.draw(this._canvas);
                        }
                }
                private static const WINS:Vector.<uint> =
                        new <uint>[
                                0, 1, 2, 
                                3, 4, 5, 
                                6, 7, 8,
                                0, 3, 6, 
                                1, 4, 7, 
                                2, 5, 8,
                                0, 4, 8, 
                                2, 4, 6
                        ]; 
                
                private const _choices:Vector.<uint> = new Vector.<uint>(9);
                private var _hasChoice:Boolean;
                
                public function Computer() { super(); }
                
                public function makeTurn(grid:Grid):void
                {
                        var max:uint;
                        
                        this._choices.splice(0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0);
                        this._hasChoice = false;
                        this.findPossibleWins(grid);
                        if (!this._hasChoice) this.findPossibleMoves(grid);
                        if (this._hasChoice)
                        {
                                for (var i:int; i < 9; i++) 
                                        max = Math.max(max, this._choices[i]);
                                grid.setItem(this._choices.indexOf(max), "o");
                        }
                }
                
                private function findPossibleWins(grid:Grid):void
                {
                        var first:String;
                        var second:String;
                        var third:String;
                        
                        for (var i:int; i < WINS.length; i += 3)
                        {
                                first = grid.getItem(WINS[i]);
                                second = grid.getItem(WINS[i + 1]);
                                third = grid.getItem(WINS[i + 2]);
                                if (first && first == second && !third)
                                        this.addChoice(WINS[i + 2]);
                                else if (first && first == third && !second)
                                        this.addChoice(WINS[i + 1]);
                                else if (second && second == third && !first)
                                        this.addChoice(WINS[i]);
                        }
                }
                
                private function findPossibleMoves(grid:Grid):void
                {
                        var first:String;
                        var second:String;
                        var third:String;
                        
                        for (var i:int; i < WINS.length; i += 3)
                        {
                                first = grid.getItem(WINS[i]);
                                second = grid.getItem(WINS[i + 1]);
                                third = grid.getItem(WINS[i + 2]);
                                if (first && !(second + third))
                                {
                                        this.addChoice(WINS[i + 1]);
                                        this.addChoice(WINS[i + 2]);
                                }
                                else if (third && !(first + second))
                                {
                                        this.addChoice(WINS[i + 1]);
                                        this.addChoice(WINS[i]);
                                }
                                else if (second && !(first + third))
                                {
                                        this.addChoice(WINS[i + 2]);
                                        this.addChoice(WINS[i]);
                                }
                                else if (!(first + second + third))
                                {
                                        this.addChoice(WINS[i + 2]);
                                        this.addChoice(WINS[i + 1]);
                                        this.addChoice(WINS[i]);
                                }
                        }
                }
                
                private function addChoice(choice:uint):void
                {
                        this._choices[choice]++;
                        this._hasChoice = true;
                }
     

                private  static const WINS:Vector.<uint> = 
                        new <uint>[
                                0, 1, 2, 
                                3, 4, 5, 
                                6, 7, 8,
                                0, 3, 6, 
                                1, 4, 7, 
                                2, 5, 8,
                                0, 4, 8, 
                                2, 4, 6
                        ];
                
                public  const _cells:Vector.<String> = 
                        new <String>["", "", "", "", "", "", "", "", ""];
                      
                public function Grid() { super(); }
                
                public function get(x:uint, y:uint):String
                {
                        return this._cells[x * 3 + y];
                }
                
                public function set(x:uint, y:uint, cell:String):void
                {
                        this._cells[x * 3 + y] = cell;
                }
                
                public function getItem(position:uint):String
                {
                        return this._cells[position];
                }
                
                public function setItem(position:uint, value:String):void
                {
                        this._cells[position] = value;
                }
                
                public function get indexOf():Function { return this._cells.indexOf; }
                
                /**
                 * There is a defect in this function. When there are two winning 
                 * sequences simultaneously present on the board, it will find only
                 * the first one. 
                 * TODO: alter the function in a way it will find all winning sequences.
                 * example -
                 * X O X | X X O
                 * O X O | X X O
                 * X O X | O O O
                 * 
                 * @return vecror of positions of of the winning cells, where positions
                 * are arranged like so:
                 * 0 1 2
                 * 3 4 5
                 * 6 7 8
                 */
                 
       
                public function winner():Vector.<uint>
                {
                        var first:String;
                        var second:String;
                        var third:String;
                        var result:Vector.<uint>;
                        var i:int;
                        
                        for (var offset:uint; offset < 24; offset += 3)
                        {
                                first = this._cells[WINS[offset]];
                                if (first)
                                {
                                        second = this._cells[WINS[offset + 1]];
                                        if (second == first)
                                        {
                                                third = this._cells[WINS[offset + 2]];
                                                if (third == second)
                                                {
                                                        if (!result)
                                                        {
                                                                result = 
                                                                        new <uint>[
                                                                                WINS[offset], 
                                                                                WINS[offset + 1], 
                                                                                WINS[offset + 2]
                                                                        ];
                                                        }
                                                        else
                                                        {
                                                                i = 3;
                                                                while (i--)
                                                                {
                                                                        if (result.indexOf(WINS[offset + i]) < 0)
                                                                                result.push(WINS[offset + i]);
                                                                }
                                                        }
                                                }
                                        }
                                }
                        }
                        return result;
                }
                
                public function clean():void
                {
                        this._cells.splice(
                                0, this._cells.length, "", "", "", "", "", "", "", "", "");
                }
        }
}