Created
November 24, 2017 12:47
-
-
Save jozsefs/fa1bca24475d5b8735f0c53baa01867f to your computer and use it in GitHub Desktop.
multi-minesweeper-server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// server.js | |
const io = require('socket.io')(1234); | |
const Board = require('./board'); | |
const game = new Board({size: 15, mineChance: 0.3}); | |
const PLAYER_PREFIX = 'p-'; | |
const players = {}; | |
const cellsToReveal = []; | |
let counter = 0; | |
io.on('connection', socket => { | |
const {id} = socket; | |
const name = PLAYER_PREFIX + (++counter); | |
const player = { | |
id, | |
name, | |
score: 0, | |
hasChosen: false | |
}; | |
players[id] = player; | |
socket.on('disconnect', reason => { | |
delete players[id]; | |
}); | |
socket.on('choose-cell', pos => { | |
chooseCell(socket, id, pos); | |
}); | |
socket.on('restart', code => { | |
if (code === 'supersecret') { | |
reset(); | |
} | |
}); | |
socket.emit('new-player', {player}); | |
}); | |
function reset() { | |
Object.values(players).forEach(player => { | |
player.hasChosen = false; | |
player.score = 0; | |
}) | |
} | |
function chooseCell(socket, socketId, pos) { | |
//console.log('choose 1', socketId, pos); | |
if (!players[socketId].hasChosen) { | |
const success = game.chooseCell(pos); | |
//console.log('choose 2', success); | |
if (success) { | |
players[socketId].hasChosen = true; | |
cellsToReveal.push({pos, socketId}); | |
} | |
} | |
io.sockets.emit('cell-chosen', {pos, socketId}); | |
} | |
function getRevealedBoard() { | |
return game.getBoard().map(row => | |
row.map(cell => | |
cell.isRevealed ? cell.value : null | |
) | |
) | |
} | |
function loop() { | |
//console.log(JSON.stringify([cellsToReveal, players], null, 2)); | |
while (cellsToReveal.length) { | |
const {pos, socketId} = cellsToReveal.shift(); | |
const {value, isMine} = game.revealCell(pos); | |
players[socketId].score += isMine ? value : 1; | |
players[socketId].hasChosen = false; | |
} | |
io.sockets.emit('board', getRevealedBoard()); | |
io.sockets.emit('players', players); | |
} | |
setInterval(loop, 1000); | |
// board.js | |
// BOARD | |
const MINE = 'X'; | |
const pos = [ | |
// above | |
[-1, -1], | |
[ 0, -1], | |
[ 1, -1], | |
// same level | |
[-1, 0], | |
[ 1, 0], | |
// below | |
[-1, 1], | |
[ 0, 1], | |
[ 1, 1], | |
]; | |
class Board { | |
constructor({size, mineChance}) { | |
this.rows = size; | |
this.cols = size; | |
this.mineChance = mineChance; | |
this.isStarted = false; | |
this.gameArea = []; | |
this.createGameArea(); | |
} | |
createGameArea() { | |
let gameArea = []; | |
for (let i = 0; i < this.rows; i++) { | |
gameArea.push([]); | |
const row = gameArea[i]; | |
for (let j = 0; j < this.cols; j++) { | |
const isMine = Math.random() > (1 - this.mineChance); | |
const value = isMine ? -10 : 0; | |
row.push({value, isMine, isRevealed: false, isLocked: false}) | |
} | |
} | |
this.gameArea = this.setNumberAmounts(gameArea); | |
} | |
getBoard() { | |
return this.gameArea; | |
} | |
setNumberAmounts(gameArea) { | |
const newTable = gameArea.slice(); | |
for (let i = 0; i < this.rows; i++) { | |
const row = newTable[i]; | |
for (let j = 0; j < this.cols; j++) { | |
const cell = row[j]; | |
if (!cell.isMine) { | |
const amount = this.calcMinesAround(newTable, i, j); | |
row[j].value = amount; | |
} | |
} | |
} | |
return newTable; | |
} | |
calcMinesAround(gameArea, x, y) { | |
let sum = 0; | |
for (let i = 0; i < pos.length; i++) { | |
const row = gameArea[x + pos[i][0]]; | |
if (row) { | |
const cell = row[y + pos[i][1]]; | |
if (cell && cell.isMine) { | |
sum++; | |
} | |
} | |
} | |
return sum; | |
} | |
chooseCell({x, y}) { | |
const cell = this.gameArea[x][y]; | |
if (cell.isRevealed || cell.isLocked) { | |
return false; | |
} | |
cell.isLocked = true; | |
return true; | |
} | |
revealCell({x, y}) { | |
const cell = this.gameArea[x][y]; | |
const {value, isMine} = cell; | |
cell.isRevealed = true; | |
return {value, isMine}; | |
} | |
} | |
module.exports = Board; | |
// Dockerfile | |
FROM node:carbon | |
# Create app directory | |
WORKDIR /usr/src/app | |
# Install app dependencies | |
# A wildcard is used to ensure both package.json AND package-lock.json are copied | |
# where available (npm@5+) | |
COPY package*.json ./ | |
RUN npm install --only=production | |
# Bundle app source | |
COPY . . | |
EXPOSE 1234 | |
CMD [ "node", "app" ] | |
// running it | |
// docker build -t js/rn-minesweeper-server . | |
// docker run -p 9999:1234 -d js/rn-minesweeper-server |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment