Skip to content
This repository has been archived by the owner on Dec 30, 2020. It is now read-only.

Commit

Permalink
Format, ease game's difficulty, update readme, remove fake P key
Browse files Browse the repository at this point in the history
Allow multiple letters to appear at once, increase vowels probability to drop, decrease letters probability to drop from .05 to .03, fix leaderboard not displayed yes when the word was found
  • Loading branch information
HunteRoi committed Dec 6, 2020
1 parent f49521c commit d23a447
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 263 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# HangSnake
This is my little gift for my girlfriend to play some old games her younger self liked very much.

Enjoy!
Enjoy!

## Note
You need to run this from a server. I'm using the plugin "Live Server" to run & dispose of a server from Visual Studio Code anytime I need it.

## To do
If I've got some spare time, I might think to properly implement a pause button using the P key (yes, only setting the `inputDirection` back to `{ x: 0, y: 0 }` is not enough). I'd also want to get rid of those `<div>` generation and use a `<canvas>`. Also want to display a real snake instead of blocks. But this will be for a different story!
94 changes: 50 additions & 44 deletions food.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,73 +3,79 @@ import { getRandomGridPosition } from './grid.js';
import { update as grantPoints } from './points.js';
import { update as updateLetters } from './hangman.js';

const CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const CHARACTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZAEIOUYAEIOUYAEIOUYAEIOUY';
const APPLE = { type: 'apple', points: 1 };
const BUG = { type: 'bug', lifespan: 30, points: 3 };

const EXPANSION_RATE = 1;
const OCCASIONAL_FOOD_PROBABILITY = 0.05;
const OCCASIONAL_FOOD_PROBABILITY = 0.03;

let food = { ...getRandomFoodPosition(), ...APPLE };
let occasionalFood = null;
const occasionalFoods = [];

export function update() {
if (occasionalFood !== null) {
if (onSnake(occasionalFood)) {
const isOk = updateLetters(occasionalFood.letter);
if (isOk) grantPoints(occasionalFood.points);
else grantPoints(occasionalFood.points * -1);

expandSnake(EXPANSION_RATE);
occasionalFood = null;
} else {
if (occasionalFood && occasionalFood.lifespan > 0) {
occasionalFood.lifespan -= 1;
} else {
occasionalFood = null;
}
}
}
if (shouldGenerateOccasionalFood()) {
occasionalFood = { ...getRandomFoodPosition(), ...BUG, letter: getRandomLetter() };
const toRemove = [];
occasionalFoods.forEach((occasionalFood, index) => {
if (onSnake(occasionalFood)) {
const isOk = updateLetters(occasionalFood.letter);
grantPoints(isOk ? occasionalFood.points : occasionalFood.points * -1);
expandSnake(EXPANSION_RATE);
toRemove.push(index);
} else {
if (occasionalFood.lifespan > 0) {
occasionalFood.lifespan -= 1;
} else {
toRemove.push(index);
}
}
});
toRemove.forEach((i) => occasionalFoods.splice(i, 1));
if (shouldGenerateOccasionalFood()) {
occasionalFoods.push({
...getRandomFoodPosition(),
...BUG,
letter: getRandomLetter(),
});
}

if (onSnake(food)) {
grantPoints(food.points);
expandSnake(EXPANSION_RATE);
food = { ...getRandomFoodPosition(), ...APPLE };
}
if (onSnake(food)) {
grantPoints(food.points);
expandSnake(EXPANSION_RATE);
food = { ...getRandomFoodPosition(), ...APPLE };
}
}

export function draw(gameboard) {
drawFood(gameboard, food);
drawFood(gameboard, food);

if (occasionalFood !== null) {
drawFood(gameboard, occasionalFood);
}
if (occasionalFoods.length !== 0) {
occasionalFoods.forEach((occasionalFood) =>
drawFood(gameboard, occasionalFood)
);
}
}

function drawFood(gameboard, food) {
const foodElement = document.createElement('div');
if (food.letter) foodElement.innerText = food.letter;
foodElement.style.gridRowStart = food.y;
foodElement.style.gridColumnStart = food.x;
foodElement.classList.add(food.type);
gameboard.appendChild(foodElement);
const foodElement = document.createElement('div');
if (food.letter) foodElement.innerText = food.letter;
foodElement.style.gridRowStart = food.y;
foodElement.style.gridColumnStart = food.x;
foodElement.classList.add(food.type);
gameboard.appendChild(foodElement);
}

function getRandomFoodPosition() {
let newFoodPosition;
while (newFoodPosition == null || onSnake(newFoodPosition)) {
newFoodPosition = getRandomGridPosition();
}
return newFoodPosition;
let newFoodPosition;
while (newFoodPosition == null || onSnake(newFoodPosition)) {
newFoodPosition = getRandomGridPosition();
}
return newFoodPosition;
}

function shouldGenerateOccasionalFood() {
return Math.random() < OCCASIONAL_FOOD_PROBABILITY && occasionalFood === null;
return Math.random() < OCCASIONAL_FOOD_PROBABILITY;
}

function getRandomLetter() {
return CHARACTERS.charAt(Math.floor(Math.random() * CHARACTERS.length));
}
return CHARACTERS.charAt(Math.floor(Math.random() * CHARACTERS.length));
}
87 changes: 47 additions & 40 deletions game.js
Original file line number Diff line number Diff line change
@@ -1,67 +1,74 @@
import { draw as drawSnake, update as updateSnake, getSpeed, getSnakeHead, snakeIntersection } from './snake.js';
import {
draw as drawSnake,
update as updateSnake,
getSpeed,
getSnakeHead,
snakeIntersection,
} from './snake.js';
import { draw as drawFood, update as updateFood } from './food.js';
import { draw as drawPoints, getPoints } from './points.js';
import { draw as drawHangman, hasFoundTheWord } from './hangman.js';
import { outsideGrid } from './grid.js';

const gameboard = document.getElementById("gameboard");
const pointsboard = document.getElementById("pointsboard");
const hangmanboard = document.getElementById("hangmanboard");
const lettersboard = document.getElementById("lettersboard");
const leaderboard = document.getElementById("leaderboard");
const gameboard = document.getElementById('gameboard');
const pointsboard = document.getElementById('pointsboard');
const hangmanboard = document.getElementById('hangmanboard');
const lettersboard = document.getElementById('lettersboard');
const leaderboard = document.getElementById('leaderboard');
let lastRenderTime = 0;
let gameOver = false;

function main(currentTime) {
const hasFoundIt = hasFoundTheWord();
if (gameOver || hasFoundIt) {
if (hasFoundIt) {
document.getElementById("app").display = "none";
document.getElementById("victory").display = "flex";
}
const hasFoundIt = hasFoundTheWord();
if (gameOver || hasFoundIt) {
if (hasFoundIt) {
document.getElementById('app').display = 'none';
document.getElementById('victory').display = 'flex';
}

const profile = prompt("What is your name?") || "Unknown";
const profileEntry = { points: getPoints(), wordFound: hasFoundTheWord() };
window.localStorage.setItem(profile, JSON.stringify(profileEntry))
const profile = prompt('What is your name?') || 'Unknown';
const profileEntry = { points: getPoints(), wordFound: hasFoundTheWord() };
window.localStorage.setItem(profile, JSON.stringify(profileEntry));

if (confirm(`${(hasFoundIt ? "You won!" : "You lost.")} Press ok to restart.`)) {
window.location = "/";
}
return;
if (
confirm(`${hasFoundIt ? 'You won!' : 'You lost.'} Press ok to restart.`)
) {
window.location = '/';
}
return;
}

window.requestAnimationFrame(main);

window.requestAnimationFrame(main);

const secondsSinceLastRender = (currentTime - lastRenderTime) / 1000;
if (secondsSinceLastRender < 1/getSpeed()) return;
const secondsSinceLastRender = (currentTime - lastRenderTime) / 1000;
if (secondsSinceLastRender < 1 / getSpeed()) return;

lastRenderTime = currentTime;
update();
draw();
lastRenderTime = currentTime;
update();
draw();
}

window.requestAnimationFrame(main);

function update() {
updateSnake();
updateFood();
checkDeath();
updateSnake();
updateFood();
checkDeath();
}

function draw() {
gameboard.innerHTML = "";
pointsboard.innerHTML = "";
hangmanboard.innerHTML = "";
lettersboard.innerHTML = "";
leaderboard.innerHTML = "";
gameboard.innerHTML = '';
pointsboard.innerHTML = '';
hangmanboard.innerHTML = '';
lettersboard.innerHTML = '';
leaderboard.innerHTML = '';

drawSnake(gameboard);
drawFood(gameboard);
drawPoints(pointsboard);
drawHangman(hangmanboard, lettersboard, leaderboard);
drawSnake(gameboard);
drawFood(gameboard);
drawPoints(pointsboard);
drawHangman(hangmanboard, lettersboard, leaderboard);
}

function checkDeath() {
gameOver = outsideGrid(getSnakeHead())
|| snakeIntersection();
gameOver = outsideGrid(getSnakeHead()) || snakeIntersection();
}
16 changes: 10 additions & 6 deletions grid.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
const GRID_SIZE = 25;

export function getRandomGridPosition() {
return {
x: Math.floor(Math.random() * GRID_SIZE) + 1,
y: Math.floor(Math.random() * GRID_SIZE) + 1
}
return {
x: Math.floor(Math.random() * GRID_SIZE) + 1,
y: Math.floor(Math.random() * GRID_SIZE) + 1,
};
}

export function outsideGrid(position) {
return position.x < 1 || position.x > GRID_SIZE
|| position.y < 1 || position.y > GRID_SIZE;
return (
position.x < 1 ||
position.x > GRID_SIZE ||
position.y < 1 ||
position.y > GRID_SIZE
);
}
74 changes: 38 additions & 36 deletions hangman.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,49 @@ const givenLetters = [];
const sentence = 'INSERT A PHRASE HERE'.split('') ?? [];

export function update(newLetter) {
if (!givenLetters.includes(newLetter)) {
givenLetters.push(newLetter);
}
return sentence.includes(newLetter);
if (!givenLetters.includes(newLetter)) {
givenLetters.push(newLetter);
}
return sentence.includes(newLetter);
}

export function draw(hangmanboard, lettersboard, leaderboard) {
sentence.forEach(l => {
const letterElement = document.createElement('span');
if (l === ' ') {
letterElement.innerText = '-';
} else if (givenLetters.includes(l)) {
letterElement.innerText = l;
} else {
letterElement.innerText = '_';
}
letterElement.innerText += ' ';
letterElement.classList.add('letter');
hangmanboard.appendChild(letterElement);
});
sentence.forEach((l) => {
const letterElement = document.createElement('span');
if (l === ' ') {
letterElement.innerText = '-';
} else if (givenLetters.includes(l)) {
letterElement.innerText = l;
} else {
letterElement.innerText = '_';
}
letterElement.innerText += ' ';
letterElement.classList.add('letter');
hangmanboard.appendChild(letterElement);
});

givenLetters.forEach(l => {
if (!sentence.includes(l)) {
lettersboard.innerText += `${l} `;
}
});
givenLetters.forEach((l) => {
if (!sentence.includes(l)) {
lettersboard.innerText += l;
}
});

const allProfiles = Object.keys(localStorage);
const allEntries = allProfiles
.map(profile => {
let entry = JSON.parse(localStorage.getItem(profile));
return { profile, ...entry };
})
.sort((current, previous) => previous.points - current.points);
allEntries.forEach(entry => {
const leaderboardElement = document.createElement("li");
leaderboardElement.innerHTML = `<h1>${entry.profile || "Unknown"} - ${entry.points} (found: ${entry.hasFoundTheWord ? 'yes' : 'no'})</h1>`;
leaderboard.appendChild(leaderboardElement);
});
const allProfiles = Object.keys(localStorage);
const allEntries = allProfiles
.map((profile) => {
let entry = JSON.parse(localStorage.getItem(profile));
return { profile, ...entry };
})
.sort((current, previous) => previous.points - current.points);
allEntries.forEach((entry) => {
const leaderboardElement = document.createElement('li');
leaderboardElement.innerHTML = `<h1>${entry.profile || 'Unknown'} ${entry.points} (found: ${entry.wordFound ? 'yes' : 'no'})</h1>`;
leaderboard.appendChild(leaderboardElement);
});
}

export function hasFoundTheWord() {
return sentence.filter(l => l !== ' ').every(l => givenLetters.includes(l));
}
return sentence
.filter((l) => l !== ' ')
.every((l) => givenLetters.includes(l));
}
Loading

0 comments on commit d23a447

Please sign in to comment.