1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
#[macro_use] extern crate prettytable; use itertools::Itertools; use prettytable::{format, Table}; use std::collections::HashSet; const NUM_SQUAD: usize = 11; pub fn calc_rating(ratings: Vec<u32>) -> u32 { let num = ratings.len(); assert_eq!(num, NUM_SQUAD); let sum = ratings.iter().sum::<u32>(); let avg = sum as f32 / num as f32; let above_sum = ratings .into_iter() .map(|x| if x as f32 > avg { x as f32 - avg } else { 0f32 }) .sum::<f32>(); let rating = (sum as f32 + above_sum).round() / num as f32; rating as u32 } pub fn generate( have: &Vec<u32>, cand: &Vec<u32>, target: u32, records_limit: usize, ) -> Vec<Vec<u32>> { assert!(have.len() <= NUM_SQUAD); let remain = NUM_SQUAD - have.len(); let mut visited = HashSet::new(); let mut possibles = Vec::new(); let mut sorted_cand = cand.clone(); sorted_cand.sort(); for bench in (0..remain) .map(|_| sorted_cand.clone()) .multi_cartesian_product() { let mut squad = have.clone(); squad.extend(&bench); let mut bench_sorted = bench.clone(); bench_sorted.sort(); if visited.contains(&bench_sorted) { continue; } visited.insert(bench_sorted.clone()); if calc_rating(squad) == target { possibles.push(bench_sorted); if possibles.len() > records_limit { break; } } } possibles } pub fn show(cand: Vec<u32>, possibles: Vec<Vec<u32>>) { let mut table = Table::new(); table.set_format(*format::consts::FORMAT_CLEAN); let mut cand = cand; cand.sort(); const SEP: &str = " "; const WIDTH: usize = 2; let header = cand .iter() .map(|x| format!("{:<w$}", x, w=WIDTH)) .collect::<Vec<_>>() .join(SEP); table.add_row(row![FdBbbl->header]); for (pos, ratings) in possibles.iter().enumerate() { let row = cand .iter() .map(|x| { let r = ratings.iter().filter(|&y| y == x).count(); if r == 0 { " ".to_string() } else { format!("{:<w$}", r, w=WIDTH) } }) .collect::<Vec<_>>() .join(SEP); if pos % 2 == 0 { table.add_row(row![Fcl->row]); } else { table.add_row(row![FdBcl->row]); } } table.printstd(); } #[cfg(test)] mod tests { use super::*; #[test] pub fn test_calc_rating() { { let v = vec![81; 11]; assert_eq!(81, calc_rating(v)); } { let v = vec![85, 86, 86, 86, 87, 87, 87, 87, 87, 87, 88]; assert_eq!(87, calc_rating(v)); } } #[test] pub fn test_generate() { let have = vec![88, 87, 87, 86, 85, 85]; let cand = vec![85, 84, 83]; let target = 86; let limits = 10; let res = generate(&have, &cand, target, limits); assert_eq!(res.len(), 9); assert_eq!(res[0], vec![83, 83, 85, 85, 85]); assert_eq!(res[1], vec![83, 84, 84, 85, 85]); assert_eq!(res[2], vec![83, 84, 85, 85, 85]); assert_eq!(res[3], vec![83, 85, 85, 85, 85]); assert_eq!(res[4], vec![84, 84, 84, 84, 85]); assert_eq!(res[5], vec![84, 84, 84, 85, 85]); assert_eq!(res[6], vec![84, 84, 85, 85, 85]); assert_eq!(res[7], vec![84, 85, 85, 85, 85]); assert_eq!(res[8], vec![85, 85, 85, 85, 85]); } }