Package: lasvegas
🎲 Las Vegas 🎲This package revolves aroundLas Vegas, the dice boardgame edited byRavensburgerand provides:a CLI playing mode against humans and/or (possibly custom) agents, with highly customizable rules,a simple confrontation tool for multiple agents,an agnostic game environment, for agent implementation/training.Table of contents⚙️ Getting started📜 Custom rules🎮 Game environment🤖 Agents🏆 A.I. Competition -- Leaderboard⏱ Execution time analysis⚖️ License🚧 Contributing🙏 Contributors⚙️ Getting started ⚙️0. RequirementsPython 3.10or higher is required. The package depends on the following third-party packages:numpy,tabulate,tqdm.1. Install withpippython3-mpipinstalllasvegas... or from source.From the folder of your choice --e.g.~/workspace/--, execute the following commands.gitclonehttps://github.com/eliegoudout/lasvegascdlasvegas/
python3-mpipinstall.2. Check your installationFrom your python interpreter, you should be able to import the package:importlasvegasPackage summaryNAME
    lasvegas - Las Vegas (boardgame) API package.

DESCRIPTION
    Exported Classes:
    -----------------
        BasePlayer: Contains player's name and behaviour.
        Game: Class to run games with player instances.
        GameEnv: Core mechanics of the game.
        GameRules: Class to set (eventually custom) rules.
        Human: Sub-class of `BasePlayer` destined for CLI use.  

    Exported Functions: 
    ------------------- 
        confront: Confronts different policies in a multiple-games match.   
        play_vs: Play a game in CLI.    

PACKAGE CONTENTS
    act (package)
    core (package)
    game
    interactiveRelevant package structurelasvegas/
 ├─ act/
 │   ├─ player.py
 │   │      BasePlayer
 │   │      Human
 │   ├─ policy.py
 │   │      Policy
 │   │      greedy_first
 │   │      greedy_score
 │   │      prompt_play
 │   │      random_play
 │   └─ rollicy.py
 │          Rollicy
 │          prompt_roll
 │          random_roll
 ├─ core/
 │   ├─ env.py
 │   │      GameEnv
 │   │      Play
 │   │      Roll
 │   └─ rules.py
 │          GameRules
 │          RuleBook
 ├─ game.py
 │      Game
 └─ interactive.py
        confront
        play_vs3. Start a game withplay_vsThis function creates an appropriateGameinstance and calls itsrunmethod. For example, you can quickly start a solo game,fromlasvegasimportplay_vsplay_vs()# Solo (default)or makeAliceandBobface aBot.play_vs(3,humans=["Alice","Bob"])# 3-player game with a Bot4. Quick breakdownLet's break down whatBobmight see during his turn.The SummaryRound 1/4
► Bob ▹ Alice ▹ Bot 0 ▹ ...Click for detailsThe first line is explicit. The second line lists the current player and the upcoming ones. Players with no more dice in the current round are not showed. The Ellipsis indicates a loop around.The Board StateBoard State:
╭───────────────────┬───────────┬───┬───┬───┬┬───╮
│     Score / Bills │ Owned by  │ ▿ │ ▼ │   ││ ✗ │
├───────────────────┼───────────┼───┼───┼───┼┼───┤
│             0 (0) │ Alice     │ 8 │   │   ││ 2 │
│             0 (0) │ ► Bob ◄   │   │ 8 │   ││ 2 │
│             0 (0) │ Bot 0 (*) │   │   │ 7 ││ 1 │
├───────────────────┼───────────┼───┼───┼───┼┼───┤
│             50000 │ Casino 0  │   │   │   ││   │
│             90000 │ Casino 1  │   │   │   ││   │
│             60000 │ Casino 2  │   │   │ 1 ││ 1 │
│       30000 90000 │ Casino 3  │   │   │   ││   │
│ 10000 20000 50000 │ Casino 4  │   │   │   ││   │
│             70000 │ Casino 5  │   │   │   ││   │
╰───────────────────┴───────────┴───┴───┴───┴┴───╯Click for detailsThe first column shows both the scores of the players as<total score> (<number of bills won>)and the bills to win at every casino this round.Every line shows how many dice of every type are at the corresponding player/casino. The first dice columns refer to players (same order than players lines), and the last columns refer to extra players.In the header,▼denotes the current player and▿the next one. Regarding the extra players columns, depending on whether or not they collect bills and have their own score, the header is✓or✗. The first player of the current round has thefirst player chip(*), and the current player is highlighted like► this ◄.The Roll TableJust Rolled:
╭────────┬─────────┬─────────────────────────╮
│ Scores │ Players │          Dice           │
├────────┼─────────┼─────────────────────────┤
│  0 (0) │ ► Bob ◄ │ 0 0 │ 1 1 │ 2 │ 3 3 │ 4 │
│  - (-) │ Xtr 0   │ 0   │     │ 2 │     │   │
╰────────┴─────────┴─────────────────────────╯Click for detailsThis is formatted to resemble what a player would see in real life after having sorted every dice rolled. For example, one can quickly see thatBobrolled three0s, one of which is fromXtr 0's. Since this extra player doesn't collect bills, it has no score.Live RankingsLive Rankings:
╭────────┬───────────┬─────╮
│ Scores │ Players   │  #  │
├────────┼───────────┼─────┤
│  0 (0) │ Bot 0 (*) │ 1st │
│  0 (0) │ ► Bob ◄   │ 1st │
│  0 (0) │ Alice     │ 1st │
╰────────┴───────────┴─────╯Click for detailsThis is explicit. When players are ex aequo, they are assigned the same -- best -- rank,You are now prompted to play 👇Your Play: █Good luck! 🍀📜 Custom rules 📜The rules arehighly customizablein numerous ways, let's have a quick overview -- refer tohelp(GameRules)for full documentation.1. Number of playersIt is possible to play withnum_players > 5. Since theRulebookdoesn't cover this case, it is then necessary to specify the number of extra playersnum_xtr_playersand if any, their number of dicenum_xtr_diceas well as whether or not they collect bills at the end of every round, withxtr_collect.2. Number of diceThe number of dice of regular playersnum_own_dicealways defaults to8.A fun extension of the game consists in giving players dice from other players. This can be done in an arbitrary way by directly passing astarting_dice2d-matrix, where coefficient at indexijis the number of dice of colourjthat playeristarts with. The shape of such a matrix is necessarily(num_players, num_players + num_xtr_players). Thus, if used, this keyword automatically defines those two variables.>>>play_vs(starting_dice=[[7,1,3],[2,6,3]])[...]├───────────────────┼─────────────────┼───┼───┼┼───┤│             0 (0) │ ► Human 0 (*) ◄ │ 7 │ 1 ││ 3 ││             0 (0) │ Bot 0           │ 2 │ 6 ││ 3 │├───────────────────┼─────────────────┼───┼───┼┼───┤3. Players orderIt is possible to partially or completely set the players order for the first round. By default, the order is completely randomized at game initialiazation. But you can control it in 2 ways: via the roundorder--i.e."who comes after who?" -- and thestarter--i.e."who starts the game?".Here is an example fromGameEnvdocstring:In a 5-player game,order=(3, None, 1)means that player1will be placed 2
turns after player3in the cycle, but the relative position of0,2and4is still set randomly at game initialization.In this example, it is still possible to setstarter=4for example.4. MiscellaneousIn addition, you can also modify the number offaces of dice-- which corresponds to the number of casinos --, all thebillsin the game, how much money should be at aminimum under each casinoindividually, the number ofroundsand even, insologames, how many extra players distribute their dice at the beginning of every round.As an example, you can try to win a solo game inMastermode, from theRulebook:play_vs(num_own_dice=1,solo_num_distrib=2)🎮 Game Environment 🎮From the bottom up, aGameinstance consists of:a set of rules,a core environment, built on top of rules,players with individual playing and rolling behaviours.The environment is an instance ofGameEnv.Click to show the attributes/properties of a `GameEnv` instance.Attributes:
-----------
    bills_pool (NDArray[int])        num_xtr_players (int)
    casinos_min (NDArray[int])       order (Sequence[int | None] | bool)
    max_dice (int)                   solo_num_distrib (int)
    num_casinos (int)                starter (int | bool)
    num_collectors (int)             starting_dice (NDArray[int])
    num_colours (int)                with_xtr (bool)
    num_players (int)                xtr_collect (bool)
    num_rounds

Attributes Upon Use:
--------------------
    bills (deque)                    next_step (Callable)
    casinos_bills (list[list[int]])  played (Play | None)
    current_player_index (int)       players_index_cycle (deque)
    current_round (int)              rolled (Roll | None)
    dice (NDArray[int])              round_order (deque)
    first_player_index (int)         scores (NDArray[int])
    is_over (bool | None)

Properties:
-----------
    casinos_dice [get, set] (NDArray[int])
    current_dice [get, set] (NDArray[int])🤖 Agents 🤖Anagentis simply a player -- human or not -- defined by its playing and rolling behaviours. You can instanciate one withfromlasvegasimportBasePlayerBasePlayer(name='My Agent',play_func=my_policy,roll_func=my_rollicy)1. PolicyDefinitionThe primary purpose of this package is to provide apolicyimplementation/evaluation framework. In our context, aPolicyis any such function,defmy_policy(env:GameEnv,**__:Any)->Play|None:that outputs aPlay(int) given an environment snapshot. If it outputsNone, thenGame.default_policy--i.e.random_playby default -- is called.Don't mind**__, it is only used by the game instance to pass players names when playing from CLI, for nicer display.Custom policyAs an example, here's a policy that avoids playing many dice:fromtypingimportAnyfromlasvegas.coreimportGameEnv,Playdefsaver(env:GameEnv,**__:Any)->Play:""" Plays the least dice possible. """returnmin(env.legal_plays(),key=lambdaplay:sum(sub_roll.get(play,0)forsub_rollinenv.rolled))2. RollicyYou can also define acustom rolling behaviourfor your agent. This allows to simulate biased dice or, for example,  to manually enter rolls in CLI with the implemented rollicyprompt_roll:>>>fromlasvegas.actimportBasePlayer,prompt_play,prompt_roll>>>my_player=BasePlayer("Alice",play_func=prompt_play,roll_func=prompt_roll)which is equivalent to the simpler>>>fromlasvegasimportHuman>>>my_player=Human("Alice",manual_roll=True)Note: In solo games, the action of distributing one bot's dice at the beginning of every round is seen as an environment action. As such, the dice throw usesrandom_rolland not the player'sRollicy.🏆 A.I. Competition -- Leaderboard 🏆1. BenchmarkingThe package comes with a simple benchmarking function,confront, which runs multiple games between given policies and sums up the results.For example, let's see how our previously defined policy,saver, does against package-embeddedgreedy_first:>>>fromlasvegasimportconfront>>>confront(saver,greedy_first)Match in 100 games:╭────────────────────────┬─────┬──────────────┬─────┬──────────────╮│ Policy                 │ 1st │ with         │ 2nd │ with         │├────────────────────────┼─────┼──────────────┼─────┼──────────────┤│ Policy 0: saver        │  17 │ 477059 (8.6) │  83 │ 334096 (6.4) ││ Policy 1: greedy_first │  83 │ 532289 (8.7) │  17 │ 401176 (6.8) │╰────────────────────────┴─────┴──────────────┴─────┴──────────────╯2. Competition 🥇🥈🥉If you are interested in defining one or more competition formats, leaderboards will be held and updated here! This is your chance to leave your mark for posterity while improving your AI skills and potentially helping the community. 🤗⏱ Execution time analysis ⏱From sources, in the root folder, you can measure the time it takes for games to be played using the light embededperfpackage:From CLI:python3 -m perf [<num_games>]for default uniformly random policy,From python interpreter: by importingperfas a package and using themainfunction. This allows you to specify the tested policy and custom game settings.Output should look like this:$python3-mperfGame time for policy 'None' (over 100 games):╭─────────────┬──────────┬──────────┬──────────┬──────────╮│ Num players │ Mean     │ Std      │ Min      │ Max      │├─────────────┼──────────┼──────────┼──────────┼──────────┤│           1 │ 5.530 ms │ 522.1 us │ 4.876 ms │ 7.929 ms ││           2 │ 1.627 ms │ 196.1 us │ 1.391 ms │ 2.626 ms ││           3 │ 2.013 ms │ 168.7 us │ 1.698 ms │ 2.873 ms ││           4 │ 2.615 ms │ 207.4 us │ 2.309 ms │ 3.758 ms ││           5 │ 2.723 ms │ 225.8 us │ 2.450 ms │ 3.794 ms │╰─────────────┴──────────┴──────────┴──────────┴──────────╯Note: Dependencies should be installed.⚖️ License ⚖️This package is distributed under theMIT License.🚧 Contributing 🚧Questions,issues,discussionsandpull requestsare welcome! Please do not hesitate tocontact me.🙏 Contributors 🙏Élie Goudout, Csongor Pilinszki-Nagy.