début plotting, pour l'instant ça marche pas
This commit is contained in:
16
Cargo.lock
generated
16
Cargo.lock
generated
@@ -60,6 +60,12 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
@@ -71,6 +77,15 @@ dependencies = [
|
|||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.9"
|
version = "1.0.9"
|
||||||
@@ -149,6 +164,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"argh",
|
"argh",
|
||||||
"csv",
|
"csv",
|
||||||
|
"itertools",
|
||||||
"rand",
|
"rand",
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
argh = "0.1.12"
|
argh = "0.1.12"
|
||||||
csv = "1.2.2"
|
csv = "1.2.2"
|
||||||
|
itertools = "0.13.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
rand_chacha = "0.3.1"
|
rand_chacha = "0.3.1"
|
||||||
serde = "1.0.188"
|
serde = "1.0.188"
|
||||||
|
|||||||
66
src/io.rs
66
src/io.rs
@@ -1,20 +1,66 @@
|
|||||||
use super::repartition::*;
|
use std::fs;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
const FORMAT_TEXT: &'static str = "<html>
|
use super::repartition::*;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
impl Repartition {
|
||||||
|
pub fn to_json(&self) -> String {
|
||||||
|
let participants = self
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.flat_map(|t| vec![t.from.clone(), t.to.clone()])
|
||||||
|
.dedup()
|
||||||
|
.collect_vec();
|
||||||
|
let mut str_nodes = String::new();
|
||||||
|
for p in participants {
|
||||||
|
str_nodes += &format!(
|
||||||
|
"{{
|
||||||
|
\"data\": {{
|
||||||
|
\"id\":\"{}\",
|
||||||
|
\"label\":\"{}\"
|
||||||
|
}},
|
||||||
|
}},",
|
||||||
|
p.name, p.name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut str_edges = String::new();
|
||||||
|
for t in &self.0 {
|
||||||
|
str_edges += &format!(
|
||||||
|
"{{
|
||||||
|
\"data\": {{
|
||||||
|
\"id\":\"{}-{}\",
|
||||||
|
\"label\":\"{}€\",
|
||||||
|
\"source\":\"{}\",
|
||||||
|
\"target\":\"{}\",
|
||||||
|
}}
|
||||||
|
}},",
|
||||||
|
t.from.name,
|
||||||
|
t.to.name,
|
||||||
|
t.amount as f32 / 100.,
|
||||||
|
t.from.name,
|
||||||
|
t.to.name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"[".to_owned() + &str_nodes + "," + &str_edges + "]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FORMAT_STRING: &'static str = "<html>
|
||||||
<head>
|
<head>
|
||||||
<script src=\"/home/jfelderh/Prog/Repartition Alpes/cytoscape.min.js\"></script>
|
<script src=\"/home/jfelderh/Prog/Repartition Alpes/cytoscape.min.js\"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id=\"graph\" style=\"width: auto;height: 500px;\"></div>
|
<div id=\"graph\" style=\"width: auto;height: 500px;\"></div>
|
||||||
|
|
||||||
<h3>Balance totale (doit être égal à zéro) : {}€</h3>
|
<h3>Balance totale (doit être égal à zéro) : TOTAL_BALANCE €</h3>
|
||||||
|
|
||||||
<script type=\"text/javascript\">
|
<script type=\"text/javascript\">
|
||||||
var cy = cytoscape({
|
var cy = cytoscape({
|
||||||
|
|
||||||
container: document.getElementById('graph'), // container to render in
|
container: document.getElementById('graph'), // container to render in
|
||||||
|
|
||||||
elements:{},
|
elements:ELEMENTS,
|
||||||
|
|
||||||
style: [ // the stylesheet for the graph
|
style: [ // the stylesheet for the graph
|
||||||
{
|
{
|
||||||
@@ -48,3 +94,15 @@ style: [ // the stylesheet for the graph
|
|||||||
|
|
||||||
</body>
|
</body>
|
||||||
";
|
";
|
||||||
|
use super::repartition::*;
|
||||||
|
pub fn plot_repartition(rep: &Repartition) {
|
||||||
|
let text_html = FORMAT_STRING
|
||||||
|
.to_string()
|
||||||
|
.replace("TOTAL_BALANCE", &rep.total_balance().to_string())
|
||||||
|
.replace("ELEMENTS", &rep.to_json());
|
||||||
|
fs::write("/tmp/repartition.html", text_html).expect("Could not write into /tmp/");
|
||||||
|
Command::new("firefox")
|
||||||
|
.arg("/tmp/repartition.html")
|
||||||
|
.output()
|
||||||
|
.expect("Could not run firefox");
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,12 +37,16 @@ fn main() {
|
|||||||
let repartition_file = fs::File::open(filename).expect("not able to read file");
|
let repartition_file = fs::File::open(filename).expect("not able to read file");
|
||||||
let mut csv_reader = csv::ReaderBuilder::new()
|
let mut csv_reader = csv::ReaderBuilder::new()
|
||||||
.has_headers(false)
|
.has_headers(false)
|
||||||
.delimiter(b';')
|
.delimiter(b',')
|
||||||
.from_reader(repartition_file);
|
.from_reader(repartition_file);
|
||||||
|
|
||||||
let user_list = csv_reader
|
let user_list = csv_reader
|
||||||
.records()
|
.records()
|
||||||
.map(Result::unwrap)
|
.map(Result::unwrap)
|
||||||
|
.map(|r| {
|
||||||
|
dbg!(&r);
|
||||||
|
r
|
||||||
|
})
|
||||||
.map(|record| User {
|
.map(|record| User {
|
||||||
name: record[0].parse::<String>().unwrap().trim_end().to_string(),
|
name: record[0].parse::<String>().unwrap().trim_end().to_string(),
|
||||||
balance_cents: (record[1].parse::<f64>().unwrap() * 100.) as i32,
|
balance_cents: (record[1].parse::<f64>().unwrap() * 100.) as i32,
|
||||||
@@ -67,9 +71,11 @@ fn main() {
|
|||||||
serde_json::to_string_pretty(&best_repartition).unwrap()
|
serde_json::to_string_pretty(&best_repartition).unwrap()
|
||||||
);
|
);
|
||||||
} else if let Some(filename) = args.transfert_list_filename {
|
} else if let Some(filename) = args.transfert_list_filename {
|
||||||
|
dbg!(&filename);
|
||||||
let repart: Repartition =
|
let repart: Repartition =
|
||||||
serde_json::from_reader(fs::File::open(filename).expect("not able to read file"))
|
serde_json::from_reader(fs::File::open(filename).expect("not able to read file"))
|
||||||
.expect("unable to read file");
|
.expect("unable to read file");
|
||||||
|
io::plot_repartition(&repart);
|
||||||
} else {
|
} else {
|
||||||
println!("No parameter given, exiting");
|
println!("No parameter given, exiting");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use std::cmp::min;
|
use std::{cmp::min, collections::HashSet};
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub email: String,
|
pub email: String,
|
||||||
@@ -85,11 +85,13 @@ pub struct Transfer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct Repartition(Vec<Transfer>);
|
pub struct Repartition(pub Vec<Transfer>);
|
||||||
|
|
||||||
type Evaluation = (usize);
|
type Evaluation = (usize);
|
||||||
|
|
||||||
impl Repartition {
|
impl Repartition {
|
||||||
|
pub fn total_balance(&self) -> i32 {
|
||||||
|
self.0.iter().map(|t| t.amount as i32).sum()
|
||||||
|
}
|
||||||
pub fn evaluate(&self) -> Evaluation {
|
pub fn evaluate(&self) -> Evaluation {
|
||||||
self.0.len()
|
self.0.len()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user