@@ -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
2121const 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
156163pub 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
162170impl 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}
0 commit comments