From a7a26a983729c6f8d8a765b3a612f793e547dad9 Mon Sep 17 00:00:00 2001 From: Ben Burlingham Date: Sat, 11 Jul 2020 14:26:52 -0700 Subject: [PATCH] Win stack replay loop. --- README.txt | 4 +--- client/controls.js | 21 ++++++++++----------- client/grid.js | 43 +++++++++++++++++++++++++++++++++++++++++++ index.html | 2 -- server/ricochet.js | 22 ++++++++++++++++++++-- style/controls.css | 3 ++- style/grid.css | 4 +++- 7 files changed, 79 insertions(+), 20 deletions(-) diff --git a/README.txt b/README.txt index 5c555eb..1f12615 100644 --- a/README.txt +++ b/README.txt @@ -13,11 +13,9 @@ A victory state can be stored by taking a snapshot of the current stack. Icons from [https://game-icons.net](https://game-icons.net) ## TODO -- replay stack - chat box - walls and winstate algorithm -- shuffle colors (easy) -- tutorial (easy) +- tutorial # Final install - move websocket server to /core diff --git a/client/controls.js b/client/controls.js index ff8857e..904b20a 100644 --- a/client/controls.js +++ b/client/controls.js @@ -12,6 +12,7 @@ const Controls = function() { document.addEventListener('L-complete', this.msgComplete.bind(this)); document.addEventListener('L-join', this.msgJoin.bind(this)); document.addEventListener('L-newround', this.msgNewRound.bind(this)); + document.addEventListener('L-replay-complete', this.msgReplayComplete.bind(this)); document.addEventListener('L-skip', this.msgSkip.bind(this)); document.addEventListener('L-stack', this.msgStack.bind(this)); @@ -32,8 +33,6 @@ const Controls = function() { document.getElementById('controls-options-walls').addEventListener('click', this.onClickOptionsWalls.bind(this)); document.getElementById('controls-countdown-skip').addEventListener('click', this.onClickCountdownSkip.bind(this)); - - document.getElementById('controls-win-replay').addEventListener('click', this.onClickWinReplay.bind(this)); document.getElementById('controls-win-next').addEventListener('click', this.onClickWinNext.bind(this)); this.setState('CONNECTING'); @@ -189,12 +188,18 @@ Controls.prototype.msgState = function(evt) { }; Controls.prototype.msgWin = function(evt) { - document.getElementById('controls-win-message').innerHTML = `Congratulations ${this.names[evt.detail.body.id]} !`; + document.getElementById('controls-win-message').innerHTML = `Congratulations ${this.names[evt.detail.player_id]} !`; document.getElementById('controls-win-count').innerHTML = evt.detail.body.moveCount; }; Controls.prototype.msgNewRound = function() { - this.winningMoveCount = Infinite; + this.winningMoveCount = Infinity; + document.getElementById('controls-win-next').style.display = 'none'; + // SHOW ARROWS IN GRID +}; + +Controls.prototype.msgReplayComplete = function() { + document.getElementById('controls-win-next').style.display = 'block'; }; //===== Click handlers @@ -232,18 +237,12 @@ Controls.prototype.onClickMovesUndo = function() { this.dispatch('L-undo'); }; -// Countdown block +// Countdown/win block Controls.prototype.onClickCountdownSkip = function() { this.dispatch('L-skip'); }; -// Win block -Controls.prototype.onClickWinReplay = function() { - // this.dispatch('L-skip'); - alert('win replay') -} - Controls.prototype.onClickWinNext = function() { this.dispatch('L-newround'); }; \ No newline at end of file diff --git a/client/grid.js b/client/grid.js index 42c0c4e..90d1f7a 100644 --- a/client/grid.js +++ b/client/grid.js @@ -8,16 +8,19 @@ const Grid = function() { this.shadows = []; this.walls = []; this.objective = {}; + this.timers = {}; this.squaresPerSide = 20; this.squareSideLength = 0; + document.addEventListener('L-newround', this.msgNewRound.bind(this)); document.addEventListener('L-stack', this.msgStack.bind(this)); document.addEventListener('L-shadows', this.msgShadows.bind(this)); document.addEventListener('G-robots', this.msgRobots.bind(this)); document.addEventListener('G-walls', this.msgWalls.bind(this)); document.addEventListener('G-objective', this.msgObjective.bind(this)); + document.addEventListener('G-win', this.msgWin.bind(this)); window.addEventListener('resize', this.debounce(this.onResize.bind(this), 500)); @@ -336,6 +339,37 @@ Grid.prototype.checkObjective = function({ id, i, j }) { document.dispatchEvent(evtSolve); }; +Grid.prototype.replayStack = function(stack) { + // All to initial positions + for (let i = 0; i < this.robots.length; i++) { + this.replayMove(stack[i]); + document.getElementById(`arrows-${stack[i].id}`).style.display = 'none'; + } + + function replayRemaining(remainingStack) { + if (remainingStack.length > 0) { + this.replayMove(remainingStack[0]); + this.timers.replay = setTimeout(replayRemaining.bind(this, remainingStack.slice(1)), 750); + } + else { + const evtSolve = new Event('L-replay-complete'); + document.dispatchEvent(evtSolve); + + this.timers.replay = setTimeout(this.replayStack.bind(this, stack), 750); + } + } + + this.timers.replay = setTimeout(replayRemaining.bind(this, stack.slice(this.robots.length)), 750) +}; + +Grid.prototype.replayMove = function({ id, i, j }) { + const robot = document.getElementById(`robot-${id}`); + const s = this.squareSideLength; + + robot.style.left = `${i * s}px`; + robot.style.top = `${j * s}px`; +}; + //===== DOM event handlers Grid.prototype.onArrowClick = function(evt) { @@ -398,6 +432,11 @@ Grid.prototype.debounce = function(fn, ms) { //===== Message handlers +Grid.prototype.msgNewRound = function() { + this.robots.forEach(({ id }) => document.getElementById(`arrows-${id}`).style.display = 'block'); + clearTimeout(this.timers.replay); +}; + Grid.prototype.msgRobots = function(evt) { // Do not assign position or redraw here: movements are fully managed using the stack. this.colors = {}; @@ -442,3 +481,7 @@ Grid.prototype.msgObjective = function(evt) { this.objective = evt.detail.body; this.drawObjective(); }; + +Grid.prototype.msgWin = function(evt) { + this.replayStack(evt.detail.body.stack) +}; diff --git a/index.html b/index.html index 09da5ef..25cf5f8 100644 --- a/index.html +++ b/index.html @@ -63,8 +63,6 @@
-
Replay
-
Start next round
diff --git a/server/ricochet.js b/server/ricochet.js index d123b05..48220c3 100644 --- a/server/ricochet.js +++ b/server/ricochet.js @@ -33,8 +33,9 @@ const Ricochet = function({ messenger }) { // Reference lookups this.robotIds = Array.from(Array(5).keys()).map(_ => uuid.v4()); + const shuffledColors = this.shuffle(COLORS); this.colors = this.robotIds.reduce((acc, id, i) => { - acc[id] = COLORS[i]; + acc[id] = shuffledColors[i]; return acc; }, {}); @@ -360,6 +361,23 @@ Ricochet.prototype.sanitizeId = function(id) { return id.replace(/[^0-9a-zA-Z\-]/g, ''); }; +Ricochet.prototype.shuffle = function(arr) { + const result = []; + let CONTROL_COUNTER = 0; + + while (arr.length && CONTROL_COUNTER < 50) { + const x = Math.floor(Math.random() * arr.length); + result.push(arr[x]); + arr.splice(x, 1); + } + + if (CONTROL_COUNTER > 39) { + console.log(`==================\n\nCRITICAL ERROR!\n\shuffle()() while() short-circuited!\n\n==================`); + } + + return result; +}; + Ricochet.prototype.onCountdownComplete = function() { clearTimeout(this.countdownTimer); @@ -382,7 +400,7 @@ Ricochet.prototype.getCountdownStateBody = function() { Ricochet.prototype.getWinStateBody = function() { return { moveCount: this.winningStack.length - this.robots.length, - id: this.winningPlayerId, + player_id: this.winningPlayerId, stack: this.winningStack }; }; diff --git a/style/controls.css b/style/controls.css index aeba7e2..9c13aaa 100644 --- a/style/controls.css +++ b/style/controls.css @@ -175,7 +175,8 @@ margin-top: -12px; } -#controls-win-replay { +#controls-win-next { + display: none; } /*===== FOOTER BLOCK =====*/ diff --git a/style/grid.css b/style/grid.css index 275d46c..805e6b5 100644 --- a/style/grid.css +++ b/style/grid.css @@ -25,6 +25,7 @@ height: 8px; margin-top: -4px; position: absolute; + z-index: 3; } .content-wall-y { @@ -32,6 +33,7 @@ margin-left: -4px; position: absolute; width: 8px; + z-index: 3; } .content-robot { @@ -57,7 +59,7 @@ .content-arrows { position: absolute; transition: left 0.4s cubic-bezier(0,1,.5,1), top 0.4s cubic-bezier(0,1,.5,1); - z-index: 5; + z-index: 4; } .content-arrow {