aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGuillermo Ramos2025-02-06 23:52:05 +0100
committerGuillermo Ramos2025-02-07 00:49:43 +0100
commit2e7780b7c13f43b61b026cfd803e0f904ef04878 (patch)
tree8fb5134e9b80d23c21c7784a4478afa417298293 /src
parentca057d600ca54b3efebd6770dbe52acb38d9a25f (diff)
downloadhiccup-2e7780b7c13f43b61b026cfd803e0f904ef04878.tar.gz
Final refactor before doing actual work
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs200
-rw-r--r--src/main.rs18
2 files changed, 121 insertions, 97 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 66ebe32..bef9ffe 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,14 +1,33 @@
use std::collections::HashMap;
use std::fmt;
+use std::ops::AddAssign;
+
+#[derive(Clone, Copy)]
+pub struct Capital {
+ principal: f64,
+ interest: f64,
+}
+
+impl Capital {
+ fn total(&self) -> f64 {
+ self.principal + self.interest
+ }
+}
+
+// TODO generate other operations using macros
+impl AddAssign for Capital {
+ fn add_assign(&mut self, other: Self) {
+ self.principal += other.principal;
+ self.interest += other.interest;
+ }
+}
pub struct Simulation {
- mortgage: Mortgage,
- updates: MortgageUpdates,
+ st: SimState,
+ updates: SimUpdates,
history: Vec<Quota>,
- topay_total: f64,
- topay_interest: f64,
- payed_principal: f64,
- payed_interest: f64,
+ topay: Capital,
+ payed: Capital,
payed_amortized: f64,
}
@@ -17,50 +36,53 @@ impl Simulation {
let pending_quotas = years * 12;
let i12 = i1 / 12.0;
- let mortgage = Mortgage {
+ let mut st = SimState {
period: 0,
principal,
i12,
- monthly: Mortgage::monthly(principal, i12, pending_quotas),
+ monthly: 0.,
pending_quotas,
};
+ st.calculate_monthly();
- let topay_total = mortgage.monthly * pending_quotas as f64;
+ let topay_total = st.monthly * pending_quotas as f64;
Simulation {
- mortgage,
- topay_total,
- topay_interest: topay_total - principal,
- payed_principal: 0.,
- payed_interest: 0.,
+ st,
+ topay: Capital {
+ principal,
+ interest: topay_total - principal,
+ },
+ payed: Capital {
+ principal: 0.,
+ interest: 0.,
+ },
payed_amortized: 0.,
history: vec![],
updates: HashMap::new(),
}
}
- pub fn run(&mut self, updates: MortgageUpdates) {
+ pub fn run(&mut self, updates: SimUpdates) {
self.updates = updates;
- let mut mortgage = self.mortgage.clone();
- while mortgage.pending_quotas > 0 && mortgage.principal > 0. {
- let quota = mortgage.step();
- self.payed_principal += quota.principal;
- self.payed_interest += quota.interest;
+ let mut st = self.st.clone();
+ while st.pending_quotas > 0 && st.principal > 0. {
+ let quota = st.step();
+ self.payed += quota.payed;
self.history.push(quota);
- self.apply_updates(&mut mortgage);
+ self.apply_updates(&mut st);
}
}
- fn apply_updates(&mut self, mortgage: &mut Mortgage) {
- match self.updates.get_mut(&mortgage.period) {
- Some(MortgageUpdate::Amortize(principal)) => {
- if *principal > mortgage.principal {
- *principal = mortgage.principal;
+ fn apply_updates(&mut self, st: &mut SimState) {
+ match self.updates.get_mut(&st.period) {
+ Some(SimUpdate::Amortize(principal)) => {
+ if *principal > st.principal {
+ *principal = st.principal;
};
- mortgage.principal -= *principal;
- mortgage.monthly =
- Mortgage::monthly(mortgage.principal, mortgage.i12, mortgage.pending_quotas);
-
+ st.principal -= *principal;
+ st.calculate_monthly();
+ self.payed.principal += *principal;
self.payed_amortized += *principal;
}
None => (),
@@ -68,82 +90,57 @@ impl Simulation {
}
pub fn render_table(&self) {
- let mortgage = &self.mortgage;
+ let st = &self.st;
println!("\n========================================================");
println!(
"=== HIPOTECA: {}€, A {} AÑOS, INTERÉS FIJO {:.2}% ===",
- mortgage.principal,
- mortgage.pending_quotas / 12,
- mortgage.i12 * 12. * 100.,
+ st.principal,
+ st.pending_quotas / 12,
+ st.i12 * 12. * 100.,
);
println!("========================================================");
println!("\n\n# SIMULACIÓN CUOTAS\n");
println!("Year | Mon | Quota ( Amrtzd + Intrst) | Pending");
- for mortgage in self.history.iter() {
- print!("{mortgage}");
- if let Some(update) = self.updates.get(&mortgage.period) {
+ for st in self.history.iter() {
+ print!("{st}");
+ if let Some(update) = self.updates.get(&st.period) {
print!(" {update}");
}
println!();
}
- let payed_total = self.payed_principal + self.payed_interest + self.payed_amortized;
-
println!("\n\n# A PRIORI\n");
println!(
"== Total a pagar: {:.2} ({:.2} cap + {:.2} int)",
- self.topay_total, mortgage.principal, self.topay_interest
+ self.topay.total(),
+ self.topay.principal,
+ self.topay.interest
);
println!(
"== Los intereses suponen un {:.2}% del total",
- 100. * self.topay_interest / self.topay_total
+ 100. * self.topay.interest / self.topay.total()
);
println!("\n\n# RESULTADO FINAL\n");
println!(
- "== Total pagado: {:.2} ({:.2} cap + {:.2} int + {:.2} amortizado)",
- payed_total, self.payed_principal, self.payed_interest, self.payed_amortized
+ "== Total pagado: {:.2} ({:.2} en cuotas + {:.2} int + {:.2} amortizado)",
+ self.payed.total(),
+ self.payed.principal - self.payed_amortized,
+ self.payed.interest,
+ self.payed_amortized
);
println!(
"== Los intereses suponen un {:.2}% del total",
- 100. * self.payed_interest / payed_total
+ 100. * self.payed.interest / self.payed.total()
);
println!();
}
}
#[derive(Clone)]
-pub struct Quota {
- period: u32,
- interest: f64,
- principal: f64,
- pending_principal: f64,
-}
-
-impl fmt::Display for Quota {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "{:4} | {:3} | {:7.2} ({:7.2} + {:7.2}) | {:10.2}",
- if (self.period - 1) % 12 == 0 {
- format!("Y{}", (self.period / 12) + 1)
- } else {
- // return Ok(());
- "".to_string()
- },
- self.period,
- self.interest + self.principal,
- self.principal,
- self.interest,
- self.pending_principal
- )
- }
-}
-
-#[derive(Clone)]
-pub struct Mortgage {
+struct SimState {
period: u32,
principal: f64,
i12: f64,
@@ -151,14 +148,23 @@ pub struct Mortgage {
pending_quotas: u32,
}
-impl Mortgage {
- fn monthly(principal: f64, i12: f64, pending_quotas: u32) -> f64 {
- principal * i12 / (1.0 - (1.0 + i12).powi(-(pending_quotas as i32)))
+impl SimState {
+ fn calculate_monthly(&mut self) {
+ self.monthly =
+ self.principal * self.i12 / (1.0 - (1.0 + self.i12).powi(-(self.pending_quotas as i32)))
+ }
+
+ fn capital(&self) -> Capital {
+ let interest = self.i12 * self.principal;
+ let principal = self.monthly - interest;
+ Capital {
+ principal,
+ interest,
+ }
}
fn step(&mut self) -> Quota {
- let interest = self.quota_interest();
- let principal = self.quota_principal();
+ let capital = self.capital();
self.period += 1;
self.pending_quotas -= 1;
@@ -166,29 +172,47 @@ impl Mortgage {
Quota {
period: self.period,
- interest,
- principal,
+ payed: capital,
pending_principal: self.principal,
}
}
+}
- fn quota_interest(&self) -> f64 {
- self.i12 * self.principal
- }
+#[derive(Clone)]
+pub struct Quota {
+ period: u32,
+ payed: Capital,
+ pending_principal: f64,
+}
- fn quota_principal(&self) -> f64 {
- self.monthly - self.quota_interest()
+impl fmt::Display for Quota {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "{:4} | {:3} | {:7.2} ({:7.2} + {:7.2}) | {:10.2}",
+ if (self.period - 1) % 12 == 0 {
+ format!("Y{}", (self.period / 12) + 1)
+ } else {
+ // return Ok(());
+ "".to_string()
+ },
+ self.period,
+ self.payed.total(),
+ self.payed.principal,
+ self.payed.interest,
+ self.pending_principal
+ )
}
}
-pub type MortgageUpdates = HashMap<u32, MortgageUpdate>;
+pub type SimUpdates = HashMap<u32, SimUpdate>;
#[derive(Clone)]
-pub enum MortgageUpdate {
+pub enum SimUpdate {
Amortize(f64),
}
-impl fmt::Display for MortgageUpdate {
+impl fmt::Display for SimUpdate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[MORTGAGE UPDATE: ")?;
match self {
diff --git a/src/main.rs b/src/main.rs
index f785bb0..fa9e01a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,16 +1,16 @@
-use hiccup::MortgageUpdate::*;
-use hiccup::{MortgageUpdates, Simulation};
+use hiccup::SimUpdate::*;
+use hiccup::{SimUpdates, Simulation};
use std::collections::HashMap;
fn main() {
- let mut sim = Simulation::new(390_000., 0.028, 30);
- let updates: MortgageUpdates = HashMap::from_iter((0..29).map(|y| match y {
- 0 => (0, Amortize(30_000.)),
- _ => (y * 12, Amortize(12_000.)),
- }));
+ // let mut sim = Simulation::new(390_000., 0.028, 30);
+ // let updates: SimUpdates = HashMap::from_iter((0..29).map(|y| match y {
+ // 0 => (0, Amortize(30_000.)),
+ // _ => (y * 12, Amortize(12_000.)),
+ // }));
- // let mut sim = Simulation::new(200_000., 0.01621, 30);
- // let updates: MortgageUpdates = HashMap::new();
+ let mut sim = Simulation::new(200_000., 0.01621, 30);
+ let updates: SimUpdates = HashMap::new();
sim.run(updates);
sim.render_table();