diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..e43b0f98 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/README.md b/README.md index f6800627..0d32bea4 100644 --- a/README.md +++ b/README.md @@ -1,135 +1,78 @@ -Ironhack Logo -# Project: Escape Room Python Game +![Header](https://raw.githubusercontent.com/mgluengo/python-project/master/images/header.png "Header") -## Overview +## Welcome To The Shire! -The goal of this project is for you to apply the Python programming skills you have learned this week in solving a real problem. We present you the design of a classic game that can be played via text - Escape Room. Your goal is to develop the game using Python based on the game design. +It’s time to play some old-school games! :video_game: -Read the game narratives and technical requirements carefully. Plan how you will achieve your goal with pseudo codes and/or flowchart. Review the logic and process in order to avoid potential errors. Then implement with Python code. After that, test your code several times with different inputs and make sure it's rock solid. The instructional team is standing by to help you in case you run into any problems. +Ok, perhaps typing commands in your terminal is not your idea of fun, but we believe that adding **The Lord of The Rings** to the mix always helps. So, here’s a nerdy and retro option to consider after you finish binge-watching the latest season of Stranger Things. ---- -## Game Design +## Project Context -### Game Map +This (humble) Escape Game was our **very first Python project** as newbie programmers at Ironhack. -![Game Map](escape-room-plan.jpg) +We went from not having coded a line before, to making this work in **less than 72 hours** – that’s the pace at coding Bootcamps! -### Game Narratives -#### Game Room +## Game Narrative -You wake up on a couch and find yourself in a strange house with no windows which you have never been to before. You don't remember why you are here and what had happened before. You feel some unknown danger is approaching and you must get out of the house, NOW! +![Shire](https://raw.githubusercontent.com/mgluengo/python-project/master/images/the_shire.png "Shire") -You are now in game room. +>*Hurry up, hobbit!* -What would you like to do? +>*The Ring has awoken. +A threat grows in the land of Mordor where the shadows loom. **Find all maps** to reach Mount Doom and destroy the Ring once and for all.* -You explore the room. This is Game Room. You find couch, piano, and Door A. +>*Your journey starts in The Shire. +You step out of Bilbo’s house… +There’s no going back.* -You examine couch. There isn't anything interesting about it. +>*You have **5 minutes** to solve the challenge.* -You examine Door A. It is locked but you don't have the key. -You examine piano. You find key for Door A. +## Game Map -You examine Door A. Your unlock it with a key you have. -Do you want to go to the next room? +![Game Map](https://github.com/mgluengo/python-project/blob/master/images/middle_earth_map.png) -#### Bedroom 1 -You are now in Bedroom 1. +## Tech -What would you like to do? +[![Python](https://img.shields.io/badge/Python-9146FF?style=for-the-badge&logo=python&logoColor=white&labelColor=101010)]() -You explore the room. This is Bedroom 1. You find queen bed, Door A, Door B, and Door C. +## What We Learned -You examine queen bed. You find key for Door B. -You examine Door C. It is locked but you don't have the key. +- Working with **dicts, lists, tuples** +- **Conditional** statements and loops +- **Functions** +- Installing, importing **modules** (e.g. time, termcolor) +- … the adrenaline rush you feel when you make your code work! :surfer: -You examine Door B. Your unlock it with a key you have. -Do you want to go to the next room? +## Next Steps -#### Bedroom 2 -You are now in Bedroom 2. +With more time, we would have prioritized the following enhancements: -What would you like to do? +- **New mini-games**. +- Repurpose challenges and add **coding quizzes** to review the content of our classes (introduce **gamification** in the context of the bootcamp). +- **Expand scope** with additional maps, characters and elements to interact with. +- Introduce **random** elements, so the experience is different every time you play. -You explore the room. This is Bedroom 2. You find double bed, dresser, and Door B. +## Links -You examine double bed. You find key for Door C. +:point_right: [See full project ppt on SpeakerDeck](https://speakerdeck.com/mgluengo/python-escape-game-lord-of-the-rings) -You examine dresser. You find key for Door D. +## Team Members -You examine Door B. Your unlock it with a key you have. +[![GitHub](https://img.shields.io/badge/GitHub-mbeovides-14a1f0?style=for-the-badge&logo=github&logoColor=white&labelColor=101010)](https://github.com/mbeovides) -Do you want to go to the next room? +[![GitHub](https://img.shields.io/badge/GitHub-mgluengo-14a1f0?style=for-the-badge&logo=github&logoColor=white&labelColor=101010)](https://github.com/mgluengo) -#### Bedroom 1 -You are now in Bedroom 1. +## Special Thanks -What would you like to do? -You examine Door C. Your unlock it with a key you have. - -Do you want to go to the next room? - -#### Living Room - -You are now in Living Room. - -What would you like to do? - -You explore the room. This is Living Room. You find dining table, Door C, and Door D. - -You examine Door D. Your unlock it with a key you have. - -Do you want to go to the next room? - -#### Outside - -Congrats! You escaped the room! - ---- - -## Getting Started - -Overwhelmed and don't know where to start? This is a tough challenge we know. But don't worry. We have included a working example for you to reference in which only 1 room (game room) is included. Read the example and make sure you understand it. Then you can expand on top of the example to code the rest of the rooms. - -The provided example is just a Minimal Viable Product (MVP). It is fully functional but not bullet proof. You should be aware of its limitations while you are working and try to make your final product as robust as possible. - -## Technical Requirements - -* Use Python lists and dictionaries to define the rooms, items, and relations of them. - -* Use a Python dictionary to store the game state. Update the state dictionary when progresses are made such as a key is collected. - -* Use Python functions to play the game. Don't use procedural code. - -* After completing each game action, call the next function to continue playing until the winning condition is reached. - -* The winning condition is for the player to successfully make to the "Outside" room. When this happens, congrat the player and end the game. - -## Necessary Deliverables - -The following deliverables should be pushed to your Github repo. - -* `main.ipynb` that contains your solution. - -## Suggested Ways to Get Started - -1. Start Jupyter Notebook from this lab directory. - -1. Launch `sample-code.ipynb` and read through the file. Also execute the code and play the game. Make sure you understand what each line of the codes does. - -1. Create `main.ipynb` and copy the codes from `sample-code.ipynb`. Expand the code following the example to create Bedroom 1. - -1. Test the game with Game Room and Bedroom 1. Make sure everything works then work on Bedroom 2 then Living Room. - -1. Test the whole game. Try to make all kinds of inputs to make sure your game is rock solid and will not break. +Kudos to our amazing TA **Gladys Mawarni** for being our Gandalf and guiding us through the first steps of our coding journey! :mage_woman: \ No newline at end of file diff --git a/escape-room-plan.jpg b/escape-room-plan.jpg deleted file mode 100644 index a3ea42c1..00000000 Binary files a/escape-room-plan.jpg and /dev/null differ diff --git a/game_code.py b/game_code.py new file mode 100644 index 00000000..29040cec --- /dev/null +++ b/game_code.py @@ -0,0 +1,385 @@ +# ESCAPE: AN ADVENTURE IN THE MIDDLE-EARTH + +# IMPORT LIBRARIES +import time +from traceback import TracebackException +from termcolor import colored +from random import randint + + +# SECTION 1: DEFINITIONS + +# Define items in THE SHIRE + +bilbo_house = { + "name": "House Bilbo", + "type": "furniture", +} + +road_a = { + "name": "road a", + "type": "door", +} + +map_a = { + "name": "map a", + "type": "key", + "target": road_a, +} + +sam_house = { + "name": "House Sam", + "type": "furniture", +} + +the_shire = { + "name": "THE SHIRE", + "type": "room", +} + +# Define items in GONDOR + +road_b = { + "name": "road b", + "type": "door", +} + +rivendell = { + "name": "Rivendell", + "type": "furniture", +} + +map_b = { + "name": "map b", + "type": "key", + "target": road_b, +} + +road_c = { + "name": "road c", + "type": "door", +} + +gondor = { + "name": "GONDOR", + "type": "room", +} + +# This is not an area - definition of road d before defining map d + +road_d = { + "name": "road d", + "type": "door", +} + +# Define items in ROHAN + +map_c = { + "name": "map c", + "type": "key", + "target": road_c, +} + +map_d = { + "name": "map d", + "type": "key", + "target": road_d, +} + +moria = { + "name": "Moria", + "type": "furniture", +} + +helm = { + "name": "Helms Deep", + "type": "furniture", +} + +road_b = { + "name": "road b", + "type": "door", +} + +rohan = { + "name": "ROHAN", + "type": "room", +} + +# Define items in MORDOR + +eye_tower = { + "name": "Eye Tower", + "type": "furniture", +} + +road_c = { + "name": "road c", + "type": "door", +} + +road_d = { + "name": "road d", + "type": "door", +} + +mordor = { + "name": "MORDOR", + "type": "room", +} + +# Define OUTSIDE + +outside = { + "name": "MOUNT DOOM" +} + +# Define all rooms(areas) and doors(roads) + +all_rooms = [the_shire, gondor, rohan, mordor, outside] + +all_doors = [road_a, road_b, road_c, road_d] + +# Define which places/areas are related + +object_relations = { + "THE SHIRE": [bilbo_house, sam_house, road_a], + "GONDOR": [rivendell, road_a, road_b, road_c], + "ROHAN": [moria, helm, road_b], + "MORDOR": [eye_tower, road_c, road_d], + "MOUNT DOOM": [road_d], + "House Sam": [map_a], + "Rivendell": [map_b], + "Moria": [map_c], + "Helms Deep": [map_d], + "road a": [the_shire, gondor], + "road b": [gondor, rohan], + "road c": [gondor, mordor], + "road d": [mordor, outside] +} + + +# SECTION 2 - DEFINE STATE AT GAME START + +# Define game state. +# When a new game starts, make a copy of this +# dict and use the copy to store gameplay state. This +# way you can replay the game multiple times. + +INIT_GAME_STATE = { + "current_room": the_shire, + "keys_collected": [], + "target_room": outside +} + + +#SECTION 3 - FUNCTIONS TO PLAY THE GAME + +def linebreak(): + """ + Print a line break + """ + print("\n\n") + +def start_game(): + """ + Start the game + """ + global start + start = time.time() + print('***********\n') + print(colored("\nESCAPE: AN ADVENTURE IN THE MIDDLE-EARTH\n", "blue", attrs=["bold"])) + print('***********\n') + print(""" + Hurry up, hobbit! + + The Ring has awoken. + A threat grows in the land of Mordor where the shadows loom. + + Find all maps to reach Mount Doom and destroy the Ring once and for all. + The fate of the free world is now in your hands! + + Your journey starts in The Shire. + + You step out of Bilbo's house... + + There's no going back. + + YOU HAVE 5 MINUTES TO SOLVE THE CHALLENGE + + """) + print('***********\n') + play_room(game_state["current_room"]) + +def play_room(room): + """ + Play a room (area). First check if the room being played is the target room. + If it is, the game will end with success. Otherwise, let player either + explore (list all items in this room) or examine an item found here. + """ + game_state["current_room"] = room + if(game_state["current_room"] == game_state["target_room"]): + print('***********\n') + print(colored("\nYou destroyed the Ring and saved the free world!\n", "blue", attrs=["bold"])) + print(""" + Farewell for now, hobbit... + but remember: for every adventure that ends + a new one begins. + """) + print('***********\n') + else: + if room['name'] != 'THE SHIRE': + time_room = time.time() + global start + time_diff = int(time_room - start) + print("\nHurry up! You have used", time_diff, "seconds so far.") + if int(time_diff) > 300: + print(colored("\nTIME OVER, HOBBIT!!\nYOU CAN STILL CONTINUE YOUR JOURNEY\nAND HOPE FOR THE BEST...","red")) + print("\nYOU ARE IN " + room["name"]) + items = [i["name"] for i in object_relations[room["name"]]] + print("You see from here: " + " // ".join(items)) + examine_item(input("\nWhere do we go next? ").strip()) + +def get_next_room_of_door(door, current_room): + """ + From object_relations, find the two rooms (areas) connected to the given door. + Return the room that is not the current_room. + """ + connected_rooms = object_relations[door["name"]] + for room in connected_rooms: + if(not current_room == room): + return room + +def examine_item(item_name): + """ + Examine an item. + First make sure the intended item belongs to the current room (area). + Then check if the item is a door. Tell player if map hasn't been + collected yet. Otherwise ask player if they want to go to the next + area. If the item is not a door, then check if it contains maps. + Collect the map if found and update the game state. At the end, + play either the current or the next room depending on the game state + to keep playing. + """ + + current_room = game_state["current_room"] + next_room = "" + output = None + game_win = False + + for item in object_relations[current_room["name"]]: + if(item["name"] == item_name): + output = "\nYou examine " + item_name + ": " + if(item["type"] == "door"): + have_key = False + for key in game_state["keys_collected"]: + if(key["target"] == item): + have_key = True + if(have_key): + output += colored("\nLook! You can enter the area with a map you have.", "cyan") + next_room = get_next_room_of_door(item, current_room) + else: + output += colored("\nYou shall not pass! First find the map to enter this area.", "red") + else: + if(item["name"] in object_relations and len(object_relations[item["name"]])>0): + print(colored("\nYou meet Gollum!\nHe will give you a new map if you win a little game.", "cyan")) + print("\nGollum says: 'let's play rock-paper-scissors!'") + game_win = rock_paper_scissors() + game_win + if game_win is True: + item_found = object_relations[item["name"]].pop() + game_state["keys_collected"].append(item_found) + output += colored("\nMy Precious! You get " + item_found["name"] + ".", "green") + else: + break + else: + output += colored("\nThere isn't anything interesting in this place.", "red") + print(output) + break + + if(output is None): + print("\n\nFeeling lost? The place you requested is not in the current area.") + + if(next_room and input("\nShall we explore the next area?\nEnter 'yes' or 'no': ").strip() == 'yes'): + print(colored("\nThe journey continues!", "green")) + play_room(next_room) + else: + play_room(current_room) + + +def rock_paper_scissors(): + + """This function triggers the rock-paper-scissors game + It returns the result of the game (either player wins or + Gollum wins)""" + + player_wins = 0 + computer_wins = 0 + winning_score = 1 # this could be changed to adjust the duration of the game (e.g. the best of 3 rounds) + game_win = False + + while player_wins < winning_score and computer_wins < winning_score: + #print(f"\nYour Score: {player_wins} Gollum Score: {computer_wins}\n") # commented out not needed for games of 1 round + print("Gollum says:") + print("...rock...") + print("...paper...") + print("...scissors...\n") + + player = input("What's your move? Type your choice: ").lower() + if player == "quit" or player == "q": + break + random_num = randint(0, 2) + if (random_num == 0): + computer = "rock" + elif (random_num == 1): + computer = "paper" + else: + computer = "scissors" + + print(f"Gollum plays: {computer}") + + if player == computer: + print("It's a tie\n") + elif player == "rock": + if computer == "paper": + print("Gollum wins :( ") + computer_wins += 1 + else: + print("You win!") + player_wins += 1 + elif player == "paper": + if computer == "rock": + print("You win!") + player_wins += 1 + else: + print("Gollum wins!") + computer_wins += 1 + elif (player == "scissors"): + if (computer == "rock"): + print("Gollum wins!") + computer_wins += 1 + else: + print("You win!") + player_wins += 1 + else: + print("Please enter a valid move") + + if player_wins > computer_wins: + game_win = True + print(colored("\nCONGRATS HOBBIT, YOU WIN! YOU GET THE MAP", "green")) + elif player_wins == computer_wins: + game_win = False + print("IT'S A TIE") + else: + game_win = False + print(colored("\nOH NO! GOLLUM WINS...\nCOME BACK IF YOU WANT TO TRY AGAIN", "red")) + + return game_win + + +#SECTION 4 - INITIATE GAME + +game_state = INIT_GAME_STATE.copy() +start_game() +countdown() + diff --git a/images/header.png b/images/header.png new file mode 100644 index 00000000..1c9f7310 Binary files /dev/null and b/images/header.png differ diff --git a/images/middle_earth_map.png b/images/middle_earth_map.png new file mode 100644 index 00000000..dc80c34d Binary files /dev/null and b/images/middle_earth_map.png differ diff --git a/images/the_shire.png b/images/the_shire.png new file mode 100644 index 00000000..a8215ae0 Binary files /dev/null and b/images/the_shire.png differ diff --git a/your-code/sample-code.ipynb b/your-code/sample-code.ipynb deleted file mode 100644 index a6f8a94d..00000000 --- a/your-code/sample-code.ipynb +++ /dev/null @@ -1,248 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# define rooms and items\n", - "\n", - "couch = {\n", - " \"name\": \"couch\",\n", - " \"type\": \"furniture\",\n", - "}\n", - "\n", - "door_a = {\n", - " \"name\": \"door a\",\n", - " \"type\": \"door\",\n", - "}\n", - "\n", - "key_a = {\n", - " \"name\": \"key for door a\",\n", - " \"type\": \"key\",\n", - " \"target\": door_a,\n", - "}\n", - "\n", - "piano = {\n", - " \"name\": \"piano\",\n", - " \"type\": \"furniture\",\n", - "}\n", - "\n", - "game_room = {\n", - " \"name\": \"game room\",\n", - " \"type\": \"room\",\n", - "}\n", - "\n", - "outside = {\n", - " \"name\": \"outside\"\n", - "}\n", - "\n", - "all_rooms = [game_room, outside]\n", - "\n", - "all_doors = [door_a]\n", - "\n", - "# define which items/rooms are related\n", - "\n", - "object_relations = {\n", - " \"game room\": [couch, piano, door_a],\n", - " \"piano\": [key_a],\n", - " \"outside\": [door_a],\n", - " \"door a\": [game_room, outside]\n", - "}\n", - "\n", - "# define game state. Do not directly change this dict. \n", - "# Instead, when a new game starts, make a copy of this\n", - "# dict and use the copy to store gameplay state. This \n", - "# way you can replay the game multiple times.\n", - "\n", - "INIT_GAME_STATE = {\n", - " \"current_room\": game_room,\n", - " \"keys_collected\": [],\n", - " \"target_room\": outside\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "def linebreak():\n", - " \"\"\"\n", - " Print a line break\n", - " \"\"\"\n", - " print(\"\\n\\n\")\n", - "\n", - "def start_game():\n", - " \"\"\"\n", - " Start the game\n", - " \"\"\"\n", - " print(\"You wake up on a couch and find yourself in a strange house with no windows which you have never been to before. You don't remember why you are here and what had happened before. You feel some unknown danger is approaching and you must get out of the house, NOW!\")\n", - " play_room(game_state[\"current_room\"])\n", - "\n", - "def play_room(room):\n", - " \"\"\"\n", - " Play a room. First check if the room being played is the target room.\n", - " If it is, the game will end with success. Otherwise, let player either \n", - " explore (list all items in this room) or examine an item found here.\n", - " \"\"\"\n", - " game_state[\"current_room\"] = room\n", - " if(game_state[\"current_room\"] == game_state[\"target_room\"]):\n", - " print(\"Congrats! You escaped the room!\")\n", - " else:\n", - " print(\"You are now in \" + room[\"name\"])\n", - " intended_action = input(\"What would you like to do? Type 'explore' or 'examine'?\").strip()\n", - " if intended_action == \"explore\":\n", - " explore_room(room)\n", - " play_room(room)\n", - " elif intended_action == \"examine\":\n", - " examine_item(input(\"What would you like to examine?\").strip())\n", - " else:\n", - " print(\"Not sure what you mean. Type 'explore' or 'examine'.\")\n", - " play_room(room)\n", - " linebreak()\n", - "\n", - "def explore_room(room):\n", - " \"\"\"\n", - " Explore a room. List all items belonging to this room.\n", - " \"\"\"\n", - " items = [i[\"name\"] for i in object_relations[room[\"name\"]]]\n", - " print(\"You explore the room. This is \" + room[\"name\"] + \". You find \" + \", \".join(items))\n", - "\n", - "def get_next_room_of_door(door, current_room):\n", - " \"\"\"\n", - " From object_relations, find the two rooms connected to the given door.\n", - " Return the room that is not the current_room.\n", - " \"\"\"\n", - " connected_rooms = object_relations[door[\"name\"]]\n", - " for room in connected_rooms:\n", - " if(not current_room == room):\n", - " return room\n", - "\n", - "def examine_item(item_name):\n", - " \"\"\"\n", - " Examine an item which can be a door or furniture.\n", - " First make sure the intended item belongs to the current room.\n", - " Then check if the item is a door. Tell player if key hasn't been \n", - " collected yet. Otherwise ask player if they want to go to the next\n", - " room. If the item is not a door, then check if it contains keys.\n", - " Collect the key if found and update the game state. At the end,\n", - " play either the current or the next room depending on the game state\n", - " to keep playing.\n", - " \"\"\"\n", - " current_room = game_state[\"current_room\"]\n", - " next_room = \"\"\n", - " output = None\n", - " \n", - " for item in object_relations[current_room[\"name\"]]:\n", - " if(item[\"name\"] == item_name):\n", - " output = \"You examine \" + item_name + \". \"\n", - " if(item[\"type\"] == \"door\"):\n", - " have_key = False\n", - " for key in game_state[\"keys_collected\"]:\n", - " if(key[\"target\"] == item):\n", - " have_key = True\n", - " if(have_key):\n", - " output += \"You unlock it with a key you have.\"\n", - " next_room = get_next_room_of_door(item, current_room)\n", - " else:\n", - " output += \"It is locked but you don't have the key.\"\n", - " else:\n", - " if(item[\"name\"] in object_relations and len(object_relations[item[\"name\"]])>0):\n", - " item_found = object_relations[item[\"name\"]].pop()\n", - " game_state[\"keys_collected\"].append(item_found)\n", - " output += \"You find \" + item_found[\"name\"] + \".\"\n", - " else:\n", - " output += \"There isn't anything interesting about it.\"\n", - " print(output)\n", - " break\n", - "\n", - " if(output is None):\n", - " print(\"The item you requested is not found in the current room.\")\n", - " \n", - " if(next_room and input(\"Do you want to go to the next room? Ener 'yes' or 'no'\").strip() == 'yes'):\n", - " play_room(next_room)\n", - " else:\n", - " play_room(current_room)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "You wake up on a couch and find yourself in a strange house with no windows which you have never been to before. You don't remember why you are here and what had happened before. You feel some unknown danger is approaching and you must get out of the house, NOW!\n", - "You are now in game room\n", - "What would you like to do? Type 'explore' or 'examine'?explore\n", - "You explore the room. This is game room. You find couch, piano, door a\n", - "You are now in game room\n", - "What would you like to do? Type 'explore' or 'examine'?examine\n", - "What would you like to examine?door a\n", - "You examine door a. It is locked but you don't have the key.\n", - "You are now in game room\n", - "What would you like to do? Type 'explore' or 'examine'?examine\n", - "What would you like to examine?piano\n", - "You examine piano. You find key for door a.\n", - "You are now in game room\n", - "What would you like to do? Type 'explore' or 'examine'?examine\n", - "What would you like to examine?door a\n", - "You examine door a. You unlock it with a key you have.\n", - "Do you want to go to the next room? Ener 'yes' or 'no'yes\n", - "Congrats! You escaped the room!\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - } - ], - "source": [ - "game_state = INIT_GAME_STATE.copy()\n", - "\n", - "start_game()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -}