use std::io::Write;
#[cfg(feature = "blasphemy")]
use rand::distr::Distribution;
#[cfg(feature = "blasphemy")]
use std::io::Read;
use crate::edge::Edge;
moddef::moddef!(
mod {
edge,
domain,
triad
}
);
fn main()
{
let mut args = std::env::args();
let executeable = args.next()
.unwrap_or_else(|| "enneagram".to_string());
assert_eq!(executeable, "enneagram", "What are you running?");
let mut edges = Vec::<Edge>::new();
loop
{
let argument = match args.next()
{
Some(number) => number,
None => {
if edges.is_empty()
{
let domain = domain::select();
let edge = domain.edge();
let edge_info = core::fmt::from_fn(|f| edge.info(f));
println!("\n{edge_info}");
return
}
else
{
let edge_info = core::fmt::from_fn(|f| Edge::common_info(&edges, f));
println!("{edge_info}");
return
}
}
};
if let Ok(mut number) = argument.parse::<u128>()
{
let index = edges.len();
loop
{
let digit = (number % 10) as u8;
let edge = Edge::from_number(digit);
edges.push(edge);
if number >= 10
{
number /= 10
}
else
{
break
}
}
if let Some(addition) = edges.get_mut(index..)
{
addition.reverse();
}
continue;
}
panic!("Invalid arguments.")
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Clause<'a>
{
Question,
Answer(&'a str),
Continuation(&'a str)
}
fn select<T>(
clause: Clause<'_>,
options: &[(&str, &dyn Fn() -> T)]
) -> T
{
assert!(options.len() > 0, "No options have been provided. Why ask a question when you provide only the illusion of choice. That's not allowed.");
let numer_of_options = u8::try_from(options.len())
.expect("Amount of options cannot exceed 255, due to technical limitations. Because we store the keys of each choice as a byte.");
match clause
{
Clause::Question => print!("\x1b[s\x1b 7"),
Clause::Answer(question) => println!("Q: {question}\x1b[s\x1b 7"),
Clause::Continuation(conjunction) => println!("\x1b[u\x1b 8\x1b[0J{conjunction}\x1b[s\x1b 7")
}
println!("(pick one)");
for (n, (choice, _)) in options.iter()
.enumerate()
.map(|(m, option)| m.checked_add(1)
.and_then(|n| u8::try_from(n).ok())
.map(|n: u8| (n, option))
.expect("Choice-numbers cannot exceed 255, due to technical limitations. Because we store the keys of each choice as a byte.")
)
{
println!("\t{n}. {choice}")
}
let mut choice_string = String::new();
std::io::stdout()
.flush()
.expect("Failed to flush stdout");
std::io::stdin()
.read_line(&mut choice_string)
.expect("We failed to read the input because of an input-output error from your operating-system.");
let choice_str = choice_string.trim();
let choice = if choice_str.is_empty()
{
#[cfg(feature = "blasphemy")]
{
use std::io::Write;
println!("~ You don't seem to have entered anything at all! Due to your indecisiveness, a choice will be made for you...");
println!("~ Your computer's random number generator will be used to generate a random number. What comes from it, i cannot guarantee.");
println!("~ Whether the elfs that reside in your machine are working for a righteous master, i don't know. It is out of my control.");
println!("~ If you want to disable this feature, you can compile this computer program without the `blasphemy` feature.");
println!("~ Your fate is now in the hands of forces beyond.");
print!("\n[ Press enter to continue... ]");
std::io::stdout()
.flush()
.expect("Failed to flush stdout");
let _ = std::io::stdin()
.read(&mut [0])
.expect("Failed to wait for any-key");
let mut divine_intellect = rand::rng(); let god_dice = rand::distr::Uniform::try_from(0..options.len() as u8) .expect("Did you not present a nonzero amount of choices to begin with? Regardless, not even God can roll his dice when the range of possibilities is unsound. Make up your mind.");
let choice_number = god_dice.sample(&mut divine_intellect);
options.get(choice_number as usize)
.expect("Due to unforseen events, it seems the number was out of range.")
}
#[cfg(not(feature = "blasphemy"))]
{
panic!("You are running the blasphemy-free version of the enneagram software. You must make the decision yourself. Machine elves are not enabled due to the risk of blasphemy.")
}
}
else
{
assert_eq!(choice_str.len(), 1, "There must have been a mistake. More bytes were read than expected. We only expect one byte to be read here.");
let choice_number = choice_str.parse::<u8>()
.expect("What you wrote could not be parsed. Please write a number corresponding to one of the choices presented to you.");
assert!(choice_number <= numer_of_options, "You tried to select an option that doesn't exist. Your number is out of range. Please write a number corresponding to one of the choices presented to you.");
let choice_index = choice_number.checked_sub(1)
.expect("Your number is out of range. Please write a number corresponding to one of the choices presented to you. It cannot be 0.");
options.get(choice_index as usize)
.expect("Your number is out of range. Please write a number corresponding to one of the choices presented to you.")
};
print!("\x1b[u\x1b 8\x1b[0J"); let (expression, result) = choice;
match clause
{
Clause::Question => println!("\nQ: {expression}\x1b[s\x1b 7"),
Clause::Answer(_) => println!("\nA: {expression}\x1b[s\x1b 7"),
Clause::Continuation(_) => println!("{expression}\x1b[s\x1b 7"),
}
result()
}