scarlet_queen_entrypoint/
pokemon_type.rs

1use std::{
2    collections::HashMap,
3    fmt::Debug,
4    fs::{self, File},
5    io::BufWriter,
6};
7
8use plotters::{
9    chart::{ChartBuilder, ChartContext},
10    prelude::{BitMapBackend, Cartesian2d, Circle, DrawingArea, IntoDrawingArea},
11    series::LineSeries,
12    style::{IntoFont, ShapeStyle, WHITE},
13};
14use scarlet_queen_core::pokemon_type::PokemonTypeTrait;
15use scarlet_queen_generation::group::PokemonTypeGroup;
16use scarlet_queen_initializer::group::InitializerSample;
17
18use crate::{
19    error::Error,
20    find_cycle::find_tail_cycle,
21    function::{main_loop, MAIN_LOOP},
22};
23
24pub fn count<P>(loop_result: Vec<Vec<P>>) -> Vec<HashMap<P, usize>>
25where
26    P: PokemonTypeTrait,
27{
28    loop_result
29        .into_iter()
30        .map(|v| {
31            v.iter().fold(HashMap::new(), |mut state, u| {
32                *state.entry(u.clone()).or_insert(0) += 1;
33                state
34            })
35        })
36        .collect::<Vec<HashMap<P, usize>>>()
37}
38
39pub fn draw_graph<P>(loop_result_count: &[HashMap<P, usize>], img_name: &str)
40where
41    P: PokemonTypeTrait,
42{
43    let graph_data: Vec<(P, Vec<(i32, i32)>)> = P::ALL
44        .into_iter()
45        .flatten()
46        .map(|v| {
47            let data: Vec<(i32, i32)> = loop_result_count
48                .iter()
49                .enumerate()
50                .map(|(i, hash_map)| (i as i32, hash_map.get(&v).map_or(0, |u| *u) as i32))
51                .collect::<Vec<(i32, i32)>>();
52            (v, data)
53        })
54        .collect::<Vec<(P, Vec<(i32, i32)>)>>();
55
56    let y_max: i32 = 100;
57    let root: DrawingArea<BitMapBackend<'_>, plotters::coord::Shift> =
58        BitMapBackend::new(img_name, (1080, 720)).into_drawing_area();
59    root.fill(&WHITE).unwrap();
60    let mut chart: ChartContext<
61        '_,
62        BitMapBackend<'_>,
63        Cartesian2d<plotters::coord::types::RangedCoordi32, plotters::coord::types::RangedCoordi32>,
64    > = ChartBuilder::on(&root)
65        .caption("Sample", ("sans-serif", 20).into_font())
66        .x_label_area_size(40)
67        .y_label_area_size(40)
68        .build_cartesian_2d(0..((MAIN_LOOP as i32) + 1), 0..(y_max + 1))
69        .unwrap();
70    chart.configure_mesh().draw().unwrap();
71
72    for (p, data) in graph_data.into_iter() {
73        let line_1: LineSeries<BitMapBackend, (i32, i32)> =
74            LineSeries::new(data.iter().map(|&(x, y)| (x, y)), p.color_map());
75        chart.draw_series(line_1).unwrap();
76        let point_1 = data
77            .iter()
78            .map(|&(x, y)| Circle::new((x, y), 4, ShapeStyle::from(p.color_map()).filled()));
79        chart.draw_series(point_1).unwrap();
80    }
81}
82
83pub fn test_and_draw<P, const N: usize, const R: usize>(test_name: &str) -> Result<(), Error>
84where
85    P: PokemonTypeTrait + Debug,
86{
87    let dir_path: String = format!("./out/{test_name}");
88    fs::create_dir_all(&dir_path)?;
89    let mut file: BufWriter<File> = BufWriter::new(File::create(format!(
90        "{}/res_{}.txt",
91        &dir_path, test_name
92    ))?);
93    let result: Vec<Vec<P>> =
94        main_loop::<P, InitializerSample<N>, PokemonTypeGroup<P, N, R>, BufWriter<File>, N, R>(
95            &mut file,
96        )
97        .unwrap();
98    let count: Vec<HashMap<P, usize>> = count(result);
99    draw_graph(&count, &format!("{}/img_{}.png", &dir_path, test_name));
100    find_tail_cycle(&count, &mut file).unwrap();
101    Ok(())
102}