Refactoring gameplay AI / Automate subs

This commit is contained in:
Cal Corum 2024-05-19 02:12:35 -05:00
parent cb6319cf29
commit f7934d464f
11 changed files with 1841 additions and 1378 deletions

View File

@ -7,6 +7,7 @@ from db_calls import *
from discord import Member
from discord.ext import commands, tasks
from discord import app_commands
import in_game
# date = f'{datetime.datetime.now().year}-{datetime.datetime.now().month}-{datetime.datetime.now().day}'
# logging.basicConfig(
@ -461,9 +462,16 @@ class Admins(commands.Cog):
@app_commands.command(name='reset-cache', description='Reset all cached player cards for gameplay')
@app_commands.checks.has_any_role('Da Commish')
async def reset_cache_command(self, interaction: discord.Interaction):
async def reset_cache_command(
self, interaction: discord.Interaction, player_cache: Optional[bool] = True,
batting_cache: Optional[bool] = True, pitching_cache: Optional[bool] = True):
await interaction.response.defer()
db_calls.PLAYER_CACHE = {}
if player_cache:
in_game.data_cache.PLAYER_CACHE = {}
if batting_cache:
in_game.data_cache.BATTINGCARD_CACHE = {}
if pitching_cache:
in_game.data_cache.PITCHINGCARD_CACHE = {}
await interaction.edit_original_response(
content=random_gif(random_from_list(['all done', 'yes sir', 'complete']))
)
@ -475,6 +483,24 @@ class Admins(commands.Cog):
await db_post('paperdex/wipe-ai', timeout=15)
await ctx.send(f'All done!')
@commands.command(name='get-bc', help='Mod: Test batting card cache')
@commands.is_owner()
async def get_battingcard_command(self, ctx, player_id: int):
await ctx.channel.send(f'Pulling the batting card for player ID: {player_id}')
this_data = None
async with ctx.channel.typing():
this_data = await in_game.data_cache.get_pd_battingcard(player_id)
await ctx.channel.send(f'Dumping data here:\n\n{this_data}')
@commands.command(name='get-pc', help='Mod: Test pitching card cache')
@commands.is_owner()
async def get_battingcard_command(self, ctx, player_id: int):
await ctx.channel.send(f'Pulling the pitching card for player ID: {player_id}')
this_data = None
async with ctx.channel.typing():
this_data = await in_game.data_cache.get_pd_pitchingcard(player_id)
await ctx.channel.send(f'Dumping data here:\n\n{this_data}')
async def setup(bot):
await bot.add_cog(Admins(bot))

View File

@ -231,7 +231,8 @@ class Economy(commands.Cog):
this_embed.add_field(
name=p_list[player]['field_name'], value=p_list[player]['message'], inline=False)
await send_to_channel(self.bot, topics[topic]['channel_name'], embed=embed)
if len(p_list) > 0:
await send_to_channel(self.bot, topics[topic]['channel_name'], embed=this_embed)
@notif_check.before_loop
async def before_notif_check(self):

View File

@ -1,11 +1,10 @@
import asyncio
import logging
import discord
import math
import copy
import os
import ai_manager
import discord
from in_game import ai_manager
import dice
import gauntlets
@ -13,23 +12,24 @@ from discord import app_commands
from discord.app_commands import Choice
from discord.ext import commands, tasks
from peewee import IntegrityError
from typing import Optional, Literal
from typing import Literal, Optional
from dice import sa_fielding_roll
from helpers import SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME, random_conf_gif, SBA_SEASON, PD_SEASON, IMAGES, \
get_team_embed, Confirm, get_pos_abbrev, SBA_COLOR, get_roster_lineups, Question, give_packs, send_to_channel, \
get_channel, get_or_create_role, team_role, get_cal_user, get_card_embeds, ButtonOptions, get_ratings_guide, \
get_team_by_owner, get_roster_sheet, get_role, player_desc, player_pcard, player_bcard
from gameplay_helpers import *
get_pos_abbrev, SBA_COLOR, get_roster_lineups, give_packs, send_to_channel, \
get_channel, team_role, get_cal_user, ButtonOptions, get_ratings_guide, \
get_team_by_owner, player_desc, player_pcard, player_bcard, get_team_embed, Confirm, get_sheets
from in_game.ai_manager import check_pitching_sub
from in_game.game_helpers import single_onestar, single_wellhit, double_twostar, double_threestar, triple, \
runner_on_first, runner_on_second, runner_on_third, gb_result_1, gb_result_2, gb_result_3, gb_result_4, \
gb_result_5, gb_result_6, gb_result_7, gb_result_8, gb_result_9, gb_result_10, gb_result_11, gb_result_12, \
gb_result_13, gb_decide, show_outfield_cards, legal_check, get_pitcher
from db_calls import db_get, db_patch, db_post, db_delete, get_team_by_abbrev
from db_calls_gameplay import StratGame, StratPlay, StratLineup, StratManagerAi, get_sba_team, get_sba_player, \
post_game, patch_game, get_game_team, post_lineups, make_sub, get_player, player_link, get_team_lineups, \
from db_calls_gameplay import StratGame, StratPlay, post_game, patch_game, get_game_team, post_lineups, make_sub, get_player, player_link, get_team_lineups, \
get_current_play, post_play, get_one_lineup, advance_runners, patch_play, complete_play, get_batting_stats, \
get_pitching_stats, undo_play, get_latest_play, advance_one_runner, count_team_games, \
get_fielding_stats, get_pitching_decisions, get_or_create_bullpen, get_active_games, patch_lineup, \
get_last_game_ids, get_plays, get_manager, get_one_game, load_ai, ai_batting, undo_subs, get_dbready_plays, \
convert_stratlineup
get_pitching_decisions, get_or_create_bullpen, get_active_games, patch_lineup, \
get_plays, get_manager, get_one_game, load_ai, ai_batting, undo_subs, get_dbready_plays
class Gameplay(commands.Cog):
@ -349,7 +349,7 @@ class Gameplay(commands.Cog):
return game_state
async def get_game_state_embed(self, game: StratGame, full_length=True, for_liveboard=False):
async def initialize_play_plus_embed(self, game: StratGame, full_length=True, for_liveboard=False):
game_state = await self.get_game_state(game)
logging.debug(f'game_state: {game_state}')
@ -366,25 +366,11 @@ class Gameplay(commands.Cog):
elif 'flashback' in game.game_type:
gt_string = ' - Flashback'
embed = discord.Embed(
title=f'{game_state["away_team"]["sname"]} @ {game_state["home_team"]["sname"]}{gt_string}',
color=int(SBA_COLOR, 16)
)
logging.debug(f'got embed')
if game.is_pd:
footer_text = f'Paper Dynasty Season {PD_SEASON}'
if game.short_game:
footer_text += f' - Reminder: all pitchers have POW(1) in 3-inning games'
embed.set_footer(text=footer_text, icon_url=IMAGES['logo'])
else:
embed.set_footer(text=f'SBa Season {SBA_SEASON}', icon_url=IMAGES['logo'])
if game_state['error']:
# embed = discord.Embed(
# title='Current Lineups',
# color=int(SBA_COLOR, 16)
# )
embed = discord.Embed(
title='Current Lineups',
color=int(SBA_COLOR, 16)
)
embed.add_field(name='Away Team',
value=game_state['away_lineup'] if game_state['away_lineup'] else 'None, yet')
embed.add_field(name='Home Team',
@ -395,19 +381,64 @@ class Gameplay(commands.Cog):
return embed
logging.debug(f'no errors')
embed.add_field(name='Game State', value=game_state['scorebug'], inline=False)
pitching_sub = None
ai_note = ''
gm_name = ''
fatigue = await ai_manager.is_pitcher_fatigued(game_state['curr_play'])
logging.debug(f'do AI stuff')
# If an AI team is playing
if True in [game_state['pitcher']['team']['is_ai'], game_state['batter']['team']['is_ai']]:
logging.debug(f'Checking AI stuff')
logging.debug(f'check mercy')
# AI Team is pitching
if game_state['pitcher']['team']['is_ai']:
if fatigue:
pitching_sub = await check_pitching_sub(game_state['curr_play'], game_state['pitcher']['team'])
if pitching_sub is not None:
game_state = await self.get_game_state(game)
ai_data = await ai_manager.pitching_ai_note(game_state['curr_play'], game_state['pitcher'])
logging.debug(f'ai_data: {ai_data}')
ai_note = ai_data['note']
gm_name = ai_data['gm_name']
# AI Team is batting
if game_state['batter']['team']['is_ai']:
# embed.set_thumbnail(url=player_pcard(game_state["pitcher"]))
ai_data = ai_manager.batting_ai_note(game_state['curr_play'], game_state['batter'])
ai_note = ai_data['note']
gm_name = ai_data['gm_name']
if pitching_sub is not None or (fatigue and pitching_sub is None) or abs(
game_state['curr_play'].home_score - game_state['curr_play'].away_score) >= 10:
color = discord.Colour.red()
else:
color = int(SBA_COLOR, 16)
embed = discord.Embed(
title=f'{game_state["away_team"]["sname"]} @ {game_state["home_team"]["sname"]}{gt_string}',
color=color
)
logging.info(f'got embed')
footer_text = f'Paper Dynasty Season {PD_SEASON}'
if game.short_game:
footer_text += f' - Reminder: all pitchers have POW(1) in 3-inning games'
embed.set_footer(text=footer_text, icon_url=IMAGES['logo'])
embed.add_field(name='Game State', value=game_state['scorebug'], inline=False)
embed.set_thumbnail(url=player_pcard(game_state['pitcher']))
logging.info(f'check mercy')
if abs(game_state['curr_play'].home_score - game_state['curr_play'].away_score) >= 10:
embed.description = '***Mercy rule in effect***'
# embed.color = discord.Colour.red()
logging.debug(f'set pitcher string')
logging.info(f'set pitcher string')
pitcher_string = f'{player_link(game, game_state["pitcher"])}'
batter_string = f'{game_state["curr_play"].batter.batting_order}. {player_link(game, game_state["batter"])} - ' \
f'{game_state["curr_play"].batter.position}'
logging.debug(f'pull bat stats')
logging.info(f'pull bat stats')
all_bat_stats = get_batting_stats(game.id, lineup_id=game_state['curr_play'].batter.id)
if len(all_bat_stats):
b_s = all_bat_stats[0]
@ -420,7 +451,7 @@ class Gameplay(commands.Cog):
if num:
batter_string += f', {num if num > 1 else ""}{" " if num > 1 else ""}{stat}'
logging.debug(f'pull pitcher stats')
logging.info(f'pull pitcher stats')
all_pit_stats = get_pitching_stats(game.id, lineup_id=game_state['curr_play'].pitcher.id)
if len(all_pit_stats):
p_s = all_pit_stats[0]
@ -433,16 +464,15 @@ class Gameplay(commands.Cog):
pitcher_string += f', {num} {stat}'
if stat == 'R' and num != p_s['pl_eruns']:
pitcher_string += f', {p_s["pl_eruns"]} ER'
if game.short_game and p_s["pl_outs"] >= 3:
pitcher_string += f'\n***F A T I G U E D***'
if fatigue and pitching_sub is None:
pitcher_string += f'\n***F A T I G U E D***'
logging.debug(f'set embed pitcher/batter')
# embed.add_field(name='Matchup', value=f'Pitcher: \nvs\nBatter: ', inline=False)
logging.info(f'set embed pitcher/batter')
embed.add_field(name='Pitcher', value=f'{pitcher_string}')
embed.add_field(name='Batter', value=f'{batter_string}')
embed.set_image(url=player_bcard(game_state['batter']))
logging.debug(f'get baserunners')
logging.info(f'get baserunners')
baserunner_string = ''
if game_state['curr_play'].on_first:
runner = await get_player(game, game_state['curr_play'].on_first)
@ -454,7 +484,7 @@ class Gameplay(commands.Cog):
runner = await get_player(game, game_state['curr_play'].on_third)
baserunner_string += f'On Third: {player_link(game, runner)}\n'
logging.debug(f'set baserunners')
logging.info(f'set baserunners')
if len(baserunner_string) > 0:
embed.add_field(name=' ', value=' ', inline=False)
embed.add_field(
@ -468,43 +498,21 @@ class Gameplay(commands.Cog):
name='Baserunners', value='None', inline=False
)
logging.debug(f'do AI stuff')
# If an AI team is playing
if True in [game_state['pitcher']['team']['is_ai'], game_state['batter']['team']['is_ai']]:
ai_note = ''
gm_name = ''
logging.debug(f'Checking AI stuff')
if len(ai_note) > 0:
embed.add_field(
name=f'{gm_name} will...',
value=ai_note,
inline=False
)
# AI Team is pitching
if game_state['pitcher']['team']['is_ai']:
ai_data = await ai_manager.pitching_ai_note(game_state['curr_play'], game_state['pitcher'])
logging.debug(f'ai_data: {ai_data}')
ai_note = ai_data['note']
gm_name = ai_data['gm_name']
embed.set_thumbnail(url=player_pcard(ai_data['pitcher']))
if pitching_sub is not None:
embed.add_field(
name='SUBSTITUTION',
value=f'The {game_state["pitcher"]["team"]["sname"]} have brought in '
f'**{player_desc(pitching_sub)}** to pitch'
)
if ai_data['sub'] is not None:
embed.add_field(
name='SUBSTITUTION',
value=f'The {game_state["pitcher"]["team"]["sname"]} have brought in '
f'{player_desc(ai_data["sub"])} to pitch'
)
# AI Team is batting
elif game_state['batter']['team']['is_ai']:
embed.set_thumbnail(url=player_pcard(game_state["pitcher"]))
ai_data = ai_manager.batting_ai_note(game_state['curr_play'], game_state['batter'])
ai_note = ai_data['note']
gm_name = ai_data['gm_name']
if ai_note:
embed.add_field(
name=f'{gm_name} will...',
value=ai_note,
inline=False
)
logging.debug(f'if not full length: return embed: {embed}')
logging.info(f'if not full length: return embed: {embed}')
if not full_length:
return embed
@ -1342,7 +1350,7 @@ class Gameplay(commands.Cog):
await interaction.channel.send(
content=f'{away_role.mention} @ {home_role.mention} is set!\n\n'
f'Go ahead and set lineups with the `/read-lineup` command!',
embed=await self.get_game_state_embed(this_game, full_length=False)
embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
return
@ -1433,7 +1441,7 @@ class Gameplay(commands.Cog):
await interaction.channel.send(
content=f'{away_role.mention} @ {home_role.mention} is set!\n\n'
f'Go ahead and set lineups with the `/read-lineup` command!',
embed=await self.get_game_state_embed(this_game, full_length=False)
embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
return
@ -1524,7 +1532,7 @@ class Gameplay(commands.Cog):
await interaction.channel.send(
content=f'{away_role.mention} @ {home_role.mention} is set!\n\n'
f'Go ahead and set lineups with the `/read-lineup` command!',
embed=await self.get_game_state_embed(this_game, full_length=False)
embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
return
@ -1639,15 +1647,6 @@ class Gameplay(commands.Cog):
f'{human_sp_card["team"]["sname"]}. Will you double check that before we get started?')
return
if this_game.game_type in ['major-league', 'hall-of-fame']:
l_check = await legal_check([human_sp_card['id']])
if not l_check['legal']:
await interaction.edit_original_response(
content=f'It looks like this is a Ranked Legal game and {player_desc(human_sp_card["player"])} is '
f'not legal in Ranked. You can start a new game once you get a new SP.'
)
return
all_lineups.append({
'game_id': this_game.id,
'team_id': team['id'],
@ -1715,7 +1714,7 @@ class Gameplay(commands.Cog):
await interaction.channel.send(
content=f'Game {gauntlets.games_played(this_run) + 1} of the run is set!\n\n'
f'Go ahead and set lineups with the `/read-lineup` command!',
embed=await self.get_game_state_embed(this_game, full_length=False)
embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
return
@ -1725,7 +1724,7 @@ class Gameplay(commands.Cog):
this_game = get_one_game(channel_id=ctx.channel.id, active=True)
try:
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game))
await ctx.send(content=None, embed=await self.initialize_play_plus_embed(this_game))
except Exception as e:
logging.error(f'could not post game state embed: {e}')
question = await ctx.send(
@ -1749,7 +1748,7 @@ class Gameplay(commands.Cog):
@commands.is_owner()
async def check_decisions_command(self, ctx: commands.Context):
this_game = get_one_game(channel_id=ctx.channel.id, active=True)
get_pitching_decisions(this_game)
get_pitching_decisions(this_game, this_game.id)
await ctx.send(random_conf_gif())
@app_commands.command(name='end-game', description='End game in this channel')
@ -1916,7 +1915,7 @@ class Gameplay(commands.Cog):
)
return
await response.edit(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
await response.edit(content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False))
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
question = await interaction.edit_original_response(content=f'Should I end this game?', view=view)
await view.wait()
@ -2689,7 +2688,7 @@ class Gameplay(commands.Cog):
post_lineups(all_lineups)
try:
await interaction.channel.send(content=None, embed=await self.get_game_state_embed(this_game))
await interaction.channel.send(content=None, embed=await self.initialize_play_plus_embed(this_game))
except IntegrityError as e:
logging.debug(f'Unable to pull game_state for game_id {this_game.id} until both lineups are in: {e}')
await interaction.response.send_message(f'Game state will be posted once both lineups are in')
@ -2762,7 +2761,7 @@ class Gameplay(commands.Cog):
await interaction.edit_original_response(
content=None,
embed=await self.get_game_state_embed(this_game)
embed=await self.initialize_play_plus_embed(this_game)
)
@group_substitution.command(name='pitcher', description='Make a pitching change')
@ -2804,7 +2803,7 @@ class Gameplay(commands.Cog):
await interaction.edit_original_response(content=f'~~{q_text}~~\nI will hold off for now.')
await interaction.channel.send(
content=None,
embed=await self.get_game_state_embed(this_game)
embed=await self.initialize_play_plus_embed(this_game)
)
return
@ -2854,12 +2853,12 @@ class Gameplay(commands.Cog):
if new_post:
await interaction.channel.send(
content=None,
embed=await self.get_game_state_embed(this_game)
embed=await self.initialize_play_plus_embed(this_game)
)
else:
await interaction.edit_original_response(
content=None,
embed=await self.get_game_state_embed(this_game)
embed=await self.initialize_play_plus_embed(this_game)
)
@commands.hybrid_command(name='gamestate', help='Post the current game state', aliases=['gs'])
@ -2872,7 +2871,7 @@ class Gameplay(commands.Cog):
response = await ctx.send(f'Building the scorebug now...')
await response.edit(content=None, embed=await self.get_game_state_embed(this_game, full_length=include_lineups))
await response.edit(content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=include_lineups))
async def checks_log_interaction(self, interaction: discord.Interaction, block_rollback: Optional[bool] = False) \
-> (Optional[StratGame], Optional[dict], Optional[StratPlay]):
@ -2932,6 +2931,33 @@ class Gameplay(commands.Cog):
)
return
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
question = await interaction.channel.send(
f'Whoa there, cowpoke. The AI can automatically make pitcher subs now and will let pitchers cook in some '
f'cases. Are you sure you want to manually run a sub for them?',
view=view
)
await view.wait()
if view.value:
await question.edit(
content=f'~~Whoa there, cowpoke. The AI can automatically make pitcher subs now and will let pitchers '
f'cook in some cases. Are you sure you want to manually run a sub for them?~~\n\nI let Cal '
f'know his stupid AI isn\'t working.',
view=None
)
await send_to_channel(
self.bot,
'commissioners-office',
content=f'{interaction.user.display_name} just ran a manual sub here: {question.jump_url}')
else:
await question.delete()
await interaction.edit_original_response(
content='Jkjkjk, we will let the ai decide when to make subs.',
embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
return
curr_pitcher = get_one_lineup(this_game.id, team_id=ai_team['id'], position='P')
pit_plays = get_plays(this_game.id, curr_pitcher.id)
logging.debug(f'pit_plays for sub in Game {this_game.id}: {pit_plays}')
@ -2975,7 +3001,7 @@ class Gameplay(commands.Cog):
make_sub(await ai_manager.get_relief_pitcher(this_play, ai_team, this_game.game_type))
await interaction.edit_original_response(
content=None,
embed=await self.get_game_state_embed(this_game, full_length=False)
embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='flyball', description='Flyballs: a, b, ballpark, bq, c')
@ -2992,11 +3018,11 @@ class Gameplay(commands.Cog):
await interaction.edit_original_response(content=f'Flyball has been logged')
await interaction.channel.send(
content=None,
embed=await self.get_game_state_embed(this_game, full_length=False)
embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
else:
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='groundball', description='Groundballs: a, b, c')
@ -3009,7 +3035,7 @@ class Gameplay(commands.Cog):
await self.groundballs(interaction, this_game, this_play, groundball_type)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='single', description='Singles: *, **, ballpark, uncapped')
@ -3194,11 +3220,11 @@ class Gameplay(commands.Cog):
await interaction.edit_original_response(content=f'Uncapped single has been logged')
await interaction.channel.send(
content=None,
embed=await self.get_game_state_embed(this_game, full_length=False)
embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
else:
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='frame-pitch', description=f'Walk/strikeout split; determined by home plate umpire')
@ -3228,7 +3254,7 @@ class Gameplay(commands.Cog):
complete_play(this_play.id, batter_to_base=batter_to_base)
await interaction.channel.send(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='double', description='Doubles: **, ***, uncapped')
@ -3249,7 +3275,7 @@ class Gameplay(commands.Cog):
batter_to_base = 2
ai_is_batting = ai_batting(this_game, this_play)
ai_manager = get_manager(this_game)
this_manager = get_manager(this_game)
if this_play.on_first:
ai_hint = ''
@ -3258,7 +3284,7 @@ class Gameplay(commands.Cog):
ai_hint = f'*The runner will attempt to advance*'
else:
ai_hint = f'*The runner will ' \
f'{ai_manager.uncapped_advance(4, this_play.starting_outs)}*'
f'{this_manager.uncapped_advance(4, this_play.starting_outs)}*'
logging.debug(f'calling of embed')
await show_outfield_cards(interaction, this_play)
@ -3275,7 +3301,7 @@ class Gameplay(commands.Cog):
await question.delete()
ai_hint = ''
if this_game.ai_team and not ai_is_batting:
ai_hint = f'*The defense will {ai_manager.throw_lead_runner(4, this_play.starting_outs)}*'
ai_hint = f'*The defense will {this_manager.throw_lead_runner(4, this_play.starting_outs)}*'
# Throw for lead runner?
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
@ -3290,7 +3316,7 @@ class Gameplay(commands.Cog):
ai_hint = ''
if this_game.ai_team and ai_is_batting:
ai_hint = f'*The trail runner will ' \
f'{ai_manager.trail_advance(3, this_play.starting_outs, True)}*'
f'{this_manager.trail_advance(3, this_play.starting_outs, True)}*'
batter_runner = await get_player(this_game, this_play.batter)
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
@ -3305,7 +3331,7 @@ class Gameplay(commands.Cog):
ai_hint = ''
if this_game.ai_team and not ai_is_batting:
ai_hint = f'*The defense will ' \
f'{ai_manager.throw_which_runner(4, this_play.starting_outs)}*'
f'{this_manager.throw_which_runner(4, this_play.starting_outs)}*'
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
view.confirm.label = 'Home Plate'
@ -3391,11 +3417,11 @@ class Gameplay(commands.Cog):
await interaction.edit_original_response(content=f'Uncapped double has been logged')
await interaction.channel.send(
content=None,
embed=await self.get_game_state_embed(this_game, full_length=False)
embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
else:
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='triple', description='Triples: no sub-types')
@ -3408,7 +3434,7 @@ class Gameplay(commands.Cog):
triple(this_play)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='homerun', description='Home Runs: ballpark, no-doubt')
@ -3427,7 +3453,7 @@ class Gameplay(commands.Cog):
complete_play(this_play.id, batter_to_base=4)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='walk', description='Walks: unintentional, intentional')
@ -3447,7 +3473,7 @@ class Gameplay(commands.Cog):
complete_play(this_play.id, batter_to_base=1)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='chaos', description='Chaos: wild-pitch, passed-ball, balk, pickoff')
@ -3527,7 +3553,7 @@ class Gameplay(commands.Cog):
complete_play(this_play.id)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='stealing', description='Running: stolen-base, caught-stealing')
@ -3681,7 +3707,7 @@ class Gameplay(commands.Cog):
complete_play(this_play.id)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='strikeout', description='Strikeout')
@ -3697,7 +3723,7 @@ class Gameplay(commands.Cog):
complete_play(this_play.id)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='popout', description='Popout')
@ -3713,7 +3739,7 @@ class Gameplay(commands.Cog):
complete_play(this_play.id)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='lineout', description='Lineouts: one out, ballpark, max outs')
@ -3766,7 +3792,7 @@ class Gameplay(commands.Cog):
complete_play(this_play.id)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='hit-by-pitch', description='Batter to first; runners advance if forced')
@ -3783,7 +3809,7 @@ class Gameplay(commands.Cog):
complete_play(this_play.id, batter_to_base=1)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='sac-bunt', description='Batter out; runners advance one base')
@ -3800,7 +3826,7 @@ class Gameplay(commands.Cog):
complete_play(this_play.id)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='undo-play', description='Remove the most recent play from the log')
@ -3829,7 +3855,7 @@ class Gameplay(commands.Cog):
undo_subs(this_game, latest_play.play_num)
await interaction.edit_original_response(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
@group_log.command(name='xcheck', description='Defender makes an x-check')
@ -4253,7 +4279,7 @@ class Gameplay(commands.Cog):
await question.edit(content=f'**The ball dropped foul; batter swings again.**', view=None)
patch_play(this_play.id, defender_id=False, check_pos='false')
await interaction.channel.send(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
return
else:
@ -4272,7 +4298,7 @@ class Gameplay(commands.Cog):
patch_play(this_play.id, locked=False)
await interaction.channel.send(
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)
)
# @group_log.command(name='xcheck', description='Defender makes an x-check')

View File

@ -12,6 +12,7 @@ import datetime
from discord import app_commands, Member
from discord.ext import commands, tasks
from difflib import get_close_matches
from typing import Optional, Literal
from discord.ext.commands import Greedy
@ -22,7 +23,6 @@ from helpers import PD_PLAYERS_ROLE_NAME, IMAGES, PD_SEASON, random_conf_gif, fu
fuzzy_search, get_channel, display_cards, get_card_embeds, get_team_embed, cardset_search, get_blank_team_card, \
get_team_by_owner, get_rosters, get_roster_sheet, legal_channel, random_conf_word, embed_pagination, get_cal_user, \
team_summary_embed, SelectView, SelectPaperdexCardset, SelectPaperdexTeam
from typing import Optional, Literal
# date = f'{datetime.datetime.now().year}-{datetime.datetime.now().month}-{datetime.datetime.now().day}'
# logging.basicConfig(
@ -694,7 +694,8 @@ class Players(commands.Cog):
@commands.has_any_role(PD_PLAYERS_ROLE_NAME)
@commands.check(legal_channel)
async def random_card_command(self, ctx: commands.Context):
this_player = await db_get('players/random', params=[('limit', 1)])['players'][0]
p_query = await db_get('players/random', params=[('limit', 1)])
this_player = p_query['players'][0]
this_embed = await get_card_embeds(
{'player': this_player, 'team': {'lname': 'Paper Dynasty', 'logo': IMAGES['logo'], 'season': PD_SEASON}}
)

View File

@ -2,7 +2,6 @@ import datetime
from dataclasses import dataclass
from typing import Optional
import requests
import logging
import aiohttp
import os
@ -10,74 +9,13 @@ import os
AUTH_TOKEN = {'Authorization': f'Bearer {os.environ.get("API_TOKEN")}'}
DB_URL = 'https://pd.manticorum.com/api'
master_debug = True
alt_database = True
alt_database = False
PLAYER_CACHE = {}
if alt_database == 'dev':
DB_URL = 'https://pddev.manticorum.com/api'
@dataclass
class Player:
player_id: int
p_name: str
cost: int
image: str
mlbclub: str
franchise: str
cardset: dict
set_num: int
rarity: dict
pos_1: str
description: str
quantity: Optional[int] = 999
image2: Optional[str] = None
pos_2: Optional[str] = None
pos_3: Optional[str] = None
pos_4: Optional[str] = None
pos_5: Optional[str] = None
pos_6: Optional[str] = None
pos_7: Optional[str] = None
pos_8: Optional[str] = None
headshot: Optional[str] = None
vanity_card: Optional[str] = None
strat_code: Optional[str] = None
bbref_id: Optional[str] = None
fangr_id: Optional[str] = None
mlbplayer: Optional[dict] = None
created: datetime.datetime = datetime.datetime.now()
def to_dict(self):
return {
'player_id': self.player_id,
'p_name': self.p_name,
'cost': self.cost,
'image': self.image,
'mlbclub': self.mlbclub,
'franchise': self.franchise,
'cardset': self.cardset,
'set_num': self.set_num,
'rarity': self.rarity,
'pos_1': self.pos_1,
'description': self.description,
'quantity': self.quantity,
'image2': self.image2,
'pos_2': self.pos_2,
'pos_3': self.pos_3,
'pos_4': self.pos_4,
'pos_5': self.pos_5,
'pos_6': self.pos_6,
'pos_7': self.pos_7,
'pos_8': self.pos_8,
'headshot': self.headshot,
'vanity_card': self.vanity_card,
'strat_code': self.strat_code,
'bbref_id': self.bbref_id,
'fangr_id': self.fangr_id,
'mlbplayer': self.mlbplayer
}
def param_char(other_params):
if other_params:
return '&'
@ -236,27 +174,3 @@ def team_hash(team):
hash_string = f'{team["sname"][-1]}{team["gmid"] / 6950123:.0f}{team["sname"][-2]}{team["gmid"] / 42069123:.0f}'
return hash_string
async def get_pd_player(player_id, as_dict: Optional[bool] = True):
if player_id in PLAYER_CACHE:
tdelta = datetime.datetime.now() - PLAYER_CACHE[player_id].created
if tdelta.total_seconds() < 1209600:
logging.debug(f'this_player: {PLAYER_CACHE[player_id]}')
if as_dict:
return PLAYER_CACHE[player_id].to_dict()
else:
return PLAYER_CACHE[player_id]
else:
logging.error(f'Refreshing player {player_id} in cache...')
this_player = await db_get('players', object_id=player_id)
for bad_key in ['mlbplayer', 'paperdex']:
if bad_key in this_player:
del this_player[bad_key]
logging.debug(f'this_player: {this_player}')
PLAYER_CACHE[player_id] = Player(**this_player)
if as_dict:
return this_player
return PLAYER_CACHE[player_id]

View File

@ -12,7 +12,8 @@ from playhouse.shortcuts import model_to_dict
from dataclasses import dataclass
from helpers import SBA_SEASON, PD_SEASON, get_player_url, get_sheets
from db_calls import db_get, get_pd_player
from db_calls import db_get
from in_game.data_cache import get_pd_player
db = SqliteDatabase(
'storage/gameplay.db',
@ -143,6 +144,9 @@ class ManagerAi(BaseModel):
uncapped_third = IntegerField(default=5)
uncapped_trail = IntegerField(default=5)
bullpen_matchup = IntegerField(default=5)
behind_aggression = IntegerField(default=5)
ahead_aggression = IntegerField(default=5)
decide_throw = IntegerField(default=5)
class StratManagerAi(pydantic.BaseModel):
@ -378,6 +382,47 @@ class StratManagerAi(pydantic.BaseModel):
return f'{throw_base} {max(throw_range, 0)}-'
def go_to_reliever(
self, this_play, tot_allowed: int, is_starter: bool = False) -> bool:
run_lead = this_play.ai_run_diff()
obc = this_play.on_base_code
logging.info(f'db_calls_gameplay - StratManagerAi - ID: {self.id} - go_to_reliever: '
f'outs: {this_play.starting_outs}, obc: {obc}, run_lead: {run_lead}, '
f'tot_allowed: {tot_allowed}')
lead_target = run_lead if is_starter else 3
# AI up big
if tot_allowed < 5 and is_starter:
logging.info(f'db_calls_gameplay - StratManagerAi - ID: {self.id} - go_to_reliever: False / code 1')
return False
elif run_lead > 5 or (run_lead > 2 and self.ahead_aggression > 5):
if tot_allowed <= lead_target or obc <= 3 or this_play.starting_outs == 2:
logging.info(f'db_calls_gameplay - StratManagerAi - ID: {self.id} - go_to_reliever: False / code 2')
return False
elif run_lead > 2 or (run_lead >= 0 and self.ahead_aggression > 5):
if tot_allowed < lead_target or obc <= 1 or this_play.starting_outs == 2:
logging.info(f'db_calls_gameplay - StratManagerAi - ID: {self.id} - go_to_reliever: False / code 3')
return False
elif run_lead >= 0 or (run_lead >= -2 and self.behind_aggression > 5):
if tot_allowed < 5 or obc <= run_lead or this_play.starting_outs == 2:
logging.info(f'db_calls_gameplay - StratManagerAi - ID: {self.id} - go_to_reliever: False / code 4')
return False
elif run_lead >= -3 and self.behind_aggression > 5:
if tot_allowed < 5 and obc <= 1:
logging.info(f'db_calls_gameplay - StratManagerAi - ID: {self.id} - go_to_reliever: False / code 5')
return False
elif run_lead <= -5:
if is_starter and this_play.inning_num <= 3:
logging.info(f'db_calls_gameplay - StratManagerAi - ID: {self.id} - go_to_reliever: False / code 6')
return False
if this_play.starting_outs != 0:
logging.info(f'db_calls_gameplay - StratManagerAi - ID: {self.id} - go_to_reliever: False / code 7')
return False
return True
def convert_strat_manager(manager: ManagerAi) -> StratManagerAi:
manager_dict = model_to_dict(manager)
@ -623,6 +668,7 @@ class Lineup(BaseModel):
after_play = IntegerField()
replacing_id = IntegerField(null=True)
active = BooleanField(default=True)
variant = IntegerField(default=0)
@dataclass
@ -637,6 +683,7 @@ class StratLineup:
replacing_id: int = None
active: bool = True
card_id: int = None
variant: int = 0
def convert_stratlineup(lineup: Lineup) -> StratLineup:
@ -887,6 +934,7 @@ class Play(BaseModel):
starting_outs = IntegerField()
away_score = IntegerField()
home_score = IntegerField()
in_pow = BooleanField(default=False)
on_first = ForeignKeyField(Lineup, null=True)
on_first_final = IntegerField(null=True)
@ -953,6 +1001,7 @@ class StratPlay:
away_score: int
home_score: int
batter_pos: str = None
in_pow: bool = False
on_first: StratLineup = None
on_first_final: int = None
@ -1004,6 +1053,12 @@ class StratPlay:
is_tied: bool = False
is_new_inning: bool = False
def ai_run_diff(self):
if self.game.ai_team == 'away':
return self.away_score - self.home_score
else:
return self.home_score - self.away_score
def convert_stratplay(play: Play) -> StratPlay:
play_dict = model_to_dict(play)
@ -1050,7 +1105,7 @@ def patch_play(
on_first_id: int = None, on_first_final: int = None, on_second_id: int = None, on_second_final: int = None,
on_third_id: int = None, on_third_final: int = None, starting_outs: int = None, runner_id: int = None,
complete: bool = None, rbi: int = None, wp: int = None, pb: int = None, pick: int = None, balk: int = None,
is_new_inning: bool = None, batter_final: int = None):
is_new_inning: bool = None, batter_final: int = None, in_pow: bool = None):
this_play = Play.get_by_id(play_id)
if batter_id is not None:
@ -1174,6 +1229,11 @@ def patch_play(
this_play.is_new_inning = 0
else:
this_play.is_new_inning = 1
if in_pow is not None:
if not in_pow:
this_play.in_pow = 0
else:
this_play.in_pow = 1
this_play.save()
# return_play = model_to_dict(this_play)
@ -2007,7 +2067,8 @@ def get_fielding_stats(game_id, lineup_id: int = None, team_id: int = None):
# return all_stats
def get_pitching_stats(game_id, lineup_id: int = None, team_id: int = None):
def get_pitching_stats(
game_id, lineup_id: int = None, team_id: int = None, in_pow: bool = None, in_innings: list = None):
pitching_stats = Play.select(
Play.pitcher,
fn.SUM(Play.outs).over(partition_by=[Play.pitcher_id]).alias('pl_outs'),
@ -2072,6 +2133,12 @@ def get_pitching_stats(game_id, lineup_id: int = None, team_id: int = None):
if lineup_id is not None:
pitching_stats = pitching_stats.where(Play.pitcher_id == lineup_id)
if in_pow is not None:
pitching_stats = pitching_stats.where(Play.in_pow == in_pow)
if in_innings is not None:
pitching_stats = pitching_stats.where(Play.inning_num << in_innings)
tm_earned_runs = None
if team_id is not None:
tm_er_first = Play.select().where(

View File

@ -4,12 +4,10 @@ import logging
import random
import discord
import requests
from peewee import DatabaseError
import ai_manager
from in_game import ai_manager
import helpers
from helpers import RARITY, get_cal_user, get_or_create_role, send_to_channel, get_channel
from helpers import RARITY, get_or_create_role, send_to_channel, get_channel
from db_calls import db_get, db_post, db_delete, db_patch

View File

@ -8,6 +8,7 @@ import traceback
import discord
import pygsheets
import requests
from discord.ext import commands
from db_calls import *

View File

@ -1,14 +1,17 @@
import copy
import logging
import math
import random
import pydantic
# import data_cache
from db_calls_gameplay import StratPlay, StratGame, get_one_lineup, get_manager, get_team_lineups, \
get_last_inning_end_play, make_sub, get_player
get_last_inning_end_play, make_sub, get_player, StratLineup, get_pitching_stats, patch_play
from db_calls import db_get, db_post
from peewee import *
from typing import Optional, Literal
from in_game import data_cache
db = SqliteDatabase(
'storage/ai-database.db',
pragmas={
@ -587,49 +590,49 @@ def get_pitcher(this_game: StratGame, this_play: StratPlay):
async def pitching_ai_note(this_play: StratPlay, this_pitcher: dict):
this_ai = get_manager(this_play.game)
gm_name = f'{this_pitcher["team"]["gmname"]}'
used_pitchers = await get_team_lineups(
game_id=this_play.game.id,
team_id=this_pitcher["team"]['id'],
inc_inactive=True,
pitchers_only=True,
as_string=False
)
last_inning_ender = get_last_inning_end_play(
this_play.game.id,
this_play.inning_half,
this_play.inning_num - 1
)
# used_pitchers = await get_team_lineups(
# game_id=this_play.game.id,
# team_id=this_pitcher["team"]['id'],
# inc_inactive=True,
# pitchers_only=True,
# as_string=False
# )
# last_inning_ender = get_last_inning_end_play(
# this_play.game.id,
# this_play.inning_half,
# this_play.inning_num - 1
# )
ai_note = ''
pitcher = this_pitcher
# Pitcher Substitutions
new_pitcher = None
if last_inning_ender and last_inning_ender.pitcher != this_play.pitcher:
logging.debug(f'{this_pitcher["team"]["sname"]} not making a change.')
ai_note += f'- have {this_pitcher["p_name"]} finish the inning\n'
elif this_play.is_new_inning and this_play.game.short_game and this_play.inning_num != 1:
logging.debug(f'{this_pitcher["team"]["sname"]} going the to pen.')
if len(used_pitchers) < 8:
make_sub(await get_relief_pitcher(
this_play, this_pitcher['team'], this_play.game.game_type
))
pitcher = await get_player(this_play.game, get_pitcher(this_play.game, this_play))
new_pitcher = pitcher
else:
ai_note += f'- continue with auto-fatigued {this_pitcher["p_name"]}\n'
else:
if len(used_pitchers) == 1:
ai_note += f'- go to the pen if the pitcher fatigues __and has allowed 5+ baserunners__ ' \
f'(`/log ai-pitcher-sub`)\n'
elif len(used_pitchers) < 8:
ai_note += f'- go to the pen if the pitcher fatigues (`/log ai-pitcher-sub`)\n'
else:
ai_note += f' - continue with {this_pitcher["p_name"]}\n'
# # Pitcher Substitutions
# new_pitcher = None
# if last_inning_ender and last_inning_ender.pitcher != this_play.pitcher:
# logging.debug(f'{this_pitcher["team"]["sname"]} not making a change.')
#
# ai_note += f'- have {this_pitcher["p_name"]} finish the inning\n'
#
# elif this_play.is_new_inning and this_play.game.short_game and this_play.inning_num != 1:
# logging.debug(f'{this_pitcher["team"]["sname"]} going the to pen.')
#
# if len(used_pitchers) < 8:
# make_sub(await get_relief_pitcher(
# this_play, this_pitcher['team'], this_play.game.game_type
# ))
# pitcher = await get_player(this_play.game, get_pitcher(this_play.game, this_play))
# new_pitcher = pitcher
# else:
# ai_note += f'- continue with auto-fatigued {this_pitcher["p_name"]}\n'
#
# else:
# if len(used_pitchers) == 1:
# ai_note += f'- go to the pen if the pitcher fatigues __and has allowed 5+ baserunners__ ' \
# f'(`/log ai-pitcher-sub`)\n'
# elif len(used_pitchers) < 8:
# ai_note += f'- go to the pen if the pitcher fatigues (`/log ai-pitcher-sub`)\n'
# else:
# ai_note += f' - continue with {this_pitcher["p_name"]}\n'
# Holding Baserunners
if this_play.starting_outs == 2 and this_play.on_base_code > 0:
@ -661,7 +664,7 @@ async def pitching_ai_note(this_play: StratPlay, this_pitcher: dict):
'note': ai_note,
'pitcher': pitcher,
'gm_name': gm_name,
'sub': new_pitcher
'sub': None
}
@ -682,3 +685,115 @@ def batting_ai_note(this_play: StratPlay, this_batter: dict):
'batter': this_batter,
'gm_name': gm_name
}
async def check_pitching_sub(this_play: StratPlay, ai_team: dict):
used_pitchers = await get_team_lineups(
game_id=this_play.game.id,
team_id=this_play.pitcher.team_id,
inc_inactive=True,
pitchers_only=True,
as_string=False
)
p_stats = get_pitching_stats(this_play.game.id, lineup_id=this_play.pitcher.id)
if len(p_stats) == 0:
logging.info(f'ai_manager - check_pitching_sub: no stats recorded yet, returning None')
return False
ps = p_stats[0]
logging.info(f'ai_manager - check_pitching_sub: beyond point of weakness')
this_ai = get_manager(this_play.game)
this_pc = await data_cache.get_pd_pitchingcard(this_play.pitcher.player_id, variant=this_play.pitcher.variant)
pof_weakness = this_pc.card.starter_rating if len(used_pitchers) == 1 else this_pc.card.relief_rating
innof_work = math.ceil((ps['pl_outs'] + 1) / 3)
gtr = this_ai.go_to_reliever(
this_play,
tot_allowed=ps['pl_hit'] + ps['pl_bb'] + ps['pl_hbp'],
is_starter=True if len(used_pitchers) == 1 else False
)
if (this_play.game.short_game or gtr or innof_work > pof_weakness + 3) and len(used_pitchers) < 8:
make_sub(await get_relief_pitcher(this_play, ai_team, this_play.game.game_type))
return await get_player(this_play.game, get_pitcher(this_play.game, this_play))
return None
async def is_pitcher_fatigued(this_play: StratPlay) -> bool:
used_pitchers = await get_team_lineups(
game_id=this_play.game.id,
team_id=this_play.pitcher.team_id,
inc_inactive=True,
pitchers_only=True,
as_string=False
)
p_stats = get_pitching_stats(this_play.game.id, lineup_id=this_play.pitcher.id)
if len(p_stats) == 0:
logging.info(f'ai_manager - is_pitcher_fatigued: no stats recorded yet, returning False')
return False
ps = p_stats[0]
if this_play.game.short_game:
pof_weakness = 1
else:
this_pc = await data_cache.get_pd_pitchingcard(this_play.pitcher.player_id, variant=this_play.pitcher.variant)
pof_weakness = this_pc.card.starter_rating if len(used_pitchers) == 1 else this_pc.card.relief_rating
# Check starter fatigue
if len(p_stats) == 1:
if ps['pl_eruns'] >= 7:
logging.info(f'ai_manager - is_pitcher_fatigued: starter allowed 7+, returning True')
return True
if ps['pl_eruns'] >= 6:
logging.info(f'ai_manager - is_pitcher_fatigued: starter allowed 6+, checking for fatigue')
f_query = get_pitching_stats(
this_play.game.id,
lineup_id=this_play.pitcher.id,
in_innings=[this_play.inning_num, this_play.inning_num - 1]
)
if f_query[0]['pl_eruns'] >= 6:
logging.info(f'ai_manager - is_pitcher_fatigued: starter allowed 6 in 2, returning True')
return True
if ps['pl_eruns'] >= 5:
logging.info(f'ai_manager - is_pitcher_fatigued: starter allowed 5+, checking for fatigue')
f_query = get_pitching_stats(
this_play.game.id,
lineup_id=this_play.pitcher.id,
in_innings=[this_play.inning_num]
)
if f_query[0]['pl_eruns'] >= 5:
logging.info(f'ai_manager - is_pitcher_fatigued: starter allowed 5 in 1, returning True')
return True
innof_work = math.ceil((ps['pl_outs'] + 1) / 3)
if innof_work < pof_weakness:
logging.info(f'ai_manager - is_pitcher_fatigued: not point of weakness, returning False')
return False
elif innof_work == pof_weakness:
patch_play(this_play.id, in_pow=True)
pow_stats = get_pitching_stats(this_play.game.id, lineup_id=this_play.pitcher.id, in_pow=True)
if len(pow_stats) == 0:
logging.info(f'ai_manager - is_pitcher_fatigued: in point of weakness, no stats recorded, returning False')
return False
pows = pow_stats[0]
if pows['pl_hit'] + pows['pl_bb'] + pows['pl_hbp'] < 3:
logging.info(f'ai_manager - is_pitcher_fatigued: in point of weakness, not fatigued, returning False')
return False
logging.info(f'ai_manager - is_pitcher_fatigued: beyond point of weakness, fatigued, returning True')
return True
# async def consider_reliever(
# this_play: StratPlay, this_pitcher: StratLineup, ai_team: dict, run_lead: int, tot_allowed: int,
# used_pitchers: list[StratLineup]):
# this_ai = get_manager(this_play.game)
#
# if (this_play.game.short_game or
# this_ai.go_to_reliever(this_play.starting_outs, this_play.on_base_code, run_lead, tot_allowed)) and \
# len(used_pitchers) < 8:
# make_sub(await get_relief_pitcher(this_play, ai_team, this_play.game.game_type))
# return await get_player(this_play.game, get_pitcher(this_play.game, this_play))
#
# return None

315
in_game/data_cache.py Normal file
View File

@ -0,0 +1,315 @@
import datetime
from dataclasses import dataclass
import logging
from typing import Optional
from db_calls import db_get
PLAYER_CACHE = {}
BATTINGCARD_CACHE = {} # { <player_id: int>: { <variant: int>: BattingWrapper } }
PITCHINGCARD_CACHE = {} # { <player_id: int>: { <variant: int>: PitchingWrapper } }
@dataclass
class Player:
player_id: int
p_name: str
cost: int
image: str
mlbclub: str
franchise: str
cardset: dict
set_num: int
rarity: dict
pos_1: str
description: str
quantity: Optional[int] = 999
image2: Optional[str] = None
pos_2: Optional[str] = None
pos_3: Optional[str] = None
pos_4: Optional[str] = None
pos_5: Optional[str] = None
pos_6: Optional[str] = None
pos_7: Optional[str] = None
pos_8: Optional[str] = None
headshot: Optional[str] = None
vanity_card: Optional[str] = None
strat_code: Optional[str] = None
bbref_id: Optional[str] = None
fangr_id: Optional[str] = None
mlbplayer: Optional[dict] = None
created: datetime.datetime = datetime.datetime.now()
def to_dict(self):
return {
'player_id': self.player_id,
'p_name': self.p_name,
'cost': self.cost,
'image': self.image,
'mlbclub': self.mlbclub,
'franchise': self.franchise,
'cardset': self.cardset,
'set_num': self.set_num,
'rarity': self.rarity,
'pos_1': self.pos_1,
'description': self.description,
'quantity': self.quantity,
'image2': self.image2,
'pos_2': self.pos_2,
'pos_3': self.pos_3,
'pos_4': self.pos_4,
'pos_5': self.pos_5,
'pos_6': self.pos_6,
'pos_7': self.pos_7,
'pos_8': self.pos_8,
'headshot': self.headshot,
'vanity_card': self.vanity_card,
'strat_code': self.strat_code,
'bbref_id': self.bbref_id,
'fangr_id': self.fangr_id,
'mlbplayer': self.mlbplayer
}
@dataclass
class BattingCard:
player_id: int
variant: int
steal_low: int
steal_high: int
steal_auto: bool
steal_jump: float
bunting: str
hit_and_run: str
running: int
offense_col: int
hand: str
@dataclass
class BattingRatings:
homerun: float
bp_homerun: float
triple: float
double_three: float
double_two: float
double_pull: float
single_two: float
single_one: float
single_center: float
bp_single: float
hbp: float
walk: float
strikeout: float
lineout: float
popout: float
flyout_a: float
flyout_bq: float
flyout_lf_b: float
flyout_rf_b: float
groundout_a: float
groundout_b: float
groundout_c: float
avg: float
obp: float
slg: float
pull_rate: float
center_rate: float
slap_rate: float
@dataclass
class BattingWrapper:
card: BattingCard
ratings_vl: BattingRatings
ratings_vr: BattingRatings
created: datetime.datetime = datetime.datetime.now()
@dataclass
class PitchingCard:
player_id: int
variant: int
balk: int
wild_pitch: int
hold: int
starter_rating: int
relief_rating: int
batting: str
offense_col: int
hand: str
closer_rating: Optional[int] = None
@dataclass
class PitchingRatings:
homerun: float
bp_homerun: float
triple: float
double_three: float
double_two: float
double_cf: float
single_two: float
single_one: float
single_center: float
bp_single: float
hbp: float
walk: float
strikeout: float
flyout_lf_b: float
flyout_cf_b: float
flyout_rf_b: float
groundout_a: float
groundout_b: float
xcheck_p: float
xcheck_c: float
xcheck_1b: float
xcheck_2b: float
xcheck_3b: float
xcheck_ss: float
xcheck_lf: float
xcheck_cf: float
xcheck_rf: float
avg: float
obp: float
slg: float
@dataclass
class PitchingWrapper:
card: PitchingCard
ratings_vl: PitchingRatings
ratings_vr: PitchingRatings
created: datetime.datetime = datetime.datetime.now()
async def get_pd_player(player_id, as_dict: Optional[bool] = True):
if player_id in PLAYER_CACHE:
tdelta = datetime.datetime.now() - PLAYER_CACHE[player_id].created
if tdelta.total_seconds() < 1209600:
logging.debug(f'this_player: {PLAYER_CACHE[player_id]}')
if as_dict:
return PLAYER_CACHE[player_id].to_dict()
else:
return PLAYER_CACHE[player_id]
else:
logging.error(f'Refreshing player {player_id} in cache...')
this_player = await db_get('players', object_id=player_id)
for bad_key in ['mlbplayer', 'paperdex']:
if bad_key in this_player:
del this_player[bad_key]
logging.debug(f'this_player: {this_player}')
PLAYER_CACHE[player_id] = Player(**this_player)
if as_dict:
return this_player
return PLAYER_CACHE[player_id]
async def get_pd_battingcard(player_id: int, variant: Optional[int] = 0):
if player_id in BATTINGCARD_CACHE and variant in BATTINGCARD_CACHE[player_id]:
tdelta = datetime.datetime.now() - BATTINGCARD_CACHE[player_id][variant].created
if tdelta.total_seconds() < 609600:
logging.info(f'this_battingcard: {BATTINGCARD_CACHE[player_id][variant]}')
return BATTINGCARD_CACHE[player_id][variant]
vl_data, vr_data = None, None
r_query = await db_get(f'battingcardratings/player/{player_id}')
if r_query['count'] > 0:
for row in r_query['ratings']:
if row['battingcard']['variant'] == variant:
if row['vs_hand'].lower() == 'r':
vr_data = row
elif row['vs_hand'].lower() == 'l':
vl_data = row
if vl_data is not None and vr_data is not None:
break
if None in [vl_data, vr_data]:
raise KeyError(f'Could not find batting card ratings for player {player_id} variant {variant}')
logging.info(f'prepping the batting card')
bc_data = vl_data['battingcard']
bc_data['player_id'] = player_id
del bc_data['id'], bc_data['player']
this_bc = BattingCard(**bc_data)
logging.info(f'prepping the vl ratings')
vl_ratings = vl_data
del vl_ratings['battingcard'], vl_ratings['id'], vl_ratings['vs_hand']
this_vl = BattingRatings(**vl_ratings)
logging.info(f'prepping the vl ratings')
vr_ratings = vr_data
del vr_ratings['battingcard'], vr_ratings['id'], vr_ratings['vs_hand']
this_vr = BattingRatings(**vr_ratings)
logging.info(f'prepping the wrapper')
this_wrapper = BattingWrapper(
card=this_bc,
ratings_vl=this_vl,
ratings_vr=this_vr
)
if player_id in BATTINGCARD_CACHE:
BATTINGCARD_CACHE[player_id][variant] = this_wrapper
else:
BATTINGCARD_CACHE[player_id] = {variant: this_wrapper}
return this_wrapper
async def get_pd_pitchingcard(player_id: int, variant: Optional[int] = 0):
if player_id in PITCHINGCARD_CACHE and variant in PITCHINGCARD_CACHE[player_id]:
tdelta = datetime.datetime.now() - PITCHINGCARD_CACHE[player_id][variant].created
if tdelta.total_seconds() < 609600:
logging.debug(f'this_pitchingcard: {PITCHINGCARD_CACHE[player_id][variant]}')
return PITCHINGCARD_CACHE[player_id][variant]
vl_data, vr_data = None, None
r_query = await db_get(f'pitchingcardratings/player/{player_id}')
if r_query['count'] > 0:
for row in r_query['ratings']:
if row['pitchingcard']['variant'] == variant:
if row['vs_hand'].lower() == 'r':
vr_data = row
elif row['vs_hand'].lower() == 'l':
vl_data = row
if vl_data is not None and vr_data is not None:
break
if None in [vl_data, vr_data]:
raise KeyError(f'Could not find batting card ratings for player {player_id} variant {variant}')
logging.debug(f'prepping the pitching card')
pc_data = vl_data['pitchingcard']
pc_data['player_id'] = player_id
del pc_data['id'], pc_data['player']
this_pc = PitchingCard(**pc_data)
logging.debug(f'prepping the vl ratings')
vl_ratings = vl_data
del vl_ratings['pitchingcard'], vl_ratings['id'], vl_ratings['vs_hand']
this_vl = PitchingRatings(**vl_ratings)
logging.debug(f'prepping the vr ratings')
vr_ratings = vr_data
del vr_ratings['pitchingcard'], vr_ratings['id'], vr_ratings['vs_hand']
this_vr = PitchingRatings(**vr_ratings)
logging.debug(f'prepping the wrapper')
this_wrapper = PitchingWrapper(
card=this_pc,
ratings_vl=this_vl,
ratings_vr=this_vr
)
if player_id in PITCHINGCARD_CACHE:
PITCHINGCARD_CACHE[player_id][variant] = this_wrapper
else:
PITCHINGCARD_CACHE[player_id] = {variant: this_wrapper}
return this_wrapper

View File

@ -1,5 +1,4 @@
import asyncio
import copy
import datetime
import logging
import random
@ -8,7 +7,7 @@ import discord
from db_calls_gameplay import StratGame, StratPlay, StratLineup, StratManagerAi, patch_play, advance_runners, \
complete_play, get_team_lineups, get_or_create_bullpen, get_player, get_sheets, make_sub, get_one_lineup, \
advance_one_runner, get_one_lineup, ai_batting, get_manager
from db_calls import db_get, db_post, Player, get_pd_player
from db_calls import db_get, db_post
from helpers import Pagination, get_team_embed, image_embed, Confirm
from typing import Literal, Optional
@ -149,18 +148,18 @@ def starting_pitcher(ai_team, bot, is_home):
return raw_cells[4][0].value
def replace_pitcher(ai_team, this_play, pitcher_card_id):
this_card = db_get(f'cards', object_id=int(pitcher_card_id))
new_lineup = {
'game_id': this_play.game.id,
'team_id': ai_team['id'],
'player_id': this_card['player']['player_id'],
'card_id': pitcher_card_id,
'position': 'P',
'batting_order': 10,
'after_play': this_play.play_num - 1
}
make_sub(new_lineup)
# def replace_pitcher(ai_team, this_play, pitcher_card_id):
# this_card = db_get(f'cards', object_id=int(pitcher_card_id))
# new_lineup = {
# 'game_id': this_play.game.id,
# 'team_id': ai_team['id'],
# 'player_id': this_card['player']['player_id'],
# 'card_id': pitcher_card_id,
# 'position': 'P',
# 'batting_order': 10,
# 'after_play': this_play.play_num - 1
# }
# make_sub(new_lineup)
def get_pitcher(this_game: StratGame, this_play: StratPlay):