♻️ refactor
							parent
							
								
									1ddb5ffe18
								
							
						
					
					
						commit
						576cf0b4e5
					
				
							
								
								
									
										219
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										219
									
								
								src/main.rs
								
								
								
								
							|  | @ -72,8 +72,13 @@ fn just <T> (t: T) -> Vec <T> { | |||
| enum PlayerAction { | ||||
| 	Quit, | ||||
| 	Help, | ||||
| 	Hint, | ||||
| 	Nonsense, | ||||
| 	RoomSpecific (PlayerActionRoomSpecific), | ||||
| } | ||||
| 
 | ||||
| #[derive (Debug, PartialEq)] | ||||
| enum PlayerActionRoomSpecific { | ||||
| 	Hint, | ||||
| 	Wait, | ||||
| 	Look (ItemName), | ||||
| 	LookAround, | ||||
|  | @ -104,79 +109,96 @@ fn _item_name_display (x: ItemName) -> &'static str { | |||
| } | ||||
| 
 | ||||
| fn parse_input (s: &str) -> PlayerAction { | ||||
| 	use PlayerAction::*; | ||||
| 	use PlayerActionRoomSpecific::*; | ||||
| 	
 | ||||
| 	let s = s.to_lowercase (); | ||||
| 	
 | ||||
| 	if s == "quit" || s == "quit game" { | ||||
| 		return PlayerAction::Quit; | ||||
| 		Quit | ||||
| 	} | ||||
| 	
 | ||||
| 	if s == "look" || s == "look around" { | ||||
| 		return PlayerAction::LookAround; | ||||
| 	else if s == "help" || s == "help me" { | ||||
| 		Help | ||||
| 	} | ||||
| 	
 | ||||
| 	if let Some (rest) = s.strip_prefix ("look at the ") { | ||||
| 		return PlayerAction::Look (parse_item_name (rest)); | ||||
| 	else if s == "look" || s == "look around" { | ||||
| 		RoomSpecific (LookAround) | ||||
| 	} | ||||
| 	
 | ||||
| 	if let Some (rest) = s.strip_prefix ("look at ") { | ||||
| 		return PlayerAction::Look (parse_item_name (rest)); | ||||
| 	else if let Some (rest) = s.strip_prefix ("look at the ") { | ||||
| 		RoomSpecific (Look (parse_item_name (rest))) | ||||
| 	} | ||||
| 	
 | ||||
| 	if let Some (rest) = s.strip_prefix ("look ") { | ||||
| 		return PlayerAction::Look (parse_item_name (rest)); | ||||
| 	else if let Some (rest) = s.strip_prefix ("look at ") { | ||||
| 		RoomSpecific (Look (parse_item_name (rest))) | ||||
| 	} | ||||
| 	
 | ||||
| 	if let Some (rest) = s.strip_prefix ("examine ") { | ||||
| 		return PlayerAction::Look (parse_item_name (rest)); | ||||
| 	else if let Some (rest) = s.strip_prefix ("look ") { | ||||
| 		RoomSpecific (Look (parse_item_name (rest))) | ||||
| 	} | ||||
| 	
 | ||||
| 	if let Some (rest) = s.strip_prefix ("use the ") { | ||||
| 		return PlayerAction::Use (parse_item_name (rest)); | ||||
| 	else if let Some (rest) = s.strip_prefix ("examine ") { | ||||
| 		RoomSpecific (Look (parse_item_name (rest))) | ||||
| 	} | ||||
| 	
 | ||||
| 	if let Some (rest) = s.strip_prefix ("use ") { | ||||
| 		return PlayerAction::Use (parse_item_name (rest)); | ||||
| 	else if let Some (rest) = s.strip_prefix ("use the ") { | ||||
| 		RoomSpecific (Use (parse_item_name (rest))) | ||||
| 	} | ||||
| 	
 | ||||
| 	if s == "do nothing" { | ||||
| 		return PlayerAction::Wait; | ||||
| 	else if let Some (rest) = s.strip_prefix ("use ") { | ||||
| 		RoomSpecific (Use (parse_item_name (rest))) | ||||
| 	} | ||||
| 	if s == "wait" { | ||||
| 		return PlayerAction::Wait; | ||||
| 	else if 
 | ||||
| 		s == "do nothing" || | ||||
| 		s == "wait" | ||||
| 	{ | ||||
| 		RoomSpecific (Wait) | ||||
| 	} | ||||
| 	
 | ||||
| 	if s == "help" { | ||||
| 		return PlayerAction::Help; | ||||
| 	else if s == "hint" { | ||||
| 		RoomSpecific (Hint) | ||||
| 	} | ||||
| 	if s == "hint" { | ||||
| 		return PlayerAction::Hint; | ||||
| 	else { | ||||
| 		Nonsense | ||||
| 	} | ||||
| 	
 | ||||
| 	PlayerAction::Nonsense | ||||
| } | ||||
| 
 | ||||
| fn parse_item_name (s: &str) -> ItemName { | ||||
| 	if s == "door" { | ||||
| 		return ItemName::Door; | ||||
| 		ItemName::Door | ||||
| 	} | ||||
| 	
 | ||||
| 	if s == "emergency exit" { | ||||
| 		return ItemName::EmergencyExit; | ||||
| 	else if s == "emergency exit" { | ||||
| 		ItemName::EmergencyExit | ||||
| 	} | ||||
| 	
 | ||||
| 	if s == "keypad" { | ||||
| 		return ItemName::Keypad; | ||||
| 	else if s == "keypad" { | ||||
| 		ItemName::Keypad | ||||
| 	} | ||||
| 	
 | ||||
| 	if s == "note" { | ||||
| 		return ItemName::Note; | ||||
| 	else if s == "note" { | ||||
| 		ItemName::Note | ||||
| 	} | ||||
| 	
 | ||||
| 	if s == "table" { | ||||
| 		return ItemName::Table; | ||||
| 	else if s == "table" { | ||||
| 		ItemName::Table | ||||
| 	} | ||||
| 	else { | ||||
| 		ItemName::Nonsense | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| macro_rules! require_detection { | ||||
| 	($condition:expr $(,)?) => { | ||||
| 		if ! $condition { | ||||
| 			return vec! [ | ||||
| 				Response::FailedDetectionCheck, | ||||
| 				undetected_item (), | ||||
| 			]; | ||||
| 		} | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| #[derive (Clone)] | ||||
| enum RoomName { | ||||
| 	/// Starting room with the dead-simple note and keypad puzzle.
 | ||||
| 	Room1, | ||||
| 	/// Duplicate of starting room so I can change things around a little.
 | ||||
| 	Room2, | ||||
| } | ||||
| 
 | ||||
| impl Default for RoomName { | ||||
| 	fn default () -> Self { | ||||
| 		Self::Room1 | ||||
| 	} | ||||
| 	
 | ||||
| 	ItemName::Nonsense | ||||
| } | ||||
| 
 | ||||
| #[derive (Clone, Default)] | ||||
|  | @ -199,55 +221,41 @@ enum Response { | |||
| 	FailedDetectionCheck, | ||||
| } | ||||
| 
 | ||||
| macro_rules! require_detection { | ||||
| 	($condition:expr $(,)?) => { | ||||
| 		if ! $condition { | ||||
| 			return vec! [ | ||||
| 				Response::FailedDetectionCheck, | ||||
| 				undetected_item (), | ||||
| 			]; | ||||
| 		} | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| #[derive (Clone, Default)] | ||||
| struct State { | ||||
| 	current_room: RoomName, | ||||
| 	room_1: StateRoom1, | ||||
| } | ||||
| 
 | ||||
| impl State { | ||||
| 	fn step (&mut self, input: &str) -> Vec <Response> { | ||||
| 		self.room_1 (input) | ||||
| 	} | ||||
| 	
 | ||||
| 	fn room_1 (&mut self, input: &str) -> Vec <Response> { | ||||
| 		use Response::*; | ||||
| 		
 | ||||
| 		let action = parse_input (input); | ||||
| 		
 | ||||
| 		match action { | ||||
| 			PlayerAction::Quit => { | ||||
| 				vec! [ | ||||
| 					line_response ("Bye."), | ||||
| 					Quit, | ||||
| 				] | ||||
| 			} | ||||
| 			PlayerAction::Help => { | ||||
| 				just (print_help ()) | ||||
| 			}, | ||||
| 			PlayerAction::Hint => { | ||||
| 			PlayerAction::Quit => vec! [ | ||||
| 				line_response ("Bye."), | ||||
| 				Response::Quit, | ||||
| 			], | ||||
| 			PlayerAction::Help => just (print_help ()), | ||||
| 			PlayerAction::Nonsense => vec! [ | ||||
| 				line_response ("I couldn't understand that. Try `help` or `hint`."), | ||||
| 				line_response ("`hint` may contain spoilers. `help` will not."), | ||||
| 			], | ||||
| 			PlayerAction::RoomSpecific (x) => self.room_1 (x), | ||||
| 		} | ||||
| 	} | ||||
| 	
 | ||||
| 	fn room_1 (&mut self, action: PlayerActionRoomSpecific) -> Vec <Response> { | ||||
| 		use PlayerActionRoomSpecific::*; | ||||
| 		
 | ||||
| 		match action { | ||||
| 			Hint => { | ||||
| 				just (line_response ("Hint for this room: Try using the `help` command.")) | ||||
| 			}, | ||||
| 			PlayerAction::Nonsense => { | ||||
| 				vec! [ | ||||
| 					line_response ("I couldn't understand that. Try `help` or `hint`."), | ||||
| 					line_response ("`hint` may contain spoilers. `help` will not."), | ||||
| 				] | ||||
| 			}, | ||||
| 			PlayerAction::Wait => { | ||||
| 			Wait => { | ||||
| 				just (line_response ("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 => { | ||||
| 			LookAround => { | ||||
| 				let mut output = vec! [ | ||||
| 					line_response ("You are in a small room. In one corner is a TABLE. Obvious exits are a DOOR, and an EMERGENCY EXIT."), | ||||
| 				]; | ||||
|  | @ -261,7 +269,7 @@ impl State { | |||
| 				
 | ||||
| 				output | ||||
| 			} | ||||
| 			PlayerAction::Look (item_name) => { | ||||
| 			Look (item_name) => { | ||||
| 				match item_name { | ||||
| 					ItemName::Door => { | ||||
| 						self.room_1.detected_keypad = true; | ||||
|  | @ -299,18 +307,14 @@ impl State { | |||
| 					}, | ||||
| 					ItemName::Table => { | ||||
| 						self.room_1.detected_note = true; | ||||
| 						vec! [ | ||||
| 							Response::Print ("You look at the TABLE. Your instincts tell you that it is period-accurate. Upon the TABLE sits a NOTE.".into ()), | ||||
| 						] | ||||
| 						just (line_response ("You look at the TABLE. Your instincts tell you that it is period-accurate. Upon the TABLE sits a NOTE.")) | ||||
| 					}, | ||||
| 					_ => { | ||||
| 						vec! [ | ||||
| 							undetected_item (), | ||||
| 						] | ||||
| 						just (undetected_item ()) | ||||
| 					}, | ||||
| 				} | ||||
| 			}, | ||||
| 			PlayerAction::Use (item_name) => { | ||||
| 			Use (item_name) => { | ||||
| 				match item_name { | ||||
| 					ItemName::Door => { | ||||
| 						let mut output = vec! [ | ||||
|  | @ -319,18 +323,18 @@ impl State { | |||
| 						
 | ||||
| 						if ! self.room_1.detected_keypad { | ||||
| 							self.room_1.detected_keypad = true; | ||||
| 							output.push (Response::Print ("You notice an electronic KEYPAD on the DOOR.".into ())); | ||||
| 							output.push (line_response ("You notice an electronic KEYPAD on the DOOR.")); | ||||
| 						} | ||||
| 						
 | ||||
| 						output | ||||
| 					}, | ||||
| 					ItemName::EmergencyExit => { | ||||
| 						vec! [ | ||||
| 							Response::Print ("You push on the emergency exit. An alarm starts sounding. Your ADVENTURE GAME ENTHUSIAST friend is going to be very mad at you.".into ()), | ||||
| 							line_response ("You push on the emergency exit. An alarm starts sounding. Your ADVENTURE GAME ENTHUSIAST friend is going to be very mad at you."), | ||||
| 							Response::Sleep (5000), | ||||
| 							Response::Print ("The alarm is still sounding. You are getting embarrassed, but you have committed to this path of action.".into ()), | ||||
| 							line_response ("The alarm is still sounding. You are getting embarrassed, but you have committed to this path of action."), | ||||
| 							Response::Sleep (5000), | ||||
| 							Response::Print ("The emergency exit unlocks, and you walk out of the game. Bye.".into ()), | ||||
| 							line_response ("The emergency exit unlocks, and you walk out of the game. Bye."), | ||||
| 							Response::JokeEnding, | ||||
| 							Response::Quit, | ||||
| 						] | ||||
|  | @ -353,9 +357,7 @@ impl State { | |||
| 						just (line_response ("You can't think of any way to USE the TABLE that would be better than LOOKing at it.")) | ||||
| 					}, | ||||
| 					_ => { | ||||
| 						vec! [ | ||||
| 							undetected_item (), | ||||
| 						] | ||||
| 						just (undetected_item ()) | ||||
| 					}, | ||||
| 				} | ||||
| 			}, | ||||
|  | @ -426,17 +428,18 @@ mod test { | |||
| 		use super::{ | ||||
| 			ItemName, | ||||
| 			PlayerAction::*, | ||||
| 			PlayerActionRoomSpecific::*, | ||||
| 		}; | ||||
| 		
 | ||||
| 		for (input, expected) in [ | ||||
| 			 ("", Nonsense), | ||||
| 			 ("look at the table", Look (ItemName::Table)), | ||||
| 			 ("look at table", Look (ItemName::Table)), | ||||
| 			 ("look table", Look (ItemName::Table)), | ||||
| 			 ("LOOK TABLE", Look (ItemName::Table)), | ||||
| 			 ("wait", Wait), | ||||
| 			 ("help", Help), | ||||
| 			 ("hint", Hint), | ||||
| 			("", Nonsense), | ||||
| 			("help", Help), | ||||
| 			("look at the table", RoomSpecific (Look (ItemName::Table))), | ||||
| 			("look at table", RoomSpecific (Look (ItemName::Table))), | ||||
| 			("look table", RoomSpecific (Look (ItemName::Table))), | ||||
| 			("LOOK TABLE", RoomSpecific (Look (ItemName::Table))), | ||||
| 			("wait", RoomSpecific (Wait)), | ||||
| 			("hint", RoomSpecific (Hint)), | ||||
| 		].into_iter () { | ||||
| 			let actual = super::parse_input (input); | ||||
| 			assert_eq! (actual, expected); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 _
						_