<s> """<STR_LIT>""" <EOL> import sys <EOL> from curtsies . fmtfuncs import * <EOL> from curtsies import FullscreenWindow , Input , fsarray <EOL> def main ( argv ) : <EOL> pool = dict ( ( name [ : - <NUM_LIT:5> ] , play ) for name , play in globals ( ) . items ( ) <EOL> if name . endswith ( '<STR_LIT>' ) ) <EOL> faceoff = [ human_play , max_play ] <EOL> try : <EOL> if len ( argv ) == <NUM_LIT:1> : <EOL> pass <EOL> elif len ( argv ) == <NUM_LIT:2> : <EOL> faceoff [ <NUM_LIT:1> ] = pool [ argv [ <NUM_LIT:1> ] ] <EOL> elif len ( argv ) == <NUM_LIT:3> : <EOL> faceoff = [ pool [ argv [ <NUM_LIT:1> ] ] , pool [ argv [ <NUM_LIT:2> ] ] ] <EOL> else : <EOL> raise KeyError <EOL> except KeyError : <EOL> print ( "<STR_LIT>" % argv [ <NUM_LIT:0> ] ) <EOL> print ( "<STR_LIT>" , '<STR_LIT:U+002CU+0020>' . join ( sorted ( pool ) ) ) <EOL> return <NUM_LIT:1> <EOL> else : <EOL> with Input ( ) as i : <EOL> with FullscreenWindow ( ) as w : <EOL> tictactoe ( w , i , * faceoff ) <EOL> return <NUM_LIT:0> <EOL> def tictactoe ( w , i , player , opponent , grid = None ) : <EOL> "<STR_LIT>" <EOL> grid = grid or empty_grid <EOL> while True : <EOL> w . render_to_terminal ( w . array_from_text ( view ( grid ) ) ) <EOL> if is_won ( grid ) : <EOL> print ( whose_move ( grid ) , "<STR_LIT>" ) <EOL> break <EOL> if not successors ( grid ) : <EOL> print ( "<STR_LIT>" ) <EOL> break <EOL> grid = player ( w , i , grid ) <EOL> player , opponent = opponent , player <EOL> def average ( ns ) : <EOL> return float ( sum ( ns ) ) / len ( ns ) <EOL> def memo ( f ) : <EOL> "<STR_LIT>" <EOL> table = { } <EOL> def memo_f ( * args ) : <EOL> try : <EOL> return table [ args ] <EOL> except KeyError : <EOL> table [ args ] = value = f ( * args ) <EOL> return value <EOL> return memo_f <EOL> def human_play ( w , i , grid ) : <EOL> "<STR_LIT>" <EOL> plaint = '<STR_LIT>' <EOL> prompt = whose_move ( grid ) + "<STR_LIT>" <EOL> while True : <EOL> w . render_to_terminal ( w . array_from_text ( view ( grid ) <EOL> + '<STR_LIT>' + plaint + prompt ) ) <EOL> key = c = i . next ( ) <EOL> try : <EOL> move = int ( key ) <EOL> except ValueError : <EOL> pass <EOL> else : <EOL> if <NUM_LIT:1> <= move <= <NUM_LIT:9> : <EOL> successor = apply_move ( grid , from_human_move ( move ) ) <EOL> if successor : return successor <EOL> plaint = ( "<STR_LIT>" <EOL> + ( grid_format <EOL> % tuple ( move if apply_move ( grid , from_human_move ( move ) ) else '<STR_LIT:->' <EOL> for move in range ( <NUM_LIT:1> , <NUM_LIT:10> ) ) <EOL> + '<STR_LIT>' ) ) <EOL> grid_format = '<STR_LIT:\n>' . join ( [ '<STR_LIT>' ] * <NUM_LIT:3> ) <EOL> def drunk_play ( w , i , grid ) : <EOL> "<STR_LIT>" <EOL> return min ( successors ( grid ) , key = drunk_value ) <EOL> def spock_play ( w , i , grid ) : <EOL> "<STR_LIT>" <EOL> return min ( successors ( grid ) , key = evaluate ) <EOL> def max_play ( w , i , grid ) : <EOL> "<STR_LIT>" <EOL> return min ( successors ( grid ) , <EOL> key = lambda succ : ( evaluate ( succ ) , drunk_value ( succ ) ) ) <EOL> @ memo <EOL> def drunk_value ( grid ) : <EOL> "<STR_LIT>" <EOL> if is_won ( grid ) : return - <NUM_LIT:1> <EOL> succs = successors ( grid ) <EOL> return - average ( map ( drunk_value , succs ) ) if succs else <NUM_LIT:0> <EOL> @ memo <EOL> def evaluate ( grid ) : <EOL> "<STR_LIT>" <EOL> if is_won ( grid ) : return - <NUM_LIT:1> <EOL> succs = successors ( grid ) <EOL> return - min ( map ( evaluate , succs ) ) if succs else <NUM_LIT:0> <EOL> empty_grid = <NUM_LIT:0> , <NUM_LIT:0> <EOL> def is_won ( grid ) : <EOL> "<STR_LIT>" <EOL> p , q = grid <EOL> return any ( way == ( way & q ) for way in ways_to_win ) <EOL> ways_to_win = ( <NUM_LIT> , <NUM_LIT> , <NUM_LIT> , <NUM_LIT> , <NUM_LIT> , <NUM_LIT> , <NUM_LIT> , <NUM_LIT> ) <EOL> def successors ( grid ) : <EOL> "<STR_LIT>" <EOL> return filter ( None , ( apply_move ( grid , move ) for move in range ( <NUM_LIT:9> ) ) ) <EOL> def apply_move ( grid , move ) : <EOL> "<STR_LIT>" <EOL> p , q = grid <EOL> bit = <NUM_LIT:1> << move <EOL> return ( q , p | bit ) if <NUM_LIT:0> == ( bit & ( p | q ) ) else None <EOL> def from_human_move ( n ) : <EOL> "<STR_LIT>" <EOL> return <NUM_LIT:9> - n <EOL> def whose_move ( grid ) : <EOL> "<STR_LIT>" <EOL> return player_marks ( grid ) [ <NUM_LIT:0> ] <EOL> def player_marks ( grid ) : <EOL> "<STR_LIT>" <EOL> p , q = grid <EOL> return '<STR_LIT>' if sum ( player_bits ( p ) ) == sum ( player_bits ( q ) ) else '<STR_LIT>' <EOL> def player_bits ( bits ) : <EOL> return ( ( bits >> i ) & <NUM_LIT:1> for i in reversed ( range ( <NUM_LIT:9> ) ) ) <EOL> def view ( grid ) : <EOL> "<STR_LIT>" <EOL> p_mark , q_mark = player_marks ( grid ) <EOL> return grid_format % tuple ( p_mark if by_p else q_mark if by_q else '<STR_LIT:.>' <EOL> for by_p , by_q in zip ( * map ( player_bits , grid ) ) ) <EOL> if __name__ == '<STR_LIT:__main__>' : <EOL> import sys <EOL> sys . exit ( main ( sys . argv ) ) </s>
