<div class="board" id="board"></div>
<button id="reset">リセット</button>
body {
display: flex;
flex-direction: column;
align-items: center;
font-family: Arial, sans-serif;
}
.board {
display: grid;
grid-template-columns: repeat(3, 80px);
grid-template-rows: repeat(3, 80px);
gap: 1px;
}
.cell {
width: 80px;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #000;
cursor: pointer;
}
.svg-icon {
width: 80%;
height: 80%;
}
button {
appearance: none;
margin-top: 20px;
padding: 7px 20px;
font-size: 16px;
line-height: 16px;
border: 1px solid #999;
border-radius: 30px;
background-color: transparent;
}
const board = document.getElementById('board');
const resetButton = document.getElementById('reset');
let cells;
let currentPlayer = 'X';
let gameOver = false;
let winningCombination = null;
function init() {
board.innerHTML = '';
gameOver = false;
currentPlayer = 'X';
winningCombination = null;
cells = Array(9).fill(null);
for (let i = 0; i < 9; i++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.addEventListener('click', () => handleCellClick(i));
board.appendChild(cell);
}
}
function handleCellClick(index) {
if (gameOver || cells[index]) return;
makeMove(index);
if (!gameOver) {
setTimeout(makeAIMove, 500);
}
}
function makeMove(index) {
if (cells[index]) return;
cells[index] = currentPlayer;
updateBoard();
if (checkWinner()) {
alert(`${currentPlayer}の勝ちです!`);
gameOver = true;
} else if (cells.every(cell => cell)) {
alert('引き分けです!');
gameOver = true;
} else {
currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
}
}
function makeAIMove() {
if (gameOver) return;
// 自分が3連続で並べられる場合に勝利するパターンを探す
let winningMove = findWinningMove();
if (winningMove !== null) {
makeMove(winningMove);
return;
}
// 相手が2連続で並べられるのを妨害する
let blockingMove = findBlockingMove();
if (blockingMove !== null) {
makeMove(blockingMove);
return;
}
// 上記のいずれも該当しない場合はランダムに置く
let availableMoves = cells.map((cell, index) => cell === null ? index : null).filter(index => index !== null);
let move = availableMoves[Math.floor(Math.random() * availableMoves.length)];
makeMove(move);
}
function findWinningMove() {
const winningCombinations = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6]
];
for (let combination of winningCombinations) {
const [a, b, c] = combination;
if (cells[a] === 'X' && cells[b] === 'X' && cells[c] === 'X') {
if (a === 0 && cells[0] === null) return 0;
if (a === 1 && cells[1] === null) return 1;
if (a === 2 && cells[2] === null) return 2;
if (a === 3 && cells[3] === null) return 3;
if (a === 4 && cells[4] === null) return 4;
if (a === 5 && cells[5] === null) return 5;
if (a === 6 && cells[6] === null) return 6;
if (a === 7 && cells[7] === null) return 7;
if (a === 8 && cells[8] === null) return 8;
}
}
return null;
}
function findBlockingMove() {
const winningCombinations = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6]
];
for (let combination of winningCombinations) {
const [a, b, c] = combination;
if (cells[a] === 'X' && cells[b] === 'X' && cells[c] === null) return c;
if (cells[a] === 'X' && cells[c] === 'X' && cells[b] === null) return b;
if (cells[b] === 'X' && cells[c] === 'X' && cells[a] === null) return a;
}
return null;
}
function updateBoard() {
board.childNodes.forEach((cell, index) => {
cell.innerHTML = ''; // リセット時に内容を消去
if (cells[index]) {
const svg = document.createElement('div');
svg.innerHTML = cells[index] === 'X' ? getSVG('X') : getSVG('O');
svg.className = 'svg-icon';
cell.appendChild(svg);
}
if (winningCombination && winningCombination.includes(index)) {
cell.querySelector('svg').style.stroke = 'red'; // 勝利セルの線の色を赤に変更
}
});
}
function getSVG(player) {
if (player === 'X') {
return `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" stroke="black" stroke-width="10">
<line x1="10" y1="10" x2="90" y2="90"/>
<line x1="90" y1="10" x2="10" y2="90"/>
</svg>
`;
} else {
return `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" stroke="black" stroke-width="10" fill="none">
<circle cx="50" cy="50" r="40"/>
</svg>
`;
}
}
function checkWinner() {
const winningCombinations = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6]
];
for (let combination of winningCombinations) {
if (combination.every(index => cells[index] === currentPlayer)) {
winningCombination = combination;
return true;
}
}
return false;
}
resetButton.addEventListener('click', init);
init();
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.