# Building a Hexagon Game Board

Playing with HTML Canvas to make a hexagonal grid-based game.

I wanted to build a dynamic gameboard in Javascript with the HTML canvas, but decided that a square grid was just too simple of a project. To step things up a notch I decided to build this basic game board a Hexagonal based system. It quickly turned into an interesting thought experiment.

## A Conventional Grid

In a conventional 3x3 grid setting we use an multidimensional array to store the data for the map. This generates 9 easily addressable points.

``````const mapWidth = 3;
const mapHeight = 3;
const mapGrid = [];
for (let y = 0; y < mapHeight; y++) {
const row = [];

for (let x = 0; x < mapWidth; x++) {
const col =  {
isOccupied: false,
x: x,
y: y
};
row.push(col);
}

mapGrid.push(row);
}
``````

This generates for us a multidimensional array of objects like similar to this:

``````mapGrid = [
[{}, {}, {}],
[{}, {}, {}],
[{}, {}, {}]
]``````

If we want to access the Top Left, it would be addressed as `mapGrid` because javascript is a zero based system. The bottom right would be `mapGrid`. From here if we want to see if a specific cell has the `isOccupied` flag set to `true`, we can easily access the location with an array check.

``````console.log(mapGrid[y][x].isOccupied);
``````

Assuming we have a Player Token at the center of the grid, and we wanted to move the character, we would use an coordinal system for direction (usually North, East, South, West). If we want our Token to move North, we would reduce the `y` value of the token by one, and add one if moving South. Moving the Token East and West we would affect the `x` value of our Token.

Although we can work with the code we have, it starts to get a little kludgy as we start to expand the functionality. Before we go to far lets, refactor what we have into classes.

``````class Cell {
constructor(x, y) {
this.isOccupied = false;
this.x = x;
this.y = y;
} // close constructor
} // close Cell

class Token {
constructor(name, startX, startY, map) {
this.name = name;
this.x = startX;
this.y = startY;
this.map = map;

this.map.occupyCell(this.x, this.y);
} // close constructor

move(direction) {
let newX = new Number(this.x);
let newY = new Number(this.y);

switch (direction.toUpperCase()) {
case "N":
newY = newY - 1;
break;
case "S":
newY = newY + 1;
break;
case "E":
newX = newX + 1;
break;
case "W":
newX = newX - 1;
break;
} // close switch

// Make sure our new position is within the contrains of our map
if (newY < 0) {
newY = 0;
} else if (newY > this.map.maxRows) {
newY = this.map.maxRows;
} // close if newY

if (newX < 0) {
newX = 0;
} else if (newX > this.map.maxCols) {
newX = this.map.maxCols;
} // close if newX

// Make sure out new position is not already occupied
if (!this.map.isCellOccupied(newX, newY)) {
// leave our current cell
this.map.clearCell(this.x, this.y);
// occupy our new cell
this.map.occupyCell(newX, newY);
// set our values
this.x = newX;
this.y = newY;
} // close if not occupied
} // close move
} // close Token

class MapGrid {
constructor(mapWidth, mapHeight) {
this.grid = [];
this.maxRows = mapHeight - 1;
this.maxCols = mapWidth - 1;

for (let y = 0; y < mapHeight; y++) {
const row = [];

for (let x = 0; x < mapWidth; x++) {
row.push(new Cell(x, y));
} // close for x++

this.grid.push(row);
} // for for y++
} // close constructor

getCell(x,y) {
return this.grid[y][x];
} // close getCell

isCellOccupied(x, y) {
return this.getCell(x, y).isOccupied;
} // close isCellOccupied

occupyCell(x, y) {
this.getCell(x, y).isOccupied = true;
} // close occupyCell

clearCell(x, y) {
this.getCell(x, y).isOccupied = false;
} // close clearCell
} // close MapGrid

const init = () => {
const gameMap = new MapGrid(3, 3);
const playerToken = new Token("Player 1", 1, 1, gameMap);

const key = event.key;

if (key === "ArrowLeft") {
playerToken.move("W");
} else if (key === "ArrowRight") {
playerToken.move("E");
} else if (key === "ArrowUp") {
playerToken.move("N");
} else if (key === "ArrowDown") {
playerToken.move("S");
}
This wasn't as simple as building a grid like you would with squares as I required to offset both the `x` and `y` values to neatly stack each hexagon. I also added an extra cell to each even row to keep the map "balanced". This lead to odd rows having 9 columns, and even having 10 which leads to moving issues later on.