Exchanges, initial cards
This commit is contained in:
parent
cab89f5d64
commit
7f83f2f8cb
253
src/lib.rs
253
src/lib.rs
@ -246,7 +246,148 @@ impl Game {
|
|||||||
self.turn = next;
|
self.turn = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PublicGame {
|
||||||
|
pub players: Vec<PublicPlayer>,
|
||||||
|
pub discard: Vec<Card>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Game> for PublicGame {
|
||||||
|
fn from(game: Game) -> Self {
|
||||||
|
let players = game.players.into_iter().map(PublicPlayer::from).collect();
|
||||||
|
let discard = game.discard;
|
||||||
|
PublicGame { players, discard }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PublicPlayer {
|
||||||
|
pub cards: usize,
|
||||||
|
pub coins: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Player> for PublicPlayer {
|
||||||
|
fn from(player: Player) -> Self {
|
||||||
|
let cards = player.cards.len();
|
||||||
|
let coins = player.coins;
|
||||||
|
PublicPlayer { cards, coins }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
|
pub struct Move {
|
||||||
|
pub action: Action,
|
||||||
|
pub target: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
|
pub struct Block {
|
||||||
|
pub blocker: usize,
|
||||||
|
pub card: Card,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase we should move to.
|
||||||
|
///
|
||||||
|
/// Coup turns have 5 phases, depending on what actions are taken each phase
|
||||||
|
/// some phases might be skipped.
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub enum Phase {
|
||||||
|
ActionChallenge(Move),
|
||||||
|
Block(Move),
|
||||||
|
BlockChallenge(Move, Block),
|
||||||
|
Resolution(Move),
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::sync::mpsc;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Channels {
|
||||||
|
txs: Vec<mpsc::Sender<Message>>,
|
||||||
|
rxs: Vec<mpsc::Receiver<Message>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Channels {
|
||||||
|
pub fn add_channel(&mut self, tx: mpsc::Sender<Message>, rx: mpsc::Receiver<Message>) {
|
||||||
|
self.txs.push(tx);
|
||||||
|
self.rxs.push(rx);
|
||||||
|
}
|
||||||
|
pub fn send(&self, id: usize, msg: Message) {
|
||||||
|
self.txs[id].send(msg).unwrap();
|
||||||
|
}
|
||||||
|
pub fn recv(&self, id: usize) -> Message {
|
||||||
|
self.rxs[id].recv().unwrap()
|
||||||
|
}
|
||||||
|
pub fn try_recv(&self, id: usize) -> Option<Message> {
|
||||||
|
self.rxs[id].try_recv().ok()
|
||||||
|
}
|
||||||
|
pub fn broadcast(&self, msg: Message) {
|
||||||
|
for id in 0..self.rxs.len() {
|
||||||
|
self.send(id, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn recv_move(&self, id: usize) -> CoupResult<Move> {
|
||||||
|
let msg = self.recv(id);
|
||||||
|
match msg {
|
||||||
|
Message::Move(move_) => Ok(move_),
|
||||||
|
_ => Err("Expected move"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn recv_discard(&self, id: usize) -> CoupResult<Card> {
|
||||||
|
let msg = self.recv(id);
|
||||||
|
match msg {
|
||||||
|
Message::Discard(card) => Ok(card),
|
||||||
|
_ => Err("Expected discard")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn try_recv_challenge(&self, id: usize) -> Option<()> {
|
||||||
|
let msg = self.try_recv(id);
|
||||||
|
match msg {
|
||||||
|
Some(Message::Challenge) => Some(()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn try_recv_block(&self, id: usize) -> Option<Card> {
|
||||||
|
let msg = self.try_recv(id);
|
||||||
|
match msg {
|
||||||
|
Some(Message::Block(card)) => Some(card),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum Message {
|
||||||
|
InitialDraw([Card; 2]),
|
||||||
|
Exchange([Card; 2]),
|
||||||
|
Turn(usize),
|
||||||
|
LoseInfluence,
|
||||||
|
Move(Move),
|
||||||
|
Challenge,
|
||||||
|
Block(Card),
|
||||||
|
Discard(Card),
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::time::{ Instant, Duration };
|
||||||
|
const WAIT_TIME: Duration = Duration::from_secs(1);
|
||||||
|
struct Timer {
|
||||||
|
start: Instant,
|
||||||
|
}
|
||||||
|
impl Timer {
|
||||||
|
fn start() -> Self {
|
||||||
|
Timer { start: Instant::now() }
|
||||||
|
}
|
||||||
|
fn is_timeout(&self) -> bool {
|
||||||
|
Instant::now() > self.start + WAIT_TIME
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Game {
|
||||||
|
pub fn initial_hand(&self, channels: &Channels) {
|
||||||
|
for (id, player) in self.players.iter().enumerate() {
|
||||||
|
channels.send(id, Message::InitialDraw(card_arr(&player.cards)));
|
||||||
|
}
|
||||||
|
}
|
||||||
fn player_lose_influence(&mut self, id: usize, channels: &Channels) -> CoupResult<()> {
|
fn player_lose_influence(&mut self, id: usize, channels: &Channels) -> CoupResult<()> {
|
||||||
channels.send(id, Message::LoseInfluence);
|
channels.send(id, Message::LoseInfluence);
|
||||||
let card = channels.recv_discard(id)?;
|
let card = channels.recv_discard(id)?;
|
||||||
@ -261,7 +402,6 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn action(&mut self, channels: &Channels) -> CoupResult<Phase> {
|
pub fn action(&mut self, channels: &Channels) -> CoupResult<Phase> {
|
||||||
channels.broadcast(Message::Turn(self.turn));
|
|
||||||
let move_ = channels.recv_move(self.turn)?;
|
let move_ = channels.recv_move(self.turn)?;
|
||||||
if move_.action.is_targeted() && move_.target.is_none() {
|
if move_.action.is_targeted() && move_.target.is_none() {
|
||||||
Err("Targeted action with no target")
|
Err("Targeted action with no target")
|
||||||
@ -415,6 +555,7 @@ impl Game {
|
|||||||
Tax => self.players[self.turn].coins += 3,
|
Tax => self.players[self.turn].coins += 3,
|
||||||
Exchange => {
|
Exchange => {
|
||||||
let drawn = vec![self.deck.pop().unwrap(), self.deck.pop().unwrap()];
|
let drawn = vec![self.deck.pop().unwrap(), self.deck.pop().unwrap()];
|
||||||
|
channels.send(self.turn, Message::Exchange(card_arr(&drawn)));
|
||||||
let hand = self.players[self.turn].cards.clone();
|
let hand = self.players[self.turn].cards.clone();
|
||||||
let mut choices = [drawn, hand].concat();
|
let mut choices = [drawn, hand].concat();
|
||||||
let mut discarded = [Ambassador; 2];
|
let mut discarded = [Ambassador; 2];
|
||||||
@ -446,111 +587,15 @@ impl Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
fn card_arr(cards: &[Card]) -> [Card; 2] {
|
||||||
pub struct Move {
|
if cards.len() < 2 {
|
||||||
pub action: Action,
|
panic!("Not enough cards");
|
||||||
pub target: Option<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
|
||||||
pub struct Block {
|
|
||||||
pub blocker: usize,
|
|
||||||
pub card: Card,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Phase we should move to.
|
|
||||||
///
|
|
||||||
/// Coup turns have 5 phases, depending on what actions are taken each phase
|
|
||||||
/// some phases might be skipped.
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
pub enum Phase {
|
|
||||||
ActionChallenge(Move),
|
|
||||||
Block(Move),
|
|
||||||
BlockChallenge(Move, Block),
|
|
||||||
Resolution(Move),
|
|
||||||
Done,
|
|
||||||
}
|
|
||||||
|
|
||||||
use std::sync::mpsc;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Channels {
|
|
||||||
txs: Vec<mpsc::Sender<Message>>,
|
|
||||||
rxs: Vec<mpsc::Receiver<Message>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Channels {
|
|
||||||
pub fn add_channel(&mut self, tx: mpsc::Sender<Message>, rx: mpsc::Receiver<Message>) {
|
|
||||||
self.txs.push(tx);
|
|
||||||
self.rxs.push(rx);
|
|
||||||
}
|
}
|
||||||
pub fn send(&self, id: usize, msg: Message) {
|
let mut arr = [Duke, Duke];
|
||||||
self.txs[id].send(msg).unwrap();
|
for i in 0..2 {
|
||||||
}
|
arr[i] = cards[i];
|
||||||
pub fn recv(&self, id: usize) -> Message {
|
|
||||||
self.rxs[id].recv().unwrap()
|
|
||||||
}
|
|
||||||
pub fn try_recv(&self, id: usize) -> Option<Message> {
|
|
||||||
self.rxs[id].try_recv().ok()
|
|
||||||
}
|
|
||||||
pub fn broadcast(&self, msg: Message) {
|
|
||||||
for id in 0..self.rxs.len() {
|
|
||||||
self.send(id, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn recv_move(&self, id: usize) -> CoupResult<Move> {
|
|
||||||
let msg = self.recv(id);
|
|
||||||
match msg {
|
|
||||||
Message::Move(move_) => Ok(move_),
|
|
||||||
_ => Err("Expected move"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn recv_discard(&self, id: usize) -> CoupResult<Card> {
|
|
||||||
let msg = self.recv(id);
|
|
||||||
match msg {
|
|
||||||
Message::Discard(card) => Ok(card),
|
|
||||||
_ => Err("Expected discard")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn try_recv_challenge(&self, id: usize) -> Option<()> {
|
|
||||||
let msg = self.try_recv(id);
|
|
||||||
match msg {
|
|
||||||
Some(Message::Challenge) => Some(()),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn try_recv_block(&self, id: usize) -> Option<Card> {
|
|
||||||
let msg = self.try_recv(id);
|
|
||||||
match msg {
|
|
||||||
Some(Message::Block(card)) => Some(card),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
||||||
pub enum Message {
|
|
||||||
Turn(usize),
|
|
||||||
LoseInfluence,
|
|
||||||
Move(Move),
|
|
||||||
Challenge,
|
|
||||||
Block(Card),
|
|
||||||
Discard(Card),
|
|
||||||
}
|
|
||||||
|
|
||||||
use std::time::{ Instant, Duration };
|
|
||||||
const WAIT_TIME: Duration = Duration::from_secs(1);
|
|
||||||
struct Timer {
|
|
||||||
start: Instant,
|
|
||||||
}
|
|
||||||
impl Timer {
|
|
||||||
fn start() -> Self {
|
|
||||||
Timer { start: Instant::now() }
|
|
||||||
}
|
|
||||||
fn is_timeout(&self) -> bool {
|
|
||||||
Instant::now() > self.start + WAIT_TIME
|
|
||||||
}
|
}
|
||||||
|
arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user