Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fibonacci Game for interactive learning #1184

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
47 changes: 47 additions & 0 deletions FibonacciGame/Drotum/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Fibonacci Game

Welcome to the **Fibonacci Game**, an interactive and fun way to learn about the Fibonacci sequence! This game is designed to teach players the fundamentals of the Fibonacci sequence through engaging gameplay, suitable for all ages.

## Table of Contents
- [About the Game](#about-the-game)
- [How to Play](#how-to-play)
- [Features](#features)
- [Installation](#installation)
- [Technologies Used](#technologies-used)
- [Contributing](#contributing)
- [License](#license)

## About the Game
The Fibonacci sequence is a series of numbers where each number is the sum of the two preceding ones, starting from 0 and 1. This game introduces players to the sequence through:
- Interactive puzzles
- Challenges that involve identifying or calculating Fibonacci numbers
- Levels that progressively increase in difficulty

The goal is to make learning math concepts both fun and intuitive!

## How to Play
1. **Start the Game**: Launch the game and choose a difficulty level to begin.
2. **Understand the Task**: Click on the Fibonacci numbers in the correct order as they appear on the screen to advance to the next level.
3. **Solve the Challenge**: Use your knowledge of the Fibonacci sequence to select the correct numbers before time runs out.
4. **Progress**: Advance to higher levels as you successfully complete each challenge.
5. **Restart Anytime**: Use the "Restart Game" button to reset and start over.

## Features
- **Educational Gameplay**: Learn the Fibonacci sequence through practical and engaging challenges.
- **Levels and Rewards**: Progress through levels with increasing complexity.
- **User-Friendly Interface**: Simple and intuitive design for players of all ages.
- **Difficulty Settings**: Choose from Easy, Medium, or Hard difficulty levels.
- **Timer and Score Tracking**: Track your performance with a timer and score system.

## Technologies Used
- **Frontend**: HTML, CSS, JavaScript
- **Framework**: React
- **Other Tools**: Node.js



---

Enjoy learning and mastering the Fibonacci sequence with our game! If you have any questions or feedback, feel free to reach out.

Happy Gaming! 🎮
275 changes: 275 additions & 0 deletions FibonacciGame/Drotum/game.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
// Memoization for Fibonacci calculation
const fibCache = {};
function fibonacci(n) {
if (n <= 1) return n;
if (fibCache[n]) return fibCache[n];
fibCache[n] = fibonacci(n - 1) + fibonacci(n - 2);
return fibCache[n];
}

let level = 1;
let currentSequence = [];
let clickedNumbers = [];
let correctFibIndex = 0;
let gameActive = true;
let timerInterval;
let timeLeft = 60; // Default time in seconds
let gamePaused = false;
const numbers = [];
let startFromIndex = 5; // Will be randomized per level

// Difficulty settings
const difficultySettings = {
easy: { distractors: 5, time: 90 },
medium: { distractors: 10, time: 60 },
hard: { distractors: 20, time: 30 }
};

// HTML Elements
const gameBoard = document.getElementById('gameBoard');
const levelDisplay = document.getElementById('levelDisplay');
const messageDisplay = document.getElementById('message');
const correctSequenceDisplay = document.getElementById('correctSequence');
const timerDisplay = document.getElementById('timerDisplay');
const pauseButton = document.getElementById('pauseButton');
const difficultySelect = document.getElementById('difficulty');
const leaderboardList = document.getElementById('leaderboardList');
const restartButton = document.getElementById('restartButton');

// Sound Elements
const correctSound = document.getElementById('correctSound');
const incorrectSound = document.getElementById('incorrectSound');
const levelUpSound = document.getElementById('levelUpSound');

// Leaderboard
let leaderboard = JSON.parse(localStorage.getItem('fibLeaderboard')) || [];

// Function to update the leaderboard display
function updateLeaderboard() {
leaderboardList.innerHTML = '';
leaderboard.forEach(entry => {
const li = document.createElement('li');
li.textContent = `Level ${entry.level} - Time: ${entry.time}s`;
leaderboardList.appendChild(li);
});
}

// Function to add a new score to the leaderboard
function addToLeaderboard(levelAchieved, timeTaken) {
leaderboard.push({ level: levelAchieved, time: timeTaken });
leaderboard.sort((a, b) => {
if (b.level === a.level) return a.time - b.time;
return b.level - a.level;
});
leaderboard = leaderboard.slice(0, 10);
localStorage.setItem('fibLeaderboard', JSON.stringify(leaderboard));
updateLeaderboard();
}

// Function to generate a Fibonacci sequence for the level, starting from a specified number
function generateFibonacciSequence(level, startFromIndex) {
const sequence = [];
for (let i = startFromIndex; i < startFromIndex + level + 5; i++) {
sequence.push(fibonacci(i));
}
return sequence;
}

// Function to generate non-Fibonacci numbers close to the Fibonacci sequence
function generateNonFibonacciNumbers(count, fibNumbers) {
const nonFib = [];
while (nonFib.length < count) {
const randomFib = fibNumbers[Math.floor(Math.random() * fibNumbers.length)];
const offset = Math.floor(Math.random() * 10) - 5; // Random offset close to Fibonacci numbers
const candidate = randomFib + offset;
if (!fibNumbers.includes(candidate) && candidate > 0 && !nonFib.includes(candidate)) {
nonFib.push(candidate);
}
}
return nonFib;
}

// Function to create number elements (static and non-overlapping)
function createNumberElement(number, isFib = true, usedPositions) {
const numberElement = document.createElement('div');
numberElement.classList.add('number');
numberElement.textContent = number;

const size = isFib ? (50 + Math.random() * 50) : (30 + Math.random() * 30);
numberElement.style.width = `${size}px`;
numberElement.style.height = numberElement.style.width;

let validPosition = false;
let x, y;

// Find a position that doesn't overlap with others
while (!validPosition) {
x = Math.random() * 80; // 80% width of the game board
y = Math.random() * 80; // 80% height of the game board
validPosition = !usedPositions.some(pos => {
const dx = pos.x - x;
const dy = pos.y - y;
return Math.sqrt(dx * dx + dy * dy) < 10; // Minimum distance of 10% to avoid overlap
});
}

numberElement.style.position = 'absolute';
numberElement.style.left = `${x}%`;
numberElement.style.top = `${y}%`;
usedPositions.push({ x, y }); // Save the position

return numberElement;
}

// Function to display Fibonacci and distractor numbers
function displayNumbers() {
const fibNumbers = currentSequence;
const difficulty = difficultySelect.value;
const distractors = generateNonFibonacciNumbers(difficultySettings[difficulty].distractors, fibNumbers);
const usedPositions = [];

// Clear any existing numbers
gameBoard.innerHTML = '';

// Generate Fibonacci numbers
fibNumbers.forEach((number) => {
const element = createNumberElement(number, true, usedPositions);
element.addEventListener('click', () => handleNumberClick(number, element));
gameBoard.appendChild(element);
});

// Generate distractor numbers
distractors.forEach((number) => {
const element = createNumberElement(number, false, usedPositions);
gameBoard.appendChild(element);
});
}

// Handle click on numbers
function handleNumberClick(number, element) {
if (!gameActive) return;

if (number === currentSequence[correctFibIndex]) {
clickedNumbers.push(number);
correctFibIndex++;
correctSound.currentTime = 0;
correctSound.play();
correctSequenceDisplay.textContent = `Correct Sequence: ${clickedNumbers.join(', ')}`;
gameBoard.removeChild(element);

if (clickedNumbers.length === currentSequence.length) {
gameActive = false;
clearInterval(timerInterval);
levelUpSound.play();
setTimeout(() => nextLevel(), 1000);
}
} else {
incorrectSound.currentTime = 0;
incorrectSound.play();
messageDisplay.textContent = "Incorrect, try again!";
}
}

// Move to the next level
function nextLevel() {
addToLeaderboard(level, timeLeft);
level++;
levelDisplay.textContent = `Level: ${level}`;
clickedNumbers = [];
correctFibIndex = 0;
const difficulty = difficultySelect.value;
timeLeft = difficultySettings[difficulty].time;

// Randomize starting Fibonacci numbers for the sequence
startFromIndex = Math.floor(Math.random() * 10) + 3; // Randomize between index 3 and 12
currentSequence = generateFibonacciSequence(level, startFromIndex);

gameActive = true;
correctSequenceDisplay.textContent = `Correct Sequence: ${currentSequence[0]}, ${currentSequence[1]}`;
displayNumbers();
resetTimer();
}

// Timer functions
function startTimer() {
timerDisplay.textContent = `Time: ${timeLeft}s`;
timerInterval = setInterval(() => {
if (!gameActive || gamePaused) return;
timeLeft--;
timerDisplay.textContent = `Time: ${timeLeft}s`;
if (timeLeft <= 0) {
clearInterval(timerInterval);
endGame();
}
}, 1000);
}

function resetTimer() {
clearInterval(timerInterval);
startTimer();
}

// Handle Pause/Resume Button
pauseButton.addEventListener('click', () => {
if (!gameActive) return;
if (gamePaused) {
gamePaused = false;
pauseButton.textContent = "Pause";
resetTimer();
} else {
gamePaused = true;
pauseButton.textContent = "Resume";
clearInterval(timerInterval);
}
});

// Handle Difficulty Change
difficultySelect.addEventListener('change', () => {
const difficulty = difficultySelect.value;
timeLeft = difficultySettings[difficulty].time;
if (gameActive && !gamePaused) {
resetTimer();
}
});

// Handle game end
function endGame() {
gameActive = false;
messageDisplay.textContent = "Time's up! Game Over.";
restartButton.style.display = "block"; // Show the restart button
}

// Handle restart button click
restartButton.addEventListener('click', () => {
restartButton.style.display = "none";
startGame(true);
updateLeaderboard();
});

// Start the game
function startGame(isRestart = false) {
// Reset level and other state variables
level = 1;
const difficulty = difficultySelect.value;
timeLeft = difficultySettings[difficulty].time;
clickedNumbers = [];
correctFibIndex = 0;
gameActive = true;

// Randomize the Fibonacci sequence's start index and generate a new sequence
startFromIndex = Math.floor(Math.random() * 10) + 3; // Randomize starting point
currentSequence = generateFibonacciSequence(level, startFromIndex);

correctSequenceDisplay.textContent = `Correct Sequence: ${currentSequence[0]}, ${currentSequence[1]}`;
displayNumbers();

if (isRestart) {
resetTimer();
}

if (!isRestart) {
addToLeaderboard(level, timeLeft);
}
}

startGame();
57 changes: 57 additions & 0 deletions FibonacciGame/Drotum/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fibonacci Click Challenge</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- Game container -->
<div class="game-container">
<h1>Fibonacci Click Challenge</h1>
<p>Click the Fibonacci numbers in the correct order to advance to the next stage!</p>

<div class="controls">
<div id="levelDisplay" class="level-display">Level: 1</div>
<div id="timerDisplay" class="timer-display">Time: 60s</div>
<button id="pauseButton">Pause</button>
<div class="difficulty-settings">
<label for="difficulty">Difficulty:</label>
<select id="difficulty">
<option value="easy">Easy</option>
<option value="medium" selected>Medium</option>
<option value="hard">Hard</option>
</select>
</div>
</div>

<div id="gameBoard" class="game-board">
<!-- Floating numbers will appear here -->
</div>

<div id="message" class="message"></div>

<div id="correctSequence" class="correct-sequence">Correct Sequence: </div>

<!-- Restart Button moved between Correct Sequence and Leaderboard -->
<button id="restartButton" style="display: block; margin: 20px auto; padding: 10px 20px; font-size: 18px; background-color: #0097e6; color: white; border: none; border-radius: 5px; cursor: pointer;">
Restart Game
</button>

<div class="leaderboard">
<h2>Leaderboard</h2>
<ol id="leaderboardList">
<!-- Leaderboard entries will be added here -->
</ol>
</div>
</div>

<!-- Sound Effects -->
<audio id="correctSound" src="sounds/correct.mp3"></audio>
<audio id="incorrectSound" src="sounds/incorrect.mp3"></audio>
<audio id="levelUpSound" src="sounds/levelup.mp3"></audio>

<script src="game.js"></script>
</body>
</html>
Binary file added FibonacciGame/Drotum/sounds/correct.mp3
Binary file not shown.
Binary file added FibonacciGame/Drotum/sounds/incorrect.mp3
Binary file not shown.
Binary file added FibonacciGame/Drotum/sounds/levelup.mp3
Binary file not shown.
Loading