ok
ok
This commit is contained in:
Executable
+582
@@ -0,0 +1,582 @@
|
||||
use core::fmt;
|
||||
use alloc::{boxed::Box, string::String, vec::Vec};
|
||||
use alloc::string::ToString;
|
||||
use alloc::borrow::ToOwned;
|
||||
use crate::{println, print, mknode, std};
|
||||
|
||||
|
||||
use async_trait::async_trait;
|
||||
use crate::std::application::{
|
||||
Application,
|
||||
Error as ShellError
|
||||
};
|
||||
|
||||
struct Parser {
|
||||
tokens: Vec<Token>,
|
||||
idx: i32,
|
||||
current: Token
|
||||
}
|
||||
|
||||
|
||||
struct Interpreter {}
|
||||
|
||||
|
||||
|
||||
impl Interpreter {
|
||||
|
||||
fn new() -> Result<Self, Error>{
|
||||
return Ok(Self {})
|
||||
}
|
||||
|
||||
fn visit(&mut self, node: Node) -> Result<Value, Error> {
|
||||
match node {
|
||||
Node::BinaryOperation(_) => return self.visit_binary_operation(node),
|
||||
Node::UnaryOperation(_) => return self.visit_unary_operation(node),
|
||||
Node::Number(_) => return self.visit_number(node),
|
||||
Node::Operator(_) => return self.visit_operator(node),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn visit_number(&mut self, node: Node) -> Result<Value, Error> {
|
||||
|
||||
if let Node::Number(x) = node {
|
||||
Ok(Value::Number(x))
|
||||
} else {
|
||||
Err(Error::Other(String::from("value accessed was not an number")))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn visit_operator(&mut self, node: Node) -> Result<Value, Error> {
|
||||
|
||||
if let Node::Operator(x) = node {
|
||||
Ok(Value::Operator(x))
|
||||
} else {
|
||||
Err(Error::Other(String::from("value is not an operator")))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn visit_binary_operation(&mut self, node: Node) -> Result<Value, Error> {
|
||||
|
||||
let left = match self.visit(self.get_node(node.clone(), "left")?.expect("returned none").to_owned())? {
|
||||
Value::Number(x) => x,
|
||||
_ => return Err(Error::Other(String::from("value is not a number"))),
|
||||
};
|
||||
|
||||
let right = match self.visit(self.get_node(node.clone(), "right")?.expect("returned none").to_owned())? {
|
||||
Value::Number(x) => x,
|
||||
_ => return Err(Error::Other(String::from("value is not a number"))),
|
||||
};
|
||||
|
||||
let operator = match self.visit(self.get_node(node.clone(), "operator")?.expect("returned none").to_owned())? {
|
||||
Value::Operator(x) => x,
|
||||
_ => return Err(Error::Other(String::from("value is not a binary operator"))),
|
||||
};
|
||||
|
||||
match operator {
|
||||
Operator::Add => {
|
||||
return Ok(Value::Number(left + right))
|
||||
},
|
||||
Operator::Sub => {
|
||||
return Ok(Value::Number(left - right))
|
||||
},
|
||||
Operator::Div => {
|
||||
if right != 0.0 {
|
||||
return Ok(Value::Number(left / right))
|
||||
} else {
|
||||
return Err(Error::LogicalError(String::from("division by 0")))
|
||||
}
|
||||
},
|
||||
Operator::Mod => {
|
||||
return Ok(Value::Number(left % right))
|
||||
},
|
||||
Operator::Qot => {
|
||||
if right != 0.0 {
|
||||
return Ok(Value::Number(
|
||||
((left / right) as i64) as f64
|
||||
))
|
||||
} else {
|
||||
return Err(Error::LogicalError(String::from("division by 0")))
|
||||
}
|
||||
},
|
||||
Operator::Mul => {
|
||||
return Ok(Value::Number(left * right))
|
||||
},
|
||||
Operator::Exp => {
|
||||
return Ok(Value::Number({
|
||||
let mut val = 1.0;
|
||||
for _ in 0..(right as i64) {
|
||||
val *= left
|
||||
};
|
||||
val
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn visit_unary_operation(&mut self, node: Node) -> Result<Value, Error> {
|
||||
|
||||
let other: f64 = match self.visit(self.get_node(node.clone(), "other")?.expect("returned none").to_owned())? {
|
||||
Value::Number(x) => x,
|
||||
_ => return Err(Error::LogicalError("value is not a number".to_string()))
|
||||
};
|
||||
|
||||
if let Node::UnaryOperation(x) = node {
|
||||
match x.operator {
|
||||
Node::Operator(Operator::Sub) => {
|
||||
return Ok(Value::Number(other * -1f64));
|
||||
},
|
||||
_ => return Err(Error::LogicalError("value is not an operator".to_string()))
|
||||
}
|
||||
} else {
|
||||
return Err(Error::LogicalError("node is not a binary operator".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_node(&self, node: Node, position: &str) -> Result<Option<Node>, Error> {
|
||||
let result = match position {
|
||||
"left" => {
|
||||
if let Node::BinaryOperation(x) = node {
|
||||
Some(x.left)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
"right" => {
|
||||
if let Node::BinaryOperation(x) = node {
|
||||
Some(x.right)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
"other" => {
|
||||
if let Node::UnaryOperation(x) = node {
|
||||
Some(x.other)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
"operator" => {
|
||||
if let Node::BinaryOperation(x) = node {
|
||||
Some(x.operator)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => return Err(Error::Other(String::from("invalid param for get_Node")))
|
||||
};
|
||||
Ok(result)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
impl Parser {
|
||||
fn new(tokens: Vec<Token>) -> Result<Self, Error> {
|
||||
let mut parser = Self { tokens, idx: -1, current: Token::Null };
|
||||
parser.advance()?;
|
||||
Ok(parser)
|
||||
|
||||
}
|
||||
|
||||
fn parse(&mut self) -> Result<Node, Error> {
|
||||
let result = self.expr();
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn advance(&mut self) -> Result<Option<Token>, Error> {
|
||||
self.idx += 1;
|
||||
if self.idx < self.tokens.len() as i32 {
|
||||
self.current = self.tokens[self.idx as usize].clone();
|
||||
Ok(Some(self.current.clone()))
|
||||
} else if self.idx == self.tokens.len() as i32 {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(Error::Eof)
|
||||
}
|
||||
}
|
||||
|
||||
fn atom(&mut self) -> Result<Node, Error> {
|
||||
let token = self.current.clone();
|
||||
|
||||
match token {
|
||||
Token::Number(x) => {
|
||||
self.advance()?;
|
||||
return Ok(Node::Number(x))
|
||||
},
|
||||
|
||||
Token::Bracket('(') => {
|
||||
self.advance()?;
|
||||
let expr = self.expr()?;
|
||||
|
||||
if let Token::Bracket(')') = self.current {
|
||||
self.advance()?;
|
||||
return Ok(expr)
|
||||
} else {
|
||||
return Err(Error::InvalidSyntax(0))
|
||||
}
|
||||
},
|
||||
_ => return Err(Error::InvalidSyntax(0))
|
||||
}
|
||||
}
|
||||
|
||||
fn power(&mut self) -> Result<Node, Error> {
|
||||
let mut left = self.atom()?;
|
||||
|
||||
while let Token::Operator(Operator::Exp) = self.current {
|
||||
let current = self.current.clone();
|
||||
self.advance()?;
|
||||
let operator = mknode!(current).expect("mknode function returned None");
|
||||
let right = self.factor()?;
|
||||
|
||||
left = Node::BinaryOperation(Box::new(BinaryOperation { left: left.clone(), operator, right }));
|
||||
}
|
||||
Ok(left)
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn factor(&mut self) -> Result<Node, Error> {
|
||||
|
||||
let token = self.current.clone();
|
||||
|
||||
match token {
|
||||
Token::Operator(Operator::Add) | Token::Operator(Operator::Sub) => {
|
||||
self.advance()?;
|
||||
let operator = mknode!(token).expect("mknode returned none");
|
||||
let other = self.factor().expect("holup");
|
||||
return Ok(Node::UnaryOperation(Box::new(UnaryOperation { operator, other})))
|
||||
},
|
||||
|
||||
_ => {
|
||||
return Ok(self.power()?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn term(&mut self) -> Result<Node, Error> {
|
||||
|
||||
let mut left = self.factor()?;
|
||||
|
||||
while let Token::Operator(Operator::Div)
|
||||
| Token::Operator(Operator::Mul)
|
||||
| Token::Operator(Operator::Mod)
|
||||
| Token::Operator(Operator::Qot) = self.current {
|
||||
|
||||
let current = self.current.clone();
|
||||
self.advance()?;
|
||||
let operator = mknode!(current).expect("mknode function returned None");
|
||||
let right = self.factor()?;
|
||||
|
||||
left = Node::BinaryOperation(Box::new(BinaryOperation { left: left.clone(), operator, right }));
|
||||
}
|
||||
Ok(left)
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn expr(&mut self) -> Result<Node, Error> {
|
||||
let mut left = self.term()?;
|
||||
|
||||
while let Token::Operator(Operator::Sub) | Token::Operator(Operator::Add) = self.current {
|
||||
let current = self.current.clone();
|
||||
self.advance()?;
|
||||
let operator = mknode!(current).expect("mknode returned None");
|
||||
let right = self.term()?;
|
||||
|
||||
left = Node::BinaryOperation(Box::new(BinaryOperation { left: left.clone(), operator, right }));
|
||||
}
|
||||
Ok(left)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! mknode {
|
||||
($token:expr) => {
|
||||
match $token {
|
||||
Token::Operator(x) => Some(Node::Operator(x)),
|
||||
Token::Number(x) => Some(Node::Number(x)),
|
||||
_ => None
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct Calculator {}
|
||||
|
||||
#[async_trait]
|
||||
impl Application for Calculator {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
async fn run(&mut self, args: Vec<String>) -> Result<(), ShellError> {
|
||||
if args.len() == 0 {
|
||||
loop {
|
||||
print!("enter equation > ");
|
||||
let inp = std::io::stdin().await;
|
||||
println!("{}", inp);
|
||||
if inp == String::from("exit\n") {
|
||||
return Ok(());
|
||||
}
|
||||
match calculate_inner(inp) {
|
||||
Ok(_) => (),
|
||||
Err(_) => { println!("your input must be a valid mathematical expression contaning only numbers (including floats) and the operators: [ +, -, *, **, /, //, % ]"); return Err(ShellError::CommandFailed(String::from("failed"))) },
|
||||
};
|
||||
}
|
||||
} else {
|
||||
match calculate_inner(args.into_iter().collect()) {
|
||||
Ok(x) => x,
|
||||
Err(_) => { println!("your input must be a valid mathematical expression contaning only numbers (including floats) and the operators: [ +, -, *, **, /, //, % ]"); return Err(ShellError::CommandFailed(String::from("failed"))) },
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn calculate_inner(mut equation: String) -> Result<f64, Error> {
|
||||
|
||||
equation.push('\n');
|
||||
let mut neweq = equation.clone();
|
||||
neweq.pop();
|
||||
|
||||
|
||||
let tokens = tokenise(&equation)?;
|
||||
|
||||
let mut parser = Parser::new(tokens)?;
|
||||
let ast = parser.parse()?;
|
||||
|
||||
|
||||
let mut interpreter = Interpreter::new()?;
|
||||
let result = interpreter.visit(ast)?;
|
||||
|
||||
let return_res = {
|
||||
if let Value::Number(x) = result {
|
||||
x
|
||||
} else {
|
||||
panic!("did not return a float!");
|
||||
}
|
||||
};
|
||||
println!("\n\n
|
||||
_____ _ _
|
||||
/ ____| | | | |
|
||||
| | _ __ _ _ ___| |_ __ _| |
|
||||
| | | '__| | | / __| __/ _` | |
|
||||
| |____| | | |_| \\__ \\ || (_| | |
|
||||
\\_____|_| \\__, |___/\\__\\__,_|_|
|
||||
_____ __/ |
|
||||
/ ____||___/ |
|
||||
| | __ _| | ___
|
||||
| | / _` | |/ __|
|
||||
| |___| (_| | | (__
|
||||
\\_____\\__,_|_|\\___|
|
||||
|
||||
┌────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ Expression -> [ {} ]
|
||||
│ │
|
||||
│ Calculated Solution -> [ {} ]
|
||||
│ │
|
||||
└────────────────────────────────────────────┘
|
||||
", neweq, return_res);
|
||||
|
||||
Ok(return_res)
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn tokenise(equation: &str) -> Result<Vec<Token>, Error> {
|
||||
let mut tokens = Vec::new();
|
||||
let mut current_num = "".to_string();
|
||||
let current_string: String = "".to_string();
|
||||
|
||||
'mainloop: for (x, character) in equation.chars().enumerate() {
|
||||
|
||||
|
||||
match character {
|
||||
'0'..='9' => current_num.push(character),
|
||||
'.' => current_num.push(character),
|
||||
_ => {
|
||||
if current_num.len() != 0 {
|
||||
tokens.push(Token::Number(current_num.parse::<f64>().unwrap()));
|
||||
current_num = "".to_string();
|
||||
} else if current_string.len() != 0 {
|
||||
|
||||
} match character {
|
||||
'+' => tokens.push(Token::Operator(Operator::Add)),
|
||||
'-' => tokens.push(Token::Operator(Operator::Sub)),
|
||||
'%' => tokens.push(Token::Operator(Operator::Mod)),
|
||||
'*' => {
|
||||
if &equation.chars().nth(x-1).unwrap() == &'*' {
|
||||
tokens.push(Token::Operator(Operator::Exp));
|
||||
} else if &equation.chars().nth(x+1).unwrap() == &'*' {
|
||||
()
|
||||
} else {
|
||||
tokens.push(Token::Operator(Operator::Mul));
|
||||
}
|
||||
},
|
||||
'/' => {
|
||||
if &equation.chars().nth(x-1).unwrap() == &'/' {
|
||||
tokens.push(Token::Operator(Operator::Qot));
|
||||
} else if &equation.chars().nth(x+1).unwrap() == &'/' {
|
||||
()
|
||||
} else {
|
||||
tokens.push(Token::Operator(Operator::Div));
|
||||
}
|
||||
},
|
||||
'(' | ')' | '[' | ']' | '{' | '}' | '<' | '>' => tokens.push(Token::Bracket(character)),
|
||||
'\n' => break 'mainloop,
|
||||
' ' => (),
|
||||
_ => {
|
||||
return Err(Error::InvalidCharacter(x))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Value {
|
||||
Number(f64),
|
||||
Operator(Operator)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
enum Token {
|
||||
Number(f64),
|
||||
Operator(Operator),
|
||||
Bracket(char),
|
||||
Null,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Debug, Clone, PartialEq)]
|
||||
enum Operator {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Qot,
|
||||
Mod,
|
||||
Exp,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
InvalidSyntax(usize),
|
||||
InvalidCharacter(usize),
|
||||
LogicalError(String),
|
||||
Eof,
|
||||
Other(String),
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
enum Node {
|
||||
Number(f64),
|
||||
Operator(Operator),
|
||||
BinaryOperation(Box<BinaryOperation>),
|
||||
UnaryOperation(Box<UnaryOperation>)
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
struct BinaryOperation {
|
||||
left: Node,
|
||||
operator: Node,
|
||||
right: Node,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
struct UnaryOperation {
|
||||
operator: Node,
|
||||
other: Node,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
impl fmt::Display for BinaryOperation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f, "(\n{} \n{} \n{}\n)
|
||||
|
||||
", self.left, self.operator, self.right
|
||||
)
|
||||
}
|
||||
}
|
||||
impl fmt::Display for UnaryOperation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f, "(\n{} \n{} \n)
|
||||
|
||||
", self.operator, self.other,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Node {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Node::Number(x) => write!(f, "{}", x),
|
||||
Node::Operator(x) => write!(f, "{}", x),
|
||||
Node::BinaryOperation(x) => {
|
||||
let inner = *x.clone();
|
||||
write!(f, "{}", inner)
|
||||
}
|
||||
Node::UnaryOperation(x) => {
|
||||
let inner = *x.clone();
|
||||
write!(f, "{}", inner)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Operator {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Operator::Add => write!(f, "+"),
|
||||
Operator::Sub => write!(f, "-"),
|
||||
Operator::Mul => write!(f, "*"),
|
||||
Operator::Div => write!(f, "/"),
|
||||
Operator::Mod => write!(f, "%"),
|
||||
Operator::Qot => write!(f, "//"),
|
||||
Operator::Exp => write!(f, "**"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
use super::entity::Enemy;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
pub enum Event {
|
||||
PlayerKilled,
|
||||
EntityKilled(Enemy),
|
||||
}
|
||||
|
||||
pub enum Choice<A, B> {
|
||||
A(A),
|
||||
B(B),
|
||||
}
|
||||
|
||||
impl core::fmt::Display for Event {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Event::PlayerKilled => write!(f, "Player killed!"),
|
||||
Event::EntityKilled(x) => write!(f, "Entity killed! {}", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> core::fmt::Display for Choice<A, B> where
|
||||
A: core::fmt::Display,
|
||||
B: core::fmt::Display
|
||||
{
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Choice::A(a) => write!(f, "{}", a),
|
||||
Choice::B(b) => write!(f, "{}", b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eventcheck<A>(e: (A, Option<Vec<Event>>)) -> Choice<A, Event> {
|
||||
match e.1 {
|
||||
Some(events) => {
|
||||
for event in events {
|
||||
match event {
|
||||
Event::PlayerKilled => {
|
||||
return Choice::B(event)
|
||||
}
|
||||
Event::EntityKilled(entity) => {
|
||||
return Choice::B(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
None => (),
|
||||
};
|
||||
|
||||
Choice::A(e.0)
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
use super::player::Player;
|
||||
use super::engine::Event;
|
||||
|
||||
use alloc::{string::String, vec::Vec, vec};
|
||||
use crate::std::random;
|
||||
|
||||
|
||||
pub trait Entity {
|
||||
fn attack_entity(&mut self, _: &mut EntityObject) -> (AttackResult, Option<Vec<Event>>) {
|
||||
(AttackResult::Miss, None)
|
||||
}
|
||||
}
|
||||
pub enum EntityObject<'a> {
|
||||
Player(&'a mut Player),
|
||||
Enemy(&'a mut Enemy),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum AttackResult {
|
||||
Miss,
|
||||
GlancingBlow(f64),
|
||||
Hit(f64),
|
||||
CriticalHit(f64),
|
||||
FriendlyFire,
|
||||
}
|
||||
|
||||
impl core::fmt::Display for AttackResult {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
AttackResult::Miss => write!(f, "Missed!"),
|
||||
AttackResult::GlancingBlow(damage) => write!(f, "Glancing Blow: {}", damage),
|
||||
AttackResult::Hit(damage) => write!(f, "Hit: {}", damage),
|
||||
AttackResult::CriticalHit(damage) => write!(f, "Critical Hit: {}", damage),
|
||||
AttackResult::FriendlyFire => write!(f, "Friendly Fire (no damage dealt)!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Enemy {
|
||||
pub health_points: f64,
|
||||
pub max_health_points: f64,
|
||||
pub base_attack_damage: f64,
|
||||
pub speed: f64,
|
||||
}
|
||||
impl Enemy {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
health_points: 200.0,
|
||||
max_health_points: 200.0,
|
||||
base_attack_damage: 5.0,
|
||||
speed: 100.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl core::fmt::Display for Enemy {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "Enemy: {}/{}", self.health_points, self.max_health_points)
|
||||
}
|
||||
}
|
||||
|
||||
impl Entity for Enemy {
|
||||
fn attack_entity(&mut self, target: &mut EntityObject) -> (AttackResult, Option<Vec<Event>>) {
|
||||
let mut entity = if let EntityObject::Player(player) = target {
|
||||
player
|
||||
} else {
|
||||
return (AttackResult::FriendlyFire, None);
|
||||
};
|
||||
|
||||
// combat implementation
|
||||
|
||||
let dmg: f64;
|
||||
|
||||
let r = random::Random::int(0, 125) as f64;
|
||||
let rs = self.speed / entity.speed * 100 as f64;
|
||||
|
||||
let attack = if r < rs * 0.2 {
|
||||
dmg = self.base_attack_damage * 1.5;
|
||||
entity.health_points -= dmg;
|
||||
AttackResult::CriticalHit(dmg)
|
||||
|
||||
} else if r < rs * 0.8 {
|
||||
dmg = self.base_attack_damage;
|
||||
entity.health_points -= dmg;
|
||||
AttackResult::Hit(dmg)
|
||||
|
||||
} else if r < rs {
|
||||
dmg = self.base_attack_damage * 0.5;
|
||||
entity.health_points -= dmg;
|
||||
AttackResult::GlancingBlow(dmg)
|
||||
} else {
|
||||
AttackResult::Miss
|
||||
};
|
||||
|
||||
if entity.health_points <= 0.0 {
|
||||
return (attack, Some(vec![Event::PlayerKilled]));
|
||||
} else {
|
||||
return (attack, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
use async_trait::async_trait;
|
||||
use rand::prelude::*;
|
||||
|
||||
use super::{
|
||||
engine::{eventcheck, Choice, Event},
|
||||
entity::{Entity, Enemy, EntityObject},
|
||||
player::Player,
|
||||
};
|
||||
|
||||
use alloc::{boxed::Box, string::{String, ToString}, vec::Vec, format, borrow::ToOwned};
|
||||
|
||||
use crate::{
|
||||
std::application::{
|
||||
Application,
|
||||
Error,
|
||||
},
|
||||
std::{
|
||||
io::{self, println, serial_println, FRAMEGEN, Element},
|
||||
random,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
pub struct GameLoop;
|
||||
|
||||
|
||||
#[async_trait]
|
||||
impl Application for GameLoop {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
async fn run(&mut self, _args: Vec<String>) -> Result<(), Error> {
|
||||
|
||||
let mut username: String = io::stdin().await;
|
||||
username = username.trim().to_string();
|
||||
|
||||
let mut player = Player::new(username);
|
||||
|
||||
let mut enemy = Enemy::new();
|
||||
|
||||
for _ in 0..30 {
|
||||
match (eventcheck(player.attack_entity(&mut EntityObject::Enemy(&mut enemy)))) {
|
||||
Choice::A(result) => {
|
||||
println!("{}", result);
|
||||
},
|
||||
Choice::B(event) => {
|
||||
println!("{}", event);
|
||||
match event {
|
||||
Event::PlayerKilled => {
|
||||
println!(" [!] {} was slain by Enemy\n\n[ You lost! ]", player.username);
|
||||
break;
|
||||
}
|
||||
Event::EntityKilled(entity) => {
|
||||
println!("\n [!] Enemy was slain by {}\n\n [ You won! ]", player.username);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("{}", eventcheck(enemy.attack_entity(&mut EntityObject::Player(&mut player))));
|
||||
println!("[{}\n[{}", player, enemy);
|
||||
}
|
||||
|
||||
FRAMEGEN.lock().render_frame();
|
||||
|
||||
|
||||
let string = String::from(format!(
|
||||
"┌────────────────────────────┐
|
||||
│ {}
|
||||
│ {} / {}
|
||||
└────────────────────────────┘"
|
||||
, player.username, player.health_points, player.max_health_points));
|
||||
let mut healthbar = Element::from_str(string);
|
||||
healthbar.render((1, 1));
|
||||
|
||||
let new2 = String::from("[an element]");
|
||||
let mut new = Element::from_str(new2);
|
||||
|
||||
|
||||
new.render((10, 10));
|
||||
new.render((10, 15));
|
||||
new.render((5, 20));
|
||||
new.render((34, 16));
|
||||
|
||||
|
||||
FRAMEGEN.lock().render_frame();
|
||||
|
||||
let fr = FRAMEGEN.lock().get_frame().to_owned();
|
||||
serial_println!("{}", {
|
||||
let mut string = String::new();
|
||||
for row in fr {
|
||||
let mut r = String::new();
|
||||
for col in row {
|
||||
r.push(col);
|
||||
}
|
||||
string.push_str(&r);
|
||||
string.push('\n')
|
||||
};
|
||||
string
|
||||
});
|
||||
|
||||
|
||||
loop {
|
||||
println!("{}", io::stdchar().await)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn random() -> u64 {
|
||||
let mut r = random::Random::int(0, 125) as u64;
|
||||
r
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Armour;
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Weapon;
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Charm;
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct OtherItem;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Item {
|
||||
Armour(Armour),
|
||||
Weapon(Weapon),
|
||||
Charm(Charm),
|
||||
Other(OtherItem),
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
pub mod player;
|
||||
pub mod items;
|
||||
pub mod entity;
|
||||
pub mod engine;
|
||||
pub mod renderer;
|
||||
pub mod init;
|
||||
@@ -0,0 +1,82 @@
|
||||
use super::{
|
||||
items::{Item, Armour},
|
||||
entity::{Entity, EntityObject, AttackResult},
|
||||
engine::Event,
|
||||
};
|
||||
|
||||
|
||||
use alloc::{string::String, vec::Vec, vec};
|
||||
|
||||
use crate::std::random;
|
||||
|
||||
pub struct Player {
|
||||
pub username: String,
|
||||
pub health_points: f64,
|
||||
pub max_health_points: f64,
|
||||
pub base_attack_damage: f64,
|
||||
pub speed: f64,
|
||||
|
||||
pub inventory: [ Item ; 15 ],
|
||||
pub equipped: [ Item ; 7 ], // helmet, chestplate, leggings, boots, mainhand, offhand, charm
|
||||
}
|
||||
impl Player {
|
||||
pub fn new(username: String) -> Self {
|
||||
Self {
|
||||
username,
|
||||
health_points: 100.0,
|
||||
max_health_points: 100.0,
|
||||
base_attack_damage: 10.0,
|
||||
speed: 100.0,
|
||||
inventory: [ Item::Armour(Armour {}); 15 ],
|
||||
equipped: [ Item::Armour(Armour {}); 7 ],
|
||||
}
|
||||
}
|
||||
}
|
||||
impl core::fmt::Display for Player {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{}: {}/{}", self.username, self.health_points, self.max_health_points)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl Entity for Player {
|
||||
fn attack_entity(&mut self, target: &mut EntityObject) -> (AttackResult, Option<Vec<Event>>) {
|
||||
let mut entity = if let EntityObject::Enemy(enemy) = target {
|
||||
enemy
|
||||
} else {
|
||||
return (AttackResult::FriendlyFire, None);
|
||||
};
|
||||
|
||||
// combat implementation
|
||||
|
||||
let dmg: f64;
|
||||
|
||||
let r = random::Random::int(0, 125) as f64;
|
||||
let rs = self.speed / entity.speed * 100 as f64;
|
||||
|
||||
let attack = if r < rs * 0.2 {
|
||||
dmg = self.base_attack_damage * 1.5;
|
||||
entity.health_points -= dmg;
|
||||
AttackResult::CriticalHit(dmg)
|
||||
|
||||
} else if r < rs * 0.8 {
|
||||
dmg = self.base_attack_damage;
|
||||
entity.health_points -= dmg;
|
||||
AttackResult::Hit(dmg)
|
||||
|
||||
} else if r < rs {
|
||||
dmg = self.base_attack_damage * 0.5;
|
||||
entity.health_points -= dmg;
|
||||
AttackResult::GlancingBlow(dmg)
|
||||
} else {
|
||||
AttackResult::Miss
|
||||
};
|
||||
|
||||
if entity.health_points <= 0.0 {
|
||||
return (attack, Some(vec![Event::EntityKilled(entity.clone())]));
|
||||
} else {
|
||||
return (attack, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
use async_trait::async_trait;
|
||||
use alloc::{boxed::Box, string::String, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
std::os::OS,
|
||||
std::io::{Color, write},
|
||||
println,
|
||||
std::application::{
|
||||
Application,
|
||||
Error,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
pub struct CrystalFetch {}
|
||||
|
||||
#[async_trait]
|
||||
impl Application for CrystalFetch {
|
||||
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
async fn run(&mut self, _args: Vec<String>) -> Result<(), Error> {
|
||||
|
||||
let os = OS.lock().os.clone();
|
||||
let version = OS.lock().version.clone();
|
||||
|
||||
|
||||
write(format_args!("
|
||||
────────────────────────────────────────────────────────
|
||||
_____ _ _ ____ _____
|
||||
/ ____| | | | |/ __ \\ / ____|
|
||||
| | _ __ _ _ ___| |_ __ _| | | | | (___
|
||||
| | | '__| | | / __| __/ _` | | | | |\\___ \\
|
||||
| |____| | | |_| \\__ \\ || (_| | | |__| |____) |
|
||||
\\_____|_| \\__, |___/\\__\\__,_|_|\\____/|_____/
|
||||
__/ |
|
||||
|___/
|
||||
"), (Color::Magenta, Color::Black));
|
||||
|
||||
println!("
|
||||
╔═══════════════════════════════
|
||||
║
|
||||
║ OS » {}
|
||||
║ BUILD » {}
|
||||
║ RAM » idk
|
||||
║ Shell » CrystalSH
|
||||
║ API » CrystalAPI
|
||||
║ Pkgs » 4
|
||||
║ Fetch » CrystalFetch
|
||||
║
|
||||
╚═══════════════════════════════
|
||||
|
||||
────────────────────────────────────────────────────────
|
||||
", os, version);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
pub mod calc;
|
||||
pub mod rickroll;
|
||||
pub mod crystalfetch;
|
||||
pub mod tasks;
|
||||
pub mod crystal_rpg;
|
||||
pub mod shell;
|
||||
@@ -0,0 +1,41 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::std::application::{
|
||||
Application,
|
||||
Error,
|
||||
};
|
||||
|
||||
use crate::{println};
|
||||
use alloc::{string::String, boxed::Box, vec::Vec};
|
||||
|
||||
|
||||
pub struct Rickroll {}
|
||||
|
||||
#[async_trait]
|
||||
impl Application for Rickroll {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
async fn run(&mut self, _args: Vec<String>) -> Result<(), Error> {
|
||||
println!("
|
||||
|
||||
_ _ _____
|
||||
| \\ | | / ____|
|
||||
| \\| | _____ _____ _ __ | | __ ___ _ __ _ __ __ _
|
||||
| . ` |/ _ \\ \\ / / _ \\ '__| | | |_ |/ _ \\| '_ \\| '_ \\ / _` |
|
||||
| |\\ | __/\\ V / __/ | | |__| | (_) | | | | | | | (_| |
|
||||
|_| \\_|\\___| \\_/ \\___|_| \\_____|\\___/|_| |_|_| |_|\\__,_|
|
||||
_______ __ __ ___ ___
|
||||
/ ____(_) \\ \\ / / | | | |
|
||||
| | __ ___ _____ \\ \\_/ /__ _ _ | | | |_ __
|
||||
| | |_ | \\ \\ / / _ \\ \\ / _ \\| | | | | | | | '_ \\
|
||||
| |__| | |\\ V / __/ | | (_) | |_| | | |__| | |_) |
|
||||
\\_____|_| \\_/ \\___| |_|\\___/ \\__,_| \\____/| .__/
|
||||
| |
|
||||
|_|
|
||||
|
||||
");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
use async_trait::async_trait;
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
print, println,
|
||||
std::application::{Application, Error},
|
||||
user::bin::*,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CMD: Mutex<CommandHandler> = Mutex::new(CommandHandler::new());
|
||||
}
|
||||
|
||||
/// boilerplate function
|
||||
/// may provide other interfacing options later on idk.
|
||||
pub async fn command_handler() {
|
||||
eventloop().await;
|
||||
}
|
||||
|
||||
/// this function starts the shell running, the function will loop repeatedly until the command to shutdown
|
||||
/// TODO: implement shutdown command
|
||||
pub async fn eventloop() {
|
||||
println!("running!");
|
||||
|
||||
let mut fetch = crystalfetch::CrystalFetch::new();
|
||||
let string = String::from(" ");
|
||||
let mut vec: Vec<String> = Vec::new();
|
||||
vec.push(string);
|
||||
fetch.run(vec).await.unwrap();
|
||||
|
||||
CMD.lock().prompt();
|
||||
|
||||
loop {
|
||||
let string = crate::std::io::stdin().await;
|
||||
CMD.lock().current.push_str(&string);
|
||||
match exec().await {
|
||||
Ok(_) => {
|
||||
();
|
||||
}
|
||||
Err(e) => {
|
||||
handle_error(e);
|
||||
}
|
||||
};
|
||||
CMD.lock().prompt();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_error(e: Error) {}
|
||||
|
||||
async fn exec() -> Result<(), Error> {
|
||||
let mut current = CMD.lock().current.clone();
|
||||
|
||||
CMD.lock().history.history.push(current.clone());
|
||||
|
||||
current.pop();
|
||||
CMD.lock().current = String::new();
|
||||
|
||||
let (cmd, args) = match CommandHandler::parse_args(current) {
|
||||
Ok((cmd, args)) => (cmd, args),
|
||||
Err(_) => {
|
||||
return Err(Error::EmptyCommand);
|
||||
}
|
||||
};
|
||||
|
||||
match cmd.as_str() {
|
||||
"calculate" | "calc" | "solve" => {
|
||||
let mut cmd = calc::Calculator::new();
|
||||
cmd.run(args).await?;
|
||||
}
|
||||
|
||||
"rickroll" => {
|
||||
let mut cmd = rickroll::Rickroll::new();
|
||||
cmd.run(args).await?;
|
||||
}
|
||||
|
||||
"crystalfetch" => {
|
||||
let mut cmd = crystalfetch::CrystalFetch::new();
|
||||
cmd.run(args).await?;
|
||||
}
|
||||
"tasks" => {
|
||||
let mut cmd = tasks::Tasks::new();
|
||||
cmd.run(args).await?;
|
||||
}
|
||||
"play" => {
|
||||
let mut gameloop = crystal_rpg::init::GameLoop::new();
|
||||
gameloop.run(args).await?;
|
||||
}
|
||||
|
||||
// direct OS functions (not applications)
|
||||
"echo" => {
|
||||
println!(
|
||||
"Crystal: '{}'",
|
||||
args.into_iter()
|
||||
.map(|mut s| {
|
||||
s.push_str(" ");
|
||||
s
|
||||
})
|
||||
.collect::<String>()
|
||||
)
|
||||
}
|
||||
|
||||
"clear" => {
|
||||
interrupts::without_interrupts(|| {
|
||||
crate::std::io::clear();
|
||||
});
|
||||
}
|
||||
|
||||
"print" => {
|
||||
use crate::std::os::OS;
|
||||
let x: String = OS.lock().version.clone();
|
||||
println!("{}", x);
|
||||
}
|
||||
"switch" => {
|
||||
crate::std::io::switch_mode();
|
||||
}
|
||||
"random" => {
|
||||
use crate::std::random::Random;
|
||||
let vec = Vec::from(["a", "b", "c", "d", "e", "f"]);
|
||||
let sel = Random::selection(vec);
|
||||
println!("{}", sel);
|
||||
}
|
||||
"filesystem" => {
|
||||
use crate::std::io;
|
||||
io::mkfs();
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(Error::UnknownCommand(
|
||||
"command not yet implemented".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct CommandHandler {
|
||||
current: String,
|
||||
history: CmdHistory,
|
||||
}
|
||||
|
||||
impl CommandHandler {
|
||||
pub fn new() -> Self {
|
||||
let handler = Self {
|
||||
current: String::new(),
|
||||
history: CmdHistory {
|
||||
history: Vec::new(),
|
||||
},
|
||||
};
|
||||
handler
|
||||
}
|
||||
|
||||
pub fn parse_args(command: String) -> Result<(String, Vec<String>), String> {
|
||||
let temp = command.split(" ").collect::<Vec<&str>>();
|
||||
let mut args: Vec<String> = Vec::new();
|
||||
for arg in temp {
|
||||
match arg {
|
||||
"" => {}
|
||||
x => args.push(x.to_string()),
|
||||
}
|
||||
}
|
||||
let cmd: String;
|
||||
if args.len() > 0 {
|
||||
cmd = args[0].clone();
|
||||
args.remove(0);
|
||||
} else {
|
||||
return Err("command was empty.".to_string());
|
||||
};
|
||||
Ok((cmd, args))
|
||||
}
|
||||
|
||||
// this function is activated every time the user presses a key on the keyboard
|
||||
// it accesses the queue of keys (a static ref in src/tasks/keyboard.rs)
|
||||
|
||||
// displays a text prompt for the user to type into.
|
||||
// this is a separate function so that it can be developed as necessary later on
|
||||
// TODO: coloured prompt
|
||||
|
||||
pub fn prompt(&self) {
|
||||
print!("\n [ Crystal ] >> ");
|
||||
}
|
||||
|
||||
// this function is run every time the enter key is pressed in the command line mode.
|
||||
// it detects the command that is being run and then executes it, passing the arguments to it.
|
||||
}
|
||||
|
||||
struct CmdHistory {
|
||||
history: Vec<String>,
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
use async_trait::async_trait;
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
applications::*,
|
||||
std::application::{Application, Error},
|
||||
std::io::{print, println},
|
||||
user::bin::*,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CMD: Mutex<Cmd> = Mutex::new(Cmd::new());
|
||||
}
|
||||
struct Cmd {}
|
||||
impl Cmd {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
// [ CRYSTAL SHELL ]
|
||||
// the purpose of this module is to provide a basic unix shell like experience for the user
|
||||
// to interact with the OS
|
||||
// this is a rewrite of my original shell.
|
||||
// this shell should support:
|
||||
// - browsing the virtual filesystem
|
||||
// - executing programs
|
||||
// - basic arithmetic
|
||||
// - chained execution ( multiple commands linked together) eg: '5 + 5 | echo' which calculates
|
||||
// the result of 5 + 5 and then sends the result to an echo command which prints it to console
|
||||
|
||||
pub fn init_sh() -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
use alloc::{string::String, vec::Vec, boxed::Box};
|
||||
use crate::std::application::{
|
||||
Application,
|
||||
Error
|
||||
};
|
||||
use crate::{print, println};
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use async_trait::async_trait;
|
||||
use alloc::{
|
||||
string::ToString,
|
||||
borrow::ToOwned,
|
||||
};
|
||||
|
||||
use crate::std::random;
|
||||
|
||||
|
||||
lazy_static! {
|
||||
static ref TASKS: Mutex<TaskList> = Mutex::new(TaskList::new());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
pub struct Tasks;
|
||||
|
||||
#[async_trait]
|
||||
impl Application for Tasks {
|
||||
fn new() -> Self { Self {} }
|
||||
|
||||
async fn run(&mut self, args: Vec<String>) -> Result<(), Error> {
|
||||
|
||||
if args[0].clone() == String::from("add") {
|
||||
|
||||
let content = args[1..].to_owned().into_iter().map(|mut s| {s.push_str(" "); s} ).collect::<String>();
|
||||
self.add_task(content);
|
||||
|
||||
}
|
||||
|
||||
if args[0].clone() == String::from("remove") {
|
||||
let idx = match args[1].to_owned().parse::<usize>() {
|
||||
Ok(x) => x,
|
||||
Err(_) => { return Err(Error::CommandFailed(String::from("number must be an integer"))) },
|
||||
};
|
||||
self.remove_task(idx);
|
||||
}
|
||||
|
||||
if args[0].clone() == String::from("select") {
|
||||
let arg2 = args[1].clone();
|
||||
if arg2 == String::from("random") {
|
||||
let len = TASKS.lock().tasks.len();
|
||||
self.select_task(random::Random::int(0, len -1) as i32);
|
||||
} else if arg2.parse::<u64>().is_ok() {
|
||||
()
|
||||
}
|
||||
}
|
||||
|
||||
if args[0].clone() == String::from("priority") {
|
||||
let idx = TASKS.lock().current;
|
||||
if idx < 0 {
|
||||
println!(
|
||||
"-------------------------------------
|
||||
no task currently set as priority
|
||||
-------------------------------------\n"
|
||||
);
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let task = TASKS.lock().tasks[idx as usize].clone();
|
||||
let content = task.content.clone();
|
||||
|
||||
println!(
|
||||
"-------------------------------------
|
||||
PRIORITY TASK: {} : {}
|
||||
-------------------------------------\n",
|
||||
idx, content
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
if args[0].as_str() == "list" {
|
||||
|
||||
println!(
|
||||
"-------------------------------------
|
||||
Your TODO List:
|
||||
-------------------------------------\n");
|
||||
|
||||
for task in TASKS.lock().tasks.iter() {
|
||||
|
||||
let idx = task.taskid;
|
||||
let content = task.content.clone();
|
||||
println!(" | Task -> {} \n | {}\n", idx, content);
|
||||
}
|
||||
println!("\n-------------------------------------");
|
||||
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Tasks {
|
||||
fn add_task(&mut self, content: String) {
|
||||
TASKS.lock().add(content);
|
||||
}
|
||||
fn remove_task(&self, idx: usize) {
|
||||
TASKS.lock().remove(idx);
|
||||
}
|
||||
fn select_task(&self, idx: i32) {
|
||||
TASKS.lock().select(idx);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TaskList {
|
||||
current: i32,
|
||||
tasks: Vec<Task>,
|
||||
next_idx: usize,
|
||||
}
|
||||
|
||||
impl TaskList {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
current: -1,
|
||||
tasks: Vec::new(),
|
||||
next_idx: 1
|
||||
}
|
||||
}
|
||||
pub fn next(&mut self) -> usize {
|
||||
self.next_idx += 1;
|
||||
self.next_idx -1
|
||||
}
|
||||
pub fn add(&mut self, content: String) -> Result<(), Error> {
|
||||
let task = Task::new(self.next(), content);
|
||||
let id = task.taskid.clone();
|
||||
self.tasks.push(task);
|
||||
Ok(())
|
||||
}
|
||||
pub fn remove(&mut self, id: usize) -> Result<(), Error> {
|
||||
for (i, task) in self.tasks.clone().iter().enumerate() {
|
||||
match task.taskid {
|
||||
id => { self.tasks.remove(i); },
|
||||
_ => { return Err(Error::CommandFailed(String::from("this task does not exist"))); },
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
pub fn select(&mut self, idx: i32) -> Result<(), Error> {
|
||||
self.current = idx;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Task {
|
||||
taskid: usize,
|
||||
content: String,
|
||||
}
|
||||
|
||||
impl Task {
|
||||
fn new(id: usize, content: String) -> Self {
|
||||
Self {
|
||||
taskid: id,
|
||||
content,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod lib;
|
||||
pub mod bin;
|
||||
Reference in New Issue
Block a user