A Bejeweled Clone in JavaScript

The JavaScript code below implements a simple clone of the tile-matching game Bejeweled. To see it in action, copy it into an .html file and open that file in a web browser that runs JavaScript. Or, for an online version, visit https://thiscouldbebetter.neocities.org/tilematchinggame.html.

MatchThree

<html>
<body>

<div id="divMain"></div>

<script type="text/javascript">

// main

function main()
{
	var tileDefns = 
	[
		new TileDefn("A", "Red"),
		new TileDefn("B", "Orange"),
		new TileDefn("C", "Yellow"),
		new TileDefn("D", "Green"),
		new TileDefn("E", "Blue"),
		new TileDefn("F", "Purple"),
	];

	tileDefns.addLookups("symbol");

	var viewSizeInPixels = new Coords(200, 240);

	var level = new Level
	(
		"Level0",
		30, // numberOfMovesAllowed
		50, // numberOfMatchesToWin
		tileDefns,
		new Map
		(
			new Coords(9, 9),
			new Coords(200, 200)
		)
	);

	Globals.Instance.initialize
	(
		200, // millisecondsPerTimerTick
		viewSizeInPixels,
		level
	);
}

// extensions

Array.prototype.addLookups = function(keyName)
{
	for (var i = 0; i < this.length; i++)
	{
		var element = this[i];
		var keyValue = element[keyName];
		this[keyValue] = element;
	}
}

// classes

function Coords(x, y)
{
	this.x = x;
	this.y = y;
}
{
	Coords.prototype.add = function(other)
	{
		this.x += other.x;
		this.y += other.y;

		return this;
	}

	Coords.prototype.clone = function()
	{
		return new Coords(this.x, this.y);
	}

	Coords.prototype.divide = function(other)
	{
		this.x /= other.x;
		this.y /= other.y;

		return this;
	}

	Coords.prototype.divideScalar = function(scalar)
	{
		this.x /= scalar;
		this.y /= scalar;

		return this;
	}

	Coords.prototype.equals = function(other)
	{
		var returnValue = 
		(
			this.x == other.x
			&& this.y == other.y
		);

		return returnValue;
	}

	Coords.prototype.floor = function()
	{
		this.x = Math.floor(this.x);
		this.y = Math.floor(this.y);

		return this;
	}

	Coords.prototype.multiply = function(other)
	{
		this.x *= other.x;
		this.y *= other.y;

		return this;
	}

	Coords.prototype.multiplyScalar = function(scalar)
	{
		this.x *= scalar;
		this.y *= scalar;

		return this;
	}

	Coords.prototype.overwriteWith = function(other)
	{
		this.x = other.x;
		this.y = other.y;

		return this;
	}

	Coords.prototype.subtract = function(other)
	{
		this.x -= other.x;
		this.y -= other.y;

		return this;
	}

	Coords.prototype.trimToRange = function(range)
	{
		if (this.x < 0)
		{
			this.x = 0;
		}
		else if (this.x > range.x)
		{
			this.x = range.x;
		}

		if (this.y < 0)
		{
			this.y = 0;
		}
		else if (this.y > range.y)
		{
			this.y = range.y;
		}

		return this;
	}
}

function Cursor(pos, isTileSelected)
{
	this.pos = pos;
	this.isTileSelected = isTileSelected;
}

function Debug()
{}
{
	Debug._idNext = 0;

	Debug.IDNext = function()
	{
		IDHelper._idNext++;
		return IDHelper._idNext;	
	}
}

function DisplayHelper()
{}
{
	DisplayHelper.prototype.clear = function()
	{
		this.graphics.fillStyle = "White";
		this.graphics.fillRect
		(
			0, 0, 
			this.viewSizeInPixels.x, 
			this.viewSizeInPixels.y
		);

		this.graphics.strokeStyle = "LightGray";
		this.graphics.strokeRect
		(
			0, 0, 
			this.viewSizeInPixels.x, 
			this.viewSizeInPixels.y
		);
	}

	DisplayHelper.prototype.drawLevel = function(level)
	{
		this.clear();

		var levelMap = level.map;
		var mapCellSizeInPixels = levelMap.cellSizeInPixels;

		this.drawMap(level.map);

		var tiles = level.tiles;

		for (var i = 0; i < tiles.length; i++)
		{
			var tile = tiles[i];
			this.drawTile
			(
				tile, 
				levelMap
			);
		}

		var cursor = level.cursor;

		this.drawPos.overwriteWith
		(
			cursor.pos
		).add
		(
			new Coords(.25, .25)
		).multiply
		(
			mapCellSizeInPixels
		);

		var cursorSizeInPixels = mapCellSizeInPixels.clone().divideScalar(2);

		if (cursor.isTileSelected == true)
		{
			this.graphics.strokeStyle = "Black";
		}
		else
		{
			this.graphics.strokeStyle = "LightGray";
		}
		
		this.graphics.strokeRect
		(
			this.drawPos.x,
			this.drawPos.y,
			cursorSizeInPixels.x,
			cursorSizeInPixels.y
		);

		var fontHeight = 10; // hack

		this.graphics.fillStyle = "LightGray";
		this.graphics.fillText
		(
			"Matches:" + level.numberOfMatchesSoFar + "/" + level.numberOfMatchesToWin,
			2, 
			levelMap.sizeInPixels.y + fontHeight
		);

		this.graphics.fillText
		(
			"Moves:" + level.numberOfMovesSoFar + "/" + level.numberOfMovesAllowed,
			2, 
			levelMap.sizeInPixels.y + (fontHeight * 2)
		);
	}

	DisplayHelper.prototype.drawMap = function(map)
	{
		var mapSizeInCells = map.sizeInCells;
		var cellSizeInPixels = map.cellSizeInPixels;

		var cellPos = new Coords(0, 0);
		var drawPos = this.drawPos;

		this.graphics.strokeStyle = "LightGray";
	
		for (var y = 0; y < mapSizeInCells.y; y++)
		{
			cellPos.y = y;

			for (var x = 0; x < mapSizeInCells.x; x++)
			{
				cellPos.x = x;

				drawPos.overwriteWith
				(
					cellPos
				).multiply
				(
					cellSizeInPixels
				);

				this.graphics.strokeRect
				(
					drawPos.x,
					drawPos.y,
					cellSizeInPixels.x,
					cellSizeInPixels.y
				);
			}
		}
	}

	DisplayHelper.prototype.drawTile = function(tile, map)
	{
		var tileDefn = tile.defn();
		var mapCellSizeInPixels = map.cellSizeInPixels;
		var tilePos = map.posOfCell(tile.cell);

		var drawPos = this.drawPos.overwriteWith
		(
			tilePos
		).multiply
		(
			mapCellSizeInPixels
		);

		var drawSize = this.drawSize.overwriteWith
		(
			mapCellSizeInPixels
		);

		var tileFractionOfLifeRemaining = 
		(
			tile.ticksToLive == null ? null : (tile.ticksToLive / Level.TicksToEliminateTile)
		)

		if (this.useColors == true)
		{
			if (tileFractionOfLifeRemaining != null)
			{
				drawSize = drawSize.multiplyScalar
				(
					tileFractionOfLifeRemaining
				);
			}

			drawPos.add
			(
				mapCellSizeInPixels.clone().subtract
				(
					drawSize
				).divideScalar(2)
			)

			this.graphics.fillStyle = tileDefn.color;
			this.graphics.fillRect
			(
				drawPos.x,
				drawPos.y,
				drawSize.x,
				drawSize.y
			);
		}
		else
		{
			var tileWidth = this.graphics.measureText(tileDefn.symbol).width;


			if (tileFractionOfLifeRemaining == null)
			{
				this.graphics.fillStyle = "LightGray";
				this.graphics.fillText
				(
					tileDefn.symbol,
					drawPos.x + (mapCellSizeInPixels.x - tileWidth) / 2,
					drawPos.y + mapCellSizeInPixels.y * .6
				);
			}
			else 
			{
				this.graphics.fillStyle = "Black";
				this.graphics.fillText
				(
					tileDefn.symbol,
					drawPos.x + (mapCellSizeInPixels.x - tileWidth) / 2,
					drawPos.y + mapCellSizeInPixels.y * .6
				);
					
				if (tileFractionOfLifeRemaining < 1)
				{
					var alpha = 1 - tileFractionOfLifeRemaining;
					this.graphics.fillStyle = "rgba(255, 255, 255, " + alpha + ")";
					this.graphics.fillRect
					(
						drawPos.x,
						drawPos.y,
						drawSize.x,
						drawSize.y	
					);
				}
			}
		}
	}

	DisplayHelper.prototype.initialize = function(useColors, viewSizeInPixels)
	{
		this.useColors = useColors;

		this.viewSizeInPixels = viewSizeInPixels;

		var canvas = document.createElement("canvas");
		canvas.width = this.viewSizeInPixels.x;
		canvas.height = this.viewSizeInPixels.y;

		this.graphics = canvas.getContext("2d");

		var divMain = document.getElementById("divMain");
		divMain.appendChild(canvas);

		this.drawPos = new Coords(0, 0);
		this.drawSize = new Coords(0, 0);
	}
}

function Globals()
{}
{
	Globals.Instance = new Globals();

	Globals.prototype.initialize = function
	(
		millisecondsPerTimerTick, 
		viewSizeInPixels,
		level
	)
	{
		this.displayHelper = new DisplayHelper();
		var useColors = true;
		this.displayHelper.initialize(useColors, viewSizeInPixels);

		this.level = level;

		this.randomizer = new RandomizerLCG
		(
			12345,
			54321,
			123456789,
			.12345
		);

		setInterval
		(
			this.handleEventTimerTick.bind(this),
			millisecondsPerTimerTick
		);		

		this.inputHelper = new InputHelper();
		this.inputHelper.initialize();
	}

	// events

	Globals.prototype.handleEventTimerTick = function()
	{
		this.level.updateForTimerTick();
	}
}

function InputHelper()
{}
{
	InputHelper.prototype.initialize = function()
	{
		document.body.onkeydown = this.handleEventKeyDown.bind(this);
	}

	// events

	InputHelper.prototype.handleEventKeyDown = function(e)
	{
		this.keyCode = e.keyCode;
	}
}

function Level(name, numberOfMovesAllowed, numberOfMatchesToWin, tileDefns, map)
{
	this.name = name;
	this.numberOfMovesAllowed = numberOfMovesAllowed;
	this.numberOfMatchesToWin = numberOfMatchesToWin;
	this.tileDefns = tileDefns;
	this.map = map;

	this.tileDefns.addLookups("name");
	this.tiles = [];

	this.cursor = new Cursor
	(
		new Coords(0, 0), // pos
		false // isTileSelected
	);

	this.numberOfMovesSoFar = 0;
	this.numberOfMatchesSoFar = 0;
	this.haveMatchesBeenCheckedSinceLastChange = false;

	this.isFinished = false;
}
{
	// constants

	Level.TicksToEliminateTile = 5;

	// instance methods

	Level.prototype.eliminateCellAtPos = function(cellPosToEliminate)
	{
		var cellToEliminate = this.map.cellAtPos
		(
			cellPosToEliminate
		);

		var tileToEliminate = cellToEliminate.tilePresent;
	
		if (tileToEliminate != null)
		{	
			/*					
			this.tiles.splice
			(
				this.tiles.indexOf(tileToEliminate),
				1
			);
			cellToEliminate.tilePresent = null;
			*/

			tileToEliminate.ticksToLive = Level.TicksToEliminateTile;
		}
	}

	Level.prototype.matchesAddToList = function(listToAddMatchesTo)
	{
		var mapSizeInCells = this.map.sizeInCells;

		var cellPos = new Coords(0, 0);
		var tileDefnNameCurrent;
		var tileDefnNamePrev;
		var tilesOfSameTypeInARow;

		var dimensionIndex = 0;

		// horizontal matches

		for (var y = 0; y < mapSizeInCells.y; y++)
		{
			cellPos.y = y;

			tileDefnNamePrev = null;
			tilesOfSameTypeInARow = 0;

			for (var x = 0; x < mapSizeInCells.x; x++)
			{
				cellPos.x = x;

				var cellAtPos = this.map.cellAtPos(cellPos);
				var tileInCell = cellAtPos.tilePresent;
				if (tileInCell != null)
				{
					tileDefnNameCurrent = tileInCell.defnName;

					tilesOfSameTypeInARow = this.matchesAddToList_2
					(
						cellPos,
						tileDefnNameCurrent,
						tileDefnNamePrev,
						tilesOfSameTypeInARow,
						dimensionIndex,
						listToAddMatchesTo
					);

					tileDefnNamePrev = tileDefnNameCurrent;
				}
			}

			cellPos.x++;
			this.matchesAddToList_3
			(
				tilesOfSameTypeInARow,
				cellPos,
				dimensionIndex,
				listToAddMatchesTo
			);
		}

		var dimensionIndex = 1;

		for (var x = 0; x < mapSizeInCells.x; x++)
		{
			cellPos.x = x;

			tileDefnNamePrev = null;
			tilesOfSameTypeInARow = 0;

			for (var y = 0; y < mapSizeInCells.y; y++)
			{
				cellPos.y = y;

				var cellAtPos = this.map.cellAtPos(cellPos);
				var tileInCell = cellAtPos.tilePresent;
				if (tileInCell != null)
				{
					tileDefnNameCurrent = tileInCell.defnName;

					tilesOfSameTypeInARow = this.matchesAddToList_2
					(
						cellPos,
						tileDefnNameCurrent,
						tileDefnNamePrev,
						tilesOfSameTypeInARow,
						dimensionIndex,
						listToAddMatchesTo
					);

					tileDefnNamePrev = tileDefnNameCurrent;
				}
			}

			cellPos.y++;
			this.matchesAddToList_3
			(
				tilesOfSameTypeInARow,
				cellPos,
				dimensionIndex,
				listToAddMatchesTo
			);
		}

		return listToAddMatchesTo;
	}

	Level.prototype.matchesAddToList_2 = function
	(
		cellPos, 
		tileDefnNameCurrent,
		tileDefnNamePrev,
		tilesOfSameTypeInARow,
		dimensionIndex,
		listToAddMatchesTo
	)
	{
		if (tileDefnNameCurrent == tileDefnNamePrev)
		{
			tilesOfSameTypeInARow++;
		}
		else
		{
			this.matchesAddToList_3
			(
				tilesOfSameTypeInARow, 
				cellPos, 
				dimensionIndex,
				listToAddMatchesTo
			);
			tilesOfSameTypeInARow = 1;
		}

		return tilesOfSameTypeInARow;
	}


	Level.prototype.matchesAddToList_3 = function
	(
		tilesOfSameTypeInARow,
		cellPos,
		dimensionIndex,
		listToAddMatchesTo
	)
	{
		var numberOfTilesPerMatch = 3;

		if (tilesOfSameTypeInARow >= numberOfTilesPerMatch)
		{
			var cellPositionsForMatch = [];

			for (var i = 1; i <= tilesOfSameTypeInARow; i++)
			{
				var cellPosToAddToMatch = new Coords
				(
					cellPos.x - (dimensionIndex == 0 ? i : 0),
					cellPos.y - (dimensionIndex == 1 ? i : 0) 
				);
				
				cellPositionsForMatch.push(cellPosToAddToMatch);
			}

			var match = new TileMatch(cellPositionsForMatch);

			listToAddMatchesTo.push(match);
		}
	}

	Level.prototype.matchesEliminate = function()
	{
		var matchesToEliminate = this.matchesAddToList([]);

		for (var m = 0; m < matchesToEliminate.length; m++)
		{
			var match = matchesToEliminate[m];

			for (var i = 0; i < match.cellPositions.length; i++)
			{
				var cellPos = match.cellPositions[i];

				this.eliminateCellAtPos(cellPos);
			}

			this.numberOfMatchesSoFar++;
		}		
	}

	Level.prototype.tilesDestabilizeAbovePos = function(cellPosToEliminate)
	{
		for (var j = cellPosToEliminate.y - 1; j >= 0; j--)
		{
			var cellPosToDestabilize = new Coords
			(
				cellPosToEliminate.x,
				j
			);
			var cellToDestabilize = this.map.cellAtPos
			(
				cellPosToDestabilize
			);
			var tileToDestabilize = cellToDestabilize.tilePresent;
			if (tileToDestabilize != null)
			{
				tileToDestabilize.isAtRest = false;
			}
		}
	}

	Level.prototype.tilesShuffle = function()
	{
		var mapCells = this.map.cells;
		var numberOfMapCells = mapCells.length;

		for (var i = 0; i < numberOfMapCells; i++)
		{
			var mapCell = mapCells[i];
			mapCell.tilePresent = null;
		}

		for (var t = 0; t < this.tiles.length; t++)
		{
			var tile = this.tiles[t];

			var mapCellIndex = Math.floor
			(
				numberOfMapCells
				* Math.random()
			);

			while (mapCells[mapCellIndex].tilePresent != null)
			{
				mapCellIndex++;
				if (mapCellIndex >= numberOfMapCells)
				{
					mapCellIndex = 0;
				}
			}

			var mapCell = mapCells[mapCellIndex];
			mapCell.tilePresent = tile;
			tile.cell = mapCell;

			tile.isAtRest = false;
		}
	}

	Level.prototype.tilesSwapAtPositions = function(cursorPos, cursorPosNext)
	{
		var cellAtPos = this.map.cellAtPos(cursorPos);
		var cellAtPosNext = this.map.cellAtPos(cursorPosNext);

		var tileAtPosCurrent = cellAtPos.tilePresent;
		var tileAtPosNext = cellAtPosNext.tilePresent;

		tileAtPosCurrent.cell = cellAtPosNext;
		tileAtPosNext.cell = cellAtPos;

		cellAtPos.tilePresent = tileAtPosNext;
		cellAtPosNext.tilePresent = tileAtPosCurrent;

		//tileAtPosCurrent.isAtRest = false;
		//tileAtPosNext.isAtRest = false;
	}

	Level.prototype.updateForTimerTick = function()
	{		
		this.updateForTimerTick_FillTopRow();

		Globals.Instance.displayHelper.drawLevel(this);

		this.updateForTimerTick_Tiles();

		this.updateForTimerTick_WinOrLose();
	}

	Level.prototype.updateForTimerTick_FillTopRow = function()
	{
		var cellPos = new Coords(0, 0);

		for (var x = 0; x < this.map.sizeInCells.x; x++)
		{
			cellPos.x = x;
			var cellAtPos = this.map.cellAtPos(cellPos);

			if (cellAtPos.tilePresent == null)
			{
				var tileDefnIndex = Math.floor
				(
					this.tileDefns.length * 
					Math.random()
					//Globals.Instance.randomizer.getNextRandom()
				);
				var tileDefnName = this.tileDefns[tileDefnIndex].symbol;
				var tile = new Tile
				(
					tileDefnName,
					cellAtPos
				);

				cellAtPos.tilePresent = tile;

				this.tiles.push(tile);

				this.haveMatchesBeenCheckedSinceLastChange = false;
			}
		}
	}

	Level.prototype.updateForTimerTick_Input = function()
	{
		var keyCode = Globals.Instance.inputHelper.keyCode;

		if (keyCode == 13) // enter
		{
			var cursor = this.cursor;
			cursor.isTileSelected = (cursor.isTileSelected == false);
		}
		else if (keyCode == 65) // a
		{	
			this.updateForTimerTick_Input_CursorMove(new Coords(-1, 0));
		}
		else if (keyCode == 68) // d
		{
			this.updateForTimerTick_Input_CursorMove(new Coords(1, 0));
		}
		else if (keyCode == 83) // s
		{
			this.updateForTimerTick_Input_CursorMove(new Coords(0, 1));
		}
		else if (keyCode == 87) // w
		{
			this.updateForTimerTick_Input_CursorMove(new Coords(0, -1));
		}

		Globals.Instance.inputHelper.keyCode = null;
	}

	Level.prototype.updateForTimerTick_Input_CursorMove = function(directionToMove)
	{
		var level = this;
		var cursor = level.cursor;
		var map = level.map;
		var mapSizeInCellsMinusOnes = map.sizeInCellsMinusOnes;

		var cursorPos = cursor.pos;
		var cursorPosNext = cursorPos.clone().add
		(
			directionToMove
		).trimToRange
		(
			mapSizeInCellsMinusOnes
		);

		if (cursorPos.equals(cursorPosNext) == false)
		{
			if (cursor.isTileSelected == true)
			{
				cursor.isTileSelected = false;
				this.tilesSwapAtPositions(cursorPos, cursorPosNext);

				var matchesResultingFromMove = this.matchesAddToList([]);
				if (matchesResultingFromMove.length == 0)
				{
					this.tilesSwapAtPositions(cursorPos, cursorPosNext);
				}
				else
				{
					this.numberOfMovesSoFar++;
					this.haveMatchesBeenCheckedSinceLastChange = false;
					cursorPos.overwriteWith(cursorPosNext);
				}
			}
			else
			{
				cursorPos.overwriteWith(cursorPosNext);
			}
		}
	}

	Level.prototype.updateForTimerTick_Tiles = function()
	{
		var tilesToRemove = [];

		for (var t = 0; t < this.tiles.length; t++)
		{
			var tile = this.tiles[t];

			if (tile.ticksToLive != null)
			{
				tile.ticksToLive--;
				if (tile.ticksToLive <= 0)
				{
					tilesToRemove.push(tile);
				}
			}
		}

		for (var t = 0; t < tilesToRemove.length; t++)
		{
			var tile = tilesToRemove[t];

							
			var tileIndex = this.tiles.indexOf(tile);
			if (tileIndex >= 0)
			{
				// hack
				// Why is tileIndex < 0 sometimes?
				this.tiles.splice
				(
					tileIndex,
					1
				);
			}

			var cellPos = this.map.posOfCell(tile.cell);

			tile.cell.tilePresent = null;
			tile.cell = null;

			this.tilesDestabilizeAbovePos(cellPos);
		}

		var directionDown = new Coords(0, 1);
		var tilePosNext = new Coords(0, 0);
		var areAllTilesAtRest = true;

		var cellPos = new Coords(0, 0);

		for (var y = this.map.sizeInCells.y - 1; y >= 0; y--)
		{
			cellPos.y = y;

			for (var x = 0; x < this.map.sizeInCells.x; x++)
			{
				cellPos.x = x;

				var cell = this.map.cellAtPos(cellPos);
				var tile = cell.tilePresent;

				if (tile == null)
				{
					areAllTilesAtRest = false;
				}
				else 
				{
					if (tile.isAtRest == false)
					{
						areAllTilesAtRest = false;
		
						tilePosNext.overwriteWith
						(
							cellPos
						).add
						(
							directionDown
						);
			
						if (tilePosNext.y >= this.map.sizeInCells.y)
						{
							tile.isAtRest = true;
						}
						else
						{
							var cellNext = this.map.cellAtPos
							(
								tilePosNext
							);
							var tileInCellNext = cellNext.tilePresent;
		
							if (tileInCellNext == null)
							{
								cell.tilePresent = null;
								cellNext.tilePresent = tile;
								tile.cell = cellNext;
							}
							else if (tileInCellNext.isAtRest == true)
							{
								tile.isAtRest = true;
							}
						}
					}
				}
			}
		}

		if (areAllTilesAtRest == true)
		{
			if (this.haveMatchesBeenCheckedSinceLastChange == true)
			{
				this.updateForTimerTick_Input();
			}
			else
			{
				this.matchesEliminate();
				this.haveMatchesBeenCheckedSinceLastChange = true;	
			}
		}
	}

	Level.prototype.updateForTimerTick_WinOrLose = function()
	{
		if (this.isFinished == false)
		{
			if (this.numberOfMatchesSoFar >= this.numberOfMatchesToWin)
			{
				alert("You win!");
				this.isFinished = true;
			}
			else if (this.numberOfMovesSoFar >= this.numberOfMovesAllowed)
			{
				alert("Out of moves! You lose.");
				this.isFinished = true;
			}
		}
	}

}

function Map(sizeInCells, sizeInPixels)
{
	this.sizeInCells = sizeInCells;
	this.sizeInPixels = sizeInPixels;

	this.sizeInCellsMinusOnes = this.sizeInCells.clone().subtract
	(
		new Coords(1, 1)
	);

	this.cellSizeInPixels = this.sizeInPixels.clone().divide
	(
		this.sizeInCells
	);

	this.cells = [];
	var numberOfCells = this.sizeInCells.x * this.sizeInCells.y;

	for (var i = 0; i < numberOfCells; i++)
	{
		var cell = new MapCell(null);
		this.cells.push(cell);
	}
}
{
	Map.prototype.cellAtPos = function(cellPos)
	{
		var cellIndex = this.indexOfCellAtPos(cellPos);
		var returnValue = this.cells[cellIndex];
		return returnValue;
	}

	Map.prototype.indexOfCellAtPos = function(cellPos)
	{
		return cellPos.y * this.sizeInCells.x + cellPos.x;
	}

	Map.prototype.posOfCell = function(cell)
	{
		return this.posOfCellAtIndex(this.cells.indexOf(cell));
	}

	Map.prototype.posOfCellAtIndex = function(cellIndex)
	{
		var cellPosX = cellIndex % this.sizeInCells.x;
		var cellPosY = (cellIndex - cellPosX) / this.sizeInCells.x;

		var returnValue = new Coords
		(
			cellPosX,
			cellPosY
		);

		return returnValue;
	}
}

function MapCell(tilePresent)
{
	this.tilePresent = tilePresent;
}

function RandomizerLCG(multiplier, addend, modulus, firstRandom)
{
	// "LCG" stands for "linear congruential generator".

	this.multiplier = multiplier;
	this.addend = addend;
	this.modulus = modulus;
	this.currentRandom = firstRandom;
}
{
	RandomizerLCG.prototype.getNextRandom = function()
	{
		this.currentRandom = 
		(
			(
				this.multiplier 
				* (this.currentRandom * this.modulus)
				+ this.addend
			) 
			% this.modulus
		) 
		/ this.modulus;

		return this.currentRandom;
	}
}

function Tile(defnName, cell)
{
	this.defnName = defnName;
	this.cell = cell;

	this.isAtRest = false;
	this.ticksToLive = null;
}
{
	Tile.prototype.defn = function()
	{
		return Globals.Instance.level.tileDefns[this.defnName];
	}
}

function TileDefn(symbol, color)
{
	this.symbol = symbol;
	this.color = color;
}

function TileMatch(cellPositions)
{
	this.cellPositions = cellPositions;
}

// run

main();

</script>
</body>
</html>
This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s