kajam_10/src/main.rs

103 lines
2.1 KiB
Rust

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 <std::io::Error> for GameError {
fn from (_: std::io::Error) -> Self {
Self::IoError
}
}
type Result <T> = std::result::Result <T, GameError>;
/// 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 <String> {
{
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 (())
}