-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
21c8dc6
commit 500d301
Showing
10 changed files
with
461 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Maze Game - DFS & Prim Algorithms | ||
|
||
A simple yet engaging maze game built with HTML, CSS, and JavaScript. Navigate through a dynamically generated maze to find the exit. Each time you play, a new maze is created, ensuring a unique experience. The game is designed to be lightweight and easy to play, making it suitable for all age groups. | ||
|
||
## Features | ||
|
||
- **Randomized Maze Generation**: Each game loads a new maze, thanks to the Depth-First Search (DFS) and Prim algorithms used for maze generation. | ||
- **Player Navigation**: Use the arrow keys to move up, down, left, or right within the maze. | ||
- **Start and Exit Indicators**: The game visually indicates the starting point and the exit. Reach the green block to win. | ||
- **Regenerate Maze**: A button allows players to generate a new maze at any time without reloading the page. | ||
|
||
## Technologies Used | ||
|
||
- **HTML**: Structure of the game canvas and control elements. | ||
- **CSS**: Styling of the game canvas and alignment of game elements. | ||
- **JavaScript**: Game logic, including maze generation, player movement, collision detection, and UI interaction. | ||
- **Python**: There is also a Python implementation of the maze generation algorithm using the Depth-First Search (DFS) algorithm. | ||
|
||
## Maze Generation Algorithm | ||
|
||
The maze is generated using a randomized version of the Depth-First Search (DFS) & Prim algorithms. This algorithm starts at a random cell, marks it as part of the maze, and recursively explores unvisited neighbors, carving out a path. The process continues until all cells are visited, resulting in a perfect maze with a single solution. | ||
|
||
## Setup | ||
|
||
1. Clone the repository to your local machine. | ||
2. Open the `index.html` file in a modern web browser. | ||
3. Alternatively, you can run the Python implementation of the maze generation algorithm by executing the `maze.py` file. | ||
|
||
```bash | ||
python maze-gen.py | ||
``` | ||
|
||
Before running the Python script, ensure that you have Python and Pygame installed on your machine. | ||
```bash | ||
pip install pygame | ||
``` | ||
|
||
## Usage | ||
|
||
- Navigate through the maze using the **arrow keys**. | ||
- Click the **Regenerate Maze** button below the canvas to start a new game with a new maze layout. | ||
|
||
## Contribution | ||
|
||
Feel free to fork the repository and submit pull requests to contribute to the game's development. Whether it's adding new features, improving the maze generation algorithm, or enhancing the game's UI/UX, all contributions are welcome. | ||
|
||
## License | ||
|
||
This project is open-source and available under the MIT License. | ||
|
||
## Contact | ||
|
||
You can reach out to me at [[email protected]](mailto:[email protected]). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>The Maze Game</title> | ||
<link rel="stylesheet" href="src/css/style.css"> | ||
<link rel="icon" type="image/x-icon" href="utils/favicon.ico"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
</head> | ||
<body> | ||
<header> | ||
<h1>The Maze Game</h1> | ||
<p>A thrilling adventure through dynamic mazes</p> | ||
</header> | ||
<div class="game-container"> | ||
<canvas id="mazeCanvas"></canvas> | ||
<button id="regenerateMaze" title="Feeling lost? Click to regenerate the maze">Regenerate Maze</button> | ||
</div> | ||
<script src="src/js/game.js"></script> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400;600&display=swap'); | ||
|
||
* { | ||
box-sizing: border-box; | ||
} | ||
|
||
body, html { | ||
height: 100%; | ||
margin: 0; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
background-color: #000; | ||
font-family: "Poppins", sans-serif; | ||
padding: 0; | ||
flex-direction: column; | ||
text-align: center; | ||
} | ||
|
||
header { | ||
margin: 20px 0; | ||
} | ||
|
||
.game-container { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
} | ||
|
||
canvas { | ||
max-width: 100%; | ||
height: auto; | ||
} | ||
|
||
@media (max-width: 800px) { | ||
canvas { | ||
width: 100%; | ||
height: auto; | ||
} | ||
} | ||
|
||
|
||
canvas { | ||
background-color: #fff; | ||
display: block; | ||
margin-bottom: 10px; | ||
|
||
} | ||
|
||
.game-container { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
} | ||
|
||
#regenerateMaze { | ||
font-family: "Poppins", sans-serif; | ||
font-size: 16px; | ||
} | ||
|
||
#regenerateMaze:hover { | ||
cursor: pointer; | ||
} | ||
|
||
header { | ||
text-align: center; | ||
margin-bottom: 20px; | ||
color: #fff; | ||
} | ||
|
||
header h1 { | ||
margin: 0; | ||
padding: 10px; | ||
color: #fff; | ||
font-size: 2.5em; | ||
} | ||
|
||
header h2 { | ||
margin-top: 5px; | ||
font-size: 1.5em; | ||
color: #fff; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
document.getElementById('regenerateMaze').addEventListener('click', () => { | ||
window.location.reload(); | ||
}); | ||
|
||
const canvas = document.getElementById('mazeCanvas'); | ||
const ctx = canvas.getContext('2d'); | ||
|
||
canvas.width = 800; | ||
canvas.height = 600; | ||
|
||
const rows = 15; | ||
const cols = 20; | ||
const cellSize = canvas.width / cols; | ||
const maze = []; | ||
|
||
for (let y = 0; y < rows; y++) { | ||
maze[y] = []; | ||
for (let x = 0; x < cols; x++) { | ||
maze[y][x] = 1; | ||
} | ||
} | ||
|
||
const player = { | ||
x: 0, | ||
y: 0, | ||
size: cellSize / 2, | ||
color: 'red' | ||
}; | ||
|
||
let exit = { | ||
x: cols - 1, | ||
y: rows - 1, | ||
size: cellSize, | ||
color: 'green' | ||
}; | ||
|
||
function carvePassagesFrom(x, y) { | ||
const directions = [ | ||
[1, 0], | ||
[-1, 0], | ||
[0, 1], | ||
[0, -1] | ||
]; | ||
|
||
directions.sort(() => Math.random() - 0.5); | ||
|
||
for (let i = 0; i < directions.length; i++) { | ||
const dx = directions[i][0]; | ||
const dy = directions[i][1]; | ||
const nx = x + dx * 2; | ||
const ny = y + dy * 2; | ||
|
||
if (nx >= 0 && nx < cols && ny >= 0 && ny < rows && maze[ny][nx] === 1) { | ||
maze[y + dy][x + dx] = 0; | ||
maze[ny][nx] = 0; | ||
carvePassagesFrom(nx, ny); | ||
} | ||
} | ||
} | ||
|
||
maze[0][0] = 0; | ||
carvePassagesFrom(0, 0); | ||
maze[rows - 1][cols - 1] = 0; | ||
|
||
function drawMaze() { | ||
for (let y = 0; y < rows; y++) { | ||
for (let x = 0; x < cols; x++) { | ||
ctx.fillStyle = maze[y][x] === 1 ? 'black' : 'white'; | ||
ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize); | ||
} | ||
} | ||
} | ||
|
||
function drawPlayer() { | ||
ctx.fillStyle = player.color; | ||
ctx.fillRect(player.x * cellSize + (cellSize - player.size) / 2, player.y * cellSize + (cellSize - player.size) / 2, player.size, player.size); | ||
} | ||
|
||
function drawExit() { | ||
ctx.fillStyle = exit.color; | ||
ctx.fillRect(exit.x * cellSize, exit.y * cellSize, exit.size, exit.size); | ||
} | ||
|
||
function checkCollision(x, y) { | ||
return maze[y][x] === 1; | ||
} | ||
|
||
function movePlayer(dx, dy) { | ||
const newX = player.x + dx; | ||
const newY = player.y + dy; | ||
if (newX >= 0 && newX < cols && newY >= 0 && newY < rows && !checkCollision(newX, newY)) { | ||
player.x = newX; | ||
player.y = newY; | ||
} | ||
} | ||
|
||
function checkWin() { | ||
if (player.x === exit.x && player.y === exit.y) { | ||
alert("Congratulations, you've escaped the maze! Now we dare you to do it again!"); | ||
window.location.reload(); | ||
} | ||
} | ||
|
||
function draw() { | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
drawMaze(); | ||
drawPlayer(); | ||
drawExit(); | ||
requestAnimationFrame(draw); | ||
} | ||
|
||
draw(); | ||
|
||
window.addEventListener('keydown', (e) => { | ||
switch(e.key) { | ||
case 'ArrowUp': movePlayer(0, -1); break; | ||
case 'ArrowDown': movePlayer(0, 1); break; | ||
case 'ArrowLeft': movePlayer(-1, 0); break; | ||
case 'ArrowRight': movePlayer(1, 0); break; | ||
} | ||
checkWin(); | ||
}); | ||
|
||
let touchStartX = 0; | ||
let touchStartY = 0; | ||
let touchEndX = 0; | ||
let touchEndY = 0; | ||
|
||
canvas.addEventListener('touchstart', (e) => { | ||
touchStartX = e.changedTouches[0].screenX; | ||
touchStartY = e.changedTouches[0].screenY; | ||
}, false); | ||
|
||
canvas.addEventListener('touchend', (e) => { | ||
touchEndX = e.changedTouches[0].screenX; | ||
touchEndY = e.changedTouches[0].screenY; | ||
handleTouchMove(); | ||
}, false); | ||
|
||
function handleTouchMove() { | ||
const dx = touchEndX - touchStartX; | ||
const dy = touchEndY - touchStartY; | ||
if (Math.abs(dx) > Math.abs(dy)) { | ||
if (dx > 0) { | ||
movePlayer(1, 0); | ||
} | ||
else { | ||
movePlayer(-1, 0); | ||
} | ||
} | ||
else { | ||
if (dy > 0) { | ||
movePlayer(0, 1); | ||
} | ||
else { | ||
movePlayer(0, -1); | ||
} | ||
} | ||
checkWin(); | ||
} |
Oops, something went wrong.