Skip to content

Commit 7fb79b5

Browse files
committed
Grapher bugfixes
1 parent 1e2a460 commit 7fb79b5

File tree

4 files changed

+56
-71
lines changed

4 files changed

+56
-71
lines changed

src/display/graph.rs

Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use super::super::{
1515
types::{GameId, GameString, HashMap, Wrapper},
1616
};
1717

18-
use std::path::Path;
18+
use std::{collections::BTreeMap, path::Path};
1919

2020
/// Common graph size in pixels
2121
const GRAPH_SIZE: (u32, u32) = (1024, 768);
@@ -105,48 +105,55 @@ pub trait TreeNode<I: IntoIterator>: Sized {
105105

106106
/// Creates a graph from a given data set
107107
/// Assumes that the data is sorted by the x value, and that the y value is a percentage
108-
fn create_graph<P: AsRef<Path>>(
109-
data: &Vec<(i16, f64)>,
108+
fn create_graph<P: AsRef<Path>, S: Into<String>>(
109+
data: &BTreeMap<i16, u32>,
110+
contast: &BTreeMap<i16, u32>,
110111
output_path: &P,
111-
ylabel: Option<&str>,
112-
xlabel: Option<&str>,
112+
ylabel: Option<S>,
113+
xlabel: Option<S>,
113114
) {
114115
let mut min_x: i16 = 0;
115116
let mut max_x: i16 = 0;
116-
for (x, _) in data {
117-
if *x < min_x || min_x == 0 {
117+
{
118+
let mut iter = data.iter();
119+
if let Some((x, _)) = iter.next() {
118120
min_x = *x;
119121
}
120-
if *x > max_x {
122+
if let Some((x, _)) = iter.next_back() {
121123
max_x = *x;
122124
}
123125
}
124126

125127
let root = SVGBackend::new(output_path, GRAPH_SIZE).into_drawing_area();
126128
root.fill(&WHITE).unwrap();
127129
let mut chart = ChartBuilder::on(&root)
128-
//.caption("Deaths of culture members through time", ("sans-serif", 50).into_font())
129130
.margin(GRAPH_MARGIN)
130131
.x_label_area_size(GRAPH_LABEL_SPACE)
131132
.y_label_area_size(GRAPH_LABEL_SPACE)
132-
.build_cartesian_2d(min_x as f64..max_x as f64, MIN_Y..MAX_Y)
133+
.build_cartesian_2d((min_x as i32)..(max_x as i32), MIN_Y..MAX_Y)
133134
.unwrap();
134135

135136
let mut mesh = chart.configure_mesh();
136137

137-
if xlabel.is_some() {
138-
mesh.x_desc(xlabel.unwrap());
138+
if let Some(xlabel) = xlabel {
139+
mesh.x_desc(xlabel);
139140
}
140141

141-
if ylabel.is_some() {
142-
mesh.y_desc(ylabel.unwrap());
142+
if let Some(ylabel) = ylabel {
143+
mesh.y_desc(ylabel);
143144
}
144145

145146
mesh.draw().unwrap();
146147

147148
chart
148149
.draw_series(LineSeries::new(
149-
data.iter().map(|(x, y)| (*x as f64, *y * MAX_Y)),
150+
(min_x..max_x).map(|year| {
151+
(
152+
year as i32,
153+
*data.get(&year).unwrap_or(&0) as f64 / *contast.get(&year).unwrap() as f64
154+
* MAX_Y,
155+
)
156+
}),
150157
&RED,
151158
))
152159
.unwrap();
@@ -155,35 +162,21 @@ fn create_graph<P: AsRef<Path>>(
155162
/// An object that can create graphs from the game state
156163
pub struct Grapher {
157164
/// Stored graph data for all faiths, certainly less memory efficient but the speed is worth it
158-
faith_graph_complete: HashMap<GameId, Vec<(i16, f64)>>,
159-
culture_graph_complete: HashMap<GameId, Vec<(i16, f64)>>,
165+
faith_graph_complete: HashMap<GameId, BTreeMap<i16, u32>>,
166+
culture_graph_complete: HashMap<GameId, BTreeMap<i16, u32>>,
167+
total_deaths: BTreeMap<i16, u32>,
160168
}
161169

162170
impl Grapher {
163171
pub fn new(
164-
faith_death_data: HashMap<GameId, HashMap<i16, f64>>,
165-
culture_death_data: HashMap<GameId, HashMap<i16, f64>>,
172+
faith_death_data: HashMap<GameId, BTreeMap<i16, u32>>,
173+
culture_death_data: HashMap<GameId, BTreeMap<i16, u32>>,
174+
total_deaths: BTreeMap<i16, u32>,
166175
) -> Self {
167-
let process = |(id, data): (&GameId, &HashMap<i16, f64>)| {
168-
let mut vec = Vec::new();
169-
for (date, deaths) in data {
170-
vec.push((*date, *deaths));
171-
if !data.contains_key(&(date + 1)) {
172-
vec.push((date + 1, 0.));
173-
}
174-
if !data.contains_key(&(date - 1)) {
175-
vec.push((date - 1, 0.));
176-
}
177-
}
178-
vec.sort_by(|a, b| a.0.cmp(&b.0));
179-
(*id, vec)
180-
};
181-
//the idea is to get all the data we may need in one go, chances are all of it is gonna be needed anywho
182-
let faith_processed = faith_death_data.iter().map(process).collect();
183-
let culture_processed = culture_death_data.iter().map(process).collect();
184176
Grapher {
185-
faith_graph_complete: faith_processed,
186-
culture_graph_complete: culture_processed,
177+
faith_graph_complete: faith_death_data,
178+
culture_graph_complete: culture_death_data,
179+
total_deaths,
187180
}
188181
}
189182

@@ -368,13 +361,13 @@ impl Grapher {
368361

369362
pub fn create_culture_graph<P: AsRef<Path>>(&self, culture_id: GameId, output_path: &P) {
370363
if let Some(data) = self.culture_graph_complete.get(&culture_id) {
371-
create_graph(data, output_path, Some(Y_LABEL), None)
364+
create_graph(data, &self.total_deaths, output_path, Some(Y_LABEL), None)
372365
}
373366
}
374367

375368
pub fn create_faith_graph<P: AsRef<Path>>(&self, faith_id: GameId, output_path: &P) {
376369
if let Some(data) = self.faith_graph_complete.get(&faith_id) {
377-
create_graph(data, output_path, Some(Y_LABEL), None)
370+
create_graph(data, &self.total_deaths, output_path, Some(Y_LABEL), None)
378371
}
379372
}
380373
}

src/parser/game_state.rs

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::HashMap;
1+
use std::collections::{BTreeMap, HashMap};
22

33
use super::{
44
super::{
@@ -90,7 +90,7 @@ pub struct GameState {
9090
traits_lookup: Vec<GameString>,
9191
/// A vassal contract id->Character transform
9292
contract_transform: HashMap<GameId, Shared<Option<GameRef<Character>>>>,
93-
character_transform: HashMap<GameId, GameRef<Character>>,
93+
character_transform: HashMap<GameId, GameId>,
9494
#[serde(skip)]
9595
county_data: HashMap<String, (GameRef<Faith>, GameRef<Culture>)>,
9696
/// The current date from the meta section
@@ -126,7 +126,7 @@ impl GameState {
126126
self.traits_lookup = array;
127127
}
128128

129-
pub fn add_character_transform(&mut self, transform: HashMap<GameId, GameRef<Character>>) {
129+
pub fn add_character_transform(&mut self, transform: HashMap<GameId, GameId>) {
130130
self.character_transform = transform;
131131
}
132132

@@ -228,10 +228,13 @@ impl GameState {
228228
let char = self.get_character(key);
229229
char.get_internal_mut().init(value, self)?;
230230
if let Some(alt) = self.character_transform.get(key) {
231-
if alt.get_internal_mut().inner().is_none() {
232-
// TODO this clone is very wasteful
233-
alt.get_internal_mut()
234-
.replace(char.get_internal().inner().unwrap().clone());
231+
if let Some(alt_char) = self.characters.get(alt) {
232+
if alt_char.get_internal().inner().is_none() {
233+
// TODO this clone is very wasteful
234+
alt_char
235+
.get_internal_mut()
236+
.replace(char.get_internal().inner().unwrap().clone());
237+
}
235238
}
236239
}
237240
Ok(())
@@ -282,7 +285,7 @@ impl GameState {
282285
}
283286

284287
pub fn new_grapher(&self) -> Grapher {
285-
let mut total_yearly_deaths: HashMap<i16, i32> = HashMap::default();
288+
let mut total_yearly_deaths: BTreeMap<i16, u32> = BTreeMap::default();
286289
let mut faith_yearly_deaths = HashMap::default();
287290
let mut culture_yearly_deaths = HashMap::default();
288291
let start_year = self.current_date.unwrap().year() - self.offset_date.unwrap().year();
@@ -299,33 +302,25 @@ impl GameState {
299302
{
300303
let entry = faith_yearly_deaths
301304
.entry(char.get_faith().as_ref().unwrap().get_internal().get_id())
302-
.or_insert(HashMap::default());
303-
let count = entry.entry(death_date.year()).or_insert(0.);
304-
*count += 1.;
305+
.or_insert(BTreeMap::default());
306+
let count = entry.entry(death_date.year()).or_insert(0);
307+
*count += 1;
305308
}
306309
{
307310
let entry = culture_yearly_deaths
308311
.entry(char.get_culture().as_ref().unwrap().get_internal().get_id())
309-
.or_insert(HashMap::default());
310-
let count = entry.entry(death_date.year()).or_insert(0.);
311-
*count += 1.;
312+
.or_insert(BTreeMap::default());
313+
let count = entry.entry(death_date.year()).or_insert(0);
314+
*count += 1;
312315
}
313316
}
314317
}
315318
}
316-
for (year, tot) in total_yearly_deaths {
317-
for data in faith_yearly_deaths.values_mut() {
318-
if let Some(count) = data.get_mut(&year) {
319-
*count /= tot as f64;
320-
}
321-
}
322-
for data in culture_yearly_deaths.values_mut() {
323-
if let Some(count) = data.get_mut(&year) {
324-
*count /= tot as f64;
325-
}
326-
}
327-
}
328-
Grapher::new(faith_yearly_deaths, culture_yearly_deaths)
319+
Grapher::new(
320+
faith_yearly_deaths,
321+
culture_yearly_deaths,
322+
total_yearly_deaths,
323+
)
329324
}
330325

331326
pub fn new_timeline(&self) -> Timeline {

src/parser/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ pub fn process_section(
188188
let mut transform = HashMap::new();
189189
for (key, val) in parsed.as_map()? {
190190
if let Ok(key) = key.parse::<GameId>() {
191-
transform.insert(key, game_state.get_character(&val.as_id()?));
191+
transform.insert(key, val.as_id()?);
192192
}
193193
}
194194
game_state.add_character_transform(transform);

src/structures/house.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,6 @@ impl Localizable for House {
154154
}
155155
_ => {}
156156
}
157-
} else {
158-
// TODO this can happen with uninitialized characters
159-
return Some("Unknown".into());
160157
}
161158
}
162159
_ => {}

0 commit comments

Comments
 (0)