From 13c58ad74b047e269631306e56334cc5a2ba287d Mon Sep 17 00:00:00 2001 From: tim Date: Fri, 9 May 2025 13:05:10 +0000 Subject: [PATCH] Initial commit --- .assets/fork.jpg | Bin 0 -> 3887 bytes .commit_template | 10 +++ .gitignore | 6 ++ adventure/seafloor/coral_reef/chest.py | 39 ++++++++ adventure/seafloor/coral_reef/reef.txt | 23 +++++ adventure/seafloor/seafloor.txt | 7 ++ .../seafloor/sunken_ship/galley/ghost.py | 25 ++++++ adventure/seafloor/sunken_ship/ship.txt | 6 ++ .../seafloor/sunken_ship/stateroom/desk.py | 26 ++++++ adventure/sinking.txt | 9 ++ fancy_printing.py | 25 ++++++ poetry.lock | 33 +++++++ pyproject.toml | 22 +++++ return_to_ship.py | 83 ++++++++++++++++++ 14 files changed, 314 insertions(+) create mode 100644 .assets/fork.jpg create mode 100644 .commit_template create mode 100644 .gitignore create mode 100644 adventure/seafloor/coral_reef/chest.py create mode 100644 adventure/seafloor/coral_reef/reef.txt create mode 100644 adventure/seafloor/seafloor.txt create mode 100644 adventure/seafloor/sunken_ship/galley/ghost.py create mode 100644 adventure/seafloor/sunken_ship/ship.txt create mode 100644 adventure/seafloor/sunken_ship/stateroom/desk.py create mode 100644 adventure/sinking.txt create mode 100644 fancy_printing.py create mode 100644 poetry.lock create mode 100644 pyproject.toml create mode 100644 return_to_ship.py diff --git a/.assets/fork.jpg b/.assets/fork.jpg new file mode 100644 index 0000000000000000000000000000000000000000..144af85ad5dfe3cff64cd441d5a5e02ca747b986 GIT binary patch literal 3887 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 ") +if guess.strip() == SECRET: + print_fancy(CHEST_OPENS) + print_fancy(INSTRUCTIONS) + os.system('cp ./../../../.assets/fork.jpg treasure.jpg') +else: + print_fancy(WRONG_CODE) diff --git a/adventure/seafloor/coral_reef/reef.txt b/adventure/seafloor/coral_reef/reef.txt new file mode 100644 index 0000000..b5986ec --- /dev/null +++ b/adventure/seafloor/coral_reef/reef.txt @@ -0,0 +1,23 @@ + You are standing at the edge of a beautiful coral reef. Schools of fish are + swirling around you in every direction. In front of you is a deep chasm + where you see larger fish sliding through the shadows. There is a chest + half-buried in the seafloor. + + + ____...------------...____ + _.-"` /o/__ ____ __ __ __ \o\_`"-._ + .' / / \ \ '. + |=====/o/======================\o\=====| + |____/_/________..____..________\_\____| + / _/ \_ <_o#\__/#o_> _/ \_ \ + \________________\####/________________/ + |===\!/========================\!/===| + | |=| .---. |=| | + |===|o|=========/ \========|o|===| + | | | \() ()/ | | | + |===|o|======{'-.) A (.-'}=====|o|===| + | __/ \__ '-.\uuu/.-' __/ \__ | + |============= .'.'^'.'.=============| + | _\o/ __ {.' __ '.} _ _\o/ _| + + diff --git a/adventure/seafloor/seafloor.txt b/adventure/seafloor/seafloor.txt new file mode 100644 index 0000000..9a78e29 --- /dev/null +++ b/adventure/seafloor/seafloor.txt @@ -0,0 +1,7 @@ + After several moments of peaceful floating, you make a gentle landing on + the seafloor, several hundered meters away from the sunken ship. You appear + to be at the edge of a plateau whose edges are encrusted with beautiful + corals. + + Both sunken_ship and coral_reef are directories, so use the `cd` command + to go into whichever one you want. diff --git a/adventure/seafloor/sunken_ship/galley/ghost.py b/adventure/seafloor/sunken_ship/galley/ghost.py new file mode 100644 index 0000000..cc79354 --- /dev/null +++ b/adventure/seafloor/sunken_ship/galley/ghost.py @@ -0,0 +1,25 @@ +# ghost.py +# -------- +# By MWC Contributors +# +# This is a Python program. You can run it by typing `python ghost.py` + +import sys +from pathlib import Path +sys.path.append('../../../..') +from fancy_printing import print_fancy + +GHOST_GIVES_KEY = [ + "You enter the cramped galley and notice a sad, lonely ghost wandering around. You always wondered if you would be afraid of ghosts, but somehow this feels completely normal. The ghost begins to speak.", + "'It has been a long while since I have seen anybody down here,' she says. 'I would like to give you a gift. Here's a key.'" +] +GHOST_IS_BORED = [ + "The ghost glances over at you. 'I hope you find some use for that key.'" +] +KEY = " Even in the faint light of your lamp, the key has a golden gleam.\n\n" + +if Path("key.txt").exists(): + print_fancy(GHOST_IS_BORED) +else: + print_fancy(GHOST_GIVES_KEY) + Path("key.txt").write_text(KEY) diff --git a/adventure/seafloor/sunken_ship/ship.txt b/adventure/seafloor/sunken_ship/ship.txt new file mode 100644 index 0000000..0803ea6 --- /dev/null +++ b/adventure/seafloor/sunken_ship/ship.txt @@ -0,0 +1,6 @@ + The sunken ship is lying on the seafloor at a slight angle. From the remains + of its masts and rigging, you can tell it's from the age before ships were made + of steel and powered by engines. You climb up in the deck, and see a large hole + allowing access to the inner chambers. You flick on your suit's light and + go inside. + diff --git a/adventure/seafloor/sunken_ship/stateroom/desk.py b/adventure/seafloor/sunken_ship/stateroom/desk.py new file mode 100644 index 0000000..b419385 --- /dev/null +++ b/adventure/seafloor/sunken_ship/stateroom/desk.py @@ -0,0 +1,26 @@ +# desk.py +# -------- +# By MWC Contributors +# +# This is a Python program. You can run it by typing `python desk.py` + +import sys +from pathlib import Path +sys.path.append('../../../..') +from fancy_printing import print_fancy + +DESCRIPTION = [ + "The stateroom contains the ruins of an elegant office. Scraps of wallpaper are peeling from the wall; there is an eel living in the chandelier. There is a huge desk at the center of the room." +] +OPEN_DESK = [ + "You try your key in the desk drawer, and it clicks open. There are many decaying pieces of paper. One has the numbers 318 written in a fine script." +] +DESK_LOCKED = [ + "You try to open the desk's drawer, but it is firmly locked." +] + +print_fancy(DESCRIPTION) +if Path("../galley/key.txt").exists(): + print_fancy(OPEN_DESK) +else: + print_fancy(DESK_LOCKED) diff --git a/adventure/sinking.txt b/adventure/sinking.txt new file mode 100644 index 0000000..6aef1cf --- /dev/null +++ b/adventure/sinking.txt @@ -0,0 +1,9 @@ + As you are lowered off the edge of the research boat, you wave goodbye to + your friends. The diving suit is tight and stiff, and your vision is limited + to the round window in front of you. Your head goes below water, and the + sharp details of the boat are replaced by a wash of blues and greens. Below + you is an endless expanse of water. You can just barely see the sunken ship + on the seafloor. You relax, allowing your body to gently float down... + + To continue, you need to go into the seafloor directory by typing + "cd seafloor". Once you're there, type `ls` to see what's inside. diff --git a/fancy_printing.py b/fancy_printing.py new file mode 100644 index 0000000..ca74114 --- /dev/null +++ b/fancy_printing.py @@ -0,0 +1,25 @@ +# fancy_printing.py +# ----------------- +# By MWC Contributors +# +# This module defines the `fancy_printing` function, +# which nicely formats and prints a list of strings. +# All the other python programs in this lab import +# `fancy_printing`. + +from click import secho +from textwrap import wrap + +def print_fancy(paragraphs): + """Formats and prints paragraphs. + `paragraphs` should be a list of strings. + """ + for paragraph in paragraphs: + wrapped_text = wrap(paragraph, initial_indent=' ', subsequent_indent=' ') + for line in wrapped_text: + secho(line, fg='cyan') + print('') + +if __name__ == '__main__': + print_fancy(["This is a just a helper program :)"]) + diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..c8bcd77 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,33 @@ +# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand. + +[[package]] +name = "click" +version = "8.1.8" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.10,<4.0" +content-hash = "529d21bdfcb7ef92c5fa9f092bcc0b6eb3849fa52bb1ea59b3406787ab5dc05b" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f4a3d2c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,22 @@ +[project] +name = "lab-terminal" +version = "0.1.0" +description = "" +authors = [ + {name = "Chris Proctor",email = "chris@chrisproctor.net"} +] +license = {text = "MIT"} +readme = "README.md" +requires-python = ">=3.10,<4.0" +dependencies = [ + "click (>=8.1.8,<9.0.0)", + "colorama (>=0.4.6,<0.5.0)" +] + + +[build-system] +requires = ["poetry-core>=2.0.0,<3.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry] +package-mode = false diff --git a/return_to_ship.py b/return_to_ship.py new file mode 100644 index 0000000..4fd2478 --- /dev/null +++ b/return_to_ship.py @@ -0,0 +1,83 @@ +# return_to_ship.py +# ----------------- +# By MWC Contributors +# +# This is a Python program. You should run it by typing `python return_to_ship.py`. + +from shutil import rmtree +from pathlib import Path +from datetime import datetime +from fancy_printing import print_fancy + +LOG_FILE = ".log" +BEGINNING = [ + "Your adventure has only just begun. You are not yet ready to return to the ship. More secrets await you in the ocean's depths. Use `ls` to look around, and use `cd adventure` to start the adventure..." +] +EMPTY_BAG = [ + "You brought the bag back to the surface, but the treasure is not inside. You'll have to go back and open the chest again." +] +RUSTY_TREASURE = [ + "As you reach the surface, you look at the treasure in your hands. To your dismay, it has corroded into bits because you didn't keep it in its bag. You'll have to get another treasure from the chest...next time make sure you store it inside a bag." +] +VICTORY = [ + "You've made it back to the boat! The crew pulls you in. Now you can finally show off the treasure you risked your life for... Use `open bag/treasure.jpg` to take a peek.", + "Congratulations! You have completed the Terminal Adventure." +] +COMMANDS = [ + "As a reminder, here are some useful commands:", + "To move a file or a directory from old to new: mv old new", + "To create a directory named bag: mkdir bag" +] + +def win(): + print_fancy(VICTORY) + win_time = datetime.now().isoformat() + Path(LOG_FILE).write_text(f"finished the lab at {win_time}\n") + +def find_file_in_path(path, file): + results = list(Path(path).rglob(file)) + if results: + return results[0] + +def bag_is_here(): + return Path("bag").exists() + +def treasure_is_here_in_bag(): + bag_path = Path("bag") + treasure_in_bag_path = find_file_in_path(bag_path, "treasure.jpg") + return bag_path.exists() and treasure_in_bag_path + +def treasure_is_here_outside_of_bag(): + return Path("treasure.jpg").exists() + +def find_treasure(): + return find_file_in_path("adventure", "treasure.jpg") + +def find_bag(): + return find_file_in_path("adventure", "bag") + +if treasure_is_here_in_bag(): + win() +elif bag_is_here(): + rmtree("bag") + print_fancy(EMPTY_BAG) +elif treasure_is_here_outside_of_bag(): + Path("treasure.jpg").unlink() + print_fancy(RUSTY_TREASURE) + print_fancy(COMMANDS) +elif not find_treasure(): + print_fancy(BEGINNING) +elif find_bag(): + bag_path = find_bag() + treasure_path = find_treasure() + if treasure_path.is_relative_to(bag_path): + message = f"You left your treasure bag at {bag_path}! Bring it back to the surface." + else: + message = f"You left your bag at {bag_path} and your treasure at {treasure_path}! Put the treasure in the bag, and then bring the bag to the surface." + print_fancy([message]) + print_fancy(COMMANDS) +else: + treasure_path = find_treasure() + message = f"You left your treasure at {treasure_path}! Create a bag, put the treasure inside, and bring the back back to the surface." + print_fancy([message]) + print_fancy(COMMANDS)