オセロビンゴ(開発中)携帯に対応1 まだただのオセロ

オセロ・ビンゴゲーム
サンプルコード

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>オセロ・ビンゴゲーム</title>
    <style>
        #gameBoard {
            /* ゲームボードのスタイリング */
            margin-top: 20px;
            /* 上部に余白を追加 */
            margin-bottom: 80px;
            /* ボタンの高さとマージンを考慮した下部の余白 */
            /* その他のスタイル設定 */
        }

        #rouletteResult {
            /* ルーレット結果表示部のスタイリング */
            margin-bottom: 80px;
            /* ボタンの高さとマージンを考慮した余白 */
            /* その他のスタイル設定 */
        }

        #newButton,
        #rouletteButton {
            position: absolute;
            bottom: -30px;
            /* .boardの外に配置 */
            /* ボタンの高さを考慮して適切に調整 */
        }

        #newButton {
            left: 0;
        }

        #rouletteButton {
            right: 0;
        }

        #rouletteResult {
            /* ルーレット結果表示部のスタイリング */
            margin-top: 60px;
            /* ボタンの分だけ余白を調整 */
        }

        body {
            position: relative;
            margin: 0;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: flex-start;
            padding-bottom: 100px;
            /* ボタンとそのマージンを考慮した下部の余白 */
            padding-top: 20px;
            /* 上部の余白 */
        }

        .cell::after {
            content: attr(data-bingoNumber);
            /* 修正:data-numberからdata-bingoNumberに */
            color: rgb(133, 173, 255);
            font-size: 25px;
            position: absolute;
            left: 5px;
            top: 5px;
        }

        .board {
            position: relative;
            /* これを追加 */
            width: min(100vw, 100vh);
            /* ビューポートの短い側に合わせてボードのサイズを設定 */
            height: min(100vw, 100vh);
            /* ビューポートの短い側に合わせてボードのサイズを設定 */
            display: grid;
            grid-template-columns: repeat(8, 1fr);
            /* 8つの等しい列を設定 */
            grid-template-rows: repeat(8, 1fr);
            /* 8つの等しい行を設定 */
            gap: 4px;
            margin: 20px auto;
            /* 上下に20pxの余白を追加し、左右は中央寄せ */
            background-color: #008000;
            border: 2px solid black;
            padding: 2px;
        }

        .cell {
            width: calc((100% - (7 * 1px)));
            height: calc((100% - (7 * 1px)));
            background-color: green;
            position: relative;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 1px solid black;
            z-index: 1;
        }

        .cell.marked {
            background-color: rgba(0, 191, 255, 0.5);
            /* 光った青色 */
            border-color: rgba(0, 191, 255, 1);
            /* より濃い青色の枠 */
        }

        .piece {
            width: 80%;
            height: 80%;
            border-radius: 50%;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }

        .black {
            background-color: black;
        }

        .white {
            background-color: white;
        }

        @media screen and (max-width: 00px) {
            .board {
                /* gap, margin, border, paddingを考慮したサイズ調整 */
                width: calc(min(100vw, 100vh) - 4px - 4px - 4px - 2px * 2);
                height: calc(min(100vw, 100vh) - 4px - 4px - 4px - 2px * 2);
                /* ここで、4pxはgap, 4pxは左右のmargin, 2px * 2はborderの幅です */

                display: grid;
                grid-template-columns: repeat(8, 1fr);
                grid-template-rows: repeat(8, 1fr);
                gap: 4px;
                margin: 2px auto;
                background-color: #008000;
                border: 2px solid black;
                padding: 2px;

                /* 最大幅と最大高さを設定してはみ出しを防ぐ */
                max-width: calc(100vw - 4px - 4px);
                max-height: calc(100vh - 4px - 4px);
                /* ここで、4pxは左右のmarginの合計です */
            }
        }
    </style>
</head>

<body>
    <div id="gameBoard" class="board">
        <button id="newButton">新規ボタン</button> <!-- `.board`内に移動 -->
        <button id="rouletteButton">ルーレット</button> <!-- `.board`内に移動 -->
    </div>
    <div id="rouletteResult"></div>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            let rouletteInterval; // ルーレットのタイマーIDを保持する変数
            const rouletteDelay = 300; // ルーレットが自動で回る間隔(ミリ秒)
            const boardSize = 8;
            const board = document.getElementById('gameBoard');
            let boardState = [];
            let currentPlayer = 'black';

            // オセロの初期化関数
            function initBoard() {
                const bingoNumbers = [...Array(boardSize * boardSize).keys()].map(x => x + 1);
                shuffleArray(bingoNumbers); // ビンゴ番号をシャッフル

                for (let i = 0; i < boardSize; i++) {
                    boardState[i] = [];
                    for (let j = 0; j < boardSize; j++) {
                        const cell = document.createElement('div');
                        cell.className = 'cell';
                        cell.dataset.row = i;
                        cell.dataset.col = j;
                        cell.dataset.bingoNumber = bingoNumbers[i * boardSize + j];  // シャッフルされたビンゴ番号を割り当てる
                        cell.addEventListener('click', () => handleCellClick(i, j));
                        board.appendChild(cell);
                        boardState[i][j] = null;
                    }
                }

                // オセロの標準的な開始配置
                const midPoint = Math.floor(boardSize / 2);
                boardState[midPoint - 1][midPoint - 1] = 'white';
                boardState[midPoint][midPoint] = 'white';
                boardState[midPoint - 1][midPoint] = 'black';
                boardState[midPoint][midPoint - 1] = 'black';

                updateBoard();
                //startTurn(); // ゲーム開始時に1ターン目を開始
            }

            // 1ターンを開始する関数
            function startTurn() {
                startRoulette(); // ルーレットを開始
                // ルーレットが終了するまで待機してからAIの手を実行
                setTimeout(() => {
                    aiMove();
                }, rouletteDelay);
            }

            // 配列をシャッフルする関数
            function shuffleArray(array) {
                for (let i = array.length - 1; i > 0; i--) {
                    const j = Math.floor(Math.random() * (i + 1));
                    [array[i], array[j]] = [array[j], array[i]];
                }
            }

            // AIが手を実行する関数
            function aiMove() {
                let legalMoves = getLegalMoves('white'); // AIは白と仮定します
                if (legalMoves.length > 0) {
                    let randomIndex = Math.floor(Math.random() * legalMoves.length);
                    let move = legalMoves[randomIndex];
                    boardState[move.row][move.col] = 'white'; // 駒を置く
                    flipPieces(move.row, move.col, 'white'); // 駒を反転させる
                    updateBoard(); // 盤面を更新
                }
                switchPlayer(); // プレイヤーを切り替える
            }

            // 指定した色が置けるかどうかを確認する関数
            function canPlacePiece(row, col, color) {
                if (boardState[row][col] !== null) return false;  // 既に駒がある場合は置けない

                const opponentColor = color === 'black' ? 'white' : 'black';
                const directions = [
                    [0, 1], [1, 1], [1, 0], [1, -1],
                    [0, -1], [-1, -1], [-1, 0], [-1, 1]
                ];  // 8方向を表す

                return directions.some(([dRow, dCol]) =>
                    hasFlippablePieces(row, col, dRow, dCol, color, opponentColor)
                );
            }

            // 指定した方向に反転可能な駒があるかどうかを確認する関数
            function hasFlippablePieces(row, col, dRow, dCol, color, opponentColor) {
                let r = row + dRow;
                let c = col + dCol;
                let hasOpponent = false;

                while (r >= 0 && r < boardSize && c >= 0 && c < boardSize) {
                    if (boardState[r][c] === opponentColor) {
                        hasOpponent = true;  // 相手の駒を見つけた
                    } else if (boardState[r][c] === color && hasOpponent) {
                        return true;  // 自分の色に戻った場合、かつ一つ以上の相手の駒を挟んでいればtrue
                    } else {
                        return false;  // 空のセルにぶつかった、または相手の駒を挟んでいない
                    }
                    r += dRow;
                    c += dCol;
                }
                return false;  // 盤外に出たか、条件を満たさない場合
            }

            // 駒を反転させる関数
            function flipPieces(row, col, color) {
                const opponentColor = color === 'black' ? 'white' : 'black';
                const directions = [
                    [0, 1], [1, 1], [1, 0], [1, -1],
                    [0, -1], [-1, -1], [-1, 0], [-1, 1]
                ];

                directions.forEach(([dRow, dCol]) => {
                    let r = row + dRow;
                    let c = col + dCol;
                    let piecesToFlip = [];

                    while (r >= 0 && r < boardSize && c >= 0 && c < boardSize && boardState[r][c] === opponentColor) {
                        piecesToFlip.push([r, c]);
                        r += dRow;
                        c += dCol;
                    }

                    // この方向が反転可能か確認(最後に自分の色の駒がある)
                    if (r >= 0 && r < boardSize && c >= 0 && c < boardSize && boardState[r][c] === color) {
                        piecesToFlip.forEach(([fr, fc]) => {
                            boardState[fr][fc] = color; // 駒を反転
                        });
                    }
                });

                updateBoard(); // 盤面を更新
            }

            // 盤面の更新を行う関数
            function updateBoard() {
                for (let i = 0; i < boardSize; i++) {
                    for (let j = 0; j < boardSize; j++) {
                        const cell = document.querySelector(`.cell[data-row="${i}"][data-col="${j}"]`);
                        if (boardState[i][j] === 'black') {
                            cell.innerHTML = '<div class="piece black"></div>';
                        } else if (boardState[i][j] === 'white') {
                            cell.innerHTML = '<div class="piece white"></div>';
                        } else {
                            cell.innerHTML = '';
                        }
                    }
                }
            }

            // ルーレットを開始する関数
            function startRoulette() {
                // ルーレットが既に起動していない場合のみ、ルーレットを開始
                if (!rouletteInterval) {
                    rouletteInterval = setInterval(() => {
                        document.getElementById('rouletteButton').click();
                    }, rouletteDelay);
                }
            }

            // セルをマークしてビンゴ成立チェックを行う関数
            function markBingo(number) {
                const row = Math.floor((number - 1) / boardSize);
                const col = (number - 1) % boardSize;
                const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
                cell.classList.add('marked');  // ビンゴマークのスタイルを適用
                checkBingo();  // ビンゴ成立チェック
            }

            // ビンゴ成立をチェックする関数
            function checkBingo() {
                // 省略:ビンゴ成立のチェックロジック
            }

            // プレイヤーを切り替える関数
            function switchPlayer() {
                currentPlayer = currentPlayer === 'black' ? 'white' : 'black';
            }

            // 指定した色の合法手を取得する関数
            function getLegalMoves(color) {
                let moves = [];
                for (let row = 0; row < boardSize; row++) {
                    for (let col = 0; col < boardSize; col++) {
                        if (boardState[row][col] === null && canPlacePiece(row, col, color)) {
                            moves.push({ row: row, col: col });
                        }
                    }
                }
                return moves;
            }

            function handleCellClick(row, col) {
                // ルーレットの結果を取得
                let rouletteResultElement = document.getElementById('rouletteResult');
                if (rouletteResultElement) {
                    // 現在のプレイヤーが駒を置くことができる場合のみ処理する
                    if (canPlacePiece(row, col, currentPlayer)) {
                        boardState[row][col] = currentPlayer; // 駒を置く
                        flipPieces(row, col, currentPlayer); // 駒を反転させる
                        updateBoard(); // 盤面を更新

                        // ルーレットの結果が数字であることを確認
                        let rouletteResultMatch = rouletteResultElement.textContent.match(/\d+/);
                        if (rouletteResultMatch) {
                            markBingo(parseInt(rouletteResultMatch[0]));  // ビンゴマーキング関数を呼び出す
                        }

                        switchPlayer(); // プレイヤーを切り替える
                        startTurn(); // 次のターンを開始
                    }
                }
            }

            // ルーレットボタンがクリックされたときの処理を行う関数
            document.getElementById('rouletteButton').addEventListener('click', () => {
                let randomNumber = Math.floor(Math.random() * (boardSize * boardSize)) + 1;
                document.getElementById('rouletteResult').textContent = `ルーレット結果: ${randomNumber}`;
            });

            initBoard(); // ゲームボードの初期化
        });
    </script>
</body>

</html>