Skip to content
The Fantasy Football AI framework
JavaScript Python HTML CSS
Branch: master
Clone or download

FFAI: Fantasy Football AI

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.

  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},


  • 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
  • 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
    • Path finding utilities
    • Examples to get started
  • 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
    • Time management
    • ...
  • Premade formations to ease the setup phase. Custom made formations can easily be implemented.
  • Games can be saved and loaded

Plans for Future Releases

  • 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+

Run FFAI's Web Server

python examples/

Go to:

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.

Create a Bot

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

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.

Gym Interface

FFAI implements the Open AI Gym interace for easy integration of machine learning algorithms.

Take a look at our



Observations are split in three parts:

  1. 'board': two-dimensional feature leayers
  2. 'state': a vector of normalized values (e.g. turn number, half, scores etc.) describing the game state
  3. '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.

Observation: 'board'

The default feature layers in obs['board'] are:

  1. OccupiedLayer()
  2. OwnPlayerLayer()
  3. OppPlayerLayer()
  4. OwnTackleZoneLayer()
  5. OppTackleZoneLayer()
  6. UpLayer()
  7. StunnedLayer()
  8. UsedLayer()
  9. AvailablePlayerLayer()
  10. AvailablePositionLayer()
  11. RollProbabilityLayer()
  12. BlockDiceLayer()
  13. ActivePlayerLayer()
  14. TargetPlayerLayer()
  15. MALayer()
  16. STLayer()
  17. AGLayer()
  18. AVLayer()
  19. MovemenLeftLayer()
  20. BallLayer()
  21. OwnHalfLayer()
  22. OwnTouchdownLayer()
  23. OppTouchdownLayer()
  24. SkillLayer(Skill.BLOCK)
  25. SkillLayer(Skill.DODGE)
  26. SkillLayer(Skill.SURE_HANDS)
  27. SkillLayer(Skill.CATCH)
  28. SkillLayer(Skill.PASS)

Custom layers can be implemented like this:

from 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:


To visualize the feature layers, use the feature_layers option when calling render:


FFAI Gym Feature Layers

Observation: 'state'

The 50 default normalized values in obs['state'] are:

  1. 'half'
  2. 'round'
  3. 'is sweltering heat'
  4. 'is very sunny'
  5. 'is nice'
  6. 'is pouring rain'
  7. 'is blizzard'
  8. 'is own turn'
  9. 'is kicking first half'
  10. 'is kicking this drive'
  11. 'own reserves'
  12. 'own kods'
  13. 'own casualites'
  14. 'opp reserves'
  15. 'opp kods'
  16. 'opp casualties'
  17. 'own score'
  18. 'own turns'
  19. 'own starting rerolls'
  20. 'own rerolls left'
  21. 'own ass coaches'
  22. 'own cheerleaders'
  23. 'own bribes'
  24. 'own babes'
  25. 'own apothecary available'
  26. 'own reroll available'
  27. 'own fame'
  28. 'opp score'
  29. 'opp turns'
  30. 'opp starting rerolls'
  31. 'opp rerolls left'
  32. 'opp ass coaches'
  33. 'opp cheerleaders'
  34. 'opp bribes'
  35. 'opp babes'
  36. 'opp apothecary available'
  37. 'opp reroll available'
  38. 'opp fame'
  39. 'is blitz available'
  40. 'is pass available'
  41. 'is handoff available'
  42. 'is foul available'
  43. 'is blitz'
  44. 'is quick snap'
  45. 'is move action'
  46. 'is block action'
  47. 'is blitz action'
  48. 'is pass action'
  49. 'is handoff action'
  50. 'is foul action'

Observation: 'procedure'

The 19 procedures represented in the one-hot vector obs['procedure'] are:

  1. StartGame
  2. CoinTossFlip
  3. CoinTossKickReceive
  4. Setup
  5. PlaceBall
  6. HighKick
  7. Touchback
  8. Turn
  9. PlayerAction
  10. Block
  11. Push
  12. FollowUp
  13. Apothecary
  14. PassAction
  15. Catch
  16. Interception
  17. GFI
  18. Dodge
  19. Pickup

Action Types

Actions consists of 31 action types. Some action types, denoted by <position> also requires an x and y-coordinate.

  1. ActionType.START_GAME
  2. ActionType.HEADS
  3. ActionType.TAILS
  4. ActionType.KICK
  5. ActionType.RECEIVE
  6. ActionType.END_PLAYER_TURN
  7. ActionType.USE_REROLL
  8. ActionType.DONT_USE_REROLL
  9. ActionType.END_TURN
  10. ActionType.STAND_UP
  12. ActionType.SELECT_BOTH_DOWN
  13. ActionType.SELECT_PUSH
  16. ActionType.SELECT_NONE
  17. ActionType.PLACE_PLAYER<Position> (Only used during high-kick)
  18. ActionType.PLACE_BALL<Position>
  19. ActionType.PUSH<Position>
  20. ActionType.FOLLOW_UP<Position>
  21. ActionType.INTERCEPTION<Position> (position of the player)
  22. ActionType.SELECT_PLAYER<Position> (position of the player)
  23. ActionType.MOVE<Position>
  24. ActionType.BLOCK<Position>
  25. ActionType.PASS<Position>
  26. ActionType.FOUL<Position>
  27. ActionType.HANDOFF<Position>
  28. ActionType.START_MOVE<Position> (position of the player)
  29. ActionType.START_BLOCK<Position> (position of the player)
  30. ActionType.START_BLITZ<Position> (position of the player)
  31. ActionType.START_PASS<Position> (position of the player)
  32. ActionType.START_FOUL<Position> (position of the player)
  33. ActionType.START_HANDOFF<Position> (position of the player)

Actions are instantiated and used like this:

action = {
    'action-type': 26,
    'x': 8,
    'y': 6
obs, reward, done, info = env.step(action)

Rewards and Info

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 five 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
  • FFAI-v1-1: 1 player on a 4x3 pitch

This is how the FFAI-v1-3 environment looks:


Disclaminers and Copyrighted Art

FFAI is not affiliated with or endorsed 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.

Get Involved

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.

You can’t perform that action at this time.