dont pass species but rather dex around

main
Bel LaPointe 2025-03-20 20:12:32 -06:00
parent 50841b807a
commit 6007c2f2ed
1 changed files with 291 additions and 255 deletions

View File

@ -1,301 +1,337 @@
pub mod mon { pub mod mon {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Species { pub struct Species {
pub name: String, pub name: String,
pub hp: i32, pub hp: i32,
pub atk: i32, pub atk: i32,
pub def: i32, pub def: i32,
pub spd: i32, pub spd: i32,
} }
#[cfg(test)] #[cfg(test)]
mod species_tests { mod species_tests {
use super::*; use super::*;
#[test] #[test]
fn test_literal() { fn test_literal() {
let _: Species = Species{ let _: Species = Species {
name: "".to_string(), name: "".to_string(),
hp: 1, hp: 1,
atk: 2, atk: 2,
def: 3, def: 3,
spd: 4, spd: 4,
}; };
} }
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Dex { pub enum Dex {
Pika, Pika,
Mari, Mari,
} }
impl Dex { impl Dex {
pub fn new(&self) -> Species { pub fn new(&self) -> Species {
self.clone().into() self.clone().into()
} }
}
impl Into<Species> for Dex { pub fn name(&self) -> String {
fn into(self) -> Species { self.new().name
match self { }
Dex::Pika => Species{
name: "Pika".to_string(),
hp: 10,
atk: 11,
def: 9,
spd: 11,
},
Dex::Mari => Species{
name: "Mari".to_string(),
hp: 10,
atk: 8,
def: 12,
spd: 9,
},
}
}
}
#[cfg(test)] pub fn hp(&self) -> i32 {
mod dex_tests { self.new().hp
use super::*; }
#[test] pub fn atk(&self) -> i32 {
fn test_dex_to_species() { self.new().atk
let dex = Dex::Pika; }
let _: Species = dex.new();
let _: Species = dex.into();
let _: Species = Dex::Pika.new();
let _: Species = Dex::Pika.into();
}
}
#[derive(Clone, Debug)] pub fn def(&self) -> i32 {
pub struct Instance { self.new().def
pub species: Species, }
pub damage: i32,
}
impl Instance { pub fn spd(&self) -> i32 {
pub fn roll(dex: Dex) -> Instance { self.new().spd
Instance{ }
species: dex.into(), }
damage: 0,
}
}
}
#[cfg(test)] impl Into<Species> for Dex {
mod instance_tests { fn into(self) -> Species {
use super::*; match self {
Dex::Pika => Species {
name: "Pika".to_string(),
hp: 10,
atk: 11,
def: 9,
spd: 11,
},
Dex::Mari => Species {
name: "Mari".to_string(),
hp: 10,
atk: 8,
def: 12,
spd: 9,
},
}
}
}
#[test] #[cfg(test)]
fn test_instance_roll() { mod dex_tests {
let i: Instance = Instance::roll(Dex::Pika); use super::*;
assert_eq!(0, i.damage);
assert_eq!(Dex::Pika.new(), i.species); #[test]
} fn test_dex_to_species() {
} let dex = Dex::Pika;
let _: Species = dex.new();
let _: Species = dex.into();
let _: Species = Dex::Pika.new();
let _: Species = Dex::Pika.into();
}
}
#[derive(Clone, Debug)]
pub struct Instance {
pub dex: Dex,
pub damage: i32,
}
impl Instance {
pub fn roll(dex: Dex) -> Instance {
Instance {
dex: dex,
damage: 0,
}
}
}
#[cfg(test)]
mod instance_tests {
use super::*;
#[test]
fn test_instance_roll() {
let i: Instance = Instance::roll(Dex::Pika);
assert_eq!(0, i.damage);
assert_eq!(Dex::Pika, i.dex);
}
}
} }
pub mod battle { pub mod battle {
use super::*; use super::*;
pub struct Engine { pub struct Engine {
teams: Vec<Team>, teams: Vec<Team>,
q: Vec<Move>, q: Vec<Move>,
} }
impl Engine { impl Engine {
pub fn new(first: Vec<mon::Instance>, second: Vec<mon::Instance>) -> Engine { pub fn new(first: Vec<mon::Instance>, second: Vec<mon::Instance>) -> Engine {
let mut result = Self{ let mut result = Self {
teams: vec![], teams: vec![],
q: vec![], q: vec![],
};
result.join(first);
result.join(second);
result
}
pub fn join(&mut self, third: Vec<mon::Instance>) {
self.teams.push(Team::new(third));
}
pub fn enqueue(&mut self, m: Move) {
self.q.push(m);
}
pub fn exec(&mut self) {
self.turn_order().iter().for_each(|idx| {
match self.q[*idx].clone() {
Move::Pass(_) => {},
Move::Attack(rIdx, wIdx) => {
let r = self.teams[rIdx.team].mons[rIdx.mon].clone();
if r.can_attack() {
let w = self.teams[wIdx.team].mons[wIdx.mon].clone();
if w.can_be_attacked() {
self.teams[wIdx.team].mons[wIdx.mon].mon = Engine::attack(&w.mon, &r.mon);
}
}
},
}; };
}); result.join(first);
self.new_turn(); result.join(second);
} result
}
fn new_turn(&mut self) { pub fn join(&mut self, third: Vec<mon::Instance>) {
self.q = vec![]; self.teams.push(Team::new(third));
} }
fn turn_order(&self) -> Vec<usize> { pub fn enqueue(&mut self, m: Move) {
let mut order = vec![]; self.q.push(m);
for i in 0..self.q.len() { }
order.push((i, match &self.q[i] {
Move::Pass(_) => 0,
Move::Attack(w, _) => self.teams[w.team].mons[w.mon].mon.species.spd,
}));
}
order.sort_unstable_by(|a, b| a.1.cmp(&b.1));
order.iter().map(|x| x.0).collect()
}
fn attack(w: &mon::Instance, r: &mon::Instance) -> mon::Instance { pub fn exec(&mut self) {
let mut w = w.clone(); self.turn_order().iter().for_each(|idx| {
let atk_delta = r.species.atk - 10; match self.q[*idx].clone() {
let def_delta = w.species.def - 10; Move::Pass(_) => {}
Move::Attack(r_idx, w_idx) => {
let r = self.teams[r_idx.team].mons[r_idx.mon].clone();
if r.can_attack() {
let w = self.teams[w_idx.team].mons[w_idx.mon].clone();
if w.can_be_attacked() {
self.teams[w_idx.team].mons[w_idx.mon].mon =
Engine::attack(&w.mon, &r.mon);
}
}
}
};
});
self.new_turn();
}
let power = match atk_delta - def_delta { fn new_turn(&mut self) {
v if v < 1 => 1, self.q = vec![];
v => v, }
};
w.damage = match w.damage + power { fn turn_order(&self) -> Vec<usize> {
v if v < w.species.hp => v, let mut order = vec![];
_ => w.species.hp, for i in 0..self.q.len() {
}; order.push((
i,
match &self.q[i] {
Move::Pass(_) => 0,
Move::Attack(w, _) => self.teams[w.team].mons[w.mon].mon.dex.new().spd,
},
));
}
order.sort_unstable_by(|a, b| a.1.cmp(&b.1));
order.iter().map(|x| x.0).collect()
}
w fn attack(w: &mon::Instance, r: &mon::Instance) -> mon::Instance {
} let mut w = w.clone();
} let atk_delta = r.dex.new().atk - 10;
let def_delta = w.dex.new().def - 10;
#[cfg(test)] let power = match atk_delta - def_delta {
mod engine_tests { v if v < 1 => 1,
use super::*; v => v,
};
#[test] w.damage = match w.damage + power {
fn test_new() { v if v < w.dex.new().hp => v,
let mut engine = Engine::new(team_a(), team_b()); _ => w.dex.new().hp,
engine.join(team_b()); };
}
#[test] w
fn test_attack() { }
let mut pika = mon::Instance::roll(mon::Dex::Pika); }
let mut mari = mon::Instance::roll(mon::Dex::Mari);
pika = Engine::attack(&mut pika, &mut mari); #[cfg(test)]
assert_eq!(1, pika.damage); mod engine_tests {
use super::*;
mari = Engine::attack(&mut mari, &mut pika); #[test]
assert_eq!(1, mari.damage); fn test_new() {
let mut engine = Engine::new(team_a(), team_b());
engine.join(team_b());
}
#[test]
fn test_attack() {
let mut pika = mon::Instance::roll(mon::Dex::Pika);
let mut mari = mon::Instance::roll(mon::Dex::Mari);
for _ in 0..pika.species.hp+5 {
pika = Engine::attack(&mut pika, &mut mari); pika = Engine::attack(&mut pika, &mut mari);
} assert_eq!(1, pika.damage);
assert_eq!(pika.species.hp, pika.damage);
assert_eq!(1, mari.damage);
}
#[test] mari = Engine::attack(&mut mari, &mut pika);
fn test_turn() { assert_eq!(1, mari.damage);
let mut engine = Engine::new(team_a(), team_b());
engine.join(team_b());
// player 0 mon 0 attacks team 1 mon 0 for _ in 0..pika.dex.new().hp + 5 {
engine.enqueue(Move::Attack(Idx{team: 0, mon: 0}, Idx{team: 1, mon: 0})); pika = Engine::attack(&mut pika, &mut mari);
// player 1 mon 0 passes }
engine.enqueue(Move::Pass(Idx{team: 1, mon: 0})); assert_eq!(pika.dex.new().hp, pika.damage);
// player 1 mon 1 not out assert_eq!(1, mari.damage);
engine.exec(); }
assert_eq!(0, engine.teams[0].mons[0].mon.damage); #[test]
assert_eq!(1, engine.teams[1].mons[0].mon.damage); fn test_turn() {
assert_eq!(0, engine.teams[1].mons[1].mon.damage); let mut engine = Engine::new(team_a(), team_b());
} engine.join(team_b());
fn team_a() -> Vec<mon::Instance> { // player 0 mon 0 attacks team 1 mon 0
vec![mon::Instance::roll(mon::Dex::Pika)] engine.enqueue(Move::Attack(
} Idx { team: 0, mon: 0 },
Idx { team: 1, mon: 0 },
));
// player 1 mon 0 passes
engine.enqueue(Move::Pass(Idx { team: 1, mon: 0 }));
// player 1 mon 1 not out
engine.exec();
fn team_b() -> Vec<mon::Instance> { assert_eq!(0, engine.teams[0].mons[0].mon.damage);
vec![mon::Instance::roll(mon::Dex::Mari), mon::Instance::roll(mon::Dex::Pika)] assert_eq!(1, engine.teams[1].mons[0].mon.damage);
} assert_eq!(0, engine.teams[1].mons[1].mon.damage);
} }
#[derive(Debug)] fn team_a() -> Vec<mon::Instance> {
struct Team { vec![mon::Instance::roll(mon::Dex::Pika)]
mons: Vec<Instance>, }
}
impl Team { fn team_b() -> Vec<mon::Instance> {
fn new(mons: Vec<mon::Instance>) -> Self { vec![
assert!(mons.len() > 0); mon::Instance::roll(mon::Dex::Mari),
let mut mons: Vec<_> = mons.iter().map(|m| Instance{mon: m.clone(), out: false}).collect(); mon::Instance::roll(mon::Dex::Pika),
mons[0].out = true; ]
Self{mons: mons} }
} }
}
#[derive(Clone, Debug)] #[derive(Debug)]
struct Instance { struct Team {
mon: mon::Instance, mons: Vec<Instance>,
out: bool, }
}
impl Instance { impl Team {
fn alive(&self) -> bool { fn new(mons: Vec<mon::Instance>) -> Self {
self.mon.damage < self.mon.species.hp assert!(mons.len() > 0);
} let mut mons: Vec<_> = mons
.iter()
.map(|m| Instance {
mon: m.clone(),
out: false,
})
.collect();
mons[0].out = true;
Self { mons: mons }
}
}
fn can_attack(&self) -> bool { #[derive(Clone, Debug)]
self.out && self.alive() struct Instance {
} mon: mon::Instance,
out: bool,
}
fn can_be_attacked(&self) -> bool { impl Instance {
self.out && self.alive() fn alive(&self) -> bool {
} self.mon.damage < self.mon.dex.new().hp
} }
#[cfg(test)] fn can_attack(&self) -> bool {
mod instance_tests { self.out && self.alive()
use super::*; }
#[test] fn can_be_attacked(&self) -> bool {
fn test_checks() { self.out && self.alive()
let mut i = Instance{ }
mon: mon::Instance::roll(mon::Dex::Pika), }
out: true,
};
assert_eq!(true, i.alive());
assert_eq!(true, i.can_attack());
assert_eq!(true, i.can_be_attacked());
i.mon.damage = i.mon.species.hp;
assert_eq!(false, i.alive());
assert_eq!(false, i.can_attack());
assert_eq!(false, i.can_be_attacked());
}
}
#[derive(Clone, Debug)] #[cfg(test)]
struct Idx { mod instance_tests {
pub team: usize, use super::*;
pub mon: usize,
}
#[derive(Clone, Debug)] #[test]
enum Move { fn test_checks() {
Pass(Idx), let mut i = Instance {
Attack(Idx, Idx), mon: mon::Instance::roll(mon::Dex::Pika),
} out: true,
};
assert_eq!(true, i.alive());
assert_eq!(true, i.can_attack());
assert_eq!(true, i.can_be_attacked());
i.mon.damage = i.mon.dex.new().hp;
assert_eq!(false, i.alive());
assert_eq!(false, i.can_attack());
assert_eq!(false, i.can_be_attacked());
}
}
#[derive(Clone, Debug)]
pub struct Idx {
pub team: usize,
pub mon: usize,
}
#[derive(Clone, Debug)]
pub enum Move {
Pass(Idx),
Attack(Idx, Idx),
}
} }