My First Flex App: Tic-Tac-Toe

So, at the insistence of my co-worker Mario I’ve been reading up a bit on Flex. I can’t say it’s been love at first site, but I’m giving it a solid chance and I’ll post my thoughts on the tech after I’ve solidified on the matter.

Anywho, here’s my first app. It’s a simple Tic-Tac-Toe game, which took longer, and is uglier than it should be, since I haven’t quite figured out what I’m doing yet. Not that that’s ever stopped me from posting before.

Amazing eh?

The MXML File:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx         = "http://www.adobe.com/2006/mxml"
	layout           = "absolute"
	width            = "220"
	height           = "190"
	creationComplete = "reset(this)"
>
	<mx:Script source = "TicTacToe.as" />
</mx:Application>

My Tile Class

package components {
	import flash.events.MouseEvent;
	import mx.controls.Button;

	public class Tile extends Button {
		public function Tile(x:int,y:int,click:Function) {
			super();
			this.x     = x;
			this.y     = y;
			this.label = "";
			this.addEventListener(MouseEvent.CLICK,click);
		}
		public function belongsTo(player:String):Boolean {
			return this.label == player;
		}
		public function isEmpty():Boolean {
			return belongsTo("");
		}
	}
}

And finally, my actual game code:

import components.*;

import mx.controls.Alert;

private const START_X:int     = 90;
private const START_Y:int     = 80;
private const TILE_SIZE:int   = 50;
private const TILE_BUFFER:int = 5;
private const BOARD_SIZE:int  = 3;

private const PLAYER_X:String = "X";
private const PLAYER_O:String = "O";

private var turn:String;
private var container:DisplayObjectContainer;
private var board:Array;

private function isValidMove(tile:Tile):Boolean {
	return(tile.label == ""); 
}

private function takeTurn(tile:Tile):void {
	tile.label = turn;
	if(turn == PLAYER_X) {
		turn = PLAYER_O;
	} else {
		turn = PLAYER_X;
	}
}

private function toggle(e:MouseEvent):void {
	var tile:Tile = Tile(e.target);

	if(!isValidMove(tile)) {
		return;
	}

	takeTurn(tile);

	if(playerWon(PLAYER_X)) {
		endGame("Yay, " + PLAYER_X + "  won!");
	}
	if(playerWon(PLAYER_O)) {
		endGame("Yay, " + PLAYER_O + "  won!");
	}
	if(!movesAreAvailable()) {
		endGame("Everybody loses. Losers.");
	}
}

private function endGame(message:String):void {
	Alert.show(message);
	reset(container);	
}

private function movesAreAvailable():Boolean {
	var i:int, j:int;
	for(i = 0; i < BOARD_SIZE; i++) {
		for(j = 0; j < BOARD_SIZE; j++) {
			if(board[i][j].isEmpty()) {
				return true;
			}
		}
	}
	return false;
}

private function playerWon(player:String):Boolean {
	var i:int, j:int;
	var status:Boolean;

	for(i = 0; i < BOARD_SIZE; i++) {
		status = true;
		for(j = 0; j < BOARD_SIZE; j++) {
			status = status && board[i][j].belongsTo(player);
		}
		if(status) {
			return status;
		}
	}

	for(i = 0; i < BOARD_SIZE; i++) {
		status = true;
		for(j = 0; j < BOARD_SIZE; j++) {
			status = status && board[j][i].belongsTo(player);
		}
		if(status) {
			return status;
		}
	}

	status = true;
	for(i = 0; i < BOARD_SIZE; i++) {
		status = status && board[i][i].belongsTo(player);
	}
	if(status) {
		return status;
	}

	status = true;
	for(i = 0; i < BOARD_SIZE; i++) {
		status = status && board[i][BOARD_SIZE - (i + 1)].belongsTo(player);
	}
	return status;
}

private function reset(applicationContainer:DisplayObjectContainer):void {
	var tile:Tile;

	board     = new Array(BOARD_SIZE);
	container = applicationContainer;
	turn      = PLAYER_X;

	while(container.numChildren) {
		container.removeChildAt(0);
	}

	for(var i:int = 0; i < BOARD_SIZE; i++) {
		board[i] = new Array(BOARD_SIZE);
		for(var j:int = 0; j < BOARD_SIZE; j++) {
			board[i][j] = new Tile(
				START_X + j * (TILE_SIZE + TILE_BUFFER),
				START_Y + i * (TILE_SIZE + TILE_BUFFER),
				toggle
			);
			container.addChild(board[i][j]);
		}
	}
}

You can also just download it

On a side note, big thanks to Alex Gorbatchev for my new syntax highlighter plugin and a round of applause for Mark Walters for the AS3 extension to said excellent plugin.