mirror of
https://github.com/RGBCube/nu_scripts
synced 2025-07-30 13:47:46 +00:00
add games folder and simple game demonstrating nu code concepts (#1100)
I'd like to contribute this game. The code exemplifies several nu concepts.
This commit is contained in:
parent
a515c4217e
commit
67e74c5657
2 changed files with 214 additions and 0 deletions
32
games/humlespring/README.md
Normal file
32
games/humlespring/README.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
# Humlespring Text Adventure
|
||||
|
||||
A simple text adventure game written in Nushell.
|
||||
|
||||
The game utilizes Nushell's functional programming capabilities in managing the game map and player state.
|
||||
|
||||
* **Immutable Data Structures**: The game map (`$map`) is defined as a record, which is an immutable data structure. This means the map's contents cannot be changed directly during gameplay, promoting data integrity and predictable game behavior. Locations, exits, items, and NPCs are all defined within this structure.
|
||||
|
||||
* **Data Transformation**: The `describe_location` function takes the player state and map as input and transforms this data to produce the location description. It uses the `get` command to access location data and `str join` to format the output, demonstrating functional data manipulation.
|
||||
|
||||
* **State Management**: The player state (`$player_state`) is a mutable record, but updates to it are handled in a controlled manner within the main loop. Actions like "go", "take", and "search" update the state by assigning new values to the `$player_state` record.
|
||||
|
||||
## How to Play
|
||||
|
||||
1. Make sure you have Nushell installed (`https://www.nushell.sh/`).
|
||||
2. Save the script as `script.nu`.
|
||||
3. Run the game by executing `nu script.nu` in your terminal.
|
||||
|
||||
## Commands
|
||||
|
||||
* `look` or `l`: Describe the current location.
|
||||
* `go` or `move` [direction]: Move in the specified direction (e.g., `go north`).
|
||||
* `take` or `get` [item]: Pick up an item (e.g., `take leaflet`).
|
||||
* `inventory` or `i`: View your inventory.
|
||||
* `talk` [npc]: Talk to a non-player character (e.g., `talk alexander`).
|
||||
* `search` [object]: Search an object in the current location (e.g., `search tree`).
|
||||
* `give` [item]: Give an item to an NPC (e.g., `give cat`).
|
||||
* `quit` or `exit`: Quit the game.
|
||||
|
||||
## Goal
|
||||
|
||||
Olivia has lost her cat, Mittens. Find Mittens and return her to Olivia in the village square.
|
182
games/humlespring/script.nu
Executable file
182
games/humlespring/script.nu
Executable file
|
@ -0,0 +1,182 @@
|
|||
#!/usr/bin/env nu
|
||||
|
||||
# --- Game Data ---
|
||||
|
||||
# Define the locations in the village
|
||||
let map = {
|
||||
village_square: {
|
||||
desc: "You are in the charming village square of Humlespring. Cobblestones pave the ground. Paths lead north, east, and west. Olivia is here, looking worried."
|
||||
exits: { north: "tavern", east: "market", west: "alexander_house" }
|
||||
items: ["leaflet"]
|
||||
npcs: {
|
||||
olivia: "Olivia paces back and forth. 'Oh, Alexander... have you seen Mittens? My cat is missing! I last saw her near the old oak tree by the market.'"
|
||||
}
|
||||
},
|
||||
tavern: {
|
||||
desc: "The 'Leaky Mug' tavern. It smells faintly of ale and sawdust. The only exit is south."
|
||||
exits: { south: "village_square" }
|
||||
items: ["mug"]
|
||||
npcs: {}
|
||||
},
|
||||
market: {
|
||||
desc: "The village market area. Stalls are mostly empty now, but an old oak tree stands tall nearby. A faint 'meow' can be heard from the tree. The path leads back west."
|
||||
exits: { west: "village_square" }
|
||||
items: [] # Mittens isn't an 'item' to take, but is found here
|
||||
npcs: {}
|
||||
special: "You look up the old oak tree and see Mittens stuck on a branch! You carefully coax her down." # Add a trigger for this
|
||||
},
|
||||
alexander_house: {
|
||||
desc: "You are outside a small, tidy cottage. This must be Alexander's house. The only exit is east. Alexander is tending his small garden."
|
||||
exits: { east: "village_square" }
|
||||
items: ["watering_can"]
|
||||
npcs: {
|
||||
alexander: "'Ah, hello!' Alexander says, wiping his brow. 'Lovely day, isn't it? Though Olivia seems quite upset about her cat, Mittens. Maybe check near the big oak by the market?'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- Game State ---
|
||||
|
||||
# Player's current status (mutable)
|
||||
mut player_state = {
|
||||
location: "village_square" # Starting location ID
|
||||
inventory: []
|
||||
found_cat: false
|
||||
}
|
||||
|
||||
# --- Helper Functions ---
|
||||
|
||||
# Describe the current location
|
||||
def describe_location [state: record, map: record] {
|
||||
let current_loc_id = $state.location
|
||||
let loc_data = ($map | get $current_loc_id)
|
||||
|
||||
# Description
|
||||
print $loc_data.desc
|
||||
|
||||
# Items
|
||||
if not ($loc_data.items | is-empty) {
|
||||
print $"You see here: ($loc_data.items | str join ', ')"
|
||||
}
|
||||
|
||||
# NPCs
|
||||
let npcs = ($loc_data.npcs | columns)
|
||||
if not ($npcs | is-empty) {
|
||||
print $"People here: ($npcs | str join ', ')"
|
||||
}
|
||||
|
||||
# Exits
|
||||
let exits = ($loc_data.exits | columns | str join ', ')
|
||||
print $"Exits are: ($exits)"
|
||||
|
||||
# Check for winning condition trigger
|
||||
if $current_loc_id == "market" and not $state.found_cat {
|
||||
print "\nHint: Maybe you should 'search tree'?"
|
||||
}
|
||||
}
|
||||
|
||||
# Handle player actions are now inlined in the main loop below
|
||||
|
||||
# --- Main Game Loop ---
|
||||
|
||||
print "Welcome to Humlespring!"
|
||||
print "-------------------------"
|
||||
describe_location $player_state $map
|
||||
|
||||
loop {
|
||||
# Get player input
|
||||
let user_input = (input "> " | str trim)
|
||||
|
||||
# Skip empty input
|
||||
if $user_input == "" { continue }
|
||||
|
||||
# Parse input (simple verb-noun)
|
||||
let parts = ($user_input | split row " ")
|
||||
let verb = ($parts | get 0 | str downcase)
|
||||
# Use `get` and `default` for robust noun handling (handles commands with no noun)
|
||||
let noun = if ($parts | length) > 1 { $parts | get 1 | default "" | str downcase } else {""}
|
||||
|
||||
# grab the current location once
|
||||
let loc_data = ($map | get $player_state.location)
|
||||
|
||||
# Handle the action directly in the loop
|
||||
match $verb {
|
||||
"quit" | "exit" => {
|
||||
print "Goodbye!"
|
||||
exit
|
||||
}
|
||||
"look" | "l" => {
|
||||
describe_location $player_state $map
|
||||
}
|
||||
"go" | "move" => {
|
||||
if ( $noun not-in ( $loc_data.exits | columns )) {
|
||||
print "You can't go that way."
|
||||
} else {
|
||||
let new_loc = ($loc_data.exits | get $noun)
|
||||
$player_state.location = $new_loc
|
||||
print $"You go ($noun)."
|
||||
print "" # line break
|
||||
describe_location $player_state $map
|
||||
}
|
||||
}
|
||||
"inventory" | "i" => {
|
||||
if ($player_state.inventory | is-empty) {
|
||||
print "Your inventory is empty."
|
||||
} else {
|
||||
print $"You are carrying: ($player_state.inventory | str join ', ')"
|
||||
}
|
||||
}
|
||||
"take" | "get" => {
|
||||
if ($loc_data.items | find -r $noun).0? != null {
|
||||
# Just add to inventory
|
||||
$player_state.inventory = ($player_state.inventory | append $noun)
|
||||
print $"You take the ($noun)."
|
||||
} else {
|
||||
print $"There is no '($noun)' here to take."
|
||||
}
|
||||
}
|
||||
"talk" => {
|
||||
if ( $noun not-in ( $loc_data.npcs | columns )) {
|
||||
print $"You cannot talk to ($noun) " } else {
|
||||
if ($loc_data.npcs | get $noun) == null {
|
||||
print $"There is no one called '($noun)' here to talk to."
|
||||
} else {
|
||||
print ($loc_data.npcs | get $noun)
|
||||
}
|
||||
}
|
||||
}
|
||||
"search" => {
|
||||
if $noun == "tree" and $player_state.location == "market" {
|
||||
if $player_state.found_cat {
|
||||
print "You already found Mittens!"
|
||||
} else {
|
||||
print ($loc_data | get special)
|
||||
$player_state.found_cat = true
|
||||
print "\nMittens purrs happily in your arms. You should return her to Olivia!"
|
||||
}
|
||||
} else {
|
||||
print "You search around, but find nothing special."
|
||||
}
|
||||
}
|
||||
"give" => {
|
||||
if $noun == "cat" and $player_state.location == "village_square" and $player_state.found_cat {
|
||||
if ('olivia' in ($loc_data.npcs | columns)) {
|
||||
print "\nYou give Mittens back to Olivia. She is overjoyed!"
|
||||
print "'Oh, thank you, thank you!' she cries, hugging her cat. 'You saved her!'"
|
||||
print "\n*** Congratulations! You completed the adventure! ***"
|
||||
exit
|
||||
} else {
|
||||
print "Olivia isn't here right now."
|
||||
}
|
||||
} else if $player_state.found_cat and $noun == "cat" {
|
||||
print "You need to be in the village square to give the cat back to Olivia."
|
||||
} else {
|
||||
print "You don't have that to give, or you can't give it here/now."
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
print "I don't understand that command. Try: go, look, take, inventory, talk, search, give, quit."
|
||||
}
|
||||
}
|
||||
print "" # Add a newline for better readability
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue