Skip to content

Fix frenzy stab #151

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions ffai/core/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -2397,7 +2397,7 @@ def get_pickup_teammate_actions(self, player):
positions=positions, rolls=d6_rolls))
return actions

def get_block_actions(self, player, blitz=False):
def get_block_actions(self, player, blitz=False, defender=None):

if player.state.has_blocked:
return []
Expand Down Expand Up @@ -2428,6 +2428,8 @@ def get_block_actions(self, player, blitz=False):
block_dice = []
stab_rolls = []
for player_to in self.get_adjacent_opponents(player, down=False):
if defender and not defender == player_to:
continue
block_positions.append(player_to.position)
dice = self.num_block_dice(attacker=player, defender=player_to,
blitz=blitz,
Expand All @@ -2446,7 +2448,7 @@ def get_block_actions(self, player, blitz=False):
block_dice=block_dice,
rolls=rolls))
if player.has_skill(Skill.STAB):
rolls = [roll + stab_rolls[i] for i, roll in enumerate(rolls)]
rolls = [roll + [stab_rolls[i]] for i, roll in enumerate(rolls)]
actions.append(ActionChoice(ActionType.STAB, team=player.team, positions=block_positions, rolls=rolls))

return actions
Expand Down
3 changes: 2 additions & 1 deletion ffai/core/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ def reset_turn(self):
self.used = False
self.used_skills.clear()
self.squares_moved.clear()
self.has_blocked = False


class Agent:
Expand Down Expand Up @@ -1278,4 +1279,4 @@ def compare(self, other, path):
if not formations_equal:
diff.append(f"{path}.formation: <too big to display> _NotEqual_ <too big to display>")

return diff
return diff
28 changes: 20 additions & 8 deletions ffai/core/procedure.py
Original file line number Diff line number Diff line change
Expand Up @@ -2460,7 +2460,6 @@ def step(self, action):
self.game.state.active_player = None
self.player.state.squares_moved.clear()
self.game.state.player_action_type = None
self.player.state.has_blocked = False
return True


Expand Down Expand Up @@ -2822,7 +2821,7 @@ def available_actions(self):
actions.extend(pass_actions)

# Pass actions
if self.game.has_ball(self.player):
if self.game.has_ball(self.player) and self.picked_up_teammate is None:
piece = self.game.get_ball_at(self.player.position)
pass_actions = self.game.get_pass_actions(self.player, piece, dump_off=self.dump_off)
actions.extend(pass_actions)
Expand Down Expand Up @@ -2909,6 +2908,8 @@ def __init__(self, game, player):
super().__init__(game)
self.player = player
self.can_undo = True
self.second_frenzy = False
self.defender = None

def start(self):
self.game.report(Outcome(OutcomeType.BLOCK_ACTION_STARTED, player=self.player))
Expand All @@ -2928,24 +2929,35 @@ def step(self, action):

defender = self.game.get_player_at(action.position)

EndPlayerTurn(self.game, self.player)

# Stab
if action.action_type == ActionType.STAB:
EndPlayerTurn(self.game, self.player)
Stab(self.game, self.player, defender)
return True

# Regular block
if not self.player.has_skill(Skill.FRENZY):
Block(self.game, self.player, defender)
return False

# Frenzy block
if self.player.has_skill(Skill.FRENZY):
# TODO: Second block can also be a stab
if not self.second_frenzy:
self.second_frenzy = True
self.defender = defender
Block(self.game, self.player, defender, frenzy_block=True)
return False

# Regular block
# second Frenzy block
EndPlayerTurn(self.game, self.player)
Block(self.game, self.player, defender)

return True

def available_actions(self):
if self.second_frenzy:
self.player.state.has_blocked = False
actions = self.game.get_block_actions(self.player, blitz=False, defender=self.defender)
if actions:
return actions
actions = self.game.get_block_actions(self.player, blitz=False)
actions.append(ActionChoice(ActionType.END_PLAYER_TURN, team=self.player.team))
if self.can_undo:
Expand Down
82 changes: 82 additions & 0 deletions tests/game/test_frenzy.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def test_frenzy_block():
assert attacker.position == defender_pos
defender_pos = Square(defender.position.x, defender.position.y)
assert game.state.active_player is attacker
game.step(Action(ActionType.BLOCK, position=defender.position))
game.step(Action(ActionType.SELECT_PUSH))
game.step(Action(ActionType.PUSH, position=game.get_available_actions()[0].positions[0]))
assert attacker.position == defender_pos
Expand Down Expand Up @@ -96,3 +97,84 @@ def test_frenzy_knocked_down():
game.step(Action(ActionType.PUSH, position=game.get_available_actions()[0].positions[0]))
assert attacker.position == defender_pos
assert game.state.active_player is not attacker


def test_frenzy_stab():
game = get_game_turn()
team = game.get_agent_team(game.actor)
# get a player
players = game.get_players_on_pitch(team, False, True)
attacker = None
defender = None
for p in players:
if p.team != team:
continue
attacker = p
adjacent = game.get_adjacent_opponents(attacker)
if len(adjacent) > 0:
attacker.extra_skills.append(Skill.FRENZY)
attacker.extra_skills.append(Skill.STAB)
defender = adjacent[0]
break
defender_pos = Square(defender.position.x, defender.position.y)
D6.fix(1) # fail stab
D6.fix(1) # fail stab
game.step(Action(ActionType.START_BLOCK, player=attacker))
game.step(Action(ActionType.STAB, position=defender.position))
assert attacker.state.used


def test_frenzy_stab():
game = get_game_turn()
team = game.get_agent_team(game.actor)
# get a player
players = game.get_players_on_pitch(team, False, True)
attacker = None
defender = None
for p in players:
if p.team != team:
continue
attacker = p
adjacent = game.get_adjacent_opponents(attacker)
if len(adjacent) > 0:
attacker.extra_skills.append(Skill.FRENZY)
attacker.extra_skills.append(Skill.STAB)
defender = adjacent[0]
break
defender_pos = Square(defender.position.x, defender.position.y)
D6.fix(1) # fail stab
D6.fix(1) # fail stab
game.step(Action(ActionType.START_BLOCK, player=attacker))
game.step(Action(ActionType.STAB, position=defender.position))
assert attacker.state.used


def test_frenzy_stab_second():
game = get_game_turn()
team = game.get_agent_team(game.actor)
# get a player
players = game.get_players_on_pitch(team, False, True)
attacker = None
defender = None
for p in players:
if p.team != team:
continue
attacker = p
adjacent = game.get_adjacent_opponents(attacker)
if len(adjacent) > 0:
attacker.extra_skills.append(Skill.FRENZY)
attacker.extra_skills.append(Skill.STAB)
defender = adjacent[0]
break
defender_pos = Square(defender.position.x, defender.position.y)
BBDie.fix(BBDieResult.PUSH)
BBDie.fix(BBDieResult.PUSH)
D6.fix(6) # successful stab
D6.fix(6) # successful stab
game.step(Action(ActionType.START_BLOCK, player=attacker))
game.step(Action(ActionType.BLOCK, position=defender.position))
game.step(Action(ActionType.SELECT_PUSH))
new_defender_position = game.get_available_actions()[0].positions[0]
game.step(Action(ActionType.PUSH, position=new_defender_position))
assert attacker.position == defender_pos
game.step(Action(ActionType.STAB, position=new_defender_position))
79 changes: 79 additions & 0 deletions tests/game/test_throw_team_mate.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,3 +430,82 @@ def test_ttm_distance():
squares, distances = game.get_pass_distances(passer, right_stuff)
for distance in distances:
assert distance == PassDistance.QUICK_PASS or distance == PassDistance.SHORT_PASS


def test_throw_teammate_while_having_ball():
# passer has the ball and has throw team mate
# after selecting START_PASS he should be either throw the ball or pick up
# a teammate, if he picks up the teammate he should only be allowed to
# throw the teammate.
game = get_game_turn()
team = game.get_agent_team(game.actor)
game.clear_board()
passer = team.players[0]
passer.role.skills = []
passer.role.ag = 2
passer.extra_skills = [Skill.THROW_TEAM_MATE]
game.put(passer, Square(1, 1))
ball = game.get_ball()
ball.position = passer.position
ball.is_carried = True
right_stuff = team.players[1]
right_stuff.role.skills = []
right_stuff.extra_skills = [Skill.RIGHT_STUFF]
right_stuff_position = Square(2, 1)
game.put(right_stuff, right_stuff_position)
game.step(Action(ActionType.START_PASS, player=passer))
D6.fix(6) # Accurate pass
D8.fix(5) # Forward scatter
D8.fix(5) # Forward scatter
D8.fix(5) # Forward scatter
D6.fix(6) # Land
game.step(Action(ActionType.PICKUP_TEAM_MATE, player=passer, position=right_stuff.position))
assert right_stuff.state.in_air
assert not (ActionType.PASS in [aa.action_type for aa in game.state.available_actions])
# throw teammate
target_square = Square(5, 5)
game.step(Action(ActionType.THROW_TEAM_MATE, player=passer, position=target_square))
assert game.has_report_of_type(OutcomeType.INACCURATE_PASS) # Always inaccurate
assert not game.has_report_of_type(OutcomeType.TURNOVER)
assert game.has_report_of_type(OutcomeType.SUCCESSFUL_LAND)
assert not game.has_report_of_type(OutcomeType.TURNOVER)
assert passer.state.used
assert not right_stuff.state.used
assert Square(target_square.x + 3, target_square.y)
assert right_stuff.state.up
assert ball.position == passer.position
assert ball.is_carried == True


def test_throw_ball_no_pickup():
# passer has the ball and has throw team mate
# after selecting START_PASS he should be either throw the ball or pick up
# a teammate, if he picks up the teammate he should only be allowed to
# throw the teammate.
game = get_game_turn()
team = game.get_agent_team(game.actor)
game.clear_board()
passer = team.players[0]
passer.role.skills = []
passer.role.ag = 2
passer.extra_skills = [Skill.THROW_TEAM_MATE]
game.put(passer, Square(1, 1))
ball = game.get_ball()
ball.position = passer.position
ball.is_carried = True
right_stuff = team.players[1]
right_stuff.role.skills = []
right_stuff.extra_skills = [Skill.RIGHT_STUFF]
right_stuff_position = Square(2, 1)
game.put(right_stuff, right_stuff_position)
catcher = team.players[3]
catcher.role.skills = []
catcher.role.ag = 3
game.put(catcher, Square(3, 3))
game.step(Action(ActionType.START_PASS, player=passer))
D6.fix(6) # Accurate pass
D6.fix(6) # Successful catch
game.step(Action(ActionType.PASS, player=passer, position=catcher.position))
assert not (ActionType.PICKUP_TEAM_MATE in [aa.action_type for aa in game.state.available_actions])
assert ball.position == catcher.position
assert ball.is_carried == True