Внедрение TicTacToe AI в мою Javascript - PullRequest
0 голосов
/ 18 апреля 2020

Я создаю игру TicTacToe, используя html, javascript и css. То, что я сделал до сих пор, позволяет двум людям играть с одной машины, и это позволяет вам перезапустить игру. То, что мне сейчас нужно, и я не могу понять, как это сделать, - это внедрение ИИ в мой код. Я читал об алгоритме "Minimax", который хорош для этого, но, поскольку я новичок в JavaScript, он не имеет особого смысла для меня.

Вот код, который я имею, некоторые советы или помощь было бы намного лучше.

const X_CLASS = 'x'
const CIRCLE_CLASS = 'circle'
const WINNING_COMBINATION = [
	[0, 1, 2],
	[3, 4, 5],
	[6, 7, 8],
	[0, 4, 8],
	[2, 4, 6],
	[0, 3, 6],
	[1, 4, 7],
	[2, 5, 8]
]
const cellElements = document.querySelectorAll('[data-cell')
const board = document.getElementById('board')
const winningMessageElement = document.getElementById('winningMessage')
const winningMessageTextElement = document.querySelector('[data-winning-message-text]')
const restartButton = document.getElementById('restartButton')
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 {
		swapTurns()
		setBoardHoverClass()
	}
}

function placeMark(cell, currentClass) {
	cell.classList.add(currentClass)
}

function swapTurns() {
	circleTurn = !circleTurn
}

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)
	}
}

// GAME ENDING POSSIBILITIES
function checkWin(currentClass) {
	return WINNING_COMBINATION.some(combination => {
		return combination.every(index => {
			return cellElements[index].classList.contains(currentClass)
		})
	})
}

function endGame(draw) {
	if (draw) {
		winningMessageTextElement.innerText = 'Draw!'
	} else {
		winningMessageTextElement.innerText = `${circleTurn ? "Os" : "Xs"} Wins!`
	}
	winningMessageElement.classList.add('show')
}

function isDraw() {
	return [...cellElements].every(cell => {
		return cell.classList.contains(X_CLASS) || cell.classList.contains(CIRCLE_CLASS)
	})
}
*, *::after, *::before {
	box-sizing: border-box;
}

:root {
	--cell-size: 100px;
	--mark-size: calc(var(--cell-size) * .9);
}

body {
	margin: 0;
}

.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;
	position: relative;
	cursor: pointer;
}

.cell:first-child,
.cell:nth-child(2),
.cell:nth-child(3) {
	border-top: none;
}

.cell:nth-child(3n + 1) {
	border-left: none;
}

.cell:nth-child(3n + 3) {
	border-right: none;
}

.cell:last-child,
.cell:nth-child(8),
.cell:nth-child(7) {
	border-bottom: none;
}

.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: lightgrey;
}

.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;
}

.winning-message {
	display: none;
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background-color: rgba(0, 0, 0, .75);
	justify-content: center;
	align-items: center;
	color: white;
	font-size: 5rem;
	flex-direction: column;
}

.winning-message button {
	font-size: 3rem;
	background-color: white;
	border: 1px solid black;
	padding: .25em .5em;
	cursor: pointer;
}

.winning-message button:hover {
	background-color: black;
	color: white;
	border-color: white;
}

.winning-message.show {
	display: flex;
}
<div class="board" id="board">
  <div class="cell" data-cell></div>
  <div class="cell" data-cell></div>
  <div class="cell" data-cell></div>
  <div class="cell" data-cell></div>
  <div class="cell" data-cell></div>
  <div class="cell" data-cell></div>
  <div class="cell" data-cell></div>
  <div class="cell" data-cell></div>
  <div class="cell" data-cell></div>
</div>
<div class="winning-message" id="winningMessage">
  <div data-winning-message-text></div>
  <button id="restartButton">Restart</button>
</div>

Заранее спасибо всем, у кого есть информация.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...