#javascript #bots #tic-tac-toe
Вопрос:
Я пытаюсь создать игру в крестики-нолики на HTML с ботом, который играет в круг. Однако я не уверен, как заставить бота поместить круг в случайную ячейку. Все остальное полностью работает, у меня просто возникли проблемы с ботом (отмечено в коде js). То, что я пробовал, — это использовать Math.random для получения случайной ячейки, однако я не понял, как получить ячейку из этого. Я верю, что это может быть ответом, но я просто застрял. Любая помощь была бы потрясающей!
Приведенный ниже код был сокращен до частей, которые могут быть важными
HTML:
<body>
<div class="board" id="board">
<div class="cell" datacell></div>
<div class="cell" datacell></div>
<div class="cell" datacell></div>
<div class="cell" datacell></div>
<div class="cell" datacell></div>
<div class="cell" datacell></div>
<div class="cell" datacell></div>
<div class="cell" datacell></div>
<div class="cell" datacell></div>
</div>
<div class="winning-message" id="winningMessage">
<div data-winning-message-text></div>
<button id = "restartButton">Restart?</button>
</div>
</body>
CSS:
.board {
width: 100vw;
height: 100vh;
display: grid;
justify-content: center;
align-content: center;
justify-items: center;
align-items: center;
grid-template-columns: repeat(3, auto);
}
.cell {
width: var(--cell-size);
height: var(--cell-size);
border: 1px solid black;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.cell.x,
.cell.circle {
cursor: not-allowed;
}
.cell.x::before,
.cell.x::after,
.cell.circle::before {
background-color: black;
}
.board.x .cell:not(.x):not(.circle):hover::before,
.board.x .cell:not(.x):not(.circle):hover::after,
.board.circle .cell:not(.x):not(.circle):hover::before{
background-color: lightgray;
}
.cell.x::before,
.cell.x::after,
.board.x .cell:not(.x):not(.circle):hover::before,
.board.x .cell:not(.x):not(.circle):hover::after {
content: '';
position: absolute;
width: calc(var(--mark-size) * .15);
height: var(--mark-size);
}
.cell.x::before,
.board.x .cell:not(.x):not(.circle):hover::before {
transform: rotate(45deg);
}
.cell.x::after,
.board.x .cell:not(.x):not(.circle):hover::after {
transform: rotate(-45deg);
}
.cell.circle::before,
.cell.circle::after,
.board.circle .cell:not(.x):not(.circle):hover::before,
.board.circle .cell:not(.x):not(.circle):hover::after {
content: '';
position: absolute;
border-radius: 50%;
}
.cell.circle::before,
.board.circle .cell:not(.x):not(.circle):hover::before{
width: var(--mark-size);
height: var(--mark-size);
}
.cell.circle::after,
.board.circle .cell:not(.x):not(.circle):hover::after {
width: calc(var(--mark-size) * .7);
height: calc(var(--mark-size) * .7);
background-color: white;
}
JS (есть проблема):
const X_CLASS = 'x'
const CIRCLE_CLASS = 'circle'
const WINNING_COMBINATIONS = [ [0,1,2], [3,4,5], [6,7,8], [0,3,6], [1,4,7], [2,5,8], [0,4,8] , [2,4,6] ]
const cellElements = document.querySelectorAll('.cell')
const board = document.getElementById('board')
const winningMessageElement = document.getElementById('winningMessage')
const restartButton = document.getElementById('restartButton')
const winningMessageTextElement = document.querySelector('[data-winning-message-text]')
let circleTurn
startGame()
restartButton.addEventListener('click', startGame)
function startGame() {
circleTurn = false
cellElements.forEach(cell => {
cell.classList.remove(X_CLASS)
cell.classList.remove(CIRCLE_CLASS)
cell.removeEventListener('click', handleClick)
cell.addEventListener('click', handleClick, { once: true})
})
setBoardHoverClass()
winningMessageElement.classList.remove('show')
}
function handleClick(e) {
const cell = e.target
const currentClass = circleTurn ? CIRCLE_CLASS : X_CLASS
placeMark(cell, currentClass)
if(checkWin(currentClass)) {
endGame(false)
} else if (isDraw()) {
endGame(true)
} else {
//ai takes place in here
Ai()
}
}
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
///heres the issue
function Ai(cell, CIRCLE_CLASS) {
if(circleTurn = true)
{
let numberGenerator = getRandomInt(9)
let test = Math.round(cellElements.length * Math.random(9))
placeMark(test)
}
}
function endGame(draw) {
if(draw) {
winningMessageTextElement.innerText = 'Draw!'
} else{
winningMessageTextElement.innerText = `${circleTurn ? "O" : "X"} Wins!`
}
winningMessageElement.classList.add('show')
}
function isDraw() {
return [...cellElements].every(cell => {
return cell.classList.contains(X_CLASS) ||
cell.classList.contains(CIRCLE_CLASS)
})
}
function placeMark(cell, currentClass) {
cell.classList.add(currentClass)
}
function checkWin(currentClass) {
return WINNING_COMBINATIONS.some(combination => {
return combination.every(index => {
return cellElements[index].classList.contains(currentClass)
})
})
}
function setBoardHoverClass() {
board.classList.remove(X_CLASS)
board.classList.remove(CIRCLE_CLASS)
if(circleTurn) {
board.classList.add(CIRCLE_CLASS)
}
else{
board.classList.add(X_CLASS)
}
}
Комментарии:
1. Код
if(circleTurn = true)
фактически выполняет задание, — вы хотите==
(вместо=
), если хотите, выполнить сравнение.2. О, я не заметил этого, ха-ха, однако у меня все еще есть проблема, так как он не может выбрать случайную ячейку.
3. Ну, функция искусственного интеллекта немного пугающая..
let numberGenerator = getRandomInt(9)
возвращает значение int от 0 до 8. Просто используйте его в качестве индекса в списке узлов, возвращаемомdocument.querySelectorAll('div.cell')
. Вы звонитеplaceMark
с(0 to 8) * 9
помощью, когда вы должны звонить с помощью элемента. Теперь в этом есть смысл?4. Я не уверен, куда это поместить, не могли бы вы уточнить?
5. Естественно, это просто установит случайную ячейку, содержащую круг. Конечно, вам придется проверить, действительно ли эта ячейка доступна. Также предпочтительнее было бы использовать некоторые средства, с помощью которых вы фактически выбираете ячейку с целью выигрыша, а не выбираете ее наугад.