Kuh-Handel: Documentation

technical specifications and implementation guide for Rust and Python

This page provides an overview of how to build your bot for kuh-handel. You can find the full Rust documentation here:

This tutorial is available for Rust and Python:

Get your bot done while the others are still oxidizing.

Your bot will be blazingly fast.

Setup

Register Bots

You want to join the competition

curl -X POST "https://ufuk-guenes.com/kuh-handel/register?player_id=<your_bot_name>&token=<your_token>"

Setup environment

We will first create a virtual environment and install the newest version of pyhandel

python -m venv .venv
source .venv/bin/activate
pip install pyhandel

if you already have an older version of the package and need to update:

pip install --upgrade pyhandel pyhandel-stubs

blazingly fast rust example

fn greet(name: &str) {
      println!("Hello, {}!", name);
    }


Simple layout

Below you can find a template from which you can start implementing your own bot

import asyncio
import random as rn
from pyhandel import Value, Money, Points
from pyhandel.animals import Animal, AnimalSet
from pyhandel.client import Client
from pyhandel.messages.actions import (
    AuctionDecision,
    Bidding,
    InitialTrade,
    NoAction,
    PlayerTurnDecision,
    SendMoney,
    TradeOpponentDecision,
)
from pyhandel.messages.game_updates import (
    AuctionRound,
    GameUpdate,
    TradeOffer,
    AuctionKind,
    MoneyTrade,
    MoneyTransfer,
)
from pyhandel.player import PlayerId
from pyhandel.player.player_actions import PlayerActions
from pyhandel.player.wallet import Wallet


class Bot(PlayerActions):

    def setup():
        # the __init__ can not take any arguments,
        # setup your class with a separate function
        raise NotImplementedError

    def _draw_or_trade(self) -> PlayerTurnDecision:
        raise NotImplementedError

    def _trade(self) -> InitialTrade:
        raise NotImplementedError

    def _provide_bidding(self, state: AuctionRound) -> Bidding:
        raise NotImplementedError

    def _buy_or_sell(self, state: AuctionRound) -> AuctionDecision:
        raise NotImplementedError

    def _send_money_to_player(self, player: str, amount: int) -> SendMoney:
        raise NotImplementedError

    def _respond_to_trade(self, offer: TradeOffer) -> TradeOpponentDecision:
        raise NotImplementedError

    def _receive_game_update(self, update: GameUpdate) -> NoAction:
        raise NotImplementedError

async def run(client, num_rounds):
    for _ in range(num_rounds):
        await client.play_one_round("game") 

if __name__ == "__main__":
    bot_name = "your_bot_name"
    bot_token = "your_private_token"
    base_url = "s://ufuk-guenes.com"  # "://127.0.0.1:2000" 
    play_n_rounds = 1


    bot = Bot()
    bot.setup()
    client = Client(bot_name, bot_token, bot, base_url)

    try:
        asyncio.run(run(client, play_n_rounds))
    except KeyboardInterrupt:
        print("Client shutdown")
    except Exception as e:
        print("Error: ", e)

blazingly fast rust example

fn greet(name: &str) {
      println!("Hello, {}!", name);
    }


More explanations

Below you can find in depth descriptions of the methods to implement

class Bot(PlayerActions):

    def _draw_or_trade(self) -> PlayerTurnDecision:
        if rn.random() < 0.5:
            return PlayerTurnDecision.Trade(self._trade())
        return PlayerTurnDecision.Draw()

    def _trade(self) -> InitialTrade:
        player = self.state.players[0]
        animal = self.state.animals[0]
        trade = InitialTrade(player, animal, 1, [0])
        print(trade.amount)
        return trade
    
    def _provide_bidding(self, state: AuctionRound) -> Bidding:
        host = state.host
        animal = state.animal
        bids = state.bids
        
        if rn.random() < 0.5:
            return Bidding.Bid(rn.randint(1, 100))
        return Bidding.Pass()
    
    def _buy_or_sell(self, state: AuctionRound) -> AuctionDecision: 
        host = state.host
        animal = state.animal
        bids = state.bids

        if rn.random() < 0.5:
            return AuctionDecision.Buy()
        return AuctionDecision.Sell()

    def _send_money_to_player(self, player: PlayerId, amount: Value) -> SendMoney: 
        if rn.random() < 0.05:
            return SendMoney.WasBluff()
        return SendMoney.Amount([0, 0])

    def _respond_to_trade(self, offer: TradeOffer) -> TradeOpponentDecision: 
        challenger = offer.challenger
        animal = offer.animal
        count = offer.animal_count
        card_offer = offer.challenger_card_offer

        if rn.random() < 0.5:
            return TradeOpponentDecision.Accept()
        return TradeOpponentDecision.CounterOffer([10, 0])
    
    def _receive_game_update(self, update):
        match update:
            case GameUpdate.Auction(kind):
                self.handle_auction(kind)
            case GameUpdate.End(ranking):
                self.handle_end(ranking)
            case GameUpdate.Start(wallet, player_order, animals):
                self.handle_start(wallet, player_order, animals)
            case GameUpdate.ExposePlayer(player, wallet):
                self.handle_expose_player(player, wallet)
            case GameUpdate.Inflation(money):
                self.handle_inflation(money)
            case GameUpdate.Trade(challenger, opponent, animal, animal_count, receiver, money_trade):
                self.handle_trade(challenger, opponent, animal, animal_count, receiver, money_trade)
        return NoAction.Ok()
    
    def handle_auction(self, kind: AuctionKind):
        match kind:
            case AuctionKind.NoBiddings(host, animal):
                pass
            case AuctionKind.NormalAuction(rounds, from_player, to_player, money_transfer):
                match money_transfer:
                    case MoneyTransfer.Public(card_amount, min_value):
                        pass
        raise NotImplementedError()
        
    def handle_end(self, ranking: list[tuple[PlayerId, Points]]):
        raise NotImplementedError()
    
    def handle_start(self, wallet: Wallet, player_order: list[PlayerId], animals: list[AnimalSet]):
        notes = wallet.bank_notes
        first_animal = animals[0]
        inflation = first_animal.inflation
        animal_value = first_animal.animal
        raise NotImplementedError()

    def handle_trade(self, challenger: PlayerId, opponent: PlayerId, animal: Animal, animal_count: int, receiver: PlayerId, money_trade: MoneyTrade):
        match money_trade:
            case MoneyTrade.Public(challenger_offer, opponent_offer):
                pass
            case MoneyTrade.Private(challenger_offer, opponent_offer):
                pass
        raise NotImplementedError()

    def handle_expose_player(self, player: PlayerId, wallet: Wallet):
        raise NotImplementedError()
    
    def handle_inflation(self, money: Money):
        raise NotImplementedError()


blazingly fast rust example

fn greet(name: &str) {
      println!("Hello, {}!", name);
    }