Skip to content

Commit 2e9ca02

Browse files
committed
Add win condition and fix invalid food placement
1 parent bfc9ef4 commit 2e9ca02

File tree

5 files changed

+106
-34
lines changed

5 files changed

+106
-34
lines changed

css/dark-snake.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ a.snake-link:hover {
122122
display: block;
123123
}
124124

125-
.snake-try-again-dialog {
125+
.snake-try-again-dialog, .snake-win-dialog {
126126
padding: 8px;
127127
margin: 0px;
128128
background-color: black;
@@ -138,4 +138,4 @@ a.snake-link:hover {
138138
margin-left: -158px;
139139
text-align: center;
140140
display: none;
141-
}
141+
}

css/green-snake.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ a.snake-link:hover {
124124
display: block;
125125
}
126126

127-
.snake-try-again-dialog {
127+
.snake-try-again-dialog, .snake-win-dialog {
128128
padding: 8px;
129129
margin: 0px;
130130
background-color: #000000;
@@ -140,4 +140,4 @@ a.snake-link:hover {
140140
margin-left: -158px;
141141
text-align: center;
142142
display: none;
143-
}
143+
}

css/light-snake.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ a.snake-link:hover {
107107
text-align: center;
108108
display: block;
109109
}
110-
.snake-try-again-dialog {
110+
.snake-try-again-dialog, .snake-win-dialog {
111111
padding: 8px;
112112
margin: 0px;
113113
background-color: #000000;

css/main-snake.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ a.snake-link:hover {
119119
display: block;
120120
}
121121

122-
.snake-try-again-dialog {
122+
.snake-try-again-dialog, .snake-win-dialog {
123123
padding: 8px;
124124
margin: 0px;
125125
background-color: #000000;
@@ -135,4 +135,4 @@ a.snake-link:hover {
135135
margin-left: -158px;
136136
text-align: center;
137137
display: none;
138-
}
138+
}

js/snake.js

Lines changed: 99 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,24 @@ SNAKE.Snake = SNAKE.Snake || (function() {
208208
blockPool[blockPool.length] = tempBlock;
209209
}
210210

211+
function recordScore() {
212+
var highScore = localStorage.jsSnakeHighScore;
213+
if (me.snakeLength > highScore) {
214+
alert('Congratulations! You have beaten your previous high score, which was ' + highScore + '.');
215+
localStorage.setItem('jsSnakeHighScore', me.snakeLength);
216+
}
217+
}
218+
219+
function handleEndCondition(handleFunc) {
220+
recordScore();
221+
me.snakeHead.elm.style.zIndex = getNextHighestZIndex(me.snakeBody);
222+
me.snakeHead.elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-alive\b/, '')
223+
me.snakeHead.elm.className += " snake-snakebody-dead";
224+
225+
isDead = true;
226+
handleFunc();
227+
}
228+
211229
// ----- public methods -----
212230

213231
me.setPaused = function(val) {
@@ -323,7 +341,10 @@ SNAKE.Snake = SNAKE.Snake || (function() {
323341
me.handleDeath();
324342
} else if (grid[newHead.row][newHead.col] === playingBoard.getGridFoodValue()) {
325343
grid[newHead.row][newHead.col] = 1;
326-
me.eatFood();
344+
if (!me.eatFood()) {
345+
me.handleWin();
346+
return;
347+
}
327348
setTimeout(function(){me.go();}, snakeSpeed);
328349
}
329350
};
@@ -354,28 +375,27 @@ SNAKE.Snake = SNAKE.Snake || (function() {
354375
me.snakeTail.next = me.snakeHead;
355376
me.snakeHead.prev = me.snakeTail;
356377

357-
playingBoard.foodEaten();
378+
if (!playingBoard.foodEaten()) {
379+
return false;
380+
}
381+
382+
return true;
358383
};
359384

360385
/**
361386
* This method handles what happens when the snake dies.
362387
* @method handleDeath
363388
*/
364389
me.handleDeath = function() {
365-
function recordScore () {
366-
var highScore = localStorage.jsSnakeHighScore;
367-
if (me.snakeLength > highScore) {
368-
alert('Congratulations! You have beaten your previous high score, which was ' + highScore + '.');
369-
localStorage.setItem('jsSnakeHighScore', me.snakeLength);
370-
}
371-
}
372-
recordScore();
373-
me.snakeHead.elm.style.zIndex = getNextHighestZIndex(me.snakeBody);
374-
me.snakeHead.elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-alive\b/,'')
375-
me.snakeHead.elm.className += " snake-snakebody-dead";
390+
handleEndCondition(playingBoard.handleDeath);
391+
};
376392

377-
isDead = true;
378-
playingBoard.handleDeath();
393+
/**
394+
* This method handles what happens when the snake wins.
395+
* @method handleDeath
396+
*/
397+
me.handleWin = function() {
398+
handleEndCondition(playingBoard.handleWin);
379399
};
380400

381401
/**
@@ -506,6 +526,7 @@ SNAKE.Food = SNAKE.Food || (function() {
506526
/**
507527
* Randomly places the food onto an available location on the playing board.
508528
* @method randomlyPlaceFood
529+
* @return {bool} Whether a food was able to spawn (true) or not (false).
509530
*/
510531
me.randomlyPlaceFood = function() {
511532
// if there exist some food, clear its presence from the board
@@ -523,12 +544,11 @@ SNAKE.Food = SNAKE.Food || (function() {
523544
col = getRandomPosition(1, maxCols);
524545

525546
// in some cases there may not be any room to put food anywhere
526-
// instead of freezing, exit out
547+
// instead of freezing, exit out (and return false to indicate
548+
// that the player beat the game)
527549
numTries++;
528550
if (numTries > 20000){
529-
row = -1;
530-
col = -1;
531-
break;
551+
return false;
532552
}
533553
}
534554

@@ -537,6 +557,7 @@ SNAKE.Food = SNAKE.Food || (function() {
537557
fColumn = col;
538558
elmFood.style.top = row * playingBoard.getBlockHeight() + "px";
539559
elmFood.style.left = col * playingBoard.getBlockWidth() + "px";
560+
return true;
540561
};
541562
};
542563
})();
@@ -625,7 +646,7 @@ SNAKE.Board = SNAKE.Board || (function() {
625646
myKeyListener,
626647
isPaused = false,//note: both the board and the snake can be paused
627648
// Board components
628-
elmContainer, elmPlayingField, elmAboutPanel, elmLengthPanel, elmHighscorePanel, elmWelcome, elmTryAgain, elmPauseScreen;
649+
elmContainer, elmPlayingField, elmAboutPanel, elmLengthPanel, elmHighscorePanel, elmWelcome, elmTryAgain, elmWin, elmPauseScreen;
629650

630651
// --- public variables ---
631652
me.grid = [];
@@ -661,6 +682,7 @@ SNAKE.Board = SNAKE.Board || (function() {
661682

662683
elmWelcome = createWelcomeElement();
663684
elmTryAgain = createTryAgainElement();
685+
elmWin = createWinElement();
664686

665687
SNAKE.addEventListener( elmContainer, "keyup", function(evt) {
666688
if (!evt) var evt = window.event;
@@ -680,6 +702,7 @@ SNAKE.Board = SNAKE.Board || (function() {
680702
elmContainer.appendChild(elmHighscorePanel);
681703
elmContainer.appendChild(elmWelcome);
682704
elmContainer.appendChild(elmTryAgain);
705+
elmContainer.appendChild(elmWin);
683706

684707
mySnake = new SNAKE.Snake({playingBoard:me,startRow:2,startCol:2});
685708
myFood = new SNAKE.Food({playingBoard: me});
@@ -760,6 +783,49 @@ SNAKE.Board = SNAKE.Board || (function() {
760783
tmpElm.appendChild(tryAgainStart);
761784
return tmpElm;
762785
}
786+
787+
function createWinElement() {
788+
var tmpElm = document.createElement("div");
789+
tmpElm.id = "sbWin" + myId;
790+
tmpElm.className = "snake-win-dialog";
791+
792+
var winTxt = document.createElement("div");
793+
winTxt.innerHTML = "JavaScript Snake<p></p>You win! :D<p></p>";
794+
var winStart = document.createElement("button");
795+
winStart.appendChild(document.createTextNode("Play Again?"));
796+
797+
var reloadGame = function () {
798+
tmpElm.style.display = "none";
799+
me.resetBoard();
800+
me.setBoardState(1);
801+
me.getBoardContainer().focus();
802+
};
803+
804+
var kbWinShortcut = function (evt) {
805+
if (boardState !== 0 || tmpElm.style.display !== "block") { return; }
806+
if (!evt) var evt = window.event;
807+
var keyNum = (evt.which) ? evt.which : evt.keyCode;
808+
if (keyNum === 32 || keyNum === 13) {
809+
reloadGame();
810+
}
811+
};
812+
SNAKE.addEventListener(window, "keyup", kbWinShortcut, true);
813+
814+
SNAKE.addEventListener(winStart, "click", reloadGame, false);
815+
tmpElm.appendChild(winTxt);
816+
tmpElm.appendChild(winStart);
817+
return tmpElm;
818+
}
819+
820+
function handleEndCondition(elmDialog) {
821+
var index = Math.max(getNextHighestZIndex(mySnake.snakeBody), getNextHighestZIndex({ tmp: { elm: myFood.getFoodElement() } }));
822+
elmContainer.removeChild(elmDialog);
823+
elmContainer.appendChild(elmDialog);
824+
elmDialog.style.zIndex = index;
825+
elmDialog.style.display = "block";
826+
me.setBoardState(0);
827+
}
828+
763829
// ---------------------------------------------------------------------
764830
// public functions
765831
// ---------------------------------------------------------------------
@@ -986,20 +1052,26 @@ SNAKE.Board = SNAKE.Board || (function() {
9861052
localStorage.setItem("jsSnakeHighScore", mySnake.snakeLength);
9871053
elmHighscorePanel.innerHTML = "Highscore: " + localStorage.jsSnakeHighScore;
9881054
}
989-
myFood.randomlyPlaceFood();
1055+
if (!myFood.randomlyPlaceFood()) {
1056+
return false;
1057+
}
1058+
return true;
9901059
};
9911060

9921061
/**
9931062
* This method is called when the snake dies.
9941063
* @method handleDeath
9951064
*/
9961065
me.handleDeath = function() {
997-
var index = Math.max(getNextHighestZIndex( mySnake.snakeBody), getNextHighestZIndex( {tmp:{elm:myFood.getFoodElement()}} ));
998-
elmContainer.removeChild(elmTryAgain);
999-
elmContainer.appendChild(elmTryAgain);
1000-
elmTryAgain.style.zIndex = index;
1001-
elmTryAgain.style.display = "block";
1002-
me.setBoardState(0);
1066+
handleEndCondition(elmTryAgain);
1067+
};
1068+
1069+
/**
1070+
* This method is called when the snake wins.
1071+
* @method handleWin
1072+
*/
1073+
me.handleWin = function () {
1074+
handleEndCondition(elmWin);
10031075
};
10041076

10051077
// ---------------------------------------------------------------------

0 commit comments

Comments
 (0)