A highly-extensible python-based AI framework for digital fantasy-football board-games. FFAI is still under development and is planned to be heavily updated.
Please cite us if you use FFAI in your publications.
@inproceedings{justesen2018blood,
title={Blood Bowl: The Next Board Game Challenge for AI},
author={Justesen, Niels and Risi, Sebastian and Togelius, Julian},
booktitle={FDG 2018, 1st Workshop on Tabletop Games},
year={2018}
}
- Rule implementation of the Living Rulebook 5 with the following limitations:
- Only skills for the Human and Orc teams have been implemented and tested
- No big guys
- No league or tournament play
- No star player points or level up
- No inducements
- No timers; Players have unlimited time each turn
- A web interface supporting:
- Hot-seat
- Online play
- Spectators
- Human vs. bot
- An AI interface that allows you to implement and test your own bots
- Implementation of the Open AI Gym interface, that allows you to train machine learning algorithms
- Custom pitches (we call these arenas). FFAI comes with arenas of four different sizes.
- Rule configurations are possible from a configuration file, including:
- Arena (which .txt file to load describing the arena)
- Ruleset (which .xml file to load containing rules for rosters etc.)
- Setup restrictions
- Number of turns
- Kick-off table enabled/disabled
- Which scatter dice to use
- ...
- Premade formations to ease the setup phase. Custom made formations can easily be implemented.
- Games can be saved and loaded
- More documentation
- AI tournament module
- Support for dungeon arenas
- Support for all skills and teams in LRB6
- League mode
- Integration with OBBLM
Make sure python 3.6 or newer is installed, together with pip.
pip install git+https://github.com/njustesen/ffai
python -m ffai.web.server
Go to: http://127.0.0.1:5000/
The main page lists active games. For each active game you can click on a team to play it. If a team is disabled it is controlled by a bot and cannot be selected. Click hot-seat to play human vs. human on the same machine.
To make you own bot you must implement the Agent class and its three methods: new_game, act, and end_game which are called by the framework. The act method must return an instance of the Action class.
Take a look at our bot_example.py.
Be aware, that you shouldn't modify instances that comes from the framework such as Square instances as these are shared with the GameState instance in FFAI. In future releases, we plan to release an AI tournament module that will clone the instances before they are handed to the bots. For now, this is up to the user to do.
FFAI implements the Open AI Gym interace for easy integration of machine learning algorithms.
Take a look at our gym_example.py.
Observations are split in three parts:
- 'board': two-dimensional feature leayers
- 'state': a vector of normalized values (e.g. turn number, half, scores etc.) describing the game state
- 'procedure' a one-hot vector describing which of 18 procedures the game is in. The game engine is structered as a stack of procedures. The top-most procedure in the stack is active.
The default feature layers in obs['board'] are:
- OccupiedLayer()
- OwnPlayerLayer()
- OppPlayerLayer()
- OwnTackleZoneLayer()
- OppTackleZoneLayer()
- UpLayer()
- UsedLayer()
- AvailablePlayerLayer()
- AvailablePositionLayer()
- RollProbabilityLayer()
- BlockDiceLayer()
- ActivePlayerLayer()
- MALayer()
- STLayer()
- AGLayer()
- AVLayer()
- MovemenLeftLayer()
- BallLayer()
- OwnHalfLayer()
- OwnTouchdownLayer()
- OppTouchdownLayer()
- SkillLayer(Skill.BLOCK)
- SkillLayer(Skill.DODGE)
- SkillLayer(Skill.SURE_HANDS)
- SkillLayer(Skill.PASS)
- SkillLayer(Skill.BLOCK)
Custom layers can be implemented like this:
from ffai.ai import FeatureLayer
class MyCustomLayer(FeatureLayer):
def produce(self, game):
out = np.zeros((game.arena.height, game.arena.width))
for y in range(len(game.state.pitch.board)):
for x in range(len(game.state.pitch.board[0])):
player = game.state.pitch.board[y][x]
out[y][x] = 1.0 if player is not None and player.role.cost > 80000 else 0.0
return out
def name(self):
return "expensive players"
and added to the environment's feature layers:
env.layers.append(MyCustomLayer())
To visualize the feature layers, use the feature_layers option when calling render:
env.render(feature_layers=True)
The 44 default normalized values in obs['state'] are:
- 'half'
- 'round'
- 'sweltering heat'
- 'very sunny'
- 'nice'
- 'pouring rain'
- 'blizzard'
- 'own turn'
- 'kicking first half'
- 'kicking this drive'
- 'own reserves'
- 'own kods'
- 'own casualites'
- 'opp reserves'
- 'opp kods'
- 'opp casualties'
- 'own score'
- 'own turns'
- 'own starting rerolls'
- 'own rerolls left'
- 'own ass coaches'
- 'own cheerleaders'
- 'own bribes'
- 'own babes'
- 'own apothecary available'
- 'own reroll available'
- 'own fame'
- 'opp score'
- 'opp turns'
- 'opp starting rerolls'
- 'opp rerolls left'
- 'opp ass coaches'
- 'opp cheerleaders'
- 'opp bribes'
- 'opp babes'
- 'opp apothecary available'
- 'opp reroll available'
- 'opp fame'
- 'blitz available'
- 'pass available'
- 'handoff available'
- 'foul available'
- 'is blitz'
- 'is quick snap'
The 19 procedures represented in the one-hot vector obs['procedure'] are:
- StartGame
- CoinTossFlip
- CoinTossKickReceive
- Setup
- PlaceBall
- HighKick
- Touchback
- Turn
- PlayerAction
- Block
- Push
- FollowUp
- Apothecary
- PassAction
- Catch
- Interception
- GFI
- Dodge
- Pickup
Actions consists of 31 action types. Some action types, denoted by also requires an x and y-coordinate.
- ActionType.START_GAME
- ActionType.HEADS
- ActionType.TAILS
- ActionType.KICK
- ActionType.RECEIVE
- ActionType.END_SETUP
- ActionType.END_PLAYER_TURN
- ActionType.USE_REROLL
- ActionType.DONT_USE_REROLL
- ActionType.END_TURN
- ActionType.STAND_UP
- ActionType.SELECT_ATTACKER_DOWN
- ActionType.SELECT_BOTH_DOWN
- ActionType.SELECT_PUSH
- ActionType.SELECT_DEFENDER_STUMBLES
- ActionType.SELECT_DEFENDER_DOWN
- ActionType.SELECT_NONE
- ActionType.PLACE_PLAYER
- ActionType.PLACE_BALL
- ActionType.PUSH
- ActionType.FOLLOW_UP
- ActionType.INTERCEPTION
- ActionType.SELECT_PLAYER
- ActionType.MOVE
- ActionType.BLOCK
- ActionType.PASS
- ActionType.FOUL
- ActionType.HANDOFF
- ActionType.SETUP_FORMATION_WEDGE
- ActionType.SETUP_FORMATION_LINE
- ActionType.SETUP_FORMATION_SPREAD
- ActionType.SETUP_FORMATION_ZONE
Actions are instantiated and used like this:
action = {
'action-type': 26,
'x': 8,
'y': 6
}
obs, reward, done, info = env.step(action)
The default reward function only rewards for a win, draw or loss 1/0/-1. However, the info object returned by the step function contains useful information for reward shaping:
'cas_inflicted': {int},
'opp_cas_inflicted': {int},
'touchdowns': {int},
'opp_touchdowns': {int},
'half': {int},
'round': {int}
These values are commulative, such that 'cas_inflicted' referes to the total number of casualties inflicted by the team.
FFAI comes with four environments with various difficulty:
- FFAI-v1: 11 players on a 26x15 pitch (traditional size)
- FFAI-v1-7: 7 players on a 20x11 pitch
- FFAI-v1-5: 5 players on a 16x8 pitch
- FFAI-v1-3: 3 players on a 12x5 pitch
This is how the FFAI-v1-3 environment looks:
FFAI is not affiliated with or endoresed by any company and/or trademark. FFAI is an open research framework and the authors have no commercial interests in this project. The web interface in FFAI currently uses a small set of icons from the Fantasy Football Client. These icons are not included in the license of FFAI. If you are the author of these icons and don't want us to use them in this project, please contact us at njustesen at gmail dot com, and we will replace them ASAP.
Do you want implement a bot for FFAI or perhaps help us test, develop, and/or organize AI competitions? Join our Discord server using this link: FFAI Discord Server.