use kajam_10_game::{ Response, State, }; /// As a dare to myself, I won't use any error-handling crates. #[derive (Debug)] enum GameError { IoError, } impl From for GameError { fn from (_: std::io::Error) -> Self { Self::IoError } } type Result = std::result::Result ; /// Prints a string, naively wrapping at 80-character boundaries /// This means a period might be wrapped separate from the sentence it ends /// , and frankly I think that's part of the charm. fn print (mut s: &str) { const COLS: usize = 80; while s.len () > COLS { println! ("{}", &s [0..80]); s = &s [80..]; } println! ("{}", s); } fn read_input () -> Result { { use std::io::Write; let mut stdout = std::io::stdout (); stdout.write_all (b"> ")?; stdout.flush ()?; } let mut buffer = String::new (); 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']; let buffer = buffer.trim_end_matches (x).to_string (); Ok (buffer) } fn game (args: &[String]) -> Result <()> { let mut state = State::default (); if args.get (1) == Some (&"cheat".to_string ()) { state.cheat (); } let responses = state.step (""); for response in responses.into_iter () { match response { Response::Print (line) => print (&line), Response::PrintMany (lines) => { for line in lines { print (line); } }, Response::Sleep (x) => std::thread::sleep (std::time::Duration::from_millis (x.into ())), _ => (), } } 'main_loop: loop { let input = read_input ()?; let responses = state.step (&input); for response in responses.into_iter () { match response { Response::Print (line) => print (&line), Response::PrintMany (lines) => { for line in lines { print (line); } }, Response::Sleep (x) => std::thread::sleep (std::time::Duration::from_millis (x.into ())), Response::Quit => break 'main_loop, _ => (), } } } Ok (()) } fn main () -> Result <()> { let args: Vec <_> = std::env::args ().collect (); game (&args [..])?; Ok (()) }