Tag Archives: actionscript

Announcing GeoHashFlash!

Okay, so it’s hardly an announcement, but I’ve been working on a flex app for determining your daily official xkcd meetup location via the geohashing method described in comic 426.

Much love to:

I’m still learning Flex and this is my first adventure with Google Map, so it’s rough. And there’s still a lot of work to do, like, validation, error checking, or testing for example. But hey, first pass!

Here’s the code for the actual GeoHash class. I have “view source” disabled because it currently contains my API key, but you can download the key-less zip.

public class GeoHasher {

	private var date:Date;
	private var dow:Number;
	private var latitude:Number;
	private var longitude:Number;

	private var dateHash:String;
	private var dowHash:String;

	private var ready:Boolean;

	public function GeoHasher() {
		this.ready = false;
	}

	public function reset(
		date:Date,
		dow:Number,
		latitude:Number,
		longitude:Number
	):void {
		this.date      = date;
		this.dow       = dow;
		this.latitude  = latitude;
		this.longitude = longitude;

		this.ready     = true;

		setHashValues();
	}

	public function getDestination():Object {
		if(ready) {
			var hash:Object = getHashAsDecimal();
			return {
				latitude: toOrdinal(latitude, hash.date),
				longitude: toOrdinal(longitude, hash.dow)
			};	
		}
		return { latitude: "", longitude: "" };
	}

	// privates

	private function setHashValues():void {
		var formattedDate:String = Utilities.dateFormat(date,"-");
		var string:String = formattedDate + "-" + dow.toString();
		var hash:String   = MD5.encrypt(string); 

		dateHash = hash.slice(0,hash.length / 2);
		dowHash  = hash.slice(hash.length / 2,hash.length);
	}

	private function toOrdinal(pre:Number, post:Number):String {
		return (Math.floor(pre) + post).toString();
	}

	private function getHash():Object {
		return { date: dateHash, dow: dowHash };
	}

	private function getHashAsDecimal():Object {
		var hash:Object = getHash();
		return {
				date: Utilities.fractionalHexToDecimal(hash.date),
				dow: Utilities.fractionalHexToDecimal(hash.dow)
		};
	}
}

Converting Fractional Hex to Decimal in ActionScript

I’m working on a little Flex Geohashing application which required me to convert a fractional Hex value to decimal and the net was no help. It’s a trivial algorithm, but it’s not the kind of thing I want to spend my time writing. So, Here you go, future!

public function fractionalHexToDecimal(hex:String):Number {
	var total:Number = 0;
	for(var i:int = 0; i < hex.length; i++) {
		total += (parseInt("0x" + hex.charAt(i)) / Math.pow(16,i+1));
	}
	return total;
}

Only pass in the fractional. No "0x". No decimal point. Here's how it do.

fractionalHexToDecimal("1");
// 0.0625

fractionalHexToDecimal("0a");
// 0.0390625

fractionalHexToDecimal("db9318c2259923d0");
// 0.8577132677070023

Geohashing App forthcoming.

Flex Game of Life Pt 2

I made a few user interface updates to my crappy Flex version of Conway’s Game of Life.

The board now wraps, and I added a Timer with an adjustable delay via the lovely HSlider control. I wanted to replace the cells with Sprites but it’s giving me grief and I want to play The Sims.

I’m still making my mind up about Flex, but I have to admit that aside from the Sprite issue I’ve been pleasantly surprised at how easy everything’s been coming together.

You can view source on the application, or you can download the zip.

Flex Game of Life

Continuing down the Flex Path, I built another really crappy version of Conway’s Game of Life. Version 2 forthcoming.

I’m still figuring out this whole Flex thing, so please, any help would be much appreciated!

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx         = "http://www.adobe.com/2006/mxml"
	layout           = "vertical"
	creationComplete = "init(gameArea);"
	width            = "425"
	height           = "425"
>
	<mx:Script><![CDATA[
		import model.*;
		private var board:Board;

		private function init(application:DisplayObjectContainer):void {
			board = new Board(application, 10, 0, 0, 30, 30, 5);
		}
	]]></mx:Script>

	<mx:Canvas id="gameArea"></mx:Canvas>
	<mx:HBox>
		<mx:Button label="Reset"  click="board.reset();" />
		<mx:Button label="Update" click="board.update();" />		
	</mx:HBox>
</mx:Application>
package model {

	import flash.display.DisplayObjectContainer;

	public class Board {

		private var size:int;
		private var startX:int;
		private var startY:int;
		private var tileWidth:int;
		private var tileHeight:int;
		private var tileBuffer:int;	
		private var board:Array;
		private var container:DisplayObjectContainer;

		public function Board(
			container:DisplayObjectContainer,
			size:int,
			startX:int,
			startY:int,
			tileWidth:int,
			tileHeight:int,
			tileBuffer:int
		) {
			this.container  = container;
			this.size       = size;
			this.startX     = startX;
			this.startY     = startY;
			this.tileWidth  = tileWidth;
			this.tileHeight = tileHeight;
			this.tileBuffer = tileBuffer;
			reset();
		}

		public function reset():void {
			this.board = new Array(this.size);
			var x:int = startX;
			var y:int = startY;

			clear();

			for(var i:int = 0; i < this.size; i++) {
				this.board[i] = new Array(this.size);
				x = startX;
				for(var j:int = 0; j < this.size; j++) {
					board[i][j] = new Cell(x, y, tileWidth, tileHeight);
					x += this.tileWidth + this.tileBuffer;
					this.container.addChild(board[i][j]);
				}
				y += this.tileHeight + this.tileBuffer;
			}
		}

		public function update():void {
			var next:Array = next();
			for(var i:int = 0; i < this.size; i++) {
				for(var j:int = 0; j < this.size; j++) {
					board[i][j].update(next[i][j]);
				}
			}
		}

		public function clear():void {
			while(this.container.numChildren) {
				this.container.removeChildAt(0);
			}
		}

		public function next():Array {
			var total:int     = 0;
			var next:Array = new Array(this.size);
			for(var i:int = 0; i < this.size; i++) {
				next[i] = new Array(this.size);
				for(var j:int = 0; j < this.size; j++) {
					next[i][j] = board[i][j].next(countNeighbors(i,j));
				}
			}
			return next;
		}

		public function isValid(position:int):Boolean {
			return(position >= 0 && position < this.size);
		}

		public function stateAt(i:int, j:int):Boolean {
			if(isValid(i) && isValid(j)) {
				return board[i][j].state;
			}
			return false;
		}

		public function countNeighbors(x:int, y:int):int {
			var count:int = 0;
			
			for(var i:int = x - 1; i <= x + 1; i++) {
				for(var j:int = y - 1; j <= y + 1; j++) {
					if(!(i == x && j == y) && stateAt(i,j)) {
						count += 1;
					}
				}
			}
			return count;
		}

	}
}
package model {
	import flash.events.MouseEvent;
	
	import mx.controls.Button;

	public class Cell extends Button {

		public var state:Boolean;

		public function Cell(x:int, y:int, width:int, height:int) {
			this.x     = x;
			this.y     = y;
			this.width = width;
			this.height = height;
			this.addEventListener(MouseEvent.CLICK,swap);
			this.reset();
		}

		public function reset():void {
			this.state = false;
		}

		public function next(neighborCount:int):Boolean {
			return((this.state && neighborCount == 2) || neighborCount == 3);
		}

		public function update(state:Boolean):void {
			this.state = state;
			if(this.state) {
				this.label = "0";
			} else {
				this.label = "";
			}
		}

		public function swap(e:MouseEvent):void {
			update(!this.state);
		}

	}
}

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.