@@ -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 ( / \b s n a k e - s n a k e b o d y - a l i v e \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 ( / \b s n a k e - s n a k e b o d y - a l i v e \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