ChatGPTで生成したバグってるソースを手直した。変数の宣言がなかったり関数ごと欠損しているソースをデバッグするところからスタートして何となく動くようになったので投稿。初めテトリスを作ろうとしたけど、まともに動かない状態から抜け出せずに挫折… オセロは、テトリスの半分以下で300行程度。
黒の手番です
備忘:CSSに一番苦戦した。borderとborder-radiusが同時に指定できない。border-radiusでコマを描くとborderで描いた枠線が欠落してしまう。最終的にはコマの白黒画像を用意してbackground-imageで読み込むように修正した。
ご参考:
プロンプト:オセロゲームのサンプルをHTML/CSS/JavaScriptで作成してください。
ChatGPT:はい、以下にHTML、CSS、JavaScriptで書かれたオセロゲームのサンプルを用意しました。
・・・
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>オセロゲーム</title>
<style>
.container {
display: flex;
flex-wrap: wrap;
width: 320px;
height: 320px;
margin: 0 auto;
}
.cell {
width: 40px;
height: 40px;
background-color: green;
border: 1px solid black;
box-sizing: border-box;
cursor: pointer;
}
.cell.black {
background-color: black;
}
.cell.white {
background-color: white;
}
.turn {
margin-top: 10px;
text-align: center;
font-size: 20px;
}
.win {
margin-top: 10px;
text-align: center;
font-size: 30px;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container"></div>
<div class="turn">黒の手番です</div>
<div class="win"></div>
<script>
const WHITE = 1;
const BLACK = -1;
const EMPTY = 0;
// ゲームボードのサイズ
const BOARD_SIZE = 8;
// ゲームボードの初期化
let board = [];
for (let i = 0; i < BOARD_SIZE; i++) {
board[i] = [];
for (let j = 0; j < BOARD_SIZE; j++) {
board[i][j] = 0;
}
}
board[3][3] = board[4][4] = 1;
board[3][4] = board[4][3] = -1;
// 現在のプレイヤー(1:黒, -1:白)
let currentPlayer = 1;
// 盤面を描画する関数
function drawBoard() {
const container = document.querySelector('.container');
container.innerHTML = '';
for (let i = 0; i < BOARD_SIZE; i++) {
for (let j = 0; j < BOARD_SIZE; j++) {
const cell = document.createElement('div');
cell.className = 'cell';
if (board[i][j] === 1) {
cell.classList.add('black');
} else if (board[i][j] === -1) {
cell.classList.add('white');
}
cell.dataset.row = i;
cell.dataset.col = j;
cell.addEventListener('click', handleClick);
container.appendChild(cell);
}
}
}
drawBoard();
// クリックイベントのハンドラー関数
function handleClick(event) {
const row = parseInt(event.target.dataset.row);
const col = parseInt(event.target.dataset.col);
if (board[row][col] !== 0) {
return;
}
const directions = [
{ x: 0, y: -1 }, // 上
{
x: 0, y
1 }, // 下
{ x: -1, y: 0 }, // 左
{ x: 1, y: 0 }, // 右
{ x: -1, y: -1 }, // 左上
{ x: 1, y: -1 }, // 右上
{ x: -1, y: 1 }, // 左下
{ x: 1, y: 1 } // 右下
];
let canPlace = false;
for (let d = 0; d < directions.length; d++) {
const dx = directions[d].x;
const dy = directions[d].y;
let x = row + dx;
let y = col + dy;
let flipCount = 0;
while (x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE) {
if (board[x][y] === -currentPlayer) {
flipCount++;
x += dx;
y += dy;
} else if (board[x][y] === currentPlayer) {
if (flipCount > 0) {
canPlace = true;
}
break;
} else {
break;
}
}
if (canPlace) {
break;
}
}
if (!canPlace) {
return;
}
board[row][col] = currentPlayer;
event.target.classList.add(currentPlayer === 1 ? 'black' : 'white');
event.target.removeEventListener('click', handleClick);
flipStones(row, col);
currentPlayer = -currentPlayer;
const turnEl = document.querySelector('.turn');
turnEl.textContent = ${ currentPlayer === 1 ? '黒' : '白' } の手番です;
if (!hasPlaceableCell()) {
currentPlayer = -currentPlayer;
if (!hasPlaceableCell()) {
const winEl = document.querySelector('.win');
const blackCount = countStones(1);
const whiteCount = countStones(-1);
if (blackCount > whiteCount) {
winEl.textContent = '黒の勝ち!';
} else if (blackCount < whiteCount) {
winEl.textContent = '白の勝ち!';
} else {
winEl.textContent = '引き分け!';
}
} else {
turnEl.textContent = ${ currentPlayer === 1 ? '黒' : '白' } はパスです;
}
}
}
// 石を返す関数
function flipStones(row, col) {
const directions = [
{ x: 0, y: -1 }, // 上
{ x: 0, y: 1 }, // 下
{ x: -1, y: 0 }, // 左
{ x: 1, y: 0 }, // 右
{ x: -1, y: -1 }, // 左上
{ x: 1, y: -1 }, // 右上
{ x: -1, y: 1 }, // 左下
{ x: 1, y: 1 } // 右下
];
for (let d = 0; d < directions.length; d++) {
const dx = directions[d].x;
const dy = directions[d].y;
let x = row + dx;
let y = col + dy;
let flipCount = 0;
while (x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE) {
if (board[x][y] === -currentPlayer) {
flipCount++;
x += dx;
y += dy;
} else if (board[x][y] === currentPlayer) {
if (flipCount > 0) {
for (let i = 1; i <= flipCount; i++) {
const flipX = row + i * dx;
const flipY = col + i * dy;
board[flipX][flipY] = currentPlayer;
const flipEl = document.querySelector(`[data-row="${flipX}"][data-col="${flipY}"]`);
flipEl.classList.remove(currentPlayer === 1 ? 'white' : 'black');
flipEl.classList.add(currentPlayer === 1 ? 'black' : 'white');
}
}
break;
} else {
break;
}
}
}
}
// 置けるセルがあるかどうかを判定する関数
function hasPlaceableCell() {
for (let i = 0; i < BOARD_SIZE; i++) {
for (let j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] === 0 && canPlaceStone(i, j)) {
return true;
}
}
}
return false;
}
// 石の数を数える関数
function countStones(player) {
let count = 0;
for (let i = 0; i < BOARD_SIZE; i++) {
for (let j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] === player) {
count++;
}
}
}
return count;
}
// ゲームをリセットする関数
function resetGame() {
board = initializeBoard();
currentPlayer = 1;
const cells = document.querySelectorAll('.cell');
for (let i = 0; i < cells.length; i++) {
cells[i].classList.remove('black', 'white');
cells[i].addEventListener('click', handleClick);
}
const turnEl = document.querySelector('.turn');
turnEl.textContent = '黒の手番です';
const winEl = document.querySelector('.win');
winEl.textContent = '';
}
function canPlaceStone(row, col, color) {
if (board[row][col] !== EMPTY) {
return false;
}
for (let drow = -1; drow <= 1; drow++) {
for (let dcol = -1; dcol <= 1; dcol++) {
if (drow === 0 && dcol === 0) {
continue;
}
let r = row + drow;
let c = col + dcol;
let flipped = false;
while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE) {
if (board[r][c] === EMPTY) {
break;
}
if (board[r][c] === color) {
if (flipped) {
return true;
} else {
break;
}
}
flipped = true;
r += drow;
c += dcol;
}
}
}
return false;
}
function initializeBoard() {
for (let row = 0; row < BOARD_SIZE; row++) {
for (let col = 0; col < BOARD_SIZE; col++) {
const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
cell.classList.remove('black', 'white');
if ((row === 3 && col === 3) || (row === 4 && col === 4)) {
cell.classList.add('white');
board[row][col] = WHITE;
} else if ((row === 3 && col === 4) || (row === 4 && col === 3)) {
cell.classList.add('black');
board[row][col] = BLACK;
} else {
board[row][col] = EMPTY;
}
}
}
}
// 初期化
let board = initializeBoard();
let currentPlayer = 1;
const cells = document.querySelectorAll('.cell');
for (let i = 0; i < cells.length; i++) {
cells[i].addEventListener('click', handleClick);
}
const resetBtn = document.querySelector('.reset');
resetBtn.addEventListener('click', resetGame);
const turnEl = document.querySelector('.turn');
turnEl.textContent = '黒の手番です';
}) ();
</script>
</body>
</html>
※インデントなど整形済み