-
Notifications
You must be signed in to change notification settings - Fork 183
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## Pull Request for PyVerse 💡 ### Requesting to submit a pull request to the PyVerse repository. --- #### Issue Title **Please enter the title of the issue related to your pull request.** [Code Addition Request]: Addition of a maze game in game development - [x] I have provided the issue title. --- #### Info about the Related Issue **What's the goal of the project?** To create a game using python *Describe the aim of the project.* To understand that games can be developed using python - [x] I have described the aim of the project. --- #### Name **Please mention your name.** Vuppu Chinmay - [x] I have provided my name. --- #### GitHub ID **Please mention your GitHub ID.** [*Enter your GitHub ID here.*](https://github.com/Chin-may02) - [x] I have provided my GitHub ID. --- #### Email ID **Please mention your email ID for further communication.** [email protected] - [x] I have provided my email ID. --- #### Identify Yourself **Mention in which program you are contributing (e.g., WoB, GSSOC, SSOC, SWOC).** - Contributor and gssoc-ext and hacktoberfest - [x] I have mentioned my participant role. --- #### Closes **Enter the issue number that will be closed through this PR.** *Closes: #668 - [x] I have provided the issue number. --- #### Describe the Add-ons or Changes You've Made **Give a clear description of what you have added or modified.** Game using python to solve a maze - [x] I have described my changes. --- #### Type of Change **Select the type of change:** - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Code style update (formatting, local variables) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update --- #### How Has This Been Tested? **Describe how your changes have been tested.** Locally ran it in my computer - [x] I have described my testing process. --- #### Checklist **Please confirm the following:** - [x] My code follows the guidelines of this project. - [x] I have performed a self-review of my own code. - [ ] I have commented my code, particularly wherever it was hard to understand. - [x] I have made corresponding changes to the documentation. - [x] My changes generate no new warnings. - [x] I have added things that prove my fix is effective or that my feature works. - [x] Any dependent changes have been merged and published in downstream modules.
- Loading branch information
Showing
2 changed files
with
220 additions
and
0 deletions.
There are no files selected for viewing
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,193 @@ | ||
import random | ||
import ipywidgets as widgets | ||
from IPython.display import display, clear_output, HTML | ||
import time | ||
|
||
def generate_maze(size): | ||
maze = [["#" for _ in range(size)] for _ in range(size)] | ||
|
||
def carve_passages(x, y): | ||
directions = [(0, 2), (2, 0), (0, -2), (-2, 0)] | ||
random.shuffle(directions) | ||
for dx, dy in directions: | ||
nx, ny = x + dx, y + dy | ||
if 1 <= nx < size - 1 and 1 <= ny < size - 1 and maze[nx][ny] == "#": | ||
maze[x + dx // 2][y + dy // 2] = " " | ||
maze[nx][ny] = " " | ||
carve_passages(nx, ny) | ||
|
||
maze[1][1] = " " | ||
carve_passages(1, 1) | ||
maze[size - 2][size - 2] = " " | ||
|
||
for _ in range(size // 2): | ||
x, y = random.randint(1, size - 2), random.randint(1, size - 2) | ||
if maze[x][y] == " ": | ||
maze[x][y] = "#" | ||
|
||
return maze | ||
|
||
def print_maze(maze, player_position): | ||
output = "" | ||
for i, row in enumerate(maze): | ||
line = "" | ||
for j, cell in enumerate(row): | ||
if (i, j) == player_position: | ||
line += "<span style='color: green;'>🧍</span>" | ||
else: | ||
line += "<span style='color: white;'>{}</span>".format(cell) | ||
output += line + "<br>" | ||
return output | ||
|
||
class MazeGame: | ||
def __init__(self): | ||
self.size = 0 | ||
self.maze = [] | ||
self.position = (1, 1) | ||
self.exit_point = None | ||
self.move_limit = 0 | ||
self.move_count = 0 | ||
self.user_path = [] | ||
self.desired_path = [] | ||
self.output_widget = widgets.Output() | ||
self.start_game() | ||
|
||
def start_game(self): | ||
clear_output(wait=True) | ||
print("🎮 Select difficulty level: ") | ||
print("1. Intermediate (11x11)") | ||
print("2. Hard (15x15)") | ||
print("3. Very Hard (21x21)") | ||
|
||
self.difficulty_dropdown = widgets.Dropdown( | ||
options=['1', '2', '3'], | ||
description='Difficulty:', | ||
) | ||
self.start_button = widgets.Button(description="Start Game") | ||
self.start_button.on_click(self.set_difficulty) | ||
|
||
display(self.difficulty_dropdown, self.start_button, self.output_widget) | ||
|
||
def set_difficulty(self, b): | ||
if self.difficulty_dropdown.value == '1': | ||
self.size = 11 | ||
self.move_limit = 20 | ||
elif self.difficulty_dropdown.value == '2': | ||
self.size = 15 | ||
self.move_limit = 30 | ||
else: | ||
self.size = 21 | ||
self.move_limit = 40 | ||
|
||
self.maze = generate_maze(self.size) | ||
self.exit_point = (self.size - 2, self.size - 2) | ||
self.position = (1, 1) | ||
self.move_count = 0 | ||
self.user_path = [] | ||
self.desired_path = self.calculate_desired_path() | ||
|
||
self.play_game() | ||
|
||
def calculate_desired_path(self): | ||
from collections import deque | ||
|
||
queue = deque([(1, 1, [])]) | ||
visited = set() | ||
visited.add((1, 1)) | ||
|
||
while queue: | ||
x, y, path = queue.popleft() | ||
if (x, y) == self.exit_point: | ||
return path | ||
|
||
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] | ||
for dx, dy in directions: | ||
nx, ny = x + dx, y + dy | ||
if (0 <= nx < self.size and 0 <= ny < self.size and | ||
self.maze[nx][ny] == " " and (nx, ny) not in visited): | ||
visited.add((nx, ny)) | ||
queue.append((nx, ny, path + [(nx, ny)])) | ||
|
||
return [] | ||
|
||
def play_game(self): | ||
clear_output(wait=True) | ||
self.start_time = time.time() | ||
with self.output_widget: | ||
display(HTML("<h2 style='color: blue;'>Welcome to the Maze Game!</h2>")) | ||
self.update_maze() | ||
|
||
button_box = widgets.HBox([ | ||
widgets.Button(description="Up"), | ||
widgets.Button(description="Down"), | ||
widgets.Button(description="Left"), | ||
widgets.Button(description="Right"), | ||
]) | ||
|
||
for button in button_box.children: | ||
button.on_click(self.move_player) | ||
|
||
display(button_box) | ||
|
||
def move_player(self, button): | ||
direction = button.description.lower() | ||
new_position = self.position | ||
|
||
if direction == "up": | ||
new_position = (self.position[0] - 1, self.position[1]) | ||
elif direction == "down": | ||
new_position = (self.position[0] + 1, self.position[1]) | ||
elif direction == "left": | ||
new_position = (self.position[0], self.position[1] - 1) | ||
elif direction == "right": | ||
new_position = (self.position[0], self.position[1] + 1) | ||
|
||
if (0 <= new_position[0] < self.size and | ||
0 <= new_position[1] < self.size and | ||
self.maze[new_position[0]][new_position[1]] != "#"): | ||
self.position = new_position | ||
self.user_path.append(new_position) | ||
self.move_count += 1 | ||
|
||
if self.position == self.exit_point: | ||
self.display_win_message() | ||
elif self.move_count >= self.move_limit: | ||
self.display_loss_message() | ||
else: | ||
self.update_maze() | ||
else: | ||
with self.output_widget: | ||
print("<span style='color: red;'>🚫 Invalid move! Can't go that way. Try again.</span>") | ||
|
||
def update_maze(self): | ||
with self.output_widget: | ||
clear_output(wait=True) | ||
print(HTML(print_maze(self.maze, self.position))) | ||
print(f"<span style='color: yellow;'>Moves left: {self.move_limit - self.move_count}</span>") | ||
print("<span style='color: cyan;'>Use the buttons to move.</span>") | ||
|
||
def display_win_message(self): | ||
clear_output(wait=True) | ||
score = self.calculate_score() | ||
with self.output_widget: | ||
print("<span style='color: green;'>🎉 Congratulations! You've reached the exit! 🎉</span>") | ||
print(f"<span style='color: white;'>Total moves: {self.move_count}</span>") | ||
print(f"<span style='color: gold;'>Your score: {score}</span>") | ||
self.start_game() | ||
|
||
def display_loss_message(self): | ||
clear_output(wait=True) | ||
with self.output_widget: | ||
print("<span style='color: red;'>🛑 Time's up or you've run out of moves! 🛑</span>") | ||
print(f"<span style='color: white;'>Total moves: {self.move_count}</span>") | ||
score = self.calculate_score() | ||
print(f"<span style='color: gold;'>Your score: {score}</span>") | ||
self.start_game() | ||
|
||
def calculate_score(self): | ||
correct_moves = len(set(self.user_path) & set(self.desired_path)) | ||
total_moves = len(self.user_path) | ||
score = correct_moves * 10 - (total_moves - correct_moves) * 5 | ||
return max(score, 0) | ||
|
||
MazeGame() |
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,27 @@ | ||
*Maze Runner* | ||
|
||
|
||
🎯 Goal | ||
|
||
The goal of this project is to create an interactive maze game that allows users to navigate through a procedurally generated maze using directional commands. | ||
|
||
🧾 Description | ||
|
||
This project is Maze Runner, where users can engage with a maze, trying to find the exit while managing their moves. The application generates a random maze based on selected difficulty levels and keeps track of user movements, providing feedback on their progress. | ||
|
||
🧮 What I Have Done! | ||
|
||
1. Implemented a maze generation algorithm to create a playable maze with walls and paths. | ||
2. Developed a player movement system that allows users to navigate through the maze using directional buttons. | ||
3. Integrated a scoring system that evaluates player performance based on the path taken and moves made. | ||
4. Included a user interface with clear visual feedback and messages for winning or losing the game. | ||
|
||
📚 Libraries Needed | ||
|
||
1. random - For generating random maze layouts. | ||
2. ipywidgets - To create interactive buttons and display elements in Jupyter Notebook. | ||
3. IPython.display - For rendering HTML and managing output in the notebook. | ||
|
||
📢 Conclusion | ||
|
||
In conclusion, the Maze Runner project highlights an engaging way for users to challenge themselves in navigating mazes. The code serves as a foundational platform for potential enhancements, such as different maze designs, additional features, or multiplayer options. |