Easter Egg Hunt

Web

Project Overview

  • Project Type: 2 Player Web Game
  • Role: Programmer, UI Artist & SFX
  • Software: VS Code, Audacity & Photoshop
  • Languages: Javascript, HTML & CSS
  • Download link: Play Game

Project Brief

Battleship Web Game themed as Easter Egg Hunt. The goal of the game is to find all the missing easter eggs. This game can be played with a friend.
The main challenge of the development process relied on taking responsibility over the art and audio department at the same time I developed all game functionalities.


Responsibilities/Achievements

  • - Implement the algorithm to place the hidden easter eggs
  • - Use of modern JavaScript syntax to develop the game with an object oriented solution
  • - Make sure the gameplay flow was correclty implemented using jQuery and CSS
  • - Use the browser local storage to store the highscores obtained by the player
  • - Generate art and audio assets for the game

Code Samples


/*
* Carlos Adan Cortes De la Fuente
* All rights reserved. Copyright (c)
* Email: dev@carlosadan.com
*/

'use strict';

// Controls the size of the grid
const GRID = {
	ROWS :    10,
	COLUMNS : 10
};

// It is going to tell how to draw the board everytime it need to be updated
const CELL_STATUS = {
	EMPTY :      0,
	HIDDEN_EGG : 1,
	FOUND_EGG :  2,
	MISSING :    3
};

// Represents the amount of eggs in each group everytime one is created
const EGG_TYPE = {
	TINY :   2,
	SMALL :  3,
	MEDIUM : 4,
	LARGE :  5
};

// Possible egg group directions
const DIRECTION = {
	UP :    0,
	DOWN :  1,
	LEFT :  2,
	RIGHT : 3,
};

class Grid {

	constructor() {
		this.resetGrid();
	}

	// Creates an empty grid
	resetGrid() {
		this.matrix = [];
		this.totalEggs = 0;
		this.eggsFound = 0;
		for(let i = 0; i < GRID.ROWS; i++) {
			this.matrix[i] = [];
			for (let j = 0; j < GRID.COLUMNS; j++) {
				this.matrix[i][j] = CELL_STATUS.EMPTY;
			}
		}
	}

	// Places the eggs randomly inside the grid
	placeEggsRandomly(eggBasket) {
		for (let eggType in eggBasket) {
			let eggGroups = eggBasket[eggType];
			// Generates the possible locations for every egg group in the egg basket
			// And places the egg in the matrix
			for (let i = 0; i < eggGroups; i++) {
				let coordinate = this.generateRandomCoordinate();
				let possibleDirections = this.getPossibleDirections(coordinate, eggType);
				// Tries to get a valid placement for the egg type
				while (!this.isCellEmpty(coordinate.row, coordinate.column) || possibleDirections.length == 0) {
					coordinate = this.generateRandomCoordinate();
					possibleDirections = this.getPossibleDirections(coordinate, eggType);
				}
				// Gets a random direction to populate the matrix
				let direction = this.chooseRandomDirection(possibleDirections);
				this.hideEggGroup(coordinate, eggType, direction);
			}
		}
	}

	// Gets a pair of random coordinates between the grid bounds
	generateRandomCoordinate() {
		return {
			row : Math.floor(Math.random() * GRID.ROWS),
			column : Math.floor(Math.random() * GRID.COLUMNS)
		};
	}

	// Returns a random direction value depending on the possible directions provided
	chooseRandomDirection(possibleDirections) {
		// Checks if there is only one direction to return
		if(possibleDirections.length == 1) {
			return possibleDirections[0];
		} else {
			let dir = possibleDirections[Math.floor(Math.random() * possibleDirections.length)];
			return possibleDirections[Math.floor(Math.random() * possibleDirections.length)];
		}
	}

	// Hide Egg
	hideEgg(row, column) {
		this.matrix[row][column] = CELL_STATUS.HIDDEN_EGG;
		this.totalEggs++;
	}

	// Hides the egg over a specific direction
	hideEggGroup(initialCoordinate, eggType, direction) {
		switch (DIRECTION[direction]) {
			case DIRECTION.UP:
				for (let i = 0; i < EGG_TYPE[eggType]; i++) {
					this.hideEgg(initialCoordinate.row - i, initialCoordinate.column);
				}
				break;
			case DIRECTION.DOWN:
				for (let i = 0; i < EGG_TYPE[eggType]; i++) {
					this.hideEgg(initialCoordinate.row + i, initialCoordinate.column);
				}
				break;
			case DIRECTION.LEFT:
				for (let i = 0; i < EGG_TYPE[eggType]; i++) {
					this.hideEgg(initialCoordinate.row, initialCoordinate.column - i);
				}
				break;
			case DIRECTION.RIGHT:
				for (let i = 0; i < EGG_TYPE[eggType]; i++) {
					this.hideEgg(initialCoordinate.row, initialCoordinate.column + i);
				}
				break;
		}
	}

	// Returns the possible directions that the eggGoup can be placed depending on the coordinate
	getPossibleDirections(coordinate, eggType) {
		let possibleDirections = [];
		for (let direction in DIRECTION) {
			switch(DIRECTION[direction]) {
				case DIRECTION.UP:
					if (this.isUpPossible(coordinate, EGG_TYPE[eggType])) {
						possibleDirections.push(direction);
					}
					break;
				case DIRECTION.DOWN:
					if (this.isDownPossible(coordinate, EGG_TYPE[eggType])) {
						possibleDirections.push(direction);
					}
					break;
				case DIRECTION.LEFT:
					if (this.isLeftPossible(coordinate, EGG_TYPE[eggType])) {
						possibleDirections.push(direction);
					}
					break;
				case DIRECTION.RIGHT:
					if (this.isRightPossible(coordinate, EGG_TYPE[eggType])) {
						possibleDirections.push(direction);
					}
					break;
			}
		}
		return possibleDirections;
	}

	// Checks from the given coordinate to go up placing the egg
	isUpPossible(coordinate, eggsToPlace) {
		let validDirection = false;
		// Checks if the row is too close to the upper boundary
		if (coordinate.row - (eggsToPlace - 1) >= 0) {
			validDirection = true;
			// Checks if the inbetween cells are empty
			for (let i = coordinate.row - 1; i > (coordinate.row - eggsToPlace); i--) {
				if (!this.isCellEmpty(i, coordinate.column)) {
					validDirection = false;
					break;
				}
			}
		}
		return validDirection;
	}

	// Checks from the given coordinate to go down placing the egg
	isDownPossible(coordinate, eggsToPlace) {
		let validDirection = false;
		// Checks if the row is too close to the lower boundary
		if (coordinate.row + (eggsToPlace - 1) < GRID.ROWS) {
			validDirection = true;
			// Checks if the inbetween cells are empty
			for (let i = coordinate.row + 1; i < (coordinate.row + eggsToPlace); i++) {
				if (!this.isCellEmpty(i, coordinate.column)) {
					validDirection = false;
					break;
				}
			}
		}
		return validDirection;
	}

	// Checks from the given coordinate to go left placing the egg
	isLeftPossible(coordinate, eggsToPlace) {
		let validDirection = false;
		// Checks if the column is too close to the left boundary
		if (coordinate.column - (eggsToPlace - 1) >= 0) {
			validDirection = true;
			// Checks if the inbetween cells are empty
			for (let i = (coordinate.column - 1); i > (coordinate.column - eggsToPlace); i--) {
				if (!this.isCellEmpty(coordinate.row, i)) {
					validDirection = false;
					break;
				}
			}
		}
		return validDirection;
	}

	// Checks from the given coordinate to go right placing the egg
	isRightPossible(coordinate, eggsToPlace) {
		let validDirection = false;
		// Checks if the column is too close to the right boundary
		if (coordinate.column + (eggsToPlace - 1) < GRID.COLUMNS) {
			validDirection = true;
			// Checks if the inbetween cells are empty
			for (let i = coordinate.column + 1; i < (coordinate.column + eggsToPlace); i++) {
				if (!this.isCellEmpty(coordinate.row, i)) {
					validDirection = false;
					break;
				}
			}
		}
		return validDirection;
	}

	// Returns if the coordinate is empty
	isCellEmpty(row, column) {
		return (this.matrix[row][column] === CELL_STATUS.EMPTY);
	}

	// Let the user know the selection of the cell is valid
	isValidGuessSelection(coordinate) {
		// Checks if the selected coordinate is a valid guess
		return (
			coordinate.row >= 0 &&
			coordinate.row < GRID.ROWS &&
			coordinate.column >= 0 &&
			coordinate.column < GRID.COLUMNS &&
			this.matrix[coordinate.row][coordinate.column] != CELL_STATUS.FOUND_EGG &&
			this.matrix[coordinate.row][coordinate.column] != CELL_STATUS.MISSING)
	}

	// Checks if there's an egg in the cell that the player selected
	isThereAnEgg(coordinate) {
		if(this.matrix[coordinate.row][coordinate.column] == CELL_STATUS.HIDDEN_EGG) {
			this.matrix[coordinate.row][coordinate.column] = CELL_STATUS.FOUND_EGG;
			this.eggsFound++;
			return true;
		} else if(this.matrix[coordinate.row][coordinate.column] == CELL_STATUS.EMPTY) {
			this.matrix[coordinate.row][coordinate.column] = CELL_STATUS.MISSING;
			return false;
		}
	}
}