♻️ refactor: refactored a lot and added some features too, whoops
parent
9303fe4897
commit
574300cdad
226
src/main.rs
226
src/main.rs
|
@ -1,9 +1,3 @@
|
||||||
use std::io::{
|
|
||||||
Write,
|
|
||||||
stdin,
|
|
||||||
stdout,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// As a dare to myself, I won't use any error-handling crates.
|
/// As a dare to myself, I won't use any error-handling crates.
|
||||||
|
|
||||||
#[derive (Debug)]
|
#[derive (Debug)]
|
||||||
|
@ -34,27 +28,16 @@ fn print (mut s: &str) {
|
||||||
println! ("{}", s);
|
println! ("{}", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_help () {
|
|
||||||
print ("All commands are ASCII and case-insensitive.");
|
|
||||||
print ("Commands should start with a verb like LOOK.");
|
|
||||||
print ("e.g. `look table`");
|
|
||||||
print ("Single-word verbs are better, e.g. prefer `hint` over `give me a hint`");
|
|
||||||
print ("When in doubt, try generic verbs like `look` or `use` over specific verbs like `actuate`, `type`, or `consolidate`.");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_undetected_item () {
|
|
||||||
print ("That ITEM does not exist in this ROOM, or you have not detected it.");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_input () -> Result <String> {
|
fn read_input () -> Result <String> {
|
||||||
{
|
{
|
||||||
let mut stdout = stdout ();
|
use std::io::Write;
|
||||||
|
let mut stdout = std::io::stdout ();
|
||||||
stdout.write_all (b"> ")?;
|
stdout.write_all (b"> ")?;
|
||||||
stdout.flush ()?;
|
stdout.flush ()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buffer = String::new ();
|
let mut buffer = String::new ();
|
||||||
stdin ().read_line (&mut buffer)?;
|
std::io::stdin ().read_line (&mut buffer)?;
|
||||||
|
|
||||||
// I don't know why I need the type annotation here, but I do.
|
// I don't know why I need the type annotation here, but I do.
|
||||||
let x: &[_] = &['\r', '\n'];
|
let x: &[_] = &['\r', '\n'];
|
||||||
|
@ -63,6 +46,54 @@ fn read_input () -> Result <String> {
|
||||||
Ok (buffer)
|
Ok (buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait Io {
|
||||||
|
fn print (&mut self, s: &str);
|
||||||
|
fn read_input (&mut self) -> Result <String>;
|
||||||
|
fn sleep (&mut self, milliseconds: u32);
|
||||||
|
|
||||||
|
fn print_many <'a, I: IntoIterator <Item=&'a str>> (&mut self, lines: I) {
|
||||||
|
for line in lines {
|
||||||
|
self.print (line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive (Default)]
|
||||||
|
struct Stdio {}
|
||||||
|
|
||||||
|
impl Io for Stdio {
|
||||||
|
fn print (&mut self, s: &str) {
|
||||||
|
print (s)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_input (&mut self) -> Result <String> {
|
||||||
|
read_input ()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sleep (&mut self, milliseconds: u32) {
|
||||||
|
use std::{
|
||||||
|
thread::sleep,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
sleep (Duration::from_millis (milliseconds.into ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_help <I: Io> (io: &mut I) {
|
||||||
|
io.print_many ([
|
||||||
|
"All commands are ASCII and case-insensitive.",
|
||||||
|
"Commands should start with a verb like LOOK.",
|
||||||
|
"e.g. `look table`",
|
||||||
|
"Single-word verbs are better, e.g. prefer `hint` over `give me a hint`",
|
||||||
|
"When in doubt, try generic verbs like `look` or `use` over specific verbs like `actuate`, `type`, or `consolidate`.",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_undetected_item <I: Io> (io: &mut I) {
|
||||||
|
io.print ("That ITEM does not exist in this ROOM, or you have not detected it.");
|
||||||
|
}
|
||||||
|
|
||||||
#[derive (Debug, PartialEq)]
|
#[derive (Debug, PartialEq)]
|
||||||
enum PlayerAction {
|
enum PlayerAction {
|
||||||
Quit,
|
Quit,
|
||||||
|
@ -72,6 +103,7 @@ enum PlayerAction {
|
||||||
Wait,
|
Wait,
|
||||||
Look (ItemName),
|
Look (ItemName),
|
||||||
LookAround,
|
LookAround,
|
||||||
|
Use (ItemName),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive (Clone, Copy, Debug, PartialEq)]
|
#[derive (Clone, Copy, Debug, PartialEq)]
|
||||||
|
@ -85,15 +117,15 @@ enum ItemName {
|
||||||
Table,
|
Table,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item_name_display (x: ItemName) -> &'static str {
|
fn _item_name_display (x: ItemName) -> &'static str {
|
||||||
match x {
|
match x {
|
||||||
Nonsense => "NONSENSE",
|
ItemName::Nonsense => "NONSENSE",
|
||||||
|
|
||||||
Door => "DOOR",
|
ItemName::Door => "DOOR",
|
||||||
EmergencyExit => "EMERGENCY EXIT",
|
ItemName::EmergencyExit => "EMERGENCY EXIT",
|
||||||
Keypad => "KEYPAD",
|
ItemName::Keypad => "KEYPAD",
|
||||||
Note => "NOTE",
|
ItemName::Note => "NOTE",
|
||||||
Table => "TABLE",
|
ItemName::Table => "TABLE",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +156,14 @@ fn parse_input (s: &str) -> PlayerAction {
|
||||||
return PlayerAction::Look (parse_item_name (rest));
|
return PlayerAction::Look (parse_item_name (rest));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some (rest) = s.strip_prefix ("use the ") {
|
||||||
|
return PlayerAction::Use (parse_item_name (rest));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some (rest) = s.strip_prefix ("use ") {
|
||||||
|
return PlayerAction::Use (parse_item_name (rest));
|
||||||
|
}
|
||||||
|
|
||||||
if s == "do nothing" {
|
if s == "do nothing" {
|
||||||
return PlayerAction::Wait;
|
return PlayerAction::Wait;
|
||||||
}
|
}
|
||||||
|
@ -165,92 +205,112 @@ fn parse_item_name (s: &str) -> ItemName {
|
||||||
ItemName::Nonsense
|
ItemName::Nonsense
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive (Default)]
|
#[derive (Clone, Default)]
|
||||||
struct StateRoom1 {
|
struct StateRoom1 {
|
||||||
detected_keypad: bool,
|
detected_keypad: bool,
|
||||||
detected_note: bool,
|
detected_note: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive (Default)]
|
#[derive (Clone, Default)]
|
||||||
struct State {
|
struct State {
|
||||||
quitting: bool,
|
quitting: bool,
|
||||||
room_1: StateRoom1,
|
room_1: StateRoom1,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn room_1 (state: &mut State) -> Result <()> {
|
fn room_1 <I: Io> (io: &mut I, state: &mut State) -> Result <()> {
|
||||||
let input = read_input ()?;
|
let input = io.read_input ()?;
|
||||||
let action = parse_input (&input);
|
let action = parse_input (&input);
|
||||||
|
|
||||||
match action {
|
match action {
|
||||||
PlayerAction::Quit => {
|
PlayerAction::Quit => {
|
||||||
print ("Bye.");
|
io.print ("Bye.");
|
||||||
state.quitting = true;
|
state.quitting = true;
|
||||||
}
|
}
|
||||||
PlayerAction::Help => {
|
PlayerAction::Help => {
|
||||||
print_help ();
|
print_help (io);
|
||||||
},
|
},
|
||||||
PlayerAction::Hint => {
|
PlayerAction::Hint => {
|
||||||
print ("Hint for this room: Try using the `help` command.");
|
io.print ("Hint for this room: Try using the `help` command.");
|
||||||
},
|
},
|
||||||
PlayerAction::Nonsense => {
|
PlayerAction::Nonsense => {
|
||||||
print ("I couldn't understand that. Try `help` or `hint`.");
|
io.print ("I couldn't understand that. Try `help` or `hint`.");
|
||||||
print ("`hint` may contain spoilers. `help` will not.");
|
io.print ("`hint` may contain spoilers. `help` will not.");
|
||||||
},
|
},
|
||||||
PlayerAction::Wait => {
|
PlayerAction::Wait => {
|
||||||
print ("You wait around a bit. You can hear humming from the electrical lights, and the distant rumble of the building's HVAC system. The room smells faintly of fresh paint. Nothing has changed.");
|
io.print ("You wait around a bit. You can hear humming from the electrical lights, and the distant rumble of the building's HVAC system. The room smells faintly of fresh paint. Nothing has changed.");
|
||||||
},
|
},
|
||||||
PlayerAction::LookAround => {
|
PlayerAction::LookAround => {
|
||||||
print ("You are in a small room. In one corner is a TABLE. Obvious exits are a locked DOOR, and an EMERGENCY EXIT.");
|
io.print ("You are in a small room. In one corner is a TABLE. Obvious exits are a locked DOOR, and an EMERGENCY EXIT.");
|
||||||
}
|
}
|
||||||
PlayerAction::Look (item_name) => {
|
PlayerAction::Look (item_name) => {
|
||||||
match item_name {
|
match item_name {
|
||||||
ItemName::Nonsense => {
|
|
||||||
print_undetected_item ();
|
|
||||||
},
|
|
||||||
ItemName::Door => {
|
ItemName::Door => {
|
||||||
print ("You examine the DOOR. It is firmly locked, and you don't have any lock-picking tools. On the DOOR is an electronic KEYPAD.");
|
io.print ("You examine the DOOR. It is firmly locked, and you don't have any lock-picking tools. On the DOOR is an electronic KEYPAD.");
|
||||||
state.room_1.detected_keypad = true;
|
state.room_1.detected_keypad = true;
|
||||||
},
|
},
|
||||||
ItemName::EmergencyExit => {
|
ItemName::EmergencyExit => {
|
||||||
print ("The EMERGENCY EXIT reads, \"Emergency exit. Push bar to open. Alarm will sound. Door will unlock in 15 seconds.\". The EMERGENCY EXIT is period-accurate for an American Wal-Mart c. 2020 C.E.");
|
io.print ("The EMERGENCY EXIT reads, \"Emergency exit. Push bar to open. Alarm will sound. Door will unlock in 10 seconds.\". The EMERGENCY EXIT is period-accurate for an American Wal-Mart c. 2020 C.E.");
|
||||||
},
|
},
|
||||||
ItemName::Keypad => {
|
ItemName::Keypad => {
|
||||||
if state.room_1.detected_keypad {
|
if ! state.room_1.detected_keypad {
|
||||||
print ("The DOOR is locked by an electronic KEYPAD. A soft amber power light indicates that the KEYPAD is likely functional. The KEYPAD buttons are the digits 0-9, Enter, and Clear. Experience tells you that the key code is likely 4 or 5 digits long.");
|
print_undetected_item (io);
|
||||||
}
|
return Ok (());
|
||||||
else {
|
|
||||||
print_undetected_item ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
io.print ("The DOOR is locked by an electronic KEYPAD. A soft amber power light indicates that the KEYPAD is likely functional. The KEYPAD buttons are the digits 0-9, Enter, and Clear. Experience tells you that the key code is likely 4 or 5 digits long.");
|
||||||
},
|
},
|
||||||
ItemName::Note => {
|
ItemName::Note => {
|
||||||
if state.room_1.detected_note {
|
if ! state.room_1.detected_note {
|
||||||
for x in [
|
print_undetected_item (io);
|
||||||
"You pick up the NOTE and read it.",
|
return Ok (());
|
||||||
"",
|
|
||||||
"Welcome to SEROTONIN DEPOSITORY.",
|
|
||||||
"As you play, keep in mind:",
|
|
||||||
"- LOOKing at ITEMS is not always safe",
|
|
||||||
"- TAKEing an item may be bad long-term",
|
|
||||||
"- WAITing counts as an action",
|
|
||||||
"- LOOKing AROUND is always safe",
|
|
||||||
"- Other NOTEs may contain non-truths",
|
|
||||||
"The code for this first KEYPAD is 1234.",
|
|
||||||
"",
|
|
||||||
" -- Phayle Sayf",
|
|
||||||
"",
|
|
||||||
"You notice that the NOTE is _not_ period-accurate.",
|
|
||||||
].into_iter () {
|
|
||||||
print (x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print_undetected_item ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
io.print_many ([
|
||||||
|
"You pick up the NOTE and read it.",
|
||||||
|
"",
|
||||||
|
"Welcome to SEROTONIN DEPOSITORY.",
|
||||||
|
"As you play, keep in mind:",
|
||||||
|
"- LOOKing at ITEMS is not always safe",
|
||||||
|
"- TAKEing an item may be bad long-term",
|
||||||
|
"- WAITing counts as an action",
|
||||||
|
"- LOOKing AROUND is always safe",
|
||||||
|
"- Other NOTEs may contain non-truths",
|
||||||
|
"The code for this first KEYPAD is 1234.",
|
||||||
|
"",
|
||||||
|
" -- Phayle Sayf",
|
||||||
|
"",
|
||||||
|
"You notice that the NOTE is _not_ period-accurate.",
|
||||||
|
])
|
||||||
},
|
},
|
||||||
ItemName::Table => {
|
ItemName::Table => {
|
||||||
print ("You look at the TABLE. Your instincts tell you that it is period-accurate. Upon the TABLE sits a NOTE.");
|
io.print ("You look at the TABLE. Your instincts tell you that it is period-accurate. Upon the TABLE sits a NOTE.");
|
||||||
state.room_1.detected_note = true;
|
state.room_1.detected_note = true;
|
||||||
},
|
},
|
||||||
|
_ => {
|
||||||
|
print_undetected_item (io);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PlayerAction::Use (item_name) => {
|
||||||
|
match item_name {
|
||||||
|
ItemName::Door => {
|
||||||
|
io.print ("You can't USE the DOOR, it is locked.");
|
||||||
|
if ! state.room_1.detected_keypad {
|
||||||
|
io.print ("You notice an electronic KEYPAD on the DOOR.");
|
||||||
|
state.room_1.detected_keypad = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ItemName ::EmergencyExit => {
|
||||||
|
io.print ("You push on the emergency exit. An alarm starts sounding. Your ADVENTURE GAME ENTHUSIAST friend is going to be very mad at you.");
|
||||||
|
io.sleep (5000);
|
||||||
|
io.print ("The alarm is still sounding. You are getting embarrassed, but you have committed to this path of action.");
|
||||||
|
io.sleep (5000);
|
||||||
|
io.print ("The emergency exit unlocks, and you walk out of the game. Bye.");
|
||||||
|
state.quitting = true;
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
print_undetected_item (io);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -259,26 +319,30 @@ fn room_1 (state: &mut State) -> Result <()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main () -> Result <()> {
|
fn main () -> Result <()> {
|
||||||
print ("Welcome to SEROTONIN DEPOSITORY, the only adventure game ever made.");
|
let mut io = Stdio::default ();
|
||||||
print ("");
|
|
||||||
print ("You have been consensually kidnapped by a diabolical ADVENTURE GAME ENTHUSIAST and encouraged to solve PUZZLES for their sick PLEASURE. The only winning move is to solve all the PUZZLES.");
|
|
||||||
print ("");
|
|
||||||
print ("Press ENTER if you dare to begin.");
|
|
||||||
|
|
||||||
let input = read_input ()?;
|
io.print_many ([
|
||||||
|
"Welcome to SEROTONIN DEPOSITORY, the only adventure game ever made.",
|
||||||
|
"",
|
||||||
|
"You have been consensually kidnapped by a diabolical ADVENTURE GAME ENTHUSIAST and encouraged to solve PUZZLES for their sick PLEASURE. The only winning move is to solve all the PUZZLES.",
|
||||||
|
"",
|
||||||
|
"Press ENTER if you dare to begin.",
|
||||||
|
]);
|
||||||
|
|
||||||
|
let input = io.read_input ()?;
|
||||||
|
|
||||||
if ! input.is_empty () {
|
if ! input.is_empty () {
|
||||||
print ("That was more than just ENTER but OKAY, overachiever.");
|
io.print ("That was more than just ENTER but OKAY, overachiever.");
|
||||||
}
|
}
|
||||||
|
|
||||||
print ("");
|
io.print ("");
|
||||||
|
|
||||||
let mut state = State::default ();
|
let mut state = State::default ();
|
||||||
|
|
||||||
print ("You are in a small room. In one corner is a TABLE.");
|
io.print ("You are in a small room. In one corner is a TABLE.");
|
||||||
|
|
||||||
while ! state.quitting {
|
while ! state.quitting {
|
||||||
room_1 (&mut state)?;
|
room_1 (&mut io, &mut state)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok (())
|
Ok (())
|
||||||
|
|
Loading…
Reference in New Issue