use rand::seq::SliceRandom;
use rand::thread_rng;
use scout_game::{get_valid_actions, Action, GameView, NewGameView, SetMap, Strategy};
use std::collections::HashMap;
use std::io;
fn turns_to_empty(
hand: &Vec<i32>,
set_map: &SetMap,
cache: &mut HashMap<Vec<i32>, usize>,
) -> usize {
if set_map.contains_key(hand) {
return 1;
}
let turns = match cache.get(hand) {
Some(n) => return *n,
None => (0..hand.len())
.flat_map(|start| (start..hand.len()).map(move |stop| (start..stop + 1)))
.map(|range| {
let mut new_hand = hand.clone();
let set: Vec<i32> = new_hand.drain(range).collect();
(set, new_hand)
})
.filter(|(set, _)| set_map.contains_key(set))
.map(
|(_, new_hand)| match turns_to_empty(&new_hand, &set_map, cache) {
1 => {
cache.insert(hand.clone(), 2);
return 2; }
x => x + 1,
},
)
.min()
.unwrap(),
};
cache.insert(hand.clone(), turns);
return turns;
}
pub struct GetPlayerAction {
set_map: SetMap,
}
impl GetPlayerAction {
pub fn new() -> GetPlayerAction {
GetPlayerAction {
set_map: scout_game::default_set_map(),
}
}
}
impl Strategy for GetPlayerAction {
fn get_action(&mut self, view: &GameView) -> Option<Action> {
println!("{}", view);
let indexes: Vec<usize> = (0..view.hand.len()).collect();
println!(" Indexes:{:?}\n", indexes);
let mut input = String::new();
println!("\nSelect action:");
io::stdin()
.read_line(&mut input)
.expect("Failed to read line");
let split: Vec<&str> = input.trim().split(" ").collect();
let action = match split[0] {
"scout" => Action::Scout(
split[1] == "1",
split[2] == "1",
split[3].parse().unwrap_or(0),
),
"show" => Action::Show(split[1].parse().unwrap_or(0), split[2].parse().unwrap_or(0)),
"scoutshow" => {
let scout = Action::Scout(
split[1] == "1",
split[2] == "1",
split[3].parse().unwrap_or(0),
);
let scout_view = match view.take_action(&scout) {
NewGameView::Win => return None,
NewGameView::Loss => return None,
NewGameView::Continue(view) => view,
};
println!("{}", scout_view);
let indexes: Vec<usize> = (0..scout_view.hand.len()).collect();
println!(" Indexes:{:?}\n", indexes);
let mut show_input = String::new();
println!("\nSelect show action (finish scoutshow):");
io::stdin()
.read_line(&mut show_input)
.expect("Failed to read line");
let show_split: Vec<&str> = show_input.trim().split(" ").collect();
let start: usize;
let stop: usize;
if show_split.len() == 2 {
start = show_split[0].parse().unwrap_or(0);
stop = show_split[1].parse().unwrap_or(0);
} else {
start = show_split[1].parse().unwrap_or(0);
stop = show_split[2].parse().unwrap_or(0);
}
Action::ScoutShow(
split[1] == "1",
split[2] == "1",
split[3].parse().unwrap_or(0),
start,
stop,
)
}
"quit" => return None,
_ => {
println!("Input not accepted! Enter: scout, show, scoutshow, or quit");
return self.get_action(&view);
}
};
if get_valid_actions(&view, &self.set_map).contains(&action) {
return Some(action);
} else {
println!("Not a valid action!");
return self.get_action(&view);
}
}
}
pub struct StrategyRush {
set_map: SetMap,
cache: HashMap<Vec<i32>, usize>,
}
impl StrategyRush {
pub fn new() -> StrategyRush {
StrategyRush {
set_map: scout_game::default_set_map(),
cache: HashMap::new(),
}
}
}
impl Strategy for StrategyRush {
fn get_action(&mut self, view: &GameView) -> Option<Action> {
let mut actions = get_valid_actions(&view, &self.set_map);
actions.shuffle(&mut thread_rng());
let mut cache = self.cache.clone();
actions.sort_by_key(|action| match view.take_action(action) {
NewGameView::Continue(new) => turns_to_empty(&new.hand, &self.set_map, &mut cache) + 1,
NewGameView::Win => 0,
NewGameView::Loss => 32,
});
self.cache = cache;
return Some(actions[0]);
}
}
#[test]
fn test_turns_to_empty() {
let set_map = scout_game::default_set_map();
let mut cache: HashMap<Vec<i32>, usize> = HashMap::new();
assert_eq!(turns_to_empty(&vec![0], &set_map, &mut cache), 1);
assert_eq!(turns_to_empty(&vec![0, 1, 2], &set_map, &mut cache), 1);
assert_eq!(turns_to_empty(&vec![0, 1, 0], &set_map, &mut cache), 2);
assert_eq!(turns_to_empty(&vec![1, 3, 5], &set_map, &mut cache), 3);
assert_eq!(turns_to_empty(&vec![1, 3, 1], &set_map, &mut cache), 2);
assert_eq!(turns_to_empty(&vec![1, 3, 3, 1], &set_map, &mut cache), 2);
assert_eq!(
turns_to_empty(&vec![1, 3, 5, 7, 1], &set_map, &mut cache),
4
);
assert_eq!(
turns_to_empty(&vec![7, 3, 2, 1, 4, 7, 1, 2, 1], &set_map, &mut cache),
5
);
}