Skip to content

Commit

Permalink
renamed coup, docs
Browse files Browse the repository at this point in the history
  • Loading branch information
dominikwilkowski committed Apr 24, 2024
1 parent dafc900 commit 4b1db05
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 29 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "coup-cli"
version = "0.1.0"
name = "coup"
version = "0.0.1"
edition = "2021"
authors = ["Dominik Wilkowski <Hi@Dominik-Wilkowski.com>"]
license = "GPL-3.0-or-later"
Expand Down
47 changes: 47 additions & 0 deletions src/bot.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
//! The bot trait [BotInterface] and a couple types that help with the bot implementation
use std::fmt;

use crate::{Action, Card, Counter, History, Score};

/// A bot struct requires three public fields:
/// ```rust
/// pub name: String,
/// pub coins: u8,
/// pub cards: Vec<Card>,
/// ```
#[derive(Debug, Clone)]
pub struct Bot {
pub name: String,
Expand All @@ -19,21 +27,37 @@ impl Bot {
}
}

/// A type to describe other bots still in the game
#[derive(Debug, Clone)]
pub struct OtherBot {
/// The name of the bot used to identify it in [Action] and [Counter]
pub name: String,
/// The amount of coins this bot has
pub coins: u8,
/// The amount of [Card] this bot still have
pub cards: u8,
}

/// The context struct is what is passed into each of the [BotInterface] methods
/// as arguments so the bot knows the context of the current move
#[derive(Debug, Clone)]
pub struct Context<'a> {
/// A list of all other bots minus the yourself
pub other_bots: &'a [OtherBot],
/// A list of all discarded [Card] so far in the game
pub discard_pile: &'a [Card],
/// A list of each events that have happened in this game so far
pub history: &'a [History],
/// The current score of the game
pub score: &'a Score,
}

/// The BotInterface trait is what drives your bot.
/// You need to store a couple things for yourself which is what the getter and
/// setter methods are for and then implement each method below that defines
/// the behavior of your bot.
/// The default implementation is a static implementation of a bot like the
/// pre-build [crate::bots::StaticBot].
pub trait BotInterface {
fn get_name(&self) -> String;
fn get_coins(&self) -> u8;
Expand Down Expand Up @@ -94,6 +118,21 @@ pub trait BotInterface {
}
}

/// The debug trait has been implemented to support both format and alternate
/// format which means you can print a bot instance with:
/// ```rust
/// let mut bot = Box::new(StaticBot::new(String::from("My static bot"))) as Box<dyn BotInterface>;
/// println!("{:?}", bot);
/// // Bot { name: "My static bot", coins: 2, cards: [] }
///
/// // or
/// println!("{:#?}", bot);
/// // Bot {
/// // name: "My static bot"
/// // coins: 2
/// // cards: []
/// // }
/// ```
impl fmt::Debug for dyn BotInterface {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
Expand All @@ -114,6 +153,14 @@ impl fmt::Debug for dyn BotInterface {
}
}

/// The display trait has been implemented which means you can print the avatar
/// of a bot instance with:
/// ```rust
/// let mut bot = Box::new(StaticBot::new(String::from("My static bot"))) as Box<dyn BotInterface>;
/// println!("{}", bot);
/// // [My static bot ♡♡ 💰2]
/// ```
impl fmt::Display for dyn BotInterface {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
Expand Down
19 changes: 13 additions & 6 deletions src/bots/honest_bot.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
//! A honest bot implementation for you to use to test your own bot with.
use crate::{
bot::{BotInterface, Context},
Action, Card,
};

/// The honest bot will try to take all actions it should take without being too
/// smart or strategic thinking. It will act on it's own cards, counter other
/// bots if they do something that it can counter based on its cards and will
/// never bluff itself
pub struct HonestBot {
pub name: String,
pub coins: u8,
Expand Down Expand Up @@ -41,11 +47,12 @@ impl BotInterface for HonestBot {
}

fn on_turn(&self, context: Context) -> Action {
// if self.get_coins() >= 10 {
let target = context.other_bots.iter().min_by_key(|bot| bot.cards).unwrap();
Action::Coup(target.name.clone())
// } else {
// Action::Income
// }
if self.get_coins() >= 10 {
let target =
context.other_bots.iter().min_by_key(|bot| bot.cards).unwrap();
Action::Coup(target.name.clone())
} else {
Action::Income
}
}
}
2 changes: 2 additions & 0 deletions src/bots/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! A collection of pre-built bots to test with
pub mod honest_bot;
pub mod static_bot;
// TODO: pub mod random_bot;
Expand Down
5 changes: 5 additions & 0 deletions src/bots/static_bot.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
//! A static bot implementation for you to use to test your own bot with.
use crate::{bot::BotInterface, Card};

/// The static bot only takes [crate::Action::Income] on turns and eventually is forced
/// by the engine to coup another bot. It won't challenge, counter or act on its
/// own cards at all.
pub struct StaticBot {
pub name: String,
pub coins: u8,
Expand Down
54 changes: 39 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@ pub mod bots;

use crate::bot::{BotInterface, Context, OtherBot};

/// One of the five cards you get in the game of Coup
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Card {
/// - [Action::Swapping] – Draw two character cards from the deck, choose which (if any) to exchange with your cards, then return two<br>
/// - [Counter::Stealing] – Block someone from stealing coins from you
Ambassador,
/// - [Action::Assassination] – Pay three coins and try to assassinate another player's character
Assassin,
/// - [Action::Stealing] – Take two coins from another player
/// - [Counter::Stealing] – Block someone from stealing coins from you
Captain,
/// - [Counter::Assassination] – Block an assassination attempt against yourself.
Contessa,
/// - [Action::Tax] – Take three coins from the treasury<br>
/// - [Counter::ForeignAid] – Block someone from taking foreign aid
Duke,
}

Expand Down Expand Up @@ -42,14 +51,13 @@ pub enum Counter {
Assassination,
/// Block foreign aid with your [Card::Duke]
ForeignAid,
/// Block stealing with your [Card::Captain]
StealingCaptain,
/// Block stealing with your [Card::Ambassador]
StealingAmbassador,
/// block tax with your [Card::Duke]
/// Block stealing with your [Card::Captain] or your [Card::Ambassador]
Stealing,
/// Block tax with your [Card::Duke]
Tax,
}

/// A collection on all possible moves in the game for bots to analyze
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum History {
ActionAssassination { by: String, target: String },
Expand All @@ -71,17 +79,19 @@ pub enum History {
CounterTax { by: String, target: String },
}

/// The score of the game for all bots
pub type Score = Vec<(String, u64)>;

/// The Coup game engine
pub struct Coup {
pub bots: Vec<Box<dyn BotInterface>>,
pub playing_bots: Vec<usize>,
pub deck: Vec<Card>,
pub discard_pile: Vec<Card>,
pub history: Vec<History>,
pub score: Score,
pub turn: usize,
pub moves: usize,
bots: Vec<Box<dyn BotInterface>>,
playing_bots: Vec<usize>,
deck: Vec<Card>,
discard_pile: Vec<Card>,
history: Vec<History>,
score: Score,
turn: usize,
moves: usize,
}

impl Coup {
Expand All @@ -101,7 +111,9 @@ impl Coup {
}
}

/// A public method to get a new deck
/// A public method to get a new deck.
/// This can be used by bots to make sure you get the same amount of cards as
/// the engine does
pub fn new_deck() -> Vec<Card> {
let mut deck = vec![
Card::Ambassador,
Expand Down Expand Up @@ -147,7 +159,8 @@ impl Coup {
> 1
}

/// Starting a round which means we setup the table, give each bots their cards and coins
/// Playing a game which means we setup the table, give each bots their cards
/// and coins and start the game loop
pub fn play(&mut self) {
// A fresh deck
let mut deck = Coup::new_deck();
Expand Down Expand Up @@ -477,6 +490,17 @@ impl Coup {
}
}

/// The debug trait has been implemented to support both format and alternate
/// format which means you can print a game instance with:
/// ```rust
/// let mut my_coup = Coup::new(vec![]);
/// println!("{:?}", my_coup);
/// ```
/// and
/// ```rust
/// let mut my_coup = Coup::new(vec![]);
/// println!("{:#?}", my_coup);
/// ```
impl fmt::Debug for Coup {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
Expand Down
9 changes: 5 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use coup_cli::{
use coup::{
bots::{HonestBot, StaticBot},
Coup,
};

fn main() {
let mut coup_game = Coup::new(vec![
Box::new(StaticBot::new(String::from("Bot 1"))),
Box::new(HonestBot::new(String::from("Bot 2"))),
Box::new(StaticBot::new(String::from("Bot 3"))),
Box::new(StaticBot::new(String::from("Charles"))),
Box::new(HonestBot::new(String::from("Tici"))),
Box::new(StaticBot::new(String::from("Novini"))),
Box::new(HonestBot::new(String::from("Dom"))),
]);

coup_game.play();
Expand Down

0 comments on commit 4b1db05

Please sign in to comment.