2021-01-14 06:30:31 +00:00
import asyncio , time , datetime , games , json , threading , jinja2 , leagues , os , leagues
from leagues import league_structure
from league_storage import league_exists
2021-01-11 04:47:49 +00:00
from flask import Flask , url_for , Response , render_template , request , jsonify , send_from_directory , abort
2020-12-29 00:48:50 +00:00
from flask_socketio import SocketIO , emit
2021-01-06 01:38:02 +00:00
import database as db
2020-12-28 08:21:47 +00:00
2021-01-07 08:10:53 +00:00
app = Flask ( " the-prestige " , static_folder = ' simmadome/build ' )
2020-12-29 00:48:50 +00:00
app . config [ ' SECRET KEY ' ] = ' dev '
2021-01-01 20:28:12 +00:00
#app.config['SERVER_NAME'] = '0.0.0.0:5000'
2020-12-29 00:48:50 +00:00
socketio = SocketIO ( app )
2020-12-28 08:21:47 +00:00
2021-01-07 08:10:53 +00:00
# Serve React App
@app.route ( ' / ' , defaults = { ' path ' : ' ' } )
@app.route ( ' /<path:path> ' )
def serve ( path ) :
if path != " " and os . path . exists ( app . static_folder + ' / ' + path ) :
return send_from_directory ( app . static_folder , path )
else :
return send_from_directory ( app . static_folder , ' index.html ' )
2021-01-02 11:21:53 +00:00
2021-01-11 04:47:49 +00:00
### API
@app.route ( ' /api/teams/search ' )
2021-01-14 06:30:31 +00:00
def search_teams ( ) :
2021-01-11 04:47:49 +00:00
query = request . args . get ( ' query ' )
page_len = int ( request . args . get ( ' page_len ' ) )
page_num = int ( request . args . get ( ' page_num ' ) )
if query is None :
abort ( 400 , " A query term is required " )
result = db . search_teams ( query )
2021-01-14 06:30:31 +00:00
if page_len is not None : #pagination should probably be done in the sqlite query but this will do for now
2021-01-11 04:47:49 +00:00
if page_num is None :
abort ( 400 , " A page_len argument must be accompanied by a page_num argument " )
result = result [ page_num * page_len : ( page_num + 1 ) * page_len ]
return jsonify ( [ json . loads ( x [ 0 ] ) [ ' name ' ] for x in result ] ) #currently all we need is the name but that can change
2021-01-16 06:13:12 +00:00
MAX_SUBLEAGUE_DIVISION_TOTAL = 22 ;
MAX_TEAMS_PER_DIVISION = 12 ;
2021-01-11 04:47:49 +00:00
2021-01-14 06:30:31 +00:00
@app.route ( ' /api/leagues ' , methods = [ ' POST ' ] )
def create_league ( ) :
config = json . loads ( request . data )
2021-01-16 06:13:12 +00:00
if league_exists ( config [ ' name ' ] ) :
return jsonify ( { ' status ' : ' err_league_exists ' } ) , 400
num_subleagues = len ( config [ ' structure ' ] [ ' subleagues ' ] )
if num_subleagues < 1 or num_subleagues % 2 != 0 :
return jsonify ( { ' status ' : ' err_invalid_subleague_count ' } ) , 400
num_divisions = len ( config [ ' structure ' ] [ ' subleagues ' ] [ 0 ] [ ' divisions ' ] )
if num_subleagues * ( num_divisions + 1 ) > MAX_SUBLEAGUE_DIVISION_TOTAL :
return jsonify ( { ' status ' : ' err_invalid_subleague_division_total ' } ) , 400
league_dic = { }
err_teams = [ ]
for subleague in config [ ' structure ' ] [ ' subleagues ' ] :
if subleague [ ' name ' ] in league_dic :
return jsonify ( { ' status ' : ' err_duplicate_name ' , ' cause ' : subleague [ ' name ' ] } )
subleague_dic = { }
for division in subleague [ ' divisions ' ] :
if division [ ' name ' ] in subleague_dic :
return jsonify ( { ' status ' : ' err_duplicate_name ' , ' cause ' : f " { subleague [ ' name ' ] } / { division [ ' name ' ] } " } ) , 400
elif len ( division [ ' teams ' ] ) > MAX_TEAMS_PER_DIVISION :
return jsonify ( { ' status ' : ' err_too_many_teams ' , ' cause ' : f " { subleague [ ' name ' ] } / { division [ ' name ' ] } " } )
teams = [ ]
for team_name in division [ ' teams ' ] :
team = games . get_team ( team_name )
if team is None :
err_teams . append ( team_name )
else :
teams . append ( team )
subleague_dic [ division [ ' name ' ] ] = teams
league_dic [ subleague [ ' name ' ] ] = subleague_dic
if len ( err_teams ) > 0 :
return jsonify ( { ' status ' : ' err_no_such_team ' , ' cause ' : err_teams } ) , 400
for ( key , min_val ) in [
2021-01-17 21:17:07 +00:00
( ' division_series ' , 1 ) ,
( ' inter_division_series ' , 1 ) ,
2021-01-16 06:13:12 +00:00
( ' inter_league_series ' , 1 )
] :
if config [ key ] < min_val :
return jsonify ( { ' status ' : ' err_invalid_optiion_value ' , ' cause ' : key } ) , 400
2021-01-14 06:30:31 +00:00
new_league = league_structure ( config [ ' name ' ] )
new_league . setup (
2021-01-17 21:17:07 +00:00
league_dic ,
2021-01-16 06:13:12 +00:00
division_games = config [ ' division_series ' ] , # need to add a check that makes sure these values are ok
2021-01-14 06:30:31 +00:00
inter_division_games = config [ ' inter_division_series ' ] ,
inter_league_games = config [ ' inter_league_series ' ] ,
)
2021-01-14 22:47:57 +00:00
new_league . constraints [ " division_leaders " ] = config [ " top_postseason " ]
new_league . constraints [ " wild_cards " ] = config [ " wildcards " ]
2021-01-14 06:30:31 +00:00
new_league . generate_schedule ( )
leagues . save_league ( new_league )
2021-01-16 06:13:12 +00:00
return jsonify ( { ' status ' : ' success_league_created ' } )
2021-01-14 06:30:31 +00:00
2020-12-28 08:21:47 +00:00
2021-01-02 11:21:53 +00:00
2021-01-11 04:47:49 +00:00
### SOCKETS
2021-01-02 11:21:53 +00:00
2021-01-01 20:28:12 +00:00
thread2 = threading . Thread ( target = socketio . run , args = ( app , ' 0.0.0.0 ' ) )
2020-12-28 08:21:47 +00:00
thread2 . start ( )
master_games_dic = { } #key timestamp : (game game, {} state)
2021-01-07 08:10:53 +00:00
game_states = [ ]
2020-12-29 00:48:50 +00:00
2021-01-02 07:29:03 +00:00
@socketio.on ( " recieved " )
2021-01-01 08:32:47 +00:00
def handle_new_conn ( data ) :
2021-01-07 08:10:53 +00:00
socketio . emit ( " states_update " , game_states , room = request . sid )
2020-12-28 08:21:47 +00:00
def update_loop ( ) :
2021-01-07 08:10:53 +00:00
global game_states
2020-12-28 08:21:47 +00:00
while True :
2021-01-07 08:10:53 +00:00
game_states = [ ]
2021-01-05 19:26:54 +00:00
game_ids = iter ( master_games_dic . copy ( ) . keys ( ) )
for game_id in game_ids :
this_game , state , discrim_string = master_games_dic [ game_id ]
2020-12-28 08:21:47 +00:00
test_string = this_game . gamestate_display_full ( )
2020-12-31 18:41:32 +00:00
state [ " leagueoruser " ] = discrim_string
2020-12-28 08:21:47 +00:00
state [ " display_inning " ] = this_game . inning #games need to be initialized with the following keys in state:
2020-12-31 22:06:56 +00:00
#is_league, bool
2020-12-28 08:21:47 +00:00
state [ " outs " ] = this_game . outs #away_name
state [ " pitcher " ] = this_game . get_pitcher ( ) . name #home_name
state [ " batter " ] = this_game . get_batter ( ) . name #max_innings
state [ " away_score " ] = this_game . teams [ " away " ] . score #top_of_inning = True
state [ " home_score " ] = this_game . teams [ " home " ] . score #update_pause = 0
#victory_lap = False
if test_string == " Game not started. " : #weather_emoji
state [ " update_emoji " ] = " 🍿 " #weather_text
state [ " update_text " ] = " Play blall! " #they also need a timestamp
2020-12-31 08:32:01 +00:00
state [ " start_delay " ] - = 1
2021-01-06 01:38:02 +00:00
2020-12-30 07:48:39 +00:00
state [ " display_top_of_inning " ] = state [ " top_of_inning " ]
2020-12-31 08:32:01 +00:00
if state [ " start_delay " ] < = 0 :
2020-12-28 08:21:47 +00:00
if this_game . top_of_inning != state [ " top_of_inning " ] :
state [ " update_pause " ] = 2
state [ " pitcher " ] = " - "
state [ " batter " ] = " - "
2020-12-29 00:48:50 +00:00
if not state [ " top_of_inning " ] :
2020-12-28 08:21:47 +00:00
state [ " display_inning " ] - = 1
2020-12-30 07:48:39 +00:00
state [ " display_top_of_inning " ] = False
2020-12-28 08:21:47 +00:00
if state [ " update_pause " ] == 1 :
state [ " update_emoji " ] = " 🍿 "
2020-12-31 02:32:07 +00:00
if this_game . over :
2020-12-31 08:32:01 +00:00
state [ " display_inning " ] - = 1
state [ " display_top_of_inning " ] = False
2020-12-31 02:32:07 +00:00
winning_team = this_game . teams [ ' home ' ] . name if this_game . teams [ ' home ' ] . score > this_game . teams [ ' away ' ] . score else this_game . teams [ ' away ' ] . name
2020-12-31 08:32:01 +00:00
if this_game . victory_lap and winning_team == this_game . teams [ ' home ' ] . name :
state [ " update_text " ] = f " { winning_team } wins with a victory lap! "
elif winning_team == this_game . teams [ ' home ' ] . name :
state [ " update_text " ] = f " { winning_team } wins, shaming { this_game . teams [ ' away ' ] . name } ! "
else :
state [ " update_text " ] = f " { winning_team } wins! "
2020-12-31 02:32:07 +00:00
state [ " pitcher " ] = " - "
state [ " batter " ] = " - "
elif this_game . top_of_inning :
2020-12-28 08:21:47 +00:00
state [ " update_text " ] = f " Top of { this_game . inning } . { this_game . teams [ ' away ' ] . name } batting! "
else :
if this_game . inning > = this_game . max_innings :
if this_game . teams [ " home " ] . score > this_game . teams [ " away " ] . score :
2020-12-31 08:32:01 +00:00
this_game . victory_lap = True
2020-12-28 08:21:47 +00:00
state [ " update_text " ] = f " Bottom of { this_game . inning } . { this_game . teams [ ' home ' ] . name } batting! "
elif state [ " update_pause " ] != 1 and test_string != " Game not started. " :
if " steals " in this_game . last_update [ 0 ] . keys ( ) :
updatestring = " "
for attempt in this_game . last_update [ 0 ] [ " steals " ] :
updatestring + = attempt + " \n "
2021-01-06 01:38:02 +00:00
state [ " update_emoji " ] = " 💎 "
2020-12-28 08:21:47 +00:00
state [ " update_text " ] = updatestring
2021-01-02 10:42:14 +00:00
elif " mulligan " in this_game . last_update [ 0 ] . keys ( ) :
updatestring = " "
punc = " "
if this_game . last_update [ 0 ] [ " defender " ] != " " :
punc = " , "
state [ " update_emoji " ] = " 🏌️♀️ "
state [ " update_text " ] = f " { this_game . last_update [ 0 ] [ ' batter ' ] } would have gone out, but they took a mulligan! "
elif " snow_atbat " in this_game . last_update [ 0 ] . keys ( ) :
state [ " update_emoji " ] = " ❄ "
state [ " update_text " ] = this_game . last_update [ 0 ] [ " text " ]
2020-12-28 08:21:47 +00:00
else :
updatestring = " "
punc = " "
if this_game . last_update [ 0 ] [ " defender " ] != " " :
punc = " . "
2021-01-17 21:17:07 +00:00
2021-01-14 03:34:46 +00:00
2020-12-28 08:21:47 +00:00
if " fc_out " in this_game . last_update [ 0 ] . keys ( ) :
name , base_string = this_game . last_update [ 0 ] [ ' fc_out ' ]
updatestring = f " { this_game . last_update [ 0 ] [ ' batter ' ] } { this_game . last_update [ 0 ] [ ' text ' ] . value . format ( name , base_string ) } { this_game . last_update [ 0 ] [ ' defender ' ] } { punc } "
else :
updatestring = f " { this_game . last_update [ 0 ] [ ' batter ' ] } { this_game . last_update [ 0 ] [ ' text ' ] . value } { this_game . last_update [ 0 ] [ ' defender ' ] } { punc } "
if this_game . last_update [ 1 ] > 0 :
updatestring + = f " { this_game . last_update [ 1 ] } runs scored! "
2020-12-30 06:31:19 +00:00
state [ " update_emoji " ] = " 🏏 "
2020-12-28 08:21:47 +00:00
state [ " update_text " ] = updatestring
2021-01-14 03:34:46 +00:00
if " veil " in this_game . last_update [ 0 ] . keys ( ) :
2021-01-17 21:17:07 +00:00
state [ " update_emoji " ] = " 🌌 "
2021-01-14 04:21:28 +00:00
state [ " update_text " ] + = f " { this_game . last_update [ 0 ] [ ' batter ' ] } ' s will manifests on { games . base_string ( this_game . last_update [ 1 ] ) } base. "
2021-01-14 03:34:46 +00:00
elif " error " in this_game . last_update [ 0 ] . keys ( ) :
2021-01-14 04:21:28 +00:00
state [ " update_emoji " ] = " 👻 "
state [ " update_text " ] = f " { this_game . last_update [ 0 ] [ ' batter ' ] } ' s hit goes ethereal, and { this_game . last_update [ 0 ] [ ' defender ' ] } can ' t catch it! { this_game . last_update [ 0 ] [ ' batter ' ] } reaches base safely. "
2020-12-28 08:21:47 +00:00
state [ " bases " ] = this_game . named_bases ( )
2021-01-06 01:38:02 +00:00
state [ " top_of_inning " ] = this_game . top_of_inning
2020-12-28 08:21:47 +00:00
2021-01-07 08:10:53 +00:00
game_states . append ( [ game_id , state ] )
2020-12-28 08:21:47 +00:00
2020-12-31 08:32:01 +00:00
if state [ " update_pause " ] < = 1 and state [ " start_delay " ] < 0 :
2020-12-31 02:32:07 +00:00
if this_game . over :
2020-12-31 08:32:01 +00:00
state [ " update_pause " ] = 2
if state [ " end_delay " ] < 0 :
2021-01-06 17:24:59 +00:00
db . cache_history ( this_game . teams [ ' home ' ] . name , this_game . teams [ " home " ] . score , this_game . teams [ ' away ' ] . name , this_game . teams [ ' away ' ] . score , this_game . weather . name )
2021-01-07 22:58:46 +00:00
master_games_dic . pop ( game_id )
2021-01-01 17:08:11 +00:00
else :
state [ " end_delay " ] - = 1
2021-01-05 19:26:54 +00:00
master_games_dic [ game_id ] [ 1 ] [ " end_delay " ] - = 1
2020-12-31 02:32:07 +00:00
else :
this_game . gamestate_update_full ( )
2020-12-28 08:21:47 +00:00
state [ " update_pause " ] - = 1
2020-12-31 02:32:07 +00:00
2021-01-07 08:10:53 +00:00
socketio . emit ( " states_update " , game_states )
2021-01-04 04:18:45 +00:00
time . sleep ( 8 )