重置所有按钮从JS文字添加新实例jQuery

时间:2015-10-28 19:08:54

标签: javascript jquery

我已经在这个问题上绞尽脑汁了一段时间了: 当我点击我的tic tac toe游戏的全部重置按钮时,它没有正确重置。当我在MYAPP.firstGame函数上使用console.log时,它会添加MYAPP.game对象的其他实例。如果播放器在重置时没有首先播放,则会导致计算机播放器连续多次播放。

我已经问过其他几位程序员并且无法弄清楚发生了什么。 如果你能帮助我,我将不胜感激。

以下是指向code pen的链接。

HTML:

  <div class="outer-container">
    <button class="hard-reset">Reset All</button>
    <div class="player-one-turn">
      <p></p>
    </div>
    <div class="player-two-turn">
      <p></p>
    </div>
    <div class="board-container">
      <div class="game-starter">
        <p>Would you like to be X or O?</p>
        <button class="choose-x">X</button>
        <button class="choose-o">O</button>
        <button class="back-button"><i class="fa fa-arrow-left"></i> Back</button>
      </div>
      <div class="game-choice">
        <p>How do you want to play?</p>
        <button class="one-player">One Player</button>
        <button class="two-player">Two Player</button>
      </div>
    <div class="game-board">
      <div class="draw-message">
        <p>It was a draw..</p>
      </div>
      <div class="lose-message">
        <p>Uh oh, you lost..</p>
      </div>
      <div class="win-message">
        <p>You Won!!! :)</p>
      </div>
      <canvas id="myCanvas"></canvas>
      <ul class="boxes">
      </ul>
    </div>
  </div>
</div>

CSS:

body,
html {
  width: 100%;
  height: 100%;
}

li {
  list-style: none;
}

.outer-container {
  background: rgba(240,180,135,1);
  box-shadow: inset -1px 1px 7px rgba(0,0,0,.2), inset 1px -1px 7px rgba(0,0,0,.2), 1px 12px 5px rgba(0,0,0,.4), 4px 3px 8px rgba(0,0,0,.4), 5px 10px 10px rgba(0,0,0,.2), -5px 10px 10px rgba(0,0,0,.4);
  position: relative;
  border-radius: 10px;
  width: 540px;
  height: 540px;
  margin: 10% auto;
  padding: 30px 0;
}


.board-container {
  width: 500px;
  height: 500px;
  background: rgba(40,40,40,1)
    -webkit-radial-gradient(center, rgba(40,80,60,1), rgba(0,20,20,.6));
  background: rgba(40,40,40,1)
    -moz-radial-gradient(center, rgba(40,80,60,1), rgba(0,20,20,.6));
  background: rgba(40,40,40,1)
    -ms-radial-gradient(center, rgba(40,80,60,1), rgba(0,20,20,.6));
  background: rgba(40,40,40,1)
    radial-gradient(center, rgba(40,80,60,1), rgba(0,20,20,.6));
  background-size: cover;
  position: relative;
  top: 20px;
  left: 20px;
  overflow: hidden;
}

.game-board {
  width: 440px;
  height: 450px;
  margin: 20px auto;
  position: relative;
}

.boxes {
  padding: 0;
}

.boxes li {
  width: 33%;
  height: 150px;
  display: inline-block;
  position: relative;
  z-index: 1000;
  margin: 0;
  overflow: hidden;
}

li i {
  font-size: 7.5rem;
  text-align: center;
  display: block;
  width: 100%;
  height: 99%;
  margin-bottom: 0;
  margin-left: 5px;
  font-style: normal;
  font-family: "Architects Daughter", "Helvetica", "sans-serif";
  color: rgba(220,220,220,.7);
  z-index: 500;
}

/* Canvas Drawing */

#myCanvas {
  width: 100%;
  height: 456px;
  position: absolute;
  z-index: 0;
  left: 0;
  top: 0;
  opacity: 0;
}

/* Player/Computer prompt */
.player-one-turn {
  background: rgba(0,200,200,1);
  left: 15px;
}

.player-two-turn {
  background: rgba(200,100,100,1);
  right: 15px;
}

.player-one-turn,
.player-two-turn {
  position: absolute;
  top: 0;
  width: 200px;
  height: 50px;
  z-index: -10;
  color: white;
  text-align: center;
}

.player-one-turn p,
.player-two-turn p {
  font-size: 1.5rem;
  margin-top: 10px;
}

/* reset button */
.hard-reset {
  position: absolute;
  top: 10px;
  right: 20px;
  background: none;
  border: none;
  font-family: 'Architects Daughter', sans-serif;
  color: rgba(100,60,50,.8);
  font-size: 1.2rem;
  border-radius: 20px;
  border: 2px dashed transparent;
}

.hard-reset:hover {
  border: 2px dashed rgba(100,60,50,1);
  color: rgba(100,60,50,1);
}

.hard-reset:focus {
  outline: none;
}

/*  Result Feedback */
span.rotate {
  color: rgba(0,200,200,1);
}

i.win {
  background: black;
}

.draw-message,
.lose-message,
.win-message {
  background: rgba(0,0,0,.8);
  width: 530px;
  height: 530px;
  z-index: 2000;
  position: absolute;
  display: none;
  left: -30px;
  top: -35px;
  box-sizing: border-box;
  margin: 0;
}

.draw-message p,
.lose-message p,
.win-message p {
  color: white;
  text-align: center;
  position: relative;
  top: 230px;
  font-size: 3rem;
  margin: 0;
  font-family: 'Architects Daughter', sans-serif;
}

/*============================================
          Game Starter
============================================*/

.game-choice,
.game-starter {
  background: rgba(40,40,40,1)
    -webkit-radial-gradient(center, rgba(40,80,60,1), rgba(0,20,20,.6));
  background: rgba(40,40,40,1)
    -moz-radial-gradient(center, rgba(40,80,60,1), rgba(0,20,20,.6));
  background: rgba(40,40,40,1)
    -ms-radial-gradient(center, rgba(40,80,60,1), rgba(0,20,20,.6));
  background: rgba(40,40,40,1)
    radial-gradient(center, rgba(40,80,60,1), rgba(0,20,20,.6));

  display: block;
  width: 100%;
  height: 500px;
  position: absolute;
  top: 0px;
  text-align: center;
  font-family: 'Architects Daughter', Helvetica, sans-serif;
  z-index: 1500;
}

.game-starter {
  display: none;
}

.game-choice p,
.game-starter p {
  font-size: 2.2rem;
}

.game-choice button,
.game-choice p,
.game-starter button,
.game-starter p {
  color: rgba(220,220,220,1);
  position: relative;
  top: 100px;
  margin: 10px auto;
}

.game-choice p,
.game-starter p {
  max-width: 60%;
}

.game-choice button,
.game-starter button {
  background: none;
  border: none;
  opacity: .6;
  border-radius: 20px;
  border: 2px solid transparent;
}

.game-choice button {
  font-size: 2rem;
}

.game-starter button {
   font-size: 2.8rem;
}

.game-choice button:focus,
.game-starter button:focus {
  outline: none;
}
.game-choice button:hover,
.game-starter button:hover {
  opacity: 1;
  border: 2px dashed rgba(230,230,230,.5);
}

.game-starter button.back-button  {
  position: absolute;
  top: 400px;
  right: 200px;
  font-size: 1.5rem;
  border: none;
}

.game-starter .back-button:hover {
  border: none;
}


/*============================
    Win/Lose animation 
==============================*/

@-webkit-keyframes rotating /* Safari and Chrome */ {
  from {
    -ms-transform: rotateY(0deg);
    -moz-transform: rotateY(0deg);
    -webkit-transform: rotateY(0deg);
    -o-transform: rotateY(0deg);
    transform: rotateY(0deg);
  }
  to {
    -ms-transform: rotateY(360deg);
    -moz-transform: rotateY(360deg);
    -webkit-transform: rotateY(360deg);
    -o-transform: rotateY(360deg);
    transform: rotateY(360deg);
  }
}
@keyframes rotating {
  from {
    -ms-transform: rotateY(0deg);
    -moz-transform: rotateY(0deg);
    -webkit-transform: rotateY(0deg);
    -o-transform: rotateY(0deg);
    transform: rotateY(0deg);
  }
  to {
    -ms-transform: rotateY(360deg);
    -moz-transform: rotateY(360deg);
    -webkit-transform: rotateY(360deg);
    -o-transform: rotateY(360deg);
    transform: rotateY(360deg);
  }
}
.rotate {
  -webkit-animation: rotating 2s linear infinite;
  -moz-animation: rotating 2s linear infinite;
  -ms-animation: rotating 2s linear infinite;
  -o-animation: rotating 2s linear infinite;
  animation: rotating 2s linear infinite;
}

JS / jQuery:

var MYAPP = MYAPP || {};

/*=========================
      Display functions
==========================*/
MYAPP.display = {  
  hideGameStarter: function() {
  $('.game-starter').fadeOut();
},

  showGameStarter: function(isTwoPlayer) {
  var message;
  if (isTwoPlayer) {
    message = "Player 1 : Would you like X or O?"
  }
  else {
    message = "Would you like to be X or O?";
  }

    window.setTimeout(function() {
    $('.game-starter').fadeIn(500).children('p').text(message);
  }, 700);
},

  showGameChoice: function() {
  $('.game-choice').fadeIn();
},

  hideGameChoice: function() {
  $('.game-choice').fadeOut(600);
},

  showPlayerOnePrompt: function() {
    var game = MYAPP.game;
  if (game.secondPlayer) {
    $('.player-one-turn p').text('Go Player 1!');
  }
  else {
    $('.player-one-turn p').text('Your turn!');
  }
  $('.player-one-turn').animate({'top': '-45px'}, 500);
},

  hidePlayerOnePrompt: function() {
  $('.player-one-turn').animate({'top': '0'}, 500);
},

  showPlayerTwoPrompt: function() {
    var game = MYAPP.game;
  if (game.secondPlayer) {
    $('.player-two-turn p').text('Go Player 2!');
  }
  else {
    $('.player-two-turn p').text('Computer\'s turn');
  }
  $('.player-two-turn').animate({'top': '-45px'}, 500);
},

  hidePlayerTwoPrompt: function() {
  $('.player-two-turn').animate({'top': '0'}, 500);
},

  showDrawMessage: function() {
  window.setTimeout(function() {
    $('.draw-message').fadeIn(500);
  }, 1500);
},

  hideDrawMessage: function() {
  $('.draw-message').fadeOut(1000);
},

  showLoseMessage: function() {
  window.setTimeout(function() {
    $('.lose-message').fadeIn(500);
}, 1500);
},

  hideLoseMessage: function() {
  $('.lose-message').fadeOut(1000);
},

  showWinMessage: function(turn) {
  window.setTimeout(function() {
    $('.win-message').fadeIn(500).children('p').text("Player " + turn + " wins!! :D ")
}, 1500);

},

  hideWinMessage: function() {
  $('.win-message').fadeOut(1000);
},

  drawBoard: function() {
  window.setTimeout(function() {
    var c = document.getElementById("myCanvas");
    var canvas = c.getContext("2d");
    canvas.lineWidth = 1;
    canvas.strokeStyle = "#fff";
    //vertical lines
    canvas.beginPath();
    canvas.moveTo(100, 0);
    canvas.lineTo(100, $('#myCanvas').height());
    canvas.closePath();
    canvas.stroke();
    canvas.beginPath();
    canvas.moveTo(200, 0);
    canvas.lineTo(200, $('#myCanvas').height());
    canvas.closePath();
    canvas.stroke();

    // horizontal lines
    canvas.lineWidth = .5;
    canvas.beginPath();
    canvas.moveTo(4, 100.5);
    canvas.lineTo(296, 100.5);
    canvas.closePath();
    canvas.stroke();

    canvas.beginPath();
    canvas.moveTo(4, 49.5);
    canvas.lineTo(296, 49.5);
    canvas.closePath();
    canvas.stroke();
  }, 1500);
},

  resetSquares: function() {
  $('.boxes').html('');
  for (var i = 1; i <= 9; i++) {
    var box = '<li class="' + i + '"><i class="letter"><span></span></i></li>';
    $(box).appendTo($('.boxes'));
  }
} 
};

/*=========================
      Game Logic
==========================*/
MYAPP.game = {
  initialize: function() {
    this.winCombos = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    [1, 4, 7],
    [2, 5, 8],
    [3, 6, 9],
    [1, 5, 9],
    [7, 5, 3]
  ];
    this.numFilledIn = 0;
    this.currentBoard = {
      1: '',
      2: '',
      3: '',
      4: '',
      5: '',
      6: '',
      7: '',
      8: '',
      9: ''
    };
  },
  whoStarts: function() {
  var random = Math.floor(Math.random() * 2 + 1);
  return random;
  },
  gameSelection: function(item) {
    if ($(item).text() === 'One Player') {
      // returns what secondPlayer value to set
      return false;
    }
    else {
      return true;
    } 
  },
  firstGame: function() {
    MYAPP.game.playerOneSymbol = $(this).text();
    MYAPP.game.playerTwoSymbol = MYAPP.game.playerOneSymbol == 'X' ? 'O' : 'X'; 
    MYAPP.game.turn = MYAPP.game.whoStarts();
    MYAPP.display.hideGameStarter();
    $('#myCanvas').animate({'opacity': '1'}, 500);
    MYAPP.display.resetSquares();
    MYAPP.game.gameInPlay = true;
    MYAPP.game.play();
  },
  play: function() {
    $('.boxes li').on('click', function() {
     MYAPP.game.playerTurn(MYAPP.game, this);
    });  

    window.setTimeout(function(){
      if (MYAPP.game.turn === 1) {
        MYAPP.display.showPlayerOnePrompt();
      }
      else if (MYAPP.game.turn === 2) {
        MYAPP.display.showPlayerTwoPrompt();
      }
    }, 1500);

    window.setTimeout(function() {
      if (MYAPP.game.turn === 2 && !MYAPP.game.secondPlayer) {
        MYAPP.game.computerPlay();
      }
    }, 1200);
  },
  playerTurn: function(game, square) {
    var symbol = game.turn === 1 ? game.playerOneSymbol : game.playerTwoSymbol;
    var box = $(square).children('i').children('span');
    if (box.text() === '' && game.gameInPlay && (game.turn === 1 || (game.turn === 2 && game.secondPlayer))) {
      box.text(symbol);
      var number = $(square).attr('class');
      game.updateSquare(game, number, symbol);
      game.endTurn(symbol);
    }
  },
  computerPlay: function() {
    //test computer move suggestion
    var game = MYAPP.game;
    var boxNumber;
    if (computerWhichMove(MYAPP.game)) {
      boxNumber = computerWhichMove(MYAPP.game);
      var currentBox = $('.' + boxNumber).children('i');
    } 
    var symbol = game.playerTwoSymbol;

    window.setTimeout(function() {
      currentBox.children('span').text(symbol);
      game.updateSquare(game, boxNumber, game.playerTwoSymbol);
      game.endTurn(symbol);
    }, 1000);
  },
  endTurn: function(symbol) {
    var display = MYAPP.display;
    this.numFilledIn = this.numFilledIn + 1;
    if (this.gameInPlay) {
      if (this.checkWin(symbol)[0]) {
        if (this.secondPlayer) {
          display.showWinMessage(this.turn);
        }
        else {
          this.turn === 1 ? display.showWinMessage(this.turn) : display.showLoseMessage();
        }
        this.gameInPlay = false;
        this.showWinningCombination();
        display.hidePlayerOnePrompt();
        display.hidePlayerTwoPrompt();
        this.reset();
      }
      // stop if it is a draw
      else if (this.numFilledIn >= 9) {
        this.gameInPlay = false;
        display.hidePlayerOnePrompt();
        display.hidePlayerTwoPrompt();
        display.showDrawMessage();
        this.reset();
      } else {
        if (this.turn === 1) {
          display.hidePlayerOnePrompt();
          display.showPlayerTwoPrompt();
          this.turn = 2;
          // call computer turn if no second player
          if (!this.secondPlayer) {
            this.computerPlay();
          }
        } else if (this.turn === 2) {
          display.showPlayerOnePrompt();
          display.hidePlayerTwoPrompt();
          this.turn = 1;
        }
      }
    }
  },
  updateSquare: function(game, number, symbol) {
    game.currentBoard[number] = symbol;
  },
  checkWin: function(symbol) {
    var currentBoard = this.currentBoard;
    var wins = this.winCombos;
    var winningCombo = [];
    var winner = wins.some(function(combination) {
      var winning = true;
      for (var i = 0; i < combination.length; i++) {
        if (currentBoard[combination[i]] !== symbol) {
          winning = false;
        }
      }
      if (winning) {
        winningCombo = combination;
      }
      return winning;
    });
    return [winner, winningCombo];
  },
  showWinningCombination: function() {
    var symbol = this.turn === 1 ? this.playerOneSymbol : this.playerTwoSymbol;
    var combo = this.checkWin(symbol)[1];
    for (var i = 0; i < combo.length; i++) {
      var currentBox = '.' + combo[i]; 
   // Black box and rotating test for winning combo  
        $(currentBox).children('i').addClass('win').children('span').addClass('rotate');
     }
  },
  reset: function() {
    var game = MYAPP.game;
    var display = MYAPP.display;

    game.initialize();
    window.setTimeout(function() {
      display.hideDrawMessage();
      display.hideLoseMessage();
      display.hideWinMessage();
      $('.boxes').fadeOut(500);
    }, 5000);
    window.setTimeout(function(){
      display.resetSquares();
      $('.boxes').fadeIn();
      game.numFilledIn = 0;
    }, 6000);
    //Make sure time for next timeout is long enough
    //to not cause problems after first game
    window.setTimeout(function() {
      game.gameInPlay = true;
      game.play();
    }, 6000);
  },
  resetGame: function() {
    $('#myCanvas').css('opacity', '0');
    MYAPP.display.resetSquares();
    MYAPP.game.initialize();
    MYAPP.game.gameInPlay = false;
    MYAPP.game.playerOneSymbol = null;
    MYAPP.game.playerTwoSymbol = null;
    MYAPP.display.showGameChoice();
  }
};

$(document).ready(function() {
  MYAPP.display.drawBoard();
  MYAPP.game.initialize();

  $('.game-choice button').click(function() {
    MYAPP.game.secondPlayer = MYAPP.game.gameSelection(this);
    MYAPP.display.hideGameChoice();
    MYAPP.display.showGameStarter(MYAPP.game.secondPlayer);
    $('.game-starter .choose-x, .game-starter .choose-o').on('click', MYAPP.game.firstGame);

    $('.back-button').on('click', function() {
      MYAPP.display.hideGameStarter();
      MYAPP.display.showGameChoice();
    });
  });
  $('.hard-reset').on('click', MYAPP.game.resetGame);
});

/*================================
    Computer Move Decisions
=================================*/    
function computerWhichMove(game) {
  var board = game.currentBoard;
  var move = winOrBlockChoice(game, 'win', board)[0];
  if (!move) {
    move = winOrBlockChoice(game, 'block', board)[0];
  }
  if (!move) {
    move = doubleThreatChoice(game, 'win');
  }
  if (!move) {
    move = doubleThreatChoice(game, 'block');
  }
  if (!move) {
    move = firstPlay(game);
  }
  if (!move) {
    move = emptyCorner(game);
  }
  if (!move) {
    move = emptySide(game);
  }
  move = (move && game.currentBoard[move]) === '' ? move : false;
  return move;
}

function winOrBlockChoice(game, choiceType, board) {
  if (choiceType === 'win') {
    var currentSymbol = game.playerTwoSymbol;
    var opponentSymbol = game.playerOneSymbol;
  } else if (choiceType === 'block') {
    var currentSymbol = game.playerOneSymbol;
    var opponentSymbol = game.playerTwoSymbol;
  } else {
    return;
  }
  var moves = [];
  game.winCombos.forEach(function(combo) {
    var notFound = [];
    var notPlayer = true;
    for (var i = 0; i < combo.length; i++) {
      if (board[combo[i]] !== currentSymbol) {
        if (board[combo[i]] === opponentSymbol) {
          notPlayer = false;
        } else {
          notFound.push(combo[i]);
        }
      }
    }
    if (notFound.length === 1 && notPlayer) {
      var move = notFound[0];
      moves.push(move);
    }
  });
  return moves;
}

function doubleThreatChoice(game, choiceType) {
  // use winChoice function to test a spot for double threat
  var board = game.currentBoard;
  var move;

  if (choiceType === 'win') {
    var currentSymbol = game.playerTwoSymbol;
    var opponentSymbol = game.playerOneSymbol;
  } else if (choiceType === 'block') {
    var currentSymbol = game.playerOneSymbol;
    var opponentSymbol = game.playerTwoSymbol;
  }

  // forced diagonal win on 4th move prevention
    if (board[5] === currentSymbol && game.numFilledIn === 3) {
      if ((board[1] === opponentSymbol && board[9] === opponentSymbol) || (board[3] === opponentSymbol && board[7] === opponentSymbol)) {
        // Play an edge to block double threat
        move = emptySide(game);
      }
    }

    if (board[5] === opponentSymbol && game.numFilledIn === 2) {
      move = diagonalSecondAttack(game);
    }

  if (!move) {
    // clone current board;
    var testBoard = $.extend({}, board);
    for (var i = 1; i <= 9; i++) {

      testBoard = $.extend({}, board);
      if (testBoard[i] === '') {
        testBoard[i] = currentSymbol;
        if (winOrBlockChoice(game, choiceType, testBoard).length >= 2) {
          move = i;
        }
      }
    }
  }
  return move || false;
}

function diagonalSecondAttack(game) {
  var board = game.currentBoard;
  var comp = game.playerTwoSymbol;
  var corners = [1,3,7,9];
  for (var i = 0; i < corners.length; i++) {
    if (board[corners[i]] === comp) {
      return 10 - corners[i];
    }
  }
}

function firstPlay(game) {
  var board = game.currentBoard;
  var corners = [1, 3, 7, 9];
  var move;
  if (game.numFilledIn === 1) {
    // player plays center
    if (board[5] === game.playerOneSymbol) {
      var cornerNum = Math.floor(Math.random() * 4 + 1);
      move = [1, 3, 7, 9][cornerNum];
    }
    //player plays corner, play opposite corner
    else {
      for (var i = 0; i < corners.length; i++) {
        if (game.currentBoard[corners[i]] === game.playerOneSymbol) {
          move = 5;
        }
      }
    }
  } else if (game.numFilledIn === 0) {
    var cornerNum = Math.floor(Math.random() * corners.length + 1);
    move = corners[cornerNum];
  }
  return move ? move : false;
}

function emptyCorner(game) {
  var board = game.currentBoard;
  var corners = [1, 3, 7, 9];
  var move;
  for (var i = 0; i < corners.length; i++) {
    if (board[corners[i]] === '') {
      move = corners[i];
    }
  }
  return move || false;
}

function emptySide(game) {
  var sides = [2, 4, 6, 8];
  for (var i = 0; i < sides.length; i++) {
    if (game.currentBoard[sides[i]] === '') {
      return sides[i];
    }
  }
  return false;
}

/* End Computer Move Decisions */

1 个答案:

答案 0 :(得分:0)

在敲击键盘后我找到了解决方案! 我所要做的就是在第一次点击方法之前添加.off。这显然等同于现在已弃用的.unbind方法,并将元素限制为单击一次。这stackoverflow question为我做了。我希望我能够知道真正的问题,因为这会对我的搜索有所帮助。