我正在做一个井字游戏,该功能非常适合用户回合,但是在计算机回合播放时,这些功能会崩溃并给出意外结果,例如两次播放,请跳过转等等。
谁能告诉我我的代码有什么问题,并帮助我解决此问题?
const start = document.getElementById('start');
const table = document.getElementById('table');
places = ["one", "two", "three", "four", "five", "six", "seven", 'eight', "nine"];
let move = 0;
start.addEventListener('click', function(){
user();
});
function user(){
table.addEventListener('click', function(event){
let pos = event.target;
let Id = event.target.id;
if (/[1-9]/.test(pos.innerHTML)){
pos.innerHTML = "X";
move += 1;
places.splice(places.indexOf(Id), 1 );
}
if (move > 8){
gameOver();
}
if (move <= 8){
computer();
}
});
}
function gameOver(){
console.log("Game Over");
}
function computer(){
let index = places[Math.floor(Math.random() * places.length)];
let pos = document.getElementById(index);
if (/[1-9]/.test(pos.innerHTML)){
pos.innerHTML = "O";
move += 1;
places.splice(places.indexOf(pos), 1 );
}
if (move > 8){
gameOver();
}
if (move <= 8) {
user();
}
}
<div class="col text-center">
<table class="table text-center">
<tbody id="table">
<tr>
<td id="one">1</td>
<td id="two">2</td>
<td id="three">3</td>
</tr>
<tr>
<td id="four">4</td>
<td id="five">5</td>
<td id="six">6</td>
</tr>
<tr>
<td id="seven">7</td>
<td id="eight">8</td>
<td id="nine">9</td>
</tr>
</tbody>
</table>
<br />
<button class="btn btn-primary" type="button" id="start">Start Game</button>
</div>
答案 0 :(得分:1)
让我尝试改写我的原始答案: 轮到计算机时,您正在执行此代码
function computer(){
let index = places[Math.floor(Math.random() * places.length)];
let pos = document.getElementById(index);
if (/[1-9]/.test(pos.innerHTML)){
pos.innerHTML = "O";
move += 1;
places.splice(places.indexOf(pos), 1 );
}
if (move > 8){
gameOver();
}
if (move <= 8) {
user();
}
}
如果if (/[1-9]/.test(pos.innerHTML)){
返回false,会发生什么? (即该字段已被占用),您的代码将继续执行,就好像计算机已经将转弯交给用户一样。
所以我的建议是,您需要确保计算机实际进行了移动,一种方法是添加一个发现的变量,该变量被初始化为false,并且在实际发现并进行计算机移动时首先将其设置为true。
这可以通过将您的方法修改为类似方式来完成:
function computer(){
let foundEmptyField=false;
while(foundEmptyField===false)
{
let index = places[Math.floor(Math.random() * places.length)];
let pos = document.getElementById(index);
if (/[1-9]/.test(pos.innerHTML)){
pos.innerHTML = "O";
move += 1;
places.splice(places.indexOf(pos), 1 );
foundEmptyField = true;
}
if(foundEmptyField===true) {
if (move > 8){
gameOver();
}
if (move <= 8) {
user();
}
}
}
}
如果您查看代码,则在user()代码中确实存在完全相同的问题
答案 1 :(得分:0)
问题说明: 您已经创建了一个事件监听器,该监听器在用户每次单击时发生
start.addEventListener('click', function(){
user();
});
您做不到的是确定轮到谁了,因此用户可能会双击甚至单击播放的图块,甚至单击计算机上的转向,并且代码不会使用户转身但接受移动当玩家转弯时。
因此,我已经添加了用户功能
}else{
return;
}
如果点击的磁贴已经按X指示播放过,则会忽略转牌。
我还向计算机功能添加了一个调用,以重试一次移动,如果计算机随机生成一个已播放的磁贴编号,则它不会交还给玩家,而是会重试。
}else{
computer();
}
最后,我简化了您的代码,因为您重复了一些代码,可以将这些代码转换成带有变量的函数。
function gameStateCheck(stTurn){
if (move > 8){
gameOver();
}
if (move <= 8) {
if (stTurn == "user"){
user();
}else{
computer();
}
}
}
替代解决方案: 此解决方案完全是-重新编写您的代码,但是由于它被告知CPU知道哪些动作有效,因此它可以正常工作,并且不会陷入函数调用循环中。
const start = document.getElementById('start');
const table = document.getElementById('table');
places = [];
start.addEventListener('click', function(){
places = []; // reset the array of available tiles to play
for (i = 0; i < 9; i++){ // re populate available tiles 0-8
places.push (i);
}
// run a loop to clear the previous game cell markers (O or X);
for (x = 0; x < table.rows.length; x++){
for (i = 0; i < table.rows[x].cells.length; i++){
table.rows[x].cells[i].innerHTML = "";
}
}
// Mark the users move
user();
});
function user(){
table.addEventListener('click', function(event){
// get the ID of the played tile
let Id = parseInt(event.target.id);
// locate the index number in the array that contains the ID
let PlayedTile = places.indexOf(Id);
if (PlayedTile > -1){
// if PlayerTile is NOT -1, it means it exists in the array
// lets remove it from the available tiles to play array
places.splice(places.indexOf(Id), 1 );
}else{
// Ok so this user has already played this tile or the CPU has
// Therefore we exit the function and nothing changes on the screen
// Recommendation: add some code to notify your user this move has been played
return;
}
// Ok so if we havent exited the function above due to having played the tile
// we can now update the cell with an "X"
event.target.innerHTML = "X";
// we now check to see if there are any further moves available (by checking the length
// of the places array, if it is 0 we declare game over)
if (places.length == 0){
gameover();
return;
}else{
// otherwise we pass control to the CPU
computer();
}
});
}
function computer(){
// we know how many moves are available by the length of the array
// so lets choose 1 random box ID number
let cpuMove = Math.floor(Math.random() * places.length);
// now lets get the value of that array index, as this value will be the table cell ID
let cpuPlayedTileId = places[cpuMove];
// now lets grab the cell element by its ID
let pos = document.getElementById(cpuPlayedTileId);
// Update the cell with an "O" marker
// NOTE the CPU cannot physically choose an invalid move as the CPU knows the available moves
pos.innerHTML = "O";
// As it is a valid move, lets remove it from the array for the player.
places.splice(places.indexOf(cpuPlayedTileId), 1 );
// check if the game is now over
if (places.length == 0){
gameover();
return;
}else{
user();
}
}
function gameover(){
alert("gameover");
console.log("Game Over");
}
#boardGame{
background: grey;
border: 1px solid black;
height: 90px;
width: 90px;
}
#boardGame tr td{
border: 1px solid silver;
width: 30px;
height: 30px;
text-align: center;
font-size: small;
}
<div class="col text-center">
<table id="boardGame" class="table text-center">
<tbody id="table">
<tr>
<td id="0"></td>
<td id="1"></td>
<td id="2"></td>
</tr>
<tr>
<td id="3"></td>
<td id="4"></td>
<td id="5"></td>
</tr>
<tr>
<td id="6"></td>
<td id="7"></td>
<td id="8"></td>
</tr>
</tbody>
</table>
<br>
<button class="btn btn-primary" type="button" id="start">Start Game</button>
</div>
您的代码库,已固定 请注意,您可能会陷入无限循环中,这将导致超出呼叫错误。但是我留下的代码与您上面的代码差不多。
我上面已编码了无错误代码,就像我要编码一样
const start = document.getElementById('start');
const table = document.getElementById('table');
places = ["one", "two", "three", "four", "five", "six", "seven", 'eight', "nine"];
let move = 0;
start.addEventListener('click', function(){
user();
});
function user(){
table.addEventListener('click', function(event){
let pos = event.target;
let Id = event.target.id;
if (/[1-9]/.test(pos.innerHTML)){
pos.innerHTML = "X";
move += 1;
places.splice(places.indexOf(Id), 1 );
}else{
return;
}
gameStateCheck("CPU");
});
}
function gameOver(){
console.log("Game Over");
}
function computer(){
let index = places[Math.floor(Math.random() * places.length)];
let pos = document.getElementById(index);
if (/[1-9]/.test(pos.innerHTML)){
pos.innerHTML = "O";
move += 1;
places.splice(places.indexOf(pos), 1 );
}else{
computer();
}
gameStateCheck("user");
}
function gameStateCheck(stTurn){
if (move > 8){
gameOver();
}
if (move <= 8) {
if (stTurn == "user"){
user();
}else{
computer();
}
}
}
<div class="col text-center">
<table class="table text-center">
<tbody id="table">
<tr>
<td id="one">1</td>
<td id="two">2</td>
<td id="three">3</td>
</tr>
<tr>
<td id="four">4</td>
<td id="five">5</td>
<td id="six">6</td>
</tr>
<tr>
<td id="seven">7</td>
<td id="eight">8</td>
<td id="nine">9</td>
</tr>
</tbody>
</table>
<br>
<button class="btn btn-primary" type="button" id="start">Start Game</button>
</div>
答案 2 :(得分:0)
欢迎来到stackoverflow。每次调用用户函数时都添加事件侦听器,但是该事件侦听器仅应添加一次。在计算机功能中,您剪接了pos的索引(即HTMLElement),而是剪接了索引var的索引,例如“ one”,“ two”等。不应从计算机功能,因为它是由事件侦听器触发的。由于计算机仅从位置上未接触的元素中进行选择,因此计算机功能中的测试是多余的。为了清楚起见,我引入了一个init函数进行进一步扩展。以下是正在运行的解决方案:
<!DOCTYPE html>
<html>
<head>
<title>Tic Tac Toe</title>
<meta charset="UTF-8">
<script type="text/javascript">
var places, move;
function init() {
places = ["one", "two", "three", "four", "five", "six", "seven", 'eight', "nine"];
move = 0;
table.addEventListener('click', user);
}
function user(event) {
let pos = event.target;
let Id = event.target.id;
if (/[1-9]/.test(pos.innerHTML)) {
pos.innerHTML = "X";
move += 1;
places.splice(places.indexOf(Id), 1);
if (move > 8) {
gameOver();
}
else {
computer();
}
}
}
function gameOver() {
console.log("Game Over");
}
function computer() {
let index = places[Math.floor(Math.random() * places.length)];
let pos = document.getElementById(index);
pos.innerHTML = "O";
move += 1;
places.splice(places.indexOf(index), 1);
if (move > 8) {
gameOver();
}
}
</script>
</head>
<body>
<div class="col text-center">
<table class="table text-center">
<tbody id="table">
<tr>
<td id="one">1</td>
<td id="two">2</td>
<td id="three">3</td>
</tr>
<tr>
<td id="four">4</td>
<td id="five">5</td>
<td id="six">6</td>
</tr>
<tr>
<td id="seven">7</td>
<td id="eight">8</td>
<td id="nine">9</td>
</tr>
</tbody>
</table>
<br />
<button class="btn btn-primary" type="button" onclick="init()" id="start">Start Game</button>
</div>
</body>
</html>