use ::card::*;
use std::error::Error;
use std::str::FromStr;
use std::io;
use std::io::Write;
fn main() -> Result<(), Box<dyn Error>> {
let n: usize = input("How many players?")?.trim().parse()?;
let c: usize = input("How many cards should each player be dealt?")?.trim().parse()?;
let mut players: Vec<Player> = Vec::new();
for i in 0..n {
players.push(Player::new(i as isize + 1));
}
let mut deck = Deck::new();
for _ in 0..c {
deck.deal_each(&mut players);
}
for player in &mut players {
gofish::process_sets(player);
}
let mut winner = 0;
let mut index = 0;
while winner == 0 {
let i = index;
let j = gofish::select_player(&players, i)?;
let v = gofish::select_value(&players[i])?;
let mut card = gofish::try_take(&mut players[j], &v);
if card.is_none() {
println!("Go fish!");
card = deck.draw();
index += 1;
}
match card {
Some(x) => {
println!("Caught a {}", x);
let value = x.value.clone();
let player = &mut players[i];
player.give(x);
gofish::process_set(player, &value);
},
_ => println!("No cards left!"),
}
winner = match gofish::try_winner(&players) {
Some(x) => x.id,
_ => 0,
};
if index >= players.len() {
index = 0;
}
}
println!("Player {} wins!", winner);
Ok(())
}
fn input(message: &str) -> io::Result<String> {
print!("{} ", message);
let mut s = String::new();
std::io::stdout().flush()?;
std::io::stdin().read_line(&mut s)?;
Ok(s)
}
mod gofish {
use super::*;
pub fn try_winner(players: &Vec<Player>) -> Option<&Player> {
let mut max = 0;
let mut winner = None;
for p in players {
if p.hand_count() == 0 && p.score > max {
max = p.score;
winner = Some(p);
}
}
winner
}
pub fn select_player(players: &Vec<Player>, curr_player: usize) -> io::Result<usize> {
let player = &players[curr_player];
println!("{}", player);
let mut j = -1;
while j < 0 {
j = match input("Who would you like to take from?")?.trim().parse::<isize>() {
Ok(x) if x != player.id as isize
&& x <= players.len() as isize
&& x > 0
&& players[x as usize].hand_count() > 0 => x - 1,
_ => continue,
};
}
Ok(j as usize)
}
pub fn select_value(player: &Player) -> io::Result<Value> {
let mut v: Option<Value> = None;
while v.is_none() {
v = match Value::from_str(super::input("Do you have any...")?.trim()) {
Ok(x) => {
if player.has_any(&Card::new_set(&x)) {
Some(x)
} else {
None
}
},
Err(_) => None,
};
}
Ok(v.unwrap())
}
pub fn try_take(other: &mut Player, value: &Value) -> Option<Card> {
for c in Card::new_set(value) {
let card = other.take(c);
if card.is_some() {
return card;
}
}
None
}
pub fn process_set(player: &mut Player, value: &Value) {
let set = Card::new_set(value);
if player.has_all(&set) {
let s = set.iter()
.map(|c| c.to_string())
.collect::<Vec<_>>()
.join(", ");
println!("Got a set! {}", s);
player.score += 1;
for c in set {
player.take(c);
}
}
}
pub fn process_sets(player: &mut Player) {
for i in 1..14 {
process_set(player, &Value::new(i));
}
}
}