{"id":17054687,"url":"https://github.com/dominikwilkowski/coup","last_synced_at":"2025-04-12T17:08:34.068Z","repository":{"id":66165755,"uuid":"412351430","full_name":"dominikwilkowski/coup","owner":"dominikwilkowski","description":"A COUP card game engine implemented in rust with a library to make it easy to build bots to play each other.","archived":false,"fork":false,"pushed_at":"2024-05-08T19:21:05.000Z","size":15441,"stargazers_count":17,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-05T02:51:23.918Z","etag":null,"topics":["cli","coup","game"],"latest_commit_sha":null,"homepage":"https://docs.rs/coup","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dominikwilkowski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-01T06:15:34.000Z","updated_at":"2024-12-16T23:35:16.000Z","dependencies_parsed_at":"2024-05-08T20:33:27.881Z","dependency_job_id":null,"html_url":"https://github.com/dominikwilkowski/coup","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dominikwilkowski%2Fcoup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dominikwilkowski%2Fcoup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dominikwilkowski%2Fcoup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dominikwilkowski%2Fcoup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dominikwilkowski","download_url":"https://codeload.github.com/dominikwilkowski/coup/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239952639,"owners_count":19723924,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","coup","game"],"created_at":"2024-10-14T10:15:30.514Z","updated_at":"2025-02-21T19:30:54.469Z","avatar_url":"https://github.com/dominikwilkowski.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg width=\"764\" src=\"assets/coup.png\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"https://crates.io/crates/coup\"\u003e\u003cimg src=\"https://img.shields.io/crates/v/coup.svg\" alt=\"crates badge\"\u003e\u003c/a\u003e\n\t\u003ca href=\"https://docs.rs/coup\"\u003e\u003cimg src=\"https://docs.rs/coup/badge.svg\" alt=\"crates docs tests\"\u003e\u003c/a\u003e\n\t\u003ca href=\"https://github.com/dominikwilkowski/coup/actions/workflows/testing.yml\"\u003e\u003cimg src=\"https://github.com/dominikwilkowski/coup/actions/workflows/testing.yml/badge.svg\" alt=\"build status\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Coup\n\nThis is a coding game where, bots you build, play the popular card game\n[COUP](https://en.wikipedia.org/wiki/Coup_(card_game)).\n\nYou write a bot to play COUP against other bots and tweak its behavior until you\nfind a winning strategy.\n\n**_This works best if you buy the physical card game and play it a couple times maybe during your lunch break_**\n\nThe idea is to have three rounds of (1,000,000) games to find the winner (sum\nall scores). Between each round you have time to make adjustments to your bot.\n\n## How does this work?\n\n- [Rules](#rules)\n- [Scoring](#scoring)\n- [How to run the game](#how-to-run-the-game)\n- [How do I build a bot](#how-do-i-build-a-bot)\n- [How does the engine work](#how-does-the-engine-work)\n- [Changelog](#changelog)\n\n## Rules\n\n1. No changes to engine\n1. Name of bots don't change between rounds (so you can target specific bots)\n1. No data sharing between games within a round\n1. No file access to other bots\n1. No changing other bots\n1. No internet access or calls to OpenAI\n1. Do not output to `stdout` or `stderr`\n\n## Scoring\n\nEach game is a zero-sum-game in terms of score.\nThat means the amount of negative points given to losers + the amount of\npositive points given to winners equals to zero.\n\nThe score is determined by the number of players (can't be more than 6 per game)\nand winners (there are instances where the game can stall in a stale-mate which\nthe engine will stop and nominate multiple winners for).\nEach game will take a max of 6 bots that are randomly elected.\nThose who win get a positive score, those who lose will get a negative score.\n\n- Score for losers: `-1/(players-1)`\n- Score for winners: `∑losers/winners`\n\n## How to run the game\n\nYou can run the game in two modes: [`play`](#play-mode) and [`loop`](#loop-mode).\n\n### Play mode\n\n\u003cp align=\"center\"\u003e\n\t\u003cimg width=\"882\" src=\"assets/play.png\"\u003e\n\u003c/p\u003e\n\nThe `play` mode will play a single game and nominate (a) winner(s) at the end.\n\n```rust\nuse coup::{\n\tbots::{HonestBot, RandomBot, StaticBot},\n\tCoup,\n};\n\nfn main() {\n\tlet mut coup_game = Coup::new(vec![\n\t\tBox::new(StaticBot),\n\t\tBox::new(StaticBot),\n\t\tBox::new(HonestBot),\n\t\tBox::new(HonestBot),\n\t\tBox::new(RandomBot),\n\t\tBox::new(RandomBot),\n\t]);\n\n\tcoup_game.play();\n}\n```\n\n### Loop mode\n\n\u003cp align=\"center\"\u003e\n\t\u003cimg width=\"680\" src=\"assets/loop.gif\"\u003e\n\u003c/p\u003e\n\nThe `loop` mode will play `n` amount of games and sum all score and nominate (a)\nwinner(s) at the end\n\n```rust\nuse coup::{\n\tbots::{HonestBot, RandomBot, StaticBot},\n\tCoup,\n};\n\nfn main() {\n\tlet mut coup_game = Coup::new(vec![\n\t\tBox::new(StaticBot),\n\t\tBox::new(StaticBot),\n\t\tBox::new(HonestBot),\n\t\tBox::new(HonestBot),\n\t\tBox::new(RandomBot),\n\t\tBox::new(RandomBot),\n\t]);\n\n\tcoup_game.looping(1_000_000);\n}\n```\n\n## How do I build a bot\n\nImplement the `BotInterface` and override the default implementations of each of\nthe methods you'd like to take control over.\nThe default implementation are the methods of the `StaticBot` which only takes\n`Income` and is forced to coup by the engine if it accumulated more or equal to\n10 coins. It does not challenge, counter or counter challenge.\n\nThe simplest way to build a bot by falling back to static behavior for each\nmethod would be:\n\n```rust\nuse coup::bot::BotInterface;\n\npub struct MyBot;\n\nimpl BotInterface for MyBot {\n\tfn get_name(\u0026self) -\u003e String {\n\t\tString::from(\"MyBot\")\n\t}\n}\n```\n\n_(This is what the `StaticBot` is.)_\n\nFrom there you can choose which, if not all, of the below methods you change to\nmake this bot your own.\n\n### Methods of the bot\n\nThe methods of `BotInterface` that will define the behavior of your bot.\n\n- `get_name` – Called only once at the instantiation of the Coup game to identify your bot\n- `on_turn` – Called when it's your turn to decide what to do\n- `on_auto_coup` – Called when you have equal to or more than 10 coins and must coup.\n- `on_challenge_action_round` – Called when another bot played an action and everyone gets to decide whether they want to challenge that action.\n- `on_counter` – Called when someone played something that can be countered with a card you may have.\n- `on_challenge_counter_round` – Called when a bot played a counter. Now everyone gets to decided whether they want to challenge that counter card.\n- `on_swapping_cards` – Called when you played your ambassador and now need to decide which cards you want to keep.\n- `on_card_loss` – Called when you lost a card and now must decide which one you want to lose\n\n### The context\n\nEach function gets `context` passed in which will contain below infos:\n\n| key            | description                                                                                                                                                                                     |\n| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `name`         | Your bots name after it was de-duped by the engine. This means if you have multiple bots with the same name they get a space and a number appended to their name which is used as an identifier |\n| `cards`        | Your cards/influences you still have                                                                                                                                                            |\n| `coins`        | Your coins                                                                                                                                                                                      |\n| `playing_bots` | A list of all playing bots this round                                                                                                                                                           |\n| `discard_pile` | A list of all discarded cards so far in the game                                                                                                                                                |\n| `history`      | A list of each event that has happened in this game so far                                                                                                                                      |\n| `score`        | The current score of the game                                                                                                                                                                   |\n\n## How does the engine work\n\nThe engine enforces all the rules laid out by the game as best as it can.\nIn areas where the rules are fuzzy or impossible to enforce in a computer world\nit does best effort to come close to the real world game.\n\n### The algorithm\n\n```\nmatch action\n\tAssassination | Stealing\n\t\t=\u003e\n\t\t\t- challenge round\n\t\t\t- counter from target\n\t\t\t- counter challenge\n\t\t\t- action\n\tCoup | Income\n\t\t=\u003e\n\t\t\t- action\n\tForeignAid\n\t\t=\u003e\n\t\t\t- counter round from everyone\n\t\t\t- counter challenge round\n\t\t\t- action\n\tSwapping | Tax\n\t\t=\u003e\n\t\t\t- challenge round\n\t\t\t- action\n```\n\n### Challenges\n\nThere are two different kind of challenges we distinguish for bots:\n- A challenge to an action\n- A challenge to a counter action\n\nBecause the rules of the game state challenges can be called by anyone (the\norder is never articulated) and because the engine can't call all bots at the\nsame time, the engine will go one by one from the bot whos action just triggered\nthe challenge.\n\nSo If player A plays an action then the first bot asked if they want to\nchallenge this is player B. If player C does the action the first bot will be\nplayer D.\n\nPerhaps best visible in [the test](https://github.com/dominikwilkowski/coup/blob/3c9fc9c1203eb8993998dc12afed323a92bcb94f/src/lib.rs#L2294-L2326).\n\n### Targeting other bots\n\nBecause some actions require you to tell the engine who you'd like to inflict\nthis action upon, the engine expects you to give it a name. This name is derived\nfrom each bots `get_name` method. The engine makes sure that there are never\nmultiple bots with the same name by adding a space and a number at the end of\nduplicate names at the instantiation of the game.\n\nSo if we have this list of bots:\n- Tici\n- Bob\n- Clara\n- Bob\n\nThe engine will change the names to:\n- Tici\n- Bob\n- Clara\n- Bob 2\n\nThese names are then communicated to you via the [context](#the-context) struct.\n\n### Auto couping\n\nThe rules state that if a player has 10 or more coins they have to coup the next\ntime it's their turn. The engine enforces this by calling the `on_auto_coup`\nmethod instead of the `on_turn` method when it's the bots turn.\n\n### Penalties\n\nThe engine will check what a bots plays is legal.\nIf a bot plays an action it can't due to insufficient funds (`couping` or\n`assassination`) it will penalize this bot by taking a card from that bot (and\nask the bot which one by calling the `on_card_loss` method).\n\nThe same happened if a bot returns an action with an invalid target (a name of a\nbot that does not exist).\n\n## Changelog\n\n### `v1.1.1`\nFixed engine to check if a target bot not just exists but also is in play.\nBefore a bot could have targeted another bot who is not playing in this round\n(where we have more than 6 bots) which could have resulted in a panic as these\nbots may not have 2 cards.\n\n### `v1.1.0`\nChallenges and counter challenges are not more fair by making sure the first bot\nbeing asked for a challenge is the bot next in line according to the bots\nposition. This way for every challenge-able action our counter action the first\nbot is different and not, as before, the first bot in this game.\n\n### `v1.0.0`\nInitial release of new rust engine\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdominikwilkowski%2Fcoup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdominikwilkowski%2Fcoup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdominikwilkowski%2Fcoup/lists"}