Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| 'use strict'; | |
| module.exports = class SnakeActions { | |
| constructor() { | |
| // Game state object contains players, coordinates of food and shields as attributes. | |
| this.gameState = { | |
| players: [], | |
| leaders: [], | |
| foodCoords: [], | |
| shieldCoords: [], | |
| } | |
| // gridSize | |
| this.gridSize = 100; | |
| // When a player picks up a shield, they will be immune for 133 state changes. | |
| // This is about 10 seconds. This can be stacked with multiple shields. | |
| this.immuneTime = 133; | |
| } | |
| addItems() { | |
| // There must be at least 70 pieces of food in play at a time | |
| var foods = this.gameState.foodCoords; | |
| var neededFood = 0, required = 70; | |
| // There must be at least 1 shield in play at a time | |
| var shields = this.gameState.shieldCoords; | |
| var neededShields = 0, requiredShields = 1; | |
| if (foods.length < required) { | |
| neededFood = (required - foods.length); | |
| } | |
| if (shields.length < requiredShields) { | |
| neededShields = (requiredShields - shields.length); | |
| } | |
| for (var f = 0; f < neededFood; f++) { | |
| var type = this.genRandomFoodType(); | |
| var coords = this.genRandomCoords(); | |
| this.gameState.foodCoords.push({ | |
| foodType: type, | |
| coords: coords | |
| }); | |
| } | |
| for (var s = 0; s < neededShields; s++) { | |
| var coords = this.genRandomCoords(); | |
| this.gameState.shieldCoords.push({ | |
| coords: coords | |
| }); | |
| } | |
| } | |
| addPlayer(nick, id) { | |
| var coords = this.genRandomCoords(); | |
| this.gameState.players.push({ | |
| id: id, | |
| nick: nick, | |
| blocks: [coords], | |
| score: 1, | |
| immunity: 0, | |
| direction: false, | |
| color: this.genRandomColor() | |
| }); | |
| } | |
| calcLeaders() { | |
| // Get array of objects with players' lengths and id | |
| var players = this.gameState.players.map(p => { | |
| return { | |
| nick: p.nick, | |
| score: p.score, | |
| color: p.color | |
| }; | |
| }); | |
| // Sort the player objects by score | |
| var leaders = players.sort((c, p) => { | |
| return c.score - p.score; | |
| }).reverse(); | |
| // We would only like at most, 5 leaders at a time. | |
| var sliceIndex = leaders.length >= 5 ? 5 : leaders.length; | |
| this.gameState.leaders = leaders.slice(0, sliceIndex); | |
| } | |
| removePlayer(deathObj) { | |
| var players = this.gameState.players; | |
| var deadPlayer = players.filter(p => p.id === deathObj.id)[0]; | |
| this.gameState.players = players.filter(p => p.id !== deathObj.id); | |
| // If the player was killed, add food in their wake | |
| if (deathObj.kill) { | |
| // For every fourth block, add food at that coordinate | |
| for (var b = 1; b < deadPlayer.blocks.length; b += 4) { | |
| var block = deadPlayer.blocks[b]; | |
| var type = this.genRandomFoodType(); | |
| this.gameState.foodCoords.push({ | |
| foodType: type, | |
| coords: [block[0], block[1]], | |
| }); | |
| } | |
| } | |
| } | |
| genRandomCoords() { | |
| var x, y; | |
| var noConflict = false; | |
| const randCoord = () => { | |
| return Math.floor(Math.random() * (this.gridSize - 1)); | |
| }; | |
| while (!noConflict) { | |
| var conflicts = 0; | |
| x = randCoord(); | |
| y = randCoord(); | |
| // Make sure coordinates don't conflict with items or another player | |
| var players = this.gameState.players; | |
| var foodCoords = this.gameState.foodCoords; | |
| var shieldCoords = this.gameState.shieldCoords; | |
| for (var f = 0; f < foodCoords.length; f++) { | |
| var coords = foodCoords[f].coords; | |
| if (x === coords[0] && y === coords[1]) { | |
| conflicts++; | |
| } | |
| } | |
| for (var s = 0; s < shieldCoords.length; s++) { | |
| var coords = shieldCoords[s].coords; | |
| if (x === coords[0] && y === coords[1]) { | |
| conflicts++; | |
| } | |
| } | |
| for (var p = 0; p < players.length; p++) { | |
| for (var b = 0; b < players[p].blocks.length; b++) { | |
| var block = players[p].blocks[b]; | |
| if (x === block[0] && y === block[1]) { | |
| conflicts++; | |
| } | |
| } | |
| } | |
| if (conflicts === 0) { | |
| noConflict = true; | |
| } | |
| } | |
| return [x, y]; | |
| } | |
| genRandomFoodType() { | |
| var type, choice = Math.floor(Math.random() * 3); | |
| switch (choice) { | |
| case 0: | |
| type = 'burger'; | |
| break; | |
| case 1: | |
| type = 'sushi'; | |
| break; | |
| case 2: | |
| type = 'cake'; | |
| break; | |
| } | |
| return type; | |
| } | |
| genRandomColor() { | |
| var chars = 'ABCDEF0123456789'; | |
| var unique = false; | |
| var hex; | |
| while (!unique) { | |
| hex = '#'; | |
| for (var c = 0; c < 6; c++) { | |
| hex += chars[Math.floor(Math.random() * chars.length)]; | |
| } | |
| // Check if color already exists among players | |
| var colorPlayer = this.gameState.players.filter(p => p.color === hex); | |
| if (colorPlayer.length === 0) { | |
| unique = true | |
| } | |
| } | |
| return hex; | |
| } | |
| updatePlayerDirection(id, action) { | |
| var players = this.gameState.players; | |
| this.gameState.players = players.map(p => { | |
| if (p.id == id) { | |
| p.direction = action; | |
| } | |
| return p; | |
| }); | |
| } | |
| updatePositions() { | |
| this.gameState.players.map(p => { | |
| switch (p.direction) { | |
| case 'UP': | |
| p.blocks[0][1] -= 1; | |
| break; | |
| case 'DOWN': | |
| p.blocks[0][1] += 1; | |
| break; | |
| case 'LEFT': | |
| p.blocks[0][0] -= 1; | |
| break; | |
| case 'RIGHT': | |
| p.blocks[0][0] += 1; | |
| break; | |
| } | |
| return p; | |
| }); | |
| this.checkCollision(); | |
| this.checkConsumption(); | |
| this.addItems(); | |
| this.calcLeaders(); | |
| } | |
| checkCollision() { | |
| var casualties = []; | |
| this.gameState.players.map(p => { | |
| var x = p.blocks[0][0]; | |
| var y = p.blocks[0][1]; | |
| var players = this.gameState.players; | |
| var bounds = (this.gridSize - 1); | |
| // Check if the player has hit a wall | |
| if ((x > bounds || x < 0) || | |
| y > bounds || y < 0) { | |
| casualties.push({ | |
| id: p.id, | |
| kill: true, | |
| }); | |
| return p; | |
| } | |
| // Check if a player has collided with themselves | |
| if (p.immunity === 0) { | |
| for (var b = 1; b < p.blocks.length; b++) { | |
| if (x === p.blocks[b][0] && y === p.blocks[b][1]) { | |
| casualties.push({ | |
| id: p.id, | |
| kill: true | |
| }); | |
| return p; | |
| } | |
| } | |
| } | |
| // Check if a player has collided with another player | |
| if (p.immunity === 0) { | |
| for (var l = 0; l < players.length; l++) { | |
| if (players[l].id !== p.id) { | |
| for (var o = 0; o < players[l].blocks.length; o++) { | |
| if (x === players[l].blocks[o][0] && y === players[l].blocks[o][1]) { | |
| // Add 10 to the other players score | |
| players[l].score += 10; | |
| // Push the colliding player to the casualties list | |
| casualties.push({ | |
| id: p.id, | |
| kill: true | |
| }); | |
| return p; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| // If player immunity is greater than 0, remove one cycle from it | |
| if (p.immunity > 0) { | |
| p.immunity--; | |
| } | |
| return p; | |
| }); | |
| casualties.map(deathObj => this.removePlayer(deathObj)); | |
| } | |
| checkConsumption() { | |
| var foodCoords = this.gameState.foodCoords; | |
| this.gameState.players.map(p => { | |
| var x = p.blocks[0][0]; | |
| var y = p.blocks[0][1]; | |
| var selfConsumed = false; | |
| var foodCoords = this.gameState.foodCoords; | |
| var shieldCoords = this.gameState.shieldCoords; | |
| // Check if the player has eaten food | |
| for (var f = 0; f < foodCoords.length; f++) { | |
| var coords = foodCoords[f].coords; | |
| if (x === coords[0] && y === coords[1]) { | |
| // Remove food from foods | |
| foodCoords.splice(f, 1); | |
| selfConsumed = true; | |
| break; | |
| } | |
| } | |
| // Check if the player has picked up a shield | |
| for (var s = 0; s < shieldCoords.length; s++) { | |
| var coords = shieldCoords[s].coords; | |
| if (x === coords[0] && y === coords[1]) { | |
| // Add immune time to player | |
| p.immunity += this.immuneTime; | |
| // Remove shield | |
| shieldCoords.splice(s, 1); | |
| } | |
| } | |
| if (selfConsumed) { | |
| // Add new block | |
| var tail = [x, y]; | |
| // If the player score is 1, push a block to the array so we have something to pop off | |
| if (p.score === 1) { | |
| p.blocks.push([p.blocks[0][0], p.blocks[0][1]]); | |
| } | |
| // Increment score | |
| p.score++; | |
| } else { | |
| var tail = p.blocks.pop(); | |
| tail[0] = x; | |
| tail[1] = y; | |
| } | |
| p.blocks.unshift(tail); | |
| return p; | |
| }); | |
| } | |
| } |