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.
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:
- Copy the entire code into a new
.htmlfile - Open it in any web browser
- Click cells to place stones
- 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