♻️ 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.
 | ||||
| 
 | ||||
| #[derive (Debug)] | ||||
|  | @ -34,27 +28,16 @@ fn print (mut s: &str) { | |||
| 	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> { | ||||
| 	{ | ||||
| 		let mut stdout = stdout (); | ||||
| 		use std::io::Write; | ||||
| 		let mut stdout = std::io::stdout (); | ||||
| 		stdout.write_all (b"> ")?; | ||||
| 		stdout.flush ()?; | ||||
| 	} | ||||
| 	
 | ||||
| 	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.
 | ||||
| 	let x: &[_] = &['\r', '\n']; | ||||
|  | @ -63,6 +46,54 @@ fn read_input () -> Result <String> { | |||
| 	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)] | ||||
| enum PlayerAction { | ||||
| 	Quit, | ||||
|  | @ -72,6 +103,7 @@ enum PlayerAction { | |||
| 	Wait, | ||||
| 	Look (ItemName), | ||||
| 	LookAround, | ||||
| 	Use (ItemName), | ||||
| } | ||||
| 
 | ||||
| #[derive (Clone, Copy, Debug, PartialEq)] | ||||
|  | @ -85,15 +117,15 @@ enum ItemName { | |||
| 	Table, | ||||
| } | ||||
| 
 | ||||
| fn item_name_display (x: ItemName) -> &'static str { | ||||
| fn _item_name_display (x: ItemName) -> &'static str { | ||||
| 	match x { | ||||
| 		Nonsense => "NONSENSE", | ||||
| 		ItemName::Nonsense => "NONSENSE", | ||||
| 		
 | ||||
| 		Door => "DOOR", | ||||
| 		EmergencyExit => "EMERGENCY EXIT", | ||||
| 		Keypad => "KEYPAD", | ||||
| 		Note => "NOTE", | ||||
| 		Table => "TABLE", | ||||
| 		ItemName::Door => "DOOR", | ||||
| 		ItemName::EmergencyExit => "EMERGENCY EXIT", | ||||
| 		ItemName::Keypad => "KEYPAD", | ||||
| 		ItemName::Note => "NOTE", | ||||
| 		ItemName::Table => "TABLE", | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -124,6 +156,14 @@ fn parse_input (s: &str) -> PlayerAction { | |||
| 		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" { | ||||
| 		return PlayerAction::Wait; | ||||
| 	} | ||||
|  | @ -165,92 +205,112 @@ fn parse_item_name (s: &str) -> ItemName { | |||
| 	ItemName::Nonsense | ||||
| } | ||||
| 
 | ||||
| #[derive (Default)] | ||||
| #[derive (Clone, Default)] | ||||
| struct StateRoom1 { | ||||
| 	detected_keypad: bool, | ||||
| 	detected_note: bool, | ||||
| } | ||||
| 
 | ||||
| #[derive (Default)] | ||||
| #[derive (Clone, Default)] | ||||
| struct State { | ||||
| 	quitting: bool, | ||||
| 	room_1: StateRoom1, | ||||
| } | ||||
| 
 | ||||
| fn room_1 (state: &mut State) -> Result <()> { | ||||
| 	let input = read_input ()?; | ||||
| fn room_1 <I: Io> (io: &mut I, state: &mut State) -> Result <()> { | ||||
| 	let input = io.read_input ()?; | ||||
| 	let action = parse_input (&input); | ||||
| 	
 | ||||
| 	match action { | ||||
| 		PlayerAction::Quit => { | ||||
| 			print ("Bye."); | ||||
| 			io.print ("Bye."); | ||||
| 			state.quitting = true; | ||||
| 		} | ||||
| 		PlayerAction::Help => { | ||||
| 			print_help (); | ||||
| 			print_help (io); | ||||
| 		}, | ||||
| 		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 => { | ||||
| 			print ("I couldn't understand that. Try `help` or `hint`."); | ||||
| 			print ("`hint` may contain spoilers. `help` will not."); | ||||
| 			io.print ("I couldn't understand that. Try `help` or `hint`."); | ||||
| 			io.print ("`hint` may contain spoilers. `help` will not."); | ||||
| 		}, | ||||
| 		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 => { | ||||
| 			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) => { | ||||
| 			match item_name { | ||||
| 				ItemName::Nonsense => { | ||||
| 					print_undetected_item (); | ||||
| 				}, | ||||
| 				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; | ||||
| 				}, | ||||
| 				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 => { | ||||
| 					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."); | ||||
| 					} | ||||
| 					else { | ||||
| 						print_undetected_item (); | ||||
| 					if ! state.room_1.detected_keypad { | ||||
| 						print_undetected_item (io); | ||||
| 						return Ok (()); | ||||
| 					} | ||||
| 					
 | ||||
| 					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 => { | ||||
| 					if state.room_1.detected_note { | ||||
| 						for x in [ | ||||
| 							"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.", | ||||
| 						].into_iter () { | ||||
| 							print (x); | ||||
| 						} | ||||
| 					} | ||||
| 					else { | ||||
| 						print_undetected_item (); | ||||
| 					if ! state.room_1.detected_note { | ||||
| 						print_undetected_item (io); | ||||
| 						return Ok (()); | ||||
| 					} | ||||
| 					
 | ||||
| 					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 => { | ||||
| 					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; | ||||
| 				}, | ||||
| 				_ => { | ||||
| 					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 <()> { | ||||
| 	print ("Welcome to SEROTONIN DEPOSITORY, the only adventure game ever made."); | ||||
| 	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 mut io = Stdio::default (); | ||||
| 	
 | ||||
| 	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 () { | ||||
| 		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 (); | ||||
| 	
 | ||||
| 	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 { | ||||
| 		room_1 (&mut state)?; | ||||
| 		room_1 (&mut io, &mut state)?; | ||||
| 	} | ||||
| 	
 | ||||
| 	Ok (()) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 _
						_