Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Ludo/charishma2k06/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Ludo App - JavaScript Mini Project

A turn-based digital adaptation of the classic board game Ludo, developed using vanilla HTML5, CSS3, and JavaScript.

## Features
- **Turn-based gameplay:** Supports 4 players (Red, Green, Yellow, Blue).
- **Dice Roll Mechanics:** Simulates 1–6 rolls with bonus turns awarded on rolling a 6.
- **Piece Movement & Base Exits:** Tokens exit the starting base when a 6 is rolled and travel clockwise around the track.
- **Capture Logic:** Landing on an opponent's token sends it back to their base.
- **Win Condition:** First player to bring their pieces home wins.

## Technologies Used
- HTML5
- CSS3 (CSS Grid & Flexbox)
- JavaScript (Vanilla ES6)

## How to Run Locally
1. Clone this repository or download the source files.
2. Open `index.html` directly in any web browser.
31 changes: 31 additions & 0 deletions Ludo/charishma2k06/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ludo Mini Project</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<h1>Ludo Game</h1>

<div class="control-panel">
<div class="status-box">
<span>Current Turn: </span>
<strong id="turn-indicator" class="turn-red">Red</strong>
</div>
<div class="dice-section">
<button id="roll-btn">Roll Dice</button>
<div id="dice-view" class="dice-display">🎲</div>
</div>
<p id="msg">Click "Roll Dice" to start!</p>
</div>

<!-- 15x15 Ludo Board Grid -->
<div id="board" class="ludo-board"></div>
</div>

<script src="script.js"></script>
</body>
</html>
186 changes: 186 additions & 0 deletions Ludo/charishma2k06/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
const BOARD_SIZE = 15;
const boardElement = document.getElementById("board");
const rollBtn = document.getElementById("roll-btn");
const diceView = document.getElementById("dice-view");
const turnIndicator = document.getElementById("turn-indicator");
const msgElement = document.getElementById("msg");

const PLAYERS = ["red", "green", "yellow", "blue"];
let currentTurnIdx = 0;
let lastRoll = 0;
let hasRolled = false;

// Common outer track coordinates (row, col)
const TRACK = [
[6, 1], [6, 2], [6, 3], [6, 4], [6, 5],
[5, 6], [4, 6], [3, 6], [2, 6], [1, 6], [0, 6],
[0, 7], [0, 8],
[1, 8], [2, 8], [3, 8], [4, 8], [5, 8],
[6, 9], [6, 10], [6, 11], [6, 12], [6, 13], [6, 14],
[7, 14], [8, 14],
[8, 13], [8, 12], [8, 11], [8, 10], [8, 9],
[9, 8], [10, 8], [11, 8], [12, 8], [13, 8], [14, 8],
[14, 7], [14, 6],
[13, 6], [12, 6], [11, 6], [10, 6], [9, 6],
[8, 5], [8, 4], [8, 3], [8, 2], [8, 1], [8, 0],
[7, 0], [6, 0]
];

// Token states: -1 means in base home, 0..51 are track positions, 52 is home goal
const gameState = {
red: { basePos: [2, 2], tokens: [-1, -1] },
green: { basePos: [2, 12], tokens: [-1, -1] },
yellow: { basePos: [12, 12], tokens: [-1, -1] },
blue: { basePos: [12, 2], tokens: [-1, -1] }
};

const START_OFFSETS = { red: 0, green: 13, yellow: 26, blue: 39 };

function initBoard() {
boardElement.innerHTML = "";
for (let r = 0; r < BOARD_SIZE; r++) {
for (let c = 0; c < BOARD_SIZE; c++) {
const cell = document.createElement("div");
cell.className = "cell";
cell.dataset.row = r;
cell.dataset.col = c;

if (r < 6 && c < 6) cell.classList.add("red-base");
else if (r < 6 && c > 8) cell.classList.add("green-base");
else if (r > 8 && c > 8) cell.classList.add("yellow-base");
else if (r > 8 && c < 6) cell.classList.add("blue-base");
else if (r >= 6 && r <= 8 && c >= 6 && c <= 8) cell.classList.add("center-cell");
else if (r === 7 && c > 0 && c < 6) cell.classList.add("red-path");
else if (c === 7 && r > 0 && r < 6) cell.classList.add("green-path");
else if (r === 7 && c > 8 && c < 14) cell.classList.add("yellow-path");
else if (c === 7 && r > 8 && r < 14) cell.classList.add("blue-path");

boardElement.appendChild(cell);
}
}
renderTokens();
}

function getCell(r, c) {
return document.querySelector(`[data-row='${r}'][data-col='${c}']`);
}

function renderTokens() {
document.querySelectorAll(".token").forEach((t) => t.remove());

PLAYERS.forEach((player) => {
gameState[player].tokens.forEach((stepPos, tIdx) => {
if (stepPos === 52) return; // Reached goal

const tokenEl = document.createElement("div");
tokenEl.className = `token ${player}`;
tokenEl.id = `${player}-token-${tIdx}`;

if (hasRolled && player === PLAYERS[currentTurnIdx]) {
if (canMoveToken(player, stepPos, lastRoll)) {
tokenEl.classList.add("clickable");
tokenEl.onclick = () => moveToken(player, tIdx);
}
}

let targetCell = null;
if (stepPos === -1) {
const [br, bc] = gameState[player].basePos;
targetCell = getCell(br, bc + tIdx);
} else {
const actualIdx = (stepPos + START_OFFSETS[player]) % TRACK.length;
const [tr, tc] = TRACK[actualIdx];
targetCell = getCell(tr, tc);
}

if (targetCell) targetCell.appendChild(tokenEl);
});
});
}

function canMoveToken(player, stepPos, roll) {
if (stepPos === -1) return roll === 6;
return stepPos + roll <= 52;
}

rollBtn.addEventListener("click", () => {
if (hasRolled) return;
lastRoll = Math.floor(Math.random() * 6) + 1;
diceView.textContent = lastRoll;
hasRolled = true;
rollBtn.disabled = true;

const currentPlayer = PLAYERS[currentTurnIdx];
const canAnyMove = gameState[currentPlayer].tokens.some((pos) =>
canMoveToken(currentPlayer, pos, lastRoll)
);

if (!canAnyMove) {
msgElement.textContent = `No moves possible for ${currentPlayer}. Turn switches.`;
setTimeout(switchTurn, 1000);
} else {
msgElement.textContent = `${currentPlayer.toUpperCase()} rolled a ${lastRoll}! Select a piece.`;
renderTokens();
}
});

function moveToken(player, tokenIdx) {
const currentPos = gameState[player].tokens[tokenIdx];
if (currentPos === -1) {
gameState[player].tokens[tokenIdx] = 0;
} else {
gameState[player].tokens[tokenIdx] = Math.min(52, currentPos + lastRoll);
}

// Check captures
checkCapture(player, gameState[player].tokens[tokenIdx]);

// Check win condition
if (gameState[player].tokens.every((pos) => pos === 52)) {
msgElement.textContent = `🎉 Player ${player.toUpperCase()} wins the game!`;
rollBtn.disabled = true;
renderTokens();
return;
}

if (lastRoll === 6) {
msgElement.textContent = `Rolled a 6! Roll again.`;
hasRolled = false;
rollBtn.disabled = false;
renderTokens();
} else {
switchTurn();
}
}

function checkCapture(activePlayer, pos) {
if (pos <= 0 || pos >= 52) return;
const activeActual = (pos + START_OFFSETS[activePlayer]) % TRACK.length;

PLAYERS.forEach((other) => {
if (other === activePlayer) return;
gameState[other].tokens.forEach((oPos, idx) => {
if (oPos > 0 && oPos < 52) {
const otherActual = (oPos + START_OFFSETS[other]) % TRACK.length;
if (activeActual === otherActual) {
gameState[other].tokens[idx] = -1;
msgElement.textContent = `${activePlayer.toUpperCase()} captured ${other.toUpperCase()}!`;
}
}
});
});
}

function switchTurn() {
currentTurnIdx = (currentTurnIdx + 1) % PLAYERS.length;
hasRolled = false;
rollBtn.disabled = false;

const nextPlayer = PLAYERS[currentTurnIdx];
turnIndicator.textContent = nextPlayer.charAt(0).toUpperCase() + nextPlayer.slice(1);
turnIndicator.className = `turn-${nextPlayer}`;
msgElement.textContent = `Turn switched to ${nextPlayer}. Roll the dice!`;
renderTokens();
}

initBoard();
137 changes: 137 additions & 0 deletions Ludo/charishma2k06/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

body {
background: #f0f2f5;
display: flex;
justify-content: center;
padding: 20px;
}

.container {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
}

h1 {
color: #333;
}

.control-panel {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
background: #fff;
padding: 14px 24px;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
}

.status-box {
font-size: 1.1rem;
}

.turn-red { color: #e53935; font-weight: bold; }
.turn-green { color: #43a047; font-weight: bold; }
.turn-yellow { color: #fbc02d; font-weight: bold; }
.turn-blue { color: #1e88e5; font-weight: bold; }

.dice-section {
display: flex;
align-items: center;
gap: 12px;
}

#roll-btn {
padding: 8px 18px;
font-size: 1rem;
font-weight: 600;
color: #fff;
background-color: #2e7d32;
border: none;
border-radius: 6px;
cursor: pointer;
transition: 0.2s ease;
}

#roll-btn:disabled {
background-color: #9e9e9e;
cursor: not-allowed;
}

.dice-display {
font-size: 2rem;
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid #ccc;
border-radius: 8px;
background: #fafafa;
}

#msg {
font-size: 0.95rem;
color: #555;
}

/* Board styling: 15x15 CSS Grid */
.ludo-board {
display: grid;
grid-template-columns: repeat(15, 32px);
grid-template-rows: repeat(15, 32px);
border: 4px solid #333;
background-color: #fff;
}

.cell {
border: 1px solid #ddd;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}

.cell.red-base { background-color: #ffebee; }
.cell.green-base { background-color: #e8f5e9; }
.cell.yellow-base { background-color: #fffde7; }
.cell.blue-base { background-color: #e3f2fd; }

.cell.red-path { background-color: #ef5350; }
.cell.green-path { background-color: #66bb6a; }
.cell.yellow-path { background-color: #ffee58; }
.cell.blue-path { background-color: #42a5f5; }

.cell.center-cell { background-color: #37474f; }

/* Token styles */
.token {
width: 22px;
height: 22px;
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.3);
cursor: pointer;
}

.token.clickable {
animation: pulse 1s infinite alternate;
}

@keyframes pulse {
from { transform: scale(1); }
to { transform: scale(1.25); }
}

.token.red { background-color: #d32f2f; }
.token.green { background-color: #2e7d32; }
.token.yellow { background-color: #fbc02d; }
.token.blue { background-color: #1976d2; }