![見出し画像](https://assets.st-note.com/production/uploads/images/146278483/rectangle_large_type_2_5b49d75703508497021f8f3cf7be833a.png?width=1200)
お気楽プログラミング:「さめがめ」ゲームを Claude 3.5 Sonnet で作る
空き時間に、昔懐かしい「さめがめ」を Claude 3.5 Sonnet で作ってみました。
作成に際して最初に与えたのは Wikipedia の「ルール」のセクションだけです。
その段階でも 6x6 で一応遊べるものが生成されたのですが、それに加えて、消去時のアニメーション、再実行ボタン、盤の大きさの選択、効果音の付与などを一つずつ行って行き、最終的には以下の結果を得ました。
途中実行時にエラーが出たりしましたが、そのときのエラーを Claude に与えることでエラーを取り除くことができました。
トータルの作成所要時間は7分ほどですね。この記事を書いている時間の方が長いです(笑)
以下のソース(HTML)を適当な場所にsamegame.html といった名前で保存して、そのファイルをブラウザで開くと遊べます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>さめがめ(サイズ選択・効果音付き)</title>
<style>
#game-container {
display: flex;
flex-direction: column;
align-items: center;
}
#game-board {
display: grid;
gap: 2px;
margin-bottom: 20px;
}
.cell {
width: 40px;
height: 40px;
border: 1px solid #000;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
cursor: pointer;
transition: all 0.3s ease;
}
.cell.removing {
transform: scale(0);
opacity: 0;
}
#start-over, #size-select {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
margin: 10px;
}
#controls {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div id="game-container">
<h1>さめがめ(サイズ選択・効果音付き)</h1>
<div id="controls">
<select id="size-select">
<option value="6">S (6x6)</option>
<option value="12">M (12x12)</option>
<option value="18">L (18x18)</option>
</select>
<button id="start-over">Start Over</button>
</div>
<div id="game-board"></div>
<p>スコア: <span id="score">0</span></p>
</div>
<script>
let BOARD_SIZE = 6;
const COLORS = ['🔴', '🔵', '🟢', '🟡', '🟣'];
let board = [];
let score = 0;
let audioContext;
function initializeBoard() {
board = [];
for (let i = 0; i < BOARD_SIZE; i++) {
board[i] = [];
for (let j = 0; j < BOARD_SIZE; j++) {
board[i][j] = COLORS[Math.floor(Math.random() * COLORS.length)];
}
}
}
function renderBoard() {
const gameBoard = document.getElementById('game-board');
gameBoard.innerHTML = '';
gameBoard.style.gridTemplateColumns = `repeat(${BOARD_SIZE}, 40px)`;
for (let i = 0; i < BOARD_SIZE; i++) {
for (let j = 0; j < BOARD_SIZE; j++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.textContent = board[i][j];
cell.onclick = () => handleClick(i, j);
gameBoard.appendChild(cell);
}
}
}
async function handleClick(row, col) {
const color = board[row][col];
const group = findGroup(row, col, color);
if (group.length > 1) {
await removeGroupWithAnimation(group);
dropTiles();
shiftColumns();
score += group.length * 10;
document.getElementById('score').textContent = score;
renderBoard();
if (isGameOver()) {
alert('ゲームオーバー!最終スコア: ' + score);
}
}
}
function findGroup(row, col, color, group = []) {
if (row < 0 || row >= BOARD_SIZE || col < 0 || col >= BOARD_SIZE || board[row][col] !== color) {
return group;
}
const key = `${row},${col}`;
if (group.includes(key)) return group;
group.push(key);
findGroup(row - 1, col, color, group);
findGroup(row + 1, col, color, group);
findGroup(row, col - 1, color, group);
findGroup(row, col + 1, color, group);
return group;
}
function removeGroupWithAnimation(group) {
return new Promise(resolve => {
const cells = document.querySelectorAll('.cell');
group.forEach(key => {
const [row, col] = key.split(',').map(Number);
const index = row * BOARD_SIZE + col;
cells[index].classList.add('removing');
});
playPopSound();
setTimeout(() => {
group.forEach(key => {
const [row, col] = key.split(',').map(Number);
board[row][col] = null;
});
resolve();
}, 300);
});
}
function playPopSound() {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioContext.currentTime); // 440Hz = A4
oscillator.frequency.exponentialRampToValueAtTime(880, audioContext.currentTime + 0.1); // 880Hz = A5
gainNode.gain.setValueAtTime(1, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.1);
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.start();
oscillator.stop(audioContext.currentTime + 0.1);
}
function dropTiles() {
for (let col = 0; col < BOARD_SIZE; col++) {
let writeRow = BOARD_SIZE - 1;
for (let row = BOARD_SIZE - 1; row >= 0; row--) {
if (board[row][col] !== null) {
board[writeRow][col] = board[row][col];
writeRow--;
}
}
while (writeRow >= 0) {
board[writeRow][col] = null;
writeRow--;
}
}
}
function shiftColumns() {
let writeCol = 0;
for (let col = 0; col < BOARD_SIZE; col++) {
if (board[BOARD_SIZE - 1][col] !== null) {
if (writeCol !== col) {
for (let row = 0; row < BOARD_SIZE; row++) {
board[row][writeCol] = board[row][col];
board[row][col] = null;
}
}
writeCol++;
}
}
}
function isGameOver() {
for (let i = 0; i < BOARD_SIZE; i++) {
for (let j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] && findGroup(i, j, board[i][j]).length > 1) {
return false;
}
}
}
return true;
}
function startOver() {
score = 0;
document.getElementById('score').textContent = score;
initializeBoard();
renderBoard();
}
function changeBoardSize() {
BOARD_SIZE = parseInt(document.getElementById('size-select').value);
startOver();
}
document.getElementById('start-over').addEventListener('click', startOver);
document.getElementById('size-select').addEventListener('change', changeBoardSize);
initializeBoard();
renderBoard();
</script>
</body>
</html>
なおトップの画像は ChatGPT に Wikipedia の「さめがめ」の記事を読ませて生成させたものです。
この記事が気に入ったらサポートをしてみませんか?