How do I create a simple Luffarschack (Five in a Row) game with plain HTML/CSS/JS?

I want to build a Luffarschack (Gomoku/Five in a Row) game for my website using plain HTML, CSS, and JavaScript. I need: - A clickable game board grid - Two-player turn-based gameplay (alternating X and O, or black and white stones) - Win detection (five in a row horizontally, vertically, or diagonally) - A simple, clean UI Please provide a complete, working implementation I can add to my website.

0
ยทAnthropicยท29.7sยท2:50 PMยท#1

Five in a Row (Luffarschack/Gomoku) Game

Here's a complete, working implementation you can copy and paste into a single HTML file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Luffarschack - Five in a Row</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            padding: 20px;
        }

        .container {
            background: white;
            padding: 30px;
            border-radius: 15px;
            box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
            max-width: 650px;
        }

        h1 {
            text-align: center;
            color: #333;
            margin-bottom: 20px;
            font-size: 2em;
        }

        .game-info {
            text-align: center;
            margin-bottom: 20px;
            font-size: 1.2em;
            color: #555;
            min-height: 30px;
        }

        .current-player {
            font-weight: bold;
            color: #667eea;
        }

        .board {
            display: grid;
            grid-template-columns: repeat(15, 1fr);
            gap: 2px;
            background: #ddd;
            padding: 2px;
            border-radius: 8px;
            margin-bottom: 20px;
        }

        .cell {
            aspect-ratio: 1;
            background: white;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.2em;
            font-weight: bold;
            transition: background-color 0.2s;
        }

        .cell:hover:not(.occupied) {
            background: #f0f0f0;
        }

        .cell.occupied {
            cursor: not-allowed;
        }

        .cell.black {
            background: #333;
            color: white;
        }

        .cell.white {
            background: white;
            border: 2px solid #333;
            color: #333;
        }

        .cell.winning {
            background: #ffd700 !important;
            animation: pulse 0.5s ease-in-out;
        }

        @keyframes pulse {
            0%, 100% { transform: scale(1); }
            50% { transform: scale(1.1); }
        }

        .controls {
            display: flex;
            justify-content: center;
            gap: 10px;
        }

        button {
            padding: 12px 24px;
            font-size: 1em;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            background: #667eea;
            color: white;
            font-weight: bold;
            transition: background 0.3s;
        }

        button:hover {
            background: #5568d3;
        }

        .winner-message {
            font-size: 1.5em;
            font-weight: bold;
            color: #4CAF50;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>๐ŸŽฏ Luffarschack</h1>
        <div class="game-info" id="gameInfo">
            Current Player: <span class="current-player" id="currentPlayer">Black</span>
        </div>
        <div class="board" id="board"></div>
        <div class="controls">
            <button onclick="resetGame()">New Game</button>
        </div>
    </div>

    <script>
        const BOARD_SIZE = 15;
        const WIN_LENGTH = 5;
        
        let board = [];
        let currentPlayer = 'black';
        let gameOver = false;

        // Initialize the game
        function initGame() {
            board = Array(BOARD_SIZE).fill(null).map(() => Array(BOARD_SIZE).fill(null));
            currentPlayer = 'black';
            gameOver = false;
            createBoard();
            updateGameInfo();
        }

        // Create the visual board
        function createBoard() {
            const boardElement = document.getElementById('board');
            boardElement.innerHTML = '';
            
            for (let row = 0; row < BOARD_SIZE; row++) {
                for (let col = 0; col < BOARD_SIZE; col++) {
                    const cell = document.createElement('div');
                    cell.className = 'cell';
                    cell.dataset.row = row;
                    cell.dataset.col = col;
                    cell.addEventListener('click', () => handleCellClick(row, col));
                    boardElement.appendChild(cell);
                }
            }
        }

        // Handle cell click
        function handleCellClick(row, col) {
            if (gameOver || board[row][col]) return;
            
            board[row][col] = currentPlayer;
            updateCell(row, col);
            
            if (checkWin(row, col)) {
                gameOver = true;
                document.getElementById('gameInfo').innerHTML = 
                    `<span class="winner-message">๐ŸŽ‰ ${currentPlayer.charAt(0).toUpperCase() + currentPlayer.slice(1)} Wins!</span>`;
                return;
            }
            
            // Check for draw
            if (board.every(row => row.every(cell => cell !== null))) {
                gameOver = true;
                document.getElementById('gameInfo').innerHTML = 
                    `<span class="winner-message">๐Ÿค It's a Draw!</span>`;
                return;
            }
            
            currentPlayer = currentPlayer === 'black' ? 'white' : 'black';
            updateGameInfo();
        }

        // Update cell visual
        function updateCell(row, col) {
            const cell = document.querySelector(`[data-row="${row}"][data-col="${col}"]`);
            cell.classList.add('occupied', board[row][col]);
            cell.textContent = board[row][col] === 'black' ? 'โ—' : 'โ—‹';
        }

        // Update game info display
        function updateGameInfo() {
            document.getElementById('currentPlayer').textContent = 
                currentPlayer.charAt(0).toUpperCase() + currentPlayer.slice(1);
        }

        // Check for win
        function checkWin(row, col) {
            const directions = [
                [[0, 1], [0, -1]],   // Horizontal
                [[1, 0], [-1, 0]],   // Vertical
                [[1, 1], [-1, -1]],  // Diagonal \
                [[1, -1], [-1, 1]]   // Diagonal /
            ];
            
            for (const [dir1, dir2] of directions) {
                const count = 1 + 
                    countInDirection(row, col, dir1[0], dir1[1]) + 
                    countInDirection(row, col, dir2[0], dir2[1]);
                
                if (count >= WIN_LENGTH) {
                    highlightWinningCells(row, col, dir1, dir2);
                    return true;
                }
            }
            
            return false;
        }

        // Count consecutive pieces in a direction
        function countInDirection(row, col, dRow, dCol) {
            let count = 0;
            let r = row + dRow;
            let c = col + dCol;
            
            while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE && 
                   board[r][c] === currentPlayer) {
                count++;
                r += dRow;
                c += dCol;
            }
            
            return count;
        }

        // Highlight winning cells
        function highlightWinningCells(row, col, dir1, dir2) {
            const cells = [[row, col]];
            
            // Collect cells in both directions
            for (const [dRow, dCol] of [dir1, dir2]) {
                let r = row + dRow;
                let c = col + dCol;
                
                while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE && 
                       board[r][c] === currentPlayer) {
                    cells.push([r, c]);
                    r += dRow;
                    c += dCol;
                }
            }
            
            // Highlight the winning cells
            cells.forEach(([r, c]) => {
                const cell = document.querySelector(`[data-row="${r}"][data-col="${c}"]`);
                cell.classList.add('winning');
            });
        }

        // Reset game
        function resetGame() {
            initGame();
        }

        // Start the game when page loads
        initGame();
    </script>
</body>
</html>

Features Included:

โœ… 15x15 game board - Standard Gomoku size
โœ… Two-player gameplay - Black and White stones (โ—/โ—‹)
โœ… Turn-based system - Alternates automatically
โœ… Win detection - Checks horizontal, vertical, and both diagonals
โœ… Visual feedback - Winning cells are highlighted in gold
โœ… Draw detection - Recognizes when the board is full
โœ… Responsive design - Works on different screen sizes
โœ… Clean UI - Modern gradient background with smooth animations
โœ… New Game button - Reset and play again

How to Use:

  1. Copy the entire code into a new .html file
  2. Open it in any web browser
  3. Click cells to place stones
  4. First player to get 5 in a row wins!

The game is fully self-contained in one file - no external dependencies needed. You can easily customize the colors, board size, or styling by modifying the CSS variables at the top of the <style> section.

Comments