[
  {
    "path": ".gitignore",
    "content": "**/a.out\n**/.DS_Store\n"
  },
  {
    "path": "ACPCServer/LICENCE",
    "content": "Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicence, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nExcept as contained in this notice, the name(s) of the above copyright holders\nshall not be used in advertising or otherwise to promote the sale, use or other\ndealings in this Software without prior written authorization.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "ACPCServer/Makefile",
    "content": "CC = gcc\nCFLAGS = -O3 -Wall\n\nPROGRAMS = all_in_expectation bm_run_matches dealer example_player\n\nall: $(PROGRAMS)\n\nclean:\n\trm -f $(PROGRAMS)\n\n\nall_in_expectation: all_in_expectation.c game.c game.h rng.c rng.h net.c net.h\n\t$(CC) $(CFLAGS) -o $@ all_in_expectation.c game.c rng.c net.c\n\nbm_server: bm_server.c game.c game.h rng.c rng.h net.c net.h\n\t$(CC) $(CFLAGS) -o $@ bm_server.c game.c rng.c net.c\n\nbm_widget: bm_widget.c net.c net.h\n\t$(CC) $(CFLAGS) -o $@ bm_widget.c net.c\n\nbm_run_matches: bm_run_matches.c net.c net.h\n\t$(CC) $(CFLAGS) -o $@ bm_run_matches.c net.c\n\ndealer: game.c game.h evalHandTables rng.c rng.h dealer.c net.c net.h\n\t$(CC) $(CFLAGS) -o $@ game.c rng.c dealer.c net.c\n\nexample_player: game.c game.h evalHandTables rng.c rng.h example_player.c net.c net.h\n\t$(CC) $(CFLAGS) -o $@ game.c rng.c example_player.c net.c\n"
  },
  {
    "path": "ACPCServer/README",
    "content": "This README contains information about the server code for the Annual Computer\nPoker Competition.  Please see the LICENCE file for information regarding the\ncode's licence.\n\n===== Software Requirements =====\n\nThis code was developed and tested for use on Unix based systems.  Though it\nmay work on other platforms, there are no guarantees.\n\nYou will need standard Unix developer tools to build the software including\ngcc, and make.\n\n===== Getting Started =====\n\n* Building the code\n\nThe Makefile provides instructions for compiling the code.  Running 'make' from\nthe command line will compile the required programs.\n\n\n* The programs\n\ndealer - Communicates with agents connected over sockets to play a game\nexample_player - A sample player implemented in C\nplay_match.pl - A perl script for running matches with the dealer\n\nUsage information for each of the programs is available by running the\nexecutable without any arguments.\n\n\n* Playing a match\n\nThe fastest way to start a match is through the play_match.pl script.  An\nexample follows:\n\n$ ./play_match.pl matchName holdem.limit.2p.reverse_blinds.game 1000 0 Alice ./example_player.limit.2p.sh Bob ./example_player.limit.2p.sh\n\nAfter play_match.pl finishes running, there will be two output files for the\ndealer and two output files for each player in the game:\n\nmatchName.err - The stderr from dealer including the messages sent to players\nmatchName.log - The log for the hands played during the match\nmatchName.playerN.std - stdout from player N\nmatchName.playerN.err - stderr from player N\n\nNote, play_match.pl expects player executables that take exactly two arguments:\nthe server IP followed by the port number.  The executable must be specified\nsuch that it is either a path or the executable name if it can be found in your\n$PATH.\n\nIf you need to pass specific arguments to you agent, we suggest wrapping it in\nanother script.  play_match.pl will pass any extra arguments to dealer.\nMatches can also be started by calling dealer and starting the players\nmanually.  More information on this is contained in the dealer section below.\n\n\n* dealer\n\nRunning dealer will start a process that waits for other players to connect to\nit.  After starting dealer, it will output something similar to the following:\n\n$ ./dealer matchName holdem.limit.2p.reverse_blinds.game 1000 0 Alice Bob\n16177 48777\n# name/game/hands/seed matchName holdem.limit.2p.reverse_blinds.game 1000 0\n#--t_response 10000\n#--t_hand 600000\n#--t_per_hand 6000\n\nOn the first line of output there should be as many numbers as there are\nplayers in the game (in this case, \"16177\" and \"48777\").  These are the ports\nthe dealer is listening on for players.  Note that these ports are specific to\nthe positions for players in the game.\n\nOnce all the players have connected to the game, the dealer will begin playing\nthe game and outputting the messages sent to each player.  After the end of the\nmatch, you should have a log file called matchName.log in the directory where\ndealer was started with the hands that were played.\n\nMatches can also be started by starting the dealer and connecting the\nexecutables by hand.  This can be useful if you want to start your own program\nin a way that is difficult to script (such as running it in a debugger).\n\n\n==== Game Definitions ====\n\nThe dealer takes game definition files to determine which game of poker it\nplays.  Please see the included game definitions for some examples.  The code\nfor handling game definitions is found in game.c and game.h.\n\nGame definitions can have the following fields (case is ignored):\n\ngamedef - the starting tag for a game definition \nend gamedef - ending tag for a game definition\nstack - the stack size for each player at the start of each hand (for no-limit)\nblind - the size of the blinds for each player (relative to the dealer)\nraisesize - the size of raises on each round (for limit games)\nlimit - specifies a limit game\nnolimit - specifies a no-limit game\nnumplayers - number of players in the game\nnumrounds - number of betting rounds per hand of the game\nfirstplayer - the player that acts first (relative to the dealer) on each round\nmaxraises - the maximum number of raises on each round\nnumsuits - the number of different suits in the deck\nnumranks - the number of different ranks in the deck\nnumholecards - the number of private cards to deal to each player\nnumboardcards - the number of cards revealed on each round\n\nEmpty lines or lines with '#' as the very first character will be ignored\n\nIf you are creating your own game definitions, please note that game.h defines\nsome constants for maximums in games (e.g., number of rounds).  These may need\nto be changed for games outside of the what is being run for the Annual\nComputer Poker Competition.\n"
  },
  {
    "path": "ACPCServer/README.submission",
    "content": "#############################################################\n# Please fill out the following information about your team \n#############################################################\n\nTeam Name:\nAgent Name (can be the same as team name):\n\nFor each team member, please list the following:\nName, Team leader (y/n)?, e-mail, Academic (y/n, position - e.g., PhD student)?, University/Business affiliation, Location (city, province/state, country)\n\nWas this submission part of an academic class project?  What level of class\n(undergraduate/graduate)?\n\n\n###########################################################################\n# Please provide as much information about your agent as possible as the\n# competition organizers are very interested in knowing more about the\n# techniques used by our competitors.\n###########################################################################\n\n1) Is your agent dynamic?  That is, does its strategy change throughout the\ncourse of a match, or is the strategy played the same throughout the match?\n\n2) Does your agent use a (approximate) Nash equilibrium strategy?\n\n3) Does your agent attempt to model your opponents?  If so, does it do so\nonline during the competition or offline from data (e.g., using logs of play or\nthe benchmark server)?\n\n4) Does your agent use techniques that would benefit from additional CPU time\nduring the competition?\n\n5) Does your agent use techniques that would benefit from additional RAM during\nthe competition?\n\n6) Would you agent benefit from additional disk space?\n\nOne/Two Paragraph Summary of Technique\n\n\nReferences to relevant papers, if any\n\n"
  },
  {
    "path": "ACPCServer/acpc_play_match.pl",
    "content": "#!/usr/bin/perl\n\n# Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n\nuse Socket;\nuse File::Basename;\n\n$hostname = `hostname` or die \"could not get hostname\";\nchomp $hostname;\n@hostent = gethostbyname( $hostname );\n$#hostent >= 4 or die \"could not look up $hostname\";\n$hostip = inet_ntoa( $hostent[ 4 ] );\n\n$#ARGV >= 3 or die \"usage: play_match.pl matchName gameDefFile #Hands rngSeed player1name player1exe player2name player2exe ... [options]\";\n\n$numPlayers = -1;\nopen FILE, '<', $ARGV[ 1 ] or die \"couldn't open game definition $ARGV[ 1 ]\";\nwhile( $_ = <FILE> ) {\n\n    @_ = split;\n\n    if( uc( $_[ 0 ] ) eq 'NUMPLAYERS' ) {\n\t$numPlayers = $_[ $#_ ];\n    }\n}\nclose FILE;\n\n$numPlayers > 1 or die \"couldn't get number of players from $ARGV[ 1 ]\";\n\n\n$#ARGV >= 3 + $numPlayers * 2 or die \"too few players on command line\";\n\npipe STDINREADPIPE, STDINWRITEPIPE or die \"couldn't create stdin pipe\";\npipe STDOUTREADPIPE, STDOUTWRITEPIPE or die \"couldn't create stdout pipe\";\n\n$dealerPID = fork();\nif( $dealerPID == 0 ) {\n    # we're the child\n\n    # replace standard in and standard out with pipe\n    close STDINWRITEPIPE;\n    close STDOUTREADPIPE;\n    open STDIN, '<&STDINREADPIPE' or die \"can't dup STDIN\";\n    open STDOUT, '>&STDOUTWRITEPIPE' or die \"can't dup STDOUT\";\n    open STDERR, \">>$ARGV[ 0 ].err\" or die \"can't open log file $ARGV[ 0 ].err\";\n\n    @args = ( \"dealer\", $ARGV[ 0 ], $ARGV[ 1 ],\n\t      $ARGV[ 2 ], $ARGV[ 3 ] );\n\n    # add names to the arguments\n    for( $p = 0; $p < $numPlayers; ++$p ) {\n\tpush @args, $ARGV[ 4 + $p * 2 ];\n    }\n\n    # add any extra arguments (options?) to the arguments\n    for( $i = 4 + $numPlayers * 2; $i <= $#ARGV; ++$i ) {\n\tpush @args, $ARGV[ $i ];\n    }\n    exec { \"./dealer\" } @args or die \"Couldn't run dealer\";\n}\n\nclose STDINREADPIPE;\nclose STDOUTWRITEPIPE;\n\n$_ = <STDOUTREADPIPE> or die \"couldn't read port description from dealer\";\n@_ = split;\n$#_ + 1 >= $numPlayers or die \"couldn't get enough ports from $_\";\n\nfor( $p = 0; $p < $numPlayers; ++$p ) {\n\n    $playerPID[ $p ] = fork();\n\n    if( $playerPID[ $p ] == 0 ) {\n\t# we're the child\n\n\t# log standard out and standard error\n\topen STDOUT, \">$ARGV[ 0 ].player$p.std\"\n\t    or die \"can't dup player $p STDOUT\";\n\topen STDERR, \">$ARGV[ 0 ].player$p.err\"\n\t    or die \"can't dup player $p STDERR\";\n\n\t($playerExec, $playerDir) = fileparse( $ARGV[ 4 + $p * 2 + 1 ] );\n\tchdir $playerDir or die \"Can't cd to $playerDir: $!\\n\";\n\texec { \"./$playerExec\" } ( \"./$playerExec\", $hostip, $_[ $p ] )\n\t    or die \"couldn't run $playerExec from $playerDir for player $p\";\n    }\n}\n\n$_ = <STDOUTREADPIPE>;\n\nfor( $p = 0; $p < $numPlayers; ++$p ) {\n    waitpid( $playerPID[ $p ], 0 );\n}\n\nwaitpid( $dealerPID, 0 );\n\n$_ or die \"couldn't get values from dealer\";\n\nprint $_;\n\nexit( 0 );\n"
  },
  {
    "path": "ACPCServer/all_in_expectation.c",
    "content": "/*\nCopyright (C) 2014 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdio.h>\n#define __STDC_LIMIT_MACROS\n#include <stdint.h>\n#include <unistd.h>\n#include <string.h>\n#include <sys/socket.h>\n#include <sys/time.h>\n#include <sys/select.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include <getopt.h>\n#include \"game.h\"\n#include \"net.h\"\n\n\nvoid getUsedCards( const Game *game,\n\t\t   const State *state,\n\t\t   const int lastRound,\n\t\t   uint8_t *used )\n{\n  int i, p;\n\n  /* start with no cards used */\n  memset( used, 0, sizeof( used[ 0 ] ) * game->numSuits * game->numRanks );\n\n  /* collect the player cards */\n  for( p = 0; p < game->numPlayers; ++p ) {\n\n    for( i = 0; i < game->numHoleCards; ++i ) {\n\n      used[ state->holeCards[ p ][ i ] ] = 1;\n    }\n  }\n\n  /* collect the board cards up to lastRound */\n  p = sumBoardCards( game, lastRound );\n  for( i = 0; i < p; ++i ) {\n\n    used[ state->boardCards[ i ] ] = 1;\n  }\n}\n\nint main( int argc, char **argv )\n{\n  int stateEnd, r, i, p, deckSize, numBoards;\n  FILE *file;\n  Game *game;\n  State state;\n  uint8_t deck[ MAX_SUITS * MAX_RANKS ];\n  uint8_t used[ MAX_SUITS * MAX_RANKS ];\n  double value[ MAX_PLAYERS ];\n  char line[ 4096 ];\n\n  if( argc < 3 ) {\n\n    fprintf( stderr, \"USAGE: %s game_def log_file\\n\", argv[ 0 ] );\n    exit( EXIT_FAILURE );\n  }\n\n  /* get the game definition */\n  file = fopen( argv[ 1 ], \"r\" );\n  if( file == NULL ) {\n\n    fprintf( stderr, \"ERROR: could not open game definition %s\\n\", argv[ 1 ] );\n    exit( EXIT_FAILURE );\n  }\n  game = readGame( file );\n  if( game == NULL ) {\n\n    fprintf( stderr, \"ERROR: could not read game %s\\n\", argv[ 1 ] );\n    exit( EXIT_FAILURE );\n  }\n  fclose( file );\n\n  /* get the log file */\n  file = fopen( argv[ 2 ], \"r\" );\n  if( file == NULL ) {\n\n    fprintf( stderr, \"ERROR: could not open log file %s\\n\", argv[ 2 ] );\n    exit( EXIT_FAILURE );\n  }\n\n  /* read every line and process all hands */\n  while( fgets( line, 4096, file ) ) {\n\n    stateEnd = readState( line, game, &state );\n    if( stateEnd < 0 ) {\n      /* couldn't read a state from the line */\n\n      continue;\n    }\n\n    if( numAllIn( game, &state ) == 0\n\t|| numFolded( game, &state ) + 1 >= game->numPlayers ) {\n      /* no one all in, or game didn't end in a showdown */\n\n      printf( \"%s\", line );\n      continue;\n    }\n\n    /* find last round where someone made an action */\n    for( r = state.round; r > 0; --r ) {\n\n      if( state.numActions[ r ] ) {\n\n\tbreak;\n      }\n    }\n\n    if( r + 1 == game->numRounds ) {\n      /* there are no board cards left to roll out on the final round */\n\n      printf( \"%s\", line );\n      continue;\n    }\n\n    /* initialise values to 0 */\n    memset( value, 0, sizeof( value ) );\n\n    /* set up a deck containing all cards up to round r */\n    getUsedCards( game, &state, r, used );\n    deckSize = 0;\n    for( i = 0; i < game->numSuits * game->numRanks; ++i ) {\n\n      if( !used[ i ] ) {\n\n\tdeck[ deckSize ] = i;\n\t++deckSize;\n      }\n    }\n\n    /* switch to using used[] as the index into deck[]\n       for the remaining cards used on the board\n       sort hands in ascending order, start with highest indexed hand */\n    const int bcStart = sumBoardCards( game, r );\n    const int numCards = sumBoardCards( game, game->numRounds - 1 ) - bcStart;\n    for( i = 0; i < numCards; ++i ) {\n\n      used[ i ] = deckSize - numCards + i;\n      state.boardCards[ bcStart + i ] = deck[ used[ i ] ];\n    }\n\n    /* try every possible board */\n    numBoards = 0;\n    while( 1 ) {\n\n      /* get the values */\n      for( p = 0; p < game->numPlayers; ++p ) {\n\n\tvalue[ p ] += valueOfState( game, &state, p );\n      }\n\n      /* move on to the next board */\n      ++numBoards;\n\n      /* find position of first card we can decrement */\n      i = 0;\n      while( used[ i ] == i && i < numCards ) {\n\n\t++ i;\n      }\n      if( i == numCards ) {\n\t/* can't decrement any cards, so we're done */\n\n\tbreak;\n      }\n\n      /* decrement the card */\n      --used[ i ];\n      state.boardCards[ bcStart + i ] = deck[ used[ i ] ];\n\n      /* fill in all earlier cards with highest possible index */\n      while( i > 0 ) {\n\n\t/* move to previous card, set index to one lower then current card */\n\t--i;\n\tused[ i ] = used[ i + 1 ] - 1;\n\tstate.boardCards[ bcStart + i ] = deck[ used[ i ] ];\n      }\n    }\n\n    /* do the printout - start with the state */\n    if( line[ stateEnd ] != 0 ) {\n\n      if( line[ stateEnd ] != ':' && line[ stateEnd ] != '\\n' ) {\n\n\tfprintf( stderr, \"ERROR: expected input of STATE:VALUES:PLAYERS\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      line[ stateEnd ] = 0;\n      ++stateEnd;\n    }\n    printf( \"%s:\", line );\n\n    /* print out the averaged values */\n    for( p = 0; p < game->numPlayers; ++p ) {\n\n      printf( p ? \"|%lf\" : \"%lf\", value[ p ] / (double)numBoards );\n    }\n\n    /* find the player names in the state line */\n    for( i = stateEnd; line[ i ] && line[ i ] != ':'; ++i );\n    if( line[ i ] == ':' ) {\n\n      printf( \"%s\", &line[ i ] );\n    } else {\n\n      printf( \"\\n\" );\n    }\n  }\n\n  fclose( file );\n  exit( EXIT_SUCCESS );\n}\n"
  },
  {
    "path": "ACPCServer/bm_run_matches.c",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#define __STDC_FORMAT_MACROS\n#include <inttypes.h>\n#include <assert.h>\n#include <string.h>\n#include <unistd.h>\n#include <netdb.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include <sys/wait.h>\n#include <errno.h>\n#include \"net.h\"\n\n#define ARG_SERVERNAME 1\n#define ARG_SERVERPORT 2\n#define ARG_BOT_COMMAND 7\n#define ARG_MIN_ARGS 6\n\nstatic void printUsage( FILE *file )\n{\n  fprintf( file, \"Sample usages:\\n\" );\n  fprintf( file, \"  bm_run_matches <bm_hostname> <bm_port> <username> <pw> \"\n\t   \"games\\n\" );\n  fprintf( file, \"    See a list of possible opponents\\n\" );\n  fprintf( file, \"  bm_run_matches <bm_hostname> <bm_port> <username> <pw> \"\n\t   \"run 2pl <local script> <# runs> <tag> <seed> <player1> \"\n\t   \"<player2>\\n\" );\n  fprintf( file, \"    Run two-player limit matches\\n\" );\n  fprintf( file, \"  bm_run_matches <bm_hostname> <bm_port> <username> <pw> \"\n\t   \"run 2pn <local script> <# runs> <tag> <seed> <player1> \"\n\t   \"<player2>\\n\" );\n  fprintf( file, \"    Run two-player no-limit matches\\n\" );\n  fprintf( file, \"  bm_run_matches <bm_hostname> <bm_port> <username> <pw> \"\n\t   \"run 3pl <local script> <# runs> <tag> <seed> <player1> <player2> \"\n\t   \"<player3>\\n\" );\n  fprintf( file, \"    Run three-player limit matches\\n\" );\n  fprintf( file, \"  bm_run_matches <bm_hostname> <bm_port> <username> <pw> \"\n\t   \"rerun 2pl <local script> <match index> <tag> <seed> <player1> \"\n\t   \"<player2> (<player3>)\\n\" );\n  fprintf( file, \"    Rerun a match that failed\\n\" );\n  fprintf( file, \"\\n\" );\n  fprintf( file, \"<username> is your benchmark server username assigned to \"\n\t   \"you by the competition chair\\n\" );\n  fprintf( file, \"<pw> is your benchmark server password assigned to you by \"\n\t   \"the competition chair\\n\" );\n  fprintf( file, \"<local script> is the script that runs your agent locally.  \"\n\t   \"It must take a hostname/IP and a port\\n\" );\n  fprintf( file, \"<num runs> is the number of matches you want to run\\n\" );\n  fprintf( file, \"<tag> is a name for this set of matches which will appear \"\n\t   \"in the names of the log files\\n\" );\n  fprintf( file, \"<seed> is a seed used to generate the random seeds that \"\n\t   \"determine the cards in each match\\n\" );\n  fprintf( file, \"<player-n> is either the name of an opponent or \\\"local\\\" \"\n\t   \"for your local agent\\n\" );\n  fprintf( file, \"\\n\" );\n  fprintf( file, \"To run N duplicate heads-up matches, do one run of N \"\n\t   \"matches with a given seed, then run a second set of N matches \"\n\t   \"with the same seed but the order of the players reversed\\n\" );\n  fprintf( file, \"\\n\" );\n  fprintf( file, \"If one match in a set fails, you can use the \\\"rerun\\\" \"\n\t   \"command to rerun the specified match with the specified seed.  \"\n\t   \"For example, if you tried to run twenty matches with seed 0 and \"\n\t   \"the last match failed, you could use the \\\"rerun\\\" command with \"\n\t   \"seed 0 and match index 19.\\n\" );\n}\n\nint main( int argc, char **argv )\n{\n  int sock, i;\n  pid_t childPID;\n  uint16_t port;\n  ReadBuf *fromServer;\n  fd_set readfds;\n  char line[ READBUF_LEN ];\n\n  if( argc < ARG_MIN_ARGS ) {\n\n    printUsage( stderr );\n    exit( EXIT_FAILURE );\n  }\n\n  /* connect to the server */\n  if( sscanf( argv[ ARG_SERVERPORT ], \"%\"SCNu16, &port ) < 1 ) {\n\n    fprintf( stderr, \"ERROR: invalid port %s\\n\", argv[ ARG_SERVERPORT ] );\n    exit( EXIT_FAILURE );\n  }\n  sock = connectTo( argv[ ARG_SERVERNAME ], port );\n  if( sock < 0 ) {\n\n    exit( EXIT_FAILURE );\n  }\n\n  // EJ additions 9/3/2012\n  // Turn on keep-alive for socket connection with more frequent checking\n  // than the Linux default.  What I've observed is that if a socket\n  // connection is idle for long enough it gets dropped.  This only\n  // happens for some users.\n  int on = 1;\n  if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) {\n    fprintf( stderr, \"ERROR: setsockopt failed; errno %i\\n\", errno );\n    exit( EXIT_FAILURE );\n  }\n#ifdef __linux__\n  // Not sure what this should be\n  int num_before_failure = 2;\n  if (setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &num_before_failure,\n\t\t sizeof(num_before_failure)) == -1) {\n    fprintf( stderr, \"ERROR: setsockopt failed; errno %i\\n\", errno );\n    exit( EXIT_FAILURE );\n  }\n  // First check after 60 seconds\n  int initial_secs = 60;\n  if (setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &initial_secs,\n\t\t sizeof(initial_secs)) == -1) {\n    fprintf( stderr, \"ERROR: setsockopt failed; errno %i\\n\", errno );\n    exit( EXIT_FAILURE );\n  }\n  // Thereafter, also check every 60 seconds\n  int interval_secs = 60;\n  if (setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &interval_secs,\n\t\t sizeof(interval_secs)) == -1) {\n    fprintf( stderr, \"ERROR: setsockopt failed; errno %i\\n\", errno );\n    exit( EXIT_FAILURE );\n  }\n#endif\n\n  /* set up read buffers */\n  fromServer = createReadBuf( sock );\n\n  /* write to server */\n  line[0] = 0;\n  for( i = 3; i < argc; ++i ) {\n    strcat( line, argv[i] );\n    if ( i < argc - 1 ) {\n      strcat( line, \" \" );\n    }\n  }\n  strcat( line, \"\\n\" );\n  int len = strlen(line);\n  if( write( sock, line, len ) < 0 ) {\n    \n    fprintf( stderr, \"ERROR: failed while sending to server\\n\" );\n    exit( EXIT_FAILURE );\n  }\n\n  /* main loop */\n  while( 1 ) {\n\n    /* clean up any children */\n    while( waitpid( -1, NULL, WNOHANG ) > 0 );\n\n    /* wait for input */\n    FD_ZERO( &readfds );\n    FD_SET( sock, &readfds );\n    i = select( sock + 1, &readfds, NULL, NULL, NULL );\n    if( i < 0 ) {\n\n      fprintf( stderr, \"ERROR: select failed\\n\" );\n      exit( EXIT_FAILURE );\n    }\n    if( i == 0 ) {\n      /* nothing ready - shouldn't happen without timeout */\n\n      continue;\n    }\n\n    /* handle server messages */\n    if( FD_ISSET( sock, &readfds ) ) {\n\n      /* get the input */\n      while( ( i = getLine( fromServer, READBUF_LEN, line, 0 ) ) >= 0 ) {\n\n\tif( i == 0 ) {\n\n\t  /* This could be an error or could just signify successful\n\t     completion of all matches */\n\t  fprintf( stderr, \"Server closed connection\\n\" );\n\t  exit( EXIT_SUCCESS );\n\t}\n\n\t/* check for server commands */\n\tif( strncasecmp( line, \"run \", 4 ) == 0 ) {\n\n\t  /* split the rest of the line into name ' ' port */\n\t  for( i = 4; line[ i ]; ++i ) {\n\n\t    if( line[ i ] == ' ' ) {\n\t      /* found the separator */\n\n\t      line[ i ] = 0;\n\t      break;\n\t    }\n\t  }\n\n\t  printf( \"starting match %s:%s\", &line[ 4 ], &line[ i + 1 ] );\n\t  fflush( stdout );\n\n\t  /* run `command machine port` */\n\t  childPID = fork();\n\t  if( childPID < 0 ) {\n\n\t    fprintf( stderr, \"ERROR: fork() failed\\n\" );\n\t    exit( EXIT_FAILURE );\n\t  }\n\t  if( childPID == 0 ) {\n\t    /* child runs the command */\n\n\t    execl( argv[ ARG_BOT_COMMAND ],\n\t\t   argv[ ARG_BOT_COMMAND ],\n\t\t   &line[ 4 ],\n\t\t   &line[ i + 1 ],\n\t\t   NULL );\n\t    fprintf( stderr,\n\t\t     \"ERROR: could not run %s\\n\",\n\t\t     argv[ ARG_BOT_COMMAND ] );\n\t    exit( EXIT_FAILURE );\n\t  }\n\t} else {\n\t  /* just a message, print it out */\n\n\t  if( fwrite( line, 1, i, stdout ) < 0 ) {\n\n\t    fprintf( stderr, \"ERROR: failed while printing server message\\n\" );\n\t    exit( EXIT_FAILURE );\n\t  }\n\t  fflush( stdout );\n\n\t  if( ! strcmp( line, \"Matches finished\\n\") ) {\n\t    exit( EXIT_SUCCESS );\n\t  }\n\t}\n      }\n    }\n  }\n\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "ACPCServer/bm_server.c",
    "content": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdio.h>\n#define __STDC_FORMAT_MACROS\n#include <inttypes.h>\n#include <assert.h>\n#include <string.h>\n#include <strings.h>\n#include <ctype.h>\n#include <unistd.h>\n#include <netdb.h>\n#include <sys/socket.h>\n#include <sys/types.h>\n#include <arpa/inet.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include <sys/wait.h>\n#include <sys/time.h>\n#include <time.h>\n#include <signal.h>\n#include <fcntl.h>\n#include \"game.h\"\n#include \"net.h\"\n#include \"rng.h\"\n\n\n#define STATUS_CLOSED 0\n#define STATUS_UNVALIDATED 1\n#define STATUS_OKAY 2\n\n#define BM_DEALER \"dealer\"\n#define BM_LOGDIR \"logs\"\n#define BM_DEALER_WAIT_SECS 5\n#define BM_MAX_IOWAIT_SECS 1\n\n\ntypedef struct LLPoolEntry_struct {\n  struct LLPoolEntry_struct *next;\n  struct LLPoolEntry_struct *prev;\n  char data[ 0 ];\n} LLPoolEntry;\n\ntypedef struct {\n  LLPoolEntry *head;\n  LLPoolEntry *free;\n  int dataSize;\n  int numEntries;\n} LLPool;\n\n/* structure giving the specification for a local bot */\ntypedef struct {\n  char *name;\n  char *command;\n} BotSpec;\n\n/* structure giving the specification for a user */\ntypedef struct {\n  char *name;\n  char *passwd;\n  struct timeval waitStart;\n} UserSpec;\n\ntypedef struct {\n  uint16_t maxMatchRuns; /* maximum number of runs for a match */\n  uint16_t maxRunningJobs; /* maximum simultaneous jobs at a time for game\n\t\t\t      0 disables the check */\n  uint32_t matchHands; /* number of hands in a match */\n  Game *game;\n  char *gameFile;\n  LLPool *bots;\n\n  int curRunningJobs;\n} GameConfig;\n\ntypedef struct {\n  uint16_t port;\n  uint16_t maxRunningBots; /* maximum simultaneous bots at a time\n\t\t\t      0 disables the check */\n  uint16_t startupTimeoutSecs; /* maximum time to wait for clients to connect\n\t\t\t\t  0 disables the timer */\n  uint16_t responseTimeoutSecs; /* maximum time to wait for clients to respond\n                                   with an action */\n  uint16_t handTimeoutSecs; /* maximum time to allowed per hand of play */\n  uint16_t avgHandTimeSecs; /* average time per hand allowed for the match */\n\n  LLPool *games;\n  LLPool *users;\n} Config;\n\ntypedef struct {\n  int status;\n  UserSpec *user; /* NULL when status is STATUS_UNVALIDATED */\n  ReadBuf *connBuf;\n} Connection;\n\ntypedef struct {\n  GameConfig *gameConf;\n  UserSpec *user;\n  int numRuns;\n  rng_state_t rng;\n  uint32_t rngSeed;\n  int useRngForSeed; /* 0: use rngSeed as seed for each dealer run\n\t\t\t1: use genrand_int32( match->rng ) */\n  char *tag;\n  struct timeval queueTime;\n  struct {\n    int isNetworkPlayer;\n    LLPoolEntry *entry; /* connection if network player, bot otherwise */\n  } players[ MAX_PLAYERS ];\n  int isRunning;\n} Match;\n\ntypedef struct {\n  pid_t dealerPID;\n  pid_t botPID[ MAX_PLAYERS ];\n  LLPoolEntry *matchEntry;\n  char *tag; /* based on tag from the match for this job */\n  uint16_t ports[ MAX_PLAYERS ];\n} MatchJob;\n\ntypedef struct {\n  int listenSocket;\n  LLPool *conns;\n  LLPool *matches;\n  LLPool *jobs;\n\n  rng_state_t rng;\n\n  char *hostname;\n\n  int devnullfd;\n} ServerState;\n\n\nLLPool *newLLPool( const int dataSize )\n{\n  LLPool *pool;\n\n  pool = (LLPool*)malloc( sizeof( LLPool ) );\n  assert( pool != 0 );\n  pool->head = NULL;\n  pool->free = NULL;\n  pool->dataSize = dataSize;\n  pool->numEntries = 0;\n  return pool;\n}\n\nint entryInList( LLPoolEntry *list, LLPoolEntry *entry )\n{\n  while( list ) {\n\n    if( entry == list ) {\n\n      return 1;\n    }\n    if( list->next ) {\n\n      assert( list->next->prev == list );\n    }\n    list = list->next;\n  }\n  return 0;\n}\n\n/* add an object to the pool.  data must have a size of pool->dataSize */\nLLPoolEntry *LLPoolAddItem( LLPool *pool, void *item )\n{\n  LLPoolEntry *entry;\n\n  if( pool->free ) {\n\n    entry = pool->free;\n    pool->free = entry->next;\n  } else {\n\n    entry = (LLPoolEntry*)malloc( sizeof( LLPoolEntry ) + pool->dataSize );\n    assert( entry != 0 );\n  }\n\nassert( !entryInList( pool->head, entry ) );\n  entry->next = pool->head;\n  entry->prev = NULL;\n  memcpy( entry->data, item, pool->dataSize );\n  if( pool->head ) {\n\n    pool->head->prev = entry;\n  }\n  pool->head = entry;\n\n  ++pool->numEntries;\n\n  return entry;\n}\n\n/* remove an item from the pool, placing it in the free list.\n   entry must have been generated by LLPoolAddItem( pool, ... )\n   (that is, calling LLPoolRemoveEntry on an entry from another pool\n   is potentially a very bad idea...) */\nvoid LLPoolRemoveEntry( LLPool *pool, LLPoolEntry *entry )\n{\n  if( entry->prev ) {\n\nassert( entry->prev->next == entry );\n    entry->prev->next = entry->next;\n  } else {\n\nassert( pool->head == entry );\n    pool->head = entry->next;\n  }\n  if( entry->next ) {\n\nassert( entry->next->prev == entry );\n    entry->next->prev = entry->prev;\n  }\n\nassert( !entryInList( pool->free, entry ) );\n  if( pool->free ) {\n\n    pool->free->prev = entry;\n  }\n  entry->next = pool->free;\n  pool->free = entry;\n\n  --pool->numEntries;\n}\n\n/* LLPool iterator start */\nLLPoolEntry *LLPoolFirstEntry( LLPool *pool )\n{\n  return pool->head;\n}\n\n/* removing entries while iterating through the list is fine, as\n   long as cur is not the entry being removed. */\nLLPoolEntry *LLPoolNextEntry( LLPoolEntry *cur )\n{\n  if( cur ) {\n\n    return cur->next;\n  }\n  return NULL;\n}\n\nvoid *LLPoolGetItem( LLPoolEntry *entry )\n{\n  return &entry->data;\n}\n\n\nvoid printUsage( FILE *file )\n{\n  fprintf( file, \"usage: bm_server config_file\\n\" );\n}\n\nvoid setGameDefaults( GameConfig *gameConf )\n{\n  gameConf->maxMatchRuns = 10;\n  gameConf->maxRunningJobs = 1;\n  gameConf->matchHands = 5000;\n  gameConf->game = NULL;\n  gameConf->gameFile = NULL;\n  gameConf->bots = newLLPool( sizeof( BotSpec ) );\n\n  gameConf->curRunningJobs = 0;\n}\n\nvoid setDefaults( Config *conf )\n{\n  conf->port = 54000;\n  conf->maxRunningBots = 0;\n  conf->startupTimeoutSecs = 600;\n  conf->responseTimeoutSecs = 6000; /* Value from 2011 ACPC */\n  conf->handTimeoutSecs = 3000 * 7; /* Not enforced for 2011 ACPC */\n  conf->avgHandTimeSecs = 70; /* Value from 2011 ACPC */\n  conf->games = newLLPool( sizeof( GameConfig ) );\n  conf->users = newLLPool( sizeof( UserSpec ) );\n}\n\n/* returns entry for bot on success, NULL on failure */\nLLPoolEntry *findBot( const GameConfig *game, const char *name )\n{\n  LLPoolEntry *cur;\n\n  for( cur = LLPoolFirstEntry( game->bots );\n       cur != NULL; cur = LLPoolNextEntry( cur ) ) {\n\n    if( !strcmp( ( (BotSpec *)LLPoolGetItem( cur ) )->name, name ) ) {\n\n      return cur;\n    }\n  }\n\n  return NULL;\n}\n\nvoid addBot( GameConfig *gameConf, const char *spec )\n{\n  BotSpec bot;\n  char name[ READBUF_LEN ];\n  char command[ READBUF_LEN ];\n\n  /* split the line into name and command */\n  if( sscanf( spec, \" %s %s\", name, command ) < 2 ) {\n\n    fprintf( stderr, \"BM_ERROR: could not get bot name and command from: %s\",\n\t     spec );\n    exit( EXIT_FAILURE );\n  }\n\n  /* make sure there are no duplicates */\n  if( !strcmp( name, \"LOCAL\" ) ) {\n\n    fprintf( stderr, \"BM_ERROR: LOCAL is a reserved bot name\\n\" );\n    exit( EXIT_FAILURE );\n  }\n  if( findBot( gameConf, name ) ) {\n\n    fprintf( stderr, \"BM_ERROR: duplicate bot %s\\n\", name );\n    exit( EXIT_FAILURE );\n  }\n\n  /* add the bot */\n  bot.name = strdup( name );\n  bot.command = strdup( command );\n  LLPoolAddItem( gameConf->bots, &bot );\n}\n\n/* returns entry for user on success, NULL on failure */\nLLPoolEntry *findUser( const Config *conf, const char *name )\n{\n  LLPoolEntry *cur;\n\n  for( cur = LLPoolFirstEntry( conf->users );\n       cur != NULL; cur = LLPoolNextEntry( cur ) ) {\n\n    if( !strcmp( ( (UserSpec *)LLPoolGetItem( cur ) )->name, name ) ) {\n\n      return cur;\n    }\n  }\n\n  return NULL;\n}\n\nvoid addUser( Config *conf, const char *spec )\n{\n  UserSpec user;\n  char name[ READBUF_LEN ];\n  char passwd[ READBUF_LEN ];\n\n  /* split the line into name and password */\n  if( sscanf( spec, \" %s %s\", name, passwd ) < 2 ) {\n\n    fprintf( stderr, \"BM_ERROR: could not get user name and password from: %s\",\n\t     spec );\n    exit( EXIT_FAILURE );\n  }\n\n  /* make sure there are no duplicates */\n  if( findUser( conf, name ) ) {\n\n    fprintf( stderr, \"BM_ERROR: duplicate user %s\\n\", name );\n    exit( EXIT_FAILURE );\n  }\n\n  /* add the user */\n  user.name = strdup( name );\n  user.passwd = strdup( passwd );\n  gettimeofday( &user.waitStart, NULL );\n  LLPoolAddItem( conf->users, &user );\n}\n\n/* returns entry for game on success, NULL on failure */\nLLPoolEntry *findGame( const Config *conf, const char *name )\n{\n  LLPoolEntry *cur;\n\n  for( cur = LLPoolFirstEntry( conf->games );\n       cur != NULL; cur = LLPoolNextEntry( cur ) ) {\n\n    if( !strcmp( ( (GameConfig *)LLPoolGetItem( cur ) )->gameFile, name ) ) {\n\n      return cur;\n    }\n  }\n\n  return NULL;\n}\n\n/* validate a logon request\n   returns user on success, or NULL on failure */\nUserSpec *validateLogon( const Config *conf, const char *line )\n{\n  LLPoolEntry *cur;\n  char name[ READBUF_LEN ];\n  char passwd[ READBUF_LEN ];\n\n  if( sscanf( line, \" %s %s\", name, passwd ) < 2 ) {\n\n    return NULL;\n  }\n\n  for( cur = LLPoolFirstEntry( conf->users );\n       cur != NULL; cur = LLPoolNextEntry( cur ) ) {\n    UserSpec *user = (UserSpec *)LLPoolGetItem( cur );\n\n    if( !strcmp( user->name, name ) ) {\n\n      if( !strcmp( user->passwd, passwd ) ) {\n\n\treturn user;\n      }\n      return NULL;\n    }\n  }\n\n  return NULL;\n}\n\nvoid readConfig( const char *filename, Config *conf )\n{\n  int start;\n  FILE *file;\n  GameConfig *gameConf;\n  char *line, lineBuf[ READBUF_LEN ];\n\n  file = fopen( filename, \"r\" );\n  if( file == NULL ) {\n\n    fprintf( stderr, \"BM_ERROR: could not open configuration file %s\\n\",\n\t     filename );\n    exit( EXIT_FAILURE );\n  }\n\n  gameConf = NULL;\n  while( fgets( lineBuf, READBUF_LEN, file ) ) {\n\n    /* skip past white space at start of line */\n    start = 0; while( isspace( lineBuf[ start ] ) ) { ++start; }\n    line = &lineBuf[ start ];\n\n    /* ignore comments or empty lines */\n    if( line[ 0 ] == '#' || line[ 0 ] == ';'\n\t|| line[ 0 ] == '\\n' || line[ 0 ] == 0 ) {\n      continue;\n    }\n\n    if( strncasecmp( line, \"port\", 4 ) == 0 ) {\n\n      if( gameConf != NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: server port must be defined outside of game blocks\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      if( sscanf( &line[ 4 ], \"%\"SCNu16, &conf->port ) < 1 ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not get port from: %s\", line );\n\texit( EXIT_FAILURE );\n      }\n    } else if( strncasecmp( line, \"game\", 4 ) == 0 ) {\n      FILE *file;\n      GameConfig gc;\n      char game[ READBUF_LEN ];\n\n      if( gameConf != NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: can't define a game within another game block\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      if( sscanf( &line[ 4 ], \" %s\", game ) < 1 ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not get game name from: %s\", line );\n\texit( EXIT_FAILURE );\n      }\n      if( findGame( conf, game ) ) {\n\n\tfprintf( stderr, \"BM_ERROR: game %s has already been used\\n\", game );\n\texit( EXIT_FAILURE );\n      }\n\n      setGameDefaults( &gc );\n      gc.gameFile = strdup( game );\n\n      file = fopen( gc.gameFile, \"r\" );\n      if( file == NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not open game file %s\\n\", gc.gameFile );\n\texit( EXIT_FAILURE );\n      }\n      gc.game = readGame( file );\n      fclose( file );\n\n      if( gc.game == NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not read game %s\", gc.gameFile );\n\texit( EXIT_FAILURE );\n      }\n      gameConf\n\t= (GameConfig *)LLPoolGetItem( LLPoolAddItem( conf->games, &gc ) );\n    } else if( strncmp( line, \"}\", 1 ) == 0 ) {\n      /* finished game definition */\n\n      gameConf = NULL;\n    } else if( strncasecmp( line, \"maxRunningBots\", 14 ) == 0 ) {\n\n      if( gameConf != NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: maxRunningBots must be defined outside of game blocks\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      if( sscanf( &line[ 14 ], \"%\"SCNu16, &conf->maxRunningBots ) < 1 ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not get maximum number of bots running from: %s\", line );\n\texit( EXIT_FAILURE );\n      }\n    } else if( strncasecmp( line, \"startupTimeoutSecs\", 18 ) == 0 ) {\n\n      if( gameConf != NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: startupTimeoutSecs must be defined outside of game blocks\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      if( sscanf( &line[ 18 ], \"%\"SCNu16, &conf->startupTimeoutSecs ) < 1 ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not get maximum dealer startup timeout: %s\", line );\n\texit( EXIT_FAILURE );\n      }\n    } else if( strncasecmp( line, \"responseTimeoutSecs\", 19 ) == 0 ) {\n\n      if( gameConf != NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: responseTimeoutSecs must be defined outside of game blocks\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      if( sscanf( &line[ 19 ], \"%\"SCNu16, &conf->responseTimeoutSecs ) < 1 ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not get maximum dealer action timeout: %s\", line );\n\texit( EXIT_FAILURE );\n      }\n    } else if( strncasecmp( line, \"handTimeoutSecs\", 15 ) == 0 ) {\n\n      if( gameConf != NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: handTimeoutSecs must be defined outside of game blocks\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      if( sscanf( &line[ 15 ], \"%\"SCNu16, &conf->handTimeoutSecs ) < 1 ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not get maximum dealer hand timeout: %s\", line );\n\texit( EXIT_FAILURE );\n      }\n    } else if( strncasecmp( line, \"avgHandTimeSecs\", 15 ) == 0 ) {\n\n      if( gameConf != NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: avgHandTimeSecs must be defined outside of game blocks\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      if( sscanf( &line[ 15 ], \"%\"SCNu16, &conf->avgHandTimeSecs ) < 1 ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not get dealer average hand time: %s\", line );\n\texit( EXIT_FAILURE );\n      }\n    } else if( strncasecmp( line, \"maxMatchRuns\", 12 ) == 0 ) {\n\n      if( gameConf == NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: maxMatchRuns must be defined within a game block\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      if( sscanf( &line[ 12 ], \"%\"SCNu16, &gameConf->maxMatchRuns ) < 1 ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not get maximum number of runs in a match from: %s\", line );\n\texit( EXIT_FAILURE );\n      }\n    } else if( strncasecmp( line, \"maxRunningJobs\", 14 ) == 0 ) {\n\n      if( gameConf == NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: maxRunningJobs must be defined within a game block\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      if( sscanf( &line[ 14 ], \"%\"SCNu16, &gameConf->maxRunningJobs ) < 1 ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not get maximum number of running jobs from: %s\", line );\n\texit( EXIT_FAILURE );\n      }\n    } else if( strncasecmp( line, \"matchHands\", 10 ) == 0 ) {\n\n      if( gameConf == NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: matchHands must be defined within a game block\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      if( sscanf( &line[ 10 ], \"%\"SCNu32, &gameConf->matchHands ) < 1 ) {\n\n\tfprintf( stderr, \"BM_ERROR: could not get number of hands in a match from: %s\", line );\n\texit( EXIT_FAILURE );\n      }\n    } else if( strncasecmp( line, \"bot\", 3 ) == 0 ) {\n\n      if( gameConf == NULL ) {\n\n\tfprintf( stderr, \"BM_ERROR: matchHands must be defined within a game block\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      addBot( gameConf, &line[ 3 ] );\n    } else if( strncasecmp( line, \"user\", 4 ) == 0 ) {\n\n      if( gameConf != NULL ) {\n\n\tfprintf( stderr,\n\t\t \"BM_ERROR: users must be defined outside of game blocks\\n\" );\n\texit( EXIT_FAILURE );\n      }\n      addUser( conf, &line[ 4 ] );\n    } else {\n\n      fprintf( stderr, \"BM_ERROR: unknown configuration option %s\", line );\n      exit( EXIT_FAILURE );\n    }\n  }\n\n  fclose( file );\n}\n\nvoid addConnection( ServerState *serv, const int sock )\n{\n  Connection conn;\n\n  /* add the connection */\n  conn.status = STATUS_UNVALIDATED;\n  conn.user = NULL;\n  conn.connBuf = createReadBuf( sock );\n  if( conn.connBuf == 0 ) {\n\n    fprintf( stderr, \"BM_ERROR: could not create read buffer for socket\\n\" );\n    exit( EXIT_FAILURE );\n  }\n  LLPoolAddItem( serv->conns, &conn );\n}\n\nint matchUsesConnection( const Match *match, const LLPoolEntry *connEntry )\n{\n  int p;\n\n  for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {\n\n    if( match->players[ p ].isNetworkPlayer\n\t&& match->players[ p ].entry == connEntry ) {\n\n      return 1;\n    }\n  }\n\n  return 0;\n}\n\nvoid closeConnection( ServerState *serv, LLPoolEntry *connEntry )\n{\n  Connection *conn = (Connection*)LLPoolGetItem( connEntry );\n  LLPoolEntry *cur, *next;\n\n  destroyReadBuf( conn->connBuf );\n  conn->status = STATUS_CLOSED;\n\n  /* remove any pending matches which relied on the connection */\n  for( cur = LLPoolFirstEntry( serv->matches ); cur != NULL; cur = next ) {\n    next = LLPoolNextEntry( cur );\n    Match *match = (Match *)LLPoolGetItem( cur );\n\n    if( matchUsesConnection( match, connEntry ) ) {\n\n      match->numRuns = 0;\n    }\n  }\n}\n\nvoid handleListenSocket( const Config *conf, ServerState *serv )\n{\n  int sock;\n  struct sockaddr_in addr;\n  socklen_t addrLen;\n\n  addrLen = sizeof( addr );\n  sock = accept( serv->listenSocket, (struct sockaddr *)&addr, &addrLen );\n  if( sock < 0 ) {\n\n    fprintf( stderr, \"WARNING: failed to accept incoming connection\\n\" );\n    return;\n  }\n\n  addConnection( serv, sock );\n}\n\n/* -1 on failure, 0 on success */\nint parseMatchSpec( const Config *conf,\n\t\t    ServerState *serv,\n\t\t    const char *spec,\n\t\t    LLPoolEntry *connEntry,\n\t\t    Match *match )\n{\n  uint32_t rngSeed;\n  int pos, t, p;\n  LLPoolEntry *entry;\n  char tag[ READBUF_LEN ];\n  char name[ READBUF_LEN ];\n\n  pos = 0;\n\n  if( sscanf( &spec[ pos ], \" %s%n\", name, &t ) < 1 ) {\n\n    return -1;\n  }\n  pos += t;\n\n  entry = findGame( conf, name );\n  if( entry == NULL ) {\n\n    return -1;\n  }\n  match->gameConf = (GameConfig *)LLPoolGetItem( entry );\n\n  if( sscanf( &spec[ pos ],\n\t      \" %d %s %\"SCNu32\" %n\",\n\t      &match->numRuns,\n\t      tag,\n\t      &rngSeed,\n\t      &t ) < 3 ) {\n\n    return -1;\n  }\n  pos += t;\n  if( match->numRuns < 0 || match->numRuns > match->gameConf->maxMatchRuns ) {\n\n    return -1;\n  }\n\n  /* make sure tag has no characters in it */\n  if( strchr( tag, '/' ) != NULL ) {\n\n    return -1;\n  }\n\n  /* get bots */\n  for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {\n\n    /* get the name */\n    if( sscanf( &spec[ pos ], \" %s%n\", name, &t ) < 1 ) {\n\n      return -1;\n    }\n    pos += t;\n\n    /* translate the name into an index */\n    if( !strcmp( name, \"LOCAL\" ) ) {\n\n      match->players[ p ].isNetworkPlayer = 1;\n      match->players[ p ].entry = connEntry;\n    } else {\n\n      match->players[ p ].isNetworkPlayer = 0;\n      match->players[ p ].entry = findBot( match->gameConf, name );\n      if( match->players[ p ].entry == NULL ) {\n\n\treturn -1;\n      }\n    }\n  }\n\n  match->tag = strdup( tag );\n  match->rngSeed = rngSeed;\n  if( rngSeed ) {\n\n    init_genrand( &match->rng, rngSeed );\n    if( match->numRuns == 1 ) {\n\n      match->useRngForSeed = 0;\n    } else {\n\n      match->useRngForSeed = 1;\n    }\n  } else {\n\n    init_genrand( &match->rng, genrand_int32( &serv->rng ) );\n  }\n\n  return 0;\n}\n\nvoid writeHelpMessage( int fd )\n{\n  int r;\n\n  r = write( fd, \"HELP - this message\\n\", 20 );\n  r = write( fd, \"GAMES - list available games and players\\n\", 41 );\n  r = write( fd, \"QSTAT - show the current queue\\n\", 31 );\n  r = write( fd, \"RUNMATCHES game #runs tag rngSeed player ... - submit match request\\n\", 68 );\n  r = write( fd, \"  - Player order decides match seating\\n\", 39 );\n  r = write( fd, \"  - \\\"LOCAL\\\" player runs the bm_widget agent (bot_command)\\n\", 60 );\n}\n\nvoid writeGameList( const Config *conf, int fd )\n{\n  int r;\n  LLPoolEntry *cur, *botCur;\n  char line[ READBUF_LEN ];\n\n  for( cur = LLPoolFirstEntry( conf->games );\n       cur != NULL; cur = LLPoolNextEntry( cur ) ) {\n    GameConfig *game = (GameConfig *)LLPoolGetItem( cur );\n\n    r = snprintf( line, sizeof( line ), \"\\n%s\\n\", game->gameFile );\n    assert( r > 0 );\n    r = write( fd, line, r );\n\n    for( botCur = LLPoolFirstEntry( game->bots );\n\t botCur != NULL; botCur = LLPoolNextEntry( botCur ) ) {\n      BotSpec *bot = (BotSpec *)LLPoolGetItem( botCur );\n\n      r = snprintf( line, sizeof( line ), \" %s\\n\", bot->name );\n      assert( r > 0 );\n      r = write( fd, line, r );\n    }\n  }\n}\n\nvoid writeQueueStatus( const Config *conf, const ServerState *serv, int fd )\n{\n  int r;\n  LLPoolEntry *cur;\n  char line[ READBUF_LEN * 4 ];\n\n  if( serv->matches->numEntries == 0 ) {\n    r = write( fd, \"Queue empty\\n\", 12 );\n  }\n\n  for( cur = LLPoolFirstEntry( serv->matches );\n       cur != NULL; cur = LLPoolNextEntry( cur ) ) {\n    Match *match = (Match *)LLPoolGetItem( cur );\n\n    r = snprintf( line,\n\t\t  sizeof( line ),\n\t\t  \"%s %s %s * %d %s\\n\",\n\t\t  match->user->name,\n\t\t  match->tag,\n\t\t  match->gameConf->gameFile,\n\t\t  match->numRuns,\n\t\t  match->isRunning ? \"R\" : \"Q\" );\n    assert( r > 0 );\n    r = write( fd, line, r );\n  }\n}\n\nvoid handleConnection( Config *conf, ServerState *serv,\n\t\t       LLPoolEntry *connEntry )\n{\n  int r;\n  Connection *conn = (Connection *)LLPoolGetItem( connEntry );\n  char line[ READBUF_LEN ];\n\n  while( ( r = getLine( conn->connBuf, READBUF_LEN, line, 0 ) ) >= 0 ) {\n\n    if( r == 0 ) {\n\n      closeConnection( serv, connEntry );\n      return;\n    }\n\n    if( conn->status == STATUS_UNVALIDATED ) {\n      UserSpec *user;\n\n      user = validateLogon( conf, line );\n      if( user == NULL ) {\n\t/* couldn't authenticate */\n\n\tr = write( conn->connBuf->fd, \"BAD LOGON\\n\", 10 );\n\tfprintf( stderr, \"BM_ERROR: connection failed to log in\\n\" );\n\tcloseConnection( serv, connEntry );\n\treturn;\n      }\n\n      /* send an okay message */\n      r = write( conn->connBuf->fd, \"LOGON OKAY - type help for commands\\n\", 36 );\n\n      /* connection status is now okay */\n      conn->user = user;\n      conn->status = STATUS_OKAY;\n      return;\n    }\n\n    if( !strncasecmp( line, \"HELP\", 4 ) ) {\n\n      writeHelpMessage( conn->connBuf->fd );\n    } else if( !strncasecmp( line, \"GAMES\", 5 ) ) {\n\n      writeGameList( conf, conn->connBuf->fd );\n    } else if( !strncasecmp( line, \"QSTAT\", 5 ) ) {\n\n      writeQueueStatus( conf, serv, conn->connBuf->fd );\n    } else if( !strncasecmp( line, \"RUNMATCHES\", 10 ) ) {\n      Match match;\n\n      if( parseMatchSpec( conf, serv, &line[ 10 ], connEntry, &match ) < 0 ) {\n\n\tfprintf( stderr, \"BM_ERROR: bad RUNMATCHES command: %s\", line );\n\tr = write( conn->connBuf->fd, \"BAD RUNMATCHES COMMAND\\n\", 23 );\n\treturn;\n      }\n      match.user = ( (Connection *)LLPoolGetItem( connEntry ) )->user;\n      match.isRunning = 0;\n      gettimeofday( &match.queueTime, NULL );\n      LLPoolAddItem( serv->matches, &match );\n      return;\n    } else {\n\n      r = write( conn->connBuf->fd, \"UNKNOWN\\n\", 8 );\n      return;\n    }\n  }\n}\n\nint timeIsEarlier( struct timeval *a, struct timeval *b )\n{\n  if( a->tv_sec < b->tv_sec ) {\n    return 1;\n  } else if( a->tv_sec == b->tv_sec\n\t     && a->tv_usec < b->tv_usec ) {\n    return 1;\n  }\n  return 0;\n}\n\n/* how many bots will match start? */\nint botsInMatch( const Match *match )\n{\n  int p, num;\n\n  num = 0;\n  for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {\n\n    if( !match->players[ p ].isNetworkPlayer ) {\n\n      ++num;\n    }\n  }\n\n  return num;\n}\n\nvoid startDealer( const Config *conf,\n\t\t  const Match *match,\n\t\t  MatchJob *job,\n\t\t  const uint32_t rngSeed )\n{\n  int stdoutPipe[ 2 ], p, arg;\n  char handsString[ 16 ], rngString[ 16 ];\n  char startupTimeoutString[ 16 ], responseTimeoutString[ 16 ];\n  char handTimeoutString[ 16 ], avgHandTimeString[ 16 ];\n  char *argv[ MAX_PLAYERS + 64 ];\n\n  if( pipe( stdoutPipe ) < 0 ) {\n\n    fprintf( stderr, \"BM_ERROR: could not create pipe for new dealer\\n\" );\n    exit( EXIT_FAILURE );\n  }\n\n  job->dealerPID = fork();\n  if( job->dealerPID < 0 ) {\n\n    fprintf( stderr, \"BM_ERROR: fork() failed\\n\" );\n    exit( EXIT_FAILURE );\n  }\n  if( !job->dealerPID ) {\n    /* child runs the dealer command */\n    int stderrfd;\n    char tag[ READBUF_LEN ];\n\n    snprintf( tag, sizeof( tag ), \"%s/%s.stderr\", BM_LOGDIR, job->tag );\n    stderrfd = open( tag, O_WRONLY | O_APPEND | O_CREAT, 0644 );\n    if( stderrfd < 0 ) {\n\n      fprintf( stderr,\n\t       \"BM_ERROR: could not create error log %s\\n\",\n\t       tag );\n      exit( EXIT_FAILURE );\n    }\n    dup2( stderrfd, 2 );\n\n    /* change stdout to be the write end of the pipe */\n    close( stdoutPipe[ 0 ] );\n    dup2( stdoutPipe[ 1 ], 1 );\n\n    arg = 0;\n\n    argv[ arg ] = BM_DEALER;\n    ++arg;\n\n    snprintf( tag, sizeof( tag ), \"%s/%s\", BM_LOGDIR, job->tag );\n    argv[ arg ] = tag;\n    ++arg;\n\n    argv[ arg ] = match->gameConf->gameFile;\n    ++arg;\n\n    snprintf( handsString,\n\t      sizeof( handsString ),\n\t      \"%\"PRIu32,\n\t      match->gameConf->matchHands );\n    argv[ arg ] = handsString;\n    ++arg;\n\n    snprintf( rngString, sizeof( rngString ), \"%\"PRIu32, rngSeed );\n    argv[ arg ] = rngString;\n    ++arg;\n\n    for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {\n\n      if( match->players[ p ].isNetworkPlayer ) {\n\n\targv[ arg ]\n\t  = ( (Connection *)LLPoolGetItem( match->players[ p ].entry ) )\n\t  ->user->name;\n      } else {\n\n\targv[ arg ]\n\t  = ( (BotSpec *)LLPoolGetItem( match->players[ p ].entry ) )->name;\n      }\n      ++arg;\n    }\n\n    if( conf->startupTimeoutSecs ) {\n\n      argv[ arg ] = \"--start_timeout\";\n      ++arg;\n\n      snprintf( startupTimeoutString,\n                sizeof( startupTimeoutString ),\n                \"%d\",\n                (int)conf->startupTimeoutSecs * 1000 );\n      argv[ arg ] = startupTimeoutString;\n      ++arg;\n    }\n\n    /* Add maximum per action timeout argument */\n    argv[ arg ] = \"--t_response\";\n    ++arg;\n\n    snprintf( responseTimeoutString,\n             sizeof( responseTimeoutString ),\n             \"%d\",\n             (int)conf->responseTimeoutSecs * 1000 );\n    argv[ arg ] = responseTimeoutString;\n    ++arg;\n\n    /* Add maximum per hand timeout argument */\n    argv[ arg ] = \"--t_hand\";\n    ++arg;\n\n    snprintf( handTimeoutString,\n             sizeof( handTimeoutString ),\n             \"%d\",\n             (int)conf->handTimeoutSecs * 1000 );\n    argv[ arg ] = handTimeoutString;\n    ++arg;\n\n    /* Add average per hand time argument */\n    argv[ arg ] = \"--t_per_hand\";\n    ++arg;\n\n    snprintf( avgHandTimeString,\n             sizeof( avgHandTimeString ),\n             \"%d\",\n             (int)conf->avgHandTimeSecs * 1000 );\n    argv[ arg ] = avgHandTimeString;\n    ++arg;\n\n\n    argv[ arg ] = \"-q\";\n    ++arg;\n\n    /* Restore the appending behaviour so multiple matches get appended into\n     * the same log file */\n    argv[ arg ] = \"-a\";\n    ++arg;\n\n    argv[ arg ] = NULL;\n\n    execv( BM_DEALER, argv );\n\n    fprintf( stderr, \"BM_ERROR: could not start dealer\\n\" );\n    exit( EXIT_FAILURE );\n  }\n\n  /* parent has to talk to child to get ports */\n  ssize_t r;\n  int pos, t;\n  fd_set readfds;\n  struct timeval timeout;\n  char portString[ READBUF_LEN ];\n\n  close( stdoutPipe[ 1 ] );\n  timeout.tv_sec = BM_DEALER_WAIT_SECS;\n  timeout.tv_usec = 0;\n  FD_ZERO( &readfds );\n  FD_SET( stdoutPipe[ 0 ], &readfds );\n  if( select( stdoutPipe[ 0 ] + 1, &readfds, NULL, NULL, &timeout ) < 1 ) {\n\n    fprintf( stderr,\n\t     \"BM_ERROR: timed out waiting for port string from dealer\\n\" );\n    exit( EXIT_FAILURE );\n  }\n  r = read( stdoutPipe[ 0 ], portString, READBUF_LEN );\n  if( r <= 0 || portString[ r - 1 ] != '\\n' ) {\n\n    fprintf( stderr, \"BM_ERROR: could not read port string from dealer\\n\" );\n    exit( EXIT_FAILURE );\n  }\n  portString[ r ] = 0;\n\n  /* parse the port string */\n  pos = 0;\n  for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {\n\n    if( sscanf( &portString[ pos ],\n\t\t\" %\"SCNu16\"%n\",\n\t\t&job->ports[ p ],\n\t\t&t ) < 1 ) {\n\n      fprintf( stderr,\n\t       \"BM_ERROR: could not get port for player %d from dealer\\n\",\n\t       p + 1 );\n      exit( EXIT_FAILURE );\n    }\n    pos += t;\n  }\n}\n\npid_t startBot( const ServerState *serv,\n\t\tconst BotSpec *bot,\n\t\tconst uint16_t port,\n\t\tconst int botPosition )\n{\n  pid_t pid;\n\n  pid = fork();\n  if( pid < 0 ) {\n\n    fprintf( stderr, \"BM_ERROR: fork() failed\\n\" );\n    exit( EXIT_FAILURE );\n  }\n  if( !pid ) {\n    /* child runs the bot command */\n    char portString[ 8 ];\n    char posString[ 16 ];\n\n    snprintf( portString, sizeof( portString ), \"%\"PRIu16, port );\n    snprintf( posString, sizeof( posString ), \"%d\", botPosition );\n\n    /* throw away bot output */\n    dup2( serv->devnullfd, 1 );\n    dup2( serv->devnullfd, 2 );\n\n    execl( bot->command,\n\t   bot->command,\n\t   serv->hostname,\n\t   portString,\n\t   posString,\n\t   NULL );\n\n    fprintf( stderr, \"BM_ERROR: could not start bot %s\\n\", bot->command );\n    exit( EXIT_FAILURE );\n  }\n\n  return pid;\n}\n\nint sendStartMessage( const ServerState *serv,\n\t\t      const MatchJob *job,\n\t\t      const Connection *conn,\n\t\t      const uint16_t port )\n{\n  int len;\n  char msg[ strlen( serv->hostname ) + 12 + READBUF_LEN ];\n\n  len = snprintf( msg, sizeof( msg ), \"# RUNNING %s\\n\", job->tag );\n  assert( len > 0 );\n  if( write( conn->connBuf->fd, msg, len ) < len ) {\n\n    fprintf( stderr, \"BM_ERROR: short write to connection\\n\" );\n    return -1;\n  }\n\n  len = snprintf( msg,\n                  sizeof( msg ),\n                  \"RUN %s %\"PRIu16\"\\n\",\n                  serv->hostname, port );\n  assert( len > 0 );\n  if( write( conn->connBuf->fd, msg, len ) < len ) {\n\n    fprintf( stderr, \"BM_ERROR: short write to connection\\n\" );\n    return -1;\n  }\n\n  return 0;\n}\n\nMatchJob runMatchJob( const Config *conf,\n\t\t      const ServerState *serv,\n\t\t      LLPoolEntry *matchEntry,\n\t\t      const uint32_t rngSeed )\n{\n  int p, botPosition;\n  MatchJob job;\n  Match *match = (Match *)LLPoolGetItem( matchEntry );\n  char tag[ READBUF_LEN ];\n\n  job.matchEntry = matchEntry;\n\n  /* make the tag from the match tag */\n  snprintf( tag, sizeof( tag ), \"%s.%s\", match->user->name, match->tag );\n  job.tag = strdup( tag );\n\n  /* initialise all PIDs to 0 */\n  job.dealerPID = 0;\n  for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {\n\n    job.botPID[ p ] = 0;\n  }\n\n  /* start the dealer */\n  startDealer( conf, match, &job, rngSeed );\n\n  /* deal with all the players */\n  botPosition = 0;\n  for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {\n\n    if( match->players[ p ].isNetworkPlayer ) {\n      /* send message with port to network player to start up */\n      Connection *conn = (Connection*)LLPoolGetItem( match->players[ p ].entry );\n\n      if( sendStartMessage( serv, &job, conn, job.ports[ p ] ) < 0 ) {\n\t/* abort the job... */\n\n\tfprintf( stderr, \"BM_ERROR: aborting job\\n\" );\n\n\tkill( job.dealerPID, SIGTERM );\n\twhile( p > 0 ) {\n\t  --p;\n\n\t  if( job.botPID[ p ] ) {\n\n\t    kill( job.botPID[ p ], SIGTERM );\n\t  }\n\t}\n\n\treturn job;\n      }\n    } else {\n      /* start up bot */\n\n      job.botPID[ p ]\n\t= startBot( serv,\n\t\t    (BotSpec *)LLPoolGetItem( match->players[ p ].entry ),\n\t\t    job.ports[ p ],\n\t\t    botPosition );\n      ++botPosition;\n    }\n  }\n\n  return job;\n}\n\nint startMatchJob( const Config *conf, ServerState *serv )\n{\n  int running;\n  LLPoolEntry *cur, *next, *best;\n  Match *curMatch, *bestMatch;\n  MatchJob job;\n\n  /* automatically done adding things if we've got no more matches */\n  if( serv->matches->numEntries == 0 ) {\n\n    return 0;\n  }\n\n  /* how many bots are currently running */\n  running = 0;\n  for( cur = LLPoolFirstEntry( serv->jobs );\n       cur != NULL; cur = LLPoolNextEntry( cur ) ) {\n    MatchJob *job = (MatchJob *)LLPoolGetItem( cur );\n\n    running += botsInMatch( (Match*)LLPoolGetItem( job->matchEntry ) );\n  }\n\n  /* pick the best match to start */\n  best = 0;\n  bestMatch = 0;\n  for( cur = LLPoolFirstEntry( serv->matches ); cur != NULL; cur = next ) {\n    next = LLPoolNextEntry( cur );\n    curMatch = (Match *)LLPoolGetItem( cur );\n\n    if( curMatch->isRunning ) {\n\n      continue;\n    }\n\n    if( curMatch->numRuns <= 0 ) {\n      /* match is finished - clean it up */\n\n      free( curMatch->tag );\n      LLPoolRemoveEntry( serv->matches, cur );\n      continue;\n    }\n\n    if( curMatch->gameConf->maxRunningJobs\n\t&& curMatch->gameConf->curRunningJobs\n\t>= curMatch->gameConf->maxRunningJobs ) {\n      /* cur refers to a match in a game which is currently too busy */\n\n      continue;\n    }\n\n    if( best == 0\n\t|| timeIsEarlier( &curMatch->user->waitStart,\n\t\t\t  &bestMatch->user->waitStart )\n\t|| ( !timeIsEarlier( &bestMatch->user->waitStart,\n\t\t\t     &curMatch->user->waitStart )\n\t     && timeIsEarlier( &curMatch->queueTime,\n\t\t\t       &bestMatch->queueTime ) ) ) {\n\n      best = cur;\n      bestMatch = curMatch;\n    }\n  }\n\n  /* return failure if we couldn't find a runnable job */\n  if( best == NULL ) {\n\n    return 0;\n  }\n\n  /* check if we have the space to run the bots */\n  if( conf->maxRunningBots\n      && botsInMatch( bestMatch ) + running > conf->maxRunningBots ) {\n\n    return 0;\n  }\n\n  /* create the job */\n  job = runMatchJob( conf,\n\t\t     serv,\n\t\t     best,\n\t\t     bestMatch->useRngForSeed\n\t\t     ? genrand_int32( &bestMatch->rng )\n\t\t     : bestMatch->rngSeed );\n  assert( job.dealerPID );\n  LLPoolAddItem( serv->jobs, &job );\n\n  /* update status about running jobs */\n  ++( bestMatch->gameConf->curRunningJobs );\n  bestMatch->isRunning = 1;\n\n  /* update the user */\n  gettimeofday( &bestMatch->user->waitStart, NULL );\n\n  /* update the match */\n  --bestMatch->numRuns;\n  gettimeofday( &bestMatch->queueTime, NULL );\n\n  return 1;\n}\n\nvoid initServerState( const Config *conf, ServerState *serv )\n{\n  struct addrinfo hints, *info;\n  uint16_t port;\n  int hnm, r;\n  char *hn;\n  char ipstr[ INET6_ADDRSTRLEN ];\n\n  serv->conns = newLLPool( sizeof( Connection ) );\n  serv->matches = newLLPool( sizeof( Match ) );\n  serv->jobs = newLLPool( sizeof( MatchJob ) );\n\n  /* create the socket clients will connect to */\n  port = conf->port;\n  serv->listenSocket = getListenSocket( &port );\n  if( serv->listenSocket < 0 ) {\n\n    fprintf( stderr, \"BM_ERROR: could not open socket for listening\\n\" );\n    exit( EXIT_FAILURE );\n  }\n  printf( \"starting server on port %\"PRIu16\"\\n\", conf->port );\n\n  init_genrand( &serv->rng, time( NULL ) );\n\n  hnm = sysconf( _SC_HOST_NAME_MAX );\n  hn = (char*)malloc( hnm );\n  assert( hn != 0 );\n  if( gethostname( hn, hnm + 1 ) < 0 ) {\n\n    fprintf( stderr, \"BM_ERROR: could not get hostname\\n\" );\n    exit( EXIT_FAILURE );\n  }\n\n  memset( &hints, 0, sizeof( hints ) );\n  hints.ai_family = AF_INET;\n  hints.ai_socktype = SOCK_STREAM;\n  if( ( r = getaddrinfo( hn, NULL, &hints, &info ) ) != 0 ) {\n\n    fprintf( stderr,\n\t     \"BM_ERROR: could not get address info for host %s\\n\",\n\t     hn );\n    exit( 1 );\n  }\n  free( hn );\n\n  /* Get an address for the server */\n  void *addr;\n\n  /* get the pointer to the address itself,\n   * different fields in IPv4 and IPv6: */\n  if ( info->ai_family == AF_INET ) {\n    /* IPv4 */\n    struct sockaddr_in *ipv4 = ( struct sockaddr_in * ) info->ai_addr;\n    addr = &( ipv4->sin_addr );\n  } else {\n    /* IPv6 */\n    struct sockaddr_in6 *ipv6 = ( struct sockaddr_in6 * ) info->ai_addr;\n    addr = &( ipv6->sin6_addr );\n  }\n\n  /* convert the IP to a string and store it:*/\n  inet_ntop( info->ai_family, addr, ipstr, sizeof( ipstr ) );\n  serv->hostname = strdup( ipstr );\n\n  freeaddrinfo( info ); /* free the linked list */\n\n  serv->devnullfd = open( \"/dev/null\", O_WRONLY );\n  if( serv->devnullfd < 0 ) {\n\n    fprintf( stderr, \"BM_ERROR: could not open /dev/null\\n\" );\n    exit( EXIT_FAILURE );\n  }\n}\n\nint checkIfJobFinished( MatchJob *job )\n{\n  int status, r, p, allDone;\n  Match *match = (Match *)LLPoolGetItem( job->matchEntry );\n\n  allDone = 1;\n\n  if( job->dealerPID ) {\n\n    r = waitpid( job->dealerPID, &status, WNOHANG );\n    if( r < 0 ) {\n\n      fprintf( stderr, \"BM_ERROR: could not wait on child\\n\" );\n      exit( EXIT_FAILURE );\n    }\n    if( r == job->dealerPID ) {\n\n      job->dealerPID = 0;\n    } else {\n\n      allDone = 0;\n    }\n  }\n\n  for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {\n    if( job->botPID[ p ] == 0 ) {\n      continue;\n    }\n\n    r = waitpid( job->botPID[ p ], &status, WNOHANG );\n    if( r < 0 ) {\n\n      fprintf( stderr, \"BM_ERROR: could not wait on child\\n\" );\n      exit( EXIT_FAILURE );\n    }\n    if( r == job->botPID[ p ] ) {\n\n      job->botPID[ p ] = 0;\n    } else {\n\n      allDone = 0;\n    }\n  }\n\n  return allDone;\n}\n\nvoid finishedJob( ServerState *serv, LLPoolEntry *jobEntry )\n{\n  MatchJob *job = (MatchJob *)LLPoolGetItem( jobEntry );\n  Match *match = (Match *)LLPoolGetItem( job->matchEntry );\n\n  free( job->tag );\n  --( match->gameConf->curRunningJobs );\n  match->isRunning = 0;\n  LLPoolRemoveEntry( serv->jobs, jobEntry );\n}\n\nint main( int argc, char **argv )\n{\n  Config conf;\n  ServerState serv;\n  int maxfd;\n  fd_set readfds;\n  LLPoolEntry *cur, *next;\n  struct timeval tv;\n\n  if( argc < 2 ) {\n\n    printUsage( stderr );\n    exit( EXIT_FAILURE );\n  }\n\n  /* Ignore SIGPIPE.  It seems that SIGPIPE can be raised when the underlying\n   * IO fails with a SIGPIPE.  Unfortunately this causes the entire benchmark\n   * server to crash and jobs are lost.  Ignore the signal to avoid death */\n  /* ???: May also need to catch SIGCHLD */\n  signal( SIGPIPE, SIG_IGN );\n\n  /* use the config file */\n  setDefaults( &conf );\n  readConfig( argv[ 1 ], &conf );\n\n  /* initialise server state */\n  initServerState( &conf, &serv );\n\n  /* main I/O loop */\n  while( 1 ) {\n\n    /* clean up any finished jobs */\n    for( cur = LLPoolFirstEntry( serv.jobs ); cur != NULL; cur = next ) {\n      next = LLPoolNextEntry( cur );\n      MatchJob *job = (MatchJob *)LLPoolGetItem( cur );\n\n      if( checkIfJobFinished( job ) ) {\n\n\tfinishedJob( &serv, cur );\n      }\n    }\n\n    /* clean up any closed connections */\n    for( cur = LLPoolFirstEntry( serv.conns ); cur != NULL; cur = next ) {\n      next = LLPoolNextEntry( cur );\n\n      if( ( (Connection *)LLPoolGetItem( cur ) )->status == STATUS_CLOSED ) {\n\n\tLLPoolRemoveEntry( serv.conns, cur );\n      }\n    }\n\n    /* start jobs, up to the maximum */\n    while( startMatchJob( &conf, &serv ) );\n\n    /* wait for input */\n    FD_ZERO( &readfds );\n    FD_SET( serv.listenSocket, &readfds );\n    maxfd = serv.listenSocket;\n    tv.tv_sec = BM_MAX_IOWAIT_SECS;\n    tv.tv_usec = 0;\n    for( cur = LLPoolFirstEntry( serv.conns );\n\t cur != NULL; cur = LLPoolNextEntry( cur ) ) {\n      Connection *conn = (Connection *)LLPoolGetItem( cur );\n\n      FD_SET( conn->connBuf->fd, &readfds );\n      if( conn->connBuf->fd > maxfd ) {\n\n\tmaxfd = conn->connBuf->fd;\n      }\n    }\n    if( select( maxfd + 1, &readfds, NULL, NULL, &tv ) < 0 ) {\n\n      fprintf( stderr, \"BM_ERROR: select failed\\n\" );\n      exit( -1 );\n    }\n\n    /* process anything that's happened */\n    if( FD_ISSET( serv.listenSocket, &readfds ) ) {\n\n      handleListenSocket( &conf, &serv );\n    }\n    for( cur = LLPoolFirstEntry( serv.conns );\n\t cur != NULL; cur = LLPoolNextEntry( cur ) ) {\n      Connection *conn = (Connection *)LLPoolGetItem( cur );\n\n      if( FD_ISSET( conn->connBuf->fd, &readfds ) ) {\n\n\thandleConnection( &conf, &serv, cur );\n      }\n    }\n  }\n\n  close( serv.listenSocket );\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "ACPCServer/bm_server.config",
    "content": "# port to connect to the server\nport 54000\n\n# maxmimum number of simultaneously locally running bots\n# 0 disables\nmaxRunningBots 0\n\n# maximum time in seconds to wait for clients to connect when starting a match\nstartupTimeoutSecs 1000\n# maximum time in seconds to wait for clients to act during a match\nresponseTimeoutSecs 60000\n# maximum time in seconds allowed for a client to play a given hand\nhandTimeoutSecs 210000\n# average time in seconds allowed for a client to spend on each hand\navgHandTimeSecs 700\n\n# heads up limit Texas Hold'em\ngame holdem.limit.2p.reverse_blinds.game {\n\n     # maximum number of times a match can be run with a single player request\n     maxMatchRuns 10\n\n     # maxmimum number of simultaneously running matches using this game\n     # 0 disables\n     maxRunningJobs 1\n\n     # number of hands in a match\n     matchHands 5000\n\n     # bot botName botStartupScript\n     # botStartupScript is run with 3 args: server name, port, local position\n     # local postion indicates which LOCAL bot this is (index starting from 0)\n     # This is useful when determining which of multiple machines to run on\n     bot testBot example_player.limit.2p.sh\n}\n\n# heads up limit Texas Hold'em\ngame holdem.nolimit.2p.reverse_blinds.game {\n\n     # maximum number of times a match can be run with a single player request\n     maxMatchRuns 10\n\n     # maxmimum number of simultaneously running matches using this game\n     # 0 disables\n     maxRunningJobs 1\n\n     # number of hands in a match\n     matchHands 5000\n\n     # bot botName botStartupScript\n     # botStartupScript is run with 3 args: server name, port, local position\n     # local postion indicates which LOCAL bot this is (index starting from 0)\n     # This is useful when determining which of multiple machines to run on\n     bot testBot example_player.nolimit.2p.sh\n}\n\n# heads up limit Texas Hold'em\ngame holdem.limit.3p.game {\n\n     # maximum number of times a match can be run with a single player request\n     maxMatchRuns 10\n\n     # maxmimum number of simultaneously running matches using this game\n     # 0 disables\n     maxRunningJobs 1\n\n     # number of hands in a match\n     matchHands 5000\n\n     # bot botName botStartupScript\n     # botStartupScript is run with 3 args: server name, port, local position\n     # local postion indicates which LOCAL bot this is (index starting from 0)\n     # This is useful when determining which of multiple machines to run on\n     bot testBot example_player.limit.3p.sh\n}\n\n# Users authorized to run jobs on the benchmark (user name pass)\nuser neil test\n"
  },
  {
    "path": "ACPCServer/bm_widget.c",
    "content": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdio.h>\n#define __STDC_FORMAT_MACROS\n#include <inttypes.h>\n#include <assert.h>\n#include <string.h>\n#include <unistd.h>\n#include <netdb.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include <sys/wait.h>\n#include <errno.h>\n#include \"net.h\"\n\n\n#define ARG_SERVERNAME 1\n#define ARG_SERVERPORT 2\n#define ARG_BOT_COMMAND 3\n#define ARG_NUM_ARGS 4\n\n\nstatic void printUsage( FILE *file )\n{\n  fprintf( file, \"usage: bm_widget bm_hostname bm_port bot_command\\n\" );\n  fprintf( file, \"  bot_command: agent executable, passed \\\"hostname port\\\"\\n\");\n}\n\n\n/* 0 on success, -1 on failure */\nint login( char *user, char *passwd, FILE *conn )\n{\n  if( fprintf( conn, \"%s %s\\n\", user, passwd ) < 0 ) {\n\n    return -1;\n  }\n  fflush( conn );\n\n  return 0;\n}\n\n\nint main( int argc, char **argv )\n{\n  int sock, i;\n  pid_t childPID;\n  uint16_t port;\n  ReadBuf *fromUser, *fromServer;\n  fd_set readfds;\n  char line[ READBUF_LEN ];\n\n  if( argc < ARG_NUM_ARGS ) {\n\n    printUsage( stderr );\n    exit( EXIT_FAILURE );\n  }\n\n\n  /* connect to the server */\n  if( sscanf( argv[ ARG_SERVERPORT ], \"%\"SCNu16, &port ) < 1 ) {\n\n    fprintf( stderr, \"ERROR: invalid port %s\\n\", argv[ ARG_SERVERPORT ] );\n    exit( EXIT_FAILURE );\n  }\n  sock = connectTo( argv[ ARG_SERVERNAME ], port );\n  if( sock < 0 ) {\n\n    exit( EXIT_FAILURE );\n  }\n\n  // EJ additions 9/3/2012\n  // Turn on keep-alive for socket connection with more frequent checking\n  // than the Linux default.  What I've observed is that if a socket\n  // connection is idle for long enough it gets dropped.  This only\n  // happens for some users.\n  int on = 1;\n  if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) {\n    fprintf( stderr, \"ERROR: setsockopt failed; errno %i\\n\", errno );\n    exit( EXIT_FAILURE );\n  }\n#ifdef __linux__\n  // Not sure what this should be\n  int num_before_failure = 2;\n  if (setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &num_before_failure,\n\t\t sizeof(num_before_failure)) == -1) {\n    fprintf( stderr, \"ERROR: setsockopt failed; errno %i\\n\", errno );\n    exit( EXIT_FAILURE );\n  }\n  // First check after 60 seconds\n  int initial_secs = 60;\n  if (setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &initial_secs,\n\t\t sizeof(initial_secs)) == -1) {\n    fprintf( stderr, \"ERROR: setsockopt failed; errno %i\\n\", errno );\n    exit( EXIT_FAILURE );\n  }\n  // Thereafter, also check every 60 seconds\n  int interval_secs = 60;\n  if (setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &interval_secs,\n\t\t sizeof(interval_secs)) == -1) {\n    fprintf( stderr, \"ERROR: setsockopt failed; errno %i\\n\", errno );\n    exit( EXIT_FAILURE );\n  }\n#endif\n\n  /* set up read buffers */\n  fromUser = createReadBuf( 0 );\n  fromServer = createReadBuf( sock );\n\n  printf( \"Log in with 'user password'\\n\" );\n  fflush( stdout );\n\n  /* main loop */\n  while( 1 ) {\n\n    /* clean up any children */\n    while( waitpid( -1, NULL, WNOHANG ) > 0 );\n\n    /* wait for input */\n    FD_ZERO( &readfds );\n    FD_SET( 0, &readfds );\n    FD_SET( sock, &readfds );\n    i = select( sock + 1, &readfds, NULL, NULL, NULL );\n    if( i < 0 ) {\n\n      fprintf( stderr, \"ERROR: select failed\\n\" );\n      exit( EXIT_FAILURE );\n    }\n    if( i == 0 ) {\n      /* nothing ready - shouldn't happen without timeout */\n\n      continue;\n    }\n\n    /* handle user input by passing it directly to server */\n    if( FD_ISSET( 0, &readfds ) ) {\n\n      /* get the input */\n      while( ( i = getLine( fromUser, READBUF_LEN, line, 0 ) ) >= 0 ) {\n\n\tif( i == 0 ) {\n\t  /* Done! */\n\n\t  exit( EXIT_SUCCESS );\n\t}\n\n\t/* write to server */\n\tif( write( sock, line, i ) < 0 ) {\n\n\t  fprintf( stderr, \"ERROR: failed while sending to server\\n\" );\n\t  exit( EXIT_FAILURE );\n\t}\n      }\n    }\n\n    /* handle server messages */\n    if( FD_ISSET( sock, &readfds ) ) {\n\n      /* get the input */\n      while( ( i = getLine( fromServer, READBUF_LEN, line, 0 ) ) >= 0 ) {\n\n\tif( i == 0 ) {\n\n\t  fprintf( stderr, \"ERROR: server closed connection?\\n\" );\n\t  exit( EXIT_FAILURE );\n\t}\n\n\t/* check for server commands */\n\tif( strncasecmp( line, \"run \", 4 ) == 0 ) {\n\n\t  /* split the rest of the line into name ' ' port */\n\t  for( i = 4; line[ i ]; ++i ) {\n\n\t    if( line[ i ] == ' ' ) {\n\t      /* found the separator */\n\n\t      line[ i ] = 0;\n\t      break;\n\t    }\n\t  }\n\n\t  printf( \"starting match %s:%s\", &line[ 4 ], &line[ i + 1 ] );\n\t  fflush( stdout );\n\n\t  /* run `command machine port` */\n\t  childPID = fork();\n\t  if( childPID < 0 ) {\n\n\t    fprintf( stderr, \"ERROR: fork() failed\\n\" );\n\t    exit( EXIT_FAILURE );\n\t  }\n\t  if( childPID == 0 ) {\n\t    /* child runs the command */\n\n\t    execl( argv[ ARG_BOT_COMMAND ],\n\t\t   argv[ ARG_BOT_COMMAND ],\n\t\t   &line[ 4 ],\n\t\t   &line[ i + 1 ],\n\t\t   NULL );\n\t    fprintf( stderr,\n\t\t     \"ERROR: could not run %s\\n\",\n\t\t     argv[ ARG_BOT_COMMAND ] );\n\t    exit( EXIT_FAILURE );\n\t  }\n\t} else {\n\t  /* just a message, print it out */\n\n\t  if( fwrite( line, 1, i, stdout ) < 0 ) {\n\n\t    fprintf( stderr, \"ERROR: failed while printing server message\\n\" );\n\t    exit( EXIT_FAILURE );\n\t  }\n\t  fflush( stdout );\n\t}\n      }\n    }\n  }\n\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "ACPCServer/dealer.c",
    "content": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdio.h>\n#define __STDC_LIMIT_MACROS\n#include <stdint.h>\n#include <unistd.h>\n#include <sys/socket.h>\n#include <sys/time.h>\n#include <sys/select.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include <getopt.h>\n#include \"game.h\"\n#include \"net.h\"\n\n\n/* the ports for players to connect to will be printed on standard out\n   (in player order)\n\n   if log file is enabled, matchName.log will contain finished states\n   and values, followed by the final total values for each player\n\n   if transaction file is enabled, matchName.tlog will contain a list\n   of actions taken and timestamps that is sufficient to recreate an\n   interrupted match\n\n   if the quiet option is not enabled, standard error will print out\n   the messages sent to and receieved from the players\n\n   the final total values for each player will be printed to both\n   standard out and standard error\n\n   exit value is EXIT_SUCCESS if the match was a success,\n   or EXIT_FAILURE on any failure */\n\n\n#define DEFAULT_MAX_INVALID_ACTIONS UINT32_MAX\n#define DEFAULT_MAX_RESPONSE_MICROS 6000000000\n#define DEFAULT_MAX_USED_HAND_MICROS 6000000000\n#define DEFAULT_MAX_USED_PER_HAND_MICROS 70000000\n\n\ntypedef struct {\n  uint32_t maxInvalidActions;\n  uint64_t maxResponseMicros;\n  uint64_t maxUsedHandMicros;\n  uint64_t maxUsedMatchMicros;\n\n  uint32_t numInvalidActions[ MAX_PLAYERS ];\n  uint64_t usedHandMicros[ MAX_PLAYERS ];\n  uint64_t usedMatchMicros[ MAX_PLAYERS ];\n} ErrorInfo;\n\n\nstatic void printUsage( FILE *file, int verbose )\n{\n  fprintf( file, \"usage: dealer matchName gameDefFile #Hands rngSeed p1name p2name ... [options]\\n\" );\n  fprintf( file, \"  -f use fixed dealer button at table\\n\" );\n  fprintf( file, \"  -l/L disable/enable log file - enabled by default\\n\" );\n  fprintf( file, \"  -p player1_port,player2_port,... [default is random]\\n\" );\n  fprintf( file, \"  -q only print errors, warnings, and final value to stderr\\n\" );\n  fprintf( file, \"  -t/T disable/enable transaction file - disabled by default\\n\" );\n  fprintf( file, \"  -a append to log/transaction files - disabled by default\\n\" );\n  fprintf( file, \"  --t_response [milliseconds] maximum time per response\\n\" );\n  fprintf( file, \"  --t_hand [milliseconds] maximum player time per hand\\n\" );\n  fprintf( file, \"  --t_per_hand [milliseconds] maximum average player time for match\\n\" );\n  fprintf( file, \"  --start_timeout [milliseconds] maximum time to wait for players to connect\\n\" );\n  fprintf( file, \"    <0 [default] is no timeout\\n\" );\n}\n\n/* returns >= 0 on success, -1 on error */\nstatic int scanPortString( const char *string,\n\t\t\t   uint16_t listenPort[ MAX_PLAYERS ] )\n{\n  int c, r, p;\n\n  c = 0;\n  for( p = 0; p < MAX_PLAYERS; ++p ) {\n\n    if( string[ c ] == 0 ) {\n      /* finished parsing the string */\n\n      break;\n    }\n\n    if( p ) {\n      /* look for separator */\n\n      if( string[ c ] != ',' ) {\n\t/* numbers should be comma separated */\n\n\treturn -1;\n      }\n      ++c;\n    }\n\n    if( sscanf( &string[ c ], \"%\"SCNu16\"%n\", &listenPort[ p ], &r ) < 1 ) {\n      /* couldn't get a number */\n\n      return -1;\n    }\n    c += r;\n  }\n\n  return 0;\n}\n\nstatic void initErrorInfo( const uint32_t maxInvalidActions,\n\t\t\t   const uint64_t maxResponseMicros,\n\t\t\t   const uint64_t maxUsedHandMicros,\n\t\t\t   const uint64_t maxUsedMatchMicros,\n\t\t\t   ErrorInfo *info )\n{\n  int s;\n\n  info->maxInvalidActions = maxInvalidActions;\n  info->maxResponseMicros = maxResponseMicros;\n  info->maxUsedHandMicros = maxUsedHandMicros;\n  info->maxUsedMatchMicros = maxUsedMatchMicros;\n\n  for( s = 0; s < MAX_PLAYERS; ++s ) {\n    info->numInvalidActions[ s ] = 0;\n    info->usedHandMicros[ s ] = 0;\n    info->usedMatchMicros[ s ] = 0;\n  }\n}\n\n\n/* update the number of invalid actions for seat\n   returns >= 0 if match should continue, -1 for failure */\nstatic int checkErrorInvalidAction( const uint8_t seat, ErrorInfo *info )\n{\n  ++( info->numInvalidActions[ seat ] );\n\n  if( info->numInvalidActions[ seat ] > info->maxInvalidActions ) {\n    return -1;\n  }\n\n  return 0;\n}\n\n/* update the time used by seat\n   returns >= 0 if match should continue, -1 for failure */\nstatic int checkErrorTimes( const uint8_t seat,\n\t\t\t    const struct timeval *sendTime,\n\t\t\t    const struct timeval *recvTime,\n\t\t\t    ErrorInfo *info )\n{\n  uint64_t responseMicros;\n\n  /* calls to gettimeofday can return earlier times on later calls :/ */\n  if( recvTime->tv_sec < sendTime->tv_sec\n      || ( recvTime->tv_sec == sendTime->tv_sec\n\t   && recvTime->tv_usec < sendTime->tv_usec ) ) {\n    return 0;\n  }\n\n  /* figure out how many microseconds the response took */\n  responseMicros = ( recvTime->tv_sec - sendTime->tv_sec ) * 1000000\n    + recvTime->tv_usec - sendTime->tv_usec;\n\n  /* update usage counts */\n  info->usedHandMicros[ seat ] += responseMicros;\n  info->usedMatchMicros[ seat ] += responseMicros;\n\n  /* check time used for the response */\n  if( responseMicros > info->maxResponseMicros ) {\n    return -1;\n  }\n\n  /* check time used in the current hand */\n  if( info->usedHandMicros[ seat ] > info->maxUsedHandMicros ) {\n    return -1;\n  }\n\n  /* check time used in the entire match */\n  if( info->usedMatchMicros[ seat ] > info->maxUsedMatchMicros ) {\n    return -1;\n  }\n\n  return 0;\n}\n\n/* note that there is a new hand\n   returns >= 0 if match should continue, -1 for failure */\nstatic int checkErrorNewHand( const Game *game, ErrorInfo *info )\n{\n  uint8_t p;\n\n  for( p = 0; p < game->numPlayers; ++p ) {\n    info->usedHandMicros[ p ] = 0;\n  }\n\n  return 0;\n}\n\n\nstatic uint8_t seatToPlayer( const Game *game, const uint8_t player0Seat,\n\t\t\t     const uint8_t seat )\n{\n  return ( seat + game->numPlayers - player0Seat ) % game->numPlayers;\n}\n\nstatic uint8_t playerToSeat( const Game *game, const uint8_t player0Seat,\n\t\t\t     const uint8_t player )\n{\n  return ( player + player0Seat ) % game->numPlayers;\n}\n\n/* returns >= 0 if match should continue, -1 for failure */\nstatic int sendPlayerMessage( const Game *game, const MatchState *state,\n\t\t\t      const int quiet, const uint8_t seat,\n\t\t\t      const int seatFD, struct timeval *sendTime )\n{\n  int c;\n  char line[ MAX_LINE_LEN ];\n\n  /* prepare the message */\n  c = printMatchState( game, state, MAX_LINE_LEN, line );\n  if( c < 0 || c > MAX_LINE_LEN - 3 ) {\n    /* message is too long */\n\n    fprintf( stderr, \"ERROR: state message too long\\n\" );\n    return -1;\n  }\n  line[ c ] = '\\r';\n  line[ c + 1 ] = '\\n';\n  line[ c + 2 ] = 0;\n  c += 2;\n\n  /* send it to the player and flush */\n  if( write( seatFD, line, c ) != c ) {\n    /* couldn't send the line */\n\n    fprintf( stderr, \"ERROR: could not send state to seat %\"PRIu8\"\\n\",\n\t     seat + 1 );\n    return -1;\n  }\n\n  /* note when we sent the message */\n  gettimeofday( sendTime, NULL );\n\n  /* log the message */\n  if( !quiet ) {\n    fprintf( stderr, \"TO %d at %zu.%.06zu %s\", seat + 1,\n\t     sendTime->tv_sec, sendTime->tv_usec, line );\n  }\n\n  return 0;\n}\n\n/* returns >= 0 if action/size has been set to a valid action\n   returns -1 for failure (disconnect, timeout, too many bad actions, etc) */\nstatic int readPlayerResponse( const Game *game,\n\t\t\t       const MatchState *state,\n\t\t\t       const int quiet,\n\t\t\t       const uint8_t seat,\n\t\t\t       const struct timeval *sendTime,\n\t\t\t       ErrorInfo *errorInfo,\n\t\t\t       ReadBuf *readBuf,\n\t\t\t       Action *action,\n\t\t\t       struct timeval *recvTime )\n{\n  int c, r;\n  MatchState tempState;\n  char line[ MAX_LINE_LEN ];\n\n  while( 1 ) {\n\n    /* read a line of input from player */\n    struct timeval start;\n    gettimeofday( &start, NULL );\n    if( getLine( readBuf, MAX_LINE_LEN, line,\n\t\t errorInfo->maxResponseMicros ) <= 0 ) {\n      /* couldn't get any input from player */\n\n      struct timeval after;\n      gettimeofday( &after, NULL );\n      uint64_t micros_spent =\n\t(uint64_t)( after.tv_sec - start.tv_sec ) * 1000000\n\t+ ( after.tv_usec - start.tv_usec );\n      fprintf( stderr, \"ERROR: could not get action from seat %\"PRIu8\"\\n\",\n\t       seat + 1 );\n      // Print out how much time has passed so we can see if this was a\n      // timeout as opposed to some other sort of failure (e.g., socket\n      // closing).\n      fprintf( stderr, \"%.1f seconds spent waiting; timeout %.1f\\n\",\n\t       micros_spent / 1000000.0,\n\t       errorInfo->maxResponseMicros / 1000000.0);\n      return -1;\n    }\n\n    /* note when the message arrived */\n    gettimeofday( recvTime, NULL );\n\n    /* log the response */\n    if( !quiet ) {\n      fprintf( stderr, \"FROM %d at %zu.%06zu %s\", seat + 1,\n\t       recvTime->tv_sec, recvTime->tv_usec, line );\n    }\n\n    /* ignore comments */\n    if( line[ 0 ] == '#' || line[ 0 ] == ';' ) {\n      continue;\n    }\n\n    /* check for any timeout issues */\n    if( checkErrorTimes( seat, sendTime, recvTime, errorInfo ) < 0 ) {\n\n      fprintf( stderr, \"ERROR: seat %\"PRIu8\" ran out of time\\n\", seat + 1 );\n      return -1;\n    }\n\n    /* parse out the state */\n    c = readMatchState( line, game, &tempState );\n    if( c < 0 ) {\n      /* couldn't get an intelligible state */\n\n      fprintf( stderr, \"WARNING: bad state format in response\\n\" );\n      continue;\n    }\n\n    /* ignore responses that don't match the current state */\n    if( !matchStatesEqual( game, state, &tempState ) ) {\n\n      fprintf( stderr, \"WARNING: ignoring un-requested response\\n\" );\n      continue;\n    }\n\n    /* get the action */\n    if( line[ c++ ] != ':'\n\t|| ( r = readAction( &line[ c ], game, action ) ) < 0 ) {\n\n      if( checkErrorInvalidAction( seat, errorInfo ) < 0 ) {\n\n\tfprintf( stderr, \"ERROR: bad action format in response\\n\" );\n      }\n\n      fprintf( stderr,\n\t       \"WARNING: bad action format in response, changed to call\\n\" );\n      action->type = a_call;\n      action->size = 0;\n      goto doneRead;\n    }\n    c += r;\n\n    /* make sure the action is valid */\n    if( !isValidAction( game, &state->state, 1, action ) ) {\n\n      if( checkErrorInvalidAction( seat, errorInfo ) < 0 ) {\n\n\tfprintf( stderr, \"ERROR: invalid action\\n\" );\n\treturn -1;\n      }\n\n      fprintf( stderr, \"WARNING: invalid action, changed to call\\n\" );\n      action->type = a_call;\n      action->size = 0;\n    }\n\n    goto doneRead;\n  }\n\n doneRead:\n  return 0;\n}\n\n/* returns >= 0 if match should continue, -1 for failure */\nstatic int setUpNewHand( const Game *game, const uint8_t fixedSeats,\n\t\t\t uint32_t *handId, uint8_t *player0Seat,\n\t\t\t rng_state_t *rng, ErrorInfo *errorInfo, State *state )\n{\n  ++( *handId );\n\n  /* rotate the players around the table */\n  if( !fixedSeats ) {\n\n    *player0Seat = ( *player0Seat + 1 ) % game->numPlayers;\n  }\n\n  if( checkErrorNewHand( game, errorInfo ) < 0 ) {\n\n    fprintf( stderr, \"ERROR: unexpected game\\n\" );\n    return -1;\n  }\n  initState( game, *handId, state );\n  dealCards( game, rng, state );\n\n  return 0;\n}\n\n/* returns >= 0 if match should continue, -1 for failure */\nstatic int processTransactionFile( const Game *game, const int fixedSeats,\n\t\t\t\t   uint32_t *handId, uint8_t *player0Seat,\n\t\t\t\t   rng_state_t *rng, ErrorInfo *errorInfo,\n\t\t\t\t   double totalValue[ MAX_PLAYERS ],\n\t\t\t\t   MatchState *state, FILE *file )\n{\n  int c, r;\n  uint32_t h;\n  uint8_t s;\n  Action action;\n  struct timeval sendTime, recvTime;\n  char line[ MAX_LINE_LEN ];\n\n  while( fgets( line, MAX_LINE_LEN, file ) ) {\n\n    /* get the log entry */\n\n    /* ACTION */\n    c = readAction( line, game, &action );\n    if( c < 0 ) {\n\n      fprintf( stderr, \"ERROR: could not parse transaction action %s\", line );\n      return -1;\n    }\n\n    /* ACTION HANDID SEND RECV */\n    if( sscanf( &line[ c ], \" %\"SCNu32\" %zu.%06zu %zu.%06zu%n\", &h,\n\t\t&sendTime.tv_sec, &sendTime.tv_usec,\n\t\t&recvTime.tv_sec, &recvTime.tv_usec, &r ) < 4 ) {\n\n      fprintf( stderr, \"ERROR: could not parse transaction stamp %s\", line );\n      return -1;\n    }\n    c += r;\n\n    /* check that we're processing the expected handId */\n    if( h != *handId ) {\n\n      fprintf( stderr, \"ERROR: handId mismatch in transaction log: %s\", line );\n      return -1;\n    }\n\n    /* make sure the action is valid */\n    if( !isValidAction( game, &state->state, 0, &action ) ) {\n\n      fprintf( stderr, \"ERROR: invalid action in transaction log: %s\", line );\n      return -1;\n    }\n\n    /* check for any timeout issues */\n    s = playerToSeat( game, *player0Seat,\n\t\t      currentPlayer( game, &state->state ) );\n    if( checkErrorTimes( s, &sendTime, &recvTime, errorInfo ) < 0 ) {\n\n      fprintf( stderr,\n\t       \"ERROR: seat %\"PRIu8\" ran out of time in transaction file\\n\",\n\t       s + 1 );\n      return -1;\n    }\n\n    doAction( game, &action, &state->state );\n\n    if( stateFinished( &state->state ) ) {\n      /* hand is finished */\n\n      /* update the total value for each player */\n      for( s = 0; s < game->numPlayers; ++s ) {\n\n\ttotalValue[ s ]\n\t  += valueOfState( game, &state->state,\n\t\t\t   seatToPlayer( game, *player0Seat, s ) );\n      }\n\n      /* move on to next hand */\n      if( setUpNewHand( game, fixedSeats, handId, player0Seat,\n\t\t\trng, errorInfo, &state->state ) < 0 ) {\n\n\treturn -1;\n      }\n    }\n  }\n\n  return 0;\n}\n\n/* returns >= 0 if match should continue, -1 on failure */\nstatic int logTransaction( const Game *game, const State *state,\n\t\t\t   const Action *action,\n\t\t\t   const struct timeval *sendTime,\n\t\t\t   const struct timeval *recvTime,\n\t\t\t   FILE *file )\n{\n  int c, r;\n  char line[ MAX_LINE_LEN ];\n\n  c = printAction( game, action, MAX_LINE_LEN, line );\n  if( c < 0 ) {\n\n    fprintf( stderr, \"ERROR: transaction message too long\\n\" );\n    return -1;\n  }\n\n  r = snprintf( &line[ c ], MAX_LINE_LEN - c,\n\t\t\" %\"PRIu32\" %zu.%06zu %zu.%06zu\\n\",\n\t\tstate->handId, sendTime->tv_sec, sendTime->tv_usec,\n\t\trecvTime->tv_sec, recvTime->tv_usec );\n  if( r < 0 ) {\n\n    fprintf( stderr, \"ERROR: transaction message too long\\n\" );\n    return -1;\n  }\n  c += r;\n\n  if( fwrite( line, 1, c, file ) != c ) {\n\n    fprintf( stderr, \"ERROR: could not write to transaction file\\n\" );\n    return -1;\n  }\n  fflush( file );\n\n  return c;\n}\n\n/* returns >= 0 if match should continue, -1 on failure */\nstatic int checkVersion( const uint8_t seat,\n\t\t\t ReadBuf *readBuf )\n{\n  uint32_t major, minor, rev;\n  char line[ MAX_LINE_LEN ];\n\n\n  if( getLine( readBuf, MAX_LINE_LEN, line, -1 ) <= 0 ) {\n\n    fprintf( stderr,\n\t     \"ERROR: could not read version string from seat %\"PRIu8\"\\n\",\n\t     seat + 1 );\n    return -1;\n  }\n\n  if( sscanf( line, \"VERSION:%\"SCNu32\".%\"SCNu32\".%\"SCNu32,\n\t      &major, &minor, &rev ) < 3 ) {\n\n    fprintf( stderr,\n\t     \"ERROR: invalid version string %s\", line );\n    return -1;\n  }\n\n  if( major != VERSION_MAJOR || minor > VERSION_MINOR ) {\n\n    fprintf( stderr, \"ERROR: this server is currently using version %\"SCNu32\".%\"SCNu32\".%\"SCNu32\"\\n\", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION );\n  }\n\n  return 0;\n}\n\n/* returns >= 0 if match should continue, -1 on failure */\nstatic int addToLogFile( const Game *game, const State *state,\n\t\t\t const double value[ MAX_PLAYERS ],\n\t\t\t const uint8_t player0Seat,\n\t\t\t char *seatName[ MAX_PLAYERS ], FILE *logFile )\n{\n  int c, r;\n  uint8_t p;\n  char line[ MAX_LINE_LEN ];\n\n  /* prepare the message */\n  c = printState( game, state, MAX_LINE_LEN, line );\n  if( c < 0 ) {\n    /* message is too long */\n\n    fprintf( stderr, \"ERROR: log state message too long\\n\" );\n    return -1;\n  }\n\n  /* add the values */\n  for( p = 0; p < game->numPlayers; ++p ) {\n\n    r = snprintf( &line[ c ], MAX_LINE_LEN - c,\n\t\t  p ? \"|%.6f\" : \":%.6f\", value[ p ] );\n    if( r < 0 ) {\n\n      fprintf( stderr, \"ERROR: log message too long\\n\" );\n      return -1;\n    }\n    c += r;\n\n    /* remove trailing zeros after decimal-point */\n    while( line[ c - 1 ] == '0' ) { --c; }\n    if( line[ c - 1 ] == '.' ) { --c; }\n    line[ c ] = 0;\n  }\n\n  /* add the player names */\n  for( p = 0; p < game->numPlayers; ++p ) {\n\n    r = snprintf( &line[ c ], MAX_LINE_LEN - c,\n\t\t  p ? \"|%s\" : \":%s\",\n\t\t  seatName[ playerToSeat( game, player0Seat, p ) ] );\n    if( r < 0 ) {\n\n      fprintf( stderr, \"ERROR: log message too long\\n\" );\n      return -1;\n    }\n    c += r;\n  }\n\n  /* print the line to log and flush */\n  if( fprintf( logFile, \"%s\\n\", line ) < 0 ) {\n\n    fprintf( stderr, \"ERROR: logging failed for game %s\\n\", line );\n    return -1;\n  }\n  fflush( logFile );\n\n  return 0;\n}\n\n/* returns >= 0 if match should continue, -1 on failure */\nstatic int printInitialMessage( const char *matchName, const char *gameName,\n\t\t\t\tconst uint32_t numHands, const uint32_t seed,\n\t\t\t\tconst ErrorInfo *info, FILE *logFile )\n{\n  int c;\n  char line[ MAX_LINE_LEN ];\n\n  c = snprintf( line, MAX_LINE_LEN, \"# name/game/hands/seed %s %s %\"PRIu32\" %\"PRIu32\"\\n#--t_response %\"PRIu64\"\\n#--t_hand %\"PRIu64\"\\n#--t_per_hand %\"PRIu64\"\\n\",\n\t\tmatchName, gameName, numHands, seed,\n\t\tinfo->maxResponseMicros / 1000,\n\t\tinfo->maxUsedHandMicros / 1000,\n\t\tinfo->maxUsedMatchMicros / numHands / 1000 );\n  if( c < 0 ) {\n    /* message is too long */\n\n    fprintf( stderr, \"ERROR: initial game comment too long\\n\" );\n    return -1;\n  }\n\n  fprintf( stderr, \"%s\", line );\n  if( logFile ) {\n\n    fprintf( logFile, \"%s\", line );\n  }\n\n  return 0;\n}\n\n/* returns >= 0 if match should continue, -1 on failure */\nstatic int printFinalMessage( const Game *game, char *seatName[ MAX_PLAYERS ],\n\t\t\t      const double totalValue[ MAX_PLAYERS ],\n\t\t\t      FILE *logFile )\n{\n  int c, r;\n  uint8_t s;\n  char line[ MAX_LINE_LEN ];\n\n  c = snprintf( line, MAX_LINE_LEN, \"SCORE\" );\n  if( c < 0 ) {\n    /* message is too long */\n\n    fprintf( stderr, \"ERROR: value state message too long\\n\" );\n    return -1;\n  }\n\n  for( s = 0; s < game->numPlayers; ++s ) {\n\n    r = snprintf( &line[ c ], MAX_LINE_LEN - c,\n\t\t  s ? \"|%.6f\" : \":%.6f\", totalValue[ s ] );\n    if( r < 0 ) {\n\n      fprintf( stderr, \"ERROR: value message too long\\n\" );\n      return -1;\n    }\n    c += r;\n\n    /* remove trailing zeros after decimal-point */\n    while( line[ c - 1 ] == '0' ) { --c; }\n    if( line[ c - 1 ] == '.' ) { --c; }\n    line[ c ] = 0;\n  }\n\n  /* add the player names */\n  for( s = 0; s < game->numPlayers; ++s ) {\n\n    r = snprintf( &line[ c ], MAX_LINE_LEN - c,\n\t\t  s ? \"|%s\" : \":%s\", seatName[ s ] );\n    if( r < 0 ) {\n\n      fprintf( stderr, \"ERROR: log message too long\\n\" );\n      return -1;\n    }\n    c += r;\n  }\n\n  fprintf( stdout, \"%s\\n\", line );\n  fprintf( stderr, \"%s\\n\", line );\n\n  if( logFile ) {\n\n    fprintf( logFile, \"%s\\n\", line );\n  }\n\n  return 0;\n}\n\n/* run a match of numHands hands of the supplied game\n\n   cards are dealt using rng, error conditions like timeouts\n   are controlled and stored in errorInfo\n\n   actions are read/sent to seat p on seatFD[ p ]\n\n   if quiet is not zero, only print out errors, warnings, and final value\n\n   if logFile is not NULL, print out a single line for each completed\n   match with the final state and all player values.  The values are\n   printed in player, not seat order.\n\n   if transactionFile is not NULL, a transaction log of actions made\n   is written to the file, and if there is any input left to read on\n   the stream when gameLoop is called, it will be processed to\n   initialise the state\n\n   returns >=0 if the match finished correctly, -1 on error */\nstatic int gameLoop( const Game *game, char *seatName[ MAX_PLAYERS ],\n\t\t     const uint32_t numHands, const int quiet,\n\t\t     const int fixedSeats, rng_state_t *rng,\n\t\t     ErrorInfo *errorInfo, const int seatFD[ MAX_PLAYERS ],\n\t\t     ReadBuf *readBuf[ MAX_PLAYERS ],\n\t\t     FILE *logFile, FILE *transactionFile )\n{\n  uint32_t handId;\n  uint8_t seat, p, player0Seat, currentP, currentSeat;\n  struct timeval t, sendTime, recvTime;\n  Action action;\n  MatchState state;\n  double value[ MAX_PLAYERS ], totalValue[ MAX_PLAYERS ];\n\n  /* check version string for each player */\n  for( seat = 0; seat < game->numPlayers; ++seat ) {\n\n    if( checkVersion( seat, readBuf[ seat ] ) < 0 ) {\n      /* error messages already handled in function */\n\n      return -1;\n    }\n  }\n\n  gettimeofday( &sendTime, NULL );\n  if( !quiet ) {\n    fprintf( stderr, \"STARTED at %zu.%06zu\\n\",\n\t     sendTime.tv_sec, sendTime.tv_usec );\n  }\n\n  /* start at the first hand */\n  handId = 0;\n  if( checkErrorNewHand( game, errorInfo ) < 0 ) {\n\n    fprintf( stderr, \"ERROR: unexpected game\\n\" );\n    return -1;\n  }\n  initState( game, handId, &state.state );\n  dealCards( game, rng, &state.state );\n  for( seat = 0; seat < game->numPlayers; ++seat ) {\n    totalValue[ seat ] = 0.0;\n  }\n\n  /* seat 0 is player 0 in first game */\n  player0Seat = 0;\n\n  /* process the transaction file */\n  if( transactionFile != NULL ) {\n\n    if( processTransactionFile( game, fixedSeats, &handId, &player0Seat,\n\t\t\t\trng, errorInfo, totalValue,\n\t\t\t\t&state, transactionFile ) < 0 ) {\n      /* error messages already handled in function */\n\n      return -1;\n    }\n  }\n\n  if( handId >= numHands ) {\n    goto finishedGameLoop;\n  }\n\n  /* play all the (remaining) hands */\n  while( 1 ) {\n\n    /* play the hand */\n    while( !stateFinished( &state.state ) ) {\n\n      /* find the current player */\n      currentP = currentPlayer( game, &state.state );\n\n      /* send state to each player */\n      for( seat = 0; seat < game->numPlayers; ++seat ) {\n\n\tstate.viewingPlayer = seatToPlayer( game, player0Seat, seat );\n\tif( sendPlayerMessage( game, &state, quiet, seat,\n\t\t\t       seatFD[ seat ], &t ) < 0 ) {\n\t  /* error messages already handled in function */\n\n\t  return -1;\n\t}\n\n\t/* remember the seat and send time if player is acting */\n\tif( state.viewingPlayer == currentP ) {\n\n\t  sendTime = t;\n\t}\n      }\n\n      /* get action from current player */\n      state.viewingPlayer = currentP;\n      currentSeat = playerToSeat( game, player0Seat, currentP );\n      if( readPlayerResponse( game, &state, quiet, currentSeat, &sendTime,\n\t\t\t      errorInfo, readBuf[ currentSeat ],\n\t\t\t      &action, &recvTime ) < 0 ) {\n\t/* error messages already handled in function */\n\n\treturn -1;\n      }\n\n      /* log the transaction */\n      if( transactionFile != NULL ) {\n\n\tif( logTransaction( game, &state.state, &action,\n\t\t\t    &sendTime, &recvTime, transactionFile ) < 0 ) {\n\t  /* error messages already handled in function */\n\n\t  return -1;\n\t}\n      }\n\n      /* do the action */\n      doAction( game, &action, &state.state );\n    }\n\n    /* get values */\n    for( p = 0; p < game->numPlayers; ++p ) {\n\n      value[ p ] = valueOfState( game, &state.state, p );\n      totalValue[ playerToSeat( game, player0Seat, p ) ] += value[ p ];\n    }\n\n    /* add the game to the log */\n    if( logFile != NULL ) {\n\n      if( addToLogFile( game, &state.state, value, player0Seat,\n\t\t\tseatName, logFile ) < 0 ) {\n\t/* error messages already handled in function */\n\n\treturn -1;\n      }\n    }\n\n    /* send final state to each player */\n    for( seat = 0; seat < game->numPlayers; ++seat ) {\n\n      state.viewingPlayer = seatToPlayer( game, player0Seat, seat );\n      if( sendPlayerMessage( game, &state, quiet, seat,\n\t\t\t     seatFD[ seat ], &t ) < 0 ) {\n\t/* error messages already handled in function */\n\n\treturn -1;\n      }\n    }\n\n    if ( !quiet ) {\n      if ( handId % 100 == 0) {\n\tfor( seat = 0; seat < game->numPlayers; ++seat ) {\n\t  fprintf(stderr, \"Seconds cumulatively spent in match for seat %i: \"\n\t\t  \"%i\\n\", seat,\n\t\t  (int)(errorInfo->usedMatchMicros[ seat ] / 1000000));\n\t}\n      }\n    }\n\n    /* start a new hand */\n    if( setUpNewHand( game, fixedSeats, &handId, &player0Seat,\n\t\t      rng, errorInfo, &state.state ) < 0 ) {\n      /* error messages already handled in function */\n\n      return -1;\n    }\n    if( handId >= numHands ) {\n      break;\n    }\n  }\n\n finishedGameLoop:\n  /* print out the final values */\n  if( !quiet ) {\n    gettimeofday( &t, NULL );\n    fprintf( stderr, \"FINISHED at %zu.%06zu\\n\",\n\t     sendTime.tv_sec, sendTime.tv_usec );\n  }\n  if( printFinalMessage( game, seatName, totalValue, logFile ) < 0 ) {\n    /* error messages already handled in function */\n\n    return -1;\n  }\n\n  return 0;\n}\n\nint main( int argc, char **argv )\n{\n  int i, listenSocket[ MAX_PLAYERS ], v, longOpt;\n  int fixedSeats, quiet, append;\n  int seatFD[ MAX_PLAYERS ];\n  FILE *file, *logFile, *transactionFile;\n  ReadBuf *readBuf[ MAX_PLAYERS ];\n  Game *game;\n  rng_state_t rng;\n  ErrorInfo errorInfo;\n  struct sockaddr_in addr;\n  socklen_t addrLen;\n  char *seatName[ MAX_PLAYERS ];\n\n  int useLogFile, useTransactionFile;\n  uint64_t maxResponseMicros, maxUsedHandMicros, maxUsedPerHandMicros;\n  int64_t startTimeoutMicros;\n  uint32_t numHands, seed, maxInvalidActions;\n  uint16_t listenPort[ MAX_PLAYERS ];\n\n  struct timeval startTime, tv;\n\n  char name[ MAX_LINE_LEN ];\n  static struct option longOptions[] = {\n    { \"t_response\", 1, 0, 0 },\n    { \"t_hand\", 1, 0, 0 },\n    { \"t_per_hand\", 1, 0, 0 },\n    { \"start_timeout\", 1, 0, 0 },\n    { 0, 0, 0, 0 }\n  };\n\n  /* set defaults */\n\n  /* game error conditions */\n  maxInvalidActions = DEFAULT_MAX_INVALID_ACTIONS;\n  maxResponseMicros = DEFAULT_MAX_RESPONSE_MICROS;\n  maxUsedHandMicros = DEFAULT_MAX_USED_HAND_MICROS;\n  maxUsedPerHandMicros = DEFAULT_MAX_USED_PER_HAND_MICROS;\n\n  /* use random ports */\n  for( i = 0; i < MAX_PLAYERS; ++i ) {\n\n    listenPort[ i ] = 0;\n  }\n\n  /* use log file, don't use transaction file */\n  useLogFile = 1;\n  useTransactionFile = 0;\n\n  /* print all messages */\n  quiet = 0;\n\n  /* by default, overwrite preexisting log/transaction files */\n  append = 0;\n\n  /* players rotate around the table */\n  fixedSeats = 0;\n\n  /* no timeout on startup */\n  startTimeoutMicros = -1;\n\n  /* parse options */\n  while( 1 ) {\n\n    i = getopt_long( argc, argv, \"flLp:qtTa\", longOptions, &longOpt );\n    if( i < 0 ) {\n\n      break;\n    }\n\n    switch( i ) {\n    case 0:\n      /* long option longOpt */\n\n      switch( longOpt ) {\n      case 0:\n\t/* t_response */\n\n\tif( sscanf( optarg, \"%\"SCNu64, &maxResponseMicros ) < 1 ) {\n\n\t  fprintf( stderr, \"ERROR: could not get response timeout from %s\\n\",\n\t\t   optarg );\n\t  exit( EXIT_FAILURE );\n\t}\n\n\t/* convert from milliseconds to microseconds */\n\tmaxResponseMicros *= 1000;\n\tbreak;\n\n      case 1:\n\t/* t_hand */\n\n\tif( sscanf( optarg, \"%\"SCNu64, &maxUsedHandMicros ) < 1 ) {\n\n\t  fprintf( stderr,\n\t\t   \"ERROR: could not get player hand timeout from %s\\n\",\n\t\t   optarg );\n\t  exit( EXIT_FAILURE );\n\t}\n\n\t/* convert from milliseconds to microseconds */\n\tmaxUsedHandMicros *= 1000;\n\tbreak;\n\n      case 2:\n\t/* t_per_hand */\n\n\tif( sscanf( optarg, \"%\"SCNu64, &maxUsedPerHandMicros ) < 1 ) {\n\n\t  fprintf( stderr, \"ERROR: could not get average player hand timeout from %s\\n\", optarg );\n\t  exit( EXIT_FAILURE );\n\t}\n\n\t/* convert from milliseconds to microseconds */\n\tmaxUsedPerHandMicros *= 1000;\n\tbreak;\n\n      case 3:\n\t/* start_timeout */\n\n\tif( sscanf( optarg, \"%\"SCNd64, &startTimeoutMicros ) < 1 ) {\n\n\t  fprintf( stderr, \"ERROR: could not get start timeout %s\\n\", optarg );\n\t  exit( EXIT_FAILURE );\n\t}\n\n\t/* convert from milliseconds to microseconds */\n\tif( startTimeoutMicros > 0 ) {\n\n\t  startTimeoutMicros *= 1000;\n\t}\n\tbreak;\n\n      }\n      break;\n\n    case 'f':\n      /* fix the player seats */;\n\n      fixedSeats = 1;\n      break;\n\n    case 'l':\n      /* no transactionFile */;\n\n      useLogFile = 0;\n      break;\n\n    case 'L':\n      /* use transactionFile */;\n\n      useLogFile = 1;\n      break;\n\n    case 'p':\n      /* port specification */\n\n      if( scanPortString( optarg, listenPort ) < 0 ) {\n\n\tfprintf( stderr, \"ERROR: bad port string %s\\n\", optarg );\n\texit( EXIT_FAILURE );\n      }\n\n      break;\n\n    case 'q':\n\n      quiet = 1;\n      break;\n\n    case 't':\n      /* no transactionFile */\n\n      useTransactionFile = 0;\n      break;\n\n    case 'T':\n      /* use transactionFile */\n\n      useTransactionFile = 1;\n      break;\n\n    case 'a':\n\n      append = 1;\n      break;\n\n    default:\n\n      fprintf( stderr, \"ERROR: unknown option %c\\n\", i );\n      exit( EXIT_FAILURE );\n    }\n  }\n\n  if( optind + 4 > argc ) {\n\n    printUsage( stdout, 0 );\n    exit( EXIT_FAILURE );\n  }\n\n  /* get the game definition */\n  file = fopen( argv[ optind + 1 ], \"r\" );\n  if( file == NULL ) {\n\n    fprintf( stderr, \"ERROR: could not open game definition %s\\n\",\n\t     argv[ optind + 1 ] );\n    exit( EXIT_FAILURE );\n  }\n  game = readGame( file );\n  if( game == NULL ) {\n\n    fprintf( stderr, \"ERROR: could not read game %s\\n\", argv[ optind + 1 ] );\n    exit( EXIT_FAILURE );\n  }\n  fclose( file );\n\n  /* save the seat names */\n  if( optind + 4 + game->numPlayers > argc ) {\n\n    printUsage( stdout, 0 );\n    exit( EXIT_FAILURE );\n  }\n  for( i = 0; i < game->numPlayers; ++i ) {\n\n    seatName[ i ] = argv[ optind + 4 + i ];\n  }\n\n  /* get number of hands */\n  if( sscanf( argv[ optind + 2 ], \"%\"SCNu32, &numHands ) < 1\n      || numHands == 0 ) {\n\n    fprintf( stderr, \"ERROR: invalid number of hands %s\\n\",\n\t     argv[ optind + 2 ] );\n    exit( EXIT_FAILURE );\n  }\n\n  /* get random number seed */\n  if( sscanf( argv[ optind + 3 ], \"%\"SCNu32, &seed ) < 1 ) {\n\n    fprintf( stderr, \"ERROR: invalid random number seed %s\\n\",\n\t     argv[ optind + 3 ] );\n    exit( EXIT_FAILURE );\n  }\n  init_genrand( &rng, seed );\n  srandom( seed ); /* used for random port selection */\n\n  if( useLogFile ) {\n    /* create/open the log */\n    if( snprintf( name, MAX_LINE_LEN, \"%s.log\", argv[ optind ] ) < 0 ) {\n\n      fprintf( stderr, \"ERROR: match file name too long %s\\n\", argv[ optind ] );\n      exit( EXIT_FAILURE );\n    }\n    if (append) {\n      logFile = fopen( name, \"a+\" );\n    } else {\n      logFile = fopen( name, \"w\" );\n    }\n    if( logFile == NULL ) {\n\n      fprintf( stderr, \"ERROR: could not open log file %s\\n\", name );\n      exit( EXIT_FAILURE );\n    }\n  } else {\n    /* no log file */\n\n    logFile = NULL;\n  }\n\n  if( useTransactionFile ) {\n    /* create/open the transaction log */\n\n    if( snprintf( name, MAX_LINE_LEN, \"%s.tlog\", argv[ optind ] ) < 0 ) {\n\n      fprintf( stderr, \"ERROR: match file name too long %s\\n\", argv[ optind ] );\n      exit( EXIT_FAILURE );\n    }\n    if (append) {\n      transactionFile = fopen( name, \"a+\" );\n    } else {\n      transactionFile = fopen( name, \"w\" );\n    }\n    if( transactionFile == NULL ) {\n\n      fprintf( stderr, \"ERROR: could not open transaction file %s\\n\", name );\n      exit( EXIT_FAILURE );\n    }\n  } else {\n    /* no transaction file */\n\n    transactionFile = NULL;\n  }\n\n  /* set up the error info */\n  initErrorInfo( maxInvalidActions, maxResponseMicros, maxUsedHandMicros,\n\t\t maxUsedPerHandMicros * numHands, &errorInfo );\n\n  /* open sockets for players to connect to */\n  for( i = 0; i < game->numPlayers; ++i ) {\n\n    listenSocket[ i ] = getListenSocket( &listenPort[ i ] );\n    if( listenSocket[ i ] < 0 ) {\n\n      fprintf( stderr, \"ERROR: could not create listen socket for player %d\\n\",\n\t       i + 1 );\n      exit( EXIT_FAILURE );\n    }\n  }\n\n  /* print out the final port assignments */\n  for( i = 0; i < game->numPlayers; ++i ) {\n\n    printf( i ? \" %\"PRIu16 : \"%\"PRIu16, listenPort[ i ] );\n  }\n  printf( \"\\n\" );\n  fflush( stdout );\n\n  /* print out usage information */\n  printInitialMessage( argv[ optind ], argv[ optind + 1 ],\n\t\t       numHands, seed, &errorInfo, logFile );\n\n  /* wait for each player to connect */\n  gettimeofday( &startTime, NULL );\n  for( i = 0; i < game->numPlayers; ++i ) {\n\n    if( startTimeoutMicros >= 0 ) {\n      uint64_t startTimeLeft;\n      fd_set fds;\n\n      gettimeofday( &tv, NULL );\n      startTimeLeft = startTimeoutMicros\n\t- (uint64_t)( tv.tv_sec - startTime.tv_sec ) * 1000000\n\t- ( tv.tv_usec - startTime.tv_usec );\n      if( startTimeLeft < 0 ) {\n\n\tstartTimeLeft = 0;\n      }\n      tv.tv_sec = startTimeLeft / 1000000;\n      tv.tv_usec = startTimeLeft % 1000000;\n\n      FD_ZERO( &fds );\n      FD_SET( listenSocket[ i ], &fds );\n      if( select( listenSocket[ i ] + 1, &fds, NULL, NULL, &tv ) < 1 ) {\n\t/* no input ready within time, or an actual error */\n\n\tfprintf( stderr, \"ERROR: timed out waiting for seat %d to connect\\n\",\n\t\t i + 1 );\n\texit( EXIT_FAILURE );\n      }\n    }\n\n    addrLen = sizeof( addr );\n    seatFD[ i ] = accept( listenSocket[ i ],\n\t\t\t  (struct sockaddr *)&addr, &addrLen );\n    if( seatFD[ i ] < 0 ) {\n\n      fprintf( stderr, \"ERROR: seat %d could not connect\\n\", i + 1 );\n      exit( EXIT_FAILURE );\n    }\n    close( listenSocket[ i ] );\n\n    v = 1;\n    setsockopt( seatFD[ i ], IPPROTO_TCP, TCP_NODELAY,\n\t\t(char *)&v, sizeof(int) );\n\n    readBuf[ i ] = createReadBuf( seatFD[ i ] );\n  }\n\n  /* play the match */\n  if( gameLoop( game, seatName, numHands, quiet, fixedSeats, &rng, &errorInfo,\n\t\tseatFD, readBuf, logFile, transactionFile ) < 0 ) {\n    /* should have already printed an error message */\n\n    exit( EXIT_FAILURE );\n  }\n\n  fflush( stderr );\n  fflush( stdout );\n  if( transactionFile != NULL ) {\n    fclose( transactionFile );\n  }\n  if( logFile != NULL ) {\n    fclose( logFile );\n  }\n  free( game );\n\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "ACPCServer/evalHandTables",
    "content": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n/* high card\t1287\t0\n   pair\t\t3718\t1287\n   two pair\t3601\t5005\n   trips\t1014\t8606\n   straight\t13\t9620\n   flush\t1287\t9633\n   f_house\t1014\t10920\n   quads\t169\t11934\n   s_flush\t13\t12103 */\n#define HANDCLASS_SINGLE_CARD 0\n#define HANDCLASS_PAIR 1287\n#define HANDCLASS_TWO_PAIR 5005\n#define HANDCLASS_TRIPS 8606\n#define HANDCLASS_STRAIGHT 9620\n#define HANDCLASS_FLUSH 9633\n#define HANDCLASS_FULL_HOUSE 10920\n#define HANDCLASS_QUADS 11934\n#define HANDCLASS_STRAIGHT_FLUSH 12103\n\ntypedef union {\n  uint16_t bySuit[ 4 ];\n  uint64_t cards;\n} Cardset;\n\nstatic const uint16_t oneSuitVal[ 8192 ] = {\n  0, 0, 0, 0, 0, 0, 0, 0, \n  0, 0, 0, 0, 0, 0, 0, 0, \n  0, 0, 0, 0, 0, 0, 0, 0, \n  0, 0, 0, 0, 0, 0, 0, 12107, \n  0, 0, 0, 0, 0, 0, 0, 0, \n  0, 0, 0, 0, 0, 0, 0, 9634, \n  0, 0, 0, 0, 0, 0, 0, 9635, \n  0, 0, 0, 9636, 0, 9637, 12108, 12108, \n  0, 0, 0, 0, 0, 0, 0, 0, \n  0, 0, 0, 0, 0, 0, 0, 9639, \n  0, 0, 0, 0, 0, 0, 0, 9640, \n  0, 0, 0, 9641, 0, 9642, 9643, 12107, \n  0, 0, 0, 0, 0, 0, 0, 9644, \n  0, 0, 0, 9645, 0, 9646, 9647, 9647, \n  0, 0, 0, 9648, 0, 9649, 9650, 9650, \n  0, 9651, 9652, 9652, 12109, 12109, 12109, 12109, \n  0, 0, 0, 0, 0, 0, 0, 0, \n  0, 0, 0, 0, 0, 0, 0, 9654, \n  0, 0, 0, 0, 0, 0, 0, 9655, \n  0, 0, 0, 9656, 0, 9657, 9658, 12107, \n  0, 0, 0, 0, 0, 0, 0, 9659, \n  0, 0, 0, 9660, 0, 9661, 9662, 9662, \n  0, 0, 0, 9663, 0, 9664, 9665, 9665, \n  0, 9666, 9667, 9667, 9668, 9668, 12108, 12108, \n  0, 0, 0, 0, 0, 0, 0, 9669, \n  0, 0, 0, 9670, 0, 9671, 9672, 9672, \n  0, 0, 0, 9673, 0, 9674, 9675, 9675, \n  0, 9676, 9677, 9677, 9678, 9678, 9678, 12107, \n  0, 0, 0, 9679, 0, 9680, 9681, 9681, \n  0, 9682, 9683, 9683, 9684, 9684, 9684, 9684, \n  0, 9685, 9686, 9686, 9687, 9687, 9687, 9687, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 0, 0, 0, 0, 0, 0, 0, \n  0, 0, 0, 0, 0, 0, 0, 9689, \n  0, 0, 0, 0, 0, 0, 0, 9690, \n  0, 0, 0, 9691, 0, 9692, 9693, 12107, \n  0, 0, 0, 0, 0, 0, 0, 9694, \n  0, 0, 0, 9695, 0, 9696, 9697, 9697, \n  0, 0, 0, 9698, 0, 9699, 9700, 9700, \n  0, 9701, 9702, 9702, 9703, 9703, 12108, 12108, \n  0, 0, 0, 0, 0, 0, 0, 9704, \n  0, 0, 0, 9705, 0, 9706, 9707, 9707, \n  0, 0, 0, 9708, 0, 9709, 9710, 9710, \n  0, 9711, 9712, 9712, 9713, 9713, 9713, 12107, \n  0, 0, 0, 9714, 0, 9715, 9716, 9716, \n  0, 9717, 9718, 9718, 9719, 9719, 9719, 9719, \n  0, 9720, 9721, 9721, 9722, 9722, 9722, 9722, \n  9723, 9723, 9723, 9723, 12109, 12109, 12109, 12109, \n  0, 0, 0, 0, 0, 0, 0, 9724, \n  0, 0, 0, 9725, 0, 9726, 9727, 9727, \n  0, 0, 0, 9728, 0, 9729, 9730, 9730, \n  0, 9731, 9732, 9732, 9733, 9733, 9733, 12107, \n  0, 0, 0, 9734, 0, 9735, 9736, 9736, \n  0, 9737, 9738, 9738, 9739, 9739, 9739, 9739, \n  0, 9740, 9741, 9741, 9742, 9742, 9742, 9742, \n  9743, 9743, 9743, 9743, 9743, 9743, 12108, 12108, \n  0, 0, 0, 9744, 0, 9745, 9746, 9746, \n  0, 9747, 9748, 9748, 9749, 9749, 9749, 9749, \n  0, 9750, 9751, 9751, 9752, 9752, 9752, 9752, \n  9753, 9753, 9753, 9753, 9753, 9753, 9753, 12107, \n  0, 9754, 9755, 9755, 9756, 9756, 9756, 9756, \n  9757, 9757, 9757, 9757, 9757, 9757, 9757, 9757, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  0, 0, 0, 0, 0, 0, 0, 0, \n  0, 0, 0, 0, 0, 0, 0, 9759, \n  0, 0, 0, 0, 0, 0, 0, 9760, \n  0, 0, 0, 9761, 0, 9762, 9763, 12107, \n  0, 0, 0, 0, 0, 0, 0, 9764, \n  0, 0, 0, 9765, 0, 9766, 9767, 9767, \n  0, 0, 0, 9768, 0, 9769, 9770, 9770, \n  0, 9771, 9772, 9772, 9773, 9773, 12108, 12108, \n  0, 0, 0, 0, 0, 0, 0, 9774, \n  0, 0, 0, 9775, 0, 9776, 9777, 9777, \n  0, 0, 0, 9778, 0, 9779, 9780, 9780, \n  0, 9781, 9782, 9782, 9783, 9783, 9783, 12107, \n  0, 0, 0, 9784, 0, 9785, 9786, 9786, \n  0, 9787, 9788, 9788, 9789, 9789, 9789, 9789, \n  0, 9790, 9791, 9791, 9792, 9792, 9792, 9792, \n  9793, 9793, 9793, 9793, 12109, 12109, 12109, 12109, \n  0, 0, 0, 0, 0, 0, 0, 9794, \n  0, 0, 0, 9795, 0, 9796, 9797, 9797, \n  0, 0, 0, 9798, 0, 9799, 9800, 9800, \n  0, 9801, 9802, 9802, 9803, 9803, 9803, 12107, \n  0, 0, 0, 9804, 0, 9805, 9806, 9806, \n  0, 9807, 9808, 9808, 9809, 9809, 9809, 9809, \n  0, 9810, 9811, 9811, 9812, 9812, 9812, 9812, \n  9813, 9813, 9813, 9813, 9813, 9813, 12108, 12108, \n  0, 0, 0, 9814, 0, 9815, 9816, 9816, \n  0, 9817, 9818, 9818, 9819, 9819, 9819, 9819, \n  0, 9820, 9821, 9821, 9822, 9822, 9822, 9822, \n  9823, 9823, 9823, 9823, 9823, 9823, 9823, 12107, \n  0, 9824, 9825, 9825, 9826, 9826, 9826, 9826, \n  9827, 9827, 9827, 9827, 9827, 9827, 9827, 9827, \n  9828, 9828, 9828, 9828, 9828, 9828, 9828, 9828, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 0, 0, 0, 0, 0, 0, 9829, \n  0, 0, 0, 9830, 0, 9831, 9832, 9832, \n  0, 0, 0, 9833, 0, 9834, 9835, 9835, \n  0, 9836, 9837, 9837, 9838, 9838, 9838, 12107, \n  0, 0, 0, 9839, 0, 9840, 9841, 9841, \n  0, 9842, 9843, 9843, 9844, 9844, 9844, 9844, \n  0, 9845, 9846, 9846, 9847, 9847, 9847, 9847, \n  9848, 9848, 9848, 9848, 9848, 9848, 12108, 12108, \n  0, 0, 0, 9849, 0, 9850, 9851, 9851, \n  0, 9852, 9853, 9853, 9854, 9854, 9854, 9854, \n  0, 9855, 9856, 9856, 9857, 9857, 9857, 9857, \n  9858, 9858, 9858, 9858, 9858, 9858, 9858, 12107, \n  0, 9859, 9860, 9860, 9861, 9861, 9861, 9861, \n  9862, 9862, 9862, 9862, 9862, 9862, 9862, 9862, \n  9863, 9863, 9863, 9863, 9863, 9863, 9863, 9863, \n  9863, 9863, 9863, 9863, 12109, 12109, 12109, 12109, \n  0, 0, 0, 9864, 0, 9865, 9866, 9866, \n  0, 9867, 9868, 9868, 9869, 9869, 9869, 9869, \n  0, 9870, 9871, 9871, 9872, 9872, 9872, 9872, \n  9873, 9873, 9873, 9873, 9873, 9873, 9873, 12107, \n  0, 9874, 9875, 9875, 9876, 9876, 9876, 9876, \n  9877, 9877, 9877, 9877, 9877, 9877, 9877, 9877, \n  9878, 9878, 9878, 9878, 9878, 9878, 9878, 9878, \n  9878, 9878, 9878, 9878, 9878, 9878, 12108, 12108, \n  0, 9879, 9880, 9880, 9881, 9881, 9881, 9881, \n  9882, 9882, 9882, 9882, 9882, 9882, 9882, 9882, \n  9883, 9883, 9883, 9883, 9883, 9883, 9883, 9883, \n  9883, 9883, 9883, 9883, 9883, 9883, 9883, 12107, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  0, 0, 0, 0, 0, 0, 0, 0, \n  0, 0, 0, 0, 0, 0, 0, 9885, \n  0, 0, 0, 0, 0, 0, 0, 9886, \n  0, 0, 0, 9887, 0, 9888, 9889, 12107, \n  0, 0, 0, 0, 0, 0, 0, 9890, \n  0, 0, 0, 9891, 0, 9892, 9893, 9893, \n  0, 0, 0, 9894, 0, 9895, 9896, 9896, \n  0, 9897, 9898, 9898, 9899, 9899, 12108, 12108, \n  0, 0, 0, 0, 0, 0, 0, 9900, \n  0, 0, 0, 9901, 0, 9902, 9903, 9903, \n  0, 0, 0, 9904, 0, 9905, 9906, 9906, \n  0, 9907, 9908, 9908, 9909, 9909, 9909, 12107, \n  0, 0, 0, 9910, 0, 9911, 9912, 9912, \n  0, 9913, 9914, 9914, 9915, 9915, 9915, 9915, \n  0, 9916, 9917, 9917, 9918, 9918, 9918, 9918, \n  9919, 9919, 9919, 9919, 12109, 12109, 12109, 12109, \n  0, 0, 0, 0, 0, 0, 0, 9920, \n  0, 0, 0, 9921, 0, 9922, 9923, 9923, \n  0, 0, 0, 9924, 0, 9925, 9926, 9926, \n  0, 9927, 9928, 9928, 9929, 9929, 9929, 12107, \n  0, 0, 0, 9930, 0, 9931, 9932, 9932, \n  0, 9933, 9934, 9934, 9935, 9935, 9935, 9935, \n  0, 9936, 9937, 9937, 9938, 9938, 9938, 9938, \n  9939, 9939, 9939, 9939, 9939, 9939, 12108, 12108, \n  0, 0, 0, 9940, 0, 9941, 9942, 9942, \n  0, 9943, 9944, 9944, 9945, 9945, 9945, 9945, \n  0, 9946, 9947, 9947, 9948, 9948, 9948, 9948, \n  9949, 9949, 9949, 9949, 9949, 9949, 9949, 12107, \n  0, 9950, 9951, 9951, 9952, 9952, 9952, 9952, \n  9953, 9953, 9953, 9953, 9953, 9953, 9953, 9953, \n  9954, 9954, 9954, 9954, 9954, 9954, 9954, 9954, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 0, 0, 0, 0, 0, 0, 9955, \n  0, 0, 0, 9956, 0, 9957, 9958, 9958, \n  0, 0, 0, 9959, 0, 9960, 9961, 9961, \n  0, 9962, 9963, 9963, 9964, 9964, 9964, 12107, \n  0, 0, 0, 9965, 0, 9966, 9967, 9967, \n  0, 9968, 9969, 9969, 9970, 9970, 9970, 9970, \n  0, 9971, 9972, 9972, 9973, 9973, 9973, 9973, \n  9974, 9974, 9974, 9974, 9974, 9974, 12108, 12108, \n  0, 0, 0, 9975, 0, 9976, 9977, 9977, \n  0, 9978, 9979, 9979, 9980, 9980, 9980, 9980, \n  0, 9981, 9982, 9982, 9983, 9983, 9983, 9983, \n  9984, 9984, 9984, 9984, 9984, 9984, 9984, 12107, \n  0, 9985, 9986, 9986, 9987, 9987, 9987, 9987, \n  9988, 9988, 9988, 9988, 9988, 9988, 9988, 9988, \n  9989, 9989, 9989, 9989, 9989, 9989, 9989, 9989, \n  9989, 9989, 9989, 9989, 12109, 12109, 12109, 12109, \n  0, 0, 0, 9990, 0, 9991, 9992, 9992, \n  0, 9993, 9994, 9994, 9995, 9995, 9995, 9995, \n  0, 9996, 9997, 9997, 9998, 9998, 9998, 9998, \n  9999, 9999, 9999, 9999, 9999, 9999, 9999, 12107, \n  0, 10000, 10001, 10001, 10002, 10002, 10002, 10002, \n  10003, 10003, 10003, 10003, 10003, 10003, 10003, 10003, \n  10004, 10004, 10004, 10004, 10004, 10004, 10004, 10004, \n  10004, 10004, 10004, 10004, 10004, 10004, 12108, 12108, \n  0, 10005, 10006, 10006, 10007, 10007, 10007, 10007, \n  10008, 10008, 10008, 10008, 10008, 10008, 10008, 10008, \n  10009, 10009, 10009, 10009, 10009, 10009, 10009, 10009, \n  10009, 10009, 10009, 10009, 10009, 10009, 10009, 12107, \n  10010, 10010, 10010, 10010, 10010, 10010, 10010, 10010, \n  10010, 10010, 10010, 10010, 10010, 10010, 10010, 10010, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  0, 0, 0, 0, 0, 0, 0, 10011, \n  0, 0, 0, 10012, 0, 10013, 10014, 10014, \n  0, 0, 0, 10015, 0, 10016, 10017, 10017, \n  0, 10018, 10019, 10019, 10020, 10020, 10020, 12107, \n  0, 0, 0, 10021, 0, 10022, 10023, 10023, \n  0, 10024, 10025, 10025, 10026, 10026, 10026, 10026, \n  0, 10027, 10028, 10028, 10029, 10029, 10029, 10029, \n  10030, 10030, 10030, 10030, 10030, 10030, 12108, 12108, \n  0, 0, 0, 10031, 0, 10032, 10033, 10033, \n  0, 10034, 10035, 10035, 10036, 10036, 10036, 10036, \n  0, 10037, 10038, 10038, 10039, 10039, 10039, 10039, \n  10040, 10040, 10040, 10040, 10040, 10040, 10040, 12107, \n  0, 10041, 10042, 10042, 10043, 10043, 10043, 10043, \n  10044, 10044, 10044, 10044, 10044, 10044, 10044, 10044, \n  10045, 10045, 10045, 10045, 10045, 10045, 10045, 10045, \n  10045, 10045, 10045, 10045, 12109, 12109, 12109, 12109, \n  0, 0, 0, 10046, 0, 10047, 10048, 10048, \n  0, 10049, 10050, 10050, 10051, 10051, 10051, 10051, \n  0, 10052, 10053, 10053, 10054, 10054, 10054, 10054, \n  10055, 10055, 10055, 10055, 10055, 10055, 10055, 12107, \n  0, 10056, 10057, 10057, 10058, 10058, 10058, 10058, \n  10059, 10059, 10059, 10059, 10059, 10059, 10059, 10059, \n  10060, 10060, 10060, 10060, 10060, 10060, 10060, 10060, \n  10060, 10060, 10060, 10060, 10060, 10060, 12108, 12108, \n  0, 10061, 10062, 10062, 10063, 10063, 10063, 10063, \n  10064, 10064, 10064, 10064, 10064, 10064, 10064, 10064, \n  10065, 10065, 10065, 10065, 10065, 10065, 10065, 10065, \n  10065, 10065, 10065, 10065, 10065, 10065, 10065, 12107, \n  10066, 10066, 10066, 10066, 10066, 10066, 10066, 10066, \n  10066, 10066, 10066, 10066, 10066, 10066, 10066, 10066, \n  10066, 10066, 10066, 10066, 10066, 10066, 10066, 10066, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 0, 0, 10067, 0, 10068, 10069, 10069, \n  0, 10070, 10071, 10071, 10072, 10072, 10072, 10072, \n  0, 10073, 10074, 10074, 10075, 10075, 10075, 10075, \n  10076, 10076, 10076, 10076, 10076, 10076, 10076, 12107, \n  0, 10077, 10078, 10078, 10079, 10079, 10079, 10079, \n  10080, 10080, 10080, 10080, 10080, 10080, 10080, 10080, \n  10081, 10081, 10081, 10081, 10081, 10081, 10081, 10081, \n  10081, 10081, 10081, 10081, 10081, 10081, 12108, 12108, \n  0, 10082, 10083, 10083, 10084, 10084, 10084, 10084, \n  10085, 10085, 10085, 10085, 10085, 10085, 10085, 10085, \n  10086, 10086, 10086, 10086, 10086, 10086, 10086, 10086, \n  10086, 10086, 10086, 10086, 10086, 10086, 10086, 12107, \n  10087, 10087, 10087, 10087, 10087, 10087, 10087, 10087, \n  10087, 10087, 10087, 10087, 10087, 10087, 10087, 10087, \n  10087, 10087, 10087, 10087, 10087, 10087, 10087, 10087, \n  10087, 10087, 10087, 10087, 12109, 12109, 12109, 12109, \n  0, 10088, 10089, 10089, 10090, 10090, 10090, 10090, \n  10091, 10091, 10091, 10091, 10091, 10091, 10091, 10091, \n  10092, 10092, 10092, 10092, 10092, 10092, 10092, 10092, \n  10092, 10092, 10092, 10092, 10092, 10092, 10092, 12107, \n  10093, 10093, 10093, 10093, 10093, 10093, 10093, 10093, \n  10093, 10093, 10093, 10093, 10093, 10093, 10093, 10093, \n  10093, 10093, 10093, 10093, 10093, 10093, 10093, 10093, \n  10093, 10093, 10093, 10093, 10093, 10093, 12108, 12108, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  0, 0, 0, 0, 0, 0, 0, 0, \n  0, 0, 0, 0, 0, 0, 0, 10095, \n  0, 0, 0, 0, 0, 0, 0, 10096, \n  0, 0, 0, 10097, 0, 10098, 10099, 12107, \n  0, 0, 0, 0, 0, 0, 0, 10100, \n  0, 0, 0, 10101, 0, 10102, 10103, 10103, \n  0, 0, 0, 10104, 0, 10105, 10106, 10106, \n  0, 10107, 10108, 10108, 10109, 10109, 12108, 12108, \n  0, 0, 0, 0, 0, 0, 0, 10110, \n  0, 0, 0, 10111, 0, 10112, 10113, 10113, \n  0, 0, 0, 10114, 0, 10115, 10116, 10116, \n  0, 10117, 10118, 10118, 10119, 10119, 10119, 12107, \n  0, 0, 0, 10120, 0, 10121, 10122, 10122, \n  0, 10123, 10124, 10124, 10125, 10125, 10125, 10125, \n  0, 10126, 10127, 10127, 10128, 10128, 10128, 10128, \n  10129, 10129, 10129, 10129, 12109, 12109, 12109, 12109, \n  0, 0, 0, 0, 0, 0, 0, 10130, \n  0, 0, 0, 10131, 0, 10132, 10133, 10133, \n  0, 0, 0, 10134, 0, 10135, 10136, 10136, \n  0, 10137, 10138, 10138, 10139, 10139, 10139, 12107, \n  0, 0, 0, 10140, 0, 10141, 10142, 10142, \n  0, 10143, 10144, 10144, 10145, 10145, 10145, 10145, \n  0, 10146, 10147, 10147, 10148, 10148, 10148, 10148, \n  10149, 10149, 10149, 10149, 10149, 10149, 12108, 12108, \n  0, 0, 0, 10150, 0, 10151, 10152, 10152, \n  0, 10153, 10154, 10154, 10155, 10155, 10155, 10155, \n  0, 10156, 10157, 10157, 10158, 10158, 10158, 10158, \n  10159, 10159, 10159, 10159, 10159, 10159, 10159, 12107, \n  0, 10160, 10161, 10161, 10162, 10162, 10162, 10162, \n  10163, 10163, 10163, 10163, 10163, 10163, 10163, 10163, \n  10164, 10164, 10164, 10164, 10164, 10164, 10164, 10164, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 0, 0, 0, 0, 0, 0, 10165, \n  0, 0, 0, 10166, 0, 10167, 10168, 10168, \n  0, 0, 0, 10169, 0, 10170, 10171, 10171, \n  0, 10172, 10173, 10173, 10174, 10174, 10174, 12107, \n  0, 0, 0, 10175, 0, 10176, 10177, 10177, \n  0, 10178, 10179, 10179, 10180, 10180, 10180, 10180, \n  0, 10181, 10182, 10182, 10183, 10183, 10183, 10183, \n  10184, 10184, 10184, 10184, 10184, 10184, 12108, 12108, \n  0, 0, 0, 10185, 0, 10186, 10187, 10187, \n  0, 10188, 10189, 10189, 10190, 10190, 10190, 10190, \n  0, 10191, 10192, 10192, 10193, 10193, 10193, 10193, \n  10194, 10194, 10194, 10194, 10194, 10194, 10194, 12107, \n  0, 10195, 10196, 10196, 10197, 10197, 10197, 10197, \n  10198, 10198, 10198, 10198, 10198, 10198, 10198, 10198, \n  10199, 10199, 10199, 10199, 10199, 10199, 10199, 10199, \n  10199, 10199, 10199, 10199, 12109, 12109, 12109, 12109, \n  0, 0, 0, 10200, 0, 10201, 10202, 10202, \n  0, 10203, 10204, 10204, 10205, 10205, 10205, 10205, \n  0, 10206, 10207, 10207, 10208, 10208, 10208, 10208, \n  10209, 10209, 10209, 10209, 10209, 10209, 10209, 12107, \n  0, 10210, 10211, 10211, 10212, 10212, 10212, 10212, \n  10213, 10213, 10213, 10213, 10213, 10213, 10213, 10213, \n  10214, 10214, 10214, 10214, 10214, 10214, 10214, 10214, \n  10214, 10214, 10214, 10214, 10214, 10214, 12108, 12108, \n  0, 10215, 10216, 10216, 10217, 10217, 10217, 10217, \n  10218, 10218, 10218, 10218, 10218, 10218, 10218, 10218, \n  10219, 10219, 10219, 10219, 10219, 10219, 10219, 10219, \n  10219, 10219, 10219, 10219, 10219, 10219, 10219, 12107, \n  10220, 10220, 10220, 10220, 10220, 10220, 10220, 10220, \n  10220, 10220, 10220, 10220, 10220, 10220, 10220, 10220, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  0, 0, 0, 0, 0, 0, 0, 10221, \n  0, 0, 0, 10222, 0, 10223, 10224, 10224, \n  0, 0, 0, 10225, 0, 10226, 10227, 10227, \n  0, 10228, 10229, 10229, 10230, 10230, 10230, 12107, \n  0, 0, 0, 10231, 0, 10232, 10233, 10233, \n  0, 10234, 10235, 10235, 10236, 10236, 10236, 10236, \n  0, 10237, 10238, 10238, 10239, 10239, 10239, 10239, \n  10240, 10240, 10240, 10240, 10240, 10240, 12108, 12108, \n  0, 0, 0, 10241, 0, 10242, 10243, 10243, \n  0, 10244, 10245, 10245, 10246, 10246, 10246, 10246, \n  0, 10247, 10248, 10248, 10249, 10249, 10249, 10249, \n  10250, 10250, 10250, 10250, 10250, 10250, 10250, 12107, \n  0, 10251, 10252, 10252, 10253, 10253, 10253, 10253, \n  10254, 10254, 10254, 10254, 10254, 10254, 10254, 10254, \n  10255, 10255, 10255, 10255, 10255, 10255, 10255, 10255, \n  10255, 10255, 10255, 10255, 12109, 12109, 12109, 12109, \n  0, 0, 0, 10256, 0, 10257, 10258, 10258, \n  0, 10259, 10260, 10260, 10261, 10261, 10261, 10261, \n  0, 10262, 10263, 10263, 10264, 10264, 10264, 10264, \n  10265, 10265, 10265, 10265, 10265, 10265, 10265, 12107, \n  0, 10266, 10267, 10267, 10268, 10268, 10268, 10268, \n  10269, 10269, 10269, 10269, 10269, 10269, 10269, 10269, \n  10270, 10270, 10270, 10270, 10270, 10270, 10270, 10270, \n  10270, 10270, 10270, 10270, 10270, 10270, 12108, 12108, \n  0, 10271, 10272, 10272, 10273, 10273, 10273, 10273, \n  10274, 10274, 10274, 10274, 10274, 10274, 10274, 10274, \n  10275, 10275, 10275, 10275, 10275, 10275, 10275, 10275, \n  10275, 10275, 10275, 10275, 10275, 10275, 10275, 12107, \n  10276, 10276, 10276, 10276, 10276, 10276, 10276, 10276, \n  10276, 10276, 10276, 10276, 10276, 10276, 10276, 10276, \n  10276, 10276, 10276, 10276, 10276, 10276, 10276, 10276, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 0, 0, 10277, 0, 10278, 10279, 10279, \n  0, 10280, 10281, 10281, 10282, 10282, 10282, 10282, \n  0, 10283, 10284, 10284, 10285, 10285, 10285, 10285, \n  10286, 10286, 10286, 10286, 10286, 10286, 10286, 12107, \n  0, 10287, 10288, 10288, 10289, 10289, 10289, 10289, \n  10290, 10290, 10290, 10290, 10290, 10290, 10290, 10290, \n  10291, 10291, 10291, 10291, 10291, 10291, 10291, 10291, \n  10291, 10291, 10291, 10291, 10291, 10291, 12108, 12108, \n  0, 10292, 10293, 10293, 10294, 10294, 10294, 10294, \n  10295, 10295, 10295, 10295, 10295, 10295, 10295, 10295, \n  10296, 10296, 10296, 10296, 10296, 10296, 10296, 10296, \n  10296, 10296, 10296, 10296, 10296, 10296, 10296, 12107, \n  10297, 10297, 10297, 10297, 10297, 10297, 10297, 10297, \n  10297, 10297, 10297, 10297, 10297, 10297, 10297, 10297, \n  10297, 10297, 10297, 10297, 10297, 10297, 10297, 10297, \n  10297, 10297, 10297, 10297, 12109, 12109, 12109, 12109, \n  0, 10298, 10299, 10299, 10300, 10300, 10300, 10300, \n  10301, 10301, 10301, 10301, 10301, 10301, 10301, 10301, \n  10302, 10302, 10302, 10302, 10302, 10302, 10302, 10302, \n  10302, 10302, 10302, 10302, 10302, 10302, 10302, 12107, \n  10303, 10303, 10303, 10303, 10303, 10303, 10303, 10303, \n  10303, 10303, 10303, 10303, 10303, 10303, 10303, 10303, \n  10303, 10303, 10303, 10303, 10303, 10303, 10303, 10303, \n  10303, 10303, 10303, 10303, 10303, 10303, 12108, 12108, \n  10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304, \n  10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304, \n  10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304, \n  10304, 10304, 10304, 10304, 10304, 10304, 10304, 12107, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  0, 0, 0, 0, 0, 0, 0, 10305, \n  0, 0, 0, 10306, 0, 10307, 10308, 10308, \n  0, 0, 0, 10309, 0, 10310, 10311, 10311, \n  0, 10312, 10313, 10313, 10314, 10314, 10314, 12107, \n  0, 0, 0, 10315, 0, 10316, 10317, 10317, \n  0, 10318, 10319, 10319, 10320, 10320, 10320, 10320, \n  0, 10321, 10322, 10322, 10323, 10323, 10323, 10323, \n  10324, 10324, 10324, 10324, 10324, 10324, 12108, 12108, \n  0, 0, 0, 10325, 0, 10326, 10327, 10327, \n  0, 10328, 10329, 10329, 10330, 10330, 10330, 10330, \n  0, 10331, 10332, 10332, 10333, 10333, 10333, 10333, \n  10334, 10334, 10334, 10334, 10334, 10334, 10334, 12107, \n  0, 10335, 10336, 10336, 10337, 10337, 10337, 10337, \n  10338, 10338, 10338, 10338, 10338, 10338, 10338, 10338, \n  10339, 10339, 10339, 10339, 10339, 10339, 10339, 10339, \n  10339, 10339, 10339, 10339, 12109, 12109, 12109, 12109, \n  0, 0, 0, 10340, 0, 10341, 10342, 10342, \n  0, 10343, 10344, 10344, 10345, 10345, 10345, 10345, \n  0, 10346, 10347, 10347, 10348, 10348, 10348, 10348, \n  10349, 10349, 10349, 10349, 10349, 10349, 10349, 12107, \n  0, 10350, 10351, 10351, 10352, 10352, 10352, 10352, \n  10353, 10353, 10353, 10353, 10353, 10353, 10353, 10353, \n  10354, 10354, 10354, 10354, 10354, 10354, 10354, 10354, \n  10354, 10354, 10354, 10354, 10354, 10354, 12108, 12108, \n  0, 10355, 10356, 10356, 10357, 10357, 10357, 10357, \n  10358, 10358, 10358, 10358, 10358, 10358, 10358, 10358, \n  10359, 10359, 10359, 10359, 10359, 10359, 10359, 10359, \n  10359, 10359, 10359, 10359, 10359, 10359, 10359, 12107, \n  10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360, \n  10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360, \n  10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 0, 0, 10361, 0, 10362, 10363, 10363, \n  0, 10364, 10365, 10365, 10366, 10366, 10366, 10366, \n  0, 10367, 10368, 10368, 10369, 10369, 10369, 10369, \n  10370, 10370, 10370, 10370, 10370, 10370, 10370, 12107, \n  0, 10371, 10372, 10372, 10373, 10373, 10373, 10373, \n  10374, 10374, 10374, 10374, 10374, 10374, 10374, 10374, \n  10375, 10375, 10375, 10375, 10375, 10375, 10375, 10375, \n  10375, 10375, 10375, 10375, 10375, 10375, 12108, 12108, \n  0, 10376, 10377, 10377, 10378, 10378, 10378, 10378, \n  10379, 10379, 10379, 10379, 10379, 10379, 10379, 10379, \n  10380, 10380, 10380, 10380, 10380, 10380, 10380, 10380, \n  10380, 10380, 10380, 10380, 10380, 10380, 10380, 12107, \n  10381, 10381, 10381, 10381, 10381, 10381, 10381, 10381, \n  10381, 10381, 10381, 10381, 10381, 10381, 10381, 10381, \n  10381, 10381, 10381, 10381, 10381, 10381, 10381, 10381, \n  10381, 10381, 10381, 10381, 12109, 12109, 12109, 12109, \n  0, 10382, 10383, 10383, 10384, 10384, 10384, 10384, \n  10385, 10385, 10385, 10385, 10385, 10385, 10385, 10385, \n  10386, 10386, 10386, 10386, 10386, 10386, 10386, 10386, \n  10386, 10386, 10386, 10386, 10386, 10386, 10386, 12107, \n  10387, 10387, 10387, 10387, 10387, 10387, 10387, 10387, \n  10387, 10387, 10387, 10387, 10387, 10387, 10387, 10387, \n  10387, 10387, 10387, 10387, 10387, 10387, 10387, 10387, \n  10387, 10387, 10387, 10387, 10387, 10387, 12108, 12108, \n  10388, 10388, 10388, 10388, 10388, 10388, 10388, 10388, \n  10388, 10388, 10388, 10388, 10388, 10388, 10388, 10388, \n  10388, 10388, 10388, 10388, 10388, 10388, 10388, 10388, \n  10388, 10388, 10388, 10388, 10388, 10388, 10388, 12107, \n  10388, 10388, 10388, 10388, 10388, 10388, 10388, 10388, \n  10388, 10388, 10388, 10388, 10388, 10388, 10388, 10388, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  0, 0, 0, 10389, 0, 10390, 10391, 10391, \n  0, 10392, 10393, 10393, 10394, 10394, 10394, 10394, \n  0, 10395, 10396, 10396, 10397, 10397, 10397, 10397, \n  10398, 10398, 10398, 10398, 10398, 10398, 10398, 12107, \n  0, 10399, 10400, 10400, 10401, 10401, 10401, 10401, \n  10402, 10402, 10402, 10402, 10402, 10402, 10402, 10402, \n  10403, 10403, 10403, 10403, 10403, 10403, 10403, 10403, \n  10403, 10403, 10403, 10403, 10403, 10403, 12108, 12108, \n  0, 10404, 10405, 10405, 10406, 10406, 10406, 10406, \n  10407, 10407, 10407, 10407, 10407, 10407, 10407, 10407, \n  10408, 10408, 10408, 10408, 10408, 10408, 10408, 10408, \n  10408, 10408, 10408, 10408, 10408, 10408, 10408, 12107, \n  10409, 10409, 10409, 10409, 10409, 10409, 10409, 10409, \n  10409, 10409, 10409, 10409, 10409, 10409, 10409, 10409, \n  10409, 10409, 10409, 10409, 10409, 10409, 10409, 10409, \n  10409, 10409, 10409, 10409, 12109, 12109, 12109, 12109, \n  0, 10410, 10411, 10411, 10412, 10412, 10412, 10412, \n  10413, 10413, 10413, 10413, 10413, 10413, 10413, 10413, \n  10414, 10414, 10414, 10414, 10414, 10414, 10414, 10414, \n  10414, 10414, 10414, 10414, 10414, 10414, 10414, 12107, \n  10415, 10415, 10415, 10415, 10415, 10415, 10415, 10415, \n  10415, 10415, 10415, 10415, 10415, 10415, 10415, 10415, \n  10415, 10415, 10415, 10415, 10415, 10415, 10415, 10415, \n  10415, 10415, 10415, 10415, 10415, 10415, 12108, 12108, \n  10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416, \n  10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416, \n  10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416, \n  10416, 10416, 10416, 10416, 10416, 10416, 10416, 12107, \n  10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416, \n  10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416, \n  10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 10417, 10418, 10418, 10419, 10419, 10419, 10419, \n  10420, 10420, 10420, 10420, 10420, 10420, 10420, 10420, \n  10421, 10421, 10421, 10421, 10421, 10421, 10421, 10421, \n  10421, 10421, 10421, 10421, 10421, 10421, 10421, 12107, \n  10422, 10422, 10422, 10422, 10422, 10422, 10422, 10422, \n  10422, 10422, 10422, 10422, 10422, 10422, 10422, 10422, \n  10422, 10422, 10422, 10422, 10422, 10422, 10422, 10422, \n  10422, 10422, 10422, 10422, 10422, 10422, 12108, 12108, \n  10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423, \n  10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423, \n  10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423, \n  10423, 10423, 10423, 10423, 10423, 10423, 10423, 12107, \n  10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423, \n  10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423, \n  10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423, \n  10423, 10423, 10423, 10423, 12109, 12109, 12109, 12109, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114, \n  0, 0, 0, 0, 0, 0, 0, 0, \n  0, 0, 0, 0, 0, 0, 0, 12106, \n  0, 0, 0, 0, 0, 0, 0, 10426, \n  0, 0, 0, 10427, 0, 10428, 10429, 12107, \n  0, 0, 0, 0, 0, 0, 0, 10430, \n  0, 0, 0, 10431, 0, 10432, 10433, 12106, \n  0, 0, 0, 10434, 0, 10435, 10436, 10436, \n  0, 10437, 10438, 10438, 10439, 10439, 12108, 12108, \n  0, 0, 0, 0, 0, 0, 0, 10440, \n  0, 0, 0, 10441, 0, 10442, 10443, 12106, \n  0, 0, 0, 10444, 0, 10445, 10446, 10446, \n  0, 10447, 10448, 10448, 10449, 10449, 10449, 12107, \n  0, 0, 0, 10450, 0, 10451, 10452, 10452, \n  0, 10453, 10454, 10454, 10455, 10455, 10455, 12106, \n  0, 10456, 10457, 10457, 10458, 10458, 10458, 10458, \n  10459, 10459, 10459, 10459, 12109, 12109, 12109, 12109, \n  0, 0, 0, 0, 0, 0, 0, 10460, \n  0, 0, 0, 10461, 0, 10462, 10463, 12106, \n  0, 0, 0, 10464, 0, 10465, 10466, 10466, \n  0, 10467, 10468, 10468, 10469, 10469, 10469, 12107, \n  0, 0, 0, 10470, 0, 10471, 10472, 10472, \n  0, 10473, 10474, 10474, 10475, 10475, 10475, 12106, \n  0, 10476, 10477, 10477, 10478, 10478, 10478, 10478, \n  10479, 10479, 10479, 10479, 10479, 10479, 12108, 12108, \n  0, 0, 0, 10480, 0, 10481, 10482, 10482, \n  0, 10483, 10484, 10484, 10485, 10485, 10485, 12106, \n  0, 10486, 10487, 10487, 10488, 10488, 10488, 10488, \n  10489, 10489, 10489, 10489, 10489, 10489, 10489, 12107, \n  0, 10490, 10491, 10491, 10492, 10492, 10492, 10492, \n  10493, 10493, 10493, 10493, 10493, 10493, 10493, 12106, \n  10494, 10494, 10494, 10494, 10494, 10494, 10494, 10494, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 0, 0, 0, 0, 0, 0, 10495, \n  0, 0, 0, 10496, 0, 10497, 10498, 12106, \n  0, 0, 0, 10499, 0, 10500, 10501, 10501, \n  0, 10502, 10503, 10503, 10504, 10504, 10504, 12107, \n  0, 0, 0, 10505, 0, 10506, 10507, 10507, \n  0, 10508, 10509, 10509, 10510, 10510, 10510, 12106, \n  0, 10511, 10512, 10512, 10513, 10513, 10513, 10513, \n  10514, 10514, 10514, 10514, 10514, 10514, 12108, 12108, \n  0, 0, 0, 10515, 0, 10516, 10517, 10517, \n  0, 10518, 10519, 10519, 10520, 10520, 10520, 12106, \n  0, 10521, 10522, 10522, 10523, 10523, 10523, 10523, \n  10524, 10524, 10524, 10524, 10524, 10524, 10524, 12107, \n  0, 10525, 10526, 10526, 10527, 10527, 10527, 10527, \n  10528, 10528, 10528, 10528, 10528, 10528, 10528, 12106, \n  10529, 10529, 10529, 10529, 10529, 10529, 10529, 10529, \n  10529, 10529, 10529, 10529, 12109, 12109, 12109, 12109, \n  0, 0, 0, 10530, 0, 10531, 10532, 10532, \n  0, 10533, 10534, 10534, 10535, 10535, 10535, 12106, \n  0, 10536, 10537, 10537, 10538, 10538, 10538, 10538, \n  10539, 10539, 10539, 10539, 10539, 10539, 10539, 12107, \n  0, 10540, 10541, 10541, 10542, 10542, 10542, 10542, \n  10543, 10543, 10543, 10543, 10543, 10543, 10543, 12106, \n  10544, 10544, 10544, 10544, 10544, 10544, 10544, 10544, \n  10544, 10544, 10544, 10544, 10544, 10544, 12108, 12108, \n  0, 10545, 10546, 10546, 10547, 10547, 10547, 10547, \n  10548, 10548, 10548, 10548, 10548, 10548, 10548, 12106, \n  10549, 10549, 10549, 10549, 10549, 10549, 10549, 10549, \n  10549, 10549, 10549, 10549, 10549, 10549, 10549, 12107, \n  10550, 10550, 10550, 10550, 10550, 10550, 10550, 10550, \n  10550, 10550, 10550, 10550, 10550, 10550, 10550, 12106, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  0, 0, 0, 0, 0, 0, 0, 10551, \n  0, 0, 0, 10552, 0, 10553, 10554, 12106, \n  0, 0, 0, 10555, 0, 10556, 10557, 10557, \n  0, 10558, 10559, 10559, 10560, 10560, 10560, 12107, \n  0, 0, 0, 10561, 0, 10562, 10563, 10563, \n  0, 10564, 10565, 10565, 10566, 10566, 10566, 12106, \n  0, 10567, 10568, 10568, 10569, 10569, 10569, 10569, \n  10570, 10570, 10570, 10570, 10570, 10570, 12108, 12108, \n  0, 0, 0, 10571, 0, 10572, 10573, 10573, \n  0, 10574, 10575, 10575, 10576, 10576, 10576, 12106, \n  0, 10577, 10578, 10578, 10579, 10579, 10579, 10579, \n  10580, 10580, 10580, 10580, 10580, 10580, 10580, 12107, \n  0, 10581, 10582, 10582, 10583, 10583, 10583, 10583, \n  10584, 10584, 10584, 10584, 10584, 10584, 10584, 12106, \n  10585, 10585, 10585, 10585, 10585, 10585, 10585, 10585, \n  10585, 10585, 10585, 10585, 12109, 12109, 12109, 12109, \n  0, 0, 0, 10586, 0, 10587, 10588, 10588, \n  0, 10589, 10590, 10590, 10591, 10591, 10591, 12106, \n  0, 10592, 10593, 10593, 10594, 10594, 10594, 10594, \n  10595, 10595, 10595, 10595, 10595, 10595, 10595, 12107, \n  0, 10596, 10597, 10597, 10598, 10598, 10598, 10598, \n  10599, 10599, 10599, 10599, 10599, 10599, 10599, 12106, \n  10600, 10600, 10600, 10600, 10600, 10600, 10600, 10600, \n  10600, 10600, 10600, 10600, 10600, 10600, 12108, 12108, \n  0, 10601, 10602, 10602, 10603, 10603, 10603, 10603, \n  10604, 10604, 10604, 10604, 10604, 10604, 10604, 12106, \n  10605, 10605, 10605, 10605, 10605, 10605, 10605, 10605, \n  10605, 10605, 10605, 10605, 10605, 10605, 10605, 12107, \n  10606, 10606, 10606, 10606, 10606, 10606, 10606, 10606, \n  10606, 10606, 10606, 10606, 10606, 10606, 10606, 12106, \n  10606, 10606, 10606, 10606, 10606, 10606, 10606, 10606, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 0, 0, 10607, 0, 10608, 10609, 10609, \n  0, 10610, 10611, 10611, 10612, 10612, 10612, 12106, \n  0, 10613, 10614, 10614, 10615, 10615, 10615, 10615, \n  10616, 10616, 10616, 10616, 10616, 10616, 10616, 12107, \n  0, 10617, 10618, 10618, 10619, 10619, 10619, 10619, \n  10620, 10620, 10620, 10620, 10620, 10620, 10620, 12106, \n  10621, 10621, 10621, 10621, 10621, 10621, 10621, 10621, \n  10621, 10621, 10621, 10621, 10621, 10621, 12108, 12108, \n  0, 10622, 10623, 10623, 10624, 10624, 10624, 10624, \n  10625, 10625, 10625, 10625, 10625, 10625, 10625, 12106, \n  10626, 10626, 10626, 10626, 10626, 10626, 10626, 10626, \n  10626, 10626, 10626, 10626, 10626, 10626, 10626, 12107, \n  10627, 10627, 10627, 10627, 10627, 10627, 10627, 10627, \n  10627, 10627, 10627, 10627, 10627, 10627, 10627, 12106, \n  10627, 10627, 10627, 10627, 10627, 10627, 10627, 10627, \n  10627, 10627, 10627, 10627, 12109, 12109, 12109, 12109, \n  0, 10628, 10629, 10629, 10630, 10630, 10630, 10630, \n  10631, 10631, 10631, 10631, 10631, 10631, 10631, 12106, \n  10632, 10632, 10632, 10632, 10632, 10632, 10632, 10632, \n  10632, 10632, 10632, 10632, 10632, 10632, 10632, 12107, \n  10633, 10633, 10633, 10633, 10633, 10633, 10633, 10633, \n  10633, 10633, 10633, 10633, 10633, 10633, 10633, 12106, \n  10633, 10633, 10633, 10633, 10633, 10633, 10633, 10633, \n  10633, 10633, 10633, 10633, 10633, 10633, 12108, 12108, \n  10634, 10634, 10634, 10634, 10634, 10634, 10634, 10634, \n  10634, 10634, 10634, 10634, 10634, 10634, 10634, 12106, \n  10634, 10634, 10634, 10634, 10634, 10634, 10634, 10634, \n  10634, 10634, 10634, 10634, 10634, 10634, 10634, 12107, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  0, 0, 0, 0, 0, 0, 0, 10635, \n  0, 0, 0, 10636, 0, 10637, 10638, 12106, \n  0, 0, 0, 10639, 0, 10640, 10641, 10641, \n  0, 10642, 10643, 10643, 10644, 10644, 10644, 12107, \n  0, 0, 0, 10645, 0, 10646, 10647, 10647, \n  0, 10648, 10649, 10649, 10650, 10650, 10650, 12106, \n  0, 10651, 10652, 10652, 10653, 10653, 10653, 10653, \n  10654, 10654, 10654, 10654, 10654, 10654, 12108, 12108, \n  0, 0, 0, 10655, 0, 10656, 10657, 10657, \n  0, 10658, 10659, 10659, 10660, 10660, 10660, 12106, \n  0, 10661, 10662, 10662, 10663, 10663, 10663, 10663, \n  10664, 10664, 10664, 10664, 10664, 10664, 10664, 12107, \n  0, 10665, 10666, 10666, 10667, 10667, 10667, 10667, \n  10668, 10668, 10668, 10668, 10668, 10668, 10668, 12106, \n  10669, 10669, 10669, 10669, 10669, 10669, 10669, 10669, \n  10669, 10669, 10669, 10669, 12109, 12109, 12109, 12109, \n  0, 0, 0, 10670, 0, 10671, 10672, 10672, \n  0, 10673, 10674, 10674, 10675, 10675, 10675, 12106, \n  0, 10676, 10677, 10677, 10678, 10678, 10678, 10678, \n  10679, 10679, 10679, 10679, 10679, 10679, 10679, 12107, \n  0, 10680, 10681, 10681, 10682, 10682, 10682, 10682, \n  10683, 10683, 10683, 10683, 10683, 10683, 10683, 12106, \n  10684, 10684, 10684, 10684, 10684, 10684, 10684, 10684, \n  10684, 10684, 10684, 10684, 10684, 10684, 12108, 12108, \n  0, 10685, 10686, 10686, 10687, 10687, 10687, 10687, \n  10688, 10688, 10688, 10688, 10688, 10688, 10688, 12106, \n  10689, 10689, 10689, 10689, 10689, 10689, 10689, 10689, \n  10689, 10689, 10689, 10689, 10689, 10689, 10689, 12107, \n  10690, 10690, 10690, 10690, 10690, 10690, 10690, 10690, \n  10690, 10690, 10690, 10690, 10690, 10690, 10690, 12106, \n  10690, 10690, 10690, 10690, 10690, 10690, 10690, 10690, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 0, 0, 10691, 0, 10692, 10693, 10693, \n  0, 10694, 10695, 10695, 10696, 10696, 10696, 12106, \n  0, 10697, 10698, 10698, 10699, 10699, 10699, 10699, \n  10700, 10700, 10700, 10700, 10700, 10700, 10700, 12107, \n  0, 10701, 10702, 10702, 10703, 10703, 10703, 10703, \n  10704, 10704, 10704, 10704, 10704, 10704, 10704, 12106, \n  10705, 10705, 10705, 10705, 10705, 10705, 10705, 10705, \n  10705, 10705, 10705, 10705, 10705, 10705, 12108, 12108, \n  0, 10706, 10707, 10707, 10708, 10708, 10708, 10708, \n  10709, 10709, 10709, 10709, 10709, 10709, 10709, 12106, \n  10710, 10710, 10710, 10710, 10710, 10710, 10710, 10710, \n  10710, 10710, 10710, 10710, 10710, 10710, 10710, 12107, \n  10711, 10711, 10711, 10711, 10711, 10711, 10711, 10711, \n  10711, 10711, 10711, 10711, 10711, 10711, 10711, 12106, \n  10711, 10711, 10711, 10711, 10711, 10711, 10711, 10711, \n  10711, 10711, 10711, 10711, 12109, 12109, 12109, 12109, \n  0, 10712, 10713, 10713, 10714, 10714, 10714, 10714, \n  10715, 10715, 10715, 10715, 10715, 10715, 10715, 12106, \n  10716, 10716, 10716, 10716, 10716, 10716, 10716, 10716, \n  10716, 10716, 10716, 10716, 10716, 10716, 10716, 12107, \n  10717, 10717, 10717, 10717, 10717, 10717, 10717, 10717, \n  10717, 10717, 10717, 10717, 10717, 10717, 10717, 12106, \n  10717, 10717, 10717, 10717, 10717, 10717, 10717, 10717, \n  10717, 10717, 10717, 10717, 10717, 10717, 12108, 12108, \n  10718, 10718, 10718, 10718, 10718, 10718, 10718, 10718, \n  10718, 10718, 10718, 10718, 10718, 10718, 10718, 12106, \n  10718, 10718, 10718, 10718, 10718, 10718, 10718, 10718, \n  10718, 10718, 10718, 10718, 10718, 10718, 10718, 12107, \n  10718, 10718, 10718, 10718, 10718, 10718, 10718, 10718, \n  10718, 10718, 10718, 10718, 10718, 10718, 10718, 12106, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  0, 0, 0, 10719, 0, 10720, 10721, 10721, \n  0, 10722, 10723, 10723, 10724, 10724, 10724, 12106, \n  0, 10725, 10726, 10726, 10727, 10727, 10727, 10727, \n  10728, 10728, 10728, 10728, 10728, 10728, 10728, 12107, \n  0, 10729, 10730, 10730, 10731, 10731, 10731, 10731, \n  10732, 10732, 10732, 10732, 10732, 10732, 10732, 12106, \n  10733, 10733, 10733, 10733, 10733, 10733, 10733, 10733, \n  10733, 10733, 10733, 10733, 10733, 10733, 12108, 12108, \n  0, 10734, 10735, 10735, 10736, 10736, 10736, 10736, \n  10737, 10737, 10737, 10737, 10737, 10737, 10737, 12106, \n  10738, 10738, 10738, 10738, 10738, 10738, 10738, 10738, \n  10738, 10738, 10738, 10738, 10738, 10738, 10738, 12107, \n  10739, 10739, 10739, 10739, 10739, 10739, 10739, 10739, \n  10739, 10739, 10739, 10739, 10739, 10739, 10739, 12106, \n  10739, 10739, 10739, 10739, 10739, 10739, 10739, 10739, \n  10739, 10739, 10739, 10739, 12109, 12109, 12109, 12109, \n  0, 10740, 10741, 10741, 10742, 10742, 10742, 10742, \n  10743, 10743, 10743, 10743, 10743, 10743, 10743, 12106, \n  10744, 10744, 10744, 10744, 10744, 10744, 10744, 10744, \n  10744, 10744, 10744, 10744, 10744, 10744, 10744, 12107, \n  10745, 10745, 10745, 10745, 10745, 10745, 10745, 10745, \n  10745, 10745, 10745, 10745, 10745, 10745, 10745, 12106, \n  10745, 10745, 10745, 10745, 10745, 10745, 10745, 10745, \n  10745, 10745, 10745, 10745, 10745, 10745, 12108, 12108, \n  10746, 10746, 10746, 10746, 10746, 10746, 10746, 10746, \n  10746, 10746, 10746, 10746, 10746, 10746, 10746, 12106, \n  10746, 10746, 10746, 10746, 10746, 10746, 10746, 10746, \n  10746, 10746, 10746, 10746, 10746, 10746, 10746, 12107, \n  10746, 10746, 10746, 10746, 10746, 10746, 10746, 10746, \n  10746, 10746, 10746, 10746, 10746, 10746, 10746, 12106, \n  10746, 10746, 10746, 10746, 10746, 10746, 10746, 10746, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 10747, 10748, 10748, 10749, 10749, 10749, 10749, \n  10750, 10750, 10750, 10750, 10750, 10750, 10750, 12106, \n  10751, 10751, 10751, 10751, 10751, 10751, 10751, 10751, \n  10751, 10751, 10751, 10751, 10751, 10751, 10751, 12107, \n  10752, 10752, 10752, 10752, 10752, 10752, 10752, 10752, \n  10752, 10752, 10752, 10752, 10752, 10752, 10752, 12106, \n  10752, 10752, 10752, 10752, 10752, 10752, 10752, 10752, \n  10752, 10752, 10752, 10752, 10752, 10752, 12108, 12108, \n  10753, 10753, 10753, 10753, 10753, 10753, 10753, 10753, \n  10753, 10753, 10753, 10753, 10753, 10753, 10753, 12106, \n  10753, 10753, 10753, 10753, 10753, 10753, 10753, 10753, \n  10753, 10753, 10753, 10753, 10753, 10753, 10753, 12107, \n  10753, 10753, 10753, 10753, 10753, 10753, 10753, 10753, \n  10753, 10753, 10753, 10753, 10753, 10753, 10753, 12106, \n  10753, 10753, 10753, 10753, 10753, 10753, 10753, 10753, \n  10753, 10753, 10753, 10753, 12109, 12109, 12109, 12109, \n  10754, 10754, 10754, 10754, 10754, 10754, 10754, 10754, \n  10754, 10754, 10754, 10754, 10754, 10754, 10754, 12106, \n  10754, 10754, 10754, 10754, 10754, 10754, 10754, 10754, \n  10754, 10754, 10754, 10754, 10754, 10754, 10754, 12107, \n  10754, 10754, 10754, 10754, 10754, 10754, 10754, 10754, \n  10754, 10754, 10754, 10754, 10754, 10754, 10754, 12106, \n  10754, 10754, 10754, 10754, 10754, 10754, 10754, 10754, \n  10754, 10754, 10754, 10754, 10754, 10754, 12108, 12108, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113, \n  0, 0, 0, 0, 0, 0, 0, 10755, \n  0, 0, 0, 10756, 0, 10757, 10758, 12106, \n  0, 0, 0, 10759, 0, 10760, 10761, 10761, \n  0, 10762, 10763, 10763, 10764, 10764, 10764, 12107, \n  0, 0, 0, 10765, 0, 10766, 10767, 10767, \n  0, 10768, 10769, 10769, 10770, 10770, 10770, 12106, \n  0, 10771, 10772, 10772, 10773, 10773, 10773, 10773, \n  10774, 10774, 10774, 10774, 10774, 10774, 12108, 12108, \n  0, 0, 0, 10775, 0, 10776, 10777, 10777, \n  0, 10778, 10779, 10779, 10780, 10780, 10780, 12106, \n  0, 10781, 10782, 10782, 10783, 10783, 10783, 10783, \n  10784, 10784, 10784, 10784, 10784, 10784, 10784, 12107, \n  0, 10785, 10786, 10786, 10787, 10787, 10787, 10787, \n  10788, 10788, 10788, 10788, 10788, 10788, 10788, 12106, \n  10789, 10789, 10789, 10789, 10789, 10789, 10789, 10789, \n  10789, 10789, 10789, 10789, 12109, 12109, 12109, 12109, \n  0, 0, 0, 10790, 0, 10791, 10792, 10792, \n  0, 10793, 10794, 10794, 10795, 10795, 10795, 12106, \n  0, 10796, 10797, 10797, 10798, 10798, 10798, 10798, \n  10799, 10799, 10799, 10799, 10799, 10799, 10799, 12107, \n  0, 10800, 10801, 10801, 10802, 10802, 10802, 10802, \n  10803, 10803, 10803, 10803, 10803, 10803, 10803, 12106, \n  10804, 10804, 10804, 10804, 10804, 10804, 10804, 10804, \n  10804, 10804, 10804, 10804, 10804, 10804, 12108, 12108, \n  0, 10805, 10806, 10806, 10807, 10807, 10807, 10807, \n  10808, 10808, 10808, 10808, 10808, 10808, 10808, 12106, \n  10809, 10809, 10809, 10809, 10809, 10809, 10809, 10809, \n  10809, 10809, 10809, 10809, 10809, 10809, 10809, 12107, \n  10810, 10810, 10810, 10810, 10810, 10810, 10810, 10810, \n  10810, 10810, 10810, 10810, 10810, 10810, 10810, 12106, \n  10810, 10810, 10810, 10810, 10810, 10810, 10810, 10810, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 0, 0, 10811, 0, 10812, 10813, 10813, \n  0, 10814, 10815, 10815, 10816, 10816, 10816, 12106, \n  0, 10817, 10818, 10818, 10819, 10819, 10819, 10819, \n  10820, 10820, 10820, 10820, 10820, 10820, 10820, 12107, \n  0, 10821, 10822, 10822, 10823, 10823, 10823, 10823, \n  10824, 10824, 10824, 10824, 10824, 10824, 10824, 12106, \n  10825, 10825, 10825, 10825, 10825, 10825, 10825, 10825, \n  10825, 10825, 10825, 10825, 10825, 10825, 12108, 12108, \n  0, 10826, 10827, 10827, 10828, 10828, 10828, 10828, \n  10829, 10829, 10829, 10829, 10829, 10829, 10829, 12106, \n  10830, 10830, 10830, 10830, 10830, 10830, 10830, 10830, \n  10830, 10830, 10830, 10830, 10830, 10830, 10830, 12107, \n  10831, 10831, 10831, 10831, 10831, 10831, 10831, 10831, \n  10831, 10831, 10831, 10831, 10831, 10831, 10831, 12106, \n  10831, 10831, 10831, 10831, 10831, 10831, 10831, 10831, \n  10831, 10831, 10831, 10831, 12109, 12109, 12109, 12109, \n  0, 10832, 10833, 10833, 10834, 10834, 10834, 10834, \n  10835, 10835, 10835, 10835, 10835, 10835, 10835, 12106, \n  10836, 10836, 10836, 10836, 10836, 10836, 10836, 10836, \n  10836, 10836, 10836, 10836, 10836, 10836, 10836, 12107, \n  10837, 10837, 10837, 10837, 10837, 10837, 10837, 10837, \n  10837, 10837, 10837, 10837, 10837, 10837, 10837, 12106, \n  10837, 10837, 10837, 10837, 10837, 10837, 10837, 10837, \n  10837, 10837, 10837, 10837, 10837, 10837, 12108, 12108, \n  10838, 10838, 10838, 10838, 10838, 10838, 10838, 10838, \n  10838, 10838, 10838, 10838, 10838, 10838, 10838, 12106, \n  10838, 10838, 10838, 10838, 10838, 10838, 10838, 10838, \n  10838, 10838, 10838, 10838, 10838, 10838, 10838, 12107, \n  10838, 10838, 10838, 10838, 10838, 10838, 10838, 10838, \n  10838, 10838, 10838, 10838, 10838, 10838, 10838, 12106, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  0, 0, 0, 10839, 0, 10840, 10841, 10841, \n  0, 10842, 10843, 10843, 10844, 10844, 10844, 12106, \n  0, 10845, 10846, 10846, 10847, 10847, 10847, 10847, \n  10848, 10848, 10848, 10848, 10848, 10848, 10848, 12107, \n  0, 10849, 10850, 10850, 10851, 10851, 10851, 10851, \n  10852, 10852, 10852, 10852, 10852, 10852, 10852, 12106, \n  10853, 10853, 10853, 10853, 10853, 10853, 10853, 10853, \n  10853, 10853, 10853, 10853, 10853, 10853, 12108, 12108, \n  0, 10854, 10855, 10855, 10856, 10856, 10856, 10856, \n  10857, 10857, 10857, 10857, 10857, 10857, 10857, 12106, \n  10858, 10858, 10858, 10858, 10858, 10858, 10858, 10858, \n  10858, 10858, 10858, 10858, 10858, 10858, 10858, 12107, \n  10859, 10859, 10859, 10859, 10859, 10859, 10859, 10859, \n  10859, 10859, 10859, 10859, 10859, 10859, 10859, 12106, \n  10859, 10859, 10859, 10859, 10859, 10859, 10859, 10859, \n  10859, 10859, 10859, 10859, 12109, 12109, 12109, 12109, \n  0, 10860, 10861, 10861, 10862, 10862, 10862, 10862, \n  10863, 10863, 10863, 10863, 10863, 10863, 10863, 12106, \n  10864, 10864, 10864, 10864, 10864, 10864, 10864, 10864, \n  10864, 10864, 10864, 10864, 10864, 10864, 10864, 12107, \n  10865, 10865, 10865, 10865, 10865, 10865, 10865, 10865, \n  10865, 10865, 10865, 10865, 10865, 10865, 10865, 12106, \n  10865, 10865, 10865, 10865, 10865, 10865, 10865, 10865, \n  10865, 10865, 10865, 10865, 10865, 10865, 12108, 12108, \n  10866, 10866, 10866, 10866, 10866, 10866, 10866, 10866, \n  10866, 10866, 10866, 10866, 10866, 10866, 10866, 12106, \n  10866, 10866, 10866, 10866, 10866, 10866, 10866, 10866, \n  10866, 10866, 10866, 10866, 10866, 10866, 10866, 12107, \n  10866, 10866, 10866, 10866, 10866, 10866, 10866, 10866, \n  10866, 10866, 10866, 10866, 10866, 10866, 10866, 12106, \n  10866, 10866, 10866, 10866, 10866, 10866, 10866, 10866, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 10867, 10868, 10868, 10869, 10869, 10869, 10869, \n  10870, 10870, 10870, 10870, 10870, 10870, 10870, 12106, \n  10871, 10871, 10871, 10871, 10871, 10871, 10871, 10871, \n  10871, 10871, 10871, 10871, 10871, 10871, 10871, 12107, \n  10872, 10872, 10872, 10872, 10872, 10872, 10872, 10872, \n  10872, 10872, 10872, 10872, 10872, 10872, 10872, 12106, \n  10872, 10872, 10872, 10872, 10872, 10872, 10872, 10872, \n  10872, 10872, 10872, 10872, 10872, 10872, 12108, 12108, \n  10873, 10873, 10873, 10873, 10873, 10873, 10873, 10873, \n  10873, 10873, 10873, 10873, 10873, 10873, 10873, 12106, \n  10873, 10873, 10873, 10873, 10873, 10873, 10873, 10873, \n  10873, 10873, 10873, 10873, 10873, 10873, 10873, 12107, \n  10873, 10873, 10873, 10873, 10873, 10873, 10873, 10873, \n  10873, 10873, 10873, 10873, 10873, 10873, 10873, 12106, \n  10873, 10873, 10873, 10873, 10873, 10873, 10873, 10873, \n  10873, 10873, 10873, 10873, 12109, 12109, 12109, 12109, \n  10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874, \n  10874, 10874, 10874, 10874, 10874, 10874, 10874, 12106, \n  10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874, \n  10874, 10874, 10874, 10874, 10874, 10874, 10874, 12107, \n  10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874, \n  10874, 10874, 10874, 10874, 10874, 10874, 10874, 12106, \n  10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874, \n  10874, 10874, 10874, 10874, 10874, 10874, 12108, 12108, \n  10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874, \n  10874, 10874, 10874, 10874, 10874, 10874, 10874, 12106, \n  10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874, \n  10874, 10874, 10874, 10874, 10874, 10874, 10874, 12107, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112, \n  0, 0, 0, 10875, 0, 10876, 10877, 10877, \n  0, 10878, 10879, 10879, 10880, 10880, 10880, 12106, \n  0, 10881, 10882, 10882, 10883, 10883, 10883, 10883, \n  10884, 10884, 10884, 10884, 10884, 10884, 10884, 12107, \n  0, 10885, 10886, 10886, 10887, 10887, 10887, 10887, \n  10888, 10888, 10888, 10888, 10888, 10888, 10888, 12106, \n  10889, 10889, 10889, 10889, 10889, 10889, 10889, 10889, \n  10889, 10889, 10889, 10889, 10889, 10889, 12108, 12108, \n  0, 10890, 10891, 10891, 10892, 10892, 10892, 10892, \n  10893, 10893, 10893, 10893, 10893, 10893, 10893, 12106, \n  10894, 10894, 10894, 10894, 10894, 10894, 10894, 10894, \n  10894, 10894, 10894, 10894, 10894, 10894, 10894, 12107, \n  10895, 10895, 10895, 10895, 10895, 10895, 10895, 10895, \n  10895, 10895, 10895, 10895, 10895, 10895, 10895, 12106, \n  10895, 10895, 10895, 10895, 10895, 10895, 10895, 10895, \n  10895, 10895, 10895, 10895, 12109, 12109, 12109, 12109, \n  0, 10896, 10897, 10897, 10898, 10898, 10898, 10898, \n  10899, 10899, 10899, 10899, 10899, 10899, 10899, 12106, \n  10900, 10900, 10900, 10900, 10900, 10900, 10900, 10900, \n  10900, 10900, 10900, 10900, 10900, 10900, 10900, 12107, \n  10901, 10901, 10901, 10901, 10901, 10901, 10901, 10901, \n  10901, 10901, 10901, 10901, 10901, 10901, 10901, 12106, \n  10901, 10901, 10901, 10901, 10901, 10901, 10901, 10901, \n  10901, 10901, 10901, 10901, 10901, 10901, 12108, 12108, \n  10902, 10902, 10902, 10902, 10902, 10902, 10902, 10902, \n  10902, 10902, 10902, 10902, 10902, 10902, 10902, 12106, \n  10902, 10902, 10902, 10902, 10902, 10902, 10902, 10902, \n  10902, 10902, 10902, 10902, 10902, 10902, 10902, 12107, \n  10902, 10902, 10902, 10902, 10902, 10902, 10902, 10902, \n  10902, 10902, 10902, 10902, 10902, 10902, 10902, 12106, \n  10902, 10902, 10902, 10902, 10902, 10902, 10902, 10902, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  0, 10903, 10904, 10904, 10905, 10905, 10905, 10905, \n  10906, 10906, 10906, 10906, 10906, 10906, 10906, 12106, \n  10907, 10907, 10907, 10907, 10907, 10907, 10907, 10907, \n  10907, 10907, 10907, 10907, 10907, 10907, 10907, 12107, \n  10908, 10908, 10908, 10908, 10908, 10908, 10908, 10908, \n  10908, 10908, 10908, 10908, 10908, 10908, 10908, 12106, \n  10908, 10908, 10908, 10908, 10908, 10908, 10908, 10908, \n  10908, 10908, 10908, 10908, 10908, 10908, 12108, 12108, \n  10909, 10909, 10909, 10909, 10909, 10909, 10909, 10909, \n  10909, 10909, 10909, 10909, 10909, 10909, 10909, 12106, \n  10909, 10909, 10909, 10909, 10909, 10909, 10909, 10909, \n  10909, 10909, 10909, 10909, 10909, 10909, 10909, 12107, \n  10909, 10909, 10909, 10909, 10909, 10909, 10909, 10909, \n  10909, 10909, 10909, 10909, 10909, 10909, 10909, 12106, \n  10909, 10909, 10909, 10909, 10909, 10909, 10909, 10909, \n  10909, 10909, 10909, 10909, 12109, 12109, 12109, 12109, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 12106, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 12107, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 12106, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910, \n  10910, 10910, 10910, 10910, 10910, 10910, 12108, 12108, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 12106, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 12107, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910, \n  10910, 10910, 10910, 10910, 10910, 10910, 10910, 12106, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111, \n  0, 10911, 10912, 10912, 10913, 10913, 10913, 10913, \n  10914, 10914, 10914, 10914, 10914, 10914, 10914, 12106, \n  10915, 10915, 10915, 10915, 10915, 10915, 10915, 10915, \n  10915, 10915, 10915, 10915, 10915, 10915, 10915, 12107, \n  10916, 10916, 10916, 10916, 10916, 10916, 10916, 10916, \n  10916, 10916, 10916, 10916, 10916, 10916, 10916, 12106, \n  10916, 10916, 10916, 10916, 10916, 10916, 10916, 10916, \n  10916, 10916, 10916, 10916, 10916, 10916, 12108, 12108, \n  10917, 10917, 10917, 10917, 10917, 10917, 10917, 10917, \n  10917, 10917, 10917, 10917, 10917, 10917, 10917, 12106, \n  10917, 10917, 10917, 10917, 10917, 10917, 10917, 10917, \n  10917, 10917, 10917, 10917, 10917, 10917, 10917, 12107, \n  10917, 10917, 10917, 10917, 10917, 10917, 10917, 10917, \n  10917, 10917, 10917, 10917, 10917, 10917, 10917, 12106, \n  10917, 10917, 10917, 10917, 10917, 10917, 10917, 10917, \n  10917, 10917, 10917, 10917, 12109, 12109, 12109, 12109, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 12106, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 12107, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 12106, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918, \n  10918, 10918, 10918, 10918, 10918, 10918, 12108, 12108, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 12106, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 12107, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 12106, \n  10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918, \n  12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115, \n  12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115 };\n\nstatic const uint16_t pairOtherVal[ 8192 ] = {\n  0, 0, 1, 0, 2, 1, 2, 0, \n  3, 3, 4, 1, 5, 2, 3, 3, \n  4, 6, 7, 4, 8, 5, 6, 6, \n  9, 7, 8, 8, 9, 9, 9, 9, \n  5, 10, 11, 10, 12, 11, 12, 12, \n  13, 13, 14, 14, 15, 15, 15, 15, \n  14, 16, 17, 17, 18, 18, 18, 18, \n  19, 19, 19, 19, 19, 19, 19, 19, \n  6, 15, 16, 20, 17, 21, 22, 22, \n  18, 23, 24, 24, 25, 25, 25, 25, \n  19, 26, 27, 27, 28, 28, 28, 28, \n  29, 29, 29, 29, 29, 29, 29, 29, \n  20, 30, 31, 31, 32, 32, 32, 32, \n  33, 33, 33, 33, 33, 33, 33, 33, \n  34, 34, 34, 34, 34, 34, 34, 34, \n  34, 34, 34, 34, 34, 34, 34, 34, \n  7, 21, 22, 35, 23, 36, 37, 37, \n  24, 38, 39, 39, 40, 40, 40, 40, \n  25, 41, 42, 42, 43, 43, 43, 43, \n  44, 44, 44, 44, 44, 44, 44, 44, \n  26, 45, 46, 46, 47, 47, 47, 47, \n  48, 48, 48, 48, 48, 48, 48, 48, \n  49, 49, 49, 49, 49, 49, 49, 49, \n  49, 49, 49, 49, 49, 49, 49, 49, \n  27, 50, 51, 51, 52, 52, 52, 52, \n  53, 53, 53, 53, 53, 53, 53, 53, \n  54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, \n  55, 55, 55, 55, 55, 55, 55, 55, \n  55, 55, 55, 55, 55, 55, 55, 55, \n  55, 55, 55, 55, 55, 55, 55, 55, \n  55, 55, 55, 55, 55, 55, 55, 55, \n  8, 28, 29, 56, 30, 57, 58, 58, \n  31, 59, 60, 60, 61, 61, 61, 61, \n  32, 62, 63, 63, 64, 64, 64, 64, \n  65, 65, 65, 65, 65, 65, 65, 65, \n  33, 66, 67, 67, 68, 68, 68, 68, \n  69, 69, 69, 69, 69, 69, 69, 69, \n  70, 70, 70, 70, 70, 70, 70, 70, \n  70, 70, 70, 70, 70, 70, 70, 70, \n  34, 71, 72, 72, 73, 73, 73, 73, \n  74, 74, 74, 74, 74, 74, 74, 74, \n  75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, \n  76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, \n  35, 77, 78, 78, 79, 79, 79, 79, \n  80, 80, 80, 80, 80, 80, 80, 80, \n  81, 81, 81, 81, 81, 81, 81, 81, \n  81, 81, 81, 81, 81, 81, 81, 81, \n  82, 82, 82, 82, 82, 82, 82, 82, \n  82, 82, 82, 82, 82, 82, 82, 82, \n  82, 82, 82, 82, 82, 82, 82, 82, \n  82, 82, 82, 82, 82, 82, 82, 82, \n  83, 83, 83, 83, 83, 83, 83, 83, \n  83, 83, 83, 83, 83, 83, 83, 83, \n  83, 83, 83, 83, 83, 83, 83, 83, \n  83, 83, 83, 83, 83, 83, 83, 83, \n  83, 83, 83, 83, 83, 83, 83, 83, \n  83, 83, 83, 83, 83, 83, 83, 83, \n  83, 83, 83, 83, 83, 83, 83, 83, \n  83, 83, 83, 83, 83, 83, 83, 83, \n  9, 36, 37, 84, 38, 85, 86, 86, \n  39, 87, 88, 88, 89, 89, 89, 89, \n  40, 90, 91, 91, 92, 92, 92, 92, \n  93, 93, 93, 93, 93, 93, 93, 93, \n  41, 94, 95, 95, 96, 96, 96, 96, \n  97, 97, 97, 97, 97, 97, 97, 97, \n  98, 98, 98, 98, 98, 98, 98, 98, \n  98, 98, 98, 98, 98, 98, 98, 98, \n  42, 99, 100, 100, 101, 101, 101, 101, \n  102, 102, 102, 102, 102, 102, 102, 102, \n  103, 103, 103, 103, 103, 103, 103, 103, \n  103, 103, 103, 103, 103, 103, 103, 103, \n  104, 104, 104, 104, 104, 104, 104, 104, \n  104, 104, 104, 104, 104, 104, 104, 104, \n  104, 104, 104, 104, 104, 104, 104, 104, \n  104, 104, 104, 104, 104, 104, 104, 104, \n  43, 105, 106, 106, 107, 107, 107, 107, \n  108, 108, 108, 108, 108, 108, 108, 108, \n  109, 109, 109, 109, 109, 109, 109, 109, \n  109, 109, 109, 109, 109, 109, 109, 109, \n  110, 110, 110, 110, 110, 110, 110, 110, \n  110, 110, 110, 110, 110, 110, 110, 110, \n  110, 110, 110, 110, 110, 110, 110, 110, \n  110, 110, 110, 110, 110, 110, 110, 110, \n  111, 111, 111, 111, 111, 111, 111, 111, \n  111, 111, 111, 111, 111, 111, 111, 111, \n  111, 111, 111, 111, 111, 111, 111, 111, \n  111, 111, 111, 111, 111, 111, 111, 111, \n  111, 111, 111, 111, 111, 111, 111, 111, \n  111, 111, 111, 111, 111, 111, 111, 111, \n  111, 111, 111, 111, 111, 111, 111, 111, \n  111, 111, 111, 111, 111, 111, 111, 111, \n  44, 112, 113, 113, 114, 114, 114, 114, \n  115, 115, 115, 115, 115, 115, 115, 115, \n  116, 116, 116, 116, 116, 116, 116, 116, \n  116, 116, 116, 116, 116, 116, 116, 116, \n  117, 117, 117, 117, 117, 117, 117, 117, \n  117, 117, 117, 117, 117, 117, 117, 117, \n  117, 117, 117, 117, 117, 117, 117, 117, \n  117, 117, 117, 117, 117, 117, 117, 117, \n  118, 118, 118, 118, 118, 118, 118, 118, \n  118, 118, 118, 118, 118, 118, 118, 118, \n  118, 118, 118, 118, 118, 118, 118, 118, \n  118, 118, 118, 118, 118, 118, 118, 118, \n  118, 118, 118, 118, 118, 118, 118, 118, \n  118, 118, 118, 118, 118, 118, 118, 118, \n  118, 118, 118, 118, 118, 118, 118, 118, \n  118, 118, 118, 118, 118, 118, 118, 118, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  119, 119, 119, 119, 119, 119, 119, 119, \n  10, 45, 46, 120, 47, 121, 122, 122, \n  48, 123, 124, 124, 125, 125, 125, 125, \n  49, 126, 127, 127, 128, 128, 128, 128, \n  129, 129, 129, 129, 129, 129, 129, 129, \n  50, 130, 131, 131, 132, 132, 132, 132, \n  133, 133, 133, 133, 133, 133, 133, 133, \n  134, 134, 134, 134, 134, 134, 134, 134, \n  134, 134, 134, 134, 134, 134, 134, 134, \n  51, 135, 136, 136, 137, 137, 137, 137, \n  138, 138, 138, 138, 138, 138, 138, 138, \n  139, 139, 139, 139, 139, 139, 139, 139, \n  139, 139, 139, 139, 139, 139, 139, 139, \n  140, 140, 140, 140, 140, 140, 140, 140, \n  140, 140, 140, 140, 140, 140, 140, 140, \n  140, 140, 140, 140, 140, 140, 140, 140, \n  140, 140, 140, 140, 140, 140, 140, 140, \n  52, 141, 142, 142, 143, 143, 143, 143, \n  144, 144, 144, 144, 144, 144, 144, 144, \n  145, 145, 145, 145, 145, 145, 145, 145, \n  145, 145, 145, 145, 145, 145, 145, 145, \n  146, 146, 146, 146, 146, 146, 146, 146, \n  146, 146, 146, 146, 146, 146, 146, 146, \n  146, 146, 146, 146, 146, 146, 146, 146, \n  146, 146, 146, 146, 146, 146, 146, 146, \n  147, 147, 147, 147, 147, 147, 147, 147, \n  147, 147, 147, 147, 147, 147, 147, 147, \n  147, 147, 147, 147, 147, 147, 147, 147, \n  147, 147, 147, 147, 147, 147, 147, 147, \n  147, 147, 147, 147, 147, 147, 147, 147, \n  147, 147, 147, 147, 147, 147, 147, 147, \n  147, 147, 147, 147, 147, 147, 147, 147, \n  147, 147, 147, 147, 147, 147, 147, 147, \n  53, 148, 149, 149, 150, 150, 150, 150, \n  151, 151, 151, 151, 151, 151, 151, 151, \n  152, 152, 152, 152, 152, 152, 152, 152, \n  152, 152, 152, 152, 152, 152, 152, 152, \n  153, 153, 153, 153, 153, 153, 153, 153, \n  153, 153, 153, 153, 153, 153, 153, 153, \n  153, 153, 153, 153, 153, 153, 153, 153, \n  153, 153, 153, 153, 153, 153, 153, 153, \n  154, 154, 154, 154, 154, 154, 154, 154, \n  154, 154, 154, 154, 154, 154, 154, 154, \n  154, 154, 154, 154, 154, 154, 154, 154, \n  154, 154, 154, 154, 154, 154, 154, 154, \n  154, 154, 154, 154, 154, 154, 154, 154, \n  154, 154, 154, 154, 154, 154, 154, 154, \n  154, 154, 154, 154, 154, 154, 154, 154, \n  154, 154, 154, 154, 154, 154, 154, 154, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  155, 155, 155, 155, 155, 155, 155, 155, \n  54, 156, 157, 157, 158, 158, 158, 158, \n  159, 159, 159, 159, 159, 159, 159, 159, \n  160, 160, 160, 160, 160, 160, 160, 160, \n  160, 160, 160, 160, 160, 160, 160, 160, \n  161, 161, 161, 161, 161, 161, 161, 161, \n  161, 161, 161, 161, 161, 161, 161, 161, \n  161, 161, 161, 161, 161, 161, 161, 161, \n  161, 161, 161, 161, 161, 161, 161, 161, \n  162, 162, 162, 162, 162, 162, 162, 162, \n  162, 162, 162, 162, 162, 162, 162, 162, \n  162, 162, 162, 162, 162, 162, 162, 162, \n  162, 162, 162, 162, 162, 162, 162, 162, \n  162, 162, 162, 162, 162, 162, 162, 162, \n  162, 162, 162, 162, 162, 162, 162, 162, \n  162, 162, 162, 162, 162, 162, 162, 162, \n  162, 162, 162, 162, 162, 162, 162, 162, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  163, 163, 163, 163, 163, 163, 163, 163, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  164, 164, 164, 164, 164, 164, 164, 164, \n  11, 55, 56, 165, 57, 166, 167, 167, \n  58, 168, 169, 169, 170, 170, 170, 170, \n  59, 171, 172, 172, 173, 173, 173, 173, \n  174, 174, 174, 174, 174, 174, 174, 174, \n  60, 175, 176, 176, 177, 177, 177, 177, \n  178, 178, 178, 178, 178, 178, 178, 178, \n  179, 179, 179, 179, 179, 179, 179, 179, \n  179, 179, 179, 179, 179, 179, 179, 179, \n  61, 180, 181, 181, 182, 182, 182, 182, \n  183, 183, 183, 183, 183, 183, 183, 183, \n  184, 184, 184, 184, 184, 184, 184, 184, \n  184, 184, 184, 184, 184, 184, 184, 184, \n  185, 185, 185, 185, 185, 185, 185, 185, \n  185, 185, 185, 185, 185, 185, 185, 185, \n  185, 185, 185, 185, 185, 185, 185, 185, \n  185, 185, 185, 185, 185, 185, 185, 185, \n  62, 186, 187, 187, 188, 188, 188, 188, \n  189, 189, 189, 189, 189, 189, 189, 189, \n  190, 190, 190, 190, 190, 190, 190, 190, \n  190, 190, 190, 190, 190, 190, 190, 190, \n  191, 191, 191, 191, 191, 191, 191, 191, \n  191, 191, 191, 191, 191, 191, 191, 191, \n  191, 191, 191, 191, 191, 191, 191, 191, \n  191, 191, 191, 191, 191, 191, 191, 191, \n  192, 192, 192, 192, 192, 192, 192, 192, \n  192, 192, 192, 192, 192, 192, 192, 192, \n  192, 192, 192, 192, 192, 192, 192, 192, \n  192, 192, 192, 192, 192, 192, 192, 192, \n  192, 192, 192, 192, 192, 192, 192, 192, \n  192, 192, 192, 192, 192, 192, 192, 192, \n  192, 192, 192, 192, 192, 192, 192, 192, \n  192, 192, 192, 192, 192, 192, 192, 192, \n  63, 193, 194, 194, 195, 195, 195, 195, \n  196, 196, 196, 196, 196, 196, 196, 196, \n  197, 197, 197, 197, 197, 197, 197, 197, \n  197, 197, 197, 197, 197, 197, 197, 197, \n  198, 198, 198, 198, 198, 198, 198, 198, \n  198, 198, 198, 198, 198, 198, 198, 198, \n  198, 198, 198, 198, 198, 198, 198, 198, \n  198, 198, 198, 198, 198, 198, 198, 198, \n  199, 199, 199, 199, 199, 199, 199, 199, \n  199, 199, 199, 199, 199, 199, 199, 199, \n  199, 199, 199, 199, 199, 199, 199, 199, \n  199, 199, 199, 199, 199, 199, 199, 199, \n  199, 199, 199, 199, 199, 199, 199, 199, \n  199, 199, 199, 199, 199, 199, 199, 199, \n  199, 199, 199, 199, 199, 199, 199, 199, \n  199, 199, 199, 199, 199, 199, 199, 199, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  200, 200, 200, 200, 200, 200, 200, 200, \n  64, 201, 202, 202, 203, 203, 203, 203, \n  204, 204, 204, 204, 204, 204, 204, 204, \n  205, 205, 205, 205, 205, 205, 205, 205, \n  205, 205, 205, 205, 205, 205, 205, 205, \n  206, 206, 206, 206, 206, 206, 206, 206, \n  206, 206, 206, 206, 206, 206, 206, 206, \n  206, 206, 206, 206, 206, 206, 206, 206, \n  206, 206, 206, 206, 206, 206, 206, 206, \n  207, 207, 207, 207, 207, 207, 207, 207, \n  207, 207, 207, 207, 207, 207, 207, 207, \n  207, 207, 207, 207, 207, 207, 207, 207, \n  207, 207, 207, 207, 207, 207, 207, 207, \n  207, 207, 207, 207, 207, 207, 207, 207, \n  207, 207, 207, 207, 207, 207, 207, 207, \n  207, 207, 207, 207, 207, 207, 207, 207, \n  207, 207, 207, 207, 207, 207, 207, 207, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  208, 208, 208, 208, 208, 208, 208, 208, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  209, 209, 209, 209, 209, 209, 209, 209, \n  65, 210, 211, 211, 212, 212, 212, 212, \n  213, 213, 213, 213, 213, 213, 213, 213, \n  214, 214, 214, 214, 214, 214, 214, 214, \n  214, 214, 214, 214, 214, 214, 214, 214, \n  215, 215, 215, 215, 215, 215, 215, 215, \n  215, 215, 215, 215, 215, 215, 215, 215, \n  215, 215, 215, 215, 215, 215, 215, 215, \n  215, 215, 215, 215, 215, 215, 215, 215, \n  216, 216, 216, 216, 216, 216, 216, 216, \n  216, 216, 216, 216, 216, 216, 216, 216, \n  216, 216, 216, 216, 216, 216, 216, 216, \n  216, 216, 216, 216, 216, 216, 216, 216, \n  216, 216, 216, 216, 216, 216, 216, 216, \n  216, 216, 216, 216, 216, 216, 216, 216, \n  216, 216, 216, 216, 216, 216, 216, 216, \n  216, 216, 216, 216, 216, 216, 216, 216, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  217, 217, 217, 217, 217, 217, 217, 217, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  218, 218, 218, 218, 218, 218, 218, 218, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  219, 219, 219, 219, 219, 219, 219, 219, \n  12, 66, 67, 220, 68, 221, 222, 222, \n  69, 223, 224, 224, 225, 225, 225, 225, \n  70, 226, 227, 227, 228, 228, 228, 228, \n  229, 229, 229, 229, 229, 229, 229, 229, \n  71, 230, 231, 231, 232, 232, 232, 232, \n  233, 233, 233, 233, 233, 233, 233, 233, \n  234, 234, 234, 234, 234, 234, 234, 234, \n  234, 234, 234, 234, 234, 234, 234, 234, \n  72, 235, 236, 236, 237, 237, 237, 237, \n  238, 238, 238, 238, 238, 238, 238, 238, \n  239, 239, 239, 239, 239, 239, 239, 239, \n  239, 239, 239, 239, 239, 239, 239, 239, \n  240, 240, 240, 240, 240, 240, 240, 240, \n  240, 240, 240, 240, 240, 240, 240, 240, \n  240, 240, 240, 240, 240, 240, 240, 240, \n  240, 240, 240, 240, 240, 240, 240, 240, \n  73, 241, 242, 242, 243, 243, 243, 243, \n  244, 244, 244, 244, 244, 244, 244, 244, \n  245, 245, 245, 245, 245, 245, 245, 245, \n  245, 245, 245, 245, 245, 245, 245, 245, \n  246, 246, 246, 246, 246, 246, 246, 246, \n  246, 246, 246, 246, 246, 246, 246, 246, \n  246, 246, 246, 246, 246, 246, 246, 246, \n  246, 246, 246, 246, 246, 246, 246, 246, \n  247, 247, 247, 247, 247, 247, 247, 247, \n  247, 247, 247, 247, 247, 247, 247, 247, \n  247, 247, 247, 247, 247, 247, 247, 247, \n  247, 247, 247, 247, 247, 247, 247, 247, \n  247, 247, 247, 247, 247, 247, 247, 247, \n  247, 247, 247, 247, 247, 247, 247, 247, \n  247, 247, 247, 247, 247, 247, 247, 247, \n  247, 247, 247, 247, 247, 247, 247, 247, \n  74, 248, 249, 249, 250, 250, 250, 250, \n  251, 251, 251, 251, 251, 251, 251, 251, \n  252, 252, 252, 252, 252, 252, 252, 252, \n  252, 252, 252, 252, 252, 252, 252, 252, \n  253, 253, 253, 253, 253, 253, 253, 253, \n  253, 253, 253, 253, 253, 253, 253, 253, \n  253, 253, 253, 253, 253, 253, 253, 253, \n  253, 253, 253, 253, 253, 253, 253, 253, \n  254, 254, 254, 254, 254, 254, 254, 254, \n  254, 254, 254, 254, 254, 254, 254, 254, \n  254, 254, 254, 254, 254, 254, 254, 254, \n  254, 254, 254, 254, 254, 254, 254, 254, \n  254, 254, 254, 254, 254, 254, 254, 254, \n  254, 254, 254, 254, 254, 254, 254, 254, \n  254, 254, 254, 254, 254, 254, 254, 254, \n  254, 254, 254, 254, 254, 254, 254, 254, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  255, 255, 255, 255, 255, 255, 255, 255, \n  75, 256, 257, 257, 258, 258, 258, 258, \n  259, 259, 259, 259, 259, 259, 259, 259, \n  260, 260, 260, 260, 260, 260, 260, 260, \n  260, 260, 260, 260, 260, 260, 260, 260, \n  261, 261, 261, 261, 261, 261, 261, 261, \n  261, 261, 261, 261, 261, 261, 261, 261, \n  261, 261, 261, 261, 261, 261, 261, 261, \n  261, 261, 261, 261, 261, 261, 261, 261, \n  262, 262, 262, 262, 262, 262, 262, 262, \n  262, 262, 262, 262, 262, 262, 262, 262, \n  262, 262, 262, 262, 262, 262, 262, 262, \n  262, 262, 262, 262, 262, 262, 262, 262, \n  262, 262, 262, 262, 262, 262, 262, 262, \n  262, 262, 262, 262, 262, 262, 262, 262, \n  262, 262, 262, 262, 262, 262, 262, 262, \n  262, 262, 262, 262, 262, 262, 262, 262, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  263, 263, 263, 263, 263, 263, 263, 263, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  264, 264, 264, 264, 264, 264, 264, 264, \n  76, 265, 266, 266, 267, 267, 267, 267, \n  268, 268, 268, 268, 268, 268, 268, 268, \n  269, 269, 269, 269, 269, 269, 269, 269, \n  269, 269, 269, 269, 269, 269, 269, 269, \n  270, 270, 270, 270, 270, 270, 270, 270, \n  270, 270, 270, 270, 270, 270, 270, 270, \n  270, 270, 270, 270, 270, 270, 270, 270, \n  270, 270, 270, 270, 270, 270, 270, 270, \n  271, 271, 271, 271, 271, 271, 271, 271, \n  271, 271, 271, 271, 271, 271, 271, 271, \n  271, 271, 271, 271, 271, 271, 271, 271, \n  271, 271, 271, 271, 271, 271, 271, 271, \n  271, 271, 271, 271, 271, 271, 271, 271, \n  271, 271, 271, 271, 271, 271, 271, 271, \n  271, 271, 271, 271, 271, 271, 271, 271, \n  271, 271, 271, 271, 271, 271, 271, 271, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  272, 272, 272, 272, 272, 272, 272, 272, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  273, 273, 273, 273, 273, 273, 273, 273, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  274, 274, 274, 274, 274, 274, 274, 274, \n  77, 275, 276, 276, 277, 277, 277, 277, \n  278, 278, 278, 278, 278, 278, 278, 278, \n  279, 279, 279, 279, 279, 279, 279, 279, \n  279, 279, 279, 279, 279, 279, 279, 279, \n  280, 280, 280, 280, 280, 280, 280, 280, \n  280, 280, 280, 280, 280, 280, 280, 280, \n  280, 280, 280, 280, 280, 280, 280, 280, \n  280, 280, 280, 280, 280, 280, 280, 280, \n  281, 281, 281, 281, 281, 281, 281, 281, \n  281, 281, 281, 281, 281, 281, 281, 281, \n  281, 281, 281, 281, 281, 281, 281, 281, \n  281, 281, 281, 281, 281, 281, 281, 281, \n  281, 281, 281, 281, 281, 281, 281, 281, \n  281, 281, 281, 281, 281, 281, 281, 281, \n  281, 281, 281, 281, 281, 281, 281, 281, \n  281, 281, 281, 281, 281, 281, 281, 281, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  282, 282, 282, 282, 282, 282, 282, 282, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  283, 283, 283, 283, 283, 283, 283, 283, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  284, 284, 284, 284, 284, 284, 284, 284, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285, \n  285, 285, 285, 285, 285, 285, 285, 285 };\n\nstatic const uint16_t anySuitVal[ 8192 ] = {\n  0, 0, 1, 0, 2, 1, 2, 0, \n  3, 3, 4, 1, 5, 2, 3, 0, \n  4, 6, 7, 4, 8, 5, 6, 1, \n  9, 7, 8, 2, 9, 3, 4, 9624, \n  5, 10, 11, 10, 12, 11, 12, 5, \n  13, 13, 14, 6, 15, 7, 8, 1, \n  14, 16, 17, 9, 18, 10, 11, 2, \n  19, 12, 13, 3, 14, 4, 9625, 9625, \n  6, 15, 16, 20, 17, 21, 22, 15, \n  18, 23, 24, 16, 25, 17, 18, 6, \n  19, 26, 27, 19, 28, 20, 21, 7, \n  29, 22, 23, 8, 24, 9, 10, 9624, \n  20, 30, 31, 25, 32, 26, 27, 11, \n  33, 28, 29, 12, 30, 13, 14, 14, \n  34, 31, 32, 15, 33, 16, 17, 17, \n  34, 18, 19, 19, 9626, 9626, 9626, 9626, \n  7, 21, 22, 35, 23, 36, 37, 35, \n  24, 38, 39, 36, 40, 37, 38, 21, \n  25, 41, 42, 39, 43, 40, 41, 22, \n  44, 42, 43, 23, 44, 24, 25, 9624, \n  26, 45, 46, 45, 47, 46, 47, 26, \n  48, 48, 49, 27, 50, 28, 29, 29, \n  49, 51, 52, 30, 53, 31, 32, 32, \n  54, 33, 34, 34, 35, 35, 9625, 9625, \n  27, 50, 51, 55, 52, 56, 57, 36, \n  53, 58, 59, 37, 60, 38, 39, 39, \n  54, 61, 62, 40, 63, 41, 42, 42, \n  64, 43, 44, 44, 45, 45, 45, 9624, \n  55, 65, 66, 46, 67, 47, 48, 48, \n  68, 49, 50, 50, 51, 51, 51, 51, \n  69, 52, 53, 53, 54, 54, 54, 54, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  8, 28, 29, 56, 30, 57, 58, 70, \n  31, 59, 60, 71, 61, 72, 73, 56, \n  32, 62, 63, 74, 64, 75, 76, 57, \n  65, 77, 78, 58, 79, 59, 60, 9624, \n  33, 66, 67, 80, 68, 81, 82, 61, \n  69, 83, 84, 62, 85, 63, 64, 64, \n  70, 86, 87, 65, 88, 66, 67, 67, \n  89, 68, 69, 69, 70, 70, 9625, 9625, \n  34, 71, 72, 90, 73, 91, 92, 71, \n  74, 93, 94, 72, 95, 73, 74, 74, \n  75, 96, 97, 75, 98, 76, 77, 77, \n  99, 78, 79, 79, 80, 80, 80, 9624, \n  76, 100, 101, 81, 102, 82, 83, 83, \n  103, 84, 85, 85, 86, 86, 86, 86, \n  104, 87, 88, 88, 89, 89, 89, 89, \n  90, 90, 90, 90, 9626, 9626, 9626, 9626, \n  35, 77, 78, 105, 79, 106, 107, 91, \n  80, 108, 109, 92, 110, 93, 94, 94, \n  81, 111, 112, 95, 113, 96, 97, 97, \n  114, 98, 99, 99, 100, 100, 100, 9624, \n  82, 115, 116, 101, 117, 102, 103, 103, \n  118, 104, 105, 105, 106, 106, 106, 106, \n  119, 107, 108, 108, 109, 109, 109, 109, \n  110, 110, 110, 110, 110, 110, 9625, 9625, \n  83, 120, 121, 111, 122, 112, 113, 113, \n  123, 114, 115, 115, 116, 116, 116, 116, \n  124, 117, 118, 118, 119, 119, 119, 119, \n  120, 120, 120, 120, 120, 120, 120, 9624, \n  125, 121, 122, 122, 123, 123, 123, 123, \n  124, 124, 124, 124, 124, 124, 124, 124, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  9, 36, 37, 84, 38, 85, 86, 126, \n  39, 87, 88, 127, 89, 128, 129, 126, \n  40, 90, 91, 130, 92, 131, 132, 127, \n  93, 133, 134, 128, 135, 129, 130, 9624, \n  41, 94, 95, 136, 96, 137, 138, 131, \n  97, 139, 140, 132, 141, 133, 134, 134, \n  98, 142, 143, 135, 144, 136, 137, 137, \n  145, 138, 139, 139, 140, 140, 9625, 9625, \n  42, 99, 100, 146, 101, 147, 148, 141, \n  102, 149, 150, 142, 151, 143, 144, 144, \n  103, 152, 153, 145, 154, 146, 147, 147, \n  155, 148, 149, 149, 150, 150, 150, 9624, \n  104, 156, 157, 151, 158, 152, 153, 153, \n  159, 154, 155, 155, 156, 156, 156, 156, \n  160, 157, 158, 158, 159, 159, 159, 159, \n  160, 160, 160, 160, 9626, 9626, 9626, 9626, \n  43, 105, 106, 161, 107, 162, 163, 161, \n  108, 164, 165, 162, 166, 163, 164, 164, \n  109, 167, 168, 165, 169, 166, 167, 167, \n  170, 168, 169, 169, 170, 170, 170, 9624, \n  110, 171, 172, 171, 173, 172, 173, 173, \n  174, 174, 175, 175, 176, 176, 176, 176, \n  175, 177, 178, 178, 179, 179, 179, 179, \n  180, 180, 180, 180, 180, 180, 9625, 9625, \n  111, 176, 177, 181, 178, 182, 183, 183, \n  179, 184, 185, 185, 186, 186, 186, 186, \n  180, 187, 188, 188, 189, 189, 189, 189, \n  190, 190, 190, 190, 190, 190, 190, 9624, \n  181, 191, 192, 192, 193, 193, 193, 193, \n  194, 194, 194, 194, 194, 194, 194, 194, \n  195, 195, 195, 195, 195, 195, 195, 195, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  44, 112, 113, 182, 114, 183, 184, 196, \n  115, 185, 186, 197, 187, 198, 199, 199, \n  116, 188, 189, 200, 190, 201, 202, 202, \n  191, 203, 204, 204, 205, 205, 205, 9624, \n  117, 192, 193, 206, 194, 207, 208, 208, \n  195, 209, 210, 210, 211, 211, 211, 211, \n  196, 212, 213, 213, 214, 214, 214, 214, \n  215, 215, 215, 215, 215, 215, 9625, 9625, \n  118, 197, 198, 216, 199, 217, 218, 218, \n  200, 219, 220, 220, 221, 221, 221, 221, \n  201, 222, 223, 223, 224, 224, 224, 224, \n  225, 225, 225, 225, 225, 225, 225, 9624, \n  202, 226, 227, 227, 228, 228, 228, 228, \n  229, 229, 229, 229, 229, 229, 229, 229, \n  230, 230, 230, 230, 230, 230, 230, 230, \n  230, 230, 230, 230, 9626, 9626, 9626, 9626, \n  119, 203, 204, 231, 205, 232, 233, 233, \n  206, 234, 235, 235, 236, 236, 236, 236, \n  207, 237, 238, 238, 239, 239, 239, 239, \n  240, 240, 240, 240, 240, 240, 240, 9624, \n  208, 241, 242, 242, 243, 243, 243, 243, \n  244, 244, 244, 244, 244, 244, 244, 244, \n  245, 245, 245, 245, 245, 245, 245, 245, \n  245, 245, 245, 245, 245, 245, 9625, 9625, \n  209, 246, 247, 247, 248, 248, 248, 248, \n  249, 249, 249, 249, 249, 249, 249, 249, \n  250, 250, 250, 250, 250, 250, 250, 250, \n  250, 250, 250, 250, 250, 250, 250, 9624, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  10, 45, 46, 120, 47, 121, 122, 210, \n  48, 123, 124, 211, 125, 212, 213, 252, \n  49, 126, 127, 214, 128, 215, 216, 253, \n  129, 217, 218, 254, 219, 255, 256, 9624, \n  50, 130, 131, 220, 132, 221, 222, 257, \n  133, 223, 224, 258, 225, 259, 260, 260, \n  134, 226, 227, 261, 228, 262, 263, 263, \n  229, 264, 265, 265, 266, 266, 9625, 9625, \n  51, 135, 136, 230, 137, 231, 232, 267, \n  138, 233, 234, 268, 235, 269, 270, 270, \n  139, 236, 237, 271, 238, 272, 273, 273, \n  239, 274, 275, 275, 276, 276, 276, 9624, \n  140, 240, 241, 277, 242, 278, 279, 279, \n  243, 280, 281, 281, 282, 282, 282, 282, \n  244, 283, 284, 284, 285, 285, 285, 285, \n  286, 286, 286, 286, 9626, 9626, 9626, 9626, \n  52, 141, 142, 245, 143, 246, 247, 287, \n  144, 248, 249, 288, 250, 289, 290, 290, \n  145, 251, 252, 291, 253, 292, 293, 293, \n  254, 294, 295, 295, 296, 296, 296, 9624, \n  146, 255, 256, 297, 257, 298, 299, 299, \n  258, 300, 301, 301, 302, 302, 302, 302, \n  259, 303, 304, 304, 305, 305, 305, 305, \n  306, 306, 306, 306, 306, 306, 9625, 9625, \n  147, 260, 261, 307, 262, 308, 309, 309, \n  263, 310, 311, 311, 312, 312, 312, 312, \n  264, 313, 314, 314, 315, 315, 315, 315, \n  316, 316, 316, 316, 316, 316, 316, 9624, \n  265, 317, 318, 318, 319, 319, 319, 319, \n  320, 320, 320, 320, 320, 320, 320, 320, \n  321, 321, 321, 321, 321, 321, 321, 321, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  53, 148, 149, 266, 150, 267, 268, 322, \n  151, 269, 270, 323, 271, 324, 325, 325, \n  152, 272, 273, 326, 274, 327, 328, 328, \n  275, 329, 330, 330, 331, 331, 331, 9624, \n  153, 276, 277, 332, 278, 333, 334, 334, \n  279, 335, 336, 336, 337, 337, 337, 337, \n  280, 338, 339, 339, 340, 340, 340, 340, \n  341, 341, 341, 341, 341, 341, 9625, 9625, \n  154, 281, 282, 342, 283, 343, 344, 344, \n  284, 345, 346, 346, 347, 347, 347, 347, \n  285, 348, 349, 349, 350, 350, 350, 350, \n  351, 351, 351, 351, 351, 351, 351, 9624, \n  286, 352, 353, 353, 354, 354, 354, 354, \n  355, 355, 355, 355, 355, 355, 355, 355, \n  356, 356, 356, 356, 356, 356, 356, 356, \n  356, 356, 356, 356, 9626, 9626, 9626, 9626, \n  155, 287, 288, 357, 289, 358, 359, 359, \n  290, 360, 361, 361, 362, 362, 362, 362, \n  291, 363, 364, 364, 365, 365, 365, 365, \n  366, 366, 366, 366, 366, 366, 366, 9624, \n  292, 367, 368, 368, 369, 369, 369, 369, \n  370, 370, 370, 370, 370, 370, 370, 370, \n  371, 371, 371, 371, 371, 371, 371, 371, \n  371, 371, 371, 371, 371, 371, 9625, 9625, \n  293, 372, 373, 373, 374, 374, 374, 374, \n  375, 375, 375, 375, 375, 375, 375, 375, \n  376, 376, 376, 376, 376, 376, 376, 376, \n  376, 376, 376, 376, 376, 376, 376, 9624, \n  377, 377, 377, 377, 377, 377, 377, 377, \n  377, 377, 377, 377, 377, 377, 377, 377, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  54, 156, 157, 294, 158, 295, 296, 378, \n  159, 297, 298, 379, 299, 380, 381, 381, \n  160, 300, 301, 382, 302, 383, 384, 384, \n  303, 385, 386, 386, 387, 387, 387, 9624, \n  161, 304, 305, 388, 306, 389, 390, 390, \n  307, 391, 392, 392, 393, 393, 393, 393, \n  308, 394, 395, 395, 396, 396, 396, 396, \n  397, 397, 397, 397, 397, 397, 9625, 9625, \n  162, 309, 310, 398, 311, 399, 400, 400, \n  312, 401, 402, 402, 403, 403, 403, 403, \n  313, 404, 405, 405, 406, 406, 406, 406, \n  407, 407, 407, 407, 407, 407, 407, 9624, \n  314, 408, 409, 409, 410, 410, 410, 410, \n  411, 411, 411, 411, 411, 411, 411, 411, \n  412, 412, 412, 412, 412, 412, 412, 412, \n  412, 412, 412, 412, 9626, 9626, 9626, 9626, \n  163, 315, 316, 413, 317, 414, 415, 415, \n  318, 416, 417, 417, 418, 418, 418, 418, \n  319, 419, 420, 420, 421, 421, 421, 421, \n  422, 422, 422, 422, 422, 422, 422, 9624, \n  320, 423, 424, 424, 425, 425, 425, 425, \n  426, 426, 426, 426, 426, 426, 426, 426, \n  427, 427, 427, 427, 427, 427, 427, 427, \n  427, 427, 427, 427, 427, 427, 9625, 9625, \n  321, 428, 429, 429, 430, 430, 430, 430, \n  431, 431, 431, 431, 431, 431, 431, 431, \n  432, 432, 432, 432, 432, 432, 432, 432, \n  432, 432, 432, 432, 432, 432, 432, 9624, \n  433, 433, 433, 433, 433, 433, 433, 433, \n  433, 433, 433, 433, 433, 433, 433, 433, \n  433, 433, 433, 433, 433, 433, 433, 433, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  164, 322, 323, 434, 324, 435, 436, 436, \n  325, 437, 438, 438, 439, 439, 439, 439, \n  326, 440, 441, 441, 442, 442, 442, 442, \n  443, 443, 443, 443, 443, 443, 443, 9624, \n  327, 444, 445, 445, 446, 446, 446, 446, \n  447, 447, 447, 447, 447, 447, 447, 447, \n  448, 448, 448, 448, 448, 448, 448, 448, \n  448, 448, 448, 448, 448, 448, 9625, 9625, \n  328, 449, 450, 450, 451, 451, 451, 451, \n  452, 452, 452, 452, 452, 452, 452, 452, \n  453, 453, 453, 453, 453, 453, 453, 453, \n  453, 453, 453, 453, 453, 453, 453, 9624, \n  454, 454, 454, 454, 454, 454, 454, 454, \n  454, 454, 454, 454, 454, 454, 454, 454, \n  454, 454, 454, 454, 454, 454, 454, 454, \n  454, 454, 454, 454, 9626, 9626, 9626, 9626, \n  329, 455, 456, 456, 457, 457, 457, 457, \n  458, 458, 458, 458, 458, 458, 458, 458, \n  459, 459, 459, 459, 459, 459, 459, 459, \n  459, 459, 459, 459, 459, 459, 459, 9624, \n  460, 460, 460, 460, 460, 460, 460, 460, \n  460, 460, 460, 460, 460, 460, 460, 460, \n  460, 460, 460, 460, 460, 460, 460, 460, \n  460, 460, 460, 460, 460, 460, 9625, 9625, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  11, 55, 56, 165, 57, 166, 167, 330, \n  58, 168, 169, 331, 170, 332, 333, 462, \n  59, 171, 172, 334, 173, 335, 336, 463, \n  174, 337, 338, 464, 339, 465, 466, 9624, \n  60, 175, 176, 340, 177, 341, 342, 467, \n  178, 343, 344, 468, 345, 469, 470, 470, \n  179, 346, 347, 471, 348, 472, 473, 473, \n  349, 474, 475, 475, 476, 476, 9625, 9625, \n  61, 180, 181, 350, 182, 351, 352, 477, \n  183, 353, 354, 478, 355, 479, 480, 480, \n  184, 356, 357, 481, 358, 482, 483, 483, \n  359, 484, 485, 485, 486, 486, 486, 9624, \n  185, 360, 361, 487, 362, 488, 489, 489, \n  363, 490, 491, 491, 492, 492, 492, 492, \n  364, 493, 494, 494, 495, 495, 495, 495, \n  496, 496, 496, 496, 9626, 9626, 9626, 9626, \n  62, 186, 187, 365, 188, 366, 367, 497, \n  189, 368, 369, 498, 370, 499, 500, 500, \n  190, 371, 372, 501, 373, 502, 503, 503, \n  374, 504, 505, 505, 506, 506, 506, 9624, \n  191, 375, 376, 507, 377, 508, 509, 509, \n  378, 510, 511, 511, 512, 512, 512, 512, \n  379, 513, 514, 514, 515, 515, 515, 515, \n  516, 516, 516, 516, 516, 516, 9625, 9625, \n  192, 380, 381, 517, 382, 518, 519, 519, \n  383, 520, 521, 521, 522, 522, 522, 522, \n  384, 523, 524, 524, 525, 525, 525, 525, \n  526, 526, 526, 526, 526, 526, 526, 9624, \n  385, 527, 528, 528, 529, 529, 529, 529, \n  530, 530, 530, 530, 530, 530, 530, 530, \n  531, 531, 531, 531, 531, 531, 531, 531, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  63, 193, 194, 386, 195, 387, 388, 532, \n  196, 389, 390, 533, 391, 534, 535, 535, \n  197, 392, 393, 536, 394, 537, 538, 538, \n  395, 539, 540, 540, 541, 541, 541, 9624, \n  198, 396, 397, 542, 398, 543, 544, 544, \n  399, 545, 546, 546, 547, 547, 547, 547, \n  400, 548, 549, 549, 550, 550, 550, 550, \n  551, 551, 551, 551, 551, 551, 9625, 9625, \n  199, 401, 402, 552, 403, 553, 554, 554, \n  404, 555, 556, 556, 557, 557, 557, 557, \n  405, 558, 559, 559, 560, 560, 560, 560, \n  561, 561, 561, 561, 561, 561, 561, 9624, \n  406, 562, 563, 563, 564, 564, 564, 564, \n  565, 565, 565, 565, 565, 565, 565, 565, \n  566, 566, 566, 566, 566, 566, 566, 566, \n  566, 566, 566, 566, 9626, 9626, 9626, 9626, \n  200, 407, 408, 567, 409, 568, 569, 569, \n  410, 570, 571, 571, 572, 572, 572, 572, \n  411, 573, 574, 574, 575, 575, 575, 575, \n  576, 576, 576, 576, 576, 576, 576, 9624, \n  412, 577, 578, 578, 579, 579, 579, 579, \n  580, 580, 580, 580, 580, 580, 580, 580, \n  581, 581, 581, 581, 581, 581, 581, 581, \n  581, 581, 581, 581, 581, 581, 9625, 9625, \n  413, 582, 583, 583, 584, 584, 584, 584, \n  585, 585, 585, 585, 585, 585, 585, 585, \n  586, 586, 586, 586, 586, 586, 586, 586, \n  586, 586, 586, 586, 586, 586, 586, 9624, \n  587, 587, 587, 587, 587, 587, 587, 587, \n  587, 587, 587, 587, 587, 587, 587, 587, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  64, 201, 202, 414, 203, 415, 416, 588, \n  204, 417, 418, 589, 419, 590, 591, 591, \n  205, 420, 421, 592, 422, 593, 594, 594, \n  423, 595, 596, 596, 597, 597, 597, 9624, \n  206, 424, 425, 598, 426, 599, 600, 600, \n  427, 601, 602, 602, 603, 603, 603, 603, \n  428, 604, 605, 605, 606, 606, 606, 606, \n  607, 607, 607, 607, 607, 607, 9625, 9625, \n  207, 429, 430, 608, 431, 609, 610, 610, \n  432, 611, 612, 612, 613, 613, 613, 613, \n  433, 614, 615, 615, 616, 616, 616, 616, \n  617, 617, 617, 617, 617, 617, 617, 9624, \n  434, 618, 619, 619, 620, 620, 620, 620, \n  621, 621, 621, 621, 621, 621, 621, 621, \n  622, 622, 622, 622, 622, 622, 622, 622, \n  622, 622, 622, 622, 9626, 9626, 9626, 9626, \n  208, 435, 436, 623, 437, 624, 625, 625, \n  438, 626, 627, 627, 628, 628, 628, 628, \n  439, 629, 630, 630, 631, 631, 631, 631, \n  632, 632, 632, 632, 632, 632, 632, 9624, \n  440, 633, 634, 634, 635, 635, 635, 635, \n  636, 636, 636, 636, 636, 636, 636, 636, \n  637, 637, 637, 637, 637, 637, 637, 637, \n  637, 637, 637, 637, 637, 637, 9625, 9625, \n  441, 638, 639, 639, 640, 640, 640, 640, \n  641, 641, 641, 641, 641, 641, 641, 641, \n  642, 642, 642, 642, 642, 642, 642, 642, \n  642, 642, 642, 642, 642, 642, 642, 9624, \n  643, 643, 643, 643, 643, 643, 643, 643, \n  643, 643, 643, 643, 643, 643, 643, 643, \n  643, 643, 643, 643, 643, 643, 643, 643, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  209, 442, 443, 644, 444, 645, 646, 646, \n  445, 647, 648, 648, 649, 649, 649, 649, \n  446, 650, 651, 651, 652, 652, 652, 652, \n  653, 653, 653, 653, 653, 653, 653, 9624, \n  447, 654, 655, 655, 656, 656, 656, 656, \n  657, 657, 657, 657, 657, 657, 657, 657, \n  658, 658, 658, 658, 658, 658, 658, 658, \n  658, 658, 658, 658, 658, 658, 9625, 9625, \n  448, 659, 660, 660, 661, 661, 661, 661, \n  662, 662, 662, 662, 662, 662, 662, 662, \n  663, 663, 663, 663, 663, 663, 663, 663, \n  663, 663, 663, 663, 663, 663, 663, 9624, \n  664, 664, 664, 664, 664, 664, 664, 664, \n  664, 664, 664, 664, 664, 664, 664, 664, \n  664, 664, 664, 664, 664, 664, 664, 664, \n  664, 664, 664, 664, 9626, 9626, 9626, 9626, \n  449, 665, 666, 666, 667, 667, 667, 667, \n  668, 668, 668, 668, 668, 668, 668, 668, \n  669, 669, 669, 669, 669, 669, 669, 669, \n  669, 669, 669, 669, 669, 669, 669, 9624, \n  670, 670, 670, 670, 670, 670, 670, 670, \n  670, 670, 670, 670, 670, 670, 670, 670, \n  670, 670, 670, 670, 670, 670, 670, 670, \n  670, 670, 670, 670, 670, 670, 9625, 9625, \n  671, 671, 671, 671, 671, 671, 671, 671, \n  671, 671, 671, 671, 671, 671, 671, 671, \n  671, 671, 671, 671, 671, 671, 671, 671, \n  671, 671, 671, 671, 671, 671, 671, 9624, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  65, 210, 211, 450, 212, 451, 452, 672, \n  213, 453, 454, 673, 455, 674, 675, 675, \n  214, 456, 457, 676, 458, 677, 678, 678, \n  459, 679, 680, 680, 681, 681, 681, 9624, \n  215, 460, 461, 682, 462, 683, 684, 684, \n  463, 685, 686, 686, 687, 687, 687, 687, \n  464, 688, 689, 689, 690, 690, 690, 690, \n  691, 691, 691, 691, 691, 691, 9625, 9625, \n  216, 465, 466, 692, 467, 693, 694, 694, \n  468, 695, 696, 696, 697, 697, 697, 697, \n  469, 698, 699, 699, 700, 700, 700, 700, \n  701, 701, 701, 701, 701, 701, 701, 9624, \n  470, 702, 703, 703, 704, 704, 704, 704, \n  705, 705, 705, 705, 705, 705, 705, 705, \n  706, 706, 706, 706, 706, 706, 706, 706, \n  706, 706, 706, 706, 9626, 9626, 9626, 9626, \n  217, 471, 472, 707, 473, 708, 709, 709, \n  474, 710, 711, 711, 712, 712, 712, 712, \n  475, 713, 714, 714, 715, 715, 715, 715, \n  716, 716, 716, 716, 716, 716, 716, 9624, \n  476, 717, 718, 718, 719, 719, 719, 719, \n  720, 720, 720, 720, 720, 720, 720, 720, \n  721, 721, 721, 721, 721, 721, 721, 721, \n  721, 721, 721, 721, 721, 721, 9625, 9625, \n  477, 722, 723, 723, 724, 724, 724, 724, \n  725, 725, 725, 725, 725, 725, 725, 725, \n  726, 726, 726, 726, 726, 726, 726, 726, \n  726, 726, 726, 726, 726, 726, 726, 9624, \n  727, 727, 727, 727, 727, 727, 727, 727, \n  727, 727, 727, 727, 727, 727, 727, 727, \n  727, 727, 727, 727, 727, 727, 727, 727, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  218, 478, 479, 728, 480, 729, 730, 730, \n  481, 731, 732, 732, 733, 733, 733, 733, \n  482, 734, 735, 735, 736, 736, 736, 736, \n  737, 737, 737, 737, 737, 737, 737, 9624, \n  483, 738, 739, 739, 740, 740, 740, 740, \n  741, 741, 741, 741, 741, 741, 741, 741, \n  742, 742, 742, 742, 742, 742, 742, 742, \n  742, 742, 742, 742, 742, 742, 9625, 9625, \n  484, 743, 744, 744, 745, 745, 745, 745, \n  746, 746, 746, 746, 746, 746, 746, 746, \n  747, 747, 747, 747, 747, 747, 747, 747, \n  747, 747, 747, 747, 747, 747, 747, 9624, \n  748, 748, 748, 748, 748, 748, 748, 748, \n  748, 748, 748, 748, 748, 748, 748, 748, \n  748, 748, 748, 748, 748, 748, 748, 748, \n  748, 748, 748, 748, 9626, 9626, 9626, 9626, \n  485, 749, 750, 750, 751, 751, 751, 751, \n  752, 752, 752, 752, 752, 752, 752, 752, \n  753, 753, 753, 753, 753, 753, 753, 753, \n  753, 753, 753, 753, 753, 753, 753, 9624, \n  754, 754, 754, 754, 754, 754, 754, 754, \n  754, 754, 754, 754, 754, 754, 754, 754, \n  754, 754, 754, 754, 754, 754, 754, 754, \n  754, 754, 754, 754, 754, 754, 9625, 9625, \n  755, 755, 755, 755, 755, 755, 755, 755, \n  755, 755, 755, 755, 755, 755, 755, 755, \n  755, 755, 755, 755, 755, 755, 755, 755, \n  755, 755, 755, 755, 755, 755, 755, 9624, \n  755, 755, 755, 755, 755, 755, 755, 755, \n  755, 755, 755, 755, 755, 755, 755, 755, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  219, 486, 487, 756, 488, 757, 758, 758, \n  489, 759, 760, 760, 761, 761, 761, 761, \n  490, 762, 763, 763, 764, 764, 764, 764, \n  765, 765, 765, 765, 765, 765, 765, 9624, \n  491, 766, 767, 767, 768, 768, 768, 768, \n  769, 769, 769, 769, 769, 769, 769, 769, \n  770, 770, 770, 770, 770, 770, 770, 770, \n  770, 770, 770, 770, 770, 770, 9625, 9625, \n  492, 771, 772, 772, 773, 773, 773, 773, \n  774, 774, 774, 774, 774, 774, 774, 774, \n  775, 775, 775, 775, 775, 775, 775, 775, \n  775, 775, 775, 775, 775, 775, 775, 9624, \n  776, 776, 776, 776, 776, 776, 776, 776, \n  776, 776, 776, 776, 776, 776, 776, 776, \n  776, 776, 776, 776, 776, 776, 776, 776, \n  776, 776, 776, 776, 9626, 9626, 9626, 9626, \n  493, 777, 778, 778, 779, 779, 779, 779, \n  780, 780, 780, 780, 780, 780, 780, 780, \n  781, 781, 781, 781, 781, 781, 781, 781, \n  781, 781, 781, 781, 781, 781, 781, 9624, \n  782, 782, 782, 782, 782, 782, 782, 782, \n  782, 782, 782, 782, 782, 782, 782, 782, \n  782, 782, 782, 782, 782, 782, 782, 782, \n  782, 782, 782, 782, 782, 782, 9625, 9625, \n  783, 783, 783, 783, 783, 783, 783, 783, \n  783, 783, 783, 783, 783, 783, 783, 783, \n  783, 783, 783, 783, 783, 783, 783, 783, \n  783, 783, 783, 783, 783, 783, 783, 9624, \n  783, 783, 783, 783, 783, 783, 783, 783, \n  783, 783, 783, 783, 783, 783, 783, 783, \n  783, 783, 783, 783, 783, 783, 783, 783, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  494, 784, 785, 785, 786, 786, 786, 786, \n  787, 787, 787, 787, 787, 787, 787, 787, \n  788, 788, 788, 788, 788, 788, 788, 788, \n  788, 788, 788, 788, 788, 788, 788, 9624, \n  789, 789, 789, 789, 789, 789, 789, 789, \n  789, 789, 789, 789, 789, 789, 789, 789, \n  789, 789, 789, 789, 789, 789, 789, 789, \n  789, 789, 789, 789, 789, 789, 9625, 9625, \n  790, 790, 790, 790, 790, 790, 790, 790, \n  790, 790, 790, 790, 790, 790, 790, 790, \n  790, 790, 790, 790, 790, 790, 790, 790, \n  790, 790, 790, 790, 790, 790, 790, 9624, \n  790, 790, 790, 790, 790, 790, 790, 790, \n  790, 790, 790, 790, 790, 790, 790, 790, \n  790, 790, 790, 790, 790, 790, 790, 790, \n  790, 790, 790, 790, 9626, 9626, 9626, 9626, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  9631, 9631, 9631, 9631, 9631, 9631, 9631, 9631, \n  12, 66, 67, 220, 68, 221, 222, 495, \n  69, 223, 224, 496, 225, 497, 498, 9623, \n  70, 226, 227, 499, 228, 500, 501, 793, \n  229, 502, 503, 794, 504, 795, 796, 9624, \n  71, 230, 231, 505, 232, 506, 507, 797, \n  233, 508, 509, 798, 510, 799, 800, 9623, \n  234, 511, 512, 801, 513, 802, 803, 803, \n  514, 804, 805, 805, 806, 806, 9625, 9625, \n  72, 235, 236, 515, 237, 516, 517, 807, \n  238, 518, 519, 808, 520, 809, 810, 9623, \n  239, 521, 522, 811, 523, 812, 813, 813, \n  524, 814, 815, 815, 816, 816, 816, 9624, \n  240, 525, 526, 817, 527, 818, 819, 819, \n  528, 820, 821, 821, 822, 822, 822, 9623, \n  529, 823, 824, 824, 825, 825, 825, 825, \n  826, 826, 826, 826, 9626, 9626, 9626, 9626, \n  73, 241, 242, 530, 243, 531, 532, 827, \n  244, 533, 534, 828, 535, 829, 830, 9623, \n  245, 536, 537, 831, 538, 832, 833, 833, \n  539, 834, 835, 835, 836, 836, 836, 9624, \n  246, 540, 541, 837, 542, 838, 839, 839, \n  543, 840, 841, 841, 842, 842, 842, 9623, \n  544, 843, 844, 844, 845, 845, 845, 845, \n  846, 846, 846, 846, 846, 846, 9625, 9625, \n  247, 545, 546, 847, 547, 848, 849, 849, \n  548, 850, 851, 851, 852, 852, 852, 9623, \n  549, 853, 854, 854, 855, 855, 855, 855, \n  856, 856, 856, 856, 856, 856, 856, 9624, \n  550, 857, 858, 858, 859, 859, 859, 859, \n  860, 860, 860, 860, 860, 860, 860, 9623, \n  861, 861, 861, 861, 861, 861, 861, 861, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  74, 248, 249, 551, 250, 552, 553, 862, \n  251, 554, 555, 863, 556, 864, 865, 9623, \n  252, 557, 558, 866, 559, 867, 868, 868, \n  560, 869, 870, 870, 871, 871, 871, 9624, \n  253, 561, 562, 872, 563, 873, 874, 874, \n  564, 875, 876, 876, 877, 877, 877, 9623, \n  565, 878, 879, 879, 880, 880, 880, 880, \n  881, 881, 881, 881, 881, 881, 9625, 9625, \n  254, 566, 567, 882, 568, 883, 884, 884, \n  569, 885, 886, 886, 887, 887, 887, 9623, \n  570, 888, 889, 889, 890, 890, 890, 890, \n  891, 891, 891, 891, 891, 891, 891, 9624, \n  571, 892, 893, 893, 894, 894, 894, 894, \n  895, 895, 895, 895, 895, 895, 895, 9623, \n  896, 896, 896, 896, 896, 896, 896, 896, \n  896, 896, 896, 896, 9626, 9626, 9626, 9626, \n  255, 572, 573, 897, 574, 898, 899, 899, \n  575, 900, 901, 901, 902, 902, 902, 9623, \n  576, 903, 904, 904, 905, 905, 905, 905, \n  906, 906, 906, 906, 906, 906, 906, 9624, \n  577, 907, 908, 908, 909, 909, 909, 909, \n  910, 910, 910, 910, 910, 910, 910, 9623, \n  911, 911, 911, 911, 911, 911, 911, 911, \n  911, 911, 911, 911, 911, 911, 9625, 9625, \n  578, 912, 913, 913, 914, 914, 914, 914, \n  915, 915, 915, 915, 915, 915, 915, 9623, \n  916, 916, 916, 916, 916, 916, 916, 916, \n  916, 916, 916, 916, 916, 916, 916, 9624, \n  917, 917, 917, 917, 917, 917, 917, 917, \n  917, 917, 917, 917, 917, 917, 917, 9623, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  75, 256, 257, 579, 258, 580, 581, 918, \n  259, 582, 583, 919, 584, 920, 921, 9623, \n  260, 585, 586, 922, 587, 923, 924, 924, \n  588, 925, 926, 926, 927, 927, 927, 9624, \n  261, 589, 590, 928, 591, 929, 930, 930, \n  592, 931, 932, 932, 933, 933, 933, 9623, \n  593, 934, 935, 935, 936, 936, 936, 936, \n  937, 937, 937, 937, 937, 937, 9625, 9625, \n  262, 594, 595, 938, 596, 939, 940, 940, \n  597, 941, 942, 942, 943, 943, 943, 9623, \n  598, 944, 945, 945, 946, 946, 946, 946, \n  947, 947, 947, 947, 947, 947, 947, 9624, \n  599, 948, 949, 949, 950, 950, 950, 950, \n  951, 951, 951, 951, 951, 951, 951, 9623, \n  952, 952, 952, 952, 952, 952, 952, 952, \n  952, 952, 952, 952, 9626, 9626, 9626, 9626, \n  263, 600, 601, 953, 602, 954, 955, 955, \n  603, 956, 957, 957, 958, 958, 958, 9623, \n  604, 959, 960, 960, 961, 961, 961, 961, \n  962, 962, 962, 962, 962, 962, 962, 9624, \n  605, 963, 964, 964, 965, 965, 965, 965, \n  966, 966, 966, 966, 966, 966, 966, 9623, \n  967, 967, 967, 967, 967, 967, 967, 967, \n  967, 967, 967, 967, 967, 967, 9625, 9625, \n  606, 968, 969, 969, 970, 970, 970, 970, \n  971, 971, 971, 971, 971, 971, 971, 9623, \n  972, 972, 972, 972, 972, 972, 972, 972, \n  972, 972, 972, 972, 972, 972, 972, 9624, \n  973, 973, 973, 973, 973, 973, 973, 973, \n  973, 973, 973, 973, 973, 973, 973, 9623, \n  973, 973, 973, 973, 973, 973, 973, 973, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  264, 607, 608, 974, 609, 975, 976, 976, \n  610, 977, 978, 978, 979, 979, 979, 9623, \n  611, 980, 981, 981, 982, 982, 982, 982, \n  983, 983, 983, 983, 983, 983, 983, 9624, \n  612, 984, 985, 985, 986, 986, 986, 986, \n  987, 987, 987, 987, 987, 987, 987, 9623, \n  988, 988, 988, 988, 988, 988, 988, 988, \n  988, 988, 988, 988, 988, 988, 9625, 9625, \n  613, 989, 990, 990, 991, 991, 991, 991, \n  992, 992, 992, 992, 992, 992, 992, 9623, \n  993, 993, 993, 993, 993, 993, 993, 993, \n  993, 993, 993, 993, 993, 993, 993, 9624, \n  994, 994, 994, 994, 994, 994, 994, 994, \n  994, 994, 994, 994, 994, 994, 994, 9623, \n  994, 994, 994, 994, 994, 994, 994, 994, \n  994, 994, 994, 994, 9626, 9626, 9626, 9626, \n  614, 995, 996, 996, 997, 997, 997, 997, \n  998, 998, 998, 998, 998, 998, 998, 9623, \n  999, 999, 999, 999, 999, 999, 999, 999, \n  999, 999, 999, 999, 999, 999, 999, 9624, \n  1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, \n  1000, 1000, 1000, 1000, 1000, 1000, 1000, 9623, \n  1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, \n  1000, 1000, 1000, 1000, 1000, 1000, 9625, 9625, \n  1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, \n  1001, 1001, 1001, 1001, 1001, 1001, 1001, 9623, \n  1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, \n  1001, 1001, 1001, 1001, 1001, 1001, 1001, 9624, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  76, 265, 266, 615, 267, 616, 617, 1002, \n  268, 618, 619, 1003, 620, 1004, 1005, 9623, \n  269, 621, 622, 1006, 623, 1007, 1008, 1008, \n  624, 1009, 1010, 1010, 1011, 1011, 1011, 9624, \n  270, 625, 626, 1012, 627, 1013, 1014, 1014, \n  628, 1015, 1016, 1016, 1017, 1017, 1017, 9623, \n  629, 1018, 1019, 1019, 1020, 1020, 1020, 1020, \n  1021, 1021, 1021, 1021, 1021, 1021, 9625, 9625, \n  271, 630, 631, 1022, 632, 1023, 1024, 1024, \n  633, 1025, 1026, 1026, 1027, 1027, 1027, 9623, \n  634, 1028, 1029, 1029, 1030, 1030, 1030, 1030, \n  1031, 1031, 1031, 1031, 1031, 1031, 1031, 9624, \n  635, 1032, 1033, 1033, 1034, 1034, 1034, 1034, \n  1035, 1035, 1035, 1035, 1035, 1035, 1035, 9623, \n  1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, \n  1036, 1036, 1036, 1036, 9626, 9626, 9626, 9626, \n  272, 636, 637, 1037, 638, 1038, 1039, 1039, \n  639, 1040, 1041, 1041, 1042, 1042, 1042, 9623, \n  640, 1043, 1044, 1044, 1045, 1045, 1045, 1045, \n  1046, 1046, 1046, 1046, 1046, 1046, 1046, 9624, \n  641, 1047, 1048, 1048, 1049, 1049, 1049, 1049, \n  1050, 1050, 1050, 1050, 1050, 1050, 1050, 9623, \n  1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, \n  1051, 1051, 1051, 1051, 1051, 1051, 9625, 9625, \n  642, 1052, 1053, 1053, 1054, 1054, 1054, 1054, \n  1055, 1055, 1055, 1055, 1055, 1055, 1055, 9623, \n  1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, \n  1056, 1056, 1056, 1056, 1056, 1056, 1056, 9624, \n  1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, \n  1057, 1057, 1057, 1057, 1057, 1057, 1057, 9623, \n  1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  273, 643, 644, 1058, 645, 1059, 1060, 1060, \n  646, 1061, 1062, 1062, 1063, 1063, 1063, 9623, \n  647, 1064, 1065, 1065, 1066, 1066, 1066, 1066, \n  1067, 1067, 1067, 1067, 1067, 1067, 1067, 9624, \n  648, 1068, 1069, 1069, 1070, 1070, 1070, 1070, \n  1071, 1071, 1071, 1071, 1071, 1071, 1071, 9623, \n  1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, \n  1072, 1072, 1072, 1072, 1072, 1072, 9625, 9625, \n  649, 1073, 1074, 1074, 1075, 1075, 1075, 1075, \n  1076, 1076, 1076, 1076, 1076, 1076, 1076, 9623, \n  1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, \n  1077, 1077, 1077, 1077, 1077, 1077, 1077, 9624, \n  1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, \n  1078, 1078, 1078, 1078, 1078, 1078, 1078, 9623, \n  1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, \n  1078, 1078, 1078, 1078, 9626, 9626, 9626, 9626, \n  650, 1079, 1080, 1080, 1081, 1081, 1081, 1081, \n  1082, 1082, 1082, 1082, 1082, 1082, 1082, 9623, \n  1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, \n  1083, 1083, 1083, 1083, 1083, 1083, 1083, 9624, \n  1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, \n  1084, 1084, 1084, 1084, 1084, 1084, 1084, 9623, \n  1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, \n  1084, 1084, 1084, 1084, 1084, 1084, 9625, 9625, \n  1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085, \n  1085, 1085, 1085, 1085, 1085, 1085, 1085, 9623, \n  1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085, \n  1085, 1085, 1085, 1085, 1085, 1085, 1085, 9624, \n  1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085, \n  1085, 1085, 1085, 1085, 1085, 1085, 1085, 9623, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  274, 651, 652, 1086, 653, 1087, 1088, 1088, \n  654, 1089, 1090, 1090, 1091, 1091, 1091, 9623, \n  655, 1092, 1093, 1093, 1094, 1094, 1094, 1094, \n  1095, 1095, 1095, 1095, 1095, 1095, 1095, 9624, \n  656, 1096, 1097, 1097, 1098, 1098, 1098, 1098, \n  1099, 1099, 1099, 1099, 1099, 1099, 1099, 9623, \n  1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, \n  1100, 1100, 1100, 1100, 1100, 1100, 9625, 9625, \n  657, 1101, 1102, 1102, 1103, 1103, 1103, 1103, \n  1104, 1104, 1104, 1104, 1104, 1104, 1104, 9623, \n  1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, \n  1105, 1105, 1105, 1105, 1105, 1105, 1105, 9624, \n  1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, \n  1106, 1106, 1106, 1106, 1106, 1106, 1106, 9623, \n  1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, \n  1106, 1106, 1106, 1106, 9626, 9626, 9626, 9626, \n  658, 1107, 1108, 1108, 1109, 1109, 1109, 1109, \n  1110, 1110, 1110, 1110, 1110, 1110, 1110, 9623, \n  1111, 1111, 1111, 1111, 1111, 1111, 1111, 1111, \n  1111, 1111, 1111, 1111, 1111, 1111, 1111, 9624, \n  1112, 1112, 1112, 1112, 1112, 1112, 1112, 1112, \n  1112, 1112, 1112, 1112, 1112, 1112, 1112, 9623, \n  1112, 1112, 1112, 1112, 1112, 1112, 1112, 1112, \n  1112, 1112, 1112, 1112, 1112, 1112, 9625, 9625, \n  1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, \n  1113, 1113, 1113, 1113, 1113, 1113, 1113, 9623, \n  1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, \n  1113, 1113, 1113, 1113, 1113, 1113, 1113, 9624, \n  1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, \n  1113, 1113, 1113, 1113, 1113, 1113, 1113, 9623, \n  1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  659, 1114, 1115, 1115, 1116, 1116, 1116, 1116, \n  1117, 1117, 1117, 1117, 1117, 1117, 1117, 9623, \n  1118, 1118, 1118, 1118, 1118, 1118, 1118, 1118, \n  1118, 1118, 1118, 1118, 1118, 1118, 1118, 9624, \n  1119, 1119, 1119, 1119, 1119, 1119, 1119, 1119, \n  1119, 1119, 1119, 1119, 1119, 1119, 1119, 9623, \n  1119, 1119, 1119, 1119, 1119, 1119, 1119, 1119, \n  1119, 1119, 1119, 1119, 1119, 1119, 9625, 9625, \n  1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, \n  1120, 1120, 1120, 1120, 1120, 1120, 1120, 9623, \n  1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, \n  1120, 1120, 1120, 1120, 1120, 1120, 1120, 9624, \n  1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, \n  1120, 1120, 1120, 1120, 1120, 1120, 1120, 9623, \n  1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, \n  1120, 1120, 1120, 1120, 9626, 9626, 9626, 9626, \n  1121, 1121, 1121, 1121, 1121, 1121, 1121, 1121, \n  1121, 1121, 1121, 1121, 1121, 1121, 1121, 9623, \n  1121, 1121, 1121, 1121, 1121, 1121, 1121, 1121, \n  1121, 1121, 1121, 1121, 1121, 1121, 1121, 9624, \n  1121, 1121, 1121, 1121, 1121, 1121, 1121, 1121, \n  1121, 1121, 1121, 1121, 1121, 1121, 1121, 9623, \n  1121, 1121, 1121, 1121, 1121, 1121, 1121, 1121, \n  1121, 1121, 1121, 1121, 1121, 1121, 9625, 9625, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  9630, 9630, 9630, 9630, 9630, 9630, 9630, 9630, \n  77, 275, 276, 660, 277, 661, 662, 1122, \n  278, 663, 664, 1123, 665, 1124, 1125, 9623, \n  279, 666, 667, 1126, 668, 1127, 1128, 1128, \n  669, 1129, 1130, 1130, 1131, 1131, 1131, 9624, \n  280, 670, 671, 1132, 672, 1133, 1134, 1134, \n  673, 1135, 1136, 1136, 1137, 1137, 1137, 9623, \n  674, 1138, 1139, 1139, 1140, 1140, 1140, 1140, \n  1141, 1141, 1141, 1141, 1141, 1141, 9625, 9625, \n  281, 675, 676, 1142, 677, 1143, 1144, 1144, \n  678, 1145, 1146, 1146, 1147, 1147, 1147, 9623, \n  679, 1148, 1149, 1149, 1150, 1150, 1150, 1150, \n  1151, 1151, 1151, 1151, 1151, 1151, 1151, 9624, \n  680, 1152, 1153, 1153, 1154, 1154, 1154, 1154, \n  1155, 1155, 1155, 1155, 1155, 1155, 1155, 9623, \n  1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, \n  1156, 1156, 1156, 1156, 9626, 9626, 9626, 9626, \n  282, 681, 682, 1157, 683, 1158, 1159, 1159, \n  684, 1160, 1161, 1161, 1162, 1162, 1162, 9623, \n  685, 1163, 1164, 1164, 1165, 1165, 1165, 1165, \n  1166, 1166, 1166, 1166, 1166, 1166, 1166, 9624, \n  686, 1167, 1168, 1168, 1169, 1169, 1169, 1169, \n  1170, 1170, 1170, 1170, 1170, 1170, 1170, 9623, \n  1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, \n  1171, 1171, 1171, 1171, 1171, 1171, 9625, 9625, \n  687, 1172, 1173, 1173, 1174, 1174, 1174, 1174, \n  1175, 1175, 1175, 1175, 1175, 1175, 1175, 9623, \n  1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, \n  1176, 1176, 1176, 1176, 1176, 1176, 1176, 9624, \n  1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, \n  1177, 1177, 1177, 1177, 1177, 1177, 1177, 9623, \n  1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  283, 688, 689, 1178, 690, 1179, 1180, 1180, \n  691, 1181, 1182, 1182, 1183, 1183, 1183, 9623, \n  692, 1184, 1185, 1185, 1186, 1186, 1186, 1186, \n  1187, 1187, 1187, 1187, 1187, 1187, 1187, 9624, \n  693, 1188, 1189, 1189, 1190, 1190, 1190, 1190, \n  1191, 1191, 1191, 1191, 1191, 1191, 1191, 9623, \n  1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, \n  1192, 1192, 1192, 1192, 1192, 1192, 9625, 9625, \n  694, 1193, 1194, 1194, 1195, 1195, 1195, 1195, \n  1196, 1196, 1196, 1196, 1196, 1196, 1196, 9623, \n  1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, \n  1197, 1197, 1197, 1197, 1197, 1197, 1197, 9624, \n  1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, \n  1198, 1198, 1198, 1198, 1198, 1198, 1198, 9623, \n  1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, \n  1198, 1198, 1198, 1198, 9626, 9626, 9626, 9626, \n  695, 1199, 1200, 1200, 1201, 1201, 1201, 1201, \n  1202, 1202, 1202, 1202, 1202, 1202, 1202, 9623, \n  1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, \n  1203, 1203, 1203, 1203, 1203, 1203, 1203, 9624, \n  1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, \n  1204, 1204, 1204, 1204, 1204, 1204, 1204, 9623, \n  1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, \n  1204, 1204, 1204, 1204, 1204, 1204, 9625, 9625, \n  1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, \n  1205, 1205, 1205, 1205, 1205, 1205, 1205, 9623, \n  1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, \n  1205, 1205, 1205, 1205, 1205, 1205, 1205, 9624, \n  1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, \n  1205, 1205, 1205, 1205, 1205, 1205, 1205, 9623, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  284, 696, 697, 1206, 698, 1207, 1208, 1208, \n  699, 1209, 1210, 1210, 1211, 1211, 1211, 9623, \n  700, 1212, 1213, 1213, 1214, 1214, 1214, 1214, \n  1215, 1215, 1215, 1215, 1215, 1215, 1215, 9624, \n  701, 1216, 1217, 1217, 1218, 1218, 1218, 1218, \n  1219, 1219, 1219, 1219, 1219, 1219, 1219, 9623, \n  1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, \n  1220, 1220, 1220, 1220, 1220, 1220, 9625, 9625, \n  702, 1221, 1222, 1222, 1223, 1223, 1223, 1223, \n  1224, 1224, 1224, 1224, 1224, 1224, 1224, 9623, \n  1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, \n  1225, 1225, 1225, 1225, 1225, 1225, 1225, 9624, \n  1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, \n  1226, 1226, 1226, 1226, 1226, 1226, 1226, 9623, \n  1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, \n  1226, 1226, 1226, 1226, 9626, 9626, 9626, 9626, \n  703, 1227, 1228, 1228, 1229, 1229, 1229, 1229, \n  1230, 1230, 1230, 1230, 1230, 1230, 1230, 9623, \n  1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, \n  1231, 1231, 1231, 1231, 1231, 1231, 1231, 9624, \n  1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, \n  1232, 1232, 1232, 1232, 1232, 1232, 1232, 9623, \n  1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, \n  1232, 1232, 1232, 1232, 1232, 1232, 9625, 9625, \n  1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, \n  1233, 1233, 1233, 1233, 1233, 1233, 1233, 9623, \n  1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, \n  1233, 1233, 1233, 1233, 1233, 1233, 1233, 9624, \n  1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, \n  1233, 1233, 1233, 1233, 1233, 1233, 1233, 9623, \n  1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  704, 1234, 1235, 1235, 1236, 1236, 1236, 1236, \n  1237, 1237, 1237, 1237, 1237, 1237, 1237, 9623, \n  1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, \n  1238, 1238, 1238, 1238, 1238, 1238, 1238, 9624, \n  1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, \n  1239, 1239, 1239, 1239, 1239, 1239, 1239, 9623, \n  1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, \n  1239, 1239, 1239, 1239, 1239, 1239, 9625, 9625, \n  1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, \n  1240, 1240, 1240, 1240, 1240, 1240, 1240, 9623, \n  1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, \n  1240, 1240, 1240, 1240, 1240, 1240, 1240, 9624, \n  1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, \n  1240, 1240, 1240, 1240, 1240, 1240, 1240, 9623, \n  1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, \n  1240, 1240, 1240, 1240, 9626, 9626, 9626, 9626, \n  1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, \n  1241, 1241, 1241, 1241, 1241, 1241, 1241, 9623, \n  1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, \n  1241, 1241, 1241, 1241, 1241, 1241, 1241, 9624, \n  1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, \n  1241, 1241, 1241, 1241, 1241, 1241, 1241, 9623, \n  1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, \n  1241, 1241, 1241, 1241, 1241, 1241, 9625, 9625, \n  1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, \n  1241, 1241, 1241, 1241, 1241, 1241, 1241, 9623, \n  1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, \n  1241, 1241, 1241, 1241, 1241, 1241, 1241, 9624, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  9629, 9629, 9629, 9629, 9629, 9629, 9629, 9629, \n  285, 705, 706, 1242, 707, 1243, 1244, 1244, \n  708, 1245, 1246, 1246, 1247, 1247, 1247, 9623, \n  709, 1248, 1249, 1249, 1250, 1250, 1250, 1250, \n  1251, 1251, 1251, 1251, 1251, 1251, 1251, 9624, \n  710, 1252, 1253, 1253, 1254, 1254, 1254, 1254, \n  1255, 1255, 1255, 1255, 1255, 1255, 1255, 9623, \n  1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, \n  1256, 1256, 1256, 1256, 1256, 1256, 9625, 9625, \n  711, 1257, 1258, 1258, 1259, 1259, 1259, 1259, \n  1260, 1260, 1260, 1260, 1260, 1260, 1260, 9623, \n  1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, \n  1261, 1261, 1261, 1261, 1261, 1261, 1261, 9624, \n  1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, \n  1262, 1262, 1262, 1262, 1262, 1262, 1262, 9623, \n  1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, \n  1262, 1262, 1262, 1262, 9626, 9626, 9626, 9626, \n  712, 1263, 1264, 1264, 1265, 1265, 1265, 1265, \n  1266, 1266, 1266, 1266, 1266, 1266, 1266, 9623, \n  1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, \n  1267, 1267, 1267, 1267, 1267, 1267, 1267, 9624, \n  1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, \n  1268, 1268, 1268, 1268, 1268, 1268, 1268, 9623, \n  1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, \n  1268, 1268, 1268, 1268, 1268, 1268, 9625, 9625, \n  1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, \n  1269, 1269, 1269, 1269, 1269, 1269, 1269, 9623, \n  1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, \n  1269, 1269, 1269, 1269, 1269, 1269, 1269, 9624, \n  1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, \n  1269, 1269, 1269, 1269, 1269, 1269, 1269, 9623, \n  1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  713, 1270, 1271, 1271, 1272, 1272, 1272, 1272, \n  1273, 1273, 1273, 1273, 1273, 1273, 1273, 9623, \n  1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, \n  1274, 1274, 1274, 1274, 1274, 1274, 1274, 9624, \n  1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, \n  1275, 1275, 1275, 1275, 1275, 1275, 1275, 9623, \n  1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, \n  1275, 1275, 1275, 1275, 1275, 1275, 9625, 9625, \n  1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, \n  1276, 1276, 1276, 1276, 1276, 1276, 1276, 9623, \n  1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, \n  1276, 1276, 1276, 1276, 1276, 1276, 1276, 9624, \n  1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, \n  1276, 1276, 1276, 1276, 1276, 1276, 1276, 9623, \n  1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, \n  1276, 1276, 1276, 1276, 9626, 9626, 9626, 9626, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 9623, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 9624, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 9623, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, \n  1277, 1277, 1277, 1277, 1277, 1277, 9625, 9625, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 9623, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 9624, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, \n  1277, 1277, 1277, 1277, 1277, 1277, 1277, 9623, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  9628, 9628, 9628, 9628, 9628, 9628, 9628, 9628, \n  714, 1278, 1279, 1279, 1280, 1280, 1280, 1280, \n  1281, 1281, 1281, 1281, 1281, 1281, 1281, 9623, \n  1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, \n  1282, 1282, 1282, 1282, 1282, 1282, 1282, 9624, \n  1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, \n  1283, 1283, 1283, 1283, 1283, 1283, 1283, 9623, \n  1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, \n  1283, 1283, 1283, 1283, 1283, 1283, 9625, 9625, \n  1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, \n  1284, 1284, 1284, 1284, 1284, 1284, 1284, 9623, \n  1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, \n  1284, 1284, 1284, 1284, 1284, 1284, 1284, 9624, \n  1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, \n  1284, 1284, 1284, 1284, 1284, 1284, 1284, 9623, \n  1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, \n  1284, 1284, 1284, 1284, 9626, 9626, 9626, 9626, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 9623, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 9624, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 9623, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, \n  1285, 1285, 1285, 1285, 1285, 1285, 9625, 9625, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 9623, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 9624, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 9623, \n  1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, \n  9627, 9627, 9627, 9627, 9627, 9627, 9627, 9627, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632, \n  9632, 9632, 9632, 9632, 9632, 9632, 9632, 9632 };\n\nstatic const uint8_t topBit[ 8192 ] = {\n  0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, \n  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, \n  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, \n  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, \n  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, \n  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, \n  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, \n  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, \n  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, \n  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, \n  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, \n  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, \n  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, \n  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, \n  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, \n  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, \n  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 };\n\nstatic const uint8_t tripsOtherVal[ 8192 ] = {\n  0, 0, 1, 0, 2, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 5, \n  4, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, \n  5, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, \n  14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, \n  6, 15, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, \n  19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, \n  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, \n  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, \n  7, 21, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, \n  25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, \n  26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, \n  26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, \n  27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, \n  27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, \n  27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, \n  27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, \n  8, 28, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, \n  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, \n  33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, \n  33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, \n  34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, \n  34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, \n  34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, \n  34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, \n  35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, \n  35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, \n  35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, \n  35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, \n  35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, \n  35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, \n  35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, \n  35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, \n  9, 36, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, \n  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, \n  41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, \n  41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, \n  42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, \n  42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, \n  42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, \n  42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, \n  43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, \n  43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, \n  43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, \n  43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, \n  43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, \n  43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, \n  43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, \n  43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, \n  10, 45, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, \n  49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, \n  50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, \n  50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, \n  51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, \n  51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, \n  51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, \n  51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, \n  52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, \n  52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, \n  52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, \n  52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, \n  52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, \n  52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, \n  52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, \n  52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, \n  11, 55, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 58, 58, \n  59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, \n  60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, \n  60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, \n  61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, \n  61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, \n  61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, \n  61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, \n  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, \n  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, \n  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, \n  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, \n  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, \n  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, \n  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, \n  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, \n  12, 66, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 69, \n  70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, \n  71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, \n  71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, \n  72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, \n  72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, \n  72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, \n  72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, \n  73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, \n  73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, \n  73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, \n  73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, \n  73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, \n  73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, \n  73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, \n  73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, \n  77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 };\n\nstatic const uint16_t quadsVal[ 13 ] = {\n  11934, 11947, 11960, 11973, 11986, 11999, 12012,\n  12025, 12038, 12051, 12064, 12077, 12090  };\n\nstatic const uint16_t tripsVal[ 13 ] = {\n  8606, 8684, 8762, 8840, 8918, 8996, 9074,\n  9152, 9230, 9308, 9386, 9464, 9542 };\n\nstatic const uint16_t fullHouseOtherVal\n= HANDCLASS_FULL_HOUSE - HANDCLASS_TRIPS;\n\nstatic const uint16_t pairsVal[ 13 ] = {\n  1287, 1573, 1859, 2145, 2431, 2717, 3003,\n  3289, 3575, 3861, 4147, 4433, 4719 };\n\nstatic const uint16_t twoPairOtherVal[ 13 ] = {\n  3718, 3731, 3744, 3757, 3770, 3783, 3796,\n  3809, 3822, 3835, 3848, 3861, 3874 };\n\nstatic int rankCardset( const Cardset cards )\n{\n  int postponed, r;\n  Cardset sets;\n\n  postponed = oneSuitVal[ cards.bySuit[ 0 ] ];\n  if( oneSuitVal[ cards.bySuit[ 1 ] ] > postponed ) {\n    postponed = oneSuitVal[ cards.bySuit[ 1 ] ];\n  }\n  if( oneSuitVal[ cards.bySuit[ 2 ] ] > postponed ) {\n    postponed = oneSuitVal[ cards.bySuit[ 2 ] ];\n  }\n  if( oneSuitVal[ cards.bySuit[ 3 ] ] > postponed ) {\n    postponed = oneSuitVal[ cards.bySuit[ 3 ] ];\n  }\n  if( postponed >= HANDCLASS_STRAIGHT_FLUSH ) {\n    /* straight flush */\n\n    return postponed;\n  }\n\n  sets.bySuit[ 0 ] = cards.bySuit[ 0 ] | cards.bySuit[ 1 ];\n  sets.bySuit[ 1 ] = cards.bySuit[ 0 ] & cards.bySuit[ 1 ];\n  sets.bySuit[ 2 ] = sets.bySuit[ 1 ] & cards.bySuit[ 2 ];\n  sets.bySuit[ 1 ] |= sets.bySuit[ 0 ] & cards.bySuit[ 2 ];\n  sets.bySuit[ 0 ] |= cards.bySuit[ 2 ];\n  sets.bySuit[ 3 ] = sets.bySuit[ 2 ] & cards.bySuit[ 3 ];\n  sets.bySuit[ 2 ] |= sets.bySuit[ 1 ] & cards.bySuit[ 3 ];\n  sets.bySuit[ 1 ] |= sets.bySuit[ 0 ] & cards.bySuit[ 3 ];\n  sets.bySuit[ 0 ] |= cards.bySuit[ 3 ];\n\n  if( sets.bySuit[ 3 ] ) {\n    /* quads */\n\n    r = topBit[ sets.bySuit[ 3 ] ];\n    return quadsVal[ r ] + topBit[ sets.bySuit[ 0 ] ^ ( 1 << r ) ];\n  }\n\n  if( sets.bySuit[ 2 ] ) {\n    /* trips or full house */\n\n    r = topBit[ sets.bySuit[ 2 ] ];\n    sets.bySuit[ 1 ] ^= ( 1 << r );\n    if( sets.bySuit[ 1 ] ) {\n      /* full house */\n\n      return tripsVal[ r ] + fullHouseOtherVal\n\t+ topBit[ sets.bySuit[ 1 ] ];\n    }\n\n    if( postponed ) {\n      /* flush */\n\n      return postponed;\n    }\n\n    postponed = anySuitVal[ sets.bySuit[ 0 ] ];\n    if( postponed >= HANDCLASS_STRAIGHT ) {\n      /* straight */\n\n      return postponed;\n    }\n\n    /* trips */\n    sets.bySuit[ 0 ] ^= ( 1 << r );\n    return tripsVal[ r ] + tripsOtherVal[ sets.bySuit[ 0 ] ];\n  } else {\n\n    if( postponed ) {\n      /* flush */\n\n      return postponed;\n    }\n\n    postponed = anySuitVal[ sets.bySuit[ 0 ] ];\n    if( postponed >= HANDCLASS_STRAIGHT ) {\n      /* straight */\n\n      return postponed;\n    }\n  }\n\n  if( sets.bySuit[ 1 ] ) {\n    /* pair or two pair */\n\n    r = topBit[ sets.bySuit[ 1 ] ];\n    sets.bySuit[ 0 ] ^= ( 1 << r );\n    sets.bySuit[ 1 ] ^= ( 1 << r );\n    if( sets.bySuit[ 1 ] ) {\n      /* two pair */\n\n      sets.bySuit[ 0 ] ^= ( 1 << topBit[ sets.bySuit[ 1 ] ] );\n      return pairsVal[ r ]\n\t+ twoPairOtherVal[ topBit[ sets.bySuit[ 1 ] ] ]\n\t+ topBit[ sets.bySuit[ 0 ] ];\n    }\n\n    return pairsVal[ r ] + pairOtherVal[ sets.bySuit[ 0 ] ];\n  }\n\n  return postponed;\n}\n\nstatic Cardset emptyCardset()\n{\n  Cardset c;\n\n  c.cards = 0;\n\n  return c;\n}\n\nstatic void addCardToCardset( Cardset *c, int suit, int rank )\n{\n  c->cards |= (uint64_t)1 << ( ( suit << 4 ) + rank );\n}\n"
  },
  {
    "path": "ACPCServer/example_player.c",
    "content": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <assert.h>\n#include <string.h>\n#include <unistd.h>\n#include <netdb.h>\n#include <sys/socket.h>\n#include <sys/time.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include <getopt.h>\n#include \"game.h\"\n#include \"rng.h\"\n#include \"net.h\"\n\nint main( int argc, char **argv )\n{\n  int sock, len, r, a;\n  int32_t min, max;\n  uint16_t port;\n  double p;\n  Game *game;\n  MatchState state;\n  Action action;\n  FILE *file, *toServer, *fromServer;\n  struct timeval tv;\n  double probs[ NUM_ACTION_TYPES ];\n  double actionProbs[ NUM_ACTION_TYPES ];\n  rng_state_t rng;\n  char line[ MAX_LINE_LEN ];\n\n  /* we make some assumptions about the actions - check them here */\n  assert( NUM_ACTION_TYPES == 3 );\n\n  if( argc < 4 ) {\n\n    fprintf( stderr, \"usage: player game server port\\n\" );\n    exit( EXIT_FAILURE );\n  }\n\n  /* Define the probabilities of actions for the player */\n  probs[ a_fold ] = 0.06;\n  probs[ a_call ] = ( 1.0 - probs[ a_fold ] ) * 0.5;\n  probs[ a_raise ] = ( 1.0 - probs[ a_fold ] ) * 0.5;\n\n  /* Initialize the player's random number state using time */\n  gettimeofday( &tv, NULL );\n  init_genrand( &rng, tv.tv_usec );\n\n  /* get the game */\n  file = fopen( argv[ 1 ], \"r\" );\n  if( file == NULL ) {\n\n    fprintf( stderr, \"ERROR: could not open game %s\\n\", argv[ 1 ] );\n    exit( EXIT_FAILURE );\n  }\n  game = readGame( file );\n  if( game == NULL ) {\n\n    fprintf( stderr, \"ERROR: could not read game %s\\n\", argv[ 1 ] );\n    exit( EXIT_FAILURE );\n  }\n  fclose( file );\n\n  /* connect to the dealer */\n  if( sscanf( argv[ 3 ], \"%\"SCNu16, &port ) < 1 ) {\n\n    fprintf( stderr, \"ERROR: invalid port %s\\n\", argv[ 3 ] );\n    exit( EXIT_FAILURE );\n  }\n  sock = connectTo( argv[ 2 ], port );\n  if( sock < 0 ) {\n\n    exit( EXIT_FAILURE );\n  }\n  toServer = fdopen( sock, \"w\" );\n  fromServer = fdopen( sock, \"r\" );\n  if( toServer == NULL || fromServer == NULL ) {\n\n    fprintf( stderr, \"ERROR: could not get socket streams\\n\" );\n    exit( EXIT_FAILURE );\n  }\n\n  /* send version string to dealer */\n  if( fprintf( toServer, \"VERSION:%\"PRIu32\".%\"PRIu32\".%\"PRIu32\"\\n\",\n\t       VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION ) != 14 ) {\n\n    fprintf( stderr, \"ERROR: could not get send version to server\\n\" );\n    exit( EXIT_FAILURE );\n  }\n  fflush( toServer );\n\n  /* play the game! */\n  while( fgets( line, MAX_LINE_LEN, fromServer ) ) {\n\n    /* ignore comments */\n    if( line[ 0 ] == '#' || line[ 0 ] == ';' ) {\n      continue;\n    }\n\n    len = readMatchState( line, game, &state );\n    if( len < 0 ) {\n\n      fprintf( stderr, \"ERROR: could not read state %s\", line );\n      exit( EXIT_FAILURE );\n    }\n\n    if( stateFinished( &state.state ) ) {\n      /* ignore the game over message */\n\n      continue;\n    }\n\n    if( currentPlayer( game, &state.state ) != state.viewingPlayer ) {\n      /* we're not acting */\n\n      continue;\n    }\n\n    /* add a colon (guaranteed to fit because we read a new-line in fgets) */\n    line[ len ] = ':';\n    ++len;\n\n    /* build the set of valid actions */\n    p = 0;\n    for( a = 0; a < NUM_ACTION_TYPES; ++a ) {\n\n      actionProbs[ a ] = 0.0;\n    }\n\n    /* consider fold */\n    action.type = a_fold;\n    action.size = 0;\n    if( isValidAction( game, &state.state, 0, &action ) ) {\n\n      actionProbs[ a_fold ] = probs[ a_fold ];\n      p += probs[ a_fold ];\n    }\n\n    /* consider call */\n    action.type = a_call;\n    action.size = 0;\n    actionProbs[ a_call ] = probs[ a_call ];\n    p += probs[ a_call ];\n\n    /* consider raise */\n    if( raiseIsValid( game, &state.state, &min, &max ) ) {\n\n      actionProbs[ a_raise ] = probs[ a_raise ];\n      p += probs[ a_raise ];\n    }\n\n    /* normalise the probabilities  */\n    assert( p > 0.0 );\n    for( a = 0; a < NUM_ACTION_TYPES; ++a ) {\n\n      actionProbs[ a ] /= p;\n    }\n\n    /* choose one of the valid actions at random */\n    p = genrand_real2( &rng );\n    for( a = 0; a < NUM_ACTION_TYPES - 1; ++a ) {\n\n      if( p <= actionProbs[ a ] ) {\n\n        break;\n      }\n      p -= actionProbs[ a ];\n    }\n    action.type = (enum ActionType)a;\n    if( a == a_raise ) {\n\n      action.size = min + genrand_int32( &rng ) % ( max - min + 1 );\n    }\n\n    /* do the action! */\n    assert( isValidAction( game, &state.state, 0, &action ) );\n    r = printAction( game, &action, MAX_LINE_LEN - len - 2,\n\t\t     &line[ len ] );\n    if( r < 0 ) {\n\n      fprintf( stderr, \"ERROR: line too long after printing action\\n\" );\n      exit( EXIT_FAILURE );\n    }\n    len += r;\n    line[ len ] = '\\r';\n    ++len;\n    line[ len ] = '\\n';\n    ++len;\n\n    if( fwrite( line, 1, len, toServer ) != len ) {\n\n      fprintf( stderr, \"ERROR: could not get send response to server\\n\" );\n      exit( EXIT_FAILURE );\n    }\n    fflush( toServer );\n  }\n\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "ACPCServer/example_player.kuhn.limit.3p.sh",
    "content": "#!/bin/bash\n./example_player kuhn.limit.3p.game $1 $2\n"
  },
  {
    "path": "ACPCServer/example_player.limit.2p.sh",
    "content": "#!/bin/bash\n./example_player holdem.limit.2p.reverse_blinds.game $1 $2\n"
  },
  {
    "path": "ACPCServer/example_player.limit.3p.sh",
    "content": "#!/bin/bash\n./example_player holdem.limit.3p.game $1 $2\n"
  },
  {
    "path": "ACPCServer/example_player.nolimit.2p.sh",
    "content": "#!/bin/bash\n./example_player holdem.nolimit.2p.reverse_blinds.game $1 $2\n"
  },
  {
    "path": "ACPCServer/example_player.nolimit.3p.sh",
    "content": "#!/bin/bash\n./example_player holdem.nolimit.3p.game $1 $2\n"
  },
  {
    "path": "ACPCServer/game.c",
    "content": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n#include <assert.h>\n#define __STDC_LIMIT_MACROS\n#include <stdint.h>\n#include \"game.h\"\n#include \"rng.h\"\n\n#include \"evalHandTables\"\n\n\nstatic enum ActionType charToAction[ 256 ] = {\n  /* 0x0X */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0x1X */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0x2X */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0x3X */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0x4X */\n  a_invalid, a_invalid, a_raise, a_call,\n  a_invalid, a_invalid, a_fold, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_call,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0x5X */\n  a_invalid, a_invalid, a_raise, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0x6X */\n  a_invalid, a_invalid, a_raise, a_call,\n  a_invalid, a_invalid, a_fold, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_call,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0x7X */\n  a_invalid, a_invalid, a_raise, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0x8X */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0x9X */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0xAX */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0xBX */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0xCX */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0xDX */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0xEX */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  /* 0xFX */\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid,\n  a_invalid, a_invalid, a_invalid, a_invalid\n};\n\nstatic char actionChars[ a_invalid + 1 ] = \"fcr\";\n\nstatic char suitChars[ MAX_SUITS + 1 ] = \"cdhs\";\nstatic char rankChars[ MAX_RANKS + 1 ] = \"23456789TJQKA\";\n\n\nstatic int consumeSpaces( const char *string, int consumeEqual )\n{\n  int i;\n\n  for( i = 0; string[ i ] != 0\n\t && ( isspace( string[ i ] )\n\t      || ( consumeEqual && string[ i ] == '=' ) );\n       ++i ) {\n  }\n\n  return i;\n}\n\n/* reads up to numItems with scanf format itemFormat from string,\n   returning item i in *items[ i ]\n   ignore the '=' character if consumeEqual is non-zero\n   returns the number of characters consumed doing this in charsConsumed\n   returns the number of items read */\nstatic int readItems( const char *itemFormat, const int numItems,\n\t\t      const char *string, const int consumeEqual,\n\t\t      void *items, const size_t itemSize,\n\t\t      int *charsConsumed )\n{\n  int i, c, r;\n  char *fmt;\n\n  i = strlen( itemFormat );\n  fmt = (char*)malloc( i + 3 );\n  assert( fmt != 0 );\n  strcpy( fmt, itemFormat );\n  fmt[ i ] = '%';\n  fmt[ i + 1 ] = 'n';\n  fmt[ i + 2 ] = 0;\n\n  c = 0;\n  for( i = 0; i < numItems; ++i ) {\n\n    c += consumeSpaces( &string[ c ], consumeEqual );\n    if( sscanf( &string[ c ], fmt, items + i * itemSize, &r ) < 1 ) {\n      break;\n    }\n    c += r;\n  }\n\n  free( fmt );\n\n  *charsConsumed = c;\n  return i;\n}\n\nGame *readGame( FILE *file )\n{\n  int stackRead, blindRead, raiseSizeRead, boardCardsRead, c, t;\n  char line[ MAX_LINE_LEN ];\n  Game *game;\n\n  game = (Game*)malloc( sizeof( *game ) );\n  assert( game != 0 );\n  stackRead = 4;\n  for( c = 0; c < MAX_ROUNDS; ++c ) {\n    game->stack[ c ] = INT32_MAX;\n  }\n  blindRead = 0;\n  raiseSizeRead = 0;\n  game->bettingType = limitBetting;\n  game->numPlayers = 0;\n  game->numRounds = 0;\n  for( c = 0; c < MAX_ROUNDS; ++c ) {\n    game->firstPlayer[ c ] = 1;\n  }\n  for( c = 0; c < MAX_ROUNDS; ++c ) {\n    game->maxRaises[ c ] = UINT8_MAX;\n  }\n  game->numSuits = 0;\n  game->numRanks = 0;\n  game->numHoleCards = 0;\n  boardCardsRead = 0;\n\n  while( fgets( line, MAX_LINE_LEN, file ) ) {\n\n    if( line[ 0 ] == '#' || line[ 0 ] == '\\n' ) {\n      continue;\n    }\n\n    if( !strncasecmp( line, \"end gamedef\", 11 ) ) {\n\n      break;\n    } else if( !strncasecmp( line, \"gamedef\", 7 ) ) {\n\n      continue;\n    } else if( !strncasecmp( line, \"stack\", 5 ) ) {\n\n      stackRead = readItems( \"%\"SCNd32, MAX_PLAYERS, &line[ 5 ],\n\t\t\t\t 1, game->stack, 4, &c );\n    } else if( !strncasecmp( line, \"blind\", 5 ) ) {\n\n      blindRead = readItems( \"%\"SCNd32, MAX_PLAYERS, &line[ 5 ],\n\t\t\t     1, game->blind, 4, &c );\n    } else if( !strncasecmp( line, \"raisesize\", 9 ) ) {\n\n      raiseSizeRead = readItems( \"%\"SCNd32, MAX_PLAYERS, &line[ 9 ],\n\t\t\t\t 1, game->raiseSize, 4, &c );\n    } else if( !strncasecmp( line, \"limit\", 5 ) ) {\n\n      game->bettingType = limitBetting;\n    } else if( !strncasecmp( line, \"nolimit\", 7 ) ) {\n\n      game->bettingType = noLimitBetting;\n    } else if( !strncasecmp( line, \"numplayers\", 10 ) ) {\n\n      readItems( \"%\"SCNu8, 1, &line[ 10 ], 1, &game->numPlayers, 1, &c );\n    } else if( !strncasecmp( line, \"numrounds\", 9 ) ) {\n\n      readItems( \"%\"SCNu8, 1, &line[ 9 ], 1, &game->numRounds, 1, &c );\n    } else if( !strncasecmp( line, \"firstplayer\", 11 ) ) {\n\n      readItems( \"%\"SCNu8, MAX_ROUNDS, &line[ 11 ],\n\t\t 1, game->firstPlayer, 1, &c );\n    } else if( !strncasecmp( line, \"maxraises\", 9 ) ) {\n\n      readItems( \"%\"SCNu8, MAX_ROUNDS, &line[ 9 ],\n\t\t 1, game->maxRaises, 1, &c );\n    } else if( !strncasecmp( line, \"numsuits\", 8 ) ) {\n\n      readItems( \"%\"SCNu8, 1, &line[ 8 ], 1, &game->numSuits, 1, &c );\n    } else if( !strncasecmp( line, \"numranks\", 8 ) ) {\n\n      readItems( \"%\"SCNu8, 1, &line[ 8 ], 1, &game->numRanks, 1, &c );\n    } else if( !strncasecmp( line, \"numholecards\", 12 ) ) {\n\n      readItems( \"%\"SCNu8, 1, &line[ 12 ], 1, &game->numHoleCards, 1, &c );\n    } else if( !strncasecmp( line, \"numboardcards\", 13 ) ) {\n\n      boardCardsRead = readItems( \"%\"SCNu8, MAX_ROUNDS, &line[ 13 ],\n\t\t\t\t  1, game->numBoardCards, 1, &c );\n    }\n  }\n\n  /* do sanity checks */\n  if( game->numRounds == 0 || game->numRounds > MAX_ROUNDS ) {\n\n    fprintf( stderr, \"invalid number of rounds: %\"PRIu8\"\\n\", game->numRounds );\n    free( game );\n    return NULL;\n  }\n\n  if( game->numPlayers < 2 || game->numPlayers > MAX_PLAYERS ) {\n\n    fprintf( stderr, \"invalid number of players: %\"PRIu8\"\\n\",\n\t     game->numPlayers );\n    free( game );\n    return NULL;\n  }\n\n  if( stackRead < game->numPlayers ) {\n\n    fprintf( stderr, \"only read %\"PRIu8\" stack sizes, need %\"PRIu8\"\\n\",\n\t    stackRead, game->numPlayers );\n    free( game );\n    return NULL;\n  }\n\n  if( blindRead < game->numPlayers ) {\n\n    fprintf( stderr, \"only read %\"PRIu8\" blinds, need %\"PRIu8\"\\n\",\n\t    blindRead, game->numPlayers );\n    free( game );\n    return NULL;\n  }\n  for( c = 0; c < game->numPlayers; ++c ) {\n\n    if( game->blind[ c ] > game->stack[ c ] ) {\n      fprintf( stderr, \"blind for player %d is greater than stack size\\n\",\n\t       c + 1 );\n      free( game );\n      return NULL;\n    }\n  }\n\n  if( game->bettingType == limitBetting\n      && raiseSizeRead < game->numRounds ) {\n\n    fprintf( stderr, \"only read %\"PRIu8\" raise sizes, need %\"PRIu8\"\\n\",\n\t     raiseSizeRead, game->numRounds );\n    free( game );\n    return NULL;\n  }\n\n  for( c = 0; c < game->numRounds; ++c ) {\n\n    if( game->firstPlayer[ c ] == 0\n\t|| game->firstPlayer[ c ] > game->numPlayers ) {\n\n      fprintf( stderr, \"invalid first player %\"PRIu8\" on round %d\\n\",\n\t      game->firstPlayer[ c ], c + 1 );\n      free( game );\n      return NULL;\n    }\n\n    --game->firstPlayer[ c ];\n  }\n\n  if( game->numSuits == 0 || game->numSuits > MAX_SUITS ) {\n\n    fprintf( stderr, \"invalid number of suits: %\"PRIu8\"\\n\", game->numSuits );\n    free( game );\n    return NULL;\n  }\n\n  if( game->numRanks == 0 || game->numRanks > MAX_RANKS ) {\n\n    fprintf( stderr, \"invalid number of ranks: %\"PRIu8\"\\n\", game->numRanks );\n    free( game );\n    return NULL;\n  }\n\n  if( game->numHoleCards == 0 || game->numHoleCards > MAX_HOLE_CARDS ) {\n\n    fprintf( stderr, \"invalid number of hole cards: %\"PRIu8\"\\n\",\n\t     game->numHoleCards );\n    free( game );\n    return NULL;\n  }\n\n  if( boardCardsRead < game->numRounds ) {\n\n    fprintf( stderr, \"only read %\"PRIu8\" board card numbers, need %\"PRIu8\"\\n\",\n\t    boardCardsRead, game->numRounds );\n    free( game );\n    return NULL;\n  }\n\n  t = game->numHoleCards * game->numPlayers;\n  for( c = 0; c < game->numRounds; ++c ) {\n    t += game->numBoardCards[ c ];\n  }\n  if( t > game->numSuits * game->numRanks ) {\n\n    fprintf( stderr, \"too many hole and board cards for specified deck\\n\" );\n    free( game );\n    return NULL;\n  }\n\n  return game;\n}\n\nvoid printGame( FILE *file, const Game *game )\n{\n  int i;\n\n  fprintf( file, \"GAMEDEF\\n\" );\n\n  if( game->bettingType == noLimitBetting ) {\n    fprintf( file, \"nolimit\\n\" );\n  } else {\n    fprintf( file, \"limit\\n\" );\n  }\n\n  fprintf( file, \"numPlayers = %\"PRIu8\"\\n\", game->numPlayers );\n\n  fprintf( file, \"numRounds = %\"PRIu8\"\\n\", game->numRounds );\n\n  for( i = 0; i < game->numPlayers; ++i ) {\n    if( game->stack[ i ] < INT32_MAX ) {\n\n      fprintf( file, \"stack =\" );\n      for( i = 0; i < game->numPlayers; ++i ) {\n\tfprintf( file, \" %\"PRId32, game->stack[ i ] );\n      }\n      fprintf( file, \"\\n\" );\n\n      break;\n    }\n  }\n\n  fprintf( file, \"blind =\" );\n  for( i = 0; i < game->numPlayers; ++i ) {\n    fprintf( file, \" %\"PRId32, game->blind[ i ] );\n  }\n  fprintf( file, \"\\n\" );\n\n  if( game->bettingType == limitBetting ) {\n\n    fprintf( file, \"raiseSize =\" );\n    for( i = 0; i < game->numRounds; ++i ) {\n      fprintf( file, \" %\"PRId32, game->raiseSize[ i ] );\n    }\n    fprintf( file, \"\\n\" );\n  }\n\n  for( i = 0; i < game->numRounds; ++i ) {\n    if( game->firstPlayer[ i ] != 0 ) {\n\n      fprintf( file, \"firstPlayer =\" );\n      for( i = 0; i < game->numRounds; ++i ) {\n\tfprintf( file, \" %\"PRIu8, game->firstPlayer[ i ] + 1 );\n      }\n      fprintf( file, \"\\n\" );\n\n      break;\n    }\n  }\n\n  for( i = 0; i < game->numRounds; ++i ) {\n    if( game->maxRaises[ i ] != UINT8_MAX ) {\n\n      fprintf( file, \"maxRaises =\" );\n      for( i = 0; i < game->numRounds; ++i ) {\n\tfprintf( file, \" %\"PRIu8, game->maxRaises[ i ] );\n      }\n      fprintf( file, \"\\n\" );\n\n      break;\n    }\n  }\n\n  fprintf( file, \"numSuits = %\"PRIu8\"\\n\", game->numSuits );\n\n  fprintf( file, \"numRanks = %\"PRIu8\"\\n\", game->numRanks );\n\n  fprintf( file, \"numHoleCards = %\"PRIu8\"\\n\", game->numHoleCards );\n\n  fprintf( file, \"numBoardCards =\" );\n  for( i = 0; i < game->numRounds; ++i ) {\n    fprintf( file, \" %\"PRIu8, game->numBoardCards[ i ] );\n  }\n  fprintf( file, \"\\n\" );\n\n  fprintf( file, \"END GAMEDEF\\n\" );\n}\n\nuint8_t bcStart( const Game *game, const uint8_t round )\n{\n  int r;\n  uint8_t start;\n\n  start = 0;\n  for( r = 0; r < round; ++r ) {\n\n    start += game->numBoardCards[ r ];\n  }\n\n  return start;\n}\n\nuint8_t sumBoardCards( const Game *game, const uint8_t round )\n{\n  int r;\n  uint8_t total;\n\n  total = 0;\n  for( r = 0; r <= round; ++r ) {\n    total += game->numBoardCards[ r ];\n  }\n\n  return total;\n}\n\nstatic uint8_t nextPlayer( const Game *game, const State *state,\n\t\t\t   const uint8_t curPlayer )\n{\n  uint8_t n;\n\n  n = curPlayer;\n  do {\n    n = ( n + 1 ) % game->numPlayers;\n  } while( state->playerFolded[ n ]\n\t   || state->spent[ n ] >= game->stack[ n ] );\n\n  return n;\n}\n\nuint8_t currentPlayer( const Game *game, const State *state )\n{\n  /* if action has already been made, compute next player from last player */\n  if( state->numActions[ state->round ] ) {\n    return nextPlayer( game, state, state->actingPlayer[ state->round ]\n\t\t       [ state->numActions[ state->round ] - 1 ] );\n  }\n\n  /* first player in a round is determined by the game and round\n     use nextPlayer() because firstPlayer[round] might be unable to act */\n  return nextPlayer( game, state, game->firstPlayer[ state->round ]\n\t\t     + game->numPlayers - 1 );\n}\n\nuint8_t numRaises( const State *state )\n{\n  int i;\n  uint8_t ret;\n\n  ret = 0;\n  for( i = 0; i < state->numActions[ state->round ]; ++i ) {\n    if( state->action[ state->round ][ i ].type == a_raise ) {\n      ++ret;\n    }\n  }\n\n  return ret;\n}\n\nuint8_t numFolded( const Game *game, const State *state )\n{\n  int p;\n  uint8_t ret;\n\n  ret = 0;\n  for( p = 0; p < game->numPlayers; ++p ) {\n    if( state->playerFolded[ p ] ) {\n      ++ret;\n    }\n  }\n\n  return ret;\n}\n\nuint8_t numCalled( const Game *game, const State *state )\n{\n  int i;\n  uint8_t ret, p;\n\n  ret = 0;\n  for( i = state->numActions[ state->round ]; i > 0; --i ) {\n\n    p = state->actingPlayer[ state->round ][ i - 1 ];\n\n    if( state->action[ state->round ][ i - 1 ].type == a_raise ) {\n      /* player initiated the bet, so they've called it */\n\n      if( state->spent[ p ] < game->stack[ p ] ) {\n\t/* player is not all-in, so they're still acting */\n\n\t++ret;\n      }\n\n      /* this is the start of the current bet, so we're finished */\n      return ret;\n    } else if( state->action[ state->round ][ i - 1 ].type == a_call ) {\n\n      if( state->spent[ p ] < game->stack[ p ] ) {\n\t/* player is not all-in, so they're still acting */\n\n\t++ret;\n      }\n    }\n  }\n\n  return ret;\n}\n\nuint8_t numAllIn( const Game *game, const State *state )\n{\n  int p;\n  uint8_t ret;\n\n  ret = 0;\n  for( p = 0; p < game->numPlayers; ++p ) {\n    if( state->spent[ p ] >= game->stack[ p ] ) {\n      ++ret;\n    }\n  }\n\n  return ret;\n}\n\nuint8_t numActingPlayers( const Game *game, const State *state )\n{\n  int p;\n  uint8_t ret;\n\n  ret = 0;\n  for( p = 0; p < game->numPlayers; ++p ) {\n    if( state->playerFolded[ p ] == 0\n\t&& state->spent[ p ] < game->stack[ p ] ) {\n      ++ret;\n    }\n  }\n\n  return ret;\n}\n\nvoid initState( const Game *game, const uint32_t handId, State *state )\n{\n  int p, r;\n\n  state->handId  = handId;\n\n  state->maxSpent = 0;\n  for( p = 0; p < game->numPlayers; ++p ) {\n\n    state->spent[ p ] = game->blind[ p ];\n    if( game->blind[ p ] > state->maxSpent ) {\n\n      state->maxSpent = game->blind[ p ];\n    }\n  }\n\n  if( game->bettingType == noLimitBetting ) {\n    /* no-limit games need to keep track of the minimum bet */\n\n    if( state->maxSpent ) {\n      /* we'll have to call the big blind and then raise by that\n\t amount, so the minimum raise-to is 2*maximum blinds */\n\n      state->minNoLimitRaiseTo = state->maxSpent * 2;\n    } else {\n      /* need to bet at least one chip, and there are no blinds/ante */\n\n      state->minNoLimitRaiseTo = 1;\n    }\n  } else {\n    /* no need to worry about minimum raises outside of no-limit games */\n\n    state->minNoLimitRaiseTo = 0;\n  }\n\n  for( p = 0; p < game->numPlayers; ++p ) {\n\n    state->spent[ p ] = game->blind[ p ];\n\n    if( game->blind[ p ] > state->maxSpent ) {\n      state->maxSpent = game->blind[ p ];\n    }\n\n    state->playerFolded[ p ] = 0;\n  }\n\n  for( r = 0; r < game->numRounds; ++r ) {\n\n    state->numActions[ r ] = 0;\n  }\n\n  state->round = 0;\n\n  state->finished = 0;\n}\n\nstatic uint8_t dealCard( rng_state_t *rng, uint8_t *deck, const int numCards )\n{\n  int i;\n  uint8_t ret;\n\n  i = genrand_int32( rng ) % numCards;\n  ret = deck[ i ];\n  deck[ i ] = deck[ numCards - 1 ];\n\n  return ret;\n}\n\nvoid dealCards( const Game *game, rng_state_t *rng, State *state )\n{\n  int r, s, numCards, i, p;\n  uint8_t deck[ MAX_RANKS * MAX_SUITS ];\n\n  numCards = 0;\n  for( s = MAX_SUITS - game->numSuits; s < MAX_SUITS; ++s ) {\n\n    for( r = MAX_RANKS - game->numRanks; r < MAX_RANKS; ++r ) {\n\n      deck[ numCards ] = makeCard( r, s );\n      ++numCards;\n    }\n  }\n\n  for( p = 0; p < game->numPlayers; ++p ) {\n\n    for( i = 0; i < game->numHoleCards; ++i ) {\n\n      state->holeCards[ p ][ i ] = dealCard( rng, deck, numCards );\n      --numCards;\n    }\n  }\n\n  s = 0;\n  for( r = 0; r < game->numRounds; ++r ) {\n\n    for( i = 0; i < game->numBoardCards[ r ]; ++i ) {\n\n      state->boardCards[ s ] = dealCard( rng, deck, numCards );\n      --numCards;\n      ++s;\n    }\n  }\n}\n\n/* check whether some portions of a state are equal,\n   common to both statesEqual and matchStatesEqual */\nstatic int statesEqualCommon( const Game *game, const State *a,\n\t\t\t      const State *b )\n{\n  int r, i, t;\n\n  /* is it the same hand? */\n  if( a->handId != b->handId ) {\n    return 0;\n  }\n\n  /* make sure the betting is the same */\n  if( a->round != b->round ) {\n    return 0;\n  }\n\n  for( r = 0; r <= a->round; ++r ) {\n\n    if( a->numActions[ r ] != b->numActions[ r ] ) {\n      return 0;\n    }\n\n    for( i = 0; i < a->numActions[ r ]; ++i ) {\n\n      if( a->action[ r ][ i ].type != b->action[ r ][ i ].type ) {\n\treturn 0;\n      }\n      if( a->action[ r ][ i ].size != b->action[ r ][ i ].size ) {\n\treturn 0;\n      }\n    }\n  }\n\n  /* spent, maxSpent, actingPlayer, finished, and playerFolded are\n     all determined by the betting taken, so if it's equal, so are\n     they (at least for valid states) */\n\n  /* are the board cards the same? */\n  t = sumBoardCards( game, a->round );\n  for( i = 0; i < t; ++i ) {\n\n    if( a->boardCards[ i ] != b->boardCards[ i ] ) {\n      return 0;\n    }\n  }\n\n  /* all tests say states are equal */\n  return 1;\n}\n\nint statesEqual( const Game *game, const State *a, const State *b )\n{\n  int p, i;\n\n  if( !statesEqualCommon( game, a, b ) ) {\n    return 0;\n  }\n\n  /* are all the hole cards the same? */\n  for( p = 0; p < game->numPlayers; ++p ) {\n\n    for( i = 0; i < game->numHoleCards; ++i ) {\n      if( a->holeCards[ p ][ i ] != b->holeCards[ p ][ i ] ) {\n\treturn 0;\n      }\n    }\n  }\n\n  return 1;\n}\n\nint matchStatesEqual( const Game *game, const MatchState *a,\n\t\t      const MatchState *b )\n{\n  int p, i;\n\n  if( a->viewingPlayer != b->viewingPlayer ) {\n    return 0;\n  }\n\n  if( !statesEqualCommon( game, &a->state, &b->state ) ) {\n    return 0;\n  }\n\n  /* are the viewing player's hole cards the same? */\n  p = a->viewingPlayer;\n  for( i = 0; i < game->numHoleCards; ++i ) {\n    if( a->state.holeCards[ p ][ i ] != b->state.holeCards[ p ][ i ] ) {\n      return 0;\n    }\n  }\n\n  return 1;\n}\n\nint raiseIsValid( const Game *game, const State *curState,\n\t\t  int32_t *minSize, int32_t *maxSize )\n{\n  int p;\n\n  if( numRaises( curState ) >= game->maxRaises[ curState->round ] ) {\n    /* already made maximum number of raises */\n\n    return 0;\n  }\n\n  if( curState->numActions[ curState->round ] + game->numPlayers\n      > MAX_NUM_ACTIONS ) {\n    /* 1 raise + NUM PLAYERS-1 calls is too many actions */\n\n    fprintf( stderr, \"WARNING: #actions in round is too close to MAX_NUM_ACTIONS, forcing call/fold\\n\" );\n    return 0;\n  }\n\n  if( numActingPlayers( game, curState ) <= 1 ) {\n    /* last remaining player can't bet if there's no one left to call\n       (this check is needed if the 2nd last player goes all in, and\n       the last player has enough stack left to bet) */\n\n    return 0;\n  }\n\n  if( game->bettingType != noLimitBetting ) {\n    /* if it's not no-limit betting, don't worry about sizes */\n\n    *minSize = 0;\n    *maxSize = 0;\n    return 1;\n  }\n\n  p = currentPlayer( game, curState );\n  *minSize = curState->minNoLimitRaiseTo;\n  *maxSize = game->stack[ p ];\n\n  /* handle case where remaining player stack is too small */\n  if( *minSize > game->stack[ p ] ) {\n    /* can't handle the minimum bet size - can we bet at all? */\n\n    if( curState->maxSpent >= game->stack[ p ] ) {\n      /* not enough money to increase current bet */\n\n      return 0;\n    } else {\n      /* can raise by going all-in */\n\n      *minSize = *maxSize;\n      return 1;\n    }\n  }\n\n  return 1;\n}\n\nint isValidAction( const Game *game, const State *curState,\n\t\t   const int tryFixing, Action *action )\n{\n  int min, max, p;\n\n  if( stateFinished( curState ) || action->type == a_invalid ) {\n    return 0;\n  }\n\n  p = currentPlayer( game, curState );\n\n  if( action->type == a_raise ) {\n\n    if( !raiseIsValid( game, curState, &min, &max ) ) {\n      /* there are no valid raise sizes */\n\n      return 0;\n    }\n\n    if( game->bettingType == noLimitBetting ) {\n      /* no limit games have a size */\n\n      if( action->size < min ) {\n\t/* bet size is too small */\n\n\tif( !tryFixing ) {\n\n\t  return 0;\n\t}\n\tfprintf( stderr, \"WARNING: raise of %d increased to %d\\n\",\n\t\t action->size, min );\n\taction->size = min;\n      } else if( action->size > max ) {\n\t/* bet size is too big */\n\n\tif( !tryFixing ) {\n\n\t  return 0;\n\t}\n\tfprintf( stderr, \"WARNING: raise of %d decreased to %d\\n\",\n\t\t action->size, max );\n\taction->size = max;\n      }\n    } else {\n\n    }\n  } else if( action->type == a_fold ) {\n\n    if( curState->spent[ p ] == curState->maxSpent\n\t|| curState->spent[ p ] == game->stack[ p ] ) {\n      /* player has already called all bets, or is all-in */\n\n      return 0;\n    }\n\n    if( action->size != 0 ) {\n\n      fprintf( stderr, \"WARNING: size given for fold\\n\" );\n      action->size = 0;\n    }\n  } else {\n    /* everything else */\n\n    if( action->size != 0 ) {\n\n      fprintf( stderr, \"WARNING: size given for something other than a no-limit raise\\n\" );\n      action->size = 0;\n    }\n  }\n\n  return 1;\n}\n\nvoid doAction( const Game *game, const Action *action, State *state )\n{\n  int p = currentPlayer( game, state );\n\n  assert( state->numActions[ state->round ] < MAX_NUM_ACTIONS );\n\n  state->action[ state->round ][ state->numActions[ state->round ] ] = *action;\n  state->actingPlayer[ state->round ][ state->numActions[ state->round ] ] = p;\n  ++state->numActions[ state->round ];\n\n  switch( action->type ) {\n  case a_fold:\n\n    state->playerFolded[ p ] = 1;\n    break;\n\n  case a_call:\n\n    if( state->maxSpent > game->stack[ p ] ) {\n      /* calling puts player all-in */\n\n      state->spent[ p ] = game->stack[ p ];\n    } else {\n      /* player matches the bet by spending same amount of money */\n\n      state->spent[ p ] = state->maxSpent;\n    }\n    break;\n\n  case a_raise:\n\n    if( game->bettingType == noLimitBetting ) {\n      /* no-limit betting uses size in action */\n\n      assert( action->size > state->maxSpent );\n      assert( action->size <= game->stack[ p ] );\n\n      /* next raise must call this bet, and raise by at least this much */\n      if( action->size + action->size - state->maxSpent\n\t  > state->minNoLimitRaiseTo ) {\n\n\tstate->minNoLimitRaiseTo\n\t  = action->size + action->size - state->maxSpent;\n      }\n      state->maxSpent = action->size;\n    } else {\n      /* limit betting uses a fixed amount on top of current bet size */\n\n      if( state->maxSpent + game->raiseSize[ state->round ]\n\t  > game->stack[ p ] ) {\n\t/* raise puts player all-in */\n\n\tstate->maxSpent = game->stack[ p ];\n      } else {\n\t/* player raises by the normal limit size */\n\n\tstate->maxSpent += game->raiseSize[ state->round ];\n      }\n    }\n\n    state->spent[ p ] = state->maxSpent;\n    break;\n\n  default:\n    fprintf( stderr, \"ERROR: trying to do invalid action %d\", action->type );\n    assert( 0 );\n  }\n\n  /* see if the round or game has ended */\n  if( numFolded( game, state ) + 1 >= game->numPlayers ) {\n    /* only one player left - game is immediately over, no showdown */\n\n    state->finished = 1;\n  } else if( numCalled( game, state ) >= numActingPlayers( game, state ) ) {\n    /* >= 2 non-folded players, all acting players have called */\n\n    if( numActingPlayers( game, state ) > 1 ) {\n      /* there are at least 2 acting players */\n\n      if( state->round + 1 < game->numRounds ) {\n\t/* active players move onto next round */\n\n\t++state->round;\n\n\t/* minimum raise-by is reset to minimum of big blind or 1 chip */\n\tstate->minNoLimitRaiseTo = 1;\n\tfor( p = 0; p < game->numPlayers; ++p ) {\n\n\t  if( game->blind[ p ] > state->minNoLimitRaiseTo ) {\n\n\t    state->minNoLimitRaiseTo = game->blind[ p ];\n\t  }\n\t}\n\n\t/* we finished at least one round, so raise-to = raise-by + maxSpent */\n\tstate->minNoLimitRaiseTo += state->maxSpent;\n      } else {\n\t/* no more betting rounds, so we're totally finished */\n\n\tstate->finished = 1;\n      }\n    } else {\n      /* not enough players for more betting, but still need a showdown */\n\n      state->finished = 1;\n      state->round = game->numRounds - 1;\n    }\n  }\n}\n\nstatic int rankHand( const Game *game, const State *state,\n\t\t     const uint8_t player )\n{\n  int i;\n  Cardset c = emptyCardset();\n\n  for( i = 0; i < game->numHoleCards; ++i ) {\n\n    addCardToCardset( &c, suitOfCard( state->holeCards[ player ][ i ] ),\n\t\t      rankOfCard( state->holeCards[ player ][ i ] ) );\n  }\n\n  for( i = 0; i < sumBoardCards( game, state->round ); ++i ) {\n\n    addCardToCardset( &c, suitOfCard( state->boardCards[ i ] ),\n\t\t      rankOfCard( state->boardCards[ i ] ) );\n  }\n\n  return rankCardset( c );\n}\n\ndouble valueOfState( const Game *game, const State *state,\n\t\t     const uint8_t player )\n{\n  double value;\n  int p, numPlayers, playerIdx, numWinners, newNumPlayers;\n  int32_t size, spent[ MAX_PLAYERS ];\n  int rank[ MAX_PLAYERS ], winRank;\n\n  if( state->playerFolded[ player ] ) {\n    /* folding player loses all spent money */\n\n    return (double)-state->spent[ player ];\n  }\n\n  if( numFolded( game, state ) + 1 == game->numPlayers ) {\n    /* everyone else folded, so player takes the pot */\n\n    value = 0.0;\n    for( p = 0; p < game->numPlayers; ++p ) {\n      if( p == player ) { continue; }\n\n      value += (double)state->spent[ p ];\n    }\n\n    return value;\n  }\n\n  /* there's a showdown, and player is particpating.  Exciting! */\n\n  /* make up a list of players */\n  numPlayers = 0;\n  playerIdx = -1; /* useless, but gets rid of a warning */\n  for( p = 0; p < game->numPlayers; ++p ) {\n\n    if( state->spent[ p ] == 0 ) {\n      continue;\n    }\n\n    if( state->playerFolded[ p ] ) {\n      /* folding players have a negative rank so they lose to a real hand\n         we have also tested for fold, so p can't be the player of interest */\n\n      rank[ numPlayers ] = -1;\n    } else {\n      /* p is participating in a showdown */\n\n      if( p == player ) {\n\tplayerIdx = numPlayers;\n      }\n      rank[ numPlayers ] = rankHand( game, state, p );\n    }\n\n    spent[ numPlayers ] = state->spent[ p ];\n    ++numPlayers;\n  }\n  assert( numPlayers > 1 );\n\n  /* go through all the sidepots player is participating in */\n  value = 0.0;\n  while( 1 ) {\n\n    /* find the smallest remaining sidepot, largest rank,\n        and number of winners with largest rank */\n    size = INT32_MAX;\n    winRank = 0;\n    numWinners = 0;\n    for( p = 0; p < numPlayers; ++p ) {\n      assert( spent[ p ] > 0 );\n\n      if( spent[ p ] < size ) {\n\tsize = spent[ p ];\n      }\n\n      if( rank[ p ] > winRank ) {\n\t/* new largest rank - only one player with this rank so far */\n\n\twinRank = rank[ p ];\n\tnumWinners = 1;\n      } else if( rank[ p ] == winRank ) {\n\t/* another player with highest rank */\n\n\t++numWinners;\n      }\n    }\n\n    if( rank[ playerIdx ] == winRank ) {\n      /* player has spent size, and splits pot with other winners */\n\n      value += (double)( size * ( numPlayers - numWinners ) )\n\t/ (double)numWinners;\n    } else {\n      /* player loses this pot */\n\n      value -= (double)size;\n    }\n\n    /* update list of players for next pot */\n    newNumPlayers = 0;\n    for( p = 0; p < numPlayers; ++p ) {\n\n      spent[ p ] -= size;\n      if( spent[ p ] == 0 ) {\n\t/* player p is not participating in next side pot */\n\n\tif( p == playerIdx ) {\n\t  /* p is the player of interest, so we're done */\n\n\t  return value;\n\t}\n\n\tcontinue;\n      }\n\n      if( p == playerIdx ) {\n\t/* p is the player of interest, so note the new index */\n\n\tplayerIdx = newNumPlayers;\n      }\n\n      if( p != newNumPlayers ) {\n\t/* put entry p into new position */\n\n\tspent[ newNumPlayers ] = spent[ p ];\n\trank[ newNumPlayers ] = rank[ p ];\n      }\n      ++newNumPlayers;\n    }\n    numPlayers = newNumPlayers;\n  }\n}\n\n/* read actions from a string, updating state with the actions\n   reading is terminated by '\\0' and ':'\n   returns number of characters consumed, or -1 on failure\n   state will be modified, even on failure */\nstatic int readBetting( const char *string, const Game *game, State *state )\n{\n  int c, r;\n  Action action;\n\n  c = 0;\n  while( 1 ) {\n\n    if( string[ c ] == 0 ) {\n      break;\n    }\n\n    if( string[ c ] == ':' ) {\n      ++c;\n      break;\n    }\n\n    /* ignore / character */\n    if( string[ c ] == '/' ) {\n      ++c;\n      continue;\n    }\n\n    r = readAction( &string[ c ], game, &action );\n    if( r < 0 ) {\n      return -1;\n    }\n\n    if( !isValidAction( game, state, 0, &action ) ) {\n      return -1;\n    }\n\n    doAction( game, &action, state );\n    c += r;\n  }\n\n  return c;\n}\n\n/* print actions to a string\n   returns number of characters printed to string, or -1 on failure\n   DOES NOT COUNT FINAL 0 TERMINATOR IN THIS COUNT!!! */\nstatic int printBetting( const Game *game, const State *state,\n\t\t\t const int maxLen, char *string )\n{\n  int i, a, c, r;\n\n  c = 0;\n  for( i = 0; i <= state->round; ++i ) {\n\n    /* print state separator */\n    if( i != 0 ) {\n\n      if( c >= maxLen ) {\n\treturn -1;\n      }\n      string[ c ] = '/';\n      ++c;\n    }\n\n    /* print betting for round */\n    for( a = 0; a < state->numActions[ i ]; ++a ) {\n\n      r = printAction( game, &state->action[ i ][ a ],\n\t\t       maxLen - c, &string[ c ] );\n      if( r < 0 ) {\n\treturn -1;\n      }\n      c += r;\n    }\n  }\n\n  if( c >= maxLen ) {\n    return -1;\n  }\n  string[ c ] = 0;\n\n  return c;\n}\n\nstatic int readHoleCards( const char *string, const Game *game,\n\t\t\t  State *state )\n{\n  int p, c, r, num;\n\n  c = 0;\n  for( p = 0; p < game->numPlayers; ++p ) {\n\n    /* check for player separator '|' */\n    if( p != 0 ) {\n      if( string[ c ] == '|' ) {\n\t++c;\n      }\n    }\n\n    num = readCards( &string[ c ], game->numHoleCards,\n\t\t     state->holeCards[ p ], &r );\n    if( num == 0 ) {\n      /* no cards for player p */\n\n      continue;\n    }\n    if( num != game->numHoleCards ) {\n      /* read some cards, but not enough - bad! */\n\n      return -1;\n    }\n    c += r;\n  }\n\n  return c;\n}\n\nstatic int printAllHoleCards( const Game *game, const State *state,\n\t\t\t      const int maxLen, char *string )\n{\n  int p, c, r;\n\n  c = 0;\n  for( p = 0; p < game->numPlayers; ++p ) {\n\n    /* print player separator '|' */\n    if( p != 0 ) {\n\n      if( c >= maxLen ) {\n\treturn -1;\n      }\n      string[ c ] = '|';\n      ++c;\n    }\n\n    r = printCards( game->numHoleCards, state->holeCards[ p ],\n\t\t    maxLen - c, &string[ c ] );\n    if( r < 0 ) {\n      return -1;\n    }\n    c += r;\n  }\n\n  if( c >= maxLen ) {\n    return -1;\n  }\n  string[ c ] = 0;\n\n  return c;\n}\n\nstatic int printPlayerHoleCards( const Game *game, const State *state,\n\t\t\t\t const uint8_t player,\n\t\t\t\t const int maxLen, char *string )\n{\n  int p, c, r;\n\n  c = 0;\n  for( p = 0; p < game->numPlayers; ++p ) {\n\n    /* print player separator '|' */\n    if( p != 0 ) {\n\n      if( c >= maxLen ) {\n\treturn -1;\n      }\n      string[ c ] = '|';\n      ++c;\n    }\n\n    if( p != player ) {\n      /* don't print other player's cards unless there was a showdown\n          and they didn't fold */\n\n      if( !stateFinished( state ) ) {\n\tcontinue;\n      }\n\n      if( state->playerFolded[ p ] ) {\n\tcontinue;\n      }\n\n      if( numFolded( game, state ) + 1 == game->numPlayers ) {\n\tcontinue;\n      }\n    }\n\n    r = printCards( game->numHoleCards, state->holeCards[ p ],\n\t\t    maxLen - c, &string[ c ] );\n    if( r < 0 ) {\n      return -1;\n    }\n    c += r;\n  }\n\n  if( c >= maxLen ) {\n    return -1;\n  }\n  string[ c ] = 0;\n\n  return c;\n}\n\nstatic int readBoardCards( const char *string, const Game *game,\n\t\t\t   State *state )\n{\n  int i, c, r;\n\n  c = 0;\n  for( i = 0; i <= state->round; ++i ) {\n\n    /* check for round separator '/' */\n    if( i != 0 ) {\n      if( string[ c ] == '/' ) {\n\t++c;\n      }\n    }\n\n    if( readCards( &string[ c ], game->numBoardCards[ i ],\n\t\t   &state->boardCards[ bcStart( game, i ) ], &r )\n\t!= game->numBoardCards[ i ] ) {\n      /* couldn't read the required number of cards - bad! */\n\n      return -1;\n    }\n    c += r;\n  }\n\n  return c;\n}\n\nstatic int printBoardCards( const Game *game, const State *state,\n\t\t\t    const int maxLen, char *string )\n{\n  int i, c, r;\n\n  c = 0;\n  for( i = 0; i <= state->round; ++i ) {\n\n    /* print round separator '/' */\n    if( i != 0 ) {\n\n      if( c >= maxLen ) {\n\treturn -1;\n      }\n      string[ c ] = '/';\n      ++c;\n    }\n\n    r = printCards( game->numBoardCards[ i ],\n\t\t    &state->boardCards[ bcStart( game, i ) ],\n\t\t    maxLen - c, &string[ c ] );\n    if( r < 0 ) {\n      return -1;\n    }\n    c += r;\n  }\n\n  if( c >= maxLen ) {\n    return -1;\n  }\n  string[ c ] = 0;\n\n  return c;\n}\n\n\nstatic int readStateCommon( const char *string, const Game *game,\n\t\t\t    State *state )\n{\n  uint32_t handId;\n  int c, r;\n\n  /* HEADER */\n  c = 0;\n\n  /* HEADER:handId */\n  if( sscanf( string, \":%\"SCNu32\"%n\", &handId, &r ) < 1 ) {\n    return -1;\n  }\n  c += r;\n\n  initState( game, handId, state );\n\n  /* HEADER:handId: */\n  if( string[ c ] != ':' ) {\n    return -1;\n  }\n  ++c;\n\n  /* HEADER:handId:betting: */\n  r = readBetting( &string[ c ], game, state );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  /* HEADER:handId:betting:holeCards */\n  r = readHoleCards( &string[ c ], game, state );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  /* HEADER:handId:betting:holeCards boardCards */\n  r = readBoardCards( &string[ c ], game, state );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  return c;\n}\n\nint readState( const char *string, const Game *game, State *state )\n{\n  int c, r;\n\n  /* HEADER = STATE */\n  if( strncmp( string, \"STATE\", 5 ) != 0 ) {\n    return -1;\n  }\n  c = 5;\n\n  /* read rest of state */\n  r = readStateCommon( &string[ 5 ], game, state );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  return c;\n}\n\nint readMatchState( const char *string, const Game *game,\n\t\t    MatchState *state )\n{\n  int c, r;\n\n  /* HEADER = MATCHSTATE:player */\n  if( sscanf( string, \"MATCHSTATE:%\"SCNu8\"%n\",\n\t      &state->viewingPlayer, &c ) < 1\n      || state->viewingPlayer >= game->numPlayers )  {\n    return -1;\n  }\n\n  /* read rest of state */\n  r = readStateCommon( &string[ c ], game, &state->state );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  return c;\n}\n\nstatic int printStateCommon( const Game *game, const State *state,\n\t\t\t     const int maxLen, char *string )\n{\n  int c, r;\n\n  /* HEADER */\n  c = 0;\n\n  /* HEADER:handId: */\n  r = snprintf( &string[ c ], maxLen - c, \":%\"PRIu32\":\", state->handId );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  /* HEADER:handId:betting */\n  r = printBetting( game, state, maxLen - c, &string[ c ] );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  /* HEADER:handId:betting: */\n  if( c >= maxLen ) {\n    return -1;\n  }\n  string[ c ] = ':';\n  ++c;\n\n  return c;\n}\n\nint printState( const Game *game, const State *state,\n\t\tconst int maxLen, char *string )\n{\n  int c, r;\n\n  c = 0;\n\n  /* STATE */\n  r = snprintf( &string[ c ], maxLen - c, \"STATE\" );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  /* STATE:handId:betting: */\n  r = printStateCommon( game, state, maxLen - c, &string[ c ] );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  /* STATE:handId:betting:holeCards */\n  r = printAllHoleCards( game, state, maxLen - c, &string[ c ] );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  /* STATE:handId:betting:holeCards boardCards */\n  r = printBoardCards( game, state, maxLen - c, &string[ c ] );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  if( c >= maxLen ) {\n    return -1;\n  }\n  string[ c ] = 0;\n\n  return c;\n}\n\nint printMatchState( const Game *game, const MatchState *state,\n\t\t     const int maxLen, char *string )\n{\n  int c, r;\n\n  c = 0;\n\n  /* MATCHSTATE:player */\n  r = snprintf( &string[ c ], maxLen - c, \"MATCHSTATE:%\"PRIu8,\n\t\tstate->viewingPlayer );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  /* MATCHSTATE:player:handId:betting: */\n  r = printStateCommon( game, &state->state, maxLen - c, &string[ c ] );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  /* MATCHSTATE:player:handId:betting:holeCards */\n  r = printPlayerHoleCards( game, &state->state, state->viewingPlayer,\n\t\t\t    maxLen - c, &string[ c ] );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  /* MATCHSTATE:player:handId:betting:holeCards boardCards */\n  r = printBoardCards( game, &state->state, maxLen - c, &string[ c ] );\n  if( r < 0 ) {\n    return -1;\n  }\n  c += r;\n\n  if( c >= maxLen ) {\n    return -1;\n  }\n  string[ c ] = 0;\n\n  return c;\n}\n\nint readAction( const char *string, const Game *game, Action *action )\n{\n  int c, r;\n\n  action->type = charToAction[ (uint8_t)string[ 0 ] ];\n  if( action->type < 0 ) {\n    return -1;\n  }\n  c = 1;\n\n  if( action->type == a_raise && game->bettingType == noLimitBetting ) {\n    /* no-limit bet/raise needs to read a size */\n\n    if( sscanf( &string[ c ], \"%\"SCNd32\"%n\", &action->size, &r ) < 1 ) {\n      return -1;\n    }\n    c += r;\n  } else {\n    /* size is zero for anything but a no-limit raise */\n\n    action->size = 0;\n  }\n\n  return c;\n}\n\nint printAction( const Game *game, const Action *action,\n\t\t const int maxLen, char *string )\n{\n  int c, r;\n\n  if( maxLen == 0 ) {\n    return -1;\n  }\n\n  c = 0;\n\n  string[ c ] = actionChars[ action->type ];\n  ++c;\n\n  if( game->bettingType == noLimitBetting && action->type == a_raise ) {\n    /* 2010 AAAI no-limit format has a size for bet/raise */\n\n    r = snprintf( &string[ c ], maxLen - c, \"%\"PRId32, action->size );\n    if( r < 0 ) {\n      return -1;\n    }\n    c += r;\n  }\n\n  if( c >= maxLen ) {\n    return -1;\n  }\n  string[ c ] = 0;\n\n  return c;\n}\n\nint readCard( const char *string, uint8_t *card )\n{\n  char *spos;\n  uint8_t c;\n\n  if( string[ 0 ] == 0 ) {\n    return -1;\n  }\n  spos = strchr( rankChars, toupper( string[ 0 ] ) );\n  if( spos == 0 ) {\n    return -1;\n  }\n  c = spos - rankChars;\n\n  if( string[ 1 ] == 0 ) {\n    return -1;\n  }\n  spos = strchr( suitChars, tolower( string[ 1 ] ) );\n  if( spos == 0 ) {\n    return -1;\n  }\n\n  *card = makeCard( c, spos - suitChars );\n\n  return 2;\n}\n\nint readCards( const char *string, const int maxCards,\n\t       uint8_t *cards, int *charsConsumed )\n{\n  int i, c, r;\n\n  c = 0;\n  for( i = 0; i < maxCards; ++i ) {\n\n    r = readCard( &string[ c ], &cards[ i ] );\n    if( r < 0 ) {\n      break;\n    }\n    c += r;\n  }\n\n  *charsConsumed = c;\n  return i;\n}\n\nint printCard( const uint8_t card, const int maxLen, char *string  )\n{\n  if( 3 > maxLen ) {\n    return -1;\n  }\n\n  string[ 0 ] = rankChars[ rankOfCard( card ) ];\n  string[ 1 ] = suitChars[ suitOfCard( card ) ];\n  string[ 2 ] = 0;\n\n  return 2;\n}\n\nint printCards( const int numCards, const uint8_t *cards,\n\t\tconst int maxLen, char *string )\n{\n  int i, c, r;\n\n  c = 0;\n\n  for( i = 0; i < numCards; ++i ) {\n\n    r = printCard( cards[ i ], maxLen - c, &string[ c ] );\n    if( r < 0 ) {\n      return -1;\n    }\n    c += r;\n  }\n\n  /* no need to null terminate, we know for sure that printCard does */\n\n  return c;\n}\n"
  },
  {
    "path": "ACPCServer/game.h",
    "content": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#ifndef _GAME_H\n#define _GAME_H\n#define __STDC_FORMAT_MACROS\n#include <inttypes.h>\n#include \"rng.h\"\n#include \"net.h\"\n\n\n#define VERSION_MAJOR 2\n#define VERSION_MINOR 0\n#define VERSION_REVISION 0\n\n\n#define MAX_ROUNDS 4\n#define MAX_PLAYERS 10\n#define MAX_BOARD_CARDS 7\n#define MAX_HOLE_CARDS 3\n#define MAX_NUM_ACTIONS 64\n#define MAX_SUITS 4\n#define MAX_RANKS 13\n#define MAX_LINE_LEN READBUF_LEN\n\n#define NUM_ACTION_TYPES 3\n\n\nenum BettingType { limitBetting, noLimitBetting };\nenum ActionType { a_fold = 0, a_call = 1, a_raise = 2,\n\t\t  a_invalid = NUM_ACTION_TYPES };\n\ntypedef struct {\n  enum ActionType type; /* is action a fold, call, or raise? */\n  int32_t size; /* for no-limit raises, we need a size\n\t\t   MUST BE 0 IN ALL CASES WHERE IT IS NOT USED */\n} Action;\n\ntypedef struct {\n\n  /* stack sizes for each player */\n  int32_t stack[ MAX_PLAYERS ];\n\n  /* entry fee for game, per player */\n  int32_t blind[ MAX_PLAYERS ];\n\n  /* size of fixed raises for limitBetting games */\n  int32_t raiseSize[ MAX_ROUNDS ];\n\n  /* general class of game */\n  enum BettingType bettingType;\n\n  /* number of players in the game */\n  uint8_t numPlayers;\n\n  /* number of betting rounds */\n  uint8_t numRounds;\n\n  /* first player to act in a round */\n  uint8_t firstPlayer[ MAX_ROUNDS ];\n\n  /* number of bets/raises that may be made in each round */\n  uint8_t maxRaises[ MAX_ROUNDS ];\n\n  /* number of suits and ranks in the deck of cards */\n  uint8_t numSuits;\n  uint8_t numRanks;\n\n  /* number of private player cards */\n  uint8_t numHoleCards;\n\n  /* number of shared public cards each round */\n  uint8_t numBoardCards[ MAX_ROUNDS ];\n} Game;\n\ntypedef struct {\n  uint32_t handId;\n\n  /* largest bet so far, including all previous rounds */\n  int32_t maxSpent;\n\n  /* minimum number of chips a player must have spend in total to raise\n     only used for noLimitBetting games */\n  int32_t minNoLimitRaiseTo;\n\n  /* spent[ p ] gives the total amount put into the pot by player p */\n  int32_t spent[ MAX_PLAYERS ];\n\n  /* action[ r ][ i ] gives the i'th action in round r */\n  Action action[ MAX_ROUNDS ][ MAX_NUM_ACTIONS ];\n\n  /* actingPlayer[ r ][ i ] gives the player who made action i in round r\n     we can always figure this out from the actions taken, but it's\n     easier to just remember this in multiplayer (because of folds) */\n  uint8_t actingPlayer[ MAX_ROUNDS ][ MAX_NUM_ACTIONS ];\n\n  /* numActions[ r ] gives the number of actions made in round r */\n  uint8_t numActions[ MAX_ROUNDS ];\n\n  /* current round: a value between 0 and game.numRounds-1\n     a showdown is still in numRounds-1, not a separate round */\n  uint8_t round;\n\n  /* finished is non-zero if and only if the game is over */\n  uint8_t finished;\n\n  /* playerFolded[ p ] is non-zero if and only player p has folded */\n  uint8_t playerFolded[ MAX_PLAYERS ];\n\n  /* public cards (including cards which may not yet be visible to players) */\n  uint8_t boardCards[ MAX_BOARD_CARDS ];\n\n  /* private cards */\n  uint8_t holeCards[ MAX_PLAYERS ][ MAX_HOLE_CARDS ];\n} State;\n\ntypedef struct {\n  State state;\n  uint8_t viewingPlayer;\n} MatchState;\n\n\n/* returns a game structure, or NULL on failure */\nGame *readGame( FILE *file );\n\nvoid printGame( FILE *file, const Game *game );\n\n/* initialise a state so that it is at the beginning of a hand\n   DOES NOT DEAL OUT CARDS */\nvoid initState( const Game *game, const uint32_t handId, State *state );\n\n/* shuffle a deck of cards and deal them out, writing the results to state */\nvoid dealCards( const Game *game, rng_state_t *rng, State *state );\n\nint statesEqual( const Game *game, const State *a, const State *b );\n\nint matchStatesEqual( const Game *game, const MatchState *a,\n\t\t      const MatchState *b );\n\n/* check if a raise is possible, and the range of valid sizes\n   returns non-zero if raise is a valid action and sets *minSize\n   and maxSize, or zero if raise is not valid */\nint raiseIsValid( const Game *game, const State *curState,\n\t\t  int32_t *minSize, int32_t *maxSize );\n\n/* check if an action is valid\n\n   if tryFixing is non-zero, try modifying the given action to produce\n   a valid action, as in the AAAI rules.  Currently this only means\n   that a no-limit raise will be modified to the nearest valid raise size\n\n   returns non-zero if final action/size is valid for state, 0 otherwise */\nint isValidAction( const Game *game, const State *curState,\n\t\t   const int tryFixing, Action *action );\n\n/* record the given action in state\n    does not check that action is valid */\nvoid doAction( const Game *game, const Action *action, State *state );\n\n/* returns non-zero if hand is finished, zero otherwise */\n#define stateFinished( constStatePtr ) ((constStatePtr)->finished)\n\n/* get the current player to act in the state */\nuint8_t currentPlayer( const Game *game, const State *state );\n\n/* number of raises in the current round */\nuint8_t numRaises( const State *state );\n\n/* number of players who have folded */\nuint8_t numFolded( const Game *game, const State *state );\n\n/* number of players who have called the current bet (or initiated it)\n   doesn't count non-acting players who are all-in */\nuint8_t numCalled( const Game *game, const State *state );\n\n/* number of players who are all-in */\nuint8_t numAllIn( const Game *game, const State *state );\n\n/* number of players who can still act (ie not all-in or folded) */\nuint8_t numActingPlayers( const Game *game, const State *state );\n\n/* get the index into array state.boardCards[] for the first board\n   card in round (where the first round is round 0) */\nuint8_t bcStart( const Game *game, const uint8_t round );\n\n/* get the total number of board cards dealt out after (zero based) round */\nuint8_t sumBoardCards( const Game *game, const uint8_t round );\n\n/* return the value of a finished hand for a player\n   returns a double because pots may be split when players tie\n   WILL HAVE UNDEFINED BEHAVIOUR IF HAND ISN'T FINISHED\n   (stateFinished(state)==0) */\ndouble valueOfState( const Game *game, const State *state,\n\t\t      const uint8_t player );\n\n/* returns number of characters consumed on success, -1 on failure\n   state will be modified even on a failure to read */\nint readState( const char *string, const Game *game, State *state );\n\n/* returns number of characters consumed on success, -1 on failure\n   state will be modified even on a failure to read */\nint readMatchState( const char *string, const Game *game, MatchState *state );\n\n/* print a state to a string, as viewed by viewingPlayer\n   returns the number of characters in string, or -1 on error\n   DOES NOT COUNT FINAL 0 TERMINATOR IN THIS COUNT!!! */\nint printState( const Game *game, const State *state,\n\t\tconst int maxLen, char *string );\n\n/* print a state to a string, as viewed by viewingPlayer\n   returns the number of characters in string, or -1 on error\n   DOES NOT COUNT FINAL 0 TERMINATOR IN THIS COUNT!!! */\nint printMatchState( const Game *game, const MatchState *state,\n\t\t     const int maxLen, char *string );\n\n/* read an action, returning the action in the passed pointer\n   action and size will be modified even on a failure to read\n   returns number of characters consumed on succes, -1 on failure */\nint readAction( const char *string, const Game *game, Action *action );\n\n/* print an action to a string\n   returns the number of characters in string, or -1 on error\n   DOES NOT COUNT FINAL 0 TERMINATOR IN THIS COUNT!!! */\nint printAction( const Game *game, const Action *action,\n\t\t const int maxLen, char *string );\n\n/* returns number of characters consumed, or -1 on error\n   on success, returns the card in *card */\nint readCard( const char *string, uint8_t *card );\n\n/* read up to maxCards cards\n   returns number of cards successfully read\n   returns number of characters consumed in charsConsumed */\nint readCards( const char *string, const int maxCards,\n\t       uint8_t *cards, int *charsConsumed );\n\n/* print a card to a string\n   returns the number of characters in string, or -1 on error\n   DOES NOT COUNT FINAL 0 TERMINATOR IN THIS COUNT!!! */\nint printCard( const uint8_t card, const int maxLen, char *string );\n\n/* print out numCards cards to a string\n   returns the number of characters in string\n   DOES NOT COUNT FINAL 0 TERMINATOR IN THIS COUNT!!! */\nint printCards( const int numCards, const uint8_t *cards,\n\t\tconst int maxLen, char *string );\n\n#define rankOfCard( card ) ((card)/MAX_SUITS)\n#define suitOfCard( card ) ((card)%MAX_SUITS)\n#define makeCard( rank, suit ) ((rank)*MAX_SUITS+(suit))\n\n#endif\n"
  },
  {
    "path": "ACPCServer/holdem.limit.2p.reverse_blinds.game",
    "content": "GAMEDEF\nlimit\nnumPlayers = 2\nnumRounds = 4\nblind = 10 5\nraiseSize = 10 10 20 20\nfirstPlayer = 2 1 1 1\nmaxRaises = 3 4 4 4\nnumSuits = 4\nnumRanks = 13\nnumHoleCards = 2\nnumBoardCards = 0 3 1 1\nEND GAMEDEF\n"
  },
  {
    "path": "ACPCServer/holdem.limit.3p.game",
    "content": "GAMEDEF\nlimit\nnumPlayers = 3\nnumRounds = 4\nblind = 5 10 0\nraiseSize = 10 10 20 20\nfirstPlayer = 3 1 1 1\nmaxRaises = 3 4 4 4\nnumSuits = 4\nnumRanks = 13\nnumHoleCards = 2\nnumBoardCards = 0 3 1 1\nEND GAMEDEF\n"
  },
  {
    "path": "ACPCServer/holdem.nolimit.2p.reverse_blinds.game",
    "content": "GAMEDEF\nnolimit\nnumPlayers = 2\nnumRounds = 4\nstack = 20000 20000\nblind = 50 100\nfirstPlayer = 1 2 2 2\nnumSuits = 4\nnumRanks = 13\nnumHoleCards = 2\nnumBoardCards = 0 3 1 1\nEND GAMEDEF\n"
  },
  {
    "path": "ACPCServer/holdem.nolimit.3p.game",
    "content": "GAMEDEF\nnolimit\nnumPlayers = 3\nnumRounds = 4\nstack = 20000 20000 20000\nblind = 50 100 0\nfirstPlayer = 3 1 1 1\nnumSuits = 4\nnumRanks = 13\nnumHoleCards = 2\nnumBoardCards = 0 3 1 1\nEND GAMEDEF\n"
  },
  {
    "path": "ACPCServer/kuhn.limit.3p.game",
    "content": "GAMEDEF\nlimit\nnumPlayers = 3\nnumRounds = 1\nblind = 1 1 1\nraiseSize = 1\nfirstPlayer = 1\nmaxRaises = 1\nnumSuits = 1\nnumRanks = 4\nnumHoleCards = 1\nnumBoardCards = 0\nEND GAMEDEF\n"
  },
  {
    "path": "ACPCServer/leduc.game",
    "content": "GAMEDEF\nnolimit\nnumPlayers = 2\nnumRounds = 2\nstack = 1200 1200\nblind = 100 100\nfirstPlayer = 1 1\nnumSuits = 2\nnumRanks = 3\nnumHoleCards = 1\nnumBoardCards = 0 1\nEND GAMEDEF\n"
  },
  {
    "path": "ACPCServer/net.c",
    "content": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <unistd.h>\n#include <netdb.h>\n#include <string.h>\n#include <sys/socket.h>\n#include <sys/time.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include \"net.h\"\n\n\nReadBuf *createReadBuf( int fd )\n{\n  ReadBuf *readBuf = (ReadBuf*)malloc( sizeof( ReadBuf ) );\n  if( readBuf == 0 ) {\n\n    return readBuf;\n  }\n\n  readBuf->fd = fd;\n  readBuf->bufStart = 0;\n  readBuf->bufEnd = 0;\n\n  return readBuf;\n}\n\nvoid destroyReadBuf( ReadBuf *readBuf )\n{\n  close( readBuf->fd );\n  free( readBuf );\n}\n\n/* get a newline terminated line and place it as a string in 'line'\n   terminates the string with a 0 character\n   if timeoutMicros is non-negative, do not spend more than\n   that number of microseconds waiting to read data\n   return number of characters read (including newline, excluding 0)\n   0 on end of file, or -1 on error or timeout */\nssize_t getLine( ReadBuf *readBuf,\n\t\t size_t maxLen,\n\t\t char *line,\n\t\t int64_t timeoutMicros )\n{\n  int haveStartTime, c;\n  ssize_t len;\n  fd_set fds;\n  struct timeval start, tv;\n\n  /* reserve space for string terminator */\n  --maxLen;\n  if( maxLen < 0 ) {\n    return -1;\n  }\n\n  /* read the line */\n  haveStartTime = 0;\n  len = 0;\n  while( len < maxLen ) {\n\n    if( readBuf->bufStart >= readBuf->bufEnd ) {\n      /* buffer is empty */\n\n      if( timeoutMicros >= 0 ) {\n\t/* figure out how much time is left for reading */\n\tuint64_t timeLeft;\n\n\ttimeLeft = timeoutMicros;\n\tif( haveStartTime ) {\n\n\t  gettimeofday( &tv, NULL );\n\t  timeLeft -= (uint64_t)( tv.tv_sec - start.tv_sec ) * 1000000\n\t    + ( tv.tv_usec - start.tv_usec );\n\t  if( timeLeft < 0 ) {\n\n\t    timeLeft = 0;\n\t  }\n\t} else {\n\n\t  haveStartTime = 1;\n\t  gettimeofday( &start, NULL );\n\t}\n\ttv.tv_sec = timeLeft / 1000000;\n\ttv.tv_usec = timeLeft % 1000000;\n\n\t/* wait for file descriptor to be ready */\n\tFD_ZERO( &fds );\n\tFD_SET( readBuf->fd, &fds );\n\tif( select( readBuf->fd + 1, &fds, NULL, NULL, &tv ) < 1 ) {\n\t  /* no input ready within time, or an actual error */\n\t\n\t  return -1;\n\t}\n      }\n\n      /* try reading a buffer full of data */\n      readBuf->bufStart = 0;\n      readBuf->bufEnd = read( readBuf->fd, readBuf->buf, READBUF_LEN );\n      if( readBuf->bufEnd == 0 ) {\n\t/* end of input */\n\n\tbreak;\n      } else if( readBuf->bufEnd < 0 ) {\n\t/* error condition */\n\n\treadBuf->bufEnd = 0;\n\treturn -1;\n      }\n    }\n\n    /* keep adding to the string until we see a newline */\n    c = readBuf->buf[ readBuf->bufStart ];\n    ++readBuf->bufStart;\n    line[ len ] = c;\n    ++len;\n    if( c == '\\n' ) {\n\n      break;\n    }\n  }\n\n  /* terminate the string */\n  line[ len ] = 0;\n  return len;\n}\n\n\nint connectTo( char *hostname, uint16_t port )\n{\n  int sock;\n  struct hostent *hostent;\n  struct sockaddr_in addr;\n\n  hostent = gethostbyname( hostname );\n  if( hostent == NULL ) {\n\n    fprintf( stderr, \"ERROR: could not look up address for %s\\n\", hostname );\n    return -1;\n  }\n\n  if( ( sock = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) {\n\n    fprintf( stderr, \"ERROR: could not open socket\\n\" );\n    return -1;\n  }\n\n  addr.sin_family = AF_INET;\n  addr.sin_port = htons( port );\n  memcpy( &addr.sin_addr, hostent->h_addr_list[ 0 ], hostent->h_length );\n\n  if( connect( sock, (struct sockaddr *)&addr, sizeof( addr ) ) < 0 ) {\n\n    fprintf( stderr, \"ERROR: could not connect to %s:%\"PRIu16\"\\n\",\n\t     hostname, port );\n    return -1;\n  }\n\n  return sock;\n}\n\nint getListenSocket( uint16_t *desiredPort )\n{\n  int sock, t;\n  struct sockaddr_in addr;\n\n  if( ( sock = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) {\n\n    return -1;\n  }\n\n  /* allow fast socket reuse - ignore failure */\n  t = 1;\n  setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &t, sizeof( int ) );\n\n  /* bind the socket to the port */\n  if( *desiredPort != 0 ) {\n\n    addr.sin_family = AF_INET;\n    addr.sin_port = htons( *desiredPort );\n    addr.sin_addr.s_addr = htonl( INADDR_ANY );\n    if( bind( sock, (struct sockaddr *)&addr, sizeof( addr ) ) < 0 ) {\n\n      return -1;\n    }\n  } else {\n\n    t = 0;\n    while( 1 ) {\n      addr.sin_family = AF_INET;\n      *desiredPort = ( random() % 64512 ) + 1024;\n      addr.sin_port = htons( *desiredPort );\n      addr.sin_addr.s_addr = htonl( INADDR_ANY );\n      if( bind( sock, (struct sockaddr *)&addr, sizeof( addr ) ) < 0 ) {\n\n\tif( t < NUM_PORT_CREATION_ATTEMPTS ) {\n\n\t  ++t;\n\t  continue;\n\t} else {\n\n\t  return -1;\n\t}\n      }\n\n      break;\n    }\n  }\n\n  /* listen on the socket */\n  if( listen( sock, 8 ) < 0 ) {\n\n    return -1;\n  }\n\n  return sock;\n}\n"
  },
  {
    "path": "ACPCServer/net.h",
    "content": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#ifndef _NET_H\n#define _NET_H\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <sys/types.h>\n#define __STDC_FORMAT_MACROS\n#include <inttypes.h>\n\n\n#define READBUF_LEN 4096\n#define NUM_PORT_CREATION_ATTEMPTS 10\n\n\n/* buffered I/O on file descriptors\n\n   Yes... this is basically re-implementing bits of a standard FILE.\n   Unfortunately, trying to mix timeouts and FILE streams either\n   a) doesn't work, or b) is fairly system specific */\ntypedef struct {\n  int fd;\n  int bufStart;\n  int bufEnd;\n  char buf[ READBUF_LEN ];\n} ReadBuf;\n\n\n/* open a socket to hostname/port\n   returns file descriptor on success, <0 on failure */\nint connectTo( char *hostname, uint16_t port );\n\n/* try opening a socket suitable for connecting to\n   if *desiredPort>0, uses specified port, otherwise use a random port\n   returns actual port in *desiredPort\n   returns file descriptor for socket, or -1 on failure */\nint getListenSocket( uint16_t *desiredPort );\n\n\n/* create a read buffer structure\n   returns 0 on failure */\nReadBuf *createReadBuf( int fd );\n\n/* destroy a read buffer - like fdopen, it will close the file descriptor */\nvoid destroyReadBuf( ReadBuf *readBuf );\n\n/* get a newline terminated line and place it as a string in 'line'\n   terminates the string with a 0 character\n   if timeoutMicros is non-negative, do not spend more than\n   that number of microseconds waiting to read data\n   return number of characters read (including newline, excluding 0)\n   0 on end of file, or -1 on error or timeout */\nssize_t getLine( ReadBuf *readBuf,\n\t\t size_t maxLen,\n\t\t char *line,\n\t\t int64_t timeoutMicros );\n\n\n#endif\n"
  },
  {
    "path": "ACPCServer/play_match.pl",
    "content": "#!/usr/bin/perl\n\n# Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n\nuse Socket;\n\n$hostname = `hostname` or die \"could not get hostname\";\nchomp $hostname;\n@hostent = gethostbyname( $hostname );\n$#hostent >= 4 or die \"could not look up $hostname\";\n$hostip = inet_ntoa( $hostent[ 4 ] );\n\n$#ARGV >= 3 or die \"usage: play_match.pl matchName gameDefFile #Hands rngSeed player1name player1exe player2name player2exe ... [options]\";\n\n$numPlayers = -1;\nopen FILE, '<', $ARGV[ 1 ] or die \"couldn't open game definition $ARGV[ 1 ]\";\nwhile( $_ = <FILE> ) {\n\n    @_ = split;\n\n    if( uc( $_[ 0 ] ) eq 'NUMPLAYERS' ) {\n\t$numPlayers = $_[ $#_ ];\n    }\n}\nclose FILE;\n\n$numPlayers > 1 or die \"couldn't get number of players from $ARGV[ 1 ]\";\n\n\n$#ARGV >= 3 + $numPlayers * 2 or die \"too few players on command line\";\n\npipe STDINREADPIPE, STDINWRITEPIPE or die \"couldn't create stdin pipe\";\npipe STDOUTREADPIPE, STDOUTWRITEPIPE or die \"couldn't create stdout pipe\";\n\n$dealerPID = fork();\nif( $dealerPID == 0 ) {\n    # we're the child\n\n    # replace standard in and standard out with pipe\n    close STDINWRITEPIPE;\n    close STDOUTREADPIPE;\n    open STDIN, '<&STDINREADPIPE' or die \"can't dup STDIN\";\n    open STDOUT, '>&STDOUTWRITEPIPE' or die \"can't dup STDOUT\";\n    open STDERR, \">>$ARGV[ 0 ].err\" or die \"can't open log file $ARGV[ 0 ].err\";\n\n    @args = ( \"dealer\", $ARGV[ 0 ], $ARGV[ 1 ],\n\t      $ARGV[ 2 ], $ARGV[ 3 ] );\n\n    # add names to the arguments\n    for( $p = 0; $p < $numPlayers; ++$p ) {\n\tpush @args, $ARGV[ 4 + $p * 2 ];\n    }\n\n    # add any extra arguments (options?) to the arguments\n    for( $i = 4 + $numPlayers * 2; $i <= $#ARGV; ++$i ) {\n\tpush @args, $ARGV[ $i ];\n    }\n    exec { \"./dealer\" } @args or die \"Couldn't run dealer\";\n}\n\nclose STDINREADPIPE;\nclose STDOUTWRITEPIPE;\n\n$_ = <STDOUTREADPIPE> or die \"couldn't read port description from dealer\";\n@_ = split;\n$#_ + 1 >= $numPlayers or die \"couldn't get enough ports from $_\";\n\nfor( $p = 0; $p < $numPlayers; ++$p ) {\n\n    $playerPID[ $p ] = fork();\n\n    if( $playerPID[ $p ] == 0 ) {\n\t# we're the child\n\n\t# log standard out and standard error\n\topen STDOUT, \">$ARGV[ 0 ].player$p.std\"\n\t    or die \"can't dup player $p STDOUT\";\n\topen STDERR, \">$ARGV[ 0 ].player$p.err\"\n\t    or die \"can't dup player $p STDERR\";\n\n\texec { $ARGV[ 4 + $p * 2 + 1 ] } ( $ARGV[ 4 + $p * 2 + 1 ],\n\t\t\t\t\t   $hostip, $_[ $p ] )\n\t    or die \"couldn't run $ARGV[ 4 + $p * 2 + 1 ] for player $p\";\n    }\n}\n\n$_ = <STDOUTREADPIPE>;\n\nfor( $p = 0; $p < $numPlayers; ++$p ) {\n    waitpid( $playerPID[ $p ], 0 );\n}\n\nwaitpid( $dealerPID, 0 );\n\n$_ or die \"couldn't get values from dealer\";\n\nprint $_;\n\nexit( 0 );\n"
  },
  {
    "path": "ACPCServer/rng.c",
    "content": "/* \n   A C-program for MT19937, with initialization improved 2002/1/26.\n   Coded by Takuji Nishimura and Makoto Matsumoto.\n\n   Before using, initialize the state by using init_genrand(seed)  \n   or init_by_array(init_key, key_length).\n\n   Copyright (C) 2011 by the Computer Poker Research Group, University of \n   Alberta\n\n   This file is a modification of work by Makoto Matsumoto and Takuji\n   Nishimura.  That work was provided with the following license:\n\n   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,\n   All rights reserved.                          \n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n     1. Redistributions of source code must retain the above copyright\n        notice, this list of conditions and the following disclaimer.\n\n     2. Redistributions in binary form must reproduce the above copyright\n        notice, this list of conditions and the following disclaimer in the\n        documentation and/or other materials provided with the distribution.\n\n     3. The names of its contributors may not be used to endorse or promote \n        products derived from this software without specific prior written \n        permission.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER\n   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n   Any feedback is very welcome.\n   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html\n   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)\n*/\n\n#include \"rng.h\"\n\n/* NOTE changes made on 2005/9/7 by Neil Burch - if you have problems\n   with this code, DON'T complain to Makoto Matsumoto... */\n\n\n/* initializes mt[RNG_N] with a seed */\nvoid init_genrand( rng_state_t *state, uint32_t s )\n{\n  state->mt[0]= s & 0xffffffffUL;\n  for (state->mti=1; state->mti<RNG_N; state->mti++) {\n    state->mt[state->mti] = \n      (1812433253UL * (state->mt[state->mti-1]\n\t\t       ^ (state->mt[state->mti-1] >> 30))\n       + state->mti); \n    /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */\n    /* In the previous versions, MSBs of the seed affect   */\n    /* only MSBs of the array mt[].                        */\n    /* 2002/01/09 modified by Makoto Matsumoto             */\n  }\n}\n\n/* initialize by an array with array-length */\n/* init_key is the array for initializing keys */\n/* key_length is its length */\n/* slight change for C++, 2004/2/26 */\nvoid init_by_array( rng_state_t *state, uint32_t init_key[], int key_length )\n{\n  int i, j, k;\n\n  init_genrand(state, 19650218UL);\n  i=1; j=0;\n  k = (RNG_N>key_length ? RNG_N : key_length);\n  for (; k; k--) {\n    state->mt[i] = ( state->mt[i]\n\t\t     ^ ( ( state->mt[i-1] ^ ( state->mt[i-1] >> 30 ) )\n\t\t\t * 1664525UL ) )\n      + init_key[j] + j; /* non linear */\n    i++; j++;\n    if (i>=RNG_N) { state->mt[0] = state->mt[RNG_N-1]; i=1; }\n    if (j>=key_length) j=0;\n  }\n  for (k=RNG_N-1; k; k--) {\n    state->mt[i] = ( state->mt[i]\n\t\t     ^ ( ( state->mt[i-1] ^ ( state->mt[i-1] >> 30 ) )\n\t\t\t * 1566083941UL ) )\n      - i; /* non linear */\n    state->mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */\n    i++;\n    if (i>=RNG_N) { state->mt[0] = state->mt[RNG_N-1]; i=1; }\n  }\n\n  state->mt[0]|= 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ \n}\n\n/* generates a random number on [0,0xffffffff]-interval */\nuint32_t genrand_int32( rng_state_t *state )\n{\n    uint32_t y;\n    static uint32_t mag01[2]={0x0UL, MATRIX_A};\n    /* mag01[x] = x * MATRIX_A  for x=0,1 */\n\n    if (state->mti == RNG_N) { /* generate RNG_N words at one time */\n        int kk;\n\n        for (kk=0;kk<RNG_N-RNG_M;kk++) {\n            y = (state->mt[kk]&UPPER_MASK)|(state->mt[kk+1]&LOWER_MASK);\n            state->mt[kk] = state->mt[kk+RNG_M] ^ (y >> 1) ^ mag01[y & 0x1UL];\n        }\n        for (;kk<RNG_N-1;kk++) {\n            y = (state->mt[kk]&UPPER_MASK)|(state->mt[kk+1]&LOWER_MASK);\n            state->mt[kk] =\n\t      state->mt[kk+(RNG_M-RNG_N)] ^ (y >> 1) ^ mag01[y & 0x1UL];\n        }\n        y = (state->mt[RNG_N-1]&UPPER_MASK)|(state->mt[0]&LOWER_MASK);\n        state->mt[RNG_N-1] = state->mt[RNG_M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];\n\n        state->mti = 0;\n    }\n  \n    y = state->mt[state->mti++];\n\n    /* Tempering */\n    y ^= (y >> 11);\n    y ^= (y << 7) & 0x9d2c5680UL;\n    y ^= (y << 15) & 0xefc60000UL;\n    y ^= (y >> 18);\n\n    return y;\n}\n"
  },
  {
    "path": "ACPCServer/rng.h",
    "content": "/*\n   Copyright (C) 2011 by the Computer Poker Research Group, University of \n   Alberta\n   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,\n   All rights reserved.                          \n*/\n\n#ifndef _RNG_H\n#define _RNG_H\n#define __STDC_FORMAT_MACROS\n#include <inttypes.h>\n\n\n/* functions included in Takuji Nishimura and Makoto Matsumoto's RNG code */\n/* NOTE changes made on 2005/9/7 by Neil Burch - if you have problems\n   with this code, DON'T complain to Makoto Matsumoto... */\n\n\n/* Period parameters */  \n#define RNG_N 624\n#define RNG_M 397\n#define MATRIX_A 0x9908b0dfUL   /* constant vector a */\n#define UPPER_MASK 0x80000000UL /* most significant w-r bits */\n#define LOWER_MASK 0x7fffffffUL /* least significant r bits */\n\n\ntypedef struct {\nuint32_t mt[ RNG_N ];\nint mti;\n} rng_state_t;\n\n\n/* initializes rng state using an integer seed */\nvoid init_genrand( rng_state_t *state, uint32_t s );\n\n/* initialize by an array with array-length */\n/* init_key is the array for initializing keys */\n/* key_length is its length */\nvoid init_by_array( rng_state_t *state, uint32_t init_key[], int key_length );\n\n\n/* all of the functions below can not be called until init_* has been called */\n\n/* generates a random number on [0,0xffffffff]-interval */\nuint32_t genrand_int32( rng_state_t *state );\n\n/* generates a random number on [0,0xffffffff]-interval */\n#define genrand_int31(state) ((int32_t)(genrand_int32(state)>>1))\n\n/* These real versions are due to Isaku Wada, 2002/01/09 added */\n/* generates a random number on [0,1]-real-interval */\n#define genrand_real1(state) (genrand_int32(state)*(1.0/4294967295.0))\n\n/* generates a random number on [0,1)-real-interval */\n#define genrand_real2(state) (genrand_int32(state)*(1.0/4294967296.0))\n\n/* generates a random number on (0,1)-real-interval */\n#define genrand_real3(state) ((((double)genrand_int32(state))+0.5)*(1.0/4294967296.0))\n\n/* generates a random number on [0,1) with 53-bit resolution*/\n#define genrand_res53(state) (((genrand_int32(state)>>5)*67108864.0+(genrand_int32(state)>>6))*(1.0/9007199254740992.0))\n\n#endif\n"
  },
  {
    "path": "ACPCServer/sum_values.pl",
    "content": "#!/usr/bin/perl\n\n#Copyright (C) 2014 by the Computer Poker Research Group, University of Alberta\n\nwhile( $_ = <> ) {\n\n    chomp $_;\n    @_ = split /:/, $_;\n    if( $_[ 0 ] ne \"STATE\" || @_ != 6 ) {\n\n\tnext;\n    }\n\n    @values = split /\\|/, $_[ 4 ];\n    @players = split /\\|/, $_[ 5 ];\n    $#values == $#players or die \"badly formed line: $_\";\n\n    for( $i = 0; $i < @players; ++$i ) {\n\n\t$totals{ $players[ $i ] } += $values[ $i ];\n    }\n}\n\nprint \"SCORE:\";\n@players = keys( %totals );\nfor( $i = 0; $i < @players; ++$i ) {\n\n    if( $i ) {\n\n\tprint \"|\";\n    }\n    print $totals{ $players[ $i ] };\n}\nfor( $i = 0; $i < @players; ++$i ) {\n\n    if( $i ) {\n\n\tprint \"|\";\n    }\n    print $players[ $i ];\n}\nprint \"\\n\";\n"
  },
  {
    "path": "ACPCServer/validate_submission.pl",
    "content": "#!/usr/bin/perl -w\n\n# Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n\nuse strict;\n\nuse POSIX;\nuse File::Path;\nuse File::Copy;\nuse File::Spec;\nuse File::stat;\nuse Getopt::Long;\nuse Pod::Usage;\n\n###############\n# Main script #\n###############\n\n# There are several variables that should be set here by the competition\n# organizer specifying what minimum length of testing is desired\n\nmy $max_submission_size = 50 * ( 1024 ** 3 ); # 50Gb of disk\nmy $max_avg_millisec_per_hand = 7 * 1000; # 7 sec average per hand\nmy $max_response_millisec = 10 * 60 * 1000; #10 minute max per response\nmy $max_millisec_per_hand = $max_avg_millisec_per_hand * 3000; # Unconstrained\nmy $max_shutdown_secs = 10; # Agents have 10 seconds to shutdown after a match\nmy $min_test_hands = 12000; \nmy $num_test_hands = 12000;\n\nmy %game_types = (\n  \"submission_2pl\" => {\n    game_def => \"holdem.limit.2p.reverse_blinds.game\",\n    chump => \"example_player.limit.2p.sh\",\n    num_hands => 3000,\n    big_blind => 10,\n    players => 2\n  },\n  \"submission_2pn\" => {\n    game_def => \"holdem.nolimit.2p.reverse_blinds.game\",\n    chump => \"example_player.nolimit.2p.sh\",\n    num_hands => 3000,\n    big_blind => 100,\n    players => 2\n  },\n  \"submission_3pl\" => {\n    game_def => \"holdem.limit.3p.game\",\n    chump => \"example_player.limit.3p.sh\",\n    num_hands => 1000,\n    big_blind => 10,\n    players => 3\n  }\n# For the possibility of future 3p_nolimit games\n#  \"3p_nolimit\" => {\n#    gamedef => \"holdem.nolimit.3p.game\",\n#    chump => \"example_player.nolimit.3p.sh\",\n#    num_hands => 1000,\n#    big_blind => 100,\n#    players => 3\n#  }\n);\n\nmy $man;\nmy $help;\n\n# Parse command line arguments\nGetOptions( 'help' => \\$help, 'man' => \\$man, \n            'num_hands=i' => \\$num_test_hands )\n  or pod2usage( -exitstatus => 2,\n                -message => \"Invalid arguments.\\n\" .\n                            \"Use --help or --man for detailed usage.\" );\n\npod2usage( -verbose => 1 ) if( $help );\npod2usage( -verbose => 2 ) if( $man );\n$#ARGV >= 0\n  or pod2usage( -exitstatus => 2,\n                -message => \"Insufficient arguments.\\n\" .\n                            \"Use --help or --man for detailed usage.\" );\n\n( $num_test_hands >= $min_test_hands )\n  or die \"Must play at least $min_test_hands hands for validation, stopped\";\n\n# Set up file paths\nmy $submission_path = File::Spec->rel2abs( $ARGV[ 0 ] ) ;\nmy ( $submission_volume, $submission_dir, $submission_last_comp )\n  = File::Spec->splitpath( $submission_path );\n\nmy $validation_dir = \"$submission_path.validation\";\nmy $validation_path\n  = File::Spec->catfile( $validation_dir, \"$submission_last_comp.validation\" );\n\n# XXX: Script relies on its relative position with the rest of the code.  This\n# isn't great, but avoids other configuration files specifying this\nmy ( $volume, $directories, $test_script_file )\n  = File::Spec->splitpath( File::Spec->rel2abs( $0 )  );\nmy $scripts_dir = File::Spec->catpath( $volume, $directories, '' );\nmy $server_dir = File::Spec->catpath( $volume, $directories, '' );\nmy $test_script_path = File::Spec->catfile( $scripts_dir, $test_script_file );\nmy $dealer_path = File::Spec->catfile( $server_dir, \"dealer\" );\nmy $example_player_path = File::Spec->catfile( $server_dir, \"example_player\" );\nmy $play_match_path = File::Spec->catfile( $server_dir, \"acpc_play_match.pl\" );\n\n# Ensure we aren't overwriting an existing validation file\n( ! -e $validation_dir ) \n  or die \"ERROR: $validation_dir already exists.  Move/remove it and rerun\\n\";\n\nmkpath( $validation_dir );\n\n# Open the validation file for writing\nmy $VALIDATION;\nopen( $VALIDATION, '>', $validation_path ) \n  or die \"ERROR: Cannot open validation file $validation_path\" . \n         \"for writing: $!\\n\";\n\n# Begin validation tests\nprint $VALIDATION \"Validating $submission_path\\n\\n\";\nprint \"Validating $submission_path\\n\";\nprint \"Validation files will be placed in $validation_dir\\n\";\nprint \"Matches in progress will have output in $server_dir\\n\";\nprint \"Check $validation_path for more detailed progress or errors\\n\\n\";\n\n# Test the versions of the files using checksums\nprint $VALIDATION \"Gathering file versions (md5sums)...\\n\\n\";\n\n# Ensure the testing script is the right version\nmy $test_script_version_cmd = \"md5sum $test_script_path\";\nprint $VALIDATION \"Testing script: $test_script_path\\n\";\nprint $VALIDATION \"$test_script_version_cmd\\n\";\n\nmy $test_script_version_output = `$test_script_version_cmd 2>&1`;\nprint $VALIDATION \"$test_script_version_output\\n\";\nif( $? != 0 ) {\n  print $VALIDATION \"FAILED.\\n\";\n  print $VALIDATION \"Validation FAILED.\\n\";\n  die \"$test_script_version_cmd\\n$test_script_version_output\\n\" . \n      \"ERROR: Unable to verify testing script version, stopped\";\n}\n\n# Verify the version of the dealer program\nmy $dealer_version_cmd = \"md5sum $dealer_path\";\nprint $VALIDATION \"dealer: $dealer_path\\n\";\nprint $VALIDATION \"$dealer_version_cmd\\n\";\n\nmy $dealer_version_output = `$dealer_version_cmd 2>&1`;\nprint $VALIDATION \"$dealer_version_output\\n\";\nif( $? != 0 ) {\n  print $VALIDATION \"FAILED.\\n\";\n  print $VALIDATION \"Validation FAILED.\\n\";\n  die \"$dealer_version_cmd\\n$dealer_version_output\\n\" . \n      \"ERROR: Unable to verify dealer version, stopped\";\n}\n\n# Verify the version of the example_player program\nmy $example_player_version_cmd = \"md5sum $example_player_path\";\nprint $VALIDATION \"example_player: $example_player_path\\n\";\nprint $VALIDATION \"$example_player_version_cmd\\n\";\n\nmy $example_player_version_output = `$example_player_version_cmd 2>&1`;\nprint $VALIDATION \"$example_player_version_output\\n\";\nif( $? != 0 ) {\n  print $VALIDATION \"FAILED.\\n\";\n  print $VALIDATION \"Validation FAILED.\\n\";\n  die \"$example_player_version_cmd\\n$example_player_version_output\\n\" . \n      \"ERROR: Unable to verify example_player version, stopped\";\n}\n\n# Verify the version of the play_match program\nmy $play_match_version_cmd = \"md5sum $play_match_path\";\nprint $VALIDATION \"play_match: $play_match_path\\n\";\nprint $VALIDATION \"$play_match_version_cmd\\n\";\n\nmy $play_match_version_output = `$play_match_version_cmd 2>&1`;\nprint $VALIDATION \"$play_match_version_output\\n\";\nif( $? != 0 ) {\n  print $VALIDATION \"FAILED.\\n\";\n  print $VALIDATION \"Validation FAILED.\\n\";\n  die \"$play_match_version_cmd\\n$play_match_version_output\\n\" . \n      \"ERROR: Unable to verify play_match.pl version, stopped\";\n}\n\n# Test for what kind of submission it is (i.e., which game)\nmy $game_label = undef;\nprint $VALIDATION \"Checking for game label... \";\nforeach my $game ( keys( %game_types ) ) {\n  if( $submission_last_comp eq $game ) {\n    $game_label = $game;\n    print $VALIDATION \"PASSED.  Found $game_label\\n\\n\";\n    last;\n  }\n}\n\nif( not defined $game_label ) {\n  $, = \", \"; # Sets the list printing separator\n  print $VALIDATION \" FAILED.\\n\";\n  print $VALIDATION \"Unrecognized directory name $submission_last_comp\\n\";\n  print $VALIDATION \"Submission directory must be one of: \",\n  print $VALIDATION keys( %game_types );\n  print $VALIDATION \"\\n\";\n  print $VALIDATION \"Validation FAILED.\\n\";\n  die \"ERROR: Unrecognized submission directory name, stopped\";\n}\n\nmy $agent_name;\nif( -d $submission_path ) {\n  $agent_name = ( File::Spec->splitdir( $submission_path ) )[ -1 ];\n} else {\n  print $VALIDATION \"FAILED.\\n\";\n  print $VALIDATION \"$submission_path is not a directory.\\n\";\n  print $VALIDATION \"Validation FAILED.\\n\";\n  die \"ERROR: Expected a directory, stopped\";\n}\n\n# Check if the directory contains a README file\nprint $VALIDATION \"Checking for README file... \";\nif( -e File::Spec->catfile( $submission_path, \"README\" ) ) {\n  print $VALIDATION \"PASSED.\\n\\n\";\n} else {\n  print $VALIDATION \"FAILED.\\n\";\n  print $VALIDATION \"Validation FAILED.\\n\";\n  die \"ERROR: Missing README file, stopped\";\n}\n\n# Check if the directory contains an executable startme.sh script\nprint $VALIDATION \"Checking for executable startme.sh script... \";\nmy $startme_stat = stat( File::Spec->catfile( $submission_path, \"startme.sh\" ) );\nif( $startme_stat ) {\n  my $mode = $startme_stat->mode;\n  my $perm_mask = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;\n  my $perm_str = sprintf( \"%03o\", $perm_mask & 00777 );\n  # Test if the file has the same permissions as the mask\n  if( ( $mode & $perm_mask ) == $perm_mask ) {\n    print $VALIDATION \"PASSED.\\n\\n\";\n  } else {\n    print $VALIDATION \"FAILED.\\n\";\n    print $VALIDATION \"startme.sh must have at least $perm_str permissions\\n\";\n    print $VALIDATION \"Validation FAILED.\\n\";\n    die \"ERROR: startme.sh must have at least $perm_str permissions, stopped\";\n  }\n} else {\n  print $VALIDATION \"FAILED.\\n\";\n  print $VALIDATION \"Validation FAILED.\\n\";\n  die \"ERROR: Unable to stat startme.sh file: $!, stopped\";\n}\n\n# Check if the uncompressed size of the agent submission directory is too big \n# NOTE: This isn't done is a very platorm independent way.  du does not always\n# have -b available (not to mention other OSes).  Should probably just walk the\n# file structure ourselves.\nprint $VALIDATION \"Checking $submission_path for uncompressed file size... \";\nmy $agent_size_cmd = \"du -bc $submission_path\";\nmy @agent_size_output = `$agent_size_cmd 2>&1`;\n# $? is the return value of the backtick command, test it for failure\nif( $? == 0 ) {\n  my @fields = split( /\\W/, $agent_size_output[ -1 ] );\n  my $agent_size = $fields[ 0 ];\n  if( $agent_size <= $max_submission_size ) {\n    print $VALIDATION \"PASSED.  ($agent_size bytes)\\n\\n\";\n  } else {\n    print $VALIDATION \"FAILED.\\n\";\n    print $VALIDATION \"Validation FAILED.\\n\";\n    die \"ERROR: $submission_path is too large, stopped\";\n  }\n} else {\n  $, = \"\"; # Sets the list printing separator\n  print $VALIDATION \"FAILED.\\n\";\n  print $VALIDATION \"Validation FAILED.\\n\";\n  die \"$agent_size_cmd\\n@agent_size_output\\n\" . \n      \"ERROR: Unable to get agent directory size, stopped\";\n}\n\n# Run the submitted agent for the specified number of trial hands.\nmy $matches_played = 0;\nmy $min_matches = ceil( $num_test_hands / \n                        $game_types{ $game_label }{ num_hands } );\n\nmy $total_decision_time = 0;\nmy $total_score = 0;\n\nmy $game_def = $game_types{ $game_label }{ game_def };\nmy $num_players = $game_types{ $game_label }{ players };\nmy $num_hands = $game_types{ $game_label }{ num_hands };\nmy $big_blind = $game_types{ $game_label }{ big_blind };\nmy $example_player_startme_path\n  = File::Spec->catfile( $server_dir, $game_types{ $game_label }{ chump } );\n\nprint \"Running matches...\\n\";\n# Change directory to the server directory as play_match relies on relative\n# paths from that directory\nchdir( $server_dir ) or die \"Unable to chdir to $server_dir: $!, stopped\";\n# Play all of the matches needed to at least meet the minimum hand count\nwhile( $matches_played < $min_matches ) {\n  my ( $match_start_time, $match_end_time );\n  my $match_name = \"$agent_name.test_match.$matches_played\";\n\n  # TODO?: Should the generated shell scripts be used to run the agent\n  # If not, then files could be left over or we may not detect issues with\n  # using the scripts\n\n  # Construct the command for running a match\n  my $match_cmd = \"$play_match_path $match_name $game_def $num_hands \" . \n                  \"$matches_played $agent_name $submission_path/startme.sh\";\n  # Add the remaining players \n  for( my $player = 1; $player < $num_players; $player++ ) {\n    $match_cmd = $match_cmd .  \" chump\" . \n      ( $num_players > 2 ? \"-$player\" : \"\" ) . \" $example_player_startme_path\"\n  }\n  # Add the server timing options\n  $match_cmd = $match_cmd . \" --t_per_hand $max_avg_millisec_per_hand \" .\n               \"--t_response $max_response_millisec \" . \n               \"--t_hand $max_millisec_per_hand\";\n\n  # Give some visual output of progress\n  print \"Match \", $matches_played + 1, \n        \" of $min_matches: $match_name\\n\";\n  print $VALIDATION \"========== Match \", $matches_played + 1, \n        \" of $min_matches: $match_name ==========\\n\";\n\n  # Ensure no other startme.sh script are running prior to the next match\n  print $VALIDATION \"Checking for existing agents... \";\n  my $lingering_agent_cmd = \"ps -eo command\";\n  my @lingering_agent_output = `$lingering_agent_cmd 2>&1`;\n  # $? is the return value of the backtick command, test it for failure\n  if( $? == 0 ) {\n    my @lingering_agents = grep { /startme\\.sh/ } @lingering_agent_output;\n    if( @lingering_agents == 0 ) {\n      print $VALIDATION \"PASSED.\\n\\n\";\n    } else {\n      $, = \"\\n\"; # Sets the list printing separator\n      print $VALIDATION \"FAILED.\\n\";\n      print $VALIDATION \"Found the following existing agents:\\n\";\n      print $VALIDATION @lingering_agents;\n      print $VALIDATION \"\\n\";\n      print $VALIDATION \"Stop other agents before proceeding with testing\\n\";\n      print $VALIDATION \"Validation FAILED.\\n\";\n      die \"ERROR: lingering startme.sh found before match $match_name, stopped\";\n    }\n  } else {\n    $, = \"\"; # Sets the list printing separator\n    print $VALIDATION \"FAILED.\\n\";\n    print $VALIDATION \"Validation FAILED.\\n\";\n    die \"$lingering_agent_cmd\\n@lingering_agent_output\\n\" . \n        \"ERROR: Unable to get processes to check for lingering agents, stopped\";\n  }\n\n  print $VALIDATION \"$match_cmd\\n\\n\";\n\n  # Collect timing statistics for the run.\n  $match_start_time = time();\n  my $match_output = `$match_cmd 2>&1`;\n  $match_end_time = time();\n\n  # Move any available output files to the $validation_dir\n  foreach my $file ( glob( \"$server_dir/$match_name*\" ) ) {\n    move( $file, $validation_dir );\n  }\n\n  chomp( $match_output );\n  print $VALIDATION \"$match_output\\n\";\n\n  if( $? != 0 ) {\n    print $VALIDATION \"FAILED.\\n\";\n    print $VALIDATION \"Validation FAILED.\\n\";\n    die \"$match_cmd\\n$match_output\\n\" . \n        \"ERROR: Match $agent_name.test_match.$matches_played FAILED \" .\n        \"(returned $?).\\n\" .\n        \"Check match log files in validation directory for cause, stopped\";\n  }\n\n  # Extract the score from the dealer output \n  # e.g., SCORE:-1430|1430:2p_limit_foo|chump\n  my $scores = ( split( /:/, $match_output ) )[ 1 ];\n  $total_score += ( split( /\\|/, $scores ) )[ 0 ];\n  $matches_played++;\n  $total_decision_time += $match_end_time - $match_start_time;\n\n  # Verify that the agent is shutting down correctly \n  print $VALIDATION \"Checking for lingering agents... \";\n  # Wait a short while to give the agent time to exit after the match \n  sleep( $max_shutdown_secs );\n  @lingering_agent_output = `$lingering_agent_cmd 2>&1`;\n  # $? is the return value of the backtick command, test it for failure\n  if( $? == 0 ) {\n    my @lingering_agents = grep { /startme\\.sh/ } @lingering_agent_output;\n    if( @lingering_agents == 0 ) {\n      print $VALIDATION \"PASSED.\\n\\n\";\n    } else {\n      $, = \"\\n\"; # Sets the list printing separator\n      print $VALIDATION \"FAILED.\\n\";\n      print $VALIDATION \"Found the following lingering agents:\\n\";\n      print $VALIDATION @lingering_agents;\n      print $VALIDATION \"\\n\";\n      print $VALIDATION \"Validation FAILED.\\n\";\n      die \"ERROR: lingering startme.sh found after match $match_name, stopped\";\n    }\n  } else {\n    print $VALIDATION \"FAILED.\\n\";\n    print $VALIDATION \"Validation FAILED.\\n\";\n    die \"$lingering_agent_cmd\\n@lingering_agent_output\\n\" . \n        \"ERROR: Unable to get processes to check for lingering agents, stopped\";\n  }\n  \n  # Check for any warnings in the output\n  print $VALIDATION \"Checking $match_name.err output for errors/warnings... \";\n\n  if( not open( DEALER_STDERR, \n      File::Spec->catfile( $validation_dir, \"$match_name.err\" ) ) ) {\n    print $VALIDATION \"FAILED.\\n\";\n    print $VALIDATION \"Unable to open $match_name.err for reading: $!\\n\";\n    print $VALIDATION \"Validation FAILED.\\n\";\n    die \"ERROR: Cannot open $match_name.err for reading to check for \" . \n        \"errors in match $match_name: $!, stopped\";\n  }\n\n  my @match_warnings = grep { /(WARNING|ERROR)/ } <DEALER_STDERR>;\n  close DEALER_STDERR;\n  \n  if( @match_warnings == 0 ) {\n    print $VALIDATION \"PASSED.\\n\\n\";\n  } else {\n    $, = \"\"; # Sets the list printing separator\n    print $VALIDATION \"FAILED.\\n\";\n    print $VALIDATION \"Found the following warnings/errors:\\n\";\n    print $VALIDATION @match_warnings;\n    print $VALIDATION \"\\n\";\n    print $VALIDATION \"Validation FAILED.\\n\";\n    die \"ERROR: dealer warnings detected in match $match_name, stopped\";\n  }\n}\n\nprint $VALIDATION \"========= Test match statistics ==========\\n\";\nprint $VALIDATION \"Matches played: $matches_played\\n\";\nprint $VALIDATION \"Hands played: \", ( $matches_played * $num_hands ), \"\\n\";\nprint $VALIDATION \"Average time per hand (seconds): \", \n                  $total_decision_time / ( $matches_played * $num_hands ), \"\\n\";\nprint $VALIDATION \"Average time per match (seconds): \", \n                  $total_decision_time / $matches_played, \"\\n\";\n\nmy $performance\n  = ( 1000 * $total_score ) / ( $big_blind * $matches_played * $num_hands );\nprint $VALIDATION \"Performance (milli big blinds per hand): \", \n                  $performance, \"\\n\";\n\nprint $VALIDATION \"Checking for winning performance... \";\nif( $performance >= 0 ) {\n  print $VALIDATION \"PASSED.\\n\\n\";\n} else {\n  print $VALIDATION \"FAILED.\\n\";\n  print $VALIDATION \"Validation FAILED.\\n\";\n  die \"ERROR: Submission unable to beat chump in test matches, stopped\";\n}\n\n# Print completion messages\nprint \"Validation PASSED.\\n\";\n\nprint $VALIDATION \"Validation PASSED.\\n\";\n\nclose $VALIDATION;\n\n# POD Documentation for usage message\n__END__\n\n=head1 NAME\n\nB<validate_submission.pl> - Checks that the sepcified submission file for the\nAnnual Computer Poker Competition is well formed and works.\n\n=head1 SYNOPSIS\n\nB<validate_submission.pl> [options] submission_dir\n\n=head1 DESCRIPTION\n\nB<validate_submission.pl> - Tests that the specified submission file passes\nbasic sanity checks expected of entries in the Annual Computer Poker\nCompetition.  This process could take a long time depending on the\nsize of your submission file and the rate at which it plays.\n\nNote that this script expects that your agent:\n\n=over 8\n\n=item *\n\nIs contained in a single directory named submission_2pl, submission_2pn\nor submission_3pl\n\n=item * \n\nHas an startme.sh script with permissions of at least 755 at the root of your\ndirectory\n\n=item * \n\nHas a README file at the root of your directory\n\n=item * \n\nIs within the size limit\n\n=item * \n\nPlays only valid actions\n\n=item * \n\nCleans itself up once the match is over \n\n=item * \n\nBeats an agent that plays randomly and does not look at its cards\n\n=back \n\nFailure on any of these points will cause the validation to fail.  Futhermore,\nensure that you are B<only running one test script at a time> as they will\ninterfere with each other.\n\nThe required argument is:\n\n=over 8\n\n=item B<submission_dir>\n\nA path to a submission directory that you want to check for basic correctness\n\n=back\n\n=head1 OPTIONS\n\n=over 8\n\n=item B<--help>\n\nPrint a brief help message and exits.\n\n=item B<--man>\n\nPrints the manual page and exits.\n\n=item B<--num_hands=[positive integer]>\n\nSet the number of hands you want to test for.  Defaults to the minimum number\nof hands for validation.  Please run as many as you can.\n\n=back\n\n=cut\n"
  },
  {
    "path": "Data/.gitignore",
    "content": "Dot/\nTrainSamples/\n*epoch*.info\n*epoch*.model\n"
  },
  {
    "path": "Source/ACPC/Tests/test_parser.lua",
    "content": "require \"ACPC.protocol_to_node\"\n\nlocal protocol_to_node = ACPCProtocolToNode()\nlocal state = protocol_to_node:parse_state(\"MATCHSTATE:0:99:cc/r8146:Kh|/As\")\n\nlocal debug = 0"
  },
  {
    "path": "Source/ACPC/acpc_game.lua",
    "content": "--- Handles communication to and from DeepStack using the ACPC protocol.\n--\n-- For details on the ACPC protocol, see\n-- <http://www.computerpokercompetition.org/downloads/documents/protocols/protocol.pdf>.\n-- @classmod acpc_game\nrequire 'ACPC.network_communication'\nrequire 'ACPC.protocol_to_node'\nlocal arguments = require 'Settings.arguments'\nlocal constants = require \"Settings.constants\"\n\n--if you want to fake what messages the acpc dealer sends, put them in the following list and uncomment it.\nlocal debug_msg = nil--{\"MATCHSTATE:0:99::Kh|/\", \"MATCHSTATE:0:99:cr200:Kh |/\", \"MATCHSTATE:0:99:cr200:Kh|/Ks\"}\n\nlocal ACPCGame = torch.class('ACPCGame')\n\n--- Constructor\nfunction ACPCGame:__init()\n  self.protocol_to_node = ACPCProtocolToNode()\nend\n\n--- Connects to a specified ACPC server which acts as the dealer.\n--\n-- @param server the server that sends states to DeepStack, which responds\n-- with actions\n-- @param port the port to connect on\n-- @see network_communication.connect\nfunction ACPCGame:connect(server, port)\n  if not debug_msg then\n    self.network_communication = ACPCNetworkCommunication()\n    self.network_communication:connect(server, port)\n  end\nend\n\nfunction ACPCGame:string_to_statenode(msg)\n  local parsed_state = self.protocol_to_node:parse_state(msg)\n  --current player to act is us\n  if parsed_state.acting_player == parsed_state.position then\n    --we should not act since this is an allin situations\n    if parsed_state.bet1 == parsed_state.bet2 and parsed_state.bet1 == arguments.stack then\n      print(\"Not our turn - all in\")\n    --we should act\n    else\n      print(\"Our turn\")\n\n      self.last_msg = msg\n      --create a tree node from the current state\n      local node = self.protocol_to_node:parsed_state_to_node(parsed_state)\n\n      return parsed_state, node\n    end\n  --current player to act is the opponent\n  else\n    print(\"Not our turn\")\n  end\n  return nil, nil\nend\n\n--- Receives and parses the next poker situation where DeepStack must act.\n--\n-- Blocks until the server sends a situation where DeepStack acts.\n-- @return the parsed state representation of the poker situation (see\n-- @{protocol_to_node.parse_state})\n-- @return a public tree node for the state (see\n-- @{protocol_to_node.parsed_state_to_node})\nfunction ACPCGame:get_next_situation()\n  while true do\n    local msg = nil\n\n    --1.0 get the message from the dealer\n    if not debug_msg then\n      msg = self.network_communication:get_line()\n    else\n      msg = table.remove(debug_msg, 1)\n    end\n\n    print(\"Received acpc dealer message:\")\n    print(msg)\n\n    --2.0 parse the string to our state representation\n    local parsed_state = self.protocol_to_node:parse_state(msg)\n\n    --3.0 figure out if we should act\n\n    --current player to act is us\n    if parsed_state.acting_player == parsed_state.position then\n      --we should not act since this is an allin situations\n      if parsed_state.bet1 == parsed_state.bet2 and parsed_state.bet1 == arguments.stack then\n        print(\"Not our turn - alling\")\n      --we should act\n      else\n        print(\"Our turn\")\n\n        self.last_msg = msg\n        --create a tree node from the current state\n        local node = self.protocol_to_node:parsed_state_to_node(parsed_state)\n\n        return parsed_state, node\n      end\n    --current player to act is the opponent\n    else\n      print(\"Not our turn\")\n    end\n  end\nend\n\n--- Informs the server that DeepStack is playing a specified action.\n-- @param adviced_action a table specifying the action chosen by Deepstack,\n-- with the fields:\n--\n-- * `action`: an element of @{constants.acpc_actions}\n--\n-- * `raise_amount`: the number of chips raised (if `action` is raise)\nfunction ACPCGame:play_action(adviced_action)\n  local message = self.protocol_to_node:action_to_message(self.last_msg, adviced_action)\n  print(\"Sending a message to the acpc dealer:\")\n  print(message)\n\n  if not debug_msg then\n    self.network_communication:send_line(message)\n  end\nend\n"
  },
  {
    "path": "Source/ACPC/network_communication.lua",
    "content": "--- Handles network communication for DeepStack.\n-- \n-- Requires [luasocket](http://w3.impa.br/~diego/software/luasocket/)\n-- (can be installed with `luarocks install luasocket`).\n-- @classmod network_communication\nlocal arguments = require \"Settings.arguments\"\nlocal socket = require \"socket\"\n\nlocal ACPCNetworkCommunication = torch.class('ACPCNetworkCommunication')\n\n--- Constructor\nfunction ACPCNetworkCommunication:_init()\nend\n\n--- Connects over a network socket.\n-- \n-- @param server the server that sends states to DeepStack, and to which\n-- DeepStack sends actions\n-- @param port the port to connect on\nfunction ACPCNetworkCommunication:connect(server, port)\n  server = server or arguments.acpc_server\n  port = port or arguments.acpc_server_port\n\n  self.connection = assert(socket.connect(server, port))\n\n  self:_handshake()\nend\n\n--- Sends a handshake message to initialize network communication.\n-- @local\nfunction ACPCNetworkCommunication:_handshake()\n    self:send_line(\"VERSION:2.0.0\")\nend\n\n--- Sends a message to the server.\n-- @param line a string to send to the server\nfunction ACPCNetworkCommunication:send_line(line)\n  self.connection:send(line .. '\\r\\n') \nend\n\n--- Waits for a text message from the server. Blocks until a message is\n-- received.\n-- @return the message received\nfunction ACPCNetworkCommunication:get_line()  \n  local out, status = self.connection:receive('*l')  \n  \n  assert(status ~= \"closed\")  \n  return out\nend\n\n--- Ends the network communication.\nfunction ACPCNetworkCommunication:close()  \n  self.connection:close()\nend"
  },
  {
    "path": "Source/ACPC/protocol_to_node.lua",
    "content": "--- Converts between DeepStack's internal representation and the ACPC protocol\n-- used to communicate with the dealer.\n--\n-- For details on the ACPC protocol, see\n-- <http://www.computerpokercompetition.org/downloads/documents/protocols/protocol.pdf>.\n-- @classmod protocol_to_node\nlocal arguments = require 'Settings.arguments'\nlocal constants = require \"Settings.constants\"\nlocal tools = require 'tools'\nlocal card_tools = require 'Game.card_tools'\nlocal card_to_string = require \"Game.card_to_string_conversion\"\n\nlocal ACPCProtocolToNode = torch.class('ACPCProtocolToNode')\n\n--- Constructor\nfunction ACPCProtocolToNode:_init()\nend\n\n--- Checks if a string starts with a given substring.\n-- @param string the string to check\n-- @param start the substring to check as the prefix of `String`\n-- @return `true` if `start` is a prefix of `string`\n-- @local\nfunction string.starts(string,start)\n   return string.sub(string,1,string.len(start))==start\nend\n\n--- Parses a list of actions from a string representation.\n-- @param actions a string representing a series of actions in ACPC format\n-- @return a list of actions, each of which is a table with fields:\n--\n-- * `action`: an element of @{constants.acpc_actions}\n--\n-- * `raise_amount`: the number of chips raised (if `action` is raise)\n-- @local\nfunction ACPCProtocolToNode:_parse_actions(actions)\n\n  local out = {}\n  local actions_remainder = actions\n\n  while actions_remainder ~= '' do\n\n    local parsed_chunk = ''\n    if string.starts(actions_remainder, \"c\") then\n      table.insert(out, {action = constants.acpc_actions.ccall})\n      parsed_chunk = \"c\"\n    elseif string.starts(actions_remainder, \"r\") then\n      local _\n      local raise_amount\n      _, _, raise_amount = string.find(actions_remainder, \"^r(%d*).*\")\n      raise_amount = tonumber(raise_amount)\n      table.insert(out, {action = constants.acpc_actions.raise, raise_amount = raise_amount})\n      parsed_chunk = \"r\" .. raise_amount\n    elseif string.starts(actions_remainder, \"f\") then\n      table.insert(out, {action = constants.acpc_actions.fold})\n      parsed_chunk = \"f\"\n    else\n      assert(false)\n    end\n\n    assert(#parsed_chunk > 0)\n    actions_remainder = string.sub(actions_remainder, #parsed_chunk + 1)\n  end\n\n\n  return out\nend\n\n--- Parses a set of parameters that represent a poker state, from a string\n-- representation.\n-- @param state a string representation of a poker state in ACPC format\n-- @return a table of state parameters, containing the fields:\n--\n-- * `position`: the acting player\n--\n-- * `hand_id`: a numerical id for the hand\n--\n-- * `actions`: a list of actions which reached the state, for each\n-- betting round - each action is a table with fields:\n--\n--     * `action`: an element of @{constants.acpc_actions}\n--\n--     * `raise_amount`: the number of chips raised (if `action` is raise)\n--\n-- * `actions_raw`: a string representation of actions for each betting round\n--\n-- * `board`: a string representation of the board cards\n--\n-- * `hand_p1`: a string representation of the first player's private hand\n--\n-- * `hand_p2`: a string representation of the second player's private hand\n-- @local\nfunction ACPCProtocolToNode:_parse_state(state)\n\n  --MATCHSTATE:0:99:cc/r8146c/cc/cc:4cTs|Qs9s/9h5d8d/6c/6d\n  local cards\n  local actions\n  local position\n  local hand_id\n  local _\n\n  _, _, position, hand_id, actions, cards = string.find(state, \"^MATCHSTATE:(%d):(%d*):([^:]*):(.*)\")\n\n  --print('position: ', position)\n  --print('actions: ', actions)\n  --print('cards: ', cards)\n\n  --cc/r8146c/cc/cc\n  local preflop_actions\n  local flop_actions\n  local turn_actions\n  local river_actions\n    _, _, preflop_actions, flop_actions, turn_actions, river_actions = string.find(actions, \"([^/]*)/?([^/]*)/?([^/]*)/?([^/]*)\")\n\n  --print('preflop_actions: ', preflop_actions)\n  --print('flop_actions: ', flop_actions)\n  --print('turn_actions: ', turn_actions)\n  --print('river_actions: ', river_actions)\n\n  --4cTs|Qs9s/9h5d8d/6c/6d\n  local hand_p1\n  local hand_p2\n  local flop = \"\"\n  local turn = \"\"\n  local river = \"\"\n\n   _, _, hand_p1, hand_p2, flop, turn, river = string.find(cards, \"([^|]*)|([^/]*)/?([^/]*)/?([^/]*)/?([^/]*)\")\n  --print('hand_p1: ', hand_p1)\n -- print('hand_p2: ', hand_p2)\n -- print('flop: ', flop)\n  --print('turn: ', turn)\n  --print('river: ', river)\n\n  local out = {}\n\n  out.position = position\n  out.hand_id = hand_id\n\n  out.actions = {}\n  out.actions[1] = self:_parse_actions(preflop_actions)\n  out.actions[2] = self:_parse_actions(flop_actions)\n  out.actions[3] = self:_parse_actions(turn_actions)\n  out.actions[4] = self:_parse_actions(river_actions)\n\n  out.actions_raw = {}\n  out.actions_raw[1] = preflop_actions\n  out.actions_raw[2] = flop_actions\n  out.actions_raw[3] = turn_actions\n  out.actions_raw[4] = river_actions\n\n  out.board = flop .. turn .. river\n\n  out.hand_p1 = hand_p1\n  out.hand_p2 = hand_p2\n\n  return out\nend\n\n--- Processes a list of actions for a betting round.\n-- @param actions a list of actions (see @{_parse_actions})\n-- @param street the betting round on which the actions takes place\n-- @param all_actions A list which the actions are appended to. Fields `player`,\n-- `street`, and `index` are added to each action.\n-- @local\nfunction ACPCProtocolToNode:_convert_actions_street(actions, street, all_actions)\n\n  local street_first_player = street == 1 and constants.players.P1 or constants.players.P2\n\n  for i=1, #actions do\n    local acting_player = -1\n    if i % 2 == 1 then\n      acting_player = street_first_player\n    else\n      acting_player = 3 - street_first_player\n    end\n\n    local action = actions[i]\n    action.player = acting_player\n    action.street = street\n    action.index = #all_actions + 1\n\n    table.insert(all_actions, action)\n  end\nend\n\n--- Processes all actions.\n-- @param actions a list of actions for each betting round\n-- @return a of list actions, processed with @{_convert_actions_street} and\n-- concatenated\n-- @local\nfunction ACPCProtocolToNode:_convert_actions(actions)\n\n  local all_actions = {}\n\n  for street = 1, 4 do\n    self:_convert_actions_street(actions[street], street, all_actions)\n  end\n\n  return all_actions\nend\n\n--- Further processes a parsed state into a format understandable by DeepStack.\n-- @param parsed_state a parsed state returned by @{_parse_state}\n-- @return a table of state parameters, with the fields:\n--\n-- * `position`: which player DeepStack is (element of @{constants.players})\n--\n-- * `current_street`: the current betting round\n--\n-- * `actions`: a list of actions which reached the state, for each\n-- betting round - each action is a table with fields:\n--\n--     * `action`: an element of @{constants.acpc_actions}\n--\n--     * `raise_amount`: the number of chips raised (if `action` is raise)\n--\n-- * `actions_raw`: a string representation of actions for each betting round\n--\n-- * `all_actions`: a concatenated list of all of the actions in `actions`,\n-- with the following fields added:\n--\n--     * `player`: the player who made the action\n--\n--     * `street`: the betting round on which the action was taken\n--\n--     * `index`: the index of the action in `all_actions`\n--\n-- * `board`: a string representation of the board cards\n--\n-- * `hand_id`: a numerical id for the current hand\n--\n-- * `hand_string`: a string representation of DeepStack's private hand\n--\n-- * `hand_id`: a numerical representation of DeepStack's private hand\n--\n-- * `acting_player`: which player is acting (element of @{constants.players})\n--\n-- * `bet1`, `bet2`: the number of chips committed by each player\n-- @local\nfunction ACPCProtocolToNode:_process_parsed_state(parsed_state)\n\n  local out = {}\n  --1.0 figure out the current street\n  local current_street = 1\n\n  if parsed_state.board ~= '' then\n    current_street = string.len(parsed_state.board) / 2 - 1\n  end\n\n  --print('current_street: ', current_street)\n\n\n  --2.0 convert actions to player actions\n  local all_actions\n  all_actions = self:_convert_actions(parsed_state.actions)\n\n  --print('all_actions: ', tools:table_to_string(all_actions))\n\n  --3.0 current board\n  local board = parsed_state.board\n  --print('board: ', board)\n\n  --in protocol 0=SB 1=BB, need to convert to our representation\n  out.position = parsed_state.position + 1\n  out.current_street = current_street\n  out.actions = parsed_state.actions\n  out.actions_raw = parsed_state.actions_raw\n  out.all_actions = all_actions\n  out.board = board\n  out.hand_number = parsed_state.hand_id\n\n  if out.position == constants.players.P1 then\n    out.hand_string = parsed_state.hand_p1\n  else\n    out.hand_string = parsed_state.hand_p2\n  end\n\n  out.hand_id = card_tools:string_to_hole_index(out.hand_string)\n\n  local acting_player = self:_get_acting_player(out)\n  --print('acting_player: ', acting_player)\n  out.acting_player = acting_player\n\n  --5.0 compute bets\n  local bet1\n  local bet2\n  bet1, bet2 = self:_compute_bets(out)\n  assert(bet1 <= bet2)\n\n  if out.position == constants.players.P1 then\n    out.bet1 = bet1\n    out.bet2 = bet2\n  else\n    out.bet1 = bet2\n    out.bet2 = bet1\n  end\n\n  return out\nend\n\n--- Computes the number of chips committed by each player at a state.\n-- @param processed_state a table containing the fields returned by\n-- @{_process_parsed_state}, except for `bet1` and `bet2`\n-- @return the number of chips committed by the first player\n-- @return the number of chips committed by the second player\n-- @local\nfunction ACPCProtocolToNode:_compute_bets(processed_state)\n\n  if processed_state.acting_player == -1 then\n    return -1, -1\n  end\n\n\n  local first_p1_action = {action = constants.acpc_actions.raise, raise_amount = arguments.sb, player = constants.players.P1, street = 1}\n  local first_p2_action = {action = constants.acpc_actions.raise, raise_amount = arguments.bb, player = constants.players.P2, street = 1}\n\n  local last_action = first_p2_action\n  local prev_last_action = first_p1_action\n\n  local prev_last_bet = first_p2_action\n\n  for i = 1, #processed_state.all_actions do\n\n    local action = processed_state.all_actions[i]\n    assert(action.player == constants.players.P1 or action.player == constants.players.P2)\n\n    prev_last_action = last_action\n    last_action = action\n\n    if action.action == constants.acpc_actions.raise and i <= (#processed_state.all_actions - 2) then\n      prev_last_bet = action\n    end\n  end\n\n  local bet1 = nil\n  local bet2 = nil\n\n  if last_action.action == constants.acpc_actions.raise and prev_last_action.action == constants.acpc_actions.raise then\n    bet1 = prev_last_action.raise_amount\n    bet2 = last_action.raise_amount\n  else\n\n    if last_action.action == constants.acpc_actions.ccall and prev_last_action.action == constants.acpc_actions.ccall then\n      bet1 = prev_last_bet.raise_amount\n      bet2 = prev_last_bet.raise_amount\n    else\n\n      --either ccal/raise or raise/ccal situation\n      assert(last_action.action.player ~= prev_last_action.player)\n\n      --raise/ccall\n      if last_action.action == constants.acpc_actions.ccall then\n        assert(prev_last_action.action == constants.acpc_actions.raise and prev_last_action.raise_amount)\n        bet1 = prev_last_action.raise_amount\n        bet2 = prev_last_action.raise_amount\n      else\n      --call/raise\n\n        assert(last_action.action == constants.acpc_actions.raise and last_action.raise_amount)\n        bet1 = prev_last_bet.raise_amount\n        bet2 = last_action.raise_amount\n      end\n    end\n  end\n\n  assert(bet1)\n  assert(bet2)\n\n  --print(\"bet1 :\", bet1)\n  --print(\"bet2 :\", bet2)\n\n  return bet1, bet2\nend\n\n--- Gives the acting player at a given state.\n-- @param processed_state a table containing the fields returned by\n-- @{_process_parsed_state}, except for `acting_player`, `bet1`, and `bet2`\n-- @return the acting player, as defined by @{constants.players}\n-- @local\nfunction ACPCProtocolToNode:_get_acting_player(processed_state)\n\n  if #processed_state.all_actions == 0  then\n    assert(processed_state.current_street == 1)\n    return constants.players.P1\n  end\n\n  local last_action = processed_state.all_actions[#processed_state.all_actions]\n\n  --has the street changed since the last action?\n  if last_action.street ~= processed_state.current_street then\n    return constants.players.P2\n  end\n\n  --is the hand over?\n  if last_action.action == constants.acpc_actions.fold then\n    return -1\n  end\n\n  if processed_state.current_street == 4 and #processed_state.actions[4] >= 2 and last_action.action == constants.acpc_actions.ccall then\n    return -1\n  end\n\n  --there are some actions on the current street\n  --the acting player is the opponent of the one who made the last action\n  return 3 - last_action.player\nend\n\n--- Turns a string representation of a poker state into a table understandable\n-- by DeepStack.\n-- @param state a string representation of a poker state, in ACPC format\n-- @return a table of state parameters, with the fields:\n--\n-- * `position`: which player DeepStack is (element of @{constants.players})\n--\n-- * `current_street`: the current betting round\n--\n-- * `actions`: a list of actions which reached the state, for each\n-- betting round - each action is a table with fields:\n--\n--     * `action`: an element of @{constants.acpc_actions}\n--\n--     * `raise_amount`: the number of chips raised (if `action` is raise)\n--\n-- * `actions_raw`: a string representation of actions for each betting round\n--\n-- * `all_actions`: a concatenated list of all of the actions in `actions`,\n-- with the following fields added:\n--\n--     * `player`: the player who made the action\n--\n--     * `street`: the betting round on which the action was taken\n--\n--     * `index`: the index of the action in `all_actions`\n--\n-- * `board`: a string representation of the board cards\n--\n-- * `hand_string`: a string representation of DeepStack's private hand\n--\n-- * `hand_id`: a numerical representation of DeepStack's private hand\n--\n-- * `acting_player`: which player is acting (element of @{constants.players})\n--\n-- * `bet1`, `bet2`: the number of chips committed by each player\nfunction ACPCProtocolToNode:parse_state(state)\n\n  local parsed_state = self:_parse_state(state)\n  local processed_state = self:_process_parsed_state(parsed_state)\n\n  return processed_state\nend\n\n--- Gets a representation of the public tree node which corresponds to a\n-- processed state.\n-- @param processed_state a processed state representation returned by\n-- @{parse_state}\n-- @return a table representing a public tree node, with the fields:\n--\n-- * `street`: the current betting round\n--\n-- * `board`: a (possibly empty) vector of board cards\n--\n-- * `current_player`: the currently acting player\n--\n-- * `bets`: a vector of chips committed by each player\nfunction ACPCProtocolToNode:parsed_state_to_node(processed_state)\n  local node = {}\n\n  node.street = processed_state.current_street\n  node.board = card_to_string:string_to_board(processed_state.board)\n  node.current_player = processed_state.acting_player\n  node.bets = arguments.Tensor{processed_state.bet1, processed_state.bet2}\n  if (node.bets[1] == arguments.sb and node.bets[2] == arguments.bb) or\n     (node.bets[1] == arguments.bb and node.bets[2] == arguments.sb) then\n    node.num_bets = 1\n  else\n    node.num_bets = 0\n  end\n\n  return node\nend\n\n--- Converts an action taken by DeepStack into a string representation.\n-- @param adviced_action the action that DeepStack chooses to take, with fields\n--\n-- * `action`: an element of @{constants.acpc_actions}\n--\n-- * `raise_amount`: the number of chips to raise (if `action` is raise)\n-- @return a string representation of the action\n-- @local\nfunction ACPCProtocolToNode:_bet_to_protocol_action(adviced_action)\n\n  if adviced_action.action == constants.acpc_actions.ccall then\n    return \"c\"\n  elseif adviced_action.action == constants.acpc_actions.fold then\n    return \"f\"\n  elseif adviced_action.action == constants.acpc_actions.raise then\n    return \"r\" .. adviced_action.raise_amount\n  else\n    assert(false)\n  end\nend\n\n--- Generates a message to send to the ACPC protocol server, given DeepStack's\n-- chosen action.\n-- @param last_message the last state message sent by the server\n-- @param adviced_action the action that DeepStack chooses to take, with fields\n--\n-- * `action`: an element of @{constants.acpc_actions}\n--\n-- * `raise_amount`: the number of chips to raise (if `action` is raise)\n-- @return a string messsage in ACPC format to send to the server\nfunction ACPCProtocolToNode:action_to_message(last_message, adviced_action)\n\n  local out = last_message\n\n  local protocol_action = self:_bet_to_protocol_action(adviced_action)\n\n  out = out  .. \":\" .. protocol_action\n\n  return out\nend\n"
  },
  {
    "path": "Source/DataGeneration/aux_data_generation.lua",
    "content": "--- Generates neural net training data by solving random poker situations.\n-- @module aux_data_generation\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_generator = require 'DataGeneration.random_card_generator'\nlocal card_to_string_conversion = require 'Game.card_to_string_conversion'\nlocal constants = require 'Settings.constants'\nlocal bucketer = require 'Nn.bucketer'\nlocal card_tools = require 'Game.card_tools'\n\nrequire 'Nn.bucket_conversion'\nrequire 'Nn.next_round_value_pre'\nrequire 'Nn.value_nn'\nrequire 'DataGeneration.range_generator'\nrequire 'TerminalEquity.terminal_equity'\nrequire 'Lookahead.lookahead'\nrequire 'Lookahead.resolving'\nrequire 'tools'\nlocal M = {}\n\n--- Generates training files by sampling random poker\n-- situations and solving them.\n--\n-- @param train_data_count the number of training examples to generate\nfunction M:generate_data(train_data_count, filename, street)\n  --valid data generation\n  local timer = torch.Timer()\n  timer:reset()\n\n  print('Generating auxiliary data ...')\n  self:generate_data_file(train_data_count, filename, street)\n  print('gen time: ' .. timer:time().real)\n\nend\n\n--- Generates data files containing examples of random poker situations with\n-- counterfactual values from an associated solution.\n--\n-- Each poker situation is randomly generated using @{range_generator} and\n-- @{random_card_generator}. For description of neural net input and target\n-- type, see @{net_builder}.\n--\n-- @param data_count the number of examples to generate\n-- @param file_name the prefix of the files where the data is saved (appended\n-- with `.inputs`, `.targets`, and `.mask`).\nfunction M:generate_data_file(data_count, file_name, street)\n  local range_generator = RangeGenerator()\n  local batch_size = arguments.gen_batch_size\n  assert(data_count % batch_size == 0, 'data count has to be divisible by the batch size')\n  local batch_count = data_count / batch_size\n\n  local target_size = game_settings.hand_count * constants.players_count\n  local targets = arguments.Tensor(batch_size, target_size)\n  local input_size = game_settings.hand_count * constants.players_count + 1\n  local inputs = arguments.Tensor(batch_size, input_size)\n  local mask = arguments.Tensor(batch_size, game_settings.hand_count):zero()\n\n  local board = arguments.Tensor()\n  local te = TerminalEquity()\n  te:set_board(board)\n  range_generator:set_board(te, board)\n\n  local bucket_conversion = BucketConversion()\n  bucket_conversion:set_board(board)\n\n  local next_round = NextRoundValuePre(ValueNn(street), nil, board)\n\n  local bucket_count = bucketer:get_bucket_count(street)\n  local bucketed_target_size = bucket_count * constants.players_count\n  local bucketed_input_size = bucket_count * constants.players_count + 1\n\n  local input_batch = arguments.Tensor(arguments.gen_batch_size, bucketed_input_size)\n  local target_batch = arguments.Tensor(arguments.gen_batch_size, bucketed_target_size)\n\n  local raw_indexes = {{1, game_settings.hand_count}, {game_settings.hand_count + 1, game_settings.hand_count * 2}}\n  local bucket_indexes = {{1, bucket_count}, {bucket_count + 1, bucket_count * 2}}\n\n  for batch = 1, batch_count do\n    local timer = torch.Timer()\n    timer:reset()\n\n    --generating ranges\n    local ranges = arguments.Tensor(constants.players_count, batch_size, game_settings.hand_count)\n    for player = 1, constants.players_count do\n      range_generator:generate_range(ranges[player])\n    end\n\n    --generating pot sizes between ante and stack - 0.1\n    local min_pot = {}\n    local max_pot = {}\n\n    if game_settings.nl then\n      min_pot = {100,200,400,2000,6000}\n      max_pot = {100,400,2000,6000,18000}\n    else\n      if street == 4 then\n        min_pot = {2,12,24}\n        max_pot = {12,24,48}\n      elseif street == 3 then\n        min_pot = {2,8,16}\n        max_pot = {8,16,24}\n      elseif street == 2 then\n        min_pot = {2,4,6}\n        max_pot = {4,6,10}\n      end\n    end\n\n    local pot_range = {}\n\n    for i = 1,#min_pot do\n      pot_range[i] = max_pot[i] - min_pot[i]\n    end\n    local random_pot_cats = torch.rand(arguments.gen_batch_size):mul(#min_pot):add(1):floor()\n    local random_pot_sizes = torch.rand(arguments.gen_batch_size,1)\n    for i = 1, arguments.gen_batch_size do\n      random_pot_sizes[i][1] = random_pot_sizes[i][1] * pot_range[random_pot_cats[i]]\n      random_pot_sizes[i][1] = random_pot_sizes[i][1] + min_pot[random_pot_cats[i]]\n    end\n\n    --pot features are pot sizes normalized between (ante/stack,1)\n    local pot_size_features = game_settings.nl and random_pot_sizes:clone():mul(1/arguments.stack) or\n        random_pot_sizes:clone():mul(1/max_pot[3])\n\n    --translating ranges to features\n    local pot_feature_index =  -1\n    inputs[{{}, pot_feature_index}]:copy(pot_size_features)\n    input_batch[{{}, pot_feature_index}]:copy(pot_size_features)\n\n    local player_indexes = {{1, game_settings.hand_count}, {game_settings.hand_count + 1, game_settings.hand_count * 2}}\n    for player = 1, constants.players_count do\n      local player_index = player_indexes[player]\n      inputs[{{}, player_index}]:copy(ranges[player])\n    end\n\n    for i = 1, arguments.gen_batch_size do\n      local next_street_boxes_inputs = arguments.Tensor(1, constants.players_count, game_settings.hand_count):zero()\n      local next_street_boxes_outputs = next_street_boxes_inputs:clone()\n\n      for player = 1, constants.players_count do\n        local player_index = player_indexes[player]\n        next_street_boxes_inputs[{{},player,{}}]:copy(inputs[{i,player_index}])\n      end\n\n      next_round:start_computation(random_pot_sizes[i], 1)\n      next_round:get_value(next_street_boxes_inputs, next_street_boxes_outputs)\n\n      for player = 1, constants.players_count do\n        local player_index = player_indexes[player]\n        targets[{i, player_index}]:copy(next_street_boxes_outputs[{{},player,{}}])\n      end\n    end\n    for player = 1, constants.players_count do\n      local player_index = raw_indexes[player]\n      local bucket_index = bucket_indexes[player]\n      bucket_conversion:card_range_to_bucket_range(inputs[{{},player_index}],input_batch[{{}, bucket_index}])\n    end\n    for player = 1, constants.players_count do\n      local player_index = raw_indexes[player]\n      local bucket_index = bucket_indexes[player]\n      bucket_conversion:hand_cfvs_to_bucket_cfvs(\n        inputs[{{}, player_index}],\n        targets[{{}, player_index}],\n        input_batch[{{}, bucket_index}],\n        target_batch[{{}, bucket_index}])\n    end\n\n    local basename = file_name .. '-' .. batch\n    local train_folder = \"xxx/\"\n    if game_settings.nl then\n      train_folder = \"NoLimit/\"\n    else\n      train_folder = \"Limit/\"\n    end\n    torch.save(arguments.data_path  .. train_folder ..  basename .. '.inputs', input_batch:float())\n    torch.save(arguments.data_path  .. train_folder ..  basename .. '.targets', target_batch:float())\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "Source/DataGeneration/data_generation.lua",
    "content": "--- Generates neural net training data by solving random poker situations.\n-- @module data_generation\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_generator = require 'DataGeneration.random_card_generator'\nlocal card_to_string_conversion = require 'Game.card_to_string_conversion'\nlocal constants = require 'Settings.constants'\nrequire 'DataGeneration.range_generator'\nrequire 'TerminalEquity.terminal_equity'\nrequire 'Lookahead.lookahead'\nrequire 'Lookahead.resolving'\n\nlocal M = {}\n\n--- Generates training files by sampling random poker\n-- situations and solving them.\n--\n-- @param train_data_count the number of training examples to generate\nfunction M:generate_data(train_data_count, filename, street)\n  --valid data generation\n  local timer = torch.Timer()\n  timer:reset()\n  print('Generating data ...')\n  self:generate_data_file(train_data_count, filename, street)\n  print('gen time: ' .. timer:time().real)\nend\n\n--- Generates data files containing examples of random poker situations with\n-- counterfactual values from an associated solution.\n--\n-- Each poker situation is randomly generated using @{range_generator} and\n-- @{random_card_generator}. For description of neural net input and target\n-- type, see @{net_builder}.\n--\n-- @param data_count the number of examples to generate\n-- @param file_name the prefix of the files where the data is saved (appended\n-- with `.inputs`, `.targets`, and `.mask`).\nfunction M:generate_data_file(data_count, file_name, street)\n  local range_generator = RangeGenerator()\n  local batch_size = arguments.gen_batch_size\n  assert(data_count % batch_size == 0, 'data count has to be divisible by the batch size')\n  local batch_count = data_count / batch_size\n\n  local target_size = game_settings.hand_count * constants.players_count\n  local targets = arguments.Tensor(batch_size, target_size)\n  local input_size = game_settings.hand_count * constants.players_count + 1\n  local inputs = arguments.Tensor(batch_size, input_size)\n  local mask = arguments.Tensor(batch_size, game_settings.hand_count):zero()\n\n  local te = TerminalEquity()\n  for batch = 1, batch_count do\n    local timer = torch.Timer()\n    timer:reset()\n    local board = card_generator:generate_cards(game_settings.board_card_count[street])\n\n    local board_string = card_to_string_conversion:cards_to_string(board)\n\n    te:set_board(board)\n    range_generator:set_board(te, board)\n\n    print('terminal time: ' .. timer:time().real)\n    --generating ranges\n    local ranges = arguments.Tensor(constants.players_count, batch_size, game_settings.hand_count)\n    for player = 1, constants.players_count do\n      range_generator:generate_range(ranges[player])\n    end\n\n    --generating pot sizes between ante and stack - 0.1\n    local min_pot = {}\n    local max_pot = {}\n\n    if game_settings.nl then\n      min_pot = {100,200,400,2000,6000}\n      max_pot = {100,400,2000,6000,18000}\n    else\n      if street == 4 then\n        min_pot = {2,12,24}\n        max_pot = {12,24,48}\n      elseif street == 3 then\n        min_pot = {2,8,16}\n        max_pot = {8,16,24}\n      elseif street == 2 then\n        min_pot = {2,4,6}\n        max_pot = {4,6,10}\n      end\n    end\n\n    local pot_range = {}\n\n    for i = 1,#min_pot do\n      pot_range[i] = max_pot[i] - min_pot[i]\n    end\n\n    local random_pot_cat = torch.rand(1):mul(#min_pot):add(1):floor()[1]\n    local random_pot_size = torch.rand(1)[1]\n\n    random_pot_size = random_pot_size * pot_range[random_pot_cat]\n    random_pot_size = random_pot_size + min_pot[random_pot_cat]\n    random_pot_size = math.floor(random_pot_size)\n\n    --pot features are pot sizes normalized between (ante/stack,1)\n    local pot_size_feature = game_settings.nl and (random_pot_size / arguments.stack) or (random_pot_size / max_pot[3])\n\n    --translating ranges to features\n    local pot_feature_index =  -1\n    inputs[{{}, pot_feature_index}]:fill(pot_size_feature)\n\n    local player_indexes = {{1, game_settings.hand_count}, {game_settings.hand_count + 1, game_settings.hand_count * 2}}\n    for player = 1, constants.players_count do\n      local player_index = player_indexes[player]\n      inputs[{{}, player_index}]:copy(ranges[player])\n    end\n    --computaton of values using re-solving\n    local values = arguments.Tensor(batch_size, constants.players_count, game_settings.hand_count)\n\n\n    local pot_size = random_pot_size\n    print(board_string .. ' ' .. batch .. ' ' .. pot_size)\n\n    local resolving = Resolving(te)\n    local current_node = {}\n\n    current_node.board = board\n    current_node.street = street\n    current_node.num_bets = 0\n    current_node.current_player = street == 1 and constants.players.P1 or constants.players.P2\n\n    --TODO support preflop bets\n    current_node.bets = arguments.Tensor{pot_size, pot_size}\n    local p1_range = ranges[1]\n    local p2_range = ranges[2]\n    resolving:resolve_first_node(current_node, p1_range, p2_range)\n    local root_values = resolving:get_root_cfv_both_players()\n    root_values:mul(1/pot_size)\n\n    values:copy(root_values)\n\n    for player = 1, constants.players_count do\n      local player_index = player_indexes[player]\n      targets[{{}, player_index}]:copy(values[{{},player,{}}])\n    end\n\n    local basename = file_name .. '-' .. board_string .. '-' .. batch\n    local train_folder = \"xxx/\"\n    if game_settings.nl then\n      train_folder = \"NoLimit/\"\n    else\n      train_folder = \"Limit/\"\n    end\n\n    torch.save(arguments.data_path  .. train_folder .. basename .. '.inputs', inputs:float())\n    torch.save(arguments.data_path  .. train_folder .. basename .. '.targets', targets:float())\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "Source/DataGeneration/main_aux_data_generation.lua",
    "content": "--- Script that generates training and validation files.\n-- @see data_generation\n-- @script main_data_generation\nlocal filename = os.time()\n\nif #arg == 0 then\n  print(\"Please specify the street. 1 = preflop, 4 = river\")\n  return\nend\n\nlocal arguments = require 'Settings.arguments'\nlocal aux_data_generation = require 'DataGeneration.aux_data_generation'\n\naux_data_generation:generate_data(arguments.train_data_count, filename, tonumber(arg[1]))\n"
  },
  {
    "path": "Source/DataGeneration/main_data_generation.lua",
    "content": "--- Script that generates training and validation files.\n-- @see data_generation\n-- @script main_data_generation\nlocal filename = os.time()\n\nif #arg == 0 then\n  print(\"Please specify the street. 1 = preflop, 4 = river\")\n  return\nend\n\nlocal arguments = require 'Settings.arguments'\nlocal data_generation = require 'DataGeneration.data_generation'\n\ndata_generation:generate_data(arguments.train_data_count, filename, tonumber(arg[1]))\n"
  },
  {
    "path": "Source/DataGeneration/random_card_generator.lua",
    "content": "--- Samples random card combinations.\n-- @module random_card_generator\n\nrequire \"torch\"\nlocal M = {}\nlocal game_settings = require 'Settings.game_settings'\nlocal arguments = require 'Settings.arguments'\n\n--- Samples a random set of cards.\n-- \n-- Each subset of the deck of the correct size is sampled with \n-- uniform probability.\n--\n-- @param count the number of cards to sample\n-- @return a vector of cards, represented numerically\nfunction M:generate_cards( count )\n  --marking all used cards\n  local used_cards = torch.ByteTensor(game_settings.card_count):zero()\n  \n  local out = arguments.Tensor(count)\n  --counter for generated cards\n  local generated_cards_count = 0\n  while(generated_cards_count < count) do\n    local card = torch.random(1, game_settings.card_count)\n    if ( used_cards[card] == 0 ) then \n      generated_cards_count = generated_cards_count + 1\n      out[generated_cards_count] = card\n      used_cards[card] = 1\n    end\n  end\n  return out\nend\n\nreturn M\n"
  },
  {
    "path": "Source/DataGeneration/range_generator.lua",
    "content": "--- Samples random probability vectors for use as player ranges.\n-- @classmod range_generator\n\nrequire \"math\"\nrequire \"torch\"\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\nlocal evaluator = require 'Game.Evaluation.evaluator'\nlocal card_tools = require 'Game.card_tools'\nlocal card_to_string = require 'Game.card_to_string_conversion'\n\nlocal RangeGenerator = torch.class('RangeGenerator')\n\n--- Recursively samples a section of the range vector.\n-- @param cards an NxJ section of the range tensor, where N is the batch size\n-- and J is the length of the range sub-vector\n-- @param mass a vector of remaining probability mass for each batch member\n-- @see generate_range\n-- @local\nfunction RangeGenerator:_generate_recursion(cards, mass)\n  local batch_size = cards:size(1)\n  assert(mass:size(1) == batch_size)\n  --we terminate recursion at size of 1\n  local card_count = cards:size(2)\n  if card_count == 1 then\n    cards:copy(mass)\n  else\n    local rand = torch.rand(batch_size)\n    if arguments.gpu then\n      rand = rand:cuda()\n    end\n    local mass1 = mass:clone():cmul(rand)\n    mass1[torch.lt(mass1, 0.00001)] = 0\n    mass1[torch.gt(mass1, 0.99999)] = 1\n    local mass2 = mass -mass1\n    local halfSize = card_count/2\n    --if the tensor contains an odd number of cards, randomize which way the\n\t--middle card goes\n    if halfSize % 1 ~= 0 then\n      halfSize = halfSize - 0.5\n      halfSize = halfSize + torch.random(0,1)\n    end\n    self:_generate_recursion(cards[{{}, {1, halfSize}}], mass1)\n    self:_generate_recursion(cards[{{}, {halfSize +1, -1}}], mass2)\n  end\nend\n\n--- Samples a batch of ranges with hands sorted by strength on the board.\n-- @param range a NxK tensor in which to store the sampled ranges, where N is\n-- the number of ranges to sample and K is the range size\n-- @see generate_range\n-- @local\nfunction RangeGenerator:_generate_sorted_range(range)\n  local batch_size = range:size(1)\n  self:_generate_recursion(range, arguments.Tensor(batch_size):fill(1))\nend\n\n--- Sets the (possibly empty) board cards to sample ranges with.\n--\n-- The sampled ranges will assign 0 probability to any private hands that\n-- share any cards with the board.\n--\n-- @param board a possibly empty vector of board cards\nfunction RangeGenerator:set_board(te, board)\n\n  local hand_strengths = arguments.Tensor(game_settings.hand_count)\n  for i=1,game_settings.hand_count do\n    hand_strengths[i] = i\n  end\n  if board:dim() == 0 then\n    hand_strengths = te:get_hand_strengths():squeeze()\n  elseif board:size(1) == 5 then\n    hand_strengths = evaluator:batch_eval(board)\n  else\n    hand_strengths = te:get_hand_strengths():squeeze()\n  end\n  local possible_hand_indexes = card_tools:get_possible_hand_indexes(board)\n  self.possible_hands_count = possible_hand_indexes:sum(1)[1]\n  self.possible_hands_mask = possible_hand_indexes:view(1, -1)\n  if not arguments.gpu then\n    self.possible_hands_mask = self.possible_hands_mask:byte()\n  else\n    self.possible_hands_mask = self.possible_hands_mask:cudaByte()\n  end\n  local non_colliding_strengths = arguments.Tensor(self.possible_hands_count)\n  non_colliding_strengths:maskedSelect(hand_strengths, self.possible_hands_mask)\n  local order\n  _, order = non_colliding_strengths:sort()\n  _, self.reverse_order = order:sort()\n  self.reverse_order = self.reverse_order:view(1, -1):long()\n  self.reordered_range = arguments.Tensor()\n  self.sorted_range =arguments.Tensor()\nend\n\n--- Samples a batch of random range vectors.\n--\n-- Each vector is sampled indepently by randomly splitting the probability\n-- mass between the bottom half and the top half of the range, and then\n-- recursing on the two halfs.\n--\n-- @{set_board} must be called first.\n--\n-- @param range a NxK tensor in which to store the sampled ranges, where N is\n-- the number of ranges to sample and K is the range size\nfunction RangeGenerator:generate_range(range)\n  local batch_size = range:size(1)\n  self.sorted_range:resize(batch_size, self.possible_hands_count)\n  self:_generate_sorted_range(self.sorted_range, self.possible_hands_count)\n  --we have to reorder the the range back to undo the sort by strength\n  local index = self.reverse_order:expandAs(self.sorted_range)\n  if arguments.gpu then\n    index = index:cuda()\n  end\n  self.reordered_range = self.sorted_range:gather(2, index)\n\n  range:zero()\n  range:maskedCopy(self.possible_hands_mask:expandAs(range), self.reordered_range)\n\nend\n"
  },
  {
    "path": "Source/Game/Evaluation/evaluator.lua",
    "content": "--- Evaluates hand strength in Leduc Hold'em and variants.\n--\n-- Works with hands which contain two or three cards, but assumes that\n-- the deck contains no more than two cards of each rank (so three-of-a-kind\n-- is not a possible hand).\n--\n-- Hand strength is given as a numerical value, where a lower strength means\n-- a stronger hand: high pair < low pair < high card < low card\n-- @module evaluator\n\nrequire 'torch'\nrequire 'math'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nlocal card_tools = require 'Game.card_tools'\nlocal arguments = require 'Settings.arguments'\n\nlocal M = {_texas_lookup = nil}\n\nfunction M:_init()\n  self._idx_to_cards = arguments.Tensor(game_settings.hand_count, game_settings.hand_card_count)\n  for card1 = 1, game_settings.card_count do\n    for card2 = card1 + 1, game_settings.card_count do\n      local idx = card_tools:get_hole_index({card1,card2})\n      --print(card_to_string:card_to_string(card1) .. card_to_string:card_to_string(card2) .. ': ' .. idx)\n      self._idx_to_cards[idx][1] = card1\n      self._idx_to_cards[idx][2] = card2\n    end\n  end\n  if self._texas_lookup == nil then\n    local f = assert(io.open(\"./Game/Evaluation/HandRanks.dat\", \"rb\"))\n    local data = f:read(\"*all\")\n    self._texas_lookup = arguments.Tensor(string.len(data) / 4):fill(0):long()\n    if arguments.gpu then\n      self._texas_lookup = self._texas_lookup:cudaLong()\n    end\n    for i = 1, string.len(data), 4 do\n      local num = 0\n      for j = i,i+3 do\n        num = num + data:byte(j) * (2 ^ ((j - i) * 8))\n      end\n      self._texas_lookup[(i - 1) / 4 + 1] = num\n    end\n    f:close()\n  end\nend\n\nM:_init()\n\n--- Gives a strength representation for a hand containing two cards.\n-- @param hand_ranks the rank of each card in the hand\n-- @return the strength value of the hand\n-- @local\nfunction M:evaluate_two_card_hand(hand_ranks)\n  --check for the pair\n  local hand_value = nil\n  if hand_ranks[1] == hand_ranks[2] then\n    --hand is a pair\n    hand_value = hand_ranks[1]\n  else\n    --hand is a high card\n    hand_value = hand_ranks[1] * game_settings.rank_count + hand_ranks[2]\n  end\n  return hand_value\nend\n\n--- Gives a strength representation for a hand containing three cards.\n-- @param hand_ranks the rank of each card in the hand\n-- @return the strength value of the hand\n-- @local\nfunction M:evaluate_three_card_hand(hand_ranks)\n  local hand_value = nil\n  --check for the pair\n  if hand_ranks[1] == hand_ranks[2] then\n    --paired hand, value of the pair goes first, value of the kicker goes second\n    hand_value = hand_ranks[1] * game_settings.rank_count + hand_ranks[3]\n  elseif hand_ranks[2] == hand_ranks[3] then\n    --paired hand, value of the pair goes first, value of the kicker goes second\n    hand_value = hand_ranks[2] * game_settings.rank_count + hand_ranks[1]\n  else\n    --hand is a high card\n    hand_value = hand_ranks[1] * game_settings.rank_count * game_settings.rank_count + hand_ranks[2] * game_settings.rank_count + hand_ranks[3]\n  end\n  return hand_value\nend\n\n--- Gives a strength representation for a texas hold'em hand containing seven cards.\n-- @param hand_ranks the rank of each card in the hand\n-- @return the strength value of the hand\n-- @local\nfunction M:evaluate_seven_card_hand(hand)\n  local rank = self._texas_lookup[54 + (hand[1] - 1) + 1]\n  for c = 2, hand:size(1) do\n    rank = self._texas_lookup[1 + rank + (hand[c] - 1) + 1]\n  end\n  return -rank\nend\n\n--- Gives a strength representation for a two or three card hand.\n-- @param hand a vector of two or three cards\n-- @param[opt] impossible_hand_value the value to return if the hand is invalid\n-- @return the strength value of the hand, or `impossible_hand_value` if the\n-- hand is invalid\nfunction M:evaluate(hand, impossible_hand_value)\n  assert(hand:max() <= game_settings.card_count and hand:min() > 0, 'hand does not correspond to any cards' )\n  impossible_hand_value = impossible_hand_value or -1\n  if not card_tools:hand_is_possible(hand) then\n    return impossible_hand_value\n  end\n  --we are not interested in the hand suit - we will use ranks instead of cards\n  if hand:size(1) == 2 then\n    local hand_ranks = hand:clone()\n    for i = 1, hand_ranks:size(1) do\n      hand_ranks[i] = card_to_string:card_to_rank(hand_ranks[i])\n    end\n    hand_ranks = hand_ranks:sort()\n    return self:evaluate_two_card_hand(hand_ranks)\n  elseif hand:size(1) == 3 then\n    local hand_ranks = hand:clone()\n    for i = 1, hand_ranks:size(1) do\n      hand_ranks[i] = card_to_string:card_to_rank(hand_ranks[i])\n    end\n    hand_ranks = hand_ranks:sort()\n    return self:evaluate_three_card_hand(hand_ranks)\n  elseif hand:size(1) == 7 then\n    return self:evaluate_seven_card_hand(hand)\n  else\n    assert(false, 'unsupported size of hand!' )\n  end\nend\n\nfunction M:evaluate_fast(hands)\n  local ret = self._texas_lookup:index(1,torch.add(hands[{{},1}],54))\n  for c = 2, hands:size(2) do\n    ret = self._texas_lookup:index(1, torch.add(hands[{{},c}],ret):add(1))\n  end\n  ret:cmul(card_tools:get_possible_hands_mask(hands))\n  ret:mul(-1)\n  return ret\nend\n\n--- Gives strength representations for all private hands on the given board.\n-- @param board a possibly empty vector of board cards\n-- @param impossible_hand_value the value to assign to hands which are invalid\n-- on the board\n-- @return a vector containing a strength value or `impossible_hand_value` for\n-- every private hand\nfunction M:batch_eval(board, impossible_hand_value)\n  local hand_values = arguments.Tensor(game_settings.hand_count):fill(-1)\n  if board:dim() == 0 then -- kuhn poker\n    for hand = 1, game_settings.card_count do\n      hand_values[hand] = math.floor((hand - 1 ) / game_settings.suit_count ) + 1\n    end\n  else\n    local board_size = board:size(1)\n    assert(board_size == 1 or board_size == 2 or board_size == 5, 'Incorrect board size for Leduc' )\n\n    local whole_hand = arguments.Tensor(board_size + game_settings.hand_card_count)\n    whole_hand[{{1, -1 - game_settings.hand_card_count}}]:copy(board)\n\n    if game_settings.hand_card_count == 1 then\n      for card = 1, game_settings.card_count do\n        whole_hand[-1] = card\n        hand_values[card] = self:evaluate(whole_hand, impossible_hand_value)\n      end\n    elseif game_settings.hand_card_count == 2 then\n      for card1 = 1, game_settings.card_count do\n        for card2 = card1 + 1, game_settings.card_count do\n          whole_hand[-2] = card1\n          whole_hand[-1] = card2\n          local idx = card_tools:get_hole_index({card1,card2})\n          --print(card_to_string:card_to_string(card1) .. card_to_string:card_to_string(card2) .. ': ' .. idx)\n          hand_values[idx] = self:evaluate(whole_hand, impossible_hand_value)\n        end\n      end\n    else\n      assert(false, \"unsupported hand_card_count: \" .. game_settings.hand_card_count)\n    end\n  end\n  return hand_values\nend\n\nfunction M:batch_eval_fast(board)\n  if board:dim() == 0 then -- kuhn poker\n    return nil\n  elseif board:dim() == 2 then\n    local batch_size = board:size(1)\n    local hands = arguments.Tensor(batch_size, game_settings.hand_count, board:size(2) + game_settings.hand_card_count):long()\n    if arguments.gpu then\n      hands = hands:cudaLong()\n    end\n    hands[{{},{},{1,board:size(2)}}]:copy(\n      board:view(batch_size, 1, board:size(2))\n           :expand(batch_size, game_settings.hand_count, board:size(2)))\n    hands[{{},{},{-2,-1}}]:copy(\n      self._idx_to_cards:view(1, game_settings.hand_count, game_settings.hand_card_count)\n                        :expand(batch_size, game_settings.hand_count, game_settings.hand_card_count))\n    return self:evaluate_fast(hands:view(-1, board:size(2) + game_settings.hand_card_count)):view(batch_size, game_settings.hand_count)\n  elseif board:dim() == 1 then\n    local hands = arguments.Tensor(game_settings.hand_count, board:size(1) + game_settings.hand_card_count):long()\n    if arguments.gpu then\n      hands = hands:cudaLong()\n    end\n    hands[{{},{1,board:size(1)}}]:copy(board:view(1,board:size(1)):expand(game_settings.hand_count,board:size(1)))\n    hands[{{},{-2,-1}}]:copy(self._idx_to_cards)\n    return self:evaluate_fast(hands)\n  else\n    assert(false, \"weird board dim \" .. board:dim())\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "Source/Game/bet_sizing.lua",
    "content": "--- Gives allowed bets during a game.\n-- Bets are restricted to be from a list of predefined fractions of the pot.\n-- @classmod bet_sizing\n\nrequire 'math'\nlocal arguments = require 'Settings.arguments'\n\nlocal BetSizing = torch.class('BetSizing')\n\n--- Constructor\n-- @param pot_fractions a list of fractions of the pot which are allowed\n-- as bets, sorted in ascending order\nfunction BetSizing:__init(pot_fractions)\n  pot_fractions = pot_fractions or {1}\n  self.pot_fractions = pot_fractions\nend\n\n--- Gives the bets which are legal at a game state.\n-- @param node a representation of the current game state, with fields:\n--\n-- * `bets`: the number of chips currently committed by each player\n--\n-- * `current_player`: the currently acting player\n-- @return an Nx2 tensor where N is the number of new possible game states,\n-- containing N sets of new commitment levels for each player\nfunction BetSizing:get_possible_bets(node)\n  local current_player = node.current_player\n  assert(current_player == 1 or current_player == 2, 'Wrong player for bet size computation')\n  local opponent = 3 - node.current_player\n  local opponent_bet = node.bets[opponent]\n\n  assert(node.bets[current_player] <= opponent_bet)\n\n  --compute min possible raise size\n  local max_raise_size = arguments.stack - opponent_bet\n  local min_raise_size = opponent_bet - node.bets[current_player]\n  min_raise_size = math.max(min_raise_size, arguments.ante)\n  min_raise_size = math.min(max_raise_size, min_raise_size)\n\n  if min_raise_size == 0 then\n    return arguments.Tensor()\n  elseif min_raise_size == max_raise_size then\n    local out = arguments.Tensor(1,2):fill(opponent_bet)\n    out[1][current_player] = opponent_bet + min_raise_size\n    return out\n  else\n     --iterate through all bets and check if they are possible\n\n     local fractions = {}\n     if node.num_bets == 0 then\n       fractions = self.pot_fractions[1]\n     elseif node.num_bets == 1 then\n       fractions = self.pot_fractions[2]\n     else\n       fractions = self.pot_fractions[3]\n     end\n     local max_possible_bets_count = #fractions + 1 --we can always go allin\n     local out = arguments.Tensor(max_possible_bets_count,2):fill(opponent_bet)\n\n     --take pot size after opponent bet is called\n     local pot = opponent_bet * 2\n     local used_bets_count = 0;\n     --try all pot fractions bet and see if we can use them\n     for i = 1, #fractions  do\n       local raise_size = pot * fractions[i]\n       if raise_size >= min_raise_size and raise_size < max_raise_size then\n         used_bets_count = used_bets_count + 1\n         out[{used_bets_count, current_player}] = opponent_bet + raise_size\n       end\n     end\n     --adding allin\n     used_bets_count  = used_bets_count + 1\n     assert(used_bets_count <= max_possible_bets_count)\n     out[{used_bets_count, current_player}] = opponent_bet + max_raise_size\n     return out[{{1, used_bets_count}, {}}]\n  end\nend\n"
  },
  {
    "path": "Source/Game/card_to_string_conversion.lua",
    "content": "--- Converts between string and numeric representations of cards.\n-- @module card_to_string_conversion\n\nrequire \"string\"\nrequire \"torch\"\nlocal arguments = require 'Settings.arguments'\nlocal game_settings =  require 'Settings.game_settings'\n\nlocal M = {};\n\n---All possible card suits - only the first 2 are used in Leduc Hold'em.\nM.suit_table = {'c', 'd', 'h', 's'}\n\n---All possible card ranks - only the first 3-4 are used in Leduc Hold'em and\n-- variants.\nM.rank_table = {'2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A'}\n\n--- Gets the suit of a card.\n-- @param card the numeric representation of the card\n-- @return the index of the suit\nfunction M:card_to_suit(card)\n  return (card - 1) % game_settings.suit_count + 1\nend\n\n--- Gets the rank of a card.\n-- @param card the numeric representation of the card\n-- @return the index of the rank\nfunction M:card_to_rank(card)\n  return torch.floor((card - 1) / game_settings.suit_count ) + 1\nend;\n\n--- Holds the string representation for every possible card, indexed by its\n-- numeric representation.\nM.card_to_string_table ={}\nfor card = 1, game_settings.card_count do\n  local rank_name = M.rank_table[M:card_to_rank(card)]\n  local suit_name = M.suit_table[M:card_to_suit(card)]\n  M.card_to_string_table[card] =  rank_name .. suit_name\nend\n\n--- Holds the numeric representation for every possible card, indexed by its\n-- string representation.\nM.string_to_card_table = {}\nfor card = 1, game_settings.card_count do\n  M.string_to_card_table[M.card_to_string_table[card]] = card\nend\n\n\n--- Converts a card's numeric representation to its string representation.\n-- @param card the numeric representation of a card\n-- @return the string representation of the card\nfunction M:card_to_string(card)\n  assert(card > 0 and card <= game_settings.card_count )\n  return M.card_to_string_table[card]\nend\n\n--- Converts several cards' numeric representations to their string\n-- representations.\n-- @param cards a vector of numeric representations of cards\n-- @return a string containing each card's string representation, concatenated\nfunction M:cards_to_string(cards)\n  if cards:dim() == 0 then\n    return \"\"\n  end\n\n  local out = \"\"\n  for card =1, cards:size(1) do\n    out = out .. self:card_to_string(cards[card])\n  end\n  return out\nend\n\n--- Converts a card's string representation to its numeric representation.\n-- @param card_string the string representation of a card\n-- @return the numeric representation of the card\nfunction M:string_to_card(card_string)\n  local card = M.string_to_card_table[card_string]\n  assert(card > 0 and card <= game_settings.card_count )\n  return card\nend\n\n--- Converts a string representing zero or more board cards to a\n-- vector of numeric representations.\n-- @param card_string either the empty string or a string representation of a\n-- card\n-- @return either an empty tensor or a tensor containing the numeric\n-- representation of the card\nfunction M:string_to_board(card_string)\n  assert(card_string)\n  if card_string == '' then\n    return arguments.Tensor{}\n  end\n\n  local num_cards = string.len(card_string) / 2\n  board = arguments.Tensor(num_cards)\n  for i = 1, num_cards do\n    board[i] = self:string_to_card(string.sub(card_string, i * 2 - 1, i * 2))\n  end\n  return board\nend\n\nreturn M\n"
  },
  {
    "path": "Source/Game/card_tools.lua",
    "content": "--- A set of tools for basic operations on cards and sets of cards.\n--\n-- Several of the functions deal with \"range vectors\", which are probability\n-- vectors over the set of possible private hands. For Leduc Hold'em,\n-- each private hand consists of one card.\n-- @module card_tools\nlocal game_settings = require 'Settings.game_settings'\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal tools = require 'tools'\nlocal card_to_string_conversion = require 'Game.card_to_string_conversion'\n\nlocal M = {}\n\n--- Gives whether a set of cards is valid.\n-- @param hand a vector of cards\n-- @return `true` if the tensor contains valid cards and no card is repeated\nfunction M:hand_is_possible(hand)\n  assert(hand:min() > 0 and hand:max() <= game_settings.card_count, 'Illegal cards in hand' )\n  local used_cards = torch.FloatTensor(game_settings.card_count):fill(0);\n  for i = 1, hand:size(1) do\n    used_cards[hand[i]] = used_cards[hand[i]] + 1\n  end\n  return used_cards:max() < 2\nend\n\nfunction M:get_possible_hands_mask(hands)\n  local used_cards = arguments.Tensor(hands:size(1), game_settings.card_count):fill(0)\n\n  used_cards:scatterAdd(2,hands,arguments.Tensor(hands:size(1), 7):fill(1))\n  local ret = torch.le(torch.max(used_cards, 2), 1):long()\n  if arguments.gpu then\n    ret = ret:cudaLong()\n  end\n\n  return ret\nend\n\n--- Gives the private hands which are valid with a given board.\n-- @param board a possibly empty vector of board cards\n-- @return a vector with an entry for every possible hand (private card), which\n--  is `1` if the hand shares no cards with the board and `0` otherwise\n-- TODO generalize\nfunction M:get_possible_hand_indexes(board)\n  local out = arguments.Tensor(game_settings.hand_count):fill(0)\n  if board:dim() == 0 then\n    out:fill(1)\n    return out\n  end\n\n  local used = {}\n  for i = 1, board:size(1) do\n    used[board[i]] = 1\n  end\n\n  for card1 = 1, game_settings.card_count do\n    if not used[card1] then\n      for card2 = card1+1, game_settings.card_count do\n        if not used[card2] then\n          out[M:get_hole_index({card1,card2})] = 1\n        end\n      end\n    end\n  end\n  return out\nend\n\n--- Gives the private hands which are invalid with a given board.\n-- @param board a possibly empty vector of board cards\n-- @return a vector with an entry for every possible hand (private card), which\n-- is `1` if the hand shares at least one card with the board and `0` otherwise\nfunction M:get_impossible_hand_indexes(board)\n  local out = self:get_possible_hand_indexes(board)\n  out:add(-1)\n  out:mul(-1)\n  return out\nend\n\n--- Gives a range vector that has uniform probability on each hand which is\n-- valid with a given board.\n-- @param board a possibly empty vector of board cards\n-- @return a range vector where invalid hands have 0 probability and valid\n-- hands have uniform probability\nfunction M:get_uniform_range(board)\n  local out = self:get_possible_hand_indexes(board)\n  out:div(out:sum())\n\n  return out\nend\n\nfunction M:get_file_range(filename)\n  local out = arguments.Tensor(game_settings.hand_count):fill(0)\n  local f = assert(io.open(filename, \"r\"))\n  while true do\n    local s = f:read(4)\n    if s == nil then\n      break\n    end\n    s = s:gsub(\"t\",\"T\")\n    s = s:gsub(\"j\",\"J\")\n    s = s:gsub(\"q\",\"Q\")\n    s = s:gsub(\"k\",\"K\")\n    s = s:gsub(\"a\",\"A\")\n    local n = f:read(\"*number\")\n    if n == nil then\n      break\n    end\n    -- read newline\n    f:read(1)\n\n    local hand = card_to_string_conversion:string_to_board(s)\n    if hand[1] > hand[2] then\n      local temp = hand[1]\n      hand[1] = hand[2]\n      hand[2] = temp\n    end\n    local idx = self:get_hole_index({hand[1], hand[2]})\n    out[idx] = n\n  end\n  out:div(out:sum())\n  return out\nend\n\n--- Randomly samples a range vector which is valid with a given board.\n-- @param board a possibly empty vector of board cards\n-- @param[opt] seed a seed for the random number generator\n-- @return a range vector where invalid hands are given 0 probability, each\n-- valid hand is given a probability randomly sampled from the uniform\n-- distribution on [0,1), and the resulting range is normalized\nfunction M:get_random_range(board, seed)\n  seed = seed or torch.random()\n\n  local gen = torch.Generator()\n  torch.manualSeed(gen, seed)\n\n  local out = torch.rand(gen, game_settings.hand_count):typeAs(arguments.Tensor())\n  out:cmul(self:get_possible_hand_indexes(board))\n  out:div(out:sum())\n\n  return out\nend\n\n--- Checks if a range vector is valid with a given board.\n-- @param range a range vector to check\n-- @param board a possibly empty vector of board cards\n-- @return `true` if the range puts 0 probability on invalid hands and has\n-- total probability 1\nfunction M:is_valid_range(range, board)\n  local check = range:clone()\n  local only_possible_hands = range:clone():cmul(self:get_impossible_hand_indexes(board)):sum() == 0\n  local sums_to_one = math.abs(1.0 - range:sum()) < 0.0001\n  return only_possible_hands and sums_to_one\nend\n\n--- Gives the current betting round based on a board vector.\n-- @param board a possibly empty vector of board cards\n-- @return the current betting round\nfunction M:board_to_street(board)\n  if board:dim() == 0 then\n    return 1\n  else\n    for i = 1,constants.streets_count do\n      if board:size(1) == game_settings.board_card_count[i] then\n        return i\n      end\n    end\n    assert(false, 'bad board dims')\n  end\nend\n\nfunction M:_build_boards(boards, cur_board, out, card_index, last_index, base_index)\n  if card_index == last_index + 1 then\n    for i = 1, last_index do\n      boards.boards[boards.index][i] = cur_board[i]\n    end\n    out[boards.index]:copy(cur_board)\n    boards.index = boards.index + 1\n    return\n  end\n\n  local startindex = 1\n  if card_index > base_index then\n    startindex = cur_board[card_index-1] + 1\n  end\n  for i = startindex, game_settings.card_count do\n    local good = true\n    for j = 1, card_index - 1 do\n      if cur_board[j] == i then\n        good = false\n      end\n    end\n    if good then\n      cur_board[card_index] = i\n      self:_build_boards(boards,cur_board, out, card_index+1, last_index, base_index)\n    end\n  end\nend\n\n--- Gives all possible sets of board cards for the game.\n-- @return an NxK tensor, where N is the number of possible boards, and K is\n-- the number of cards on each board\nfunction M:get_next_round_boards(board)\n  local street = self:board_to_street(board)\n  local boards_count = self:get_next_boards_count(street)\n  local out = arguments.Tensor(boards_count, game_settings.board_card_count[street+1])\n  local boards = {index = 1, boards = out}\n  local cur_board = arguments.Tensor(game_settings.board_card_count[street+1])\n  if board:dim() > 0 then\n    for i = 1, board:size(1) do\n      cur_board[i] = board[i]\n    end\n  end\n\n  self:_build_boards(boards, cur_board, out,\n    game_settings.board_card_count[street] + 1,\n    game_settings.board_card_count[street+1],\n    game_settings.board_card_count[street] + 1)\n--  assert(boards.index == boards_count, boards.index .. ' ' .. boards_count)\n  if self.flop_board_idx == nil and board:dim() == 0 then\n    self.flop_board_idx = arguments.Tensor(game_settings.card_count, game_settings.card_count, game_settings.card_count)\n    for i = 1, boards_count do\n      local card1 = out[i][1]\n      local card2 = out[i][2]\n      local card3 = out[i][3]\n      self.flop_board_idx[card1][card2][card3] = i\n      self.flop_board_idx[card1][card3][card2] = i\n      self.flop_board_idx[card2][card1][card3] = i\n      self.flop_board_idx[card2][card3][card1] = i\n      self.flop_board_idx[card3][card1][card2] = i\n      self.flop_board_idx[card3][card2][card1] = i\n    end\n  end\n  return out\nend\n\n--- Gives all possible sets of board cards for the game.\n-- @return an NxK tensor, where N is the number of possible boards, and K is\n-- the number of cards on each board\nfunction M:get_last_round_boards(board)\n  local street = self:board_to_street(board)\n  local boards_count = self:get_last_boards_count(street)\n  local out = arguments.Tensor(boards_count, game_settings.board_card_count[constants.streets_count])\n  local boards = {index = 1, boards = out}\n  local cur_board = arguments.Tensor(game_settings.board_card_count[constants.streets_count])\n  if board:dim() > 0 then\n    for i = 1, board:size(1) do\n      cur_board[i] = board[i]\n    end\n  end\n\n  self:_build_boards(boards, cur_board, out,\n    game_settings.board_card_count[street] + 1,\n    game_settings.board_card_count[constants.streets_count],\n    game_settings.board_card_count[street] + 1)\n--  assert(boards.index == boards_count, boards.index .. ' ' .. boards_count)\n  return out\nend\n\n--- Gives the number of possible boards.\n-- @return the number of possible boards\nfunction M:get_next_boards_count(street)\n  local used_cards = game_settings.board_card_count[street]\n\n  local new_cards = game_settings.board_card_count[street+1] - game_settings.board_card_count[street]\n  return tools:choose(game_settings.card_count - used_cards, new_cards)\nend\n\n\n--- Gives the number of possible boards.\n-- @return the number of possible boards\nfunction M:get_last_boards_count(street)\n  local used_cards = game_settings.board_card_count[street]\n\n  local new_cards = game_settings.board_card_count[constants.streets_count] - game_settings.board_card_count[street]\n  return tools:choose(game_settings.card_count - used_cards, new_cards)\nend\n\n--- Gives a numerical index for a set of board cards.\n-- @param board a non-empty vector of board cards\n-- @return the numerical index for the board\nfunction M:get_board_index(board)\n  assert(board:size(1) > 3)\n\n  local used_cards = arguments.Tensor(game_settings.card_count):fill(0)\n  for i = 1, board:size(1) - 1 do\n    used_cards[board[i]] = 1\n  end\n  local ans = 0\n  for i = 1, game_settings.card_count do\n    if used_cards[i] == 0 then\n      ans = ans + 1\n    end\n    if i == board[-1] then\n      return ans\n    end\n  end\n  return -1\nend\n\n--- Gives a numerical index for a set of board cards.\n-- @param board a non-empty vector of board cards\n-- @return the numerical index for the board\nfunction M:get_flop_board_index(board)\n  if self.flop_board_idx == nil then\n    self:get_next_round_boards(arguments.Tensor())\n  end\n  return self.flop_board_idx[board[1]][board[2]][board[3]]\nend\n\n--- Gives a numerical index for a set of hole cards.\n-- @param hand a non-empty vector of hole cards, sorted\n-- @return the numerical index for the hand\nfunction M:get_hole_index(hand)\n  local index = 1\n  for i = 1, #hand do\n    index = index + tools:choose(hand[i] - 1, i)\n  end\n  return index\nend\n\n--- Gives a numerical index for a set of hole cards.\n-- @param hand a non-empty vector of hole cards, sorted\n-- @return the numerical index for the hand\nfunction M:string_to_hole_index(hand_string)\n  local hole = card_to_string_conversion:string_to_board(hand_string)\n  hole = torch.sort(hole)\n  index = 1\n  for i = 1, hole:size(1) do\n    index = index + tools:choose(hole[i] - 1, i)\n  end\n  return index\nend\n\n--- Normalizes a range vector over hands which are valid with a given board.\n-- @param board a possibly empty vector of board cards\n-- @param range a range vector\n-- @return a modified version of `range` where each invalid hand is given 0\n-- probability and the vector is normalized\nfunction M:normalize_range(board, range)\n  local mask = self:get_possible_hand_indexes(board)\n  local out = range:clone():cmul(mask)\n  --return zero range if it all collides with board (avoid div by zero)\n  if out:sum() == 0 then\n    return out\n  end\n  out:div(out:sum())\n  return out\nend\n\n\nreturn M\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/flop-situation1-p1.txt",
    "content": "4d7c\t0.054927\n2c7c\t0.995828\n5d9c\t0.99831\n4dJc\t0.998619\n5d9h\t0.99831\n2s5s\t0.997305\n5d9s\t0.99831\n4dJs\t0.998619\n2c8c\t0.996726\n4dTc\t0.746475\n5d8c\t0.998541\n4dTh\t0.746475\n4c7s\t0.054927\n4cJh\t0.998619\n2c6c\t0.995154\n5d8h\t0.998541\n5dTc\t0.998028\n2s8s\t0.996726\n5dTh\t0.998028\n5dTs\t0.998028\n2s9s\t0.996303\n2s4s\t0.997887\n4dJh\t0.998619\n2s6s\t0.995154\n3dKs\t0.999133\n3dAh\t0.999944\n2sQc\t0.998384\n2sKh\t0.999134\n2sKc\t0.999134\n2sAh\t0.999375\n2sAc\t0.999375\n2sQh\t0.998384\n4d7h\t0.054927\n2s7s\t0.995828\n2h3h\t0.996645\n4cTh\t0.746475\n5d8s\t0.998541\n4d6c\t0.998793\n2c9c\t0.996303\n4d6h\t0.998793\n4cJd\t0.998619\n4cJs\t0.998619\n4cTd\t0.746475\n3dJc\t0.99866\n3dJh\t0.99866\n4s7c\t0.054927\n4cTs\t0.746475\n2cQs\t0.998384\n2cQh\t0.998384\n2cQd\t0.998384\n3dAs\t0.999944\n2cKs\t0.999134\n2hQs\t0.998384\n2cKh\t0.999134\n2hQd\t0.998384\n2cKd\t0.999134\n2hKs\t0.999134\n2cKc\t0.999069\n2hKd\t0.999134\n2cAs\t0.999375\n2hAs\t0.999375\n2cAh\t0.999375\n2hAd\t0.999375\n2cAd\t0.999375\n4sJd\t0.998619\n4c6h\t0.998793\n4sTc\t0.746475\n5d7c\t0.999284\n4sTd\t0.746475\n5d7h\t0.999284\n2d5d\t0.997305\n5d7s\t0.999284\n2d6d\t0.995154\n4s7d\t0.054927\n2d7d\t0.995828\n5cTs\t0.998028\n2s3s\t0.996645\n2d8d\t0.996726\n4s7h\t0.054927\n5c9s\t0.99831\n2d9d\t0.996303\n3d8d\t0.997718\n3s7s\t0.999628\n4c7h\t0.054927\n4s6c\t0.998793\n2dQs\t0.998384\n4s6d\t0.998793\n3s8s\t0.997718\n2dKs\t0.999134\n4s6h\t0.998793\n2dKd\t0.999069\n5sTc\t0.998028\n2dAs\t0.999375\n2dAh\t0.999375\n3hKd\t0.999133\n2dAc\t0.999375\n5sTd\t0.998028\n4c7d\t0.054927\n5c7d\t0.999284\n5c7s\t0.999284\n2c4c\t0.997887\n5sTh\t0.998028\n3dKh\t0.999133\n2sQd\t0.998384\n2sKd\t0.999134\n5s9c\t0.99831\n2sAd\t0.999375\n3sJh\t0.99866\n4d7s\t0.054927\n3sJd\t0.99866\n3dQh\t0.998311\n3sJc\t0.99866\n4d6s\t0.998793\n5s9d\t0.99831\n3sQh\t0.998311\n3dQs\t0.998311\n3sQd\t0.998311\n3dJs\t0.99866\n3sQc\t0.998311\n4c6s\t0.998793\n5s9h\t0.99831\n3sKh\t0.999133\n3sKd\t0.999133\n2hQc\t0.998384\n3sKc\t0.999133\n2hKc\t0.999134\n5s8c\t0.998541\n2hAc\t0.999375\n3sAh\t0.999944\n2d3d\t0.996645\n3sAd\t0.999944\n3sAc\t0.999944\n4sTh\t0.746475\n5s8d\t0.998541\n5cTd\t0.998028\n5c9d\t0.99831\n5c8d\t0.998541\n2dQh\t0.998384\n2dKh\t0.999134\n5c8s\t0.998541\n5s8h\t0.998541\n2c5c\t0.997305\n4dTs\t0.746475\n5s7c\t0.999284\n3hAs\t0.999944\n3h7h\t0.999628\n3dQc\t0.998311\n5s7d\t0.999284\n2h6h\t0.995154\n5s7h\t0.999284\n2h8h\t0.996726\n3h8h\t0.997718\n3hKc\t0.999133\n2d4d\t0.997887\n4c6d\t0.998793\n3dAc\t0.999944\n5c9h\t0.99831\n2dQc\t0.998384\n5c7h\t0.999284\n2h7h\t0.995828\n3hJs\t0.99866\n4sJc\t0.998619\n3hAc\t0.999944\n4sJh\t0.998619\n3hJd\t0.99866\n5cTh\t0.998028\n3hJc\t0.99866\n3hQs\t0.998311\n3dKc\t0.999133\n3hAd\t0.999944\n3d7d\t0.999628\n2hKh\t0.999069\n3hKs\t0.999133\n3hQc\t0.998311\n3hQd\t0.998311\n2h9h\t0.996303\n2sKs\t0.999069\n2dKc\t0.999134\n5c8h\t0.998541\n2cAc\t0.99962\n2dAd\t0.99962\n2sAs\t0.99962\n2hAh\t0.99962\n2sQs\t1.0\n2dQd\t1.0\n2cQc\t1.0\n2hQh\t1.0\n2hTh\t0.996464\n2sTs\t0.996464\n2dTd\t0.996464\n2cTc\t0.996464\n4sAd\t0.99996\n4cAs\t0.99996\n4dAs\t0.99996\n4dAh\t0.99996\n4dAc\t0.99996\n4sAc\t0.99996\n4cAd\t0.99996\n4sAh\t0.99996\n4cAh\t0.99996\n4dQs\t0.998753\n4sQd\t0.998753\n4cQs\t0.998753\n4sQc\t0.998753\n4cQd\t0.998753\n4cQh\t0.998753\n4sQh\t0.998753\n4dQh\t0.998753\n4dQc\t0.998753\n4c9c\t0.998765\n4d9d\t0.998765\n4s9s\t0.998765\n6h8s\t0.999003\n6d8s\t0.999003\n6c8d\t0.999003\n6c8h\t0.999003\n6c8s\t0.999003\n6s8h\t0.999003\n6d8c\t0.999003\n6d8h\t0.999003\n6s8c\t0.999003\n6h8c\t0.999003\n6h8d\t0.999003\n6s8d\t0.999003\n6cJd\t0.998794\n6cJh\t0.998794\n6sJc\t0.998794\n6cJs\t0.998794\n6hJc\t0.998794\n6hJd\t0.998794\n6dJs\t0.998794\n6dJh\t0.998794\n6dJc\t0.998794\n6hJs\t0.998794\n6sJh\t0.998794\n6sJd\t0.998794\n6sTh\t0.998801\n6cTh\t0.998801\n6dTc\t0.998801\n6cTd\t0.998801\n6hTc\t0.998801\n6hTd\t0.998801\n6hTs\t0.998801\n6cTs\t0.998801\n6dTh\t0.998801\n6dTs\t0.998801\n6sTd\t0.998801\n6sTc\t0.998801\n2sJs\t0.99771\n2cJc\t0.99771\n2hJh\t0.99771\n2dJd\t0.99771\n6d9s\t0.998993\n6c9s\t0.998993\n6h9s\t0.998993\n6s9d\t0.998993\n6h9d\t0.998993\n6h9c\t0.998993\n6c9d\t0.998993\n6c9h\t0.998993\n6s9c\t0.998993\n6d9c\t0.998993\n6d9h\t0.998993\n6s9h\t0.998993\n3d9d\t0.997845\n3s9s\t0.997845\n3h9h\t0.997845\n5cJs\t0.998705\n5dJs\t0.998705\n5sJh\t0.998705\n5cJd\t0.998705\n5dJc\t0.998705\n5dJh\t0.998705\n5sJd\t0.998705\n5cJh\t0.998705\n5sJc\t0.998705\n4c5d\t0.99914\n4s5d\t0.99914\n4d5s\t0.99914\n4d5c\t0.99914\n4c5s\t0.99914\n4s5c\t0.99914\n4dKh\t0.999263\n4sKd\t0.999263\n4dKs\t0.999263\n4sKh\t0.999263\n4cKd\t0.999263\n4dKc\t0.999263\n4sKc\t0.999263\n4cKh\t0.999263\n4cKs\t0.999263\n5d6h\t0.998976\n5d6c\t0.998976\n5d6s\t0.998976\n5c6s\t0.998976\n5c6h\t0.998976\n5s6h\t0.998976\n5s6d\t0.998976\n5s6c\t0.998976\n5c6d\t0.998976\n7hQc\t0.999282\n7cQd\t0.999282\n7sQh\t0.999282\n7dQh\t0.999282\n7hQs\t0.999282\n7hQd\t0.999282\n7dQs\t0.999282\n7sQc\t0.999282\n7sQd\t0.999282\n7cQh\t0.999282\n7cQs\t0.999282\n7dQc\t0.999282\n4s8s\t0.99947\n4c8c\t0.99947\n4d8d\t0.99947\n7s9h\t0.999505\n7s9d\t0.999505\n7c9h\t0.999505\n7d9c\t0.999505\n7c9s\t0.999505\n7d9h\t0.999505\n7h9s\t0.999505\n7c9d\t0.999505\n7s9c\t0.999505\n7h9d\t0.999505\n7h9c\t0.999505\n7d9s\t0.999505\n5cKd\t0.99968\n5cKh\t0.99968\n5cKs\t0.99968\n5sKc\t0.99968\n5dKc\t0.99968\n5dKh\t0.99968\n5sKh\t0.99968\n5dKs\t0.99968\n5sKd\t0.99968\n7hTc\t0.99917\n7cTs\t0.99917\n7dTh\t0.99917\n7hTd\t0.99917\n7dTc\t0.99917\n7hTs\t0.99917\n7cTd\t0.99917\n7cTh\t0.99917\n7sTd\t0.99917\n7sTh\t0.99917\n7dTs\t0.99917\n7sTc\t0.99917\n5dQh\t0.999182\n5sQh\t0.999182\n5cQd\t0.999182\n5cQh\t0.999182\n5sQd\t0.999182\n5sQc\t0.999182\n5cQs\t0.999182\n5dQs\t0.999182\n5dQc\t0.999182\n8dQh\t0.99951\n8cQh\t0.99951\n8sQc\t0.99951\n8cQs\t0.99951\n8sQd\t0.99951\n8hQs\t0.99951\n8cQd\t0.99951\n8hQc\t0.99951\n8sQh\t0.99951\n8hQd\t0.99951\n8dQs\t0.99951\n8dQc\t0.99951\n3dTd\t0.998642\n3hTh\t0.998642\n3sTs\t0.998642\n3dKd\t0.999834\n3hKh\t0.999834\n3sKs\t0.999834\n6d7h\t0.999388\n6c7h\t0.999388\n6c7s\t0.999388\n6d7s\t0.999388\n6h7c\t0.999388\n6h7d\t0.999388\n6c7d\t0.999388\n6h7s\t0.999388\n6s7h\t0.999388\n6s7c\t0.999388\n6s7d\t0.999388\n6d7c\t0.999388\n7cJh\t0.999225\n7cJd\t0.999225\n7dJc\t0.999225\n7hJc\t0.999225\n7dJh\t0.999225\n7dJs\t0.999225\n7sJd\t0.999225\n7cJs\t0.999225\n7hJs\t0.999225\n7sJc\t0.999225\n7hJd\t0.999225\n7sJh\t0.999225\n8cKd\t0.999476\n8dKc\t0.999476\n8hKc\t0.999476\n8sKd\t0.999476\n8dKs\t0.999476\n8dKh\t0.999476\n8hKs\t0.999476\n8sKh\t0.999476\n8cKs\t0.999476\n8sKc\t0.999476\n8cKh\t0.999476\n8hKd\t0.999476\n7h8c\t0.999334\n7h8s\t0.999334\n7d8s\t0.999334\n7c8s\t0.999334\n7c8h\t0.999334\n7s8c\t0.999334\n7c8d\t0.999334\n7h8d\t0.999334\n7s8d\t0.999334\n7d8c\t0.999334\n7s8h\t0.999334\n7d8h\t0.999334\n6dAh\t0.999538\n6sAh\t0.999538\n6cAd\t0.999538\n6sAd\t0.999538\n6hAs\t0.999538\n6hAd\t0.999538\n6dAc\t0.999538\n6cAs\t0.999538\n6dAs\t0.999538\n6sAc\t0.999538\n6hAc\t0.999538\n6cAh\t0.999538\n3h6h\t0.997878\n3s6s\t0.997878\n3d6d\t0.997878\n8hJc\t0.999249\n8dJc\t0.999249\n8hJs\t0.999249\n8sJd\t0.999249\n8dJh\t0.999249\n8sJh\t0.999249\n8dJs\t0.999249\n8hJd\t0.999249\n8sJc\t0.999249\n8cJs\t0.999249\n8cJh\t0.999249\n8cJd\t0.999249\n6dQh\t0.999268\n6cQh\t0.999268\n6dQs\t0.999268\n6hQs\t0.999268\n6cQs\t0.999268\n6hQc\t0.999268\n6hQd\t0.999268\n6sQc\t0.999268\n6dQc\t0.999268\n6sQh\t0.999268\n6sQd\t0.999268\n6cQd\t0.999268\n3sQs\t1.0\n3hQh\t1.0\n3dQd\t1.0\n9cQd\t0.999676\n9sQh\t0.999676\n9sQd\t0.999676\n9hQs\t0.999676\n9hQc\t0.999676\n9cQh\t0.999676\n9dQs\t0.999676\n9dQh\t0.999676\n9hQd\t0.999676\n9dQc\t0.999676\n9cQs\t0.999676\n9sQc\t0.999676\n3dJd\t1.0\n3hJh\t1.0\n3sJs\t1.0\n7dKc\t0.999681\n7dKh\t0.999681\n7dKs\t0.999681\n7hKc\t0.999681\n7hKs\t0.999681\n7hKd\t0.999681\n7cKd\t0.999681\n7cKs\t0.999681\n7sKh\t0.999681\n7sKc\t0.999681\n7sKd\t0.999681\n7cKh\t0.999681\n6hKs\t0.999635\n6sKh\t0.999635\n6dKs\t0.999635\n6sKc\t0.999635\n6dKc\t0.999635\n6hKc\t0.999635\n6hKd\t0.999635\n6dKh\t0.999635\n6cKs\t0.999635\n6sKd\t0.999635\n6cKd\t0.999635\n6cKh\t0.999635\n8hTd\t0.999166\n8hTc\t0.999166\n8cTh\t0.999166\n8sTh\t0.999166\n8cTd\t0.999166\n8dTh\t0.999166\n8hTs\t0.999166\n8dTc\t0.999166\n8sTd\t0.999166\n8sTc\t0.999166\n8dTs\t0.999166\n8cTs\t0.999166\n5cAh\t0.99993\n5sAh\t0.99993\n5dAs\t0.99993\n5dAc\t0.99993\n5cAs\t0.99993\n5sAd\t0.99993\n5sAc\t0.99993\n5dAh\t0.99993\n5cAd\t0.99993\n5dTd\t1.0\n5sTs\t1.0\n5cTc\t1.0\n9sJc\t0.999412\n9cJs\t0.999412\n9sJd\t0.999412\n9cJd\t0.999412\n9hJd\t0.999412\n9dJs\t0.999412\n9sJh\t0.999412\n9hJc\t0.999412\n9hJs\t0.999412\n9cJh\t0.999412\n9dJc\t0.999412\n9dJh\t0.999412\nTcQs\t0.999585\nTsQh\t0.999585\nTcQh\t0.999585\nTdQh\t0.999585\nTdQc\t0.999585\nTdQs\t0.999585\nTcQd\t0.999585\nTsQd\t0.999585\nThQc\t0.999585\nThQd\t0.999585\nThQs\t0.999585\nTsQc\t0.999585\n8c9d\t0.999263\n8s9h\t0.999263\n8h9c\t0.999263\n8c9s\t0.999263\n8d9s\t0.999263\n8c9h\t0.999263\n8d9h\t0.999263\n8d9c\t0.999263\n8h9s\t0.999263\n8s9d\t0.999263\n8s9c\t0.999263\n8h9d\t0.999263\nTsJh\t0.999552\nThJc\t0.999552\nTcJs\t0.999552\nThJd\t0.999552\nTdJs\t0.999552\nTcJd\t0.999552\nTcJh\t0.999552\nTsJc\t0.999552\nThJs\t0.999552\nTdJh\t0.999552\nTdJc\t0.999552\nTsJd\t0.999552\n3sAs\t1.0\n3dAd\t1.0\n3hAh\t1.0\n9cKs\t1.0\n9hKd\t1.0\n9sKc\t1.0\n9hKs\t1.0\n9sKd\t1.0\n9sKh\t1.0\n9dKs\t1.0\n9dKh\t1.0\n9hKc\t1.0\n9dKc\t1.0\n9cKh\t1.0\n9cKd\t1.0\n9sTh\t0.999319\n9dTh\t0.999319\n9sTd\t0.999319\n9cTs\t0.999319\n9dTs\t0.999319\n9sTc\t0.999319\n9cTd\t0.999319\n9cTh\t0.999319\n9hTs\t0.999319\n9dTc\t0.999319\n9hTc\t0.999319\n9hTd\t0.999319\n4dTd\t0.999633\n4cTc\t0.999633\n4sTs\t0.999633\n4s7s\t1.0\n4d7d\t1.0\n4c7c\t1.0\nJdQs\t0.999668\nJdQh\t0.999668\nJcQs\t0.999668\nJdQc\t0.999668\nJsQh\t0.999668\nJsQd\t0.999668\nJsQc\t0.999668\nJhQs\t0.999668\nJhQc\t0.999668\nJhQd\t0.999668\nJcQh\t0.999668\nJcQd\t0.999668\n7cAh\t0.999432\n7sAc\t0.999432\n7hAd\t0.999432\n7dAh\t0.999432\n7cAd\t0.999432\n7hAs\t0.999432\n7sAd\t0.999432\n7hAc\t0.999432\n7cAs\t0.999432\n7sAh\t0.999432\n7dAc\t0.999432\n7dAs\t0.999432\n6sJs\t0.99937\n6cJc\t0.99937\n6hJh\t0.99937\n6dJd\t0.99937\n2s2h\t0.994712\n2s2d\t0.994712\n2d2c\t0.994712\n2s2c\t0.994712\n2h2d\t0.994712\n2h2c\t0.994712\nTcKd\t0.999596\nTdKs\t0.999596\nThKs\t0.999596\nTsKh\t0.999596\nThKc\t0.999596\nTdKc\t0.999596\nTdKh\t0.999596\nTsKc\t0.999596\nTcKs\t0.999596\nThKd\t0.999596\nTcKh\t0.999596\nTsKd\t0.999596\n4dJd\t0.999691\n4sJs\t0.999691\n4cJc\t0.999691\n8sAh\t0.998841\n8cAs\t0.998841\n8dAh\t0.998841\n8dAs\t0.998841\n8hAs\t0.998841\n8hAc\t0.998841\n8sAd\t0.998841\n8dAc\t0.998841\n8hAd\t0.998841\n8cAh\t0.998841\n8cAd\t0.998841\n8sAc\t0.998841\n4sQs\t0.999011\n4cQc\t0.999011\n4dQd\t0.999011\n7dJd\t1.0\n7sJs\t1.0\n7hJh\t1.0\n7cJc\t1.0\n4sKs\t0.999506\n4cKc\t0.999506\n4dKd\t0.999506\n5sQs\t1.0\n5cQc\t1.0\n5dQd\t1.0\nJcKh\t0.999541\nJsKh\t0.999541\nJdKh\t0.999541\nJhKd\t0.999541\nJhKc\t0.999541\nJsKc\t0.999541\nJhKs\t0.999541\nJdKs\t0.999541\nJcKs\t0.999541\nJdKc\t0.999541\nJcKd\t0.999541\nJsKd\t0.999541\n5s9s\t0.99958\n5c9c\t0.99958\n5d9d\t0.99958\n5c8c\t0.999487\n5s8s\t0.999487\n5d8d\t0.999487\n7hQh\t0.999947\n7dQd\t0.999947\n7cQc\t0.999947\n7sQs\t0.999947\n6dQd\t1.0\n6cQc\t1.0\n6hQh\t1.0\n6sQs\t1.0\n5sJs\t0.999097\n5dJd\t0.999097\n5cJc\t0.999097\n3s4s\t0.998532\n3d4d\t0.998532\n3d5d\t0.999632\n3s5s\t0.999632\n6dTd\t0.999359\n6cTc\t0.999359\n6sTs\t0.999359\n6hTh\t0.999359\nQdKc\t0.999563\nQdKs\t0.999563\nQsKc\t0.999563\nQcKd\t0.999563\nQhKs\t0.999563\nQsKh\t0.999563\nQhKd\t0.999563\nQhKc\t0.999563\nQsKd\t0.999563\nQdKh\t0.999563\nQcKs\t0.999563\nQcKh\t0.999563\n9dAs\t0.999563\n9cAd\t0.999563\n9sAc\t0.999563\n9sAh\t0.999563\n9sAd\t0.999563\n9dAc\t0.999563\n9dAh\t0.999563\n9hAs\t0.999563\n9cAs\t0.999563\n9hAd\t0.999563\n9hAc\t0.999563\n9cAh\t0.999563\n7cTc\t0.999773\n7dTd\t0.999773\n7sTs\t0.999773\n7hTh\t0.999773\n8hJh\t1.0\n8sJs\t1.0\n8cJc\t1.0\n8dJd\t1.0\n6s9s\t0.999471\n6c9c\t0.999471\n6h9h\t0.999471\n6d9d\t0.999471\n7h9h\t0.99974\n7c9c\t0.99974\n7d9d\t0.99974\n7s9s\t0.99974\n3s3h\t0.998777\n3s3d\t0.998777\n3h3d\t0.998777\n5sKs\t0.999668\n5cKc\t0.999668\n5dKd\t0.999668\n8cTc\t0.99998\n8sTs\t0.99998\n8dTd\t0.99998\n8hTh\t0.99998\n4s6s\t0.99937\n4d6d\t0.99937\n4c6c\t0.99937\n5s7s\t0.999569\n5d7d\t0.999569\n5c7c\t0.999569\n6s8s\t0.999658\n6c8c\t0.999658\n6h8h\t0.999658\n6d8d\t0.999658\n8h9h\t0.999906\n8d9d\t0.999906\n8c9c\t0.999906\n8s9s\t0.999906\nTdAc\t1.0\nTsAh\t1.0\nTdAh\t1.0\nTcAd\t1.0\nTsAc\t1.0\nTcAs\t1.0\nTsAd\t1.0\nThAc\t1.0\nTcAh\t1.0\nThAd\t1.0\nTdAs\t1.0\nThAs\t1.0\n8dQd\t0.999833\n8cQc\t0.999833\n8sQs\t0.999833\n8hQh\t0.999833\n7s8s\t1.0\n7c8c\t1.0\n7h8h\t1.0\n7d8d\t1.0\n9dJd\t0.999681\n9cJc\t0.999681\n9hJh\t0.999681\n9sJs\t0.999681\n9dTd\t0.99983\n9hTh\t0.99983\n9sTs\t0.99983\n9cTc\t0.99983\nJhAc\t1.0\nJcAd\t1.0\nJdAs\t1.0\nJdAc\t1.0\nJsAc\t1.0\nJhAs\t1.0\nJhAd\t1.0\nJdAh\t1.0\nJsAh\t1.0\nJcAs\t1.0\nJcAh\t1.0\nJsAd\t1.0\n6d7d\t1.0\n6s7s\t1.0\n6c7c\t1.0\n6h7h\t1.0\n6dKd\t0.999788\n6cKc\t0.999788\n6sKs\t0.999788\n6hKh\t0.999788\nKsAc\t0.999809\nKhAd\t0.999809\nKcAs\t0.999809\nKsAh\t0.999809\nKdAc\t0.999809\nKdAh\t0.999809\nKdAs\t0.999809\nKhAc\t0.999809\nKsAd\t0.999809\nKhAs\t0.999809\nKcAd\t0.999809\nKcAh\t0.999809\nJsAs\t0.999261\nAdAc\t0.99494\n8dKd\t0.999783\n4d4c\t1.0\n9dKd\t1.0\n4d5d\t0.999435\nJhJd\t1.0\n9dAd\t1.0\nJhJc\t1.0\nJhQh\t1.0\n4dAd\t1.0\n4c5c\t0.999435\nJhKh\t1.0\n4cAc\t1.0\n5s5d\t1.0\n8d8c\t1.0\n9hAh\t1.0\nJhAh\t0.999261\nTsTh\t1.0\n8hAh\t0.999686\nTsTc\t1.0\n5s5c\t1.0\nJdJc\t1.0\n5s6s\t1.0\nJdQd\t1.0\n8hKh\t0.999783\n5sAs\t1.0\n9hQh\t0.999783\nJdKd\t1.0\nThTc\t1.0\n5d5c\t1.0\nThJh\t1.0\n5d6d\t1.0\n8h8c\t1.0\nThQh\t1.0\nJdAd\t0.999261\n8h8d\t1.0\nThKh\t1.0\n9sAs\t1.0\nThAh\t0.999204\n8sAs\t0.999686\nJcQc\t1.0\n8sKs\t0.999783\nTdJd\t1.0\n5dAd\t1.0\n5c6c\t1.0\nTdQd\t1.0\nJcKc\t1.0\n9sQs\t0.999783\n5cAc\t1.0\nTdKd\t1.0\n6s6h\t1.0\n6s6d\t1.0\nTdAd\t0.999204\nJcAc\t0.999261\n9s9h\t1.0\nQsQh\t1.0\nQsQd\t1.0\nQsQc\t1.0\nQsKs\t1.0\n8cKc\t0.999783\n6s6c\t1.0\n8s8c\t1.0\n8s8d\t1.0\n4s4c\t1.0\nQsAs\t0.99921\nJsJh\t1.0\nQsAh\t1.0\nJsJc\t1.0\nQsAd\t1.0\nQsAc\t1.0\nQhQd\t1.0\n4s5s\t0.999435\nQhQc\t1.0\n4sAs\t1.0\n8s8h\t1.0\nQhKh\t1.0\n7cAc\t0.999863\n7hKh\t0.999909\n7cKc\t0.999909\nQhAs\t1.0\n9cQc\t0.999783\nQhAh\t0.99921\n9cKc\t1.0\nQhAd\t1.0\n9cAc\t1.0\nQhAc\t1.0\nTsJs\t1.0\nQdQc\t1.0\nTsQs\t1.0\n6sAs\t1.0\nTsKs\t1.0\n6h6d\t1.0\nTsAs\t0.999204\nQdKd\t1.0\nThTd\t1.0\n6h6c\t1.0\nQdAs\t1.0\nQdAh\t1.0\n9h9d\t1.0\nQdAd\t0.99921\n9sKs\t1.0\nQdAc\t1.0\n6hAh\t1.0\n6d6c\t1.0\n7dAd\t0.999863\n9s9c\t1.0\nQcKc\t1.0\n8cAc\t0.999686\nQcAs\t1.0\nQcAh\t1.0\nQcAd\t1.0\n4s4d\t1.0\nQcAc\t0.99921\nJsJd\t1.0\nKsKh\t1.0\nKsKd\t1.0\n8dAd\t0.999686\nKsKc\t1.0\n9dQd\t0.999783\nKsAs\t1.0\n6dAd\t1.0\n7dKd\t0.999909\nTsTd\t1.0\n6cAc\t1.0\nKhKd\t1.0\nKhKc\t1.0\n7s7h\t1.0\nKhAh\t1.0\n7s7d\t1.0\n7s7c\t1.0\nTcJc\t1.0\nKdKc\t1.0\nTcKc\t1.0\n7sKs\t0.999909\nJsQs\t1.0\n7sAs\t0.999863\nKdAd\t1.0\n7h7d\t1.0\n7d7c\t1.0\n7h7c\t1.0\nTdTc\t1.0\n7hAh\t0.999863\n9s9d\t1.0\nKcAc\t1.0\nTcAc\t0.999204\nAsAh\t0.99494\n9hKh\t1.0\nAhAc\t0.99494\nAhAd\t0.99494\nAsAc\t0.99494\nAsAd\t0.99494\n9h9c\t1.0\n9d9c\t1.0\nJsKs\t1.0\nTcQc\t1.0\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/flop-situation1-p2.txt",
    "content": "3s5c\t1.0\n4d7c\t1.0\n2c7c\t1.0\n4c9h\t1.0\n5d9c\t1.0\n4dJc\t1.0\n5d9h\t1.0\n2s5s\t1.0\n5d9s\t1.0\n4dJs\t1.0\n2c8c\t1.0\n4dTc\t1.0\n5d8c\t1.0\n4dTh\t1.0\n4c7s\t1.0\n4cJh\t1.0\n2c6c\t1.0\n5d8h\t1.0\n5dTc\t1.0\n2s8s\t1.0\n5dTh\t1.0\n4d9c\t1.0\n5dTs\t1.0\n2s9s\t1.0\n2s4s\t1.0\n4d9s\t1.0\n3d9h\t1.0\n2sTd\t1.0\n4dJh\t1.0\n4d8h\t1.0\n2s6s\t1.0\n2sJd\t1.0\n3dKs\t1.0\n3dAh\t1.0\n4d9h\t1.0\n3d9s\t1.0\n4d8c\t1.0\n2sQc\t1.0\n2sTh\t1.0\n2sKh\t1.0\n2sTc\t1.0\n2sKc\t1.0\n2sJh\t1.0\n2sAh\t1.0\n2sJc\t1.0\n2sAc\t1.0\n2sQh\t1.0\n4d7h\t1.0\n2s7s\t1.0\n2h3h\t1.0\n4cTh\t1.0\n4c9d\t1.0\n5d8s\t1.0\n4d6c\t1.0\n2c9c\t1.0\n4d6h\t1.0\n2cTs\t1.0\n4cJd\t1.0\n2cTh\t1.0\n4cJs\t1.0\n2cTd\t1.0\n4cTd\t1.0\n3d4c\t1.0\n3d6h\t1.0\n2cJs\t1.0\n3dJc\t1.0\n2cJh\t1.0\n3dJh\t1.0\n2cJd\t1.0\n3dTc\t1.0\n4s7c\t1.0\n4cTs\t1.0\n2cQs\t1.0\n2hTs\t1.0\n2cQh\t1.0\n2hTd\t1.0\n2cQd\t1.0\n2hJs\t1.0\n3dAs\t1.0\n2hJd\t1.0\n2cKs\t1.0\n2hQs\t1.0\n2cKh\t1.0\n2hQd\t1.0\n2cKd\t1.0\n2hKs\t1.0\n2cKc\t1.0\n2hKd\t1.0\n2cAs\t1.0\n2hAs\t1.0\n2cAh\t1.0\n2hAd\t1.0\n2cAd\t1.0\n4sJd\t1.0\n4c6h\t1.0\n4sTc\t1.0\n5d7c\t1.0\n4sTd\t1.0\n5d7h\t1.0\n2d5d\t1.0\n5d7s\t1.0\n3d9c\t1.0\n3s4d\t1.0\n2d6d\t1.0\n3s4c\t1.0\n4s9c\t1.0\n4s7d\t1.0\n2d7d\t1.0\n3s5d\t1.0\n5cTs\t1.0\n2s3s\t1.0\n2d8d\t1.0\n4s7h\t1.0\n5c9s\t1.0\n3s6h\t1.0\n2d9d\t1.0\n3s6d\t1.0\n2dTs\t1.0\n3s6c\t1.0\n3d8d\t1.0\n3s7s\t1.0\n2dJs\t1.0\n4c7h\t1.0\n4s9d\t1.0\n4s6c\t1.0\n2dQs\t1.0\n4s6d\t1.0\n3d5s\t1.0\n3s8s\t1.0\n2dKs\t1.0\n4s6h\t1.0\n2dKd\t1.0\n5sTc\t1.0\n2dAs\t1.0\n2dAh\t1.0\n3hKd\t1.0\n2dAc\t1.0\n5sTd\t1.0\n4c7d\t1.0\n5c7d\t1.0\n3s9h\t1.0\n5c7s\t1.0\n3s9d\t1.0\n2c4c\t1.0\n3s9c\t1.0\n4s8c\t1.0\n5sTh\t1.0\n4s8d\t1.0\n3sTh\t1.0\n3dKh\t1.0\n3sTd\t1.0\n2sQd\t1.0\n3sTc\t1.0\n2sKd\t1.0\n5s9c\t1.0\n2sAd\t1.0\n3sJh\t1.0\n4d7s\t1.0\n3sJd\t1.0\n3dQh\t1.0\n3sJc\t1.0\n4d6s\t1.0\n5s9d\t1.0\n3d6c\t1.0\n3sQh\t1.0\n3dQs\t1.0\n3sQd\t1.0\n3dJs\t1.0\n3sQc\t1.0\n4c6s\t1.0\n5s9h\t1.0\n2hTc\t1.0\n3sKh\t1.0\n2hJc\t1.0\n3sKd\t1.0\n2hQc\t1.0\n3sKc\t1.0\n2hKc\t1.0\n5s8c\t1.0\n2hAc\t1.0\n3sAh\t1.0\n2d3d\t1.0\n3sAd\t1.0\n3dTh\t1.0\n3sAc\t1.0\n4sTh\t1.0\n5s8d\t1.0\n5cTd\t1.0\n3h4s\t1.0\n5c9d\t1.0\n3h4d\t1.0\n5c8d\t1.0\n3h4c\t1.0\n2dTh\t1.0\n3h5s\t1.0\n2dJh\t1.0\n3h5d\t1.0\n2dQh\t1.0\n3h5c\t1.0\n2dKh\t1.0\n3h6s\t1.0\n5c8s\t1.0\n5s8h\t1.0\n4s9h\t1.0\n3h6d\t1.0\n2c5c\t1.0\n3h6c\t1.0\n4dTs\t1.0\n5s7c\t1.0\n3hAs\t1.0\n3h7h\t1.0\n3dQc\t1.0\n5s7d\t1.0\n2h6h\t1.0\n5s7h\t1.0\n2h8h\t1.0\n4c8s\t1.0\n3d6s\t1.0\n3h8h\t1.0\n3d5c\t1.0\n4c8h\t1.0\n3hKc\t1.0\n4c8d\t1.0\n2d4d\t1.0\n3h9s\t1.0\n4c6d\t1.0\n3dAc\t1.0\n5c9h\t1.0\n3h9d\t1.0\n2dTc\t1.0\n3h9c\t1.0\n2dQc\t1.0\n3hTs\t1.0\n5c7h\t1.0\n3d4s\t1.0\n4s8h\t1.0\n3hTd\t1.0\n4d8s\t1.0\n3hTc\t1.0\n2h7h\t1.0\n3hJs\t1.0\n4sJc\t1.0\n3hAc\t1.0\n4sJh\t1.0\n3hJd\t1.0\n5cTh\t1.0\n3hJc\t1.0\n2dJc\t1.0\n3hQs\t1.0\n3dKc\t1.0\n3hAd\t1.0\n3d7d\t1.0\n2hKh\t1.0\n4c9s\t1.0\n3hKs\t1.0\n3hQc\t1.0\n3hQd\t1.0\n3dTs\t1.0\n2h9h\t1.0\n2sKs\t1.0\n2dKc\t1.0\n5c8h\t1.0\n2cAc\t0.998052\n2dAd\t0.998052\n2sAs\t0.998052\n2hAh\t0.998052\n2sQs\t0.994289\n2dQd\t0.994289\n2cQc\t0.994289\n2hQh\t0.994289\n2hTh\t0.991671\n2sTs\t0.991671\n2dTd\t0.991671\n2cTc\t0.991671\n4sAd\t0.991476\n4cAs\t0.991476\n4dAs\t0.991476\n4dAh\t0.991476\n4dAc\t0.991476\n4sAc\t0.991476\n4cAd\t0.991476\n4sAh\t0.991476\n4cAh\t0.991476\n4dQs\t0.986773\n4sQd\t0.986773\n4cQs\t0.986773\n4sQc\t0.986773\n4cQd\t0.986773\n4cQh\t0.986773\n4sQh\t0.986773\n4dQh\t0.986773\n4dQc\t0.986773\n4c9c\t0.984597\n4d9d\t0.984597\n4s9s\t0.984597\n6h8s\t0.982601\n6d8s\t0.982601\n6c8d\t0.982601\n6c8h\t0.982601\n6c8s\t0.982601\n6s8h\t0.982601\n6d8c\t0.982601\n6d8h\t0.982601\n6s8c\t0.982601\n6h8c\t0.982601\n6h8d\t0.982601\n6s8d\t0.982601\n6cJd\t0.981204\n6cJh\t0.981204\n6sJc\t0.981204\n6cJs\t0.981204\n6hJc\t0.981204\n6hJd\t0.981204\n6dJs\t0.981204\n6dJh\t0.981204\n6dJc\t0.981204\n6hJs\t0.981204\n6sJh\t0.981204\n6sJd\t0.981204\n6sTh\t0.979326\n6cTh\t0.979326\n6dTc\t0.979326\n6cTd\t0.979326\n6hTc\t0.979326\n6hTd\t0.979326\n6hTs\t0.979326\n6cTs\t0.979326\n6dTh\t0.979326\n6dTs\t0.979326\n6sTd\t0.979326\n6sTc\t0.979326\n2sJs\t0.977355\n2cJc\t0.977355\n2hJh\t0.977355\n2dJd\t0.977355\n6d9s\t0.96981\n6c9s\t0.96981\n6h9s\t0.96981\n6s9d\t0.96981\n6h9d\t0.96981\n6h9c\t0.96981\n6c9d\t0.96981\n6c9h\t0.96981\n6s9c\t0.96981\n6d9c\t0.96981\n6d9h\t0.96981\n6s9h\t0.96981\n3d9d\t0.969495\n3s9s\t0.969495\n3h9h\t0.969495\n5cJs\t0.968892\n5dJs\t0.968892\n5sJh\t0.968892\n5cJd\t0.968892\n5dJc\t0.968892\n5dJh\t0.968892\n5sJd\t0.968892\n5cJh\t0.968892\n5sJc\t0.968892\n4c5d\t0.960249\n4s5d\t0.960249\n4d5s\t0.960249\n4d5c\t0.960249\n4c5s\t0.960249\n4s5c\t0.960249\n4dKh\t0.95173\n4sKd\t0.95173\n4dKs\t0.95173\n4sKh\t0.95173\n4cKd\t0.95173\n4dKc\t0.95173\n4sKc\t0.95173\n4cKh\t0.95173\n4cKs\t0.95173\n5d6h\t0.903048\n5d6c\t0.903048\n5d6s\t0.903048\n5c6s\t0.903048\n5c6h\t0.903048\n5s6h\t0.903048\n5s6d\t0.903048\n5s6c\t0.903048\n5c6d\t0.903048\n7hQc\t0.866116\n7cQd\t0.866116\n7sQh\t0.866116\n7dQh\t0.866116\n7hQs\t0.866116\n7hQd\t0.866116\n7dQs\t0.866116\n7sQc\t0.866116\n7sQd\t0.866116\n7cQh\t0.866116\n7cQs\t0.866116\n7dQc\t0.866116\n4s8s\t0.86404\n4c8c\t0.86404\n4d8d\t0.86404\n7s9h\t0.861573\n7s9d\t0.861573\n7c9h\t0.861573\n7d9c\t0.861573\n7c9s\t0.861573\n7d9h\t0.861573\n7h9s\t0.861573\n7c9d\t0.861573\n7s9c\t0.861573\n7h9d\t0.861573\n7h9c\t0.861573\n7d9s\t0.861573\n5cKd\t0.854165\n5cKh\t0.854165\n5cKs\t0.854165\n5sKc\t0.854165\n5dKc\t0.854165\n5dKh\t0.854165\n5sKh\t0.854165\n5dKs\t0.854165\n5sKd\t0.854165\n7hTc\t0.847387\n7cTs\t0.847387\n7dTh\t0.847387\n7hTd\t0.847387\n7dTc\t0.847387\n7hTs\t0.847387\n7cTd\t0.847387\n7cTh\t0.847387\n7sTd\t0.847387\n7sTh\t0.847387\n7dTs\t0.847387\n7sTc\t0.847387\n5dQh\t0.847241\n5sQh\t0.847241\n5cQd\t0.847241\n5cQh\t0.847241\n5sQd\t0.847241\n5sQc\t0.847241\n5cQs\t0.847241\n5dQs\t0.847241\n5dQc\t0.847241\n8dQh\t0.846896\n8cQh\t0.846896\n8sQc\t0.846896\n8cQs\t0.846896\n8sQd\t0.846896\n8hQs\t0.846896\n8cQd\t0.846896\n8hQc\t0.846896\n8sQh\t0.846896\n8hQd\t0.846896\n8dQs\t0.846896\n8dQc\t0.846896\n3dTd\t0.844179\n3hTh\t0.844179\n3sTs\t0.844179\n3dKd\t0.84136\n3hKh\t0.84136\n3sKs\t0.84136\n6d7h\t0.830509\n6c7h\t0.830509\n6c7s\t0.830509\n6d7s\t0.830509\n6h7c\t0.830509\n6h7d\t0.830509\n6c7d\t0.830509\n6h7s\t0.830509\n6s7h\t0.830509\n6s7c\t0.830509\n6s7d\t0.830509\n6d7c\t0.830509\n7cJh\t0.819686\n7cJd\t0.819686\n7dJc\t0.819686\n7hJc\t0.819686\n7dJh\t0.819686\n7dJs\t0.819686\n7sJd\t0.819686\n7cJs\t0.819686\n7hJs\t0.819686\n7sJc\t0.819686\n7hJd\t0.819686\n7sJh\t0.819686\n8cKd\t0.815898\n8dKc\t0.815898\n8hKc\t0.815898\n8sKd\t0.815898\n8dKs\t0.815898\n8dKh\t0.815898\n8hKs\t0.815898\n8sKh\t0.815898\n8cKs\t0.815898\n8sKc\t0.815898\n8cKh\t0.815898\n8hKd\t0.815898\n7h8c\t0.801449\n7h8s\t0.801449\n7d8s\t0.801449\n7c8s\t0.801449\n7c8h\t0.801449\n7s8c\t0.801449\n7c8d\t0.801449\n7h8d\t0.801449\n7s8d\t0.801449\n7d8c\t0.801449\n7s8h\t0.801449\n7d8h\t0.801449\n6dAh\t0.797539\n6sAh\t0.797539\n6cAd\t0.797539\n6sAd\t0.797539\n6hAs\t0.797539\n6hAd\t0.797539\n6dAc\t0.797539\n6cAs\t0.797539\n6dAs\t0.797539\n6sAc\t0.797539\n6hAc\t0.797539\n6cAh\t0.797539\n3h6h\t0.788231\n3s6s\t0.788231\n3d6d\t0.788231\n8hJc\t0.775972\n8dJc\t0.775972\n8hJs\t0.775972\n8sJd\t0.775972\n8dJh\t0.775972\n8sJh\t0.775972\n8dJs\t0.775972\n8hJd\t0.775972\n8sJc\t0.775972\n8cJs\t0.775972\n8cJh\t0.775972\n8cJd\t0.775972\n6dQh\t0.773292\n6cQh\t0.773292\n6dQs\t0.773292\n6hQs\t0.773292\n6cQs\t0.773292\n6hQc\t0.773292\n6hQd\t0.773292\n6sQc\t0.773292\n6dQc\t0.773292\n6sQh\t0.773292\n6sQd\t0.773292\n6cQd\t0.773292\n3sQs\t0.770838\n3hQh\t0.770838\n3dQd\t0.770838\n9cQd\t0.766948\n9sQh\t0.766948\n9sQd\t0.766948\n9hQs\t0.766948\n9hQc\t0.766948\n9cQh\t0.766948\n9dQs\t0.766948\n9dQh\t0.766948\n9hQd\t0.766948\n9dQc\t0.766948\n9cQs\t0.766948\n9sQc\t0.766948\n3dJd\t0.762357\n3hJh\t0.762357\n3sJs\t0.762357\n7dKc\t0.75886\n7dKh\t0.75886\n7dKs\t0.75886\n7hKc\t0.75886\n7hKs\t0.75886\n7hKd\t0.75886\n7cKd\t0.75886\n7cKs\t0.75886\n7sKh\t0.75886\n7sKc\t0.75886\n7sKd\t0.75886\n7cKh\t0.75886\n6hKs\t0.757507\n6sKh\t0.757507\n6dKs\t0.757507\n6sKc\t0.757507\n6dKc\t0.757507\n6hKc\t0.757507\n6hKd\t0.757507\n6dKh\t0.757507\n6cKs\t0.757507\n6sKd\t0.757507\n6cKd\t0.757507\n6cKh\t0.757507\n8hTd\t0.756533\n8hTc\t0.756533\n8cTh\t0.756533\n8sTh\t0.756533\n8cTd\t0.756533\n8dTh\t0.756533\n8hTs\t0.756533\n8dTc\t0.756533\n8sTd\t0.756533\n8sTc\t0.756533\n8dTs\t0.756533\n8cTs\t0.756533\n5cAh\t0.728201\n5sAh\t0.728201\n5dAs\t0.728201\n5dAc\t0.728201\n5cAs\t0.728201\n5sAd\t0.728201\n5sAc\t0.728201\n5dAh\t0.728201\n5cAd\t0.728201\n5dTd\t0.727556\n5sTs\t0.727556\n5cTc\t0.727556\n9sJc\t0.726804\n9cJs\t0.726804\n9sJd\t0.726804\n9cJd\t0.726804\n9hJd\t0.726804\n9dJs\t0.726804\n9sJh\t0.726804\n9hJc\t0.726804\n9hJs\t0.726804\n9cJh\t0.726804\n9dJc\t0.726804\n9dJh\t0.726804\n2s9c\t0.687853\n2d9s\t0.687853\n2h9d\t0.687853\n2h9c\t0.687853\n2d9c\t0.687853\n2c9s\t0.687853\n2c9h\t0.687853\n2d9h\t0.687853\n2h9s\t0.687853\n2s9h\t0.687853\n2c9d\t0.687853\n2s9d\t0.687853\nTcQs\t0.687123\nTsQh\t0.687123\nTcQh\t0.687123\nTdQh\t0.687123\nTdQc\t0.687123\nTdQs\t0.687123\nTcQd\t0.687123\nTsQd\t0.687123\nThQc\t0.687123\nThQd\t0.687123\nThQs\t0.687123\nTsQc\t0.687123\n8c9d\t0.674819\n8s9h\t0.674819\n8h9c\t0.674819\n8c9s\t0.674819\n8d9s\t0.674819\n8c9h\t0.674819\n8d9h\t0.674819\n8d9c\t0.674819\n8h9s\t0.674819\n8s9d\t0.674819\n8s9c\t0.674819\n8h9d\t0.674819\nTsJh\t0.63339\nThJc\t0.63339\nTcJs\t0.63339\nThJd\t0.63339\nTdJs\t0.63339\nTcJd\t0.63339\nTcJh\t0.63339\nTsJc\t0.63339\nThJs\t0.63339\nTdJh\t0.63339\nTdJc\t0.63339\nTsJd\t0.63339\n3sAs\t0.624236\n3dAd\t0.624236\n3hAh\t0.624236\n9cKs\t0.617503\n9hKd\t0.617503\n9sKc\t0.617503\n9hKs\t0.617503\n9sKd\t0.617503\n9sKh\t0.617503\n9dKs\t0.617503\n9dKh\t0.617503\n9hKc\t0.617503\n9dKc\t0.617503\n9cKh\t0.617503\n9cKd\t0.617503\n9sTh\t0.607465\n9dTh\t0.607465\n9sTd\t0.607465\n9cTs\t0.607465\n9dTs\t0.607465\n9sTc\t0.607465\n9cTd\t0.607465\n9cTh\t0.607465\n9hTs\t0.607465\n9dTc\t0.607465\n9hTc\t0.607465\n9hTd\t0.607465\n4dTd\t0.590917\n4cTc\t0.590917\n4sTs\t0.590917\n4s7s\t0.579037\n4d7d\t0.579037\n4c7c\t0.579037\nJdQs\t0.578568\nJdQh\t0.578568\nJcQs\t0.578568\nJdQc\t0.578568\nJsQh\t0.578568\nJsQd\t0.578568\nJsQc\t0.578568\nJhQs\t0.578568\nJhQc\t0.578568\nJhQd\t0.578568\nJcQh\t0.578568\nJcQd\t0.578568\n7cAh\t0.57586\n7sAc\t0.57586\n7hAd\t0.57586\n7dAh\t0.57586\n7cAd\t0.57586\n7hAs\t0.57586\n7sAd\t0.57586\n7hAc\t0.57586\n7cAs\t0.57586\n7sAh\t0.57586\n7dAc\t0.57586\n7dAs\t0.57586\n6sJs\t0.575364\n6cJc\t0.575364\n6hJh\t0.575364\n6dJd\t0.575364\n2s2h\t0.543474\n2s2d\t0.543474\n2d2c\t0.543474\n2s2c\t0.543474\n2h2d\t0.543474\n2h2c\t0.543474\nTcKd\t0.504897\nTdKs\t0.504897\nThKs\t0.504897\nTsKh\t0.504897\nThKc\t0.504897\nTdKc\t0.504897\nTdKh\t0.504897\nTsKc\t0.504897\nTcKs\t0.504897\nThKd\t0.504897\nTcKh\t0.504897\nTsKd\t0.504897\n4dJd\t0.470046\n4sJs\t0.470046\n4cJc\t0.470046\n8sAh\t0.424842\n8cAs\t0.424842\n8dAh\t0.424842\n8dAs\t0.424842\n8hAs\t0.424842\n8hAc\t0.424842\n8sAd\t0.424842\n8dAc\t0.424842\n8hAd\t0.424842\n8cAh\t0.424842\n8cAd\t0.424842\n8sAc\t0.424842\n4sQs\t0.40569\n4cQc\t0.40569\n4dQd\t0.40569\n7dJd\t0.394607\n7sJs\t0.394607\n7hJh\t0.394607\n7cJc\t0.394607\n4sKs\t0.394111\n4cKc\t0.394111\n4dKd\t0.394111\n5sQs\t0.387608\n5cQc\t0.387608\n5dQd\t0.387608\nJcKh\t0.384868\nJsKh\t0.384868\nJdKh\t0.384868\nJhKd\t0.384868\nJhKc\t0.384868\nJsKc\t0.384868\nJhKs\t0.384868\nJdKs\t0.384868\nJcKs\t0.384868\nJdKc\t0.384868\nJcKd\t0.384868\nJsKd\t0.384868\n5s9s\t0.382969\n5c9c\t0.382969\n5d9d\t0.382969\n5c8c\t0.369193\n5s8s\t0.369193\n5d8d\t0.369193\n7hQh\t0.364789\n7dQd\t0.364789\n7cQc\t0.364789\n7sQs\t0.364789\n6dQd\t0.355186\n6cQc\t0.355186\n6hQh\t0.355186\n6sQs\t0.355186\n5sJs\t0.352002\n5dJd\t0.352002\n5cJc\t0.352002\n3s4s\t0.321444\n3d4d\t0.321444\n3d5d\t0.320805\n3s5s\t0.320805\n3s7c\t0.264895\n3h7c\t0.264895\n3d7c\t0.264895\n3s7h\t0.264895\n3s7d\t0.264895\n3d7h\t0.264895\n3h7s\t0.264895\n3h7d\t0.264895\n3d7s\t0.264895\n6dTd\t0.254433\n6cTc\t0.254433\n6sTs\t0.254433\n6hTh\t0.254433\nQdKc\t0.235819\nQdKs\t0.235819\nQsKc\t0.235819\nQcKd\t0.235819\nQhKs\t0.235819\nQsKh\t0.235819\nQhKd\t0.235819\nQhKc\t0.235819\nQsKd\t0.235819\nQdKh\t0.235819\nQcKs\t0.235819\nQcKh\t0.235819\n9dAs\t0.224596\n9cAd\t0.224596\n9sAc\t0.224596\n9sAh\t0.224596\n9sAd\t0.224596\n9dAc\t0.224596\n9dAh\t0.224596\n9hAs\t0.224596\n9cAs\t0.224596\n9hAd\t0.224596\n9hAc\t0.224596\n9cAh\t0.224596\n7cTc\t0.217163\n7dTd\t0.217163\n7sTs\t0.217163\n7hTh\t0.217163\n8hJh\t0.207646\n8sJs\t0.207646\n8cJc\t0.207646\n8dJd\t0.207646\n6s9s\t0.181485\n6c9c\t0.181485\n6h9h\t0.181485\n6d9d\t0.181485\n7h9h\t0.166302\n7c9c\t0.166302\n7d9d\t0.166302\n7s9s\t0.166302\n3s3h\t0.165745\n3s3d\t0.165745\n3h3d\t0.165745\n5sKs\t0.152201\n5cKc\t0.152201\n5dKd\t0.152201\n8cTc\t0.151698\n8sTs\t0.151698\n8dTd\t0.151698\n8hTh\t0.151698\n2s5c\t0.137359\n2h5s\t0.137359\n2c5d\t0.137359\n2c5s\t0.137359\n2d5c\t0.137359\n2h5d\t0.137359\n2d5s\t0.137359\n2h5c\t0.137359\n2s5d\t0.137359\n4s6s\t0.135811\n4d6d\t0.135811\n4c6c\t0.135811\n5s7s\t0.129799\n5d7d\t0.129799\n5c7c\t0.129799\n6s8s\t0.112885\n6c8c\t0.112885\n6h8h\t0.112885\n6d8d\t0.112885\n8h9h\t0.077446\n8d9d\t0.077446\n8c9c\t0.077446\n8s9s\t0.077446\nTdAc\t0.07454\nTsAh\t0.07454\nTdAh\t0.07454\nTcAd\t0.07454\nTsAc\t0.07454\nTcAs\t0.07454\nTsAd\t0.07454\nThAc\t0.07454\nTcAh\t0.07454\nThAd\t0.07454\nTdAs\t0.07454\nThAs\t0.07454\n8dQd\t0.070912\n8cQc\t0.070912\n8sQs\t0.070912\n8hQh\t0.070912\n7s8s\t0.062422\n7c8c\t0.062422\n7h8h\t0.062422\n7d8d\t0.062422\n9dJd\t0.038739\n9cJc\t0.038739\n9hJh\t0.038739\n9sJs\t0.038739\n9dTd\t0.033651\n9hTh\t0.033651\n9sTs\t0.033651\n9cTc\t0.033651\nJhAc\t0.0119\nJcAd\t0.0119\nJdAs\t0.0119\nJdAc\t0.0119\nJsAc\t0.0119\nJhAs\t0.0119\nJhAd\t0.0119\nJdAh\t0.0119\nJsAh\t0.0119\nJcAs\t0.0119\nJcAh\t0.0119\nJsAd\t0.0119\n6d7d\t0.009426\n6s7s\t0.009426\n6c7c\t0.009426\n6h7h\t0.009426\n6dKd\t0.003541\n6cKc\t0.003541\n6sKs\t0.003541\n6hKh\t0.003541\nKsAc\t0.00052\nKhAd\t0.00052\nKcAs\t0.00052\nKsAh\t0.00052\nKdAc\t0.00052\nKdAh\t0.00052\nKdAs\t0.00052\nKhAc\t0.00052\nKsAd\t0.00052\nKhAs\t0.00052\nKcAd\t0.00052\nKcAh\t0.00052\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/flop-situation2-p1.txt",
    "content": "4d7c\t0.054927\n2c7c\t0.995828\n5d9c\t0.99831\n4dJc\t0.998619\n5d9h\t0.99831\n2s5s\t0.997305\n5d9s\t0.99831\n4dJs\t0.998619\n2c8c\t0.996726\n4dTc\t0.746475\n5d8c\t0.998541\n4dTh\t0.746475\n4c7s\t0.054927\n4cJh\t0.998619\n2c6c\t0.995154\n5d8h\t0.998541\n5dTc\t0.998028\n2s8s\t0.996726\n5dTh\t0.998028\n5dTs\t0.998028\n2s9s\t0.996303\n2s4s\t0.997887\n4dJh\t0.998619\n2s6s\t0.995154\n3dKs\t0.999133\n3dAh\t0.999944\n2sQc\t0.998384\n2sKh\t0.999134\n2sKc\t0.999134\n2sAh\t0.999375\n2sAc\t0.999375\n2sQh\t0.998384\n4d7h\t0.054927\n2s7s\t0.995828\n2h3h\t0.996645\n4cTh\t0.746475\n5d8s\t0.998541\n4d6c\t0.998793\n2c9c\t0.996303\n4d6h\t0.998793\n4cJd\t0.998619\n4cJs\t0.998619\n4cTd\t0.746475\n3dJc\t0.99866\n3dJh\t0.99866\n4s7c\t0.054927\n4cTs\t0.746475\n2cQs\t0.998384\n2cQh\t0.998384\n2cQd\t0.998384\n3dAs\t0.999944\n2cKs\t0.999134\n2hQs\t0.998384\n2cKh\t0.999134\n2hQd\t0.998384\n2cKd\t0.999134\n2hKs\t0.999134\n2cKc\t0.999069\n2hKd\t0.999134\n2cAs\t0.999375\n2hAs\t0.999375\n2cAh\t0.999375\n2hAd\t0.999375\n2cAd\t0.999375\n4sJd\t0.998619\n4c6h\t0.998793\n4sTc\t0.746475\n5d7c\t0.999284\n4sTd\t0.746475\n5d7h\t0.999284\n2d5d\t0.997305\n5d7s\t0.999284\n2d6d\t0.995154\n4s7d\t0.054927\n2d7d\t0.995828\n5cTs\t0.998028\n2s3s\t0.996645\n2d8d\t0.996726\n4s7h\t0.054927\n5c9s\t0.99831\n2d9d\t0.996303\n3d8d\t0.997718\n3s7s\t0.999628\n4c7h\t0.054927\n4s6c\t0.998793\n2dQs\t0.998384\n4s6d\t0.998793\n3s8s\t0.997718\n2dKs\t0.999134\n4s6h\t0.998793\n2dKd\t0.999069\n5sTc\t0.998028\n2dAs\t0.999375\n2dAh\t0.999375\n3hKd\t0.999133\n2dAc\t0.999375\n5sTd\t0.998028\n4c7d\t0.054927\n5c7d\t0.999284\n5c7s\t0.999284\n2c4c\t0.997887\n5sTh\t0.998028\n3dKh\t0.999133\n2sQd\t0.998384\n2sKd\t0.999134\n5s9c\t0.99831\n2sAd\t0.999375\n3sJh\t0.99866\n4d7s\t0.054927\n3sJd\t0.99866\n3dQh\t0.998311\n3sJc\t0.99866\n4d6s\t0.998793\n5s9d\t0.99831\n3sQh\t0.998311\n3dQs\t0.998311\n3sQd\t0.998311\n3dJs\t0.99866\n3sQc\t0.998311\n4c6s\t0.998793\n5s9h\t0.99831\n3sKh\t0.999133\n3sKd\t0.999133\n2hQc\t0.998384\n3sKc\t0.999133\n2hKc\t0.999134\n5s8c\t0.998541\n2hAc\t0.999375\n3sAh\t0.999944\n2d3d\t0.996645\n3sAd\t0.999944\n3sAc\t0.999944\n4sTh\t0.746475\n5s8d\t0.998541\n5cTd\t0.998028\n5c9d\t0.99831\n5c8d\t0.998541\n2dQh\t0.998384\n2dKh\t0.999134\n5c8s\t0.998541\n5s8h\t0.998541\n2c5c\t0.997305\n4dTs\t0.746475\n5s7c\t0.999284\n3hAs\t0.999944\n3h7h\t0.999628\n3dQc\t0.998311\n5s7d\t0.999284\n2h6h\t0.995154\n5s7h\t0.999284\n2h8h\t0.996726\n3h8h\t0.997718\n3hKc\t0.999133\n2d4d\t0.997887\n4c6d\t0.998793\n3dAc\t0.999944\n5c9h\t0.99831\n2dQc\t0.998384\n5c7h\t0.999284\n2h7h\t0.995828\n3hJs\t0.99866\n4sJc\t0.998619\n3hAc\t0.999944\n4sJh\t0.998619\n3hJd\t0.99866\n5cTh\t0.998028\n3hJc\t0.99866\n3hQs\t0.998311\n3dKc\t0.999133\n3hAd\t0.999944\n3d7d\t0.999628\n2hKh\t0.999069\n3hKs\t0.999133\n3hQc\t0.998311\n3hQd\t0.998311\n2h9h\t0.996303\n2sKs\t0.999069\n2dKc\t0.999134\n5c8h\t0.998541\n2cAc\t0.99962\n2dAd\t0.99962\n2sAs\t0.99962\n2hAh\t0.99962\n2sQs\t1.0\n2dQd\t1.0\n2cQc\t1.0\n2hQh\t1.0\n2hTh\t0.996464\n2sTs\t0.996464\n2dTd\t0.996464\n2cTc\t0.996464\n4sAd\t0.99996\n4cAs\t0.99996\n4dAs\t0.99996\n4dAh\t0.99996\n4dAc\t0.99996\n4sAc\t0.99996\n4cAd\t0.99996\n4sAh\t0.99996\n4cAh\t0.99996\n4dQs\t0.998753\n4sQd\t0.998753\n4cQs\t0.998753\n4sQc\t0.998753\n4cQd\t0.998753\n4cQh\t0.998753\n4sQh\t0.998753\n4dQh\t0.998753\n4dQc\t0.998753\n4c9c\t0.998765\n4d9d\t0.998765\n4s9s\t0.998765\n6h8s\t0.999003\n6d8s\t0.999003\n6c8d\t0.999003\n6c8h\t0.999003\n6c8s\t0.999003\n6s8h\t0.999003\n6d8c\t0.999003\n6d8h\t0.999003\n6s8c\t0.999003\n6h8c\t0.999003\n6h8d\t0.999003\n6s8d\t0.999003\n6cJd\t0.998794\n6cJh\t0.998794\n6sJc\t0.998794\n6cJs\t0.998794\n6hJc\t0.998794\n6hJd\t0.998794\n6dJs\t0.998794\n6dJh\t0.998794\n6dJc\t0.998794\n6hJs\t0.998794\n6sJh\t0.998794\n6sJd\t0.998794\n6sTh\t0.998801\n6cTh\t0.998801\n6dTc\t0.998801\n6cTd\t0.998801\n6hTc\t0.998801\n6hTd\t0.998801\n6hTs\t0.998801\n6cTs\t0.998801\n6dTh\t0.998801\n6dTs\t0.998801\n6sTd\t0.998801\n6sTc\t0.998801\n2sJs\t0.99771\n2cJc\t0.99771\n2hJh\t0.99771\n2dJd\t0.99771\n6d9s\t0.998993\n6c9s\t0.998993\n6h9s\t0.998993\n6s9d\t0.998993\n6h9d\t0.998993\n6h9c\t0.998993\n6c9d\t0.998993\n6c9h\t0.998993\n6s9c\t0.998993\n6d9c\t0.998993\n6d9h\t0.998993\n6s9h\t0.998993\n3d9d\t0.997845\n3s9s\t0.997845\n3h9h\t0.997845\n5cJs\t0.998705\n5dJs\t0.998705\n5sJh\t0.998705\n5cJd\t0.998705\n5dJc\t0.998705\n5dJh\t0.998705\n5sJd\t0.998705\n5cJh\t0.998705\n5sJc\t0.998705\n4c5d\t0.99914\n4s5d\t0.99914\n4d5s\t0.99914\n4d5c\t0.99914\n4c5s\t0.99914\n4s5c\t0.99914\n4dKh\t0.999263\n4sKd\t0.999263\n4dKs\t0.999263\n4sKh\t0.999263\n4cKd\t0.999263\n4dKc\t0.999263\n4sKc\t0.999263\n4cKh\t0.999263\n4cKs\t0.999263\n5d6h\t0.998976\n5d6c\t0.998976\n5d6s\t0.998976\n5c6s\t0.998976\n5c6h\t0.998976\n5s6h\t0.998976\n5s6d\t0.998976\n5s6c\t0.998976\n5c6d\t0.998976\n7hQc\t0.999282\n7cQd\t0.999282\n7sQh\t0.999282\n7dQh\t0.999282\n7hQs\t0.999282\n7hQd\t0.999282\n7dQs\t0.999282\n7sQc\t0.999282\n7sQd\t0.999282\n7cQh\t0.999282\n7cQs\t0.999282\n7dQc\t0.999282\n4s8s\t0.99947\n4c8c\t0.99947\n4d8d\t0.99947\n7s9h\t0.999505\n7s9d\t0.999505\n7c9h\t0.999505\n7d9c\t0.999505\n7c9s\t0.999505\n7d9h\t0.999505\n7h9s\t0.999505\n7c9d\t0.999505\n7s9c\t0.999505\n7h9d\t0.999505\n7h9c\t0.999505\n7d9s\t0.999505\n5cKd\t0.99968\n5cKh\t0.99968\n5cKs\t0.99968\n5sKc\t0.99968\n5dKc\t0.99968\n5dKh\t0.99968\n5sKh\t0.99968\n5dKs\t0.99968\n5sKd\t0.99968\n7hTc\t0.99917\n7cTs\t0.99917\n7dTh\t0.99917\n7hTd\t0.99917\n7dTc\t0.99917\n7hTs\t0.99917\n7cTd\t0.99917\n7cTh\t0.99917\n7sTd\t0.99917\n7sTh\t0.99917\n7dTs\t0.99917\n7sTc\t0.99917\n5dQh\t0.999182\n5sQh\t0.999182\n5cQd\t0.999182\n5cQh\t0.999182\n5sQd\t0.999182\n5sQc\t0.999182\n5cQs\t0.999182\n5dQs\t0.999182\n5dQc\t0.999182\n8dQh\t0.99951\n8cQh\t0.99951\n8sQc\t0.99951\n8cQs\t0.99951\n8sQd\t0.99951\n8hQs\t0.99951\n8cQd\t0.99951\n8hQc\t0.99951\n8sQh\t0.99951\n8hQd\t0.99951\n8dQs\t0.99951\n8dQc\t0.99951\n3dTd\t0.998642\n3hTh\t0.998642\n3sTs\t0.998642\n3dKd\t0.999834\n3hKh\t0.999834\n3sKs\t0.999834\n6d7h\t0.999388\n6c7h\t0.999388\n6c7s\t0.999388\n6d7s\t0.999388\n6h7c\t0.999388\n6h7d\t0.999388\n6c7d\t0.999388\n6h7s\t0.999388\n6s7h\t0.999388\n6s7c\t0.999388\n6s7d\t0.999388\n6d7c\t0.999388\n7cJh\t0.999225\n7cJd\t0.999225\n7dJc\t0.999225\n7hJc\t0.999225\n7dJh\t0.999225\n7dJs\t0.999225\n7sJd\t0.999225\n7cJs\t0.999225\n7hJs\t0.999225\n7sJc\t0.999225\n7hJd\t0.999225\n7sJh\t0.999225\n8cKd\t0.999476\n8dKc\t0.999476\n8hKc\t0.999476\n8sKd\t0.999476\n8dKs\t0.999476\n8dKh\t0.999476\n8hKs\t0.999476\n8sKh\t0.999476\n8cKs\t0.999476\n8sKc\t0.999476\n8cKh\t0.999476\n8hKd\t0.999476\n7h8c\t0.999334\n7h8s\t0.999334\n7d8s\t0.999334\n7c8s\t0.999334\n7c8h\t0.999334\n7s8c\t0.999334\n7c8d\t0.999334\n7h8d\t0.999334\n7s8d\t0.999334\n7d8c\t0.999334\n7s8h\t0.999334\n7d8h\t0.999334\n6dAh\t0.999538\n6sAh\t0.999538\n6cAd\t0.999538\n6sAd\t0.999538\n6hAs\t0.999538\n6hAd\t0.999538\n6dAc\t0.999538\n6cAs\t0.999538\n6dAs\t0.999538\n6sAc\t0.999538\n6hAc\t0.999538\n6cAh\t0.999538\n3h6h\t0.997878\n3s6s\t0.997878\n3d6d\t0.997878\n8hJc\t0.999249\n8dJc\t0.999249\n8hJs\t0.999249\n8sJd\t0.999249\n8dJh\t0.999249\n8sJh\t0.999249\n8dJs\t0.999249\n8hJd\t0.999249\n8sJc\t0.999249\n8cJs\t0.999249\n8cJh\t0.999249\n8cJd\t0.999249\n6dQh\t0.999268\n6cQh\t0.999268\n6dQs\t0.999268\n6hQs\t0.999268\n6cQs\t0.999268\n6hQc\t0.999268\n6hQd\t0.999268\n6sQc\t0.999268\n6dQc\t0.999268\n6sQh\t0.999268\n6sQd\t0.999268\n6cQd\t0.999268\n3sQs\t1.0\n3hQh\t1.0\n3dQd\t1.0\n9cQd\t0.999676\n9sQh\t0.999676\n9sQd\t0.999676\n9hQs\t0.999676\n9hQc\t0.999676\n9cQh\t0.999676\n9dQs\t0.999676\n9dQh\t0.999676\n9hQd\t0.999676\n9dQc\t0.999676\n9cQs\t0.999676\n9sQc\t0.999676\n3dJd\t1.0\n3hJh\t1.0\n3sJs\t1.0\n7dKc\t0.999681\n7dKh\t0.999681\n7dKs\t0.999681\n7hKc\t0.999681\n7hKs\t0.999681\n7hKd\t0.999681\n7cKd\t0.999681\n7cKs\t0.999681\n7sKh\t0.999681\n7sKc\t0.999681\n7sKd\t0.999681\n7cKh\t0.999681\n6hKs\t0.999635\n6sKh\t0.999635\n6dKs\t0.999635\n6sKc\t0.999635\n6dKc\t0.999635\n6hKc\t0.999635\n6hKd\t0.999635\n6dKh\t0.999635\n6cKs\t0.999635\n6sKd\t0.999635\n6cKd\t0.999635\n6cKh\t0.999635\n8hTd\t0.999166\n8hTc\t0.999166\n8cTh\t0.999166\n8sTh\t0.999166\n8cTd\t0.999166\n8dTh\t0.999166\n8hTs\t0.999166\n8dTc\t0.999166\n8sTd\t0.999166\n8sTc\t0.999166\n8dTs\t0.999166\n8cTs\t0.999166\n5cAh\t0.99993\n5sAh\t0.99993\n5dAs\t0.99993\n5dAc\t0.99993\n5cAs\t0.99993\n5sAd\t0.99993\n5sAc\t0.99993\n5dAh\t0.99993\n5cAd\t0.99993\n5dTd\t1.0\n5sTs\t1.0\n5cTc\t1.0\n9sJc\t0.999412\n9cJs\t0.999412\n9sJd\t0.999412\n9cJd\t0.999412\n9hJd\t0.999412\n9dJs\t0.999412\n9sJh\t0.999412\n9hJc\t0.999412\n9hJs\t0.999412\n9cJh\t0.999412\n9dJc\t0.999412\n9dJh\t0.999412\nTcQs\t0.999585\nTsQh\t0.999585\nTcQh\t0.999585\nTdQh\t0.999585\nTdQc\t0.999585\nTdQs\t0.999585\nTcQd\t0.999585\nTsQd\t0.999585\nThQc\t0.999585\nThQd\t0.999585\nThQs\t0.999585\nTsQc\t0.999585\n8c9d\t0.999263\n8s9h\t0.999263\n8h9c\t0.999263\n8c9s\t0.999263\n8d9s\t0.999263\n8c9h\t0.999263\n8d9h\t0.999263\n8d9c\t0.999263\n8h9s\t0.999263\n8s9d\t0.999263\n8s9c\t0.999263\n8h9d\t0.999263\nTsJh\t0.999552\nThJc\t0.999552\nTcJs\t0.999552\nThJd\t0.999552\nTdJs\t0.999552\nTcJd\t0.999552\nTcJh\t0.999552\nTsJc\t0.999552\nThJs\t0.999552\nTdJh\t0.999552\nTdJc\t0.999552\nTsJd\t0.999552\n3sAs\t1.0\n3dAd\t1.0\n3hAh\t1.0\n9cKs\t1.0\n9hKd\t1.0\n9sKc\t1.0\n9hKs\t1.0\n9sKd\t1.0\n9sKh\t1.0\n9dKs\t1.0\n9dKh\t1.0\n9hKc\t1.0\n9dKc\t1.0\n9cKh\t1.0\n9cKd\t1.0\n9sTh\t0.999319\n9dTh\t0.999319\n9sTd\t0.999319\n9cTs\t0.999319\n9dTs\t0.999319\n9sTc\t0.999319\n9cTd\t0.999319\n9cTh\t0.999319\n9hTs\t0.999319\n9dTc\t0.999319\n9hTc\t0.999319\n9hTd\t0.999319\n4dTd\t0.999633\n4cTc\t0.999633\n4sTs\t0.999633\n4s7s\t1.0\n4d7d\t1.0\n4c7c\t1.0\nJdQs\t0.999668\nJdQh\t0.999668\nJcQs\t0.999668\nJdQc\t0.999668\nJsQh\t0.999668\nJsQd\t0.999668\nJsQc\t0.999668\nJhQs\t0.999668\nJhQc\t0.999668\nJhQd\t0.999668\nJcQh\t0.999668\nJcQd\t0.999668\n7cAh\t0.999432\n7sAc\t0.999432\n7hAd\t0.999432\n7dAh\t0.999432\n7cAd\t0.999432\n7hAs\t0.999432\n7sAd\t0.999432\n7hAc\t0.999432\n7cAs\t0.999432\n7sAh\t0.999432\n7dAc\t0.999432\n7dAs\t0.999432\n6sJs\t0.99937\n6cJc\t0.99937\n6hJh\t0.99937\n6dJd\t0.99937\n2s2h\t0.994712\n2s2d\t0.994712\n2d2c\t0.994712\n2s2c\t0.994712\n2h2d\t0.994712\n2h2c\t0.994712\nTcKd\t0.999596\nTdKs\t0.999596\nThKs\t0.999596\nTsKh\t0.999596\nThKc\t0.999596\nTdKc\t0.999596\nTdKh\t0.999596\nTsKc\t0.999596\nTcKs\t0.999596\nThKd\t0.999596\nTcKh\t0.999596\nTsKd\t0.999596\n4dJd\t0.999691\n4sJs\t0.999691\n4cJc\t0.999691\n8sAh\t0.998841\n8cAs\t0.998841\n8dAh\t0.998841\n8dAs\t0.998841\n8hAs\t0.998841\n8hAc\t0.998841\n8sAd\t0.998841\n8dAc\t0.998841\n8hAd\t0.998841\n8cAh\t0.998841\n8cAd\t0.998841\n8sAc\t0.998841\n4sQs\t0.999011\n4cQc\t0.999011\n4dQd\t0.999011\n7dJd\t1.0\n7sJs\t1.0\n7hJh\t1.0\n7cJc\t1.0\n4sKs\t0.999506\n4cKc\t0.999506\n4dKd\t0.999506\n5sQs\t1.0\n5cQc\t1.0\n5dQd\t1.0\nJcKh\t0.999541\nJsKh\t0.999541\nJdKh\t0.999541\nJhKd\t0.999541\nJhKc\t0.999541\nJsKc\t0.999541\nJhKs\t0.999541\nJdKs\t0.999541\nJcKs\t0.999541\nJdKc\t0.999541\nJcKd\t0.999541\nJsKd\t0.999541\n5s9s\t0.99958\n5c9c\t0.99958\n5d9d\t0.99958\n5c8c\t0.999487\n5s8s\t0.999487\n5d8d\t0.999487\n7hQh\t0.999947\n7dQd\t0.999947\n7cQc\t0.999947\n7sQs\t0.999947\n6dQd\t1.0\n6cQc\t1.0\n6hQh\t1.0\n6sQs\t1.0\n5sJs\t0.999097\n5dJd\t0.999097\n5cJc\t0.999097\n3s4s\t0.998532\n3d4d\t0.998532\n3d5d\t0.999632\n3s5s\t0.999632\n6dTd\t0.999359\n6cTc\t0.999359\n6sTs\t0.999359\n6hTh\t0.999359\nQdKc\t0.999563\nQdKs\t0.999563\nQsKc\t0.999563\nQcKd\t0.999563\nQhKs\t0.999563\nQsKh\t0.999563\nQhKd\t0.999563\nQhKc\t0.999563\nQsKd\t0.999563\nQdKh\t0.999563\nQcKs\t0.999563\nQcKh\t0.999563\n9dAs\t0.999563\n9cAd\t0.999563\n9sAc\t0.999563\n9sAh\t0.999563\n9sAd\t0.999563\n9dAc\t0.999563\n9dAh\t0.999563\n9hAs\t0.999563\n9cAs\t0.999563\n9hAd\t0.999563\n9hAc\t0.999563\n9cAh\t0.999563\n7cTc\t0.999773\n7dTd\t0.999773\n7sTs\t0.999773\n7hTh\t0.999773\n8hJh\t1.0\n8sJs\t1.0\n8cJc\t1.0\n8dJd\t1.0\n6s9s\t0.999471\n6c9c\t0.999471\n6h9h\t0.999471\n6d9d\t0.999471\n7h9h\t0.99974\n7c9c\t0.99974\n7d9d\t0.99974\n7s9s\t0.99974\n3s3h\t0.998777\n3s3d\t0.998777\n3h3d\t0.998777\n5sKs\t0.999668\n5cKc\t0.999668\n5dKd\t0.999668\n8cTc\t0.99998\n8sTs\t0.99998\n8dTd\t0.99998\n8hTh\t0.99998\n4s6s\t0.99937\n4d6d\t0.99937\n4c6c\t0.99937\n5s7s\t0.999569\n5d7d\t0.999569\n5c7c\t0.999569\n6s8s\t0.999658\n6c8c\t0.999658\n6h8h\t0.999658\n6d8d\t0.999658\n8h9h\t0.999906\n8d9d\t0.999906\n8c9c\t0.999906\n8s9s\t0.999906\nTdAc\t1.0\nTsAh\t1.0\nTdAh\t1.0\nTcAd\t1.0\nTsAc\t1.0\nTcAs\t1.0\nTsAd\t1.0\nThAc\t1.0\nTcAh\t1.0\nThAd\t1.0\nTdAs\t1.0\nThAs\t1.0\n8dQd\t0.999833\n8cQc\t0.999833\n8sQs\t0.999833\n8hQh\t0.999833\n7s8s\t1.0\n7c8c\t1.0\n7h8h\t1.0\n7d8d\t1.0\n9dJd\t0.999681\n9cJc\t0.999681\n9hJh\t0.999681\n9sJs\t0.999681\n9dTd\t0.99983\n9hTh\t0.99983\n9sTs\t0.99983\n9cTc\t0.99983\nJhAc\t1.0\nJcAd\t1.0\nJdAs\t1.0\nJdAc\t1.0\nJsAc\t1.0\nJhAs\t1.0\nJhAd\t1.0\nJdAh\t1.0\nJsAh\t1.0\nJcAs\t1.0\nJcAh\t1.0\nJsAd\t1.0\n6d7d\t1.0\n6s7s\t1.0\n6c7c\t1.0\n6h7h\t1.0\n6dKd\t0.999788\n6cKc\t0.999788\n6sKs\t0.999788\n6hKh\t0.999788\nKsAc\t0.999809\nKhAd\t0.999809\nKcAs\t0.999809\nKsAh\t0.999809\nKdAc\t0.999809\nKdAh\t0.999809\nKdAs\t0.999809\nKhAc\t0.999809\nKsAd\t0.999809\nKhAs\t0.999809\nKcAd\t0.999809\nKcAh\t0.999809\nJsAs\t0.999261\nAdAc\t0.99494\n8dKd\t0.999783\n4d4c\t1.0\n9dKd\t1.0\n4d5d\t0.999435\nJhJd\t1.0\n9dAd\t1.0\nJhJc\t1.0\nJhQh\t1.0\n4dAd\t1.0\n4c5c\t0.999435\nJhKh\t1.0\n4cAc\t1.0\n5s5d\t1.0\n8d8c\t1.0\n9hAh\t1.0\nJhAh\t0.999261\nTsTh\t1.0\n8hAh\t0.999686\nTsTc\t1.0\n5s5c\t1.0\nJdJc\t1.0\n5s6s\t1.0\nJdQd\t1.0\n8hKh\t0.999783\n5sAs\t1.0\n9hQh\t0.999783\nJdKd\t1.0\nThTc\t1.0\n5d5c\t1.0\nThJh\t1.0\n5d6d\t1.0\n8h8c\t1.0\nThQh\t1.0\nJdAd\t0.999261\n8h8d\t1.0\nThKh\t1.0\n9sAs\t1.0\nThAh\t0.999204\n8sAs\t0.999686\nJcQc\t1.0\n8sKs\t0.999783\nTdJd\t1.0\n5dAd\t1.0\n5c6c\t1.0\nTdQd\t1.0\nJcKc\t1.0\n9sQs\t0.999783\n5cAc\t1.0\nTdKd\t1.0\n6s6h\t1.0\n6s6d\t1.0\nTdAd\t0.999204\nJcAc\t0.999261\n9s9h\t1.0\nQsQh\t1.0\nQsQd\t1.0\nQsQc\t1.0\nQsKs\t1.0\n8cKc\t0.999783\n6s6c\t1.0\n8s8c\t1.0\n8s8d\t1.0\n4s4c\t1.0\nQsAs\t0.99921\nJsJh\t1.0\nQsAh\t1.0\nJsJc\t1.0\nQsAd\t1.0\nQsAc\t1.0\nQhQd\t1.0\n4s5s\t0.999435\nQhQc\t1.0\n4sAs\t1.0\n8s8h\t1.0\nQhKh\t1.0\n7cAc\t0.999863\n7hKh\t0.999909\n7cKc\t0.999909\nQhAs\t1.0\n9cQc\t0.999783\nQhAh\t0.99921\n9cKc\t1.0\nQhAd\t1.0\n9cAc\t1.0\nQhAc\t1.0\nTsJs\t1.0\nQdQc\t1.0\nTsQs\t1.0\n6sAs\t1.0\nTsKs\t1.0\n6h6d\t1.0\nTsAs\t0.999204\nQdKd\t1.0\nThTd\t1.0\n6h6c\t1.0\nQdAs\t1.0\nQdAh\t1.0\n9h9d\t1.0\nQdAd\t0.99921\n9sKs\t1.0\nQdAc\t1.0\n6hAh\t1.0\n6d6c\t1.0\n7dAd\t0.999863\n9s9c\t1.0\nQcKc\t1.0\n8cAc\t0.999686\nQcAs\t1.0\nQcAh\t1.0\nQcAd\t1.0\n4s4d\t1.0\nQcAc\t0.99921\nJsJd\t1.0\nKsKh\t1.0\nKsKd\t1.0\n8dAd\t0.999686\nKsKc\t1.0\n9dQd\t0.999783\nKsAs\t1.0\n6dAd\t1.0\n7dKd\t0.999909\nTsTd\t1.0\n6cAc\t1.0\nKhKd\t1.0\nKhKc\t1.0\n7s7h\t1.0\nKhAh\t1.0\n7s7d\t1.0\n7s7c\t1.0\nTcJc\t1.0\nKdKc\t1.0\nTcKc\t1.0\n7sKs\t0.999909\nJsQs\t1.0\n7sAs\t0.999863\nKdAd\t1.0\n7h7d\t1.0\n7d7c\t1.0\n7h7c\t1.0\nTdTc\t1.0\n7hAh\t0.999863\n9s9d\t1.0\nKcAc\t1.0\nTcAc\t0.999204\nAsAh\t0.99494\n9hKh\t1.0\nAhAc\t0.99494\nAhAd\t0.99494\nAsAc\t0.99494\nAsAd\t0.99494\n9h9c\t1.0\n9d9c\t1.0\nJsKs\t1.0\nTcQc\t1.0\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/flop-situation2-p2.txt",
    "content": "6d7h\t0.830509\n6c7h\t0.830509\n6c7s\t0.830509\n6d7s\t0.830509\n6h7c\t0.830509\n6h7d\t0.830509\n6c7d\t0.830509\n6h7s\t0.830509\n6s7h\t0.830509\n6s7c\t0.830509\n6s7d\t0.830509\n6d7c\t0.830509\n7cJh\t0.819686\n7cJd\t0.819686\n7dJc\t0.819686\n7hJc\t0.819686\n7dJh\t0.819686\n7dJs\t0.819686\n7sJd\t0.819686\n7cJs\t0.819686\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/flop-situation3-p1.txt",
    "content": "8s8h\t1.0\nAhAc\t0.99494\n4s4c\t1.0\n5sAs\t1.0\n9dQd\t0.999783\n9hAh\t1.0\nJhJc\t0.999812\nJsQs\t1.0\nJhJd\t0.999812\nKhKd\t0.99985\n9cAc\t1.0\nAsAh\t0.99494\nTsTh\t0.999517\nKsKd\t0.99985\nJsAs\t0.999261\nQcAc\t0.99921\n8dKd\t0.999783\nQcAs\t1.0\nTsTd\t0.999517\n8s8c\t1.0\nJsKs\t1.0\nQdAc\t1.0\n4s4h\t1.0\nQdAs\t1.0\n4s4d\t1.0\n7dKd\t0.999833\nTsTc\t0.999517\nQdQc\t0.999789\nKhAh\t1.0\nQhAh\t0.99921\nJsJc\t0.999812\n7d7c\t0.999893\nJsJd\t0.999812\n7hAh\t0.999378\nJsJh\t0.999812\nQhQd\t0.999789\nTcAc\t0.999078\nQsAh\t1.0\n6d6c\t0.999991\n8sAs\t0.999386\n6hAh\t1.0\nQsKs\t1.0\nTsJs\t0.999815\nQsQd\t0.999789\n5hAh\t1.0\nJcAc\t0.999261\n6h6c\t0.999991\n5s6s\t1.0\nTcQc\t1.0\n7hKh\t0.999833\n4s5s\t0.999406\nJcQc\t1.0\n6h6d\t0.999991\n7sAs\t0.999378\n6sAs\t1.0\n5s5c\t1.0\nTcJc\t0.999815\n5s5d\t1.0\n5d5c\t1.0\nAsAc\t0.99494\n8cAc\t0.999386\n8hAh\t0.999386\n4sAs\t0.999938\n8d8c\t1.0\n9s9h\t1.0\nJdJc\t0.999812\n9s9d\t1.0\nJhAh\t0.999261\n9s9c\t1.0\n7s7d\t0.999893\nTdKd\t0.999882\n7s7h\t0.999893\nTsQs\t1.0\n5h6h\t1.0\n4c5c\t0.999406\n9dKd\t1.0\n4h4d\t1.0\nKsAs\t1.0\nTdQd\t1.0\nQcAh\t1.0\n4h4c\t1.0\n7cAc\t0.999378\n4h5h\t0.999406\nQdKd\t1.0\n6s6c\t0.999991\nQhAc\t1.0\nTdJd\t0.999815\nQhKh\t1.0\n9sQs\t0.999783\nQsAc\t1.0\n6s6d\t0.999991\n8h8d\t1.0\nTdTc\t0.999517\nQsQh\t0.999789\n6s6h\t0.999991\n8h8c\t1.0\nThAh\t0.999078\n7h7d\t0.999893\n5cAc\t1.0\n9cQc\t0.999783\n9sKs\t1.0\n8hKh\t0.999783\nThKh\t0.999882\n7s7c\t0.999893\n9sAs\t1.0\n4cAc\t0.999938\n9h9d\t1.0\n6cAc\t1.0\n4hAh\t0.999938\n5h5d\t1.0\nThQh\t1.0\n8s8d\t1.0\n4d4c\t1.0\n8sKs\t0.999783\n4d5d\t0.999406\nQhQc\t0.999789\n9h9c\t1.0\nQsQc\t0.999789\nThJh\t0.999815\n7h7c\t0.999893\n9d9c\t1.0\nJdKd\t1.0\nThTc\t0.999517\n5s5h\t1.0\nThTd\t0.999517\nJhQh\t1.0\n5c6c\t1.0\nQdAh\t1.0\n9hQh\t0.999783\nQsAs\t0.99921\n7sKs\t0.999833\nTsKs\t0.999882\n5d6d\t1.0\n9hKh\t1.0\nTsAs\t0.999078\nJdQd\t1.0\n5h5c\t1.0\nQhAs\t1.0\nKsKh\t0.99985\nJhKh\t1.0\nKdAc\t0.999809\nKdAs\t0.999809\nKhAc\t0.999809\nKsAh\t0.999809\nKdAh\t0.999809\nKhAs\t0.999809\nKsAc\t0.999809\n6dKd\t0.999788\n6hKh\t0.999788\n6sKs\t0.999788\n6d7d\t1.0\n6s7s\t1.0\n6c7c\t1.0\n6h7h\t1.0\nJhAs\t0.999991\nJsAc\t0.999991\nJhAc\t0.999991\nJsAh\t0.999991\nJdAs\t0.999991\nJcAh\t0.999991\nJcAs\t0.999991\nJdAc\t0.999991\nJdAh\t0.999991\n9hTh\t0.999241\n9cTc\t0.999241\n9sTs\t0.999241\n9dTd\t0.999241\n9cJc\t0.999681\n9hJh\t0.999681\n9sJs\t0.999681\n9dJd\t0.999681\n7s8s\t0.999593\n7d8d\t0.999593\n7h8h\t0.999593\n7c8c\t0.999593\n8cQc\t0.999833\n8hQh\t0.999833\n8sQs\t0.999833\n8dQd\t0.999833\nThAs\t1.0\nTcAs\t1.0\nTcAh\t1.0\nTsAh\t1.0\nThAc\t1.0\nTdAh\t1.0\nTdAc\t1.0\nTsAc\t1.0\nTdAs\t1.0\n8c9c\t0.99976\n8d9d\t0.99976\n8s9s\t0.99976\n8h9h\t0.99976\n6c8c\t0.999658\n6d8d\t0.999658\n6h8h\t0.999658\n6s8s\t0.999658\n5h7h\t0.999569\n5c7c\t0.999569\n5d7d\t0.999569\n5s7s\t0.999569\n4s6s\t0.99937\n4d6d\t0.99937\n4h6h\t0.99937\n4c6c\t0.99937\n8dTd\t0.999506\n8hTh\t0.999506\n8cTc\t0.999506\n8sTs\t0.999506\n5sKs\t0.999668\n5hKh\t0.999668\n5dKd\t0.999668\n3s3d\t0.998486\n3h3d\t0.998486\n3s3h\t0.998486\n7h9h\t0.999421\n7d9d\t0.999421\n7s9s\t0.999421\n7c9c\t0.999421\n6d9d\t0.999321\n6h9h\t0.999321\n6c9c\t0.999321\n6s9s\t0.999321\n8dJd\t1.0\n8sJs\t1.0\n8hJh\t1.0\n8cJc\t1.0\n7hTh\t0.99966\n7cTc\t0.99966\n7dTd\t0.99966\n7sTs\t0.99966\n9cAs\t0.999563\n9sAc\t0.999563\n9dAs\t0.999563\n9cAh\t0.999563\n9dAh\t0.999563\n9sAh\t0.999563\n9hAc\t0.999563\n9dAc\t0.999563\n9hAs\t0.999563\nQsKh\t0.999563\nQcKs\t0.999563\nQhKd\t0.999563\nQhKs\t0.999563\nQdKs\t0.999563\nQcKh\t0.999563\nQsKd\t0.999563\nQcKd\t0.999563\nQdKh\t0.999563\n6cTc\t0.999359\n6dTd\t0.999359\n6sTs\t0.999359\n6hTh\t0.999359\n3h5h\t0.999632\n3s5s\t0.999632\n3d5d\t0.999632\n3d4d\t0.998532\n3h4h\t0.998532\n3s4s\t0.998532\n5hJh\t0.999097\n5dJd\t0.999097\n5sJs\t0.999097\n5cJc\t0.999097\n6hQh\t1.0\n6cQc\t1.0\n6sQs\t1.0\n6dQd\t1.0\n7sQs\t0.999947\n7dQd\t0.999947\n7cQc\t0.999947\n7hQh\t0.999947\n5s8s\t0.999487\n5c8c\t0.999487\n5d8d\t0.999487\n5h8h\t0.999487\n5s9s\t0.999539\n5h9h\t0.999539\n5c9c\t0.999539\n5d9d\t0.999539\nJcKs\t0.999541\nJhKs\t0.999541\nJdKs\t0.999541\nJsKd\t0.999541\nJhKd\t0.999541\nJsKh\t0.999541\nJcKh\t0.999541\nJcKd\t0.999541\nJdKh\t0.999541\n5dQd\t1.0\n5cQc\t1.0\n5sQs\t1.0\n5hQh\t1.0\n4dKd\t0.999506\n4sKs\t0.999506\n4hKh\t0.999506\n7cJc\t1.0\n7sJs\t1.0\n7dJd\t1.0\n7hJh\t1.0\n4sQs\t0.998908\n4dQd\t0.998908\n4cQc\t0.998908\n4hQh\t0.998908\n8dAh\t0.998841\n8hAc\t0.998841\n8hAs\t0.998841\n8sAh\t0.998841\n8dAc\t0.998841\n8cAs\t0.998841\n8cAh\t0.998841\n8sAc\t0.998841\n8dAs\t0.998841\n4cJc\t0.999519\n4hJh\t0.999519\n4sJs\t0.999519\n4dJd\t0.999519\nTcKd\t0.999596\nTcKh\t0.999596\nThKs\t0.999596\nTdKs\t0.999596\nTdKh\t0.999596\nThKd\t0.999596\nTsKh\t0.999596\nTcKs\t0.999596\nTsKd\t0.999596\n2s2h\t0.994151\n2d2c\t0.994151\n2h2c\t0.994151\n2h2d\t0.994151\n2s2c\t0.994151\n2s2d\t0.994151\n6sJs\t0.99937\n6hJh\t0.99937\n6cJc\t0.99937\n6dJd\t0.99937\n7dAs\t0.999388\n7hAc\t0.999388\n7sAh\t0.999388\n7sAc\t0.999388\n7dAh\t0.999388\n7hAs\t0.999388\n7cAh\t0.999388\n7cAs\t0.999388\n7dAc\t0.999388\nJcQd\t0.999517\nJhQc\t0.999517\nJdQh\t0.999517\nJsQh\t0.999517\nJcQh\t0.999517\nJdQc\t0.999517\nJdQs\t0.999517\nJsQc\t0.999517\nJhQs\t0.999517\nJhQd\t0.999517\nJsQd\t0.999517\nJcQs\t0.999517\n4c7c\t1.0\n4d7d\t1.0\n4h7h\t1.0\n4s7s\t1.0\n4hTh\t0.999347\n4dTd\t0.999347\n4sTs\t0.999347\n4cTc\t0.999347\n9hTc\t0.999158\n9cTh\t0.999158\n9dTh\t0.999158\n9hTs\t0.999158\n9sTc\t0.999158\n9sTh\t0.999158\n9cTd\t0.999158\n9hTd\t0.999158\n9sTd\t0.999158\n9dTc\t0.999158\n9cTs\t0.999158\n9dTs\t0.999158\n9cKs\t1.0\n9cKh\t1.0\n9dKs\t1.0\n9sKd\t1.0\n9hKs\t1.0\n9hKd\t1.0\n9dKh\t1.0\n9sKh\t1.0\n9cKd\t1.0\n3hAh\t0.999815\n3sAs\t0.999815\nTdJh\t0.999512\nTcJs\t0.999512\nTsJh\t0.999512\nTdJs\t0.999512\nTsJd\t0.999512\nTsJc\t0.999512\nThJd\t0.999512\nThJc\t0.999512\nTdJc\t0.999512\nThJs\t0.999512\nTcJh\t0.999512\nTcJd\t0.999512\n8s9h\t0.999263\n8c9s\t0.999263\n8s9d\t0.999263\n8s9c\t0.999263\n8h9c\t0.999263\n8c9h\t0.999263\n8d9s\t0.999263\n8d9h\t0.999263\n8c9d\t0.999263\n8h9d\t0.999263\n8d9c\t0.999263\n8h9s\t0.999263\nTsQd\t0.999368\nThQs\t0.999368\nTsQh\t0.999368\nTsQc\t0.999368\nTdQs\t0.999368\nTcQd\t0.999368\nTdQh\t0.999368\nTcQh\t0.999368\nTcQs\t0.999368\nThQd\t0.999368\nThQc\t0.999368\nTdQc\t0.999368\n9sJh\t0.999412\n9dJc\t0.999412\n9hJs\t0.999412\n9hJc\t0.999412\n9sJc\t0.999412\n9hJd\t0.999412\n9dJs\t0.999412\n9cJs\t0.999412\n9cJh\t0.999412\n9cJd\t0.999412\n9dJh\t0.999412\n9sJd\t0.999412\n5cTc\t1.0\n5sTs\t1.0\n5dTd\t1.0\n5hTh\t1.0\n5dAs\t0.999721\n5hAc\t0.999721\n5sAc\t0.999721\n5hAs\t0.999721\n5cAh\t0.999721\n5sAh\t0.999721\n5cAs\t0.999721\n5dAc\t0.999721\n5dAh\t0.999721\n8sTc\t0.999166\n8dTh\t0.999166\n8sTd\t0.999166\n8hTd\t0.999166\n8sTh\t0.999166\n8hTc\t0.999166\n8hTs\t0.999166\n8dTc\t0.999166\n8cTd\t0.999166\n8dTs\t0.999166\n8cTs\t0.999166\n8cTh\t0.999166\n6cKs\t0.999635\n6hKd\t0.999635\n6cKh\t0.999635\n6cKd\t0.999635\n6sKd\t0.999635\n6dKh\t0.999635\n6sKh\t0.999635\n6hKs\t0.999635\n6dKs\t0.999635\n7sKd\t0.999455\n7dKh\t0.999455\n7cKs\t0.999455\n7hKs\t0.999455\n7dKs\t0.999455\n7cKh\t0.999455\n7hKd\t0.999455\n7cKd\t0.999455\n7sKh\t0.999455\n3sJs\t1.0\n3hJh\t1.0\n3dJd\t1.0\n9dQc\t0.999502\n9hQc\t0.999502\n9sQc\t0.999502\n9cQs\t0.999502\n9sQh\t0.999502\n9hQs\t0.999502\n9sQd\t0.999502\n9hQd\t0.999502\n9cQh\t0.999502\n9cQd\t0.999502\n9dQs\t0.999502\n9dQh\t0.999502\n3hQh\t0.999811\n3sQs\t0.999811\n3dQd\t0.999811\n6hQc\t0.999029\n6hQd\t0.999029\n6cQh\t0.999029\n6sQh\t0.999029\n6sQc\t0.999029\n6dQs\t0.999029\n6hQs\t0.999029\n6sQd\t0.999029\n6dQh\t0.999029\n6cQd\t0.999029\n6dQc\t0.999029\n6cQs\t0.999029\n8sJc\t0.999249\n8dJs\t0.999249\n8dJc\t0.999249\n8sJd\t0.999249\n8sJh\t0.999249\n8cJh\t0.999249\n8dJh\t0.999249\n8hJd\t0.999249\n8hJc\t0.999249\n8cJd\t0.999249\n8hJs\t0.999249\n8cJs\t0.999249\n3d6d\t0.997878\n3s6s\t0.997878\n3h6h\t0.997878\n6dAc\t0.999486\n6dAh\t0.999486\n6dAs\t0.999486\n6cAh\t0.999486\n6hAc\t0.999486\n6sAh\t0.999486\n6sAc\t0.999486\n6hAs\t0.999486\n6cAs\t0.999486\n7c8h\t0.999334\n7h8c\t0.999334\n7d8s\t0.999334\n7s8c\t0.999334\n7s8d\t0.999334\n7h8s\t0.999334\n7h8d\t0.999334\n7s8h\t0.999334\n7c8s\t0.999334\n7d8h\t0.999334\n7d8c\t0.999334\n7c8d\t0.999334\n8dKh\t0.999476\n8hKd\t0.999476\n8dKs\t0.999476\n8cKs\t0.999476\n8cKh\t0.999476\n8cKd\t0.999476\n8sKh\t0.999476\n8sKd\t0.999476\n8hKs\t0.999476\n7sJd\t0.99917\n7hJs\t0.99917\n7dJs\t0.99917\n7cJh\t0.99917\n7dJh\t0.99917\n7hJc\t0.99917\n7dJc\t0.99917\n7hJd\t0.99917\n7sJh\t0.99917\n7cJd\t0.99917\n7cJs\t0.99917\n7sJc\t0.99917\n6d7h\t0.999388\n6c7s\t0.999388\n6c7h\t0.999388\n6d7c\t0.999388\n6h7s\t0.999388\n6h7d\t0.999388\n6h7c\t0.999388\n6s7h\t0.999388\n6d7s\t0.999388\n6s7c\t0.999388\n6s7d\t0.999388\n6c7d\t0.999388\n3sKs\t0.999802\n3dKd\t0.999802\n3hKh\t0.999802\n3dTd\t0.998642\n3sTs\t0.998642\n3hTh\t0.998642\n8hQd\t0.999244\n8dQs\t0.999244\n8cQs\t0.999244\n8hQc\t0.999244\n8hQs\t0.999244\n8dQc\t0.999244\n8sQc\t0.999244\n8sQd\t0.999244\n8cQh\t0.999244\n8cQd\t0.999244\n8sQh\t0.999244\n8dQh\t0.999244\n5dQs\t0.999073\n5dQh\t0.999073\n5sQc\t0.999073\n5dQc\t0.999073\n5sQd\t0.999073\n5hQs\t0.999073\n5cQd\t0.999073\n5hQd\t0.999073\n5hQc\t0.999073\n5cQh\t0.999073\n5cQs\t0.999073\n5sQh\t0.999073\n7cTs\t0.99917\n7dTh\t0.99917\n7sTc\t0.99917\n7dTc\t0.99917\n7cTd\t0.99917\n7sTh\t0.99917\n7sTd\t0.99917\n7cTh\t0.99917\n7hTc\t0.99917\n7hTd\t0.99917\n7hTs\t0.99917\n7dTs\t0.99917\n5cKs\t0.999452\n5hKd\t0.999452\n5hKs\t0.999452\n5cKh\t0.999452\n5dKs\t0.999452\n5sKh\t0.999452\n5dKh\t0.999452\n5cKd\t0.999452\n5sKd\t0.999452\n7c9h\t0.999505\n7c9d\t0.999505\n7d9c\t0.999505\n7h9s\t0.999505\n7d9h\t0.999505\n7d9s\t0.999505\n7s9c\t0.999505\n7h9d\t0.999505\n7c9s\t0.999505\n7s9h\t0.999505\n7s9d\t0.999505\n7h9c\t0.999505\n4h8h\t0.99947\n4s8s\t0.99947\n4c8c\t0.99947\n4d8d\t0.99947\n7hQc\t0.999282\n7cQs\t0.999282\n7dQc\t0.999282\n7cQd\t0.999282\n7dQh\t0.999282\n7hQd\t0.999282\n7sQc\t0.999282\n7hQs\t0.999282\n7dQs\t0.999282\n7cQh\t0.999282\n7sQd\t0.999282\n7sQh\t0.999282\n5h6s\t0.998976\n5c6s\t0.998976\n5s6h\t0.998976\n5h6c\t0.998976\n5s6d\t0.998976\n5h6d\t0.998976\n5d6c\t0.998976\n5c6h\t0.998976\n5c6d\t0.998976\n5d6s\t0.998976\n5s6c\t0.998976\n5d6h\t0.998976\n4dKh\t0.999183\n4cKh\t0.999183\n4sKh\t0.999183\n4dKs\t0.999183\n4hKd\t0.999183\n4sKd\t0.999183\n4cKd\t0.999183\n4hKs\t0.999183\n4cKs\t0.999183\n4c5d\t0.99914\n4h5s\t0.99914\n4s5d\t0.99914\n4s5h\t0.99914\n4d5h\t0.99914\n4d5s\t0.99914\n4s5c\t0.99914\n4h5c\t0.99914\n4d5c\t0.99914\n4c5h\t0.99914\n4c5s\t0.99914\n4h5d\t0.99914\n5dJs\t0.998705\n5sJh\t0.998705\n5cJh\t0.998705\n5sJd\t0.998705\n5cJs\t0.998705\n5sJc\t0.998705\n5dJc\t0.998705\n5hJd\t0.998705\n5hJc\t0.998705\n5hJs\t0.998705\n5dJh\t0.998705\n5cJd\t0.998705\n3s9s\t0.997845\n3h9h\t0.997845\n3d9d\t0.997845\n6d9h\t0.998993\n6h9s\t0.998993\n6s9h\t0.998993\n6d9s\t0.998993\n6d9c\t0.998993\n6h9c\t0.998993\n6c9d\t0.998993\n6s9d\t0.998993\n6c9s\t0.998993\n6h9d\t0.998993\n6c9h\t0.998993\n6s9c\t0.998993\n2hJh\t0.99771\n2dJd\t0.99771\n2sJs\t0.99771\n2cJc\t0.99771\n6dTs\t0.998801\n6hTc\t0.998801\n6cTs\t0.998801\n6cTd\t0.998801\n6sTh\t0.998801\n6cTh\t0.998801\n6hTd\t0.998801\n6sTc\t0.998801\n6hTs\t0.998801\n6sTd\t0.998801\n6dTh\t0.998801\n6dTc\t0.998801\n6hJd\t0.998794\n6sJh\t0.998794\n6cJh\t0.998794\n6hJs\t0.998794\n6dJc\t0.998794\n6sJc\t0.998794\n6dJh\t0.998794\n6sJd\t0.998794\n6hJc\t0.998794\n6cJs\t0.998794\n6cJd\t0.998794\n6dJs\t0.998794\n6s8h\t0.999003\n6h8c\t0.999003\n6c8h\t0.999003\n6d8s\t0.999003\n6s8d\t0.999003\n6d8c\t0.999003\n6d8h\t0.999003\n6c8s\t0.999003\n6s8c\t0.999003\n6h8d\t0.999003\n6h8s\t0.999003\n6c8d\t0.999003\n4d9d\t0.998765\n4c9c\t0.998765\n4h9h\t0.998765\n4s9s\t0.998765\n4sQd\t0.998753\n4cQs\t0.998753\n4dQs\t0.998753\n4sQc\t0.998753\n4hQc\t0.998753\n4hQd\t0.998753\n4hQs\t0.998753\n4dQc\t0.998753\n4sQh\t0.998753\n4cQh\t0.998753\n4cQd\t0.998753\n4dQh\t0.998753\n4dAs\t0.999831\n4hAs\t0.999831\n4hAc\t0.999831\n4dAc\t0.999831\n4dAh\t0.999831\n4sAh\t0.999831\n4sAc\t0.999831\n4cAh\t0.999831\n4cAs\t0.999831\n2dTd\t0.996464\n2sTs\t0.996464\n2hTh\t0.996464\n2cTc\t0.996464\n2sQs\t1.0\n2hQh\t1.0\n2cQc\t1.0\n2dQd\t1.0\n2cAc\t0.99962\n2hAh\t0.99962\n2sAs\t0.99962\n4hJs\t0.998619\n4hTd\t0.746475\n5c7d\t0.999284\n4hTs\t0.746475\n5c8s\t0.998541\n5c8h\t0.998541\n4d7h\t0.054927\n2cAh\t0.999367\n2cAs\t0.999367\n4h7d\t0.054927\n2cKd\t0.999134\n4h7s\t0.054927\n2cKh\t0.999134\n4h6d\t0.998793\n2cKs\t0.999134\n4h6s\t0.998793\n4d7s\t0.054927\n4hJd\t0.998619\n2cQd\t0.998384\n2cQh\t0.998384\n5s7h\t0.999284\n2cQs\t0.998384\n4c7d\t0.054927\n5c8d\t0.998541\n5s7c\t0.999284\n5s8d\t0.998541\n4dTs\t0.746475\n5s8c\t0.998541\n4cTd\t0.746475\n4sJd\t0.998619\n5s9h\t0.99831\n4sTd\t0.746475\n5s9d\t0.99831\n2c9c\t0.996303\n4c7s\t0.054927\n5s9c\t0.99831\n2c8c\t0.996726\n4s7d\t0.054927\n5sTh\t0.998028\n4s6d\t0.998793\n5sTd\t0.998028\n2c7c\t0.995828\n5h7s\t0.999284\n5h7c\t0.999284\n4dTc\t0.746475\n3dAc\t0.999944\n2c6c\t0.995154\n3dAs\t0.999944\n3dKh\t0.999133\n3dQc\t0.998311\n3dQh\t0.998311\n2c5c\t0.997305\n3dJc\t0.99866\n3dJh\t0.99866\n2c4c\t0.997887\n2dAc\t0.999367\n2dAh\t0.999367\n2dAs\t0.999367\n2dKd\t0.999069\n2dKh\t0.999134\n2dKs\t0.999134\n3hAc\t0.999944\n2dQc\t0.998384\n3hAs\t0.999944\n4cTh\t0.746475\n5d7s\t0.999284\n2dQh\t0.998384\n3hQc\t0.998311\n2dQs\t0.998384\n5d7h\t0.999284\n3hJc\t0.99866\n5c9s\t0.99831\n5d7c\t0.999284\n5d8s\t0.998541\n4cTs\t0.746475\n5d8h\t0.998541\n3h8h\t0.997718\n2d9d\t0.996303\n3h7h\t0.999628\n5d8c\t0.998541\n2d8d\t0.996726\n5d9s\t0.99831\n5d9h\t0.99831\n5d9c\t0.99831\n2d7d\t0.995828\n3sAh\t0.999944\n3sKd\t0.999133\n5dTh\t0.998028\n3sQd\t0.998311\n2d6d\t0.995154\n5dTc\t0.998028\n3sJd\t0.99866\n4c6d\t0.998793\n2d5d\t0.997305\n4dJc\t0.998619\n4c6h\t0.998793\n2d4d\t0.997887\n3s8s\t0.997718\n3s7s\t0.999628\n2d3d\t0.996645\n5c7s\t0.999284\n5c9h\t0.99831\n5c7h\t0.999284\n2hAc\t0.999367\n4cJd\t0.998619\n4d6c\t0.998793\n4d7c\t0.054927\n2hAs\t0.999367\n2hKd\t0.999134\n2hKh\t0.999069\n4c7h\t0.054927\n2hKs\t0.999134\n2hQc\t0.998384\n4hJc\t0.998619\n2hQd\t0.998384\n5s8h\t0.998541\n4dTh\t0.746475\n2hQs\t0.998384\n4sJh\t0.998619\n4sTh\t0.746475\n5c9d\t0.99831\n4s7h\t0.054927\n4s6h\t0.998793\n5h7d\t0.999284\n5h8d\t0.998541\n5h8c\t0.998541\n5h9s\t0.99831\n4dJs\t0.998619\n2h9h\t0.996303\n5h9d\t0.99831\n5h9c\t0.99831\n3d8d\t0.997718\n3d7d\t0.999628\n2h8h\t0.996726\n5hTs\t0.998028\n4dJh\t0.998619\n5hTd\t0.998028\n5hTc\t0.998028\n2h7h\t0.995828\n3hKs\t0.999133\n3hQs\t0.998311\n3hJs\t0.99866\n2h6h\t0.995154\n2h5h\t0.997305\n5dTs\t0.998028\n3sQc\t0.998311\n2h4h\t0.997887\n3sJc\t0.99866\n4cJs\t0.998619\n2h3h\t0.996645\n5cTs\t0.998028\n5cTh\t0.998028\n2sAc\t0.999367\n4hTc\t0.746475\n2sAh\t0.999367\n4h6c\t0.998793\n2sKd\t0.999134\n2sKh\t0.999134\n2sKs\t0.999069\n4sTc\t0.746475\n2sQc\t0.998384\n2sQd\t0.998384\n4s6c\t0.998793\n2sQh\t0.998384\n5h8s\t0.998541\n3dKs\t0.999133\n3dJs\t0.99866\n5cTd\t0.998028\n3hKd\t0.999133\n3hJd\t0.99866\n3sAc\t0.999944\n3sQh\t0.998311\n2s9s\t0.996303\n2s8s\t0.996726\n4cJh\t0.998619\n4sJc\t0.998619\n4s7c\t0.054927\n3dAh\t0.999944\n2s7s\t0.995828\n3hQd\t0.998311\n2s6s\t0.995154\n3sJh\t0.99866\n4d6h\t0.998793\n4h7c\t0.054927\n2s5s\t0.997305\n3dQs\t0.998311\n2s4s\t0.997887\n5s7d\t0.999284\n4d6s\t0.998793\n4c6s\t0.998793\n2s3s\t0.996645\n5sTc\t0.998028\n3sKh\t0.999133\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/flop-situation3-p2.txt",
    "content": "8s8h\t1.0\nAhAc\t1.0\n4s4c\t1.0\n5sAs\t1.0\n9dQd\t1.0\n9hAh\t1.0\nJhJc\t1.0\nJsQs\t1.0\nJhJd\t1.0\nKhKd\t1.0\n9cAc\t1.0\nAsAh\t1.0\nTsTh\t1.0\nKsKd\t1.0\nJsAs\t1.0\nQcAc\t1.0\n8dKd\t1.0\nQcAs\t1.0\nTsTd\t1.0\n8s8c\t1.0\nJsKs\t1.0\nQdAc\t1.0\n4s4h\t1.0\nQdAs\t1.0\n4s4d\t1.0\n7dKd\t1.0\nTsTc\t1.0\nQdQc\t1.0\nKhAh\t1.0\nQhAh\t1.0\nJsJc\t1.0\n7d7c\t1.0\nJsJd\t1.0\n7hAh\t1.0\nJsJh\t1.0\nQhQd\t1.0\nTcAc\t1.0\nQsAh\t1.0\n6d6c\t1.0\n8sAs\t1.0\n6hAh\t1.0\nQsKs\t1.0\nTsJs\t1.0\nQsQd\t1.0\n5hAh\t1.0\nJcAc\t1.0\n6h6c\t1.0\n5s6s\t1.0\nTcQc\t1.0\n7hKh\t1.0\n4s5s\t1.0\nJcQc\t1.0\n6h6d\t1.0\n7sAs\t1.0\n6sAs\t1.0\n5s5c\t1.0\nTcJc\t1.0\n5s5d\t1.0\n5d5c\t1.0\nAsAc\t1.0\n8cAc\t1.0\n8hAh\t1.0\n4sAs\t1.0\n8d8c\t1.0\n9s9h\t1.0\nJdJc\t1.0\n9s9d\t1.0\nJhAh\t1.0\n9s9c\t1.0\n7s7d\t1.0\nTdKd\t1.0\n7s7h\t1.0\nTsQs\t1.0\n5h6h\t1.0\n4c5c\t1.0\n9dKd\t1.0\n4h4d\t1.0\nKsAs\t1.0\nTdQd\t1.0\nQcAh\t1.0\n4h4c\t1.0\n7cAc\t1.0\n4h5h\t1.0\nQdKd\t1.0\n6s6c\t1.0\nQhAc\t1.0\nTdJd\t1.0\nQhKh\t1.0\n9sQs\t1.0\nQsAc\t1.0\n6s6d\t1.0\n8h8d\t1.0\nTdTc\t1.0\nQsQh\t1.0\n6s6h\t1.0\n8h8c\t1.0\nThAh\t1.0\n7h7d\t1.0\n5cAc\t1.0\n9cQc\t1.0\n9sKs\t1.0\n8hKh\t1.0\nThKh\t1.0\n7s7c\t1.0\n9sAs\t1.0\n4cAc\t1.0\n9h9d\t1.0\n6cAc\t1.0\n4hAh\t1.0\n5h5d\t1.0\nThQh\t1.0\n8s8d\t1.0\n4d4c\t1.0\n8sKs\t1.0\n4d5d\t1.0\nQhQc\t1.0\n9h9c\t1.0\nQsQc\t1.0\nThJh\t1.0\n7h7c\t1.0\n9d9c\t1.0\nJdKd\t1.0\nThTc\t1.0\n5s5h\t1.0\nThTd\t1.0\nJhQh\t1.0\n5c6c\t1.0\nQdAh\t1.0\n9hQh\t1.0\nQsAs\t1.0\n7sKs\t1.0\nTsKs\t1.0\n5d6d\t1.0\n9hKh\t1.0\nTsAs\t1.0\nJdQd\t1.0\n5h5c\t1.0\nQhAs\t1.0\nKsKh\t1.0\nJhKh\t1.0\nKdAc\t0.99948\nKdAs\t0.99948\nKhAc\t0.99948\nKsAh\t0.99948\nKdAh\t0.99948\nKhAs\t0.99948\nKsAc\t0.99948\n6dKd\t0.996459\n6hKh\t0.996459\n6sKs\t0.996459\n6d7d\t0.990574\n6s7s\t0.990574\n6c7c\t0.990574\n6h7h\t0.990574\nJhAs\t0.9881\nJsAc\t0.9881\nJhAc\t0.9881\nJsAh\t0.9881\nJdAs\t0.9881\nJcAh\t0.9881\nJcAs\t0.9881\nJdAc\t0.9881\nJdAh\t0.9881\n9hTh\t0.966349\n9cTc\t0.966349\n9sTs\t0.966349\n9dTd\t0.966349\n9cJc\t0.961261\n9hJh\t0.961261\n9sJs\t0.961261\n9dJd\t0.961261\n7s8s\t0.937578\n7d8d\t0.937578\n7h8h\t0.937578\n7c8c\t0.937578\n8cQc\t0.929088\n8hQh\t0.929088\n8sQs\t0.929088\n8dQd\t0.929088\nThAs\t0.92546\nTcAs\t0.92546\nTcAh\t0.92546\nTsAh\t0.92546\nThAc\t0.92546\nTdAh\t0.92546\nTdAc\t0.92546\nTsAc\t0.92546\nTdAs\t0.92546\n8c9c\t0.922554\n8d9d\t0.922554\n8s9s\t0.922554\n8h9h\t0.922554\n6c8c\t0.887115\n6d8d\t0.887115\n6h8h\t0.887115\n6s8s\t0.887115\n5h7h\t0.870201\n5c7c\t0.870201\n5d7d\t0.870201\n5s7s\t0.870201\n4s6s\t0.864189\n4d6d\t0.864189\n4h6h\t0.864189\n4c6c\t0.864189\n8dTd\t0.848302\n8hTh\t0.848302\n8cTc\t0.848302\n8sTs\t0.848302\n5sKs\t0.847799\n5hKh\t0.847799\n5dKd\t0.847799\n3s3d\t0.834255\n3h3d\t0.834255\n3s3h\t0.834255\n7h9h\t0.833698\n7d9d\t0.833698\n7s9s\t0.833698\n7c9c\t0.833698\n6d9d\t0.818515\n6h9h\t0.818515\n6c9c\t0.818515\n6s9s\t0.818515\n8dJd\t0.792354\n8sJs\t0.792354\n8hJh\t0.792354\n8cJc\t0.792354\n7hTh\t0.782837\n7cTc\t0.782837\n7dTd\t0.782837\n7sTs\t0.782837\n9cAs\t0.775404\n9sAc\t0.775404\n9dAs\t0.775404\n9cAh\t0.775404\n9dAh\t0.775404\n9sAh\t0.775404\n9hAc\t0.775404\n9dAc\t0.775404\n9hAs\t0.775404\nQsKh\t0.764181\nQcKs\t0.764181\nQhKd\t0.764181\nQhKs\t0.764181\nQdKs\t0.764181\nQcKh\t0.764181\nQsKd\t0.764181\nQcKd\t0.764181\nQdKh\t0.764181\n6cTc\t0.745567\n6dTd\t0.745567\n6sTs\t0.745567\n6hTh\t0.745567\n3h5h\t0.679195\n3s5s\t0.679195\n3d5d\t0.679195\n3d4d\t0.678556\n3h4h\t0.678556\n3s4s\t0.678556\n5hJh\t0.647998\n5dJd\t0.647998\n5sJs\t0.647998\n5cJc\t0.647998\n6hQh\t0.644814\n6cQc\t0.644814\n6sQs\t0.644814\n6dQd\t0.644814\n7sQs\t0.635211\n7dQd\t0.635211\n7cQc\t0.635211\n7hQh\t0.635211\n5s8s\t0.630807\n5c8c\t0.630807\n5d8d\t0.630807\n5h8h\t0.630807\n5s9s\t0.617031\n5h9h\t0.617031\n5c9c\t0.617031\n5d9d\t0.617031\nJcKs\t0.615132\nJhKs\t0.615132\nJdKs\t0.615132\nJsKd\t0.615132\nJhKd\t0.615132\nJsKh\t0.615132\nJcKh\t0.615132\nJcKd\t0.615132\nJdKh\t0.615132\n5dQd\t0.612392\n5cQc\t0.612392\n5sQs\t0.612392\n5hQh\t0.612392\n4dKd\t0.605889\n4sKs\t0.605889\n4hKh\t0.605889\n7cJc\t0.605393\n7sJs\t0.605393\n7dJd\t0.605393\n7hJh\t0.605393\n4sQs\t0.59431\n4dQd\t0.59431\n4cQc\t0.59431\n4hQh\t0.59431\n8dAh\t0.575158\n8hAc\t0.575158\n8hAs\t0.575158\n8sAh\t0.575158\n8dAc\t0.575158\n8cAs\t0.575158\n8cAh\t0.575158\n8sAc\t0.575158\n8dAs\t0.575158\n4cJc\t0.529954\n4hJh\t0.529954\n4sJs\t0.529954\n4dJd\t0.529954\nTcKd\t0.495103\nTcKh\t0.495103\nThKs\t0.495103\nTdKs\t0.495103\nTdKh\t0.495103\nThKd\t0.495103\nTsKh\t0.495103\nTcKs\t0.495103\nTsKd\t0.495103\n2s2h\t0.456526\n2d2c\t0.456526\n2h2c\t0.456526\n2h2d\t0.456526\n2s2c\t0.456526\n2s2d\t0.456526\n6sJs\t0.424636\n6hJh\t0.424636\n6cJc\t0.424636\n6dJd\t0.424636\n7dAs\t0.42414\n7hAc\t0.42414\n7sAh\t0.42414\n7sAc\t0.42414\n7dAh\t0.42414\n7hAs\t0.42414\n7cAh\t0.42414\n7cAs\t0.42414\n7dAc\t0.42414\nJcQd\t0.421432\nJhQc\t0.421432\nJdQh\t0.421432\nJsQh\t0.421432\nJcQh\t0.421432\nJdQc\t0.421432\nJdQs\t0.421432\nJsQc\t0.421432\nJhQs\t0.421432\nJhQd\t0.421432\nJsQd\t0.421432\nJcQs\t0.421432\n4c7c\t0.420963\n4d7d\t0.420963\n4h7h\t0.420963\n4s7s\t0.420963\n4hTh\t0.409083\n4dTd\t0.409083\n4sTs\t0.409083\n4cTc\t0.409083\n9hTc\t0.392535\n9cTh\t0.392535\n9dTh\t0.392535\n9hTs\t0.392535\n9sTc\t0.392535\n9sTh\t0.392535\n9cTd\t0.392535\n9hTd\t0.392535\n9sTd\t0.392535\n9dTc\t0.392535\n9cTs\t0.392535\n9dTs\t0.392535\n9cKs\t0.382497\n9cKh\t0.382497\n9dKs\t0.382497\n9sKd\t0.382497\n9hKs\t0.382497\n9hKd\t0.382497\n9dKh\t0.382497\n9sKh\t0.382497\n9cKd\t0.382497\n3hAh\t0.375764\n3sAs\t0.375764\nTdJh\t0.36661\nTcJs\t0.36661\nTsJh\t0.36661\nTdJs\t0.36661\nTsJd\t0.36661\nTsJc\t0.36661\nThJd\t0.36661\nThJc\t0.36661\nTdJc\t0.36661\nThJs\t0.36661\nTcJh\t0.36661\nTcJd\t0.36661\n8s9h\t0.325181\n8c9s\t0.325181\n8s9d\t0.325181\n8s9c\t0.325181\n8h9c\t0.325181\n8c9h\t0.325181\n8d9s\t0.325181\n8d9h\t0.325181\n8c9d\t0.325181\n8h9d\t0.325181\n8d9c\t0.325181\n8h9s\t0.325181\nTsQd\t0.312877\nThQs\t0.312877\nTsQh\t0.312877\nTsQc\t0.312877\nTdQs\t0.312877\nTcQd\t0.312877\nTdQh\t0.312877\nTcQh\t0.312877\nTcQs\t0.312877\nThQd\t0.312877\nThQc\t0.312877\nTdQc\t0.312877\n9sJh\t0.273196\n9dJc\t0.273196\n9hJs\t0.273196\n9hJc\t0.273196\n9sJc\t0.273196\n9hJd\t0.273196\n9dJs\t0.273196\n9cJs\t0.273196\n9cJh\t0.273196\n9cJd\t0.273196\n9dJh\t0.273196\n9sJd\t0.273196\n5cTc\t0.272444\n5sTs\t0.272444\n5dTd\t0.272444\n5hTh\t0.272444\n5dAs\t0.271799\n5hAc\t0.271799\n5sAc\t0.271799\n5hAs\t0.271799\n5cAh\t0.271799\n5sAh\t0.271799\n5cAs\t0.271799\n5dAc\t0.271799\n5dAh\t0.271799\n8sTc\t0.243467\n8dTh\t0.243467\n8sTd\t0.243467\n8hTd\t0.243467\n8sTh\t0.243467\n8hTc\t0.243467\n8hTs\t0.243467\n8dTc\t0.243467\n8cTd\t0.243467\n8dTs\t0.243467\n8cTs\t0.243467\n8cTh\t0.243467\n6cKs\t0.242493\n6hKd\t0.242493\n6cKh\t0.242493\n6cKd\t0.242493\n6sKd\t0.242493\n6dKh\t0.242493\n6sKh\t0.242493\n6hKs\t0.242493\n6dKs\t0.242493\n7sKd\t0.24114\n7dKh\t0.24114\n7cKs\t0.24114\n7hKs\t0.24114\n7dKs\t0.24114\n7cKh\t0.24114\n7hKd\t0.24114\n7cKd\t0.24114\n7sKh\t0.24114\n3sJs\t0.237643\n3hJh\t0.237643\n3dJd\t0.237643\n9dQc\t0.233052\n9hQc\t0.233052\n9sQc\t0.233052\n9cQs\t0.233052\n9sQh\t0.233052\n9hQs\t0.233052\n9sQd\t0.233052\n9hQd\t0.233052\n9cQh\t0.233052\n9cQd\t0.233052\n9dQs\t0.233052\n9dQh\t0.233052\n3hQh\t0.229162\n3sQs\t0.229162\n3dQd\t0.229162\n6hQc\t0.226708\n6hQd\t0.226708\n6cQh\t0.226708\n6sQh\t0.226708\n6sQc\t0.226708\n6dQs\t0.226708\n6hQs\t0.226708\n6sQd\t0.226708\n6dQh\t0.226708\n6cQd\t0.226708\n6dQc\t0.226708\n6cQs\t0.226708\n8sJc\t0.224028\n8dJs\t0.224028\n8dJc\t0.224028\n8sJd\t0.224028\n8sJh\t0.224028\n8cJh\t0.224028\n8dJh\t0.224028\n8hJd\t0.224028\n8hJc\t0.224028\n8cJd\t0.224028\n8hJs\t0.224028\n8cJs\t0.224028\n3d6d\t0.211769\n3s6s\t0.211769\n3h6h\t0.211769\n6dAc\t0.202461\n6dAh\t0.202461\n6dAs\t0.202461\n6cAh\t0.202461\n6hAc\t0.202461\n6sAh\t0.202461\n6sAc\t0.202461\n6hAs\t0.202461\n6cAs\t0.202461\n7c8h\t0.198551\n7h8c\t0.198551\n7d8s\t0.198551\n7s8c\t0.198551\n7s8d\t0.198551\n7h8s\t0.198551\n7h8d\t0.198551\n7s8h\t0.198551\n7c8s\t0.198551\n7d8h\t0.198551\n7d8c\t0.198551\n7c8d\t0.198551\n8dKh\t0.184102\n8hKd\t0.184102\n8dKs\t0.184102\n8cKs\t0.184102\n8cKh\t0.184102\n8cKd\t0.184102\n8sKh\t0.184102\n8sKd\t0.184102\n8hKs\t0.184102\n7sJd\t0.180314\n7hJs\t0.180314\n7dJs\t0.180314\n7cJh\t0.180314\n7dJh\t0.180314\n7hJc\t0.180314\n7dJc\t0.180314\n7hJd\t0.180314\n7sJh\t0.180314\n7cJd\t0.180314\n7cJs\t0.180314\n7sJc\t0.180314\n6d7h\t0.169491\n6c7s\t0.169491\n6c7h\t0.169491\n6d7c\t0.169491\n6h7s\t0.169491\n6h7d\t0.169491\n6h7c\t0.169491\n6s7h\t0.169491\n6d7s\t0.169491\n6s7c\t0.169491\n6s7d\t0.169491\n6c7d\t0.169491\n3sKs\t0.15864\n3dKd\t0.15864\n3hKh\t0.15864\n3dTd\t0.155821\n3sTs\t0.155821\n3hTh\t0.155821\n8hQd\t0.153104\n8dQs\t0.153104\n8cQs\t0.153104\n8hQc\t0.153104\n8hQs\t0.153104\n8dQc\t0.153104\n8sQc\t0.153104\n8sQd\t0.153104\n8cQh\t0.153104\n8cQd\t0.153104\n8sQh\t0.153104\n8dQh\t0.153104\n5dQs\t0.152759\n5dQh\t0.152759\n5sQc\t0.152759\n5dQc\t0.152759\n5sQd\t0.152759\n5hQs\t0.152759\n5cQd\t0.152759\n5hQd\t0.152759\n5hQc\t0.152759\n5cQh\t0.152759\n5cQs\t0.152759\n5sQh\t0.152759\n7cTs\t0.152613\n7dTh\t0.152613\n7sTc\t0.152613\n7dTc\t0.152613\n7cTd\t0.152613\n7sTh\t0.152613\n7sTd\t0.152613\n7cTh\t0.152613\n7hTc\t0.152613\n7hTd\t0.152613\n7hTs\t0.152613\n7dTs\t0.152613\n5cKs\t0.145835\n5hKd\t0.145835\n5hKs\t0.145835\n5cKh\t0.145835\n5dKs\t0.145835\n5sKh\t0.145835\n5dKh\t0.145835\n5cKd\t0.145835\n5sKd\t0.145835\n7c9h\t0.138427\n7c9d\t0.138427\n7d9c\t0.138427\n7h9s\t0.138427\n7d9h\t0.138427\n7d9s\t0.138427\n7s9c\t0.138427\n7h9d\t0.138427\n7c9s\t0.138427\n7s9h\t0.138427\n7s9d\t0.138427\n7h9c\t0.138427\n4h8h\t0.13596\n4s8s\t0.13596\n4c8c\t0.13596\n4d8d\t0.13596\n7hQc\t0.133884\n7cQs\t0.133884\n7dQc\t0.133884\n7cQd\t0.133884\n7dQh\t0.133884\n7hQd\t0.133884\n7sQc\t0.133884\n7hQs\t0.133884\n7dQs\t0.133884\n7cQh\t0.133884\n7sQd\t0.133884\n7sQh\t0.133884\n5h6s\t0.096952\n5c6s\t0.096952\n5s6h\t0.096952\n5h6c\t0.096952\n5s6d\t0.096952\n5h6d\t0.096952\n5d6c\t0.096952\n5c6h\t0.096952\n5c6d\t0.096952\n5d6s\t0.096952\n5s6c\t0.096952\n5d6h\t0.096952\n4dKh\t0.04827\n4cKh\t0.04827\n4sKh\t0.04827\n4dKs\t0.04827\n4hKd\t0.04827\n4sKd\t0.04827\n4cKd\t0.04827\n4hKs\t0.04827\n4cKs\t0.04827\n4c5d\t0.039751\n4h5s\t0.039751\n4s5d\t0.039751\n4s5h\t0.039751\n4d5h\t0.039751\n4d5s\t0.039751\n4s5c\t0.039751\n4h5c\t0.039751\n4d5c\t0.039751\n4c5h\t0.039751\n4c5s\t0.039751\n4h5d\t0.039751\n5dJs\t0.031108\n5sJh\t0.031108\n5cJh\t0.031108\n5sJd\t0.031108\n5cJs\t0.031108\n5sJc\t0.031108\n5dJc\t0.031108\n5hJd\t0.031108\n5hJc\t0.031108\n5hJs\t0.031108\n5dJh\t0.031108\n5cJd\t0.031108\n3s9s\t0.030505\n3h9h\t0.030505\n3d9d\t0.030505\n6d9h\t0.03019\n6h9s\t0.03019\n6s9h\t0.03019\n6d9s\t0.03019\n6d9c\t0.03019\n6h9c\t0.03019\n6c9d\t0.03019\n6s9d\t0.03019\n6c9s\t0.03019\n6h9d\t0.03019\n6c9h\t0.03019\n6s9c\t0.03019\n2hJh\t0.022645\n2dJd\t0.022645\n2sJs\t0.022645\n2cJc\t0.022645\n6dTs\t0.020674\n6hTc\t0.020674\n6cTs\t0.020674\n6cTd\t0.020674\n6sTh\t0.020674\n6cTh\t0.020674\n6hTd\t0.020674\n6sTc\t0.020674\n6hTs\t0.020674\n6sTd\t0.020674\n6dTh\t0.020674\n6dTc\t0.020674\n6hJd\t0.018796\n6sJh\t0.018796\n6cJh\t0.018796\n6hJs\t0.018796\n6dJc\t0.018796\n6sJc\t0.018796\n6dJh\t0.018796\n6sJd\t0.018796\n6hJc\t0.018796\n6cJs\t0.018796\n6cJd\t0.018796\n6dJs\t0.018796\n6s8h\t0.017399\n6h8c\t0.017399\n6c8h\t0.017399\n6d8s\t0.017399\n6s8d\t0.017399\n6d8c\t0.017399\n6d8h\t0.017399\n6c8s\t0.017399\n6s8c\t0.017399\n6h8d\t0.017399\n6h8s\t0.017399\n6c8d\t0.017399\n4d9d\t0.015403\n4c9c\t0.015403\n4h9h\t0.015403\n4s9s\t0.015403\n4sQd\t0.013227\n4cQs\t0.013227\n4dQs\t0.013227\n4sQc\t0.013227\n4hQc\t0.013227\n4hQd\t0.013227\n4hQs\t0.013227\n4dQc\t0.013227\n4sQh\t0.013227\n4cQh\t0.013227\n4cQd\t0.013227\n4dQh\t0.013227\n4dAs\t0.008524\n4hAs\t0.008524\n4hAc\t0.008524\n4dAc\t0.008524\n4dAh\t0.008524\n4sAh\t0.008524\n4sAc\t0.008524\n4cAh\t0.008524\n4cAs\t0.008524\n2dTd\t0.008329\n2sTs\t0.008329\n2hTh\t0.008329\n2cTc\t0.008329\n2sQs\t0.005711\n2hQh\t0.005711\n2cQc\t0.005711\n2dQd\t0.005711\n2cAc\t0.001948\n2hAh\t0.001948\n2sAs\t0.001948\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/flop-situation4-p1.txt",
    "content": "4d4c\t1.0\nAdAc\t0.99494\n9h9c\t1.0\nAhAd\t0.99494\n9h9d\t1.0\nAsAd\t0.99494\n9sKs\t1.0\nKcAc\t1.0\nJhQh\t1.0\n9hQh\t0.999783\nAsAh\t0.99494\n8s8c\t1.0\nAsAc\t0.99494\nJhJc\t0.999812\nJhAh\t0.999261\n9hKh\t1.0\nAhAc\t0.99494\nKhAh\t1.0\n6s6c\t0.999991\nKhKc\t0.99985\n8hAh\t0.999386\n8dAd\t0.999386\nJhKh\t1.0\n9d9c\t1.0\n9dQd\t0.999783\nKsKc\t0.99985\nKdAd\t1.0\nKsKh\t0.99985\n9dKd\t1.0\nQcAd\t1.0\nJhJd\t0.999812\nQcAs\t1.0\n8cAc\t0.999386\n4d5d\t0.999406\n8hKh\t0.999783\n4dAd\t0.999938\n8h8c\t1.0\nQdAd\t0.99921\nJsAs\t0.999261\nQdAs\t1.0\n6sAs\t1.0\nQdKd\t1.0\n6h6d\t0.999991\n5h5d\t1.0\n6h6c\t0.999991\nQhAc\t1.0\nJsKs\t1.0\nQhAh\t0.99921\nJsQs\t1.0\n5h5c\t1.0\nJsJc\t0.999812\nQhKh\t1.0\nJsJd\t0.999812\nQhQc\t0.999789\nJsJh\t0.999812\nQsAc\t1.0\nTcAc\t0.999078\nQsAh\t1.0\n9dAd\t1.0\n5d5c\t1.0\n8h8d\t1.0\n5dAd\t1.0\n6hAh\t1.0\nQsQc\t0.999789\nTcKc\t0.999882\nQsQh\t0.999789\n6d6c\t0.999991\n9sQs\t0.999783\n8sAs\t0.999386\n9sAs\t1.0\n8sKs\t0.999783\n5c6c\t1.0\nTcQc\t1.0\n4s4d\t1.0\nTcJc\t0.999815\n9s9d\t1.0\n6dAd\t1.0\n9s9h\t1.0\nTdAd\t0.999078\n5cAc\t1.0\n9cQc\t0.999783\n6s6h\t0.999991\n9cKc\t1.0\nJdQd\t1.0\n6cAc\t1.0\nKdKc\t0.99985\nTdKd\t0.999882\n9hAh\t1.0\n7s7h\t0.999893\n8dKd\t0.999783\n7s7d\t0.999893\nKsKd\t0.99985\nTdQd\t1.0\nQcAh\t1.0\nTdJd\t0.999815\n4sAs\t0.999938\nTdTc\t0.999517\nQdAh\t1.0\n7s7c\t0.999893\n4cAc\t0.999938\n7sKs\t0.999833\nQhAd\t1.0\nThAh\t0.999078\n5h6h\t1.0\n7sAs\t0.999378\nQhQd\t0.999789\n7h7d\t0.999893\nQsAs\t0.99921\n7h7c\t0.999893\nQsKs\t1.0\nThKh\t0.999882\nJcAc\t0.999261\n7hKh\t0.999833\nJcKc\t1.0\nThQh\t1.0\nJcQc\t1.0\nThJh\t0.999815\n8d8c\t1.0\nThTc\t0.999517\n6s6d\t0.999991\nThTd\t0.999517\n8cKc\t0.999783\n7hAh\t0.999378\nKsAs\t1.0\n7d7c\t0.999893\nQcKc\t1.0\n7dKd\t0.999833\n4c5c\t0.999406\nTsAs\t0.999078\nQhAs\t1.0\n7dAd\t0.999378\nQsAd\t1.0\n7cKc\t0.999833\nQsQd\t0.999789\n7cAc\t0.999378\n4s4c\t1.0\nTsKs\t0.999882\nJdKd\t1.0\nTsQs\t1.0\nKhKd\t0.99985\nTsJs\t0.999815\nQdAc\t1.0\nTsTc\t0.999517\n5hAh\t1.0\nTsTd\t0.999517\n9s9c\t1.0\nJdJc\t0.999812\n8s8d\t1.0\n8s8h\t1.0\n9cAc\t1.0\nTsTh\t0.999517\nQcAc\t0.99921\nJdAd\t0.999261\n5d6d\t1.0\nQdQc\t0.999789\nKcAs\t0.999809\nKdAc\t0.999809\nKcAd\t0.999809\nKdAh\t0.999809\nKsAh\t0.999809\nKsAd\t0.999809\nKdAs\t0.999809\nKcAh\t0.999809\nKhAc\t0.999809\nKsAc\t0.999809\nKhAs\t0.999809\nKhAd\t0.999809\n6sKs\t0.999788\n6cKc\t0.999788\n6dKd\t0.999788\n6hKh\t0.999788\n6d7d\t1.0\n6h7h\t1.0\n6c7c\t1.0\n6s7s\t1.0\nJsAh\t0.999991\nJdAh\t0.999991\nJsAd\t0.999991\nJsAc\t0.999991\nJcAd\t0.999991\nJcAh\t0.999991\nJcAs\t0.999991\nJdAc\t0.999991\nJhAs\t0.999991\nJdAs\t0.999991\nJhAc\t0.999991\nJhAd\t0.999991\n9hTh\t0.999241\n9cTc\t0.999241\n9dTd\t0.999241\n9sTs\t0.999241\n9dJd\t0.999681\n9hJh\t0.999681\n9sJs\t0.999681\n9cJc\t0.999681\n7c8c\t0.999593\n7s8s\t0.999593\n7d8d\t0.999593\n7h8h\t0.999593\n8cQc\t0.999833\n8dQd\t0.999833\n8sQs\t0.999833\n8hQh\t0.999833\nTcAs\t1.0\nTdAh\t1.0\nTsAd\t1.0\nTcAh\t1.0\nThAc\t1.0\nTsAc\t1.0\nTdAc\t1.0\nTsAh\t1.0\nTcAd\t1.0\nThAs\t1.0\nThAd\t1.0\nTdAs\t1.0\n8h9h\t0.99976\n8s9s\t0.99976\n8d9d\t0.99976\n8c9c\t0.99976\n6d8d\t0.999658\n6h8h\t0.999658\n6c8c\t0.999658\n6s8s\t0.999658\n5h7h\t0.999569\n5c7c\t0.999569\n5d7d\t0.999569\n4c6c\t0.99937\n4d6d\t0.99937\n4s6s\t0.99937\n8dTd\t0.999506\n8cTc\t0.999506\n8sTs\t0.999506\n8hTh\t0.999506\n5hKh\t0.999668\n5cKc\t0.999668\n5dKd\t0.999668\n3s3d\t0.998486\n3s3h\t0.998486\n3h3d\t0.998486\n7d9d\t0.999421\n7c9c\t0.999421\n7s9s\t0.999421\n7h9h\t0.999421\n6c9c\t0.999321\n6h9h\t0.999321\n6d9d\t0.999321\n6s9s\t0.999321\n8dJd\t1.0\n8sJs\t1.0\n8hJh\t1.0\n8cJc\t1.0\n7sTs\t0.99966\n7cTc\t0.99966\n7hTh\t0.99966\n7dTd\t0.99966\n9cAh\t0.999563\n9sAc\t0.999563\n9cAs\t0.999563\n9dAs\t0.999563\n9dAh\t0.999563\n9dAc\t0.999563\n9hAc\t0.999563\n9hAd\t0.999563\n9sAh\t0.999563\n9cAd\t0.999563\n9hAs\t0.999563\n9sAd\t0.999563\nQdKh\t0.999563\nQsKh\t0.999563\nQcKh\t0.999563\nQcKs\t0.999563\nQdKs\t0.999563\nQcKd\t0.999563\nQhKs\t0.999563\nQdKc\t0.999563\nQhKd\t0.999563\nQsKc\t0.999563\nQsKd\t0.999563\nQhKc\t0.999563\n6cTc\t0.999359\n6dTd\t0.999359\n6hTh\t0.999359\n6sTs\t0.999359\n3d5d\t0.999632\n3h5h\t0.999632\n3s4s\t0.998532\n3d4d\t0.998532\n5hJh\t0.999097\n5cJc\t0.999097\n5dJd\t0.999097\n6sQs\t1.0\n6dQd\t1.0\n6cQc\t1.0\n6hQh\t1.0\n7hQh\t0.999947\n7sQs\t0.999947\n7dQd\t0.999947\n7cQc\t0.999947\n5c8c\t0.999487\n5h8h\t0.999487\n5d8d\t0.999487\n5d9d\t0.999539\n5c9c\t0.999539\n5h9h\t0.999539\nJdKc\t0.999541\nJcKd\t0.999541\nJhKs\t0.999541\nJsKc\t0.999541\nJcKh\t0.999541\nJcKs\t0.999541\nJhKd\t0.999541\nJsKh\t0.999541\nJhKc\t0.999541\nJsKd\t0.999541\nJdKs\t0.999541\nJdKh\t0.999541\n5dQd\t1.0\n5cQc\t1.0\n5hQh\t1.0\n4cKc\t0.999506\n4dKd\t0.999506\n4sKs\t0.999506\n7hJh\t1.0\n7dJd\t1.0\n7cJc\t1.0\n7sJs\t1.0\n4sQs\t0.998908\n4dQd\t0.998908\n4cQc\t0.998908\n8dAc\t0.998841\n8hAd\t0.998841\n8sAh\t0.998841\n8cAs\t0.998841\n8cAd\t0.998841\n8hAc\t0.998841\n8dAh\t0.998841\n8cAh\t0.998841\n8hAs\t0.998841\n8sAc\t0.998841\n8sAd\t0.998841\n8dAs\t0.998841\n4sJs\t0.999519\n4cJc\t0.999519\n4dJd\t0.999519\nTsKc\t0.999596\nThKc\t0.999596\nTdKh\t0.999596\nTsKh\t0.999596\nTcKh\t0.999596\nTcKd\t0.999596\nTdKc\t0.999596\nTdKs\t0.999596\nTsKd\t0.999596\nThKd\t0.999596\nThKs\t0.999596\nTcKs\t0.999596\n2s2h\t0.994151\n2d2c\t0.994151\n2h2d\t0.994151\n2s2c\t0.994151\n2s2d\t0.994151\n2h2c\t0.994151\n6sJs\t0.99937\n6hJh\t0.99937\n6dJd\t0.99937\n6cJc\t0.99937\n7hAs\t0.999388\n7dAs\t0.999388\n7hAd\t0.999388\n7hAc\t0.999388\n7cAh\t0.999388\n7cAd\t0.999388\n7dAc\t0.999388\n7dAh\t0.999388\n7sAc\t0.999388\n7cAs\t0.999388\n7sAd\t0.999388\n7sAh\t0.999388\nJcQd\t0.999517\nJdQc\t0.999517\nJhQc\t0.999517\nJhQd\t0.999517\nJhQs\t0.999517\nJdQs\t0.999517\nJcQs\t0.999517\nJcQh\t0.999517\nJdQh\t0.999517\nJsQc\t0.999517\nJsQd\t0.999517\nJsQh\t0.999517\n4c7c\t1.0\n4d7d\t1.0\n4s7s\t1.0\n4cTc\t0.999347\n4dTd\t0.999347\n4sTs\t0.999347\n9sTc\t0.999158\n9hTd\t0.999158\n9hTs\t0.999158\n9cTs\t0.999158\n9cTd\t0.999158\n9cTh\t0.999158\n9sTd\t0.999158\n9sTh\t0.999158\n9dTs\t0.999158\n9hTc\t0.999158\n9dTc\t0.999158\n9dTh\t0.999158\n9hKc\t1.0\n9dKc\t1.0\n9sKh\t1.0\n9cKd\t1.0\n9sKd\t1.0\n9dKs\t1.0\n9hKd\t1.0\n9sKc\t1.0\n9cKh\t1.0\n9cKs\t1.0\n9hKs\t1.0\n9dKh\t1.0\n3sAs\t0.999815\n3hAh\t0.999815\n3dAd\t0.999815\nTsJh\t0.999512\nTsJd\t0.999512\nTdJs\t0.999512\nTcJs\t0.999512\nTdJc\t0.999512\nTsJc\t0.999512\nTcJd\t0.999512\nThJs\t0.999512\nTcJh\t0.999512\nTdJh\t0.999512\nThJc\t0.999512\nThJd\t0.999512\n8s9h\t0.999263\n8d9h\t0.999263\n8h9s\t0.999263\n8h9d\t0.999263\n8d9s\t0.999263\n8c9d\t0.999263\n8c9h\t0.999263\n8s9d\t0.999263\n8c9s\t0.999263\n8d9c\t0.999263\n8h9c\t0.999263\n8s9c\t0.999263\nThQc\t0.999368\nTsQc\t0.999368\nTdQs\t0.999368\nTcQd\t0.999368\nTcQh\t0.999368\nTsQh\t0.999368\nTsQd\t0.999368\nTcQs\t0.999368\nTdQc\t0.999368\nThQs\t0.999368\nTdQh\t0.999368\nThQd\t0.999368\n9sJc\t0.999412\n9hJc\t0.999412\n9dJc\t0.999412\n9hJs\t0.999412\n9cJs\t0.999412\n9cJh\t0.999412\n9dJs\t0.999412\n9cJd\t0.999412\n9dJh\t0.999412\n9hJd\t0.999412\n9sJh\t0.999412\n9sJd\t0.999412\n5hTh\t1.0\n5dTd\t1.0\n5cTc\t1.0\n5dAs\t0.999721\n5dAh\t0.999721\n5cAh\t0.999721\n5hAs\t0.999721\n5hAd\t0.999721\n5hAc\t0.999721\n5cAd\t0.999721\n5dAc\t0.999721\n5cAs\t0.999721\n8sTd\t0.999166\n8sTh\t0.999166\n8cTh\t0.999166\n8sTc\t0.999166\n8cTd\t0.999166\n8hTd\t0.999166\n8hTs\t0.999166\n8dTs\t0.999166\n8hTc\t0.999166\n8dTc\t0.999166\n8dTh\t0.999166\n8cTs\t0.999166\n6cKd\t0.999635\n6hKc\t0.999635\n6dKc\t0.999635\n6cKs\t0.999635\n6dKh\t0.999635\n6hKd\t0.999635\n6dKs\t0.999635\n6sKd\t0.999635\n6cKh\t0.999635\n6sKh\t0.999635\n6sKc\t0.999635\n6hKs\t0.999635\n7hKc\t0.999455\n7sKh\t0.999455\n7cKs\t0.999455\n7cKh\t0.999455\n7dKc\t0.999455\n7dKh\t0.999455\n7sKd\t0.999455\n7dKs\t0.999455\n7cKd\t0.999455\n7sKc\t0.999455\n7hKs\t0.999455\n7hKd\t0.999455\n3dJd\t1.0\n3hJh\t1.0\n3sJs\t1.0\n9dQc\t0.999502\n9cQh\t0.999502\n9hQs\t0.999502\n9dQh\t0.999502\n9sQc\t0.999502\n9dQs\t0.999502\n9sQd\t0.999502\n9hQc\t0.999502\n9cQd\t0.999502\n9hQd\t0.999502\n9cQs\t0.999502\n9sQh\t0.999502\n3hQh\t0.999811\n3dQd\t0.999811\n3sQs\t0.999811\n6cQd\t0.999029\n6cQs\t0.999029\n6dQh\t0.999029\n6cQh\t0.999029\n6hQd\t0.999029\n6hQc\t0.999029\n6dQc\t0.999029\n6dQs\t0.999029\n6sQc\t0.999029\n6hQs\t0.999029\n6sQh\t0.999029\n6sQd\t0.999029\n8dJc\t0.999249\n8dJh\t0.999249\n8sJc\t0.999249\n8cJd\t0.999249\n8hJc\t0.999249\n8hJs\t0.999249\n8cJs\t0.999249\n8sJd\t0.999249\n8cJh\t0.999249\n8sJh\t0.999249\n8hJd\t0.999249\n8dJs\t0.999249\n3h6h\t0.997878\n3s6s\t0.997878\n3d6d\t0.997878\n6sAc\t0.999486\n6dAs\t0.999486\n6sAh\t0.999486\n6sAd\t0.999486\n6cAd\t0.999486\n6cAh\t0.999486\n6dAc\t0.999486\n6dAh\t0.999486\n6hAc\t0.999486\n6cAs\t0.999486\n6hAs\t0.999486\n6hAd\t0.999486\n7h8c\t0.999334\n7s8h\t0.999334\n7s8d\t0.999334\n7h8s\t0.999334\n7s8c\t0.999334\n7c8d\t0.999334\n7c8h\t0.999334\n7h8d\t0.999334\n7d8s\t0.999334\n7d8h\t0.999334\n7c8s\t0.999334\n7d8c\t0.999334\n8dKh\t0.999476\n8hKd\t0.999476\n8cKs\t0.999476\n8hKc\t0.999476\n8hKs\t0.999476\n8cKh\t0.999476\n8cKd\t0.999476\n8dKc\t0.999476\n8sKd\t0.999476\n8sKc\t0.999476\n8dKs\t0.999476\n8sKh\t0.999476\n7sJc\t0.99917\n7sJd\t0.99917\n7hJd\t0.99917\n7dJs\t0.99917\n7cJd\t0.99917\n7hJc\t0.99917\n7dJh\t0.99917\n7sJh\t0.99917\n7dJc\t0.99917\n7hJs\t0.99917\n7cJs\t0.99917\n7cJh\t0.99917\n6d7c\t0.999388\n6c7s\t0.999388\n6c7h\t0.999388\n6d7s\t0.999388\n6h7d\t0.999388\n6h7c\t0.999388\n6d7h\t0.999388\n6s7c\t0.999388\n6h7s\t0.999388\n6s7d\t0.999388\n6s7h\t0.999388\n6c7d\t0.999388\n3sKs\t0.999802\n3hKh\t0.999802\n3dKd\t0.999802\n3dTd\t0.998642\n3sTs\t0.998642\n3hTh\t0.998642\n8sQh\t0.999244\n8dQc\t0.999244\n8cQd\t0.999244\n8dQh\t0.999244\n8cQs\t0.999244\n8sQc\t0.999244\n8cQh\t0.999244\n8hQd\t0.999244\n8sQd\t0.999244\n8hQc\t0.999244\n8hQs\t0.999244\n8dQs\t0.999244\n5cQd\t0.999073\n5dQc\t0.999073\n5dQh\t0.999073\n5dQs\t0.999073\n5cQs\t0.999073\n5hQc\t0.999073\n5cQh\t0.999073\n5hQs\t0.999073\n5hQd\t0.999073\n7dTc\t0.99917\n7cTd\t0.99917\n7sTd\t0.99917\n7dTs\t0.99917\n7sTc\t0.99917\n7hTc\t0.99917\n7cTs\t0.99917\n7cTh\t0.99917\n7dTh\t0.99917\n7sTh\t0.99917\n7hTs\t0.99917\n7hTd\t0.99917\n5cKs\t0.999452\n5cKd\t0.999452\n5cKh\t0.999452\n5dKc\t0.999452\n5dKh\t0.999452\n5dKs\t0.999452\n5hKc\t0.999452\n5hKd\t0.999452\n5hKs\t0.999452\n7h9s\t0.999505\n7d9s\t0.999505\n7c9s\t0.999505\n7c9h\t0.999505\n7d9h\t0.999505\n7s9c\t0.999505\n7d9c\t0.999505\n7c9d\t0.999505\n7s9h\t0.999505\n7h9c\t0.999505\n7h9d\t0.999505\n7s9d\t0.999505\n4s8s\t0.99947\n4c8c\t0.99947\n4d8d\t0.99947\n7dQs\t0.999282\n7hQc\t0.999282\n7sQh\t0.999282\n7sQd\t0.999282\n7sQc\t0.999282\n7hQs\t0.999282\n7cQh\t0.999282\n7dQh\t0.999282\n7hQd\t0.999282\n7cQs\t0.999282\n7cQd\t0.999282\n7dQc\t0.999282\n5d6c\t0.998976\n5h6c\t0.998976\n5d6s\t0.998976\n5c6d\t0.998976\n5d6h\t0.998976\n5c6h\t0.998976\n5c6s\t0.998976\n5h6s\t0.998976\n5h6d\t0.998976\n4dKc\t0.999183\n4cKd\t0.999183\n4cKh\t0.999183\n4sKc\t0.999183\n4cKs\t0.999183\n4dKs\t0.999183\n4dKh\t0.999183\n4sKh\t0.999183\n4sKd\t0.999183\n4d5h\t0.99914\n4s5c\t0.99914\n4s5d\t0.99914\n4s5h\t0.99914\n4d5c\t0.99914\n4c5d\t0.99914\n4c5h\t0.99914\n5dJh\t0.998705\n5cJs\t0.998705\n5cJh\t0.998705\n5dJc\t0.998705\n5hJd\t0.998705\n5hJc\t0.998705\n5dJs\t0.998705\n5cJd\t0.998705\n5hJs\t0.998705\n3s9s\t0.997845\n3d9d\t0.997845\n3h9h\t0.997845\n6s9c\t0.998993\n6d9h\t0.998993\n6s9h\t0.998993\n6d9s\t0.998993\n6h9s\t0.998993\n6h9c\t0.998993\n6c9s\t0.998993\n6c9h\t0.998993\n6c9d\t0.998993\n6h9d\t0.998993\n6s9d\t0.998993\n6d9c\t0.998993\n2dJd\t0.99771\n2cJc\t0.99771\n2hJh\t0.99771\n2sJs\t0.99771\n6hTs\t0.998801\n6dTs\t0.998801\n6cTd\t0.998801\n6sTc\t0.998801\n6cTh\t0.998801\n6dTh\t0.998801\n6sTh\t0.998801\n6cTs\t0.998801\n6dTc\t0.998801\n6sTd\t0.998801\n6hTd\t0.998801\n6hTc\t0.998801\n6sJh\t0.998794\n6hJd\t0.998794\n6dJc\t0.998794\n6dJh\t0.998794\n6dJs\t0.998794\n6hJc\t0.998794\n6sJc\t0.998794\n6cJh\t0.998794\n6cJs\t0.998794\n6hJs\t0.998794\n6sJd\t0.998794\n6cJd\t0.998794\n6h8s\t0.999003\n6c8s\t0.999003\n6s8d\t0.999003\n6d8c\t0.999003\n6c8h\t0.999003\n6c8d\t0.999003\n6s8c\t0.999003\n6s8h\t0.999003\n6h8c\t0.999003\n6d8h\t0.999003\n6d8s\t0.999003\n6h8d\t0.999003\n4s9s\t0.998765\n4c9c\t0.998765\n4d9d\t0.998765\n4cQh\t0.998753\n4cQd\t0.998753\n4cQs\t0.998753\n4sQh\t0.998753\n4sQd\t0.998753\n4sQc\t0.998753\n4dQh\t0.998753\n4dQs\t0.998753\n4dQc\t0.998753\n4sAh\t0.999831\n4sAc\t0.999831\n4cAd\t0.999831\n4sAd\t0.999831\n4cAh\t0.999831\n4dAh\t0.999831\n4cAs\t0.999831\n4dAs\t0.999831\n4dAc\t0.999831\n2sTs\t0.996464\n2cTc\t0.996464\n2dTd\t0.996464\n2hTh\t0.996464\n2cQc\t1.0\n2sQs\t1.0\n2hQh\t1.0\n2dQd\t1.0\n2sAs\t0.99962\n2dAd\t0.99962\n2cAc\t0.99962\n2hAh\t0.99962\n4sTd\t0.746475\n3hJc\t0.99866\n2c4c\t0.997887\n3sAd\t0.999944\n3sAc\t0.999944\n3sKd\t0.999133\n3sKh\t0.999133\n3dQh\t0.998311\n3dJc\t0.99866\n2dAc\t0.999367\n3dQc\t0.998311\n4c6d\t0.998793\n3sQc\t0.998311\n3d7d\t0.999628\n3dKc\t0.999133\n4c6h\t0.998793\n3sQd\t0.998311\n4c6s\t0.998793\n3sQh\t0.998311\n2dAh\t0.999367\n5cTd\t0.998028\n3sJc\t0.99866\n3sJh\t0.99866\n2dAs\t0.999367\n3dAc\t0.999944\n2dKc\t0.999134\n2dKd\t0.999069\n5c9s\t0.99831\n2dKh\t0.999134\n2dKs\t0.999134\n5c8h\t0.998541\n2dQc\t0.998384\n5c7d\t0.999284\n2dQh\t0.998384\n5c7s\t0.999284\n2dQs\t0.998384\n4s6h\t0.998793\n5dTc\t0.998028\n5dTs\t0.998028\n5d9c\t0.99831\n5d9h\t0.99831\n5d9s\t0.99831\n4s7d\t0.054927\n5d8h\t0.998541\n5d7c\t0.999284\n2d9d\t0.996303\n4dJc\t0.998619\n5d7h\t0.999284\n4dJh\t0.998619\n4dJs\t0.998619\n4dTc\t0.746475\n4dTh\t0.746475\n5hTd\t0.998028\n2d8d\t0.996726\n2cAd\t0.999367\n2cAs\t0.999367\n2cKd\t0.999134\n2cKh\t0.999134\n2d7d\t0.995828\n5h9d\t0.99831\n2cKs\t0.999134\n5h8c\t0.998541\n2d6d\t0.995154\n5h8s\t0.998541\n2cQd\t0.998384\n5h7s\t0.999284\n4dTs\t0.746475\n2cQs\t0.998384\n3hJs\t0.99866\n4sTh\t0.746475\n2d5d\t0.997305\n4sJh\t0.998619\n3d8d\t0.997718\n2d4d\t0.997887\n3h8h\t0.997718\n2d3d\t0.996645\n4cJh\t0.998619\n2hAc\t0.999367\n4cJs\t0.998619\n4cTh\t0.746475\n4cTs\t0.746475\n2hAd\t0.999367\n2hAs\t0.999367\n2hKc\t0.999134\n2hKd\t0.999134\n2hKh\t0.999069\n2hKs\t0.999134\n2hQc\t0.998384\n2hQd\t0.998384\n4c7d\t0.054927\n4c7h\t0.054927\n4d7c\t0.054927\n3hAc\t0.999944\n4d7h\t0.054927\n3sKc\t0.999133\n2hQs\t0.998384\n3dJh\t0.99866\n3dKh\t0.999133\n3hAd\t0.999944\n3dAh\t0.999944\n3sJd\t0.99866\n5c9d\t0.99831\n3hAs\t0.999944\n4d7s\t0.054927\n5c8s\t0.998541\n4d6c\t0.998793\n5c7h\t0.999284\n3hKc\t0.999133\n4s6d\t0.998793\n5dTh\t0.998028\n2h9h\t0.996303\n4s7h\t0.054927\n5d8c\t0.998541\n5d8s\t0.998541\n3s7s\t0.999628\n2h8h\t0.996726\n4s7c\t0.054927\n5d7s\t0.999284\n3h7h\t0.999628\n2h7h\t0.995828\n5hTc\t0.998028\n2cAh\t0.999367\n5hTs\t0.998028\n2h6h\t0.995154\n5h8d\t0.998541\n5h7c\t0.999284\n2cQh\t0.998384\n2h5h\t0.997305\n4sTc\t0.746475\n4sJc\t0.998619\n2h3h\t0.996645\n2c8c\t0.996726\n4d6h\t0.998793\n4d6s\t0.998793\n2sAc\t0.999367\n2sAd\t0.999367\n2sAh\t0.999367\n3hKd\t0.999133\n2c5c\t0.997305\n2sKc\t0.999134\n3dQs\t0.998311\n2sKd\t0.999134\n3dKs\t0.999133\n2sKh\t0.999134\n3dJs\t0.99866\n2sKs\t0.999069\n5cTs\t0.998028\n2sQc\t0.998384\n5c8d\t0.998541\n2sQd\t0.998384\n2sQh\t0.998384\n3hKs\t0.999133\n3hJd\t0.99866\n2cKc\t0.999069\n5h9s\t0.99831\n5h7d\t0.999284\n3hQc\t0.998311\n3hQs\t0.998311\n4sJd\t0.998619\n2c9c\t0.996303\n4cTd\t0.746475\n2s9s\t0.996303\n2c6c\t0.995154\n4c7s\t0.054927\n2s8s\t0.996726\n5cTh\t0.998028\n2s7s\t0.995828\n5h9c\t0.99831\n2s6s\t0.995154\n3dAs\t0.999944\n4s6c\t0.998793\n2s4s\t0.997887\n4cJd\t0.998619\n3sAh\t0.999944\n3hQd\t0.998311\n2s3s\t0.996645\n5c9h\t0.99831\n2c7c\t0.995828\n3s8s\t0.997718\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/flop-situation4-p2.txt",
    "content": "4d4c\t1.0\nAdAc\t1.0\n9h9c\t1.0\nAhAd\t1.0\n9h9d\t1.0\nAsAd\t1.0\n9sKs\t1.0\nKcAc\t1.0\nJhQh\t1.0\n9hQh\t1.0\nAsAh\t1.0\n8s8c\t1.0\nAsAc\t1.0\nJhJc\t1.0\nJhAh\t1.0\n9hKh\t1.0\nAhAc\t1.0\nKhAh\t1.0\n6s6c\t1.0\nKhKc\t1.0\n8hAh\t1.0\n8dAd\t1.0\nJhKh\t1.0\n9d9c\t1.0\n9dQd\t1.0\nKsKc\t1.0\nKdAd\t1.0\nKsKh\t1.0\n9dKd\t1.0\nQcAd\t1.0\nJhJd\t1.0\nQcAs\t1.0\n8cAc\t1.0\n4d5d\t1.0\n8hKh\t1.0\n4dAd\t1.0\n8h8c\t1.0\nQdAd\t1.0\nJsAs\t1.0\nQdAs\t1.0\n6sAs\t1.0\nQdKd\t1.0\n6h6d\t1.0\n5h5d\t1.0\n6h6c\t1.0\nQhAc\t1.0\nJsKs\t1.0\nQhAh\t1.0\nJsQs\t1.0\n5h5c\t1.0\nJsJc\t1.0\nQhKh\t1.0\nJsJd\t1.0\nQhQc\t1.0\nJsJh\t1.0\nQsAc\t1.0\nTcAc\t1.0\nQsAh\t1.0\n9dAd\t1.0\n5d5c\t1.0\n8h8d\t1.0\n5dAd\t1.0\n6hAh\t1.0\nQsQc\t1.0\nTcKc\t1.0\nQsQh\t1.0\n6d6c\t1.0\n9sQs\t1.0\n8sAs\t1.0\n9sAs\t1.0\n8sKs\t1.0\n5c6c\t1.0\nTcQc\t1.0\n4s4d\t1.0\nTcJc\t1.0\n9s9d\t1.0\n6dAd\t1.0\n9s9h\t1.0\nTdAd\t1.0\n5cAc\t1.0\n9cQc\t1.0\n6s6h\t1.0\n9cKc\t1.0\nJdQd\t1.0\n6cAc\t1.0\nKdKc\t1.0\nTdKd\t1.0\n9hAh\t1.0\n7s7h\t1.0\n8dKd\t1.0\n7s7d\t1.0\nKsKd\t1.0\nTdQd\t1.0\nQcAh\t1.0\nTdJd\t1.0\n4sAs\t1.0\nTdTc\t1.0\nQdAh\t1.0\n7s7c\t1.0\n4cAc\t1.0\n7sKs\t1.0\nQhAd\t1.0\nThAh\t1.0\n5h6h\t1.0\n7sAs\t1.0\nQhQd\t1.0\n7h7d\t1.0\nQsAs\t1.0\n7h7c\t1.0\nQsKs\t1.0\nThKh\t1.0\nJcAc\t1.0\n7hKh\t1.0\nJcKc\t1.0\nThQh\t1.0\nJcQc\t1.0\nThJh\t1.0\n8d8c\t1.0\nThTc\t1.0\n6s6d\t1.0\nThTd\t1.0\n8cKc\t1.0\n7hAh\t1.0\nKsAs\t1.0\n7d7c\t1.0\nQcKc\t1.0\n7dKd\t1.0\n4c5c\t1.0\nTsAs\t1.0\nQhAs\t1.0\n7dAd\t1.0\nQsAd\t1.0\n7cKc\t1.0\nQsQd\t1.0\n7cAc\t1.0\n4s4c\t1.0\nTsKs\t1.0\nJdKd\t1.0\nTsQs\t1.0\nKhKd\t1.0\nTsJs\t1.0\nQdAc\t1.0\nTsTc\t1.0\n5hAh\t1.0\nTsTd\t1.0\n9s9c\t1.0\nJdJc\t1.0\n8s8d\t1.0\n8s8h\t1.0\n9cAc\t1.0\nTsTh\t1.0\nQcAc\t1.0\nJdAd\t1.0\n5d6d\t1.0\nQdQc\t1.0\nKcAs\t0.99948\nKdAc\t0.99948\nKcAd\t0.99948\nKdAh\t0.99948\nKsAh\t0.99948\nKsAd\t0.99948\nKdAs\t0.99948\nKcAh\t0.99948\nKhAc\t0.99948\nKsAc\t0.99948\nKhAs\t0.99948\nKhAd\t0.99948\n6sKs\t0.996459\n6cKc\t0.996459\n6dKd\t0.996459\n6hKh\t0.996459\n6d7d\t0.990574\n6h7h\t0.990574\n6c7c\t0.990574\n6s7s\t0.990574\nJsAh\t0.9881\nJdAh\t0.9881\nJsAd\t0.9881\nJsAc\t0.9881\nJcAd\t0.9881\nJcAh\t0.9881\nJcAs\t0.9881\nJdAc\t0.9881\nJhAs\t0.9881\nJdAs\t0.9881\nJhAc\t0.9881\nJhAd\t0.9881\n9hTh\t0.966349\n9cTc\t0.966349\n9dTd\t0.966349\n9sTs\t0.966349\n9dJd\t0.961261\n9hJh\t0.961261\n9sJs\t0.961261\n9cJc\t0.961261\n7c8c\t0.937578\n7s8s\t0.937578\n7d8d\t0.937578\n7h8h\t0.937578\n8cQc\t0.929088\n8dQd\t0.929088\n8sQs\t0.929088\n8hQh\t0.929088\nTcAs\t0.92546\nTdAh\t0.92546\nTsAd\t0.92546\nTcAh\t0.92546\nThAc\t0.92546\nTsAc\t0.92546\nTdAc\t0.92546\nTsAh\t0.92546\nTcAd\t0.92546\nThAs\t0.92546\nThAd\t0.92546\nTdAs\t0.92546\n8h9h\t0.922554\n8s9s\t0.922554\n8d9d\t0.922554\n8c9c\t0.922554\n6d8d\t0.887115\n6h8h\t0.887115\n6c8c\t0.887115\n6s8s\t0.887115\n5h7h\t0.870201\n5c7c\t0.870201\n5d7d\t0.870201\n4c6c\t0.864189\n4d6d\t0.864189\n4s6s\t0.864189\n8dTd\t0.848302\n8cTc\t0.848302\n8sTs\t0.848302\n8hTh\t0.848302\n5hKh\t0.847799\n5cKc\t0.847799\n5dKd\t0.847799\n3s3d\t0.834255\n3s3h\t0.834255\n3h3d\t0.834255\n7d9d\t0.833698\n7c9c\t0.833698\n7s9s\t0.833698\n7h9h\t0.833698\n6c9c\t0.818515\n6h9h\t0.818515\n6d9d\t0.818515\n6s9s\t0.818515\n8dJd\t0.792354\n8sJs\t0.792354\n8hJh\t0.792354\n8cJc\t0.792354\n7sTs\t0.782837\n7cTc\t0.782837\n7hTh\t0.782837\n7dTd\t0.782837\n9cAh\t0.775404\n9sAc\t0.775404\n9cAs\t0.775404\n9dAs\t0.775404\n9dAh\t0.775404\n9dAc\t0.775404\n9hAc\t0.775404\n9hAd\t0.775404\n9sAh\t0.775404\n9cAd\t0.775404\n9hAs\t0.775404\n9sAd\t0.775404\nQdKh\t0.764181\nQsKh\t0.764181\nQcKh\t0.764181\nQcKs\t0.764181\nQdKs\t0.764181\nQcKd\t0.764181\nQhKs\t0.764181\nQdKc\t0.764181\nQhKd\t0.764181\nQsKc\t0.764181\nQsKd\t0.764181\nQhKc\t0.764181\n6cTc\t0.745567\n6dTd\t0.745567\n6hTh\t0.745567\n6sTs\t0.745567\n3d5d\t0.679195\n3h5h\t0.679195\n3s4s\t0.678556\n3d4d\t0.678556\n5hJh\t0.647998\n5cJc\t0.647998\n5dJd\t0.647998\n6sQs\t0.644814\n6dQd\t0.644814\n6cQc\t0.644814\n6hQh\t0.644814\n7hQh\t0.635211\n7sQs\t0.635211\n7dQd\t0.635211\n7cQc\t0.635211\n5c8c\t0.630807\n5h8h\t0.630807\n5d8d\t0.630807\n5d9d\t0.617031\n5c9c\t0.617031\n5h9h\t0.617031\nJdKc\t0.615132\nJcKd\t0.615132\nJhKs\t0.615132\nJsKc\t0.615132\nJcKh\t0.615132\nJcKs\t0.615132\nJhKd\t0.615132\nJsKh\t0.615132\nJhKc\t0.615132\nJsKd\t0.615132\nJdKs\t0.615132\nJdKh\t0.615132\n5dQd\t0.612392\n5cQc\t0.612392\n5hQh\t0.612392\n4cKc\t0.605889\n4dKd\t0.605889\n4sKs\t0.605889\n7hJh\t0.605393\n7dJd\t0.605393\n7cJc\t0.605393\n7sJs\t0.605393\n4sQs\t0.59431\n4dQd\t0.59431\n4cQc\t0.59431\n8dAc\t0.575158\n8hAd\t0.575158\n8sAh\t0.575158\n8cAs\t0.575158\n8cAd\t0.575158\n8hAc\t0.575158\n8dAh\t0.575158\n8cAh\t0.575158\n8hAs\t0.575158\n8sAc\t0.575158\n8sAd\t0.575158\n8dAs\t0.575158\n4sJs\t0.529954\n4cJc\t0.529954\n4dJd\t0.529954\nTsKc\t0.495103\nThKc\t0.495103\nTdKh\t0.495103\nTsKh\t0.495103\nTcKh\t0.495103\nTcKd\t0.495103\nTdKc\t0.495103\nTdKs\t0.495103\nTsKd\t0.495103\nThKd\t0.495103\nThKs\t0.495103\nTcKs\t0.495103\n2s2h\t0.456526\n2d2c\t0.456526\n2h2d\t0.456526\n2s2c\t0.456526\n2s2d\t0.456526\n2h2c\t0.456526\n6sJs\t0.424636\n6hJh\t0.424636\n6dJd\t0.424636\n6cJc\t0.424636\n7hAs\t0.42414\n7dAs\t0.42414\n7hAd\t0.42414\n7hAc\t0.42414\n7cAh\t0.42414\n7cAd\t0.42414\n7dAc\t0.42414\n7dAh\t0.42414\n7sAc\t0.42414\n7cAs\t0.42414\n7sAd\t0.42414\n7sAh\t0.42414\nJcQd\t0.421432\nJdQc\t0.421432\nJhQc\t0.421432\nJhQd\t0.421432\nJhQs\t0.421432\nJdQs\t0.421432\nJcQs\t0.421432\nJcQh\t0.421432\nJdQh\t0.421432\nJsQc\t0.421432\nJsQd\t0.421432\nJsQh\t0.421432\n4c7c\t0.420963\n4d7d\t0.420963\n4s7s\t0.420963\n4cTc\t0.409083\n4dTd\t0.409083\n4sTs\t0.409083\n9sTc\t0.392535\n9hTd\t0.392535\n9hTs\t0.392535\n9cTs\t0.392535\n9cTd\t0.392535\n9cTh\t0.392535\n9sTd\t0.392535\n9sTh\t0.392535\n9dTs\t0.392535\n9hTc\t0.392535\n9dTc\t0.392535\n9dTh\t0.392535\n9hKc\t0.382497\n9dKc\t0.382497\n9sKh\t0.382497\n9cKd\t0.382497\n9sKd\t0.382497\n9dKs\t0.382497\n9hKd\t0.382497\n9sKc\t0.382497\n9cKh\t0.382497\n9cKs\t0.382497\n9hKs\t0.382497\n9dKh\t0.382497\n3sAs\t0.375764\n3hAh\t0.375764\n3dAd\t0.375764\nTsJh\t0.36661\nTsJd\t0.36661\nTdJs\t0.36661\nTcJs\t0.36661\nTdJc\t0.36661\nTsJc\t0.36661\nTcJd\t0.36661\nThJs\t0.36661\nTcJh\t0.36661\nTdJh\t0.36661\nThJc\t0.36661\nThJd\t0.36661\n8s9h\t0.325181\n8d9h\t0.325181\n8h9s\t0.325181\n8h9d\t0.325181\n8d9s\t0.325181\n8c9d\t0.325181\n8c9h\t0.325181\n8s9d\t0.325181\n8c9s\t0.325181\n8d9c\t0.325181\n8h9c\t0.325181\n8s9c\t0.325181\nThQc\t0.312877\nTsQc\t0.312877\nTdQs\t0.312877\nTcQd\t0.312877\nTcQh\t0.312877\nTsQh\t0.312877\nTsQd\t0.312877\nTcQs\t0.312877\nTdQc\t0.312877\nThQs\t0.312877\nTdQh\t0.312877\nThQd\t0.312877\n9sJc\t0.273196\n9hJc\t0.273196\n9dJc\t0.273196\n9hJs\t0.273196\n9cJs\t0.273196\n9cJh\t0.273196\n9dJs\t0.273196\n9cJd\t0.273196\n9dJh\t0.273196\n9hJd\t0.273196\n9sJh\t0.273196\n9sJd\t0.273196\n5hTh\t0.272444\n5dTd\t0.272444\n5cTc\t0.272444\n5dAs\t0.271799\n5dAh\t0.271799\n5cAh\t0.271799\n5hAs\t0.271799\n5hAd\t0.271799\n5hAc\t0.271799\n5cAd\t0.271799\n5dAc\t0.271799\n5cAs\t0.271799\n8sTd\t0.243467\n8sTh\t0.243467\n8cTh\t0.243467\n8sTc\t0.243467\n8cTd\t0.243467\n8hTd\t0.243467\n8hTs\t0.243467\n8dTs\t0.243467\n8hTc\t0.243467\n8dTc\t0.243467\n8dTh\t0.243467\n8cTs\t0.243467\n6cKd\t0.242493\n6hKc\t0.242493\n6dKc\t0.242493\n6cKs\t0.242493\n6dKh\t0.242493\n6hKd\t0.242493\n6dKs\t0.242493\n6sKd\t0.242493\n6cKh\t0.242493\n6sKh\t0.242493\n6sKc\t0.242493\n6hKs\t0.242493\n7hKc\t0.24114\n7sKh\t0.24114\n7cKs\t0.24114\n7cKh\t0.24114\n7dKc\t0.24114\n7dKh\t0.24114\n7sKd\t0.24114\n7dKs\t0.24114\n7cKd\t0.24114\n7sKc\t0.24114\n7hKs\t0.24114\n7hKd\t0.24114\n3dJd\t0.237643\n3hJh\t0.237643\n3sJs\t0.237643\n9dQc\t0.233052\n9cQh\t0.233052\n9hQs\t0.233052\n9dQh\t0.233052\n9sQc\t0.233052\n9dQs\t0.233052\n9sQd\t0.233052\n9hQc\t0.233052\n9cQd\t0.233052\n9hQd\t0.233052\n9cQs\t0.233052\n9sQh\t0.233052\n3hQh\t0.229162\n3dQd\t0.229162\n3sQs\t0.229162\n6cQd\t0.226708\n6cQs\t0.226708\n6dQh\t0.226708\n6cQh\t0.226708\n6hQd\t0.226708\n6hQc\t0.226708\n6dQc\t0.226708\n6dQs\t0.226708\n6sQc\t0.226708\n6hQs\t0.226708\n6sQh\t0.226708\n6sQd\t0.226708\n8dJc\t0.224028\n8dJh\t0.224028\n8sJc\t0.224028\n8cJd\t0.224028\n8hJc\t0.224028\n8hJs\t0.224028\n8cJs\t0.224028\n8sJd\t0.224028\n8cJh\t0.224028\n8sJh\t0.224028\n8hJd\t0.224028\n8dJs\t0.224028\n3h6h\t0.211769\n3s6s\t0.211769\n3d6d\t0.211769\n6sAc\t0.202461\n6dAs\t0.202461\n6sAh\t0.202461\n6sAd\t0.202461\n6cAd\t0.202461\n6cAh\t0.202461\n6dAc\t0.202461\n6dAh\t0.202461\n6hAc\t0.202461\n6cAs\t0.202461\n6hAs\t0.202461\n6hAd\t0.202461\n7h8c\t0.198551\n7s8h\t0.198551\n7s8d\t0.198551\n7h8s\t0.198551\n7s8c\t0.198551\n7c8d\t0.198551\n7c8h\t0.198551\n7h8d\t0.198551\n7d8s\t0.198551\n7d8h\t0.198551\n7c8s\t0.198551\n7d8c\t0.198551\n8dKh\t0.184102\n8hKd\t0.184102\n8cKs\t0.184102\n8hKc\t0.184102\n8hKs\t0.184102\n8cKh\t0.184102\n8cKd\t0.184102\n8dKc\t0.184102\n8sKd\t0.184102\n8sKc\t0.184102\n8dKs\t0.184102\n8sKh\t0.184102\n7sJc\t0.180314\n7sJd\t0.180314\n7hJd\t0.180314\n7dJs\t0.180314\n7cJd\t0.180314\n7hJc\t0.180314\n7dJh\t0.180314\n7sJh\t0.180314\n7dJc\t0.180314\n7hJs\t0.180314\n7cJs\t0.180314\n7cJh\t0.180314\n6d7c\t0.169491\n6c7s\t0.169491\n6c7h\t0.169491\n6d7s\t0.169491\n6h7d\t0.169491\n6h7c\t0.169491\n6d7h\t0.169491\n6s7c\t0.169491\n6h7s\t0.169491\n6s7d\t0.169491\n6s7h\t0.169491\n6c7d\t0.169491\n3sKs\t0.15864\n3hKh\t0.15864\n3dKd\t0.15864\n3dTd\t0.155821\n3sTs\t0.155821\n3hTh\t0.155821\n8sQh\t0.153104\n8dQc\t0.153104\n8cQd\t0.153104\n8dQh\t0.153104\n8cQs\t0.153104\n8sQc\t0.153104\n8cQh\t0.153104\n8hQd\t0.153104\n8sQd\t0.153104\n8hQc\t0.153104\n8hQs\t0.153104\n8dQs\t0.153104\n5cQd\t0.152759\n5dQc\t0.152759\n5dQh\t0.152759\n5dQs\t0.152759\n5cQs\t0.152759\n5hQc\t0.152759\n5cQh\t0.152759\n5hQs\t0.152759\n5hQd\t0.152759\n7dTc\t0.152613\n7cTd\t0.152613\n7sTd\t0.152613\n7dTs\t0.152613\n7sTc\t0.152613\n7hTc\t0.152613\n7cTs\t0.152613\n7cTh\t0.152613\n7dTh\t0.152613\n7sTh\t0.152613\n7hTs\t0.152613\n7hTd\t0.152613\n5cKs\t0.145835\n5cKd\t0.145835\n5cKh\t0.145835\n5dKc\t0.145835\n5dKh\t0.145835\n5dKs\t0.145835\n5hKc\t0.145835\n5hKd\t0.145835\n5hKs\t0.145835\n7h9s\t0.138427\n7d9s\t0.138427\n7c9s\t0.138427\n7c9h\t0.138427\n7d9h\t0.138427\n7s9c\t0.138427\n7d9c\t0.138427\n7c9d\t0.138427\n7s9h\t0.138427\n7h9c\t0.138427\n7h9d\t0.138427\n7s9d\t0.138427\n4s8s\t0.13596\n4c8c\t0.13596\n4d8d\t0.13596\n7dQs\t0.133884\n7hQc\t0.133884\n7sQh\t0.133884\n7sQd\t0.133884\n7sQc\t0.133884\n7hQs\t0.133884\n7cQh\t0.133884\n7dQh\t0.133884\n7hQd\t0.133884\n7cQs\t0.133884\n7cQd\t0.133884\n7dQc\t0.133884\n5d6c\t0.096952\n5h6c\t0.096952\n5d6s\t0.096952\n5c6d\t0.096952\n5d6h\t0.096952\n5c6h\t0.096952\n5c6s\t0.096952\n5h6s\t0.096952\n5h6d\t0.096952\n4dKc\t0.04827\n4cKd\t0.04827\n4cKh\t0.04827\n4sKc\t0.04827\n4cKs\t0.04827\n4dKs\t0.04827\n4dKh\t0.04827\n4sKh\t0.04827\n4sKd\t0.04827\n4d5h\t0.039751\n4s5c\t0.039751\n4s5d\t0.039751\n4s5h\t0.039751\n4d5c\t0.039751\n4c5d\t0.039751\n4c5h\t0.039751\n5dJh\t0.031108\n5cJs\t0.031108\n5cJh\t0.031108\n5dJc\t0.031108\n5hJd\t0.031108\n5hJc\t0.031108\n5dJs\t0.031108\n5cJd\t0.031108\n5hJs\t0.031108\n3s9s\t0.030505\n3d9d\t0.030505\n3h9h\t0.030505\n6s9c\t0.03019\n6d9h\t0.03019\n6s9h\t0.03019\n6d9s\t0.03019\n6h9s\t0.03019\n6h9c\t0.03019\n6c9s\t0.03019\n6c9h\t0.03019\n6c9d\t0.03019\n6h9d\t0.03019\n6s9d\t0.03019\n6d9c\t0.03019\n2dJd\t0.022645\n2cJc\t0.022645\n2hJh\t0.022645\n2sJs\t0.022645\n6hTs\t0.020674\n6dTs\t0.020674\n6cTd\t0.020674\n6sTc\t0.020674\n6cTh\t0.020674\n6dTh\t0.020674\n6sTh\t0.020674\n6cTs\t0.020674\n6dTc\t0.020674\n6sTd\t0.020674\n6hTd\t0.020674\n6hTc\t0.020674\n6sJh\t0.018796\n6hJd\t0.018796\n6dJc\t0.018796\n6dJh\t0.018796\n6dJs\t0.018796\n6hJc\t0.018796\n6sJc\t0.018796\n6cJh\t0.018796\n6cJs\t0.018796\n6hJs\t0.018796\n6sJd\t0.018796\n6cJd\t0.018796\n6h8s\t0.017399\n6c8s\t0.017399\n6s8d\t0.017399\n6d8c\t0.017399\n6c8h\t0.017399\n6c8d\t0.017399\n6s8c\t0.017399\n6s8h\t0.017399\n6h8c\t0.017399\n6d8h\t0.017399\n6d8s\t0.017399\n6h8d\t0.017399\n4s9s\t0.015403\n4c9c\t0.015403\n4d9d\t0.015403\n4cQh\t0.013227\n4cQd\t0.013227\n4cQs\t0.013227\n4sQh\t0.013227\n4sQd\t0.013227\n4sQc\t0.013227\n4dQh\t0.013227\n4dQs\t0.013227\n4dQc\t0.013227\n4sAh\t0.008524\n4sAc\t0.008524\n4cAd\t0.008524\n4sAd\t0.008524\n4cAh\t0.008524\n4dAh\t0.008524\n4cAs\t0.008524\n4dAs\t0.008524\n4dAc\t0.008524\n2sTs\t0.008329\n2cTc\t0.008329\n2dTd\t0.008329\n2hTh\t0.008329\n2cQc\t0.005711\n2sQs\t0.005711\n2hQh\t0.005711\n2dQd\t0.005711\n2sAs\t0.001948\n2dAd\t0.001948\n2cAc\t0.001948\n2hAh\t0.001948\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/situation-p1.txt",
    "content": "7hjh\t1.000\n6h7h\t1.000\n4s7s\t1.000\n9d9c\t1.000\n9s9d\t1.000\n6s7s\t1.000\ntsqs\t1.000\n9s9h\t1.000\n9s9c\t1.000\n4h7h\t1.000\n9h9c\t1.000\n9h9d\t1.000\n9sks\t1.000\njhjc\t1.000\njdjc\t1.000\njhjd\t1.000\nqsqh\t1.000\nqsqc\t1.000\nqhqc\t1.000\n6sks\t1\n9sqs\t1\n7hth\t1\ntsth\t1\nthtd\t1\ntdtc\t1\nthtc\t1\n7s9h\t1\n7h9s\t1\n7s9c\t1\n7h9c\t1\n7h9d\t1\n7s9d\t1\n7s9s\t0.999\n7h9h\t0.999\n6c7s\t0.999\n6s7h\t0.999\n6d7h\t0.999\n6c7h\t0.999\n6h7s\t0.999\n6d7s\t0.999\n7sas\t0.999\n4s6s\t0.999\n4c6c\t0.999\n4h6h\t0.999\n4d6d\t0.999\n6h9h\t0.999\n7sqh\t0.999\n7sjd\t0.999\n7sth\t0.999\n7htc\t0.999\n7sjh\t0.999\n7std\t0.999\n7hjd\t0.999\n7sjc\t0.999\n7stc\t0.999\n7hjc\t0.999\n7htd\t0.999\n6s9h\t0.999\n6d9s\t0.999\n6s9d\t0.999\n6h9s\t0.999\n6c9s\t0.999\n6s9c\t0.999\n4d6s\t0.999\n4c6h\t0.999\n4d6c\t0.999\n4d6h\t0.999\n4h6d\t0.999\n4h6s\t0.999\n4h6c\t0.999\n4c6d\t0.999\n4c6s\t0.999\n3h7h\t0.997\njsjh\t0.996\n2h7h\t0.996\n2s7s\t0.996\n4s6d\t0.990\n4s6c\t0.990\n6h9c\t0.986\n6h9d\t0.986\n6c9h\t0.985\n6d9h\t0.985\n8hks\t0.979\ntstc\t0.978\ntstd\t0.978\n6c9d\t0.977\n6d9c\t0.977\njsjd\t0.976\njsjc\t0.976\n8cah\t0.976\n8dah\t0.976\n4s6h\t0.972\n6d9d\t0.968\n6c9c\t0.968\n6s6h\t0.966\n7sts\t0.965\n7sqs\t0.965\n8hac\t0.959\n8had\t0.959\n5h6h\t0.942\n8h9s\t0.939\n6sts\t0.936\n8das\t0.935\n8cas\t0.935\n6h8d\t0.933\n6h8c\t0.933\n8dad\t0.929\n8cac\t0.929\n6d8d\t0.927\n6c8c\t0.927\n7sjs\t0.927\n6d8c\t0.926\n6c8d\t0.926\n8has\t0.924\n6hqs\t0.919\n8dac\t0.912\n8cad\t0.912\n6hth\t0.911\n7sqc\t0.908\n6sas\t0.904\n6h8h\t0.901\n5h6s\t0.900\n3s7s\t0.896\n7hqh\t0.894\n6sqs\t0.894\n8hah\t0.893\n7sks\t0.889\n8hkh\t0.884\n7hqc\t0.880\n7hts\t0.886\nkskh\t0.863\n6c8h\t0.862\n6d8h\t0.862\n6skh\t0.82\n7hkc\t0.817\n7hkd\t0.817\n7hjs\t0.794\n7hqs\t0.788\n7hkh\t0.772\n7skd\t0.758\n7skc\t0.758\n6cqs\t0.757\n6dqs\t0.757\n6dtd\t0.753\n6ctc\t0.753\n9hjh\t0.742\n4s9s\t0.741\n6s8d\t0.722\n6s8c\t0.722\n6s6d\t0.719\n6s6c\t0.719\n7skh\t0.706\n6s8h\t0.701\n9sts\t0.697\n9cjc\t0.680\n9djd\t0.68\n7hks\t0.663\n5h7s\t0.653\n5h7h\t0.650\n6sjs\t0.643\n6cjc\t0.635\n6djd\t0.635\n6hjh\t0.623\n5d7s\t0.615\n5c7s\t0.615\n5h6d\t0.615\n5h6c\t0.615\nkhkc\t0.614\nkhkd\t0.614\n7hac\t0.602\n7had\t0.602\n5d7h\t0.599\n5c7h\t0.599\n7hah\t0.587\n7has\t0.568\n9dtd\t0.551\n9ctc\t0.551\n8cks\t0.532\n8dks\t0.532\n6skc\t0.517\n6skd\t0.517\n2s3s\t0.512\n6hqh\t0.510\n8h9h\t0.51\n9hth\t0.506\n4sks\t0.481\n3sqs\t0.465\n9hqh\t0.456\n7sad\t0.448\n7sac\t0.448\n6hks\t0.446\n5c6c\t0.444\n5d6d\t0.444\n5c6h\t0.440\n5d6h\t0.440\ntsjs\t0.439\n7sah\t0.428\n3c6c\t0.412\n3d6d\t0.412\n7s7h\t0.366\n7h8h\t0.350\n7h8c\t0.343\n7h8d\t0.343\n6h6d\t0.342\n6h6c\t0.342\n9hqs\t0.335\n7s8c\t0.333\n7s8d\t0.333\n2s6s\t0.327\n8h8d\t0.326\n8h8c\t0.326\nkskc\t0.311\nkskd\t0.311\n7s8h\t0.307\n6cqc\t0.293\n6s9s\t0.246\n6hjs\t0.229\n6hqc\t0.226\n6sqc\t0.222\n3s9s\t0.222\n6d6c\t0.216\n9sqc\t0.209\n6sqh\t0.193\n5c6s\t0.185\n5d6s\t0.185\n9sjh\t0.175\n9dts\t0.163\n9cts\t0.163\n9cqc\t0.160\n9ctd\t0.157\n9dtc\t0.157\n9sqh\t0.142\n9htc\t0.132\n9sjd\t0.111\n9sjc\t0.111\n3s4s\t0.109\n9cjs\t0.102\n9djs\t0.102\n9hjs\t0.092\n9hjd\t0.088\n9hjc\t0.088\n3s6s\t0.074\n2s9s\t0.074\n9dth\t0.072\n9cth\t0.072\n6hkh\t0.072\n8hkc\t0.068\n8hkd\t0.068\n9hts\t0.066\n4c7s\t0.055\n4d7s\t0.055\n4s7h\t0.055\n4d7h\t0.055\n4h7s\t0.055\n4c7h\t0.055\n9djc\t0.049\n9cjd\t0.049\n6cjs\t0.039\n6djs\t0.039\n8d8c\t0.036\n2s4s\t0.032\n8dkh\t0.024\n8ckh\t0.024\n9sjs\t0.021\n6hkd\t0.011\n6hkc\t0.011\n9hqc\t0.001\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/situation-p2.txt",
    "content": "5d5c\t1\n5h5d\t1\n5h5c\t1\n7sas\t0.991\n7hah\t0.982\n8d8c\t0.969\n8h8c\t0.953\n8h8d\t0.953\n5h7h\t0.870\n7sks\t0.855\n7h9h\t0.834\n7s9s\t0.834\n7hkh\t0.807\n7sts\t0.783\n6s7s\t0.688\n6h9h\t0.662\n7sqs  0.635\n7hqh\t0.635\n7sjs\t0.605\n7hjh\t0.605\n7h8h\t0.581\n6d9d\t0.560\n6c9c\t0.560\n4s6s\t0.548\n7hth\t0.526\n4h6h\t0.524\n3s4s\t0.516\n7s7h\t0.493\n4s7s\t0.421\n7sah\t0.402\n7sad\t0.394\n7sac\t0.394\n7has\t0.390\n7had\t0.387\n7hac\t0.387\n6s9s\t0.318\n4c6c\t0.281\n4d6d\t0.281\n6h7h\t0.274\n9hjh\t0.245\n7hkd\t0.233\n7hkc\t0.233\n7skc\t0.229\n7skd\t0.229\n6hjh\t0.229\n6djd\t0.228\n6cjc\t0.228\n9sjs\t0.227\n6sjs\t0.223\n9sts\t0.220\n9djd\t0.214\n9cjc\t0.214\n7skh\t0.208\n4h7h\t0.206\n6hqh\t0.184\n7sjh\t0.180\n7hjc\t0.180\n7hjs\t0.180\n7sjc\t0.180\n7hjd\t0.180\n7sjd\t0.180\n7h8c\t0.177\n7h8d\t0.177\n6hth\t0.177\n6sts\t0.176\n7hks\t0.168\n6sqs\t0.167\n3sqs\t0.165\n9cqc\t0.163\n6cqc\t0.160\n7s8h\t0.155\n7s8d\t0.151\n7s8c\t0.151\n3c6c\t0.148\n3d6d\t0.148\n7s9c\t0.138\n7h9c\t0.138\n7h9d\t0.138\n7s9d\t0.138\n7hqc\t0.134\n7hqs\t0.134\n7sqc\t0.134\n6dtd\t0.133\n6ctc\t0.133\n6sqh\t0.133\n7sqh\t0.131\n9hqh\t0.126\n4sqs\t0.103\n3h6h\t0.101\n3s6s\t0.100\n6sqc\t0.098\n7htc\t0.097\n7htd\t0.097\n3s3h\t0.083\ntsjd\t0.064\ntsjc\t0.064\n3h3c\t0.064\n3h3d\t0.064\n6hqs\t0.064\n9hth\t0.064\n9ctc\t0.061\n9dtd\t0.061\n9hqs\t0.060\n7s9h\t0.052\n7h9s\t0.051\ntsjh\t0.049\n4hks\t0.047\n4hkh\t0.047\n9sqh\t0.037\n7stc\t0.035\n7std\t0.035\n6h9s\t0.030\n6h9d\t0.030\n6h9c\t0.030\n9dqs\t0.030\n9cqs\t0.030\n6c9d\t0.027\n6d9c\t0.027\n7hts\t0.025\ntdjs\t0.024\ntcjs\t0.024\n2sjs\t0.023\n9sjh\t0.023\n9hts\t0.022\n6dts\t0.021\n6cts\t0.021\nthjs\t0.020\n6hts\t0.019\ntsjs\t0.018\n6dqh\t0.016\n6cqh\t0.016\n6cqs\t0.013\n6dqs\t0.013\nthjh\t0.013\ntcjc\t0.013\ntdjd\t0.013\n3sjs\t0.012\n6stc\t0.011\n6std\t0.011\n6hjs\t0.010\n6d9s\t0.010\n6c9s\t0.010\n4dks\t0.010\n4cks\t0.010\n6sth\t0.009\n6sjh\t0.009\n2sts\t0.008\n6sjc\t0.008\n6sjd\t0.008\n8dac\t0.007\n8cad\t0.007\n2sqs\t0.006\n2s2h\t0.005\n6dqc\t0.005\n8dah\t0.005\n8cah\t0.005\n8cas\t0.003\n8das\t0.003\n9sqc\t0.002\n9d9c\t0.001\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/situation2-p1.txt",
    "content": "TsAs\t0.012875\nQcAc\t0.192686\nQdAs\t0.177237\nQcAs\t0.177237\nQcAd\t0.184158\nQdAc\t0.184158\nQdAd\t0.192686\nJsAs\t0.005649\nKcAc\t0.138829\nKsAd\t0.009415\nKsAc\t0.009415\nKcAs\t0.052031\nKcAd\t0.137483\nKsAs\t0.170011\nAsAd\t0.208837\nAsAc\t0.208837\nAdAc\t0.199488\nQhAc\t0.170189\nQhAd\t0.170189\nQhAs\t0.157085\nQdQc\t0.052385\n5dAd\t0.017711\n5cAc\t0.017711\nJcAc\t0.008799\nJdAd\t0.008799\nJcAd\t0.007662\nJdAc\t0.007662\n5sAs\t0.001169\nTsJs\t0.042813\nKhAs\t0.085118\nKhAd\t0.115602\nKhAc\t0.115602\nJhAs\t0.001147\nTdJd\t0.010486\nTcJc\t0.010486\nJdAs\t0.005942\nJcAs\t0.005942\nQhQd\t0.202023\nQhQc\t0.202023\n8h9h\t0.041717\n9hTh\t0.001733\n3c4c\t0.026533\n3d4d\t0.026533\n7h8h\t0.03391\n8hTh\t0.018794\n5d5c\t0.052883\n6h8h\t0.027873\n6h7h\t0.04121\n5s5c\t0.076916\n5s5d\t0.076916\n3s4s\t0.059114\nThAc\t0.030011\nThAd\t0.030011\n7h9h\t0.029347\n4h6h\t0.022629\n3h4h\t0.009688\n6h9h\t0.024147\nTdJc\t0.007639\nTcJd\t0.007639\n7hTh\t0.034049\nTdJh\t0.055531\nTcJh\t0.055531\nThAs\t0.071851\n4h7h\t0.012634\nTdQd\t0.000673\nTcQc\t0.000673\n5sAc\t0.064845\n5sAd\t0.064845\nTdAd\t0.079246\nTcAc\t0.079246\n4hTh\t0.043931\nThJd\t0.03863\nThJc\t0.03863\n5dAs\t0.072294\n5cAs\t0.072294\nTsJh\t0.038892\n3hJh\t0.069059\n5dAc\t0.013776\n5cAd\t0.013776\n6h6d\t0.009231\n6h6c\t0.009231\n6hTh\t0.030378\nTcAd\t0.07591\nTdAc\t0.07591\nJhKh\t0.009611\n5s7s\t0.025734\n5s8s\t0.02286\n5cQc\t0.035853\n5dQd\t0.035853\n4hJh\t0.060204\nJsKs\t0.005812\n7hJh\t0.008289\nThJs\t0.040627\n6hJh\t0.030884\nThKh\t0.000347\nTdQh\t0.001823\nTcQh\t0.001823\n3hTh\t0.037308\nJcKh\t0.000934\nJdKh\t0.000934\n3s5s\t0.024575\n3h6h\t0.012474\n9cQh\t0.004281\n9dQh\t0.004281\n7h7c\t0.002059\n7h7d\t0.002059\nTsKs\t0.002045\n4d5d\t0.025888\n4c5c\t0.025888\n2s2h\t0.028576\n5s6s\t0.024846\n3s3h\t0.001982\nTdKh\t0.013255\nTcKh\t0.013255\n5s9s\t0.005584\n5d6d\t0.004354\n5c6c\t0.004354\nTdQc\t0.001049\nTcQd\t0.001049\n4h8h\t0.014043\n3d5d\t0.03399\n3c5c\t0.03399\n4hKh\t0.018503\n4s5s\t0.027164\n5sQc\t0.033502\n5sQd\t0.033502\n3hKh\t0.072335\n5sKs\t0.13698\n5cQd\t0.035113\n5dQc\t0.035113\n8dQd\t0.003277\n8cQc\t0.003277\n2hJh\t0.041547\n5dQh\t0.124608\n5cQh\t0.124608\n5sQh\t0.091956\n5cKc\t0.048871\n2hTh\t0.035427\n3h9h\t0.029182\n5dKh\t0.07234\n5cKh\t0.07234\n5dKc\t0.042486\n2hQh\t0.124463\n9hAc\t0.003917\n9hAd\t0.003917\n4h5d\t0.066644\n4h5c\t0.066644\n9dAd\t0.052463\n9cAc\t0.052463\n5sKh\t0.044651\n4h5s\t0.03626\n8dQh\t0.017434\n8cQh\t0.017434\n4h9h\t0.033067\n9dAc\t0.037488\n9cAd\t0.037488\n5dKs\t0.008237\n5cKs\t0.008237\n2hKc\t0.008389\n5s9h\t0.008825\n5d9h\t0.008854\n5c9h\t0.008854\n8cAc\t0.011438\n8dAd\t0.011438\n2d3d\t0.011506\n2c3c\t0.011506\n8cAs\t0.013006\n8dAs\t0.013006\n8cAd\t0.013162\n8dAc\t0.013162\n5c8h\t0.014688\n5d8h\t0.014688\n5dJd\t0.016029\n5cJc\t0.016029\n5dJs\t0.00012\n2hKs\t0.016178\n5s6h\t0.000494\n6dQd\t0.000581\n3h7h\t0.016483\n8cQd\t0.001366\n6s6h\t0.01679\n5d7h\t0.017885\n2hQd\t0.002738\n5c7h\t0.017885\n3sKh\t0.017964\n5cJd\t0.017986\n5dJc\t0.017986\n2h6h\t0.019178\n3h8h\t0.019209\n2c5c\t0.006802\n4cKh\t0.01921\n3cQh\t0.008199\n4dKh\t0.01921\n5sTh\t0.019601\n4sKh\t0.019823\n5c6h\t0.022814\n5d6h\t0.022814\n3dKh\t0.023955\n3cKh\t0.023955\n2h7h\t0.024077\n7cQh\t0.026845\n7dQh\t0.026845\n6cQh\t0.028938\n6dQh\t0.028938\n2h3h\t0.0296\n3hKs\t0.030566\n2h8h\t0.031678\n5sJh\t0.033156\n6cQc\t0.000581\n6cQd\t0.000774\n9hAs\t0.001626\n5d6s\t0.001928\n7cQd\t0.002405\n7dQc\t0.002405\n5s7h\t0.002685\n5sTs\t0.033328\n7cQc\t0.003244\n8s8h\t0.004057\n2cKh\t0.033397\n5cTd\t0.004871\n5dTd\t0.005643\n2dKh\t0.033397\n4cQh\t0.006077\n2d5d\t0.006802\n5dTh\t0.034641\n2d4d\t0.007283\n7s7h\t0.008199\n5cTh\t0.034641\n2h4h\t0.035935\n2h9h\t0.03762\n5cJh\t0.040793\n5dJh\t0.040793\n5sJs\t0.044384\n6dQc\t0.000774\n8dQc\t0.001366\n5c6s\t0.001928\n4hKs\t0.002551\n7dQd\t0.003244\n9cAs\t0.045121\n5dTc\t0.004871\n4dQh\t0.006077\n9dAs\t0.045121\n3dQh\t0.008199\n2s4s\t0.047701\n5cJs\t0.00012\nTdAs\t0.063543\n2hQc\t0.002738\nTcAs\t0.063543\n5cTc\t0.005643\n2hKh\t0.065274\n2s3s\t0.070069\n2s5s\t0.070284\n2c4c\t0.007283\n2sKh\t0.109528\n5s8h\t0.004287\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/situation2-p2.txt",
    "content": "ThQh\t1.0\nTsAs\t1.0\nQcAc\t1.0\nQdAs\t1.0\nQcAs\t1.0\nQcAd\t1.0\nQdAc\t1.0\nQdAd\t1.0\nJsAs\t1.0\nKcAc\t0.999988\nKsAd\t0.99948\nKsAc\t0.99948\nKcAs\t0.99948\nKcAd\t0.99948\nKsAs\t0.999246\nAsAd\t0.995804\nAsAc\t0.995804\nAdAc\t0.995165\nQhAc\t0.985218\nQhAd\t0.985218\n9hQh\t0.983855\nQhAs\t0.983609\nQdQc\t0.94031\n5dAd\t0.938396\n5cAc\t0.938396\nJcAc\t0.922008\nJdAd\t0.922008\nJhQh\t0.91829\nJcAd\t0.909971\nJdAc\t0.909971\n5sAs\t0.892997\nTsJs\t0.884349\nJsAc\t0.864439\nJsAd\t0.864439\nKhAs\t0.861762\nKhAd\t0.78992\nKhAc\t0.78992\nJhAs\t0.783567\nTdJd\t0.77909\nTcJc\t0.77909\nThJh\t0.728156\nJdAs\t0.724391\nJcAs\t0.724391\nQhQd\t0.695481\nQhQc\t0.695481\n8h9h\t0.690308\n9sAs\t0.687567\n8hQh\t0.682829\n9hTh\t0.67847\nJhAd\t0.649819\nJhAc\t0.649819\n8sAs\t0.598506\n6s7s\t0.586651\n3c4c\t0.568265\n3d4d\t0.568265\n7h8h\t0.531157\n8hTh\t0.524748\n5d5c\t0.51912\n8s9s\t0.508511\n6h8h\t0.502902\n6h7h\t0.49231\n5s5c\t0.489826\n5s5d\t0.489826\n3s4s\t0.465243\n7hQh\t0.428411\nThAc\t0.421081\nThAd\t0.421081\n7sAs\t0.415702\n7h9h\t0.408588\n4h6h\t0.391207\n3h4h\t0.387373\n9sTs\t0.367639\n6h9h\t0.359178\n9cQc\t0.336767\n9dQd\t0.336767\nTdJc\t0.336202\nTcJd\t0.336202\n7hTh\t0.327239\nTdJh\t0.323304\nTcJh\t0.323304\n7hAc\t0.312333\n7hAd\t0.312333\nThAs\t0.28378\n4h7h\t0.2764\n6d6c\t0.274163\nTdQd\t0.259542\nTcQc\t0.259542\n7s8s\t0.259143\n5sAc\t0.258624\n5sAd\t0.258624\nTdAd\t0.255515\nTcAc\t0.255515\nQhKh\t0.255014\n4hTh\t0.247383\nThJd\t0.242815\nThJc\t0.242815\n5dAs\t0.24056\n5cAs\t0.24056\n8c9h\t0.240101\n8d9h\t0.240101\n4s6s\t0.240024\nTsJh\t0.239936\n8h9d\t0.237024\n8h9c\t0.237024\n8sTs\t0.236164\n3hJh\t0.235815\n5dAc\t0.23249\n5cAd\t0.23249\n6h6d\t0.230447\n6h6c\t0.230447\n6hTh\t0.223814\nTcAd\t0.222871\nTdAc\t0.222871\nJhKh\t0.217936\n5s7s\t0.217457\n5s8s\t0.209134\n5cQc\t0.205279\n5dQd\t0.205279\n4hJh\t0.204402\n4s7s\t0.190774\n8hAd\t0.188829\n8hAc\t0.188829\nTsQh\t0.188518\n6d7d\t0.182818\n6c7c\t0.182818\nJsKs\t0.182139\n7hJh\t0.180032\nThJs\t0.175976\nJcQc\t0.174283\nJdQd\t0.174283\n6hQh\t0.171648\n9sJs\t0.171103\n6h7d\t0.169491\n6h7c\t0.169491\n9cTh\t0.16643\n9dTh\t0.16643\n6hJh\t0.16181\n6d7h\t0.154108\n6c7h\t0.154108\nThKh\t0.15041\nTdQh\t0.147366\nTcQh\t0.147366\n3hTh\t0.145828\n9cJh\t0.143185\n9dJh\t0.143185\n8dJh\t0.135506\n8cJh\t0.135506\n7h8c\t0.135312\n7h8d\t0.135312\nJcKh\t0.130459\nJdKh\t0.130459\n5c8c\t0.130091\n5d8d\t0.130091\n3s5s\t0.129354\n8hJh\t0.127313\n8sJs\t0.125964\n5d7d\t0.12219\n5c7c\t0.12219\n3h6h\t0.122119\n6hAd\t0.12198\n6hAc\t0.12198\n9cQh\t0.120908\n9dQh\t0.120908\n7c8h\t0.119344\n7d8h\t0.119344\n6cKh\t0.11848\n6dKh\t0.11848\n2h2c\t0.118067\n2h2d\t0.118067\n7cKh\t0.113613\n7dKh\t0.113613\n7h7c\t0.111914\n7h7d\t0.111914\nTsKs\t0.11125\n4d5d\t0.110589\n4c5c\t0.110589\n9hQd\t0.104607\n9hQc\t0.104607\n2s2h\t0.100401\n9hTd\t0.099982\n9hTc\t0.099982\nJsKh\t0.098504\n5s6s\t0.098339\n3s3h\t0.097965\n8dTh\t0.095905\n8cTh\t0.095905\n6s8s\t0.095264\nTdKh\t0.095156\nTcKh\t0.095156\n5s9s\t0.089266\n5d6d\t0.087465\n5c6c\t0.087465\nTdQc\t0.087005\nTcQd\t0.087005\n7sKs\t0.086537\n6hKh\t0.084513\n9hJh\t0.084366\nTdJs\t0.083068\nTcJs\t0.083068\n9dKh\t0.081128\n9cKh\t0.081128\n3h3d\t0.079948\n3h3c\t0.079948\n8h8c\t0.077443\n8h8d\t0.077443\n9sQh\t0.077198\nJsQh\t0.076678\n4h4d\t0.073616\n4h4c\t0.073616\n4h8h\t0.073565\n9dQc\t0.071635\n9cQd\t0.071635\n3d5d\t0.071211\n3c5c\t0.071211\n8cKh\t0.071153\n8dKh\t0.071153\n7hKh\t0.066619\n4hKh\t0.066001\n4s5s\t0.063675\n5sQc\t0.063187\n5sQd\t0.063187\n5c9c\t0.062731\n5d9d\t0.062731\nJcQd\t0.061811\nJdQc\t0.061811\nTsKh\t0.061088\n8hKh\t0.056488\nJhKc\t0.056085\n9hJd\t0.05348\n9hJc\t0.05348\n3hKh\t0.050775\n8hQd\t0.05038\n8hQc\t0.05038\n3s6s\t0.049144\nTsQc\t0.049088\nTsQd\t0.049088\n6sAs\t0.046578\nThQc\t0.045762\nThQd\t0.045762\nJcQh\t0.045513\nJdQh\t0.045513\n8hJd\t0.045208\n8hJc\t0.045208\n5sKs\t0.044395\n9sKs\t0.044308\nJcKc\t0.043908\n5cQd\t0.039281\n5dQc\t0.039281\n8dQd\t0.035404\n8cQc\t0.035404\n6d7c\t0.035172\n6c7d\t0.035172\n7sTs\t0.035108\nTsJd\t0.032898\nTsJc\t0.032898\n7hAs\t0.032515\n9hKc\t0.03239\n6hAs\t0.030463\n8sKs\t0.030326\n6s6d\t0.028536\n6s6c\t0.028536\n7hKc\t0.026387\n8s9h\t0.025309\n9h9c\t0.025287\n9h9d\t0.025287\n8hTc\t0.024807\n8hTd\t0.024807\n3hQh\t0.024048\n9s9h\t0.022733\n2hJh\t0.022645\n7hQc\t0.021782\n7hQd\t0.021782\nJdKc\t0.020455\n4d5c\t0.019111\n4c5d\t0.019111\n6h8d\t0.017399\n6h8c\t0.017399\n6sKs\t0.017271\n5dQh\t0.016629\n5cQh\t0.016629\n3sTs\t0.016566\n9hKs\t0.016399\nTcKc\t0.014618\n5sQh\t0.014519\n7d7c\t0.014207\n6hKc\t0.012789\n5cKc\t0.012455\n8h9s\t0.012401\n8hKc\t0.010877\nTsAc\t0.009255\nTsAd\t0.009255\n2hTh\t0.008329\n6d8h\t0.008122\n6c8h\t0.008122\nJsQd\t0.00778\nJsQc\t0.00778\n3h9h\t0.007491\n4s4h\t0.007365\nTdKc\t0.007048\n4sAs\t0.006925\n9sQc\t0.006557\n9sQd\t0.006557\n5dKh\t0.00609\n5cKh\t0.00609\n5dKc\t0.006084\n2hQh\t0.005711\n4c5s\t0.005594\n4d5s\t0.005594\n4hQh\t0.005377\nQcKc\t0.005261\n9hAc\t0.005189\n9hAd\t0.005189\nJhQd\t0.004636\nJhQc\t0.004636\n5c6d\t0.004245\n5d6c\t0.004245\n4h5d\t0.004108\n4h5c\t0.004108\n9dAd\t0.003654\n9cAc\t0.003654\n5sKh\t0.002873\nThTd\t0.002718\nThTc\t0.002718\n7s7c\t0.002255\n7s7d\t0.002255\nQdKc\t0.002196\n4h5s\t0.001528\n5s6d\t0.001469\n5s6c\t0.001469\n7sQh\t0.001327\n8dQh\t0.000626\n8cQh\t0.000626\n4h9h\t0.00042\n2sTs\t0.000129\n9dAc\t0.000111\n9cAd\t0.000111\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/situation3-p1.txt",
    "content": "7c9d\t0.576598\n7c9s\t0.576598\n8dQc\t0.004872\n8cQd\t0.081817\n8cQs\t0.081817\n8sQc\t0.004872\n2dKc\t0.735301\n2sKc\t0.735301\n2hQd\t0.280807\n2hQs\t0.280807\n7s9d\t0.000698\n7d9s\t0.000698\n2hKd\t0.385034\n2hKs\t0.385034\n7s9c\t0.532047\n7d9c\t0.532047\n2hQc\t0.408286\n8sJc\t0.367419\n8dJc\t0.367419\n8dJs\t0.271071\n8cJs\t0.376085\n8sJd\t0.271071\n8cJd\t0.376085\n9dQc\t0.367292\n9sQc\t0.367292\n9cQs\t0.320529\n9sQd\t0.382032\n9cQd\t0.320529\n9dQs\t0.382032\n7cTd\t0.626715\n7cTs\t0.626715\n3d8d\t0.974662\n3s8s\t0.974662\n8dTc\t0.736024\n8cTs\t0.731034\n8sTd\t0.520424\n8cTd\t0.731034\n8sTc\t0.736024\n8dTs\t0.520424\n4cTd\t0.661603\n4cTs\t0.661603\n7dTs\t0.180292\n7sTd\t0.180292\n2dQc\t0.537249\n2sQc\t0.537249\n2hKc\t0.508368\n2cKs\t0.705708\n2cKd\t0.705708\n6cKd\t0.616555\n6cKs\t0.616555\n2d8d\t0.067562\n2s8s\t0.067562\n9cJd\t0.482259\n9dJc\t0.515822\n9sJc\t0.515822\n9dJs\t0.42837\n9cJs\t0.482259\n9sJd\t0.42837\n2cQd\t0.604471\n2cQs\t0.604471\n6sKc\t0.748055\n6dKc\t0.748055\n6cQd\t0.602979\n6cQs\t0.602979\n6dKs\t0.35925\n6sKd\t0.35925\n6hQd\t0.160684\n6hQs\t0.160684\n6hKd\t0.184386\n6hKs\t0.184386\n7sTc\t0.527372\n7dTc\t0.527372\n4sTd\t0.382808\n4dTs\t0.382808\n4sTc\t0.490031\n4dTc\t0.490031\n4cJd\t0.579057\n4cJs\t0.579057\n3dQh\t0.209001\n3sQh\t0.209001\nTdQc\t0.665616\nTsQc\t0.665616\nTcQd\t0.630535\nTcQs\t0.630535\nTdQs\t0.553059\nTsQd\t0.553059\n2hKh\t0.184811\n6dQc\t0.577865\n6sQc\t0.577865\n3sJd\t0.302203\n3dJs\t0.302203\n8cKd\t0.809187\n8cKs\t0.809187\n8c9d\t0.938184\n8d9s\t0.607714\n8s9d\t0.607714\n8s9c\t0.999263\n8d9c\t0.999263\n8c9s\t0.938184\n3sJc\t0.260805\n3dJc\t0.260805\n2sKd\t0.635289\n2dKs\t0.635289\n2dKd\t0.636623\n2sKs\t0.636623\n2sQd\t0.409617\n2dQs\t0.409617\n6hKc\t0.29862\n8h9d\t0.687069\n8h9s\t0.687069\n2dQd\t0.41179\n2sQs\t0.41179\n4dJc\t0.487367\n4sJc\t0.487367\n6hQc\t0.260818\n4s9s\t0.825609\n4d9d\t0.825609\nTsJd\t0.603136\nTdJc\t0.763068\nTdJs\t0.603136\nTcJs\t0.701756\nTcJd\t0.701756\nTsJc\t0.763068\n6sQd\t0.361312\n6dQs\t0.361312\n8dKc\t0.570998\n8sKc\t0.570998\n4dJs\t0.405203\n4sJd\t0.405203\n6sJd\t0.390351\n6dJs\t0.390351\n3dJh\t0.037906\n3sJh\t0.037906\n3sQd\t0.339884\n3dQs\t0.339884\n8dKs\t0.156603\n8sKd\t0.156603\n6hJs\t0.251252\n6hJd\t0.251252\n7c8s\t0.761798\n7c8d\t0.761798\n3dQc\t0.374428\n3sQc\t0.374428\n6dTs\t0.328233\n6sTd\t0.328233\n9hTc\t0.491011\n9sTd\t0.741425\n9dTc\t0.958052\n9sTh\t0.660847\n9dTs\t0.741425\n9hTs\t0.57964\n9cTd\t0.980837\n9dTh\t0.660847\n9cTs\t0.980837\n9sTc\t0.958052\n9hTd\t0.57964\n4s8s\t0.891436\n4d8d\t0.891436\n9cKd\t0.768042\n9cKs\t0.768042\n9dKc\t0.732077\n9sKc\t0.732077\n7s8c\t0.697854\n7d8c\t0.697854\n7cJs\t0.546098\n7cJd\t0.546098\nTdJh\t0.528774\nTsJh\t0.528774\n7d8s\t0.451054\n7s8d\t0.451054\n7sJd\t0.322379\n7dJs\t0.322379\n9sKd\t0.271689\n9dKs\t0.271689\n8hJs\t0.248402\n8hJd\t0.248402\n7dKs\t0.45682\n7sKd\t0.45682\nTcJh\t0.447069\n8s9h\t0.705435\n8d9h\t0.705435\nJcQd\t0.999668\nJdQs\t0.989737\nJsQd\t0.989737\nJsQc\t0.999668\nJcQs\t0.999668\nJdQc\t0.999668\n2sAc\t0.26047\n2dAc\t0.26047\n7cAs\t0.372264\n7cAd\t0.372264\n7sAc\t0.383251\n7dAs\t0.201945\n7sAd\t0.201945\n7dAc\t0.383251\n9cTh\t0.567681\n7dQs\t0.19954\n7sQd\t0.19954\n6cJs\t0.417697\n6cJd\t0.417697\n7dJc\t0.478664\n7sJc\t0.478664\n8hQd\t0.105077\n8hQs\t0.105077\n7cKd\t0.798464\n7cKs\t0.798464\nThJc\t0.362791\n6d9s\t0.33735\n6s9d\t0.33735\n8hTd\t0.358348\n8hTs\t0.358348\n4cQs\t0.486572\n4cQd\t0.486572\n7hKd\t0.200805\n7hKs\t0.200805\nThJs\t0.366346\nThJd\t0.366346\n8hJc\t0.158606\n2sAd\t0.125948\n2dAs\t0.125948\n2sAs\t0.12656\n2dAd\t0.12656\n6cTd\t0.344955\n6cTs\t0.344955\n9hQs\t0.399326\n9hQd\t0.399326\n6dJc\t0.368011\n6sJc\t0.368011\n6sAd\t0.475394\n6dAs\t0.475394\n6dKh\t0.210138\n6sKh\t0.210138\n3sJs\t0.307328\n3dJd\t0.307328\n2hQh\t0.011411\n6s8d\t0.218216\n6d8s\t0.218216\n7hKc\t0.409867\n6dTc\t0.316415\n6sTc\t0.316415\n7hTd\t0.072864\n7hTs\t0.072864\n7h8c\t0.412121\n3s9s\t0.915402\n3d9d\t0.915402\n7h9d\t0.112383\n7h9s\t0.112383\n7dKc\t0.746292\n7sKc\t0.746292\n2s6s\t0.011833\n2d6d\t0.011833\n3sAd\t0.020721\n3dAs\t0.020721\n6hJc\t0.255927\n6cKh\t0.277723\n6c9d\t0.391757\n6c9s\t0.391757\n6s8c\t0.251417\n6d8c\t0.251417\n5d9s\t0.008335\n5s9d\t0.008335\n6s9c\t0.387243\n6d9c\t0.387243\n6dAc\t0.603403\n6sAc\t0.603403\n5c9s\t0.008803\n5c9d\t0.008803\n7hTc\t0.120492\n3sKc\t0.019864\n3dKc\t0.019864\n5s9c\t0.016244\n5d9c\t0.016244\n4sQd\t0.321008\n4dQs\t0.321008\n8h9c\t0.714389\n9hQc\t0.32268\n3dQd\t0.348615\n3sQs\t0.348615\n2h6h\t0.374044\n7h9c\t0.218194\n3dKs\t0.026622\n3sKd\t0.026622\n6c8s\t0.272968\n6c8d\t0.272968\nThQc\t0.469357\n6cAs\t0.593829\n6cAd\t0.593829\n8hQc\t0.187573\n8hKd\t0.61596\n8hKs\t0.61596\nThQs\t0.627559\nThQd\t0.627559\n2cAd\t0.229155\n2cAs\t0.229155\n2c6c\t0.086933\nTcQh\t0.141596\n7cQd\t0.306419\n7cQs\t0.306419\n4sQc\t0.429419\n4dQc\t0.429419\n4sTs\t0.469618\n4dTd\t0.469618\n7dQc\t0.233307\n7sQc\t0.233307\n7h8s\t0.371923\n7h8d\t0.371923\n4d5c\t0.375902\n4s5c\t0.375902\n6hTd\t0.254551\n6hTs\t0.254551\n6s7d\t0.035004\n6d7s\t0.035004\n2h7h\t0.80108\n6s7h\t0.042054\n6d7h\t0.042054\n6c7h\t0.045399\n2d7d\t0.850397\n2s7s\t0.850397\nTsQh\t0.218291\nTdQh\t0.218291\n2cQh\t0.020234\n3dTd\t0.547335\n3sTs\t0.547335\n6h8c\t0.108551\n9hKd\t0.528364\n9hKs\t0.528364\n6hTc\t0.229084\n8c9h\t0.808115\n2sKh\t0.200768\n2dKh\t0.200768\n8hKc\t0.742747\n6c7s\t0.033139\n6c7d\t0.033139\nTdKc\t0.619885\nTsKc\t0.619885\n8cJh\t0.032788\nJhQs\t0.849488\nJhQd\t0.849488\n3sAc\t0.026183\n3dAc\t0.026183\n6s7c\t0.040271\n6d7c\t0.040271\nJcQh\t0.999668\n4c5s\t0.278276\n4c5d\t0.278276\nTcKd\t0.600251\nTcKs\t0.600251\nJhQc\t0.875425\n8dJh\t0.024449\n8sJh\t0.024449\n6h7d\t0.02614\n6h7s\t0.02614\n3dKd\t0.022563\n3sKs\t0.022563\nTdKs\t0.271795\nTsKd\t0.271795\n2c7c\t0.883777\n2sJs\t0.306491\n2dJd\t0.306491\n6h8d\t0.103823\n6h8s\t0.103823\n5c8s\t0.182661\n5c8d\t0.182661\n6sJh\t0.089906\n6dJh\t0.089906\n9hJd\t0.314241\n9hJs\t0.314241\n6h7c\t0.025703\nJdQh\t0.999668\nJsQh\t0.999668\n6h9c\t0.224107\n5s8d\t0.101857\n5d8s\t0.101857\n4d5s\t0.134176\n4s5d\t0.134176\n2c8c\t0.004952\n6dTh\t0.076579\n6sTh\t0.076579\n6d8h\t0.08826\n6s8h\t0.08826\n6cTh\t0.084164\n2cQc\t0.100448\n6c8h\t0.074305\n5d8c\t0.228083\n5s8c\t0.228083\n9dJh\t0.254641\n9sJh\t0.254641\n6cQh\t0.048666\n6sQh\t0.021021\n6dQh\t0.021021\n8cKh\t0.440539\n8hAs\t0.285489\n8hAd\t0.285489\n2cKc\t0.337836\n9hKc\t0.616775\n8hAc\t0.607257\n9hJc\t0.293782\n6cJh\t0.100179\n7dKh\t0.244947\n7sKh\t0.244947\n6h9s\t0.293552\n6h9d\t0.293552\n2s9s\t0.033625\n2d9d\t0.033625\n7cTh\t0.010525\n7hQs\t0.186607\n7hQd\t0.186607\n7dQh\t0.069081\n7sQh\t0.069081\n6s9h\t0.145742\n6d9h\t0.145742\n6hJh\t0.031416\n7cKh\t0.381057\n6cJc\t0.234386\n8sKh\t0.246953\n8dKh\t0.246953\n2dAh\t0.037724\n2sAh\t0.037724\n8cAs\t0.998841\n8cAd\t0.998841\n8sAd\t0.793184\n8dAs\t0.793184\n6dJd\t0.345568\n6sJs\t0.345568\n8sTh\t0.424029\n8dTh\t0.424029\n9dKh\t0.362624\n9sKh\t0.362624\n2cKh\t0.248771\n7c8h\t0.272613\n4dJd\t0.38451\n4sJs\t0.38451\n9cKh\t0.437988\n6dQd\t0.406045\n6sQs\t0.406045\n7cQh\t0.021296\n6c9h\t0.176795\n2cTc\t0.010327\n4c9c\t0.276899\n8sAc\t0.998841\n8dAc\t0.998841\n2dTd\t0.084362\n2sTs\t0.084362\n7d8h\t0.20001\n7s8h\t0.20001\nJcKs\t0.398371\nJcKd\t0.398371\n7hJd\t0.129925\n7hJs\t0.129925\nJsKc\t0.413866\nJdKc\t0.413866\n2hAd\t0.063911\n2hAs\t0.063911\n9cJh\t0.193916\nJdKs\t0.265609\nJsKd\t0.265609\n7hQc\t0.251705\n7hJc\t0.283341\n2hAc\t0.092257\n2cAh\t0.051811\n8sAh\t0.412602\n8dAh\t0.412602\n8hTc\t0.384091\n4cTh\t0.168071\n7sAh\t0.00395\n7dAh\t0.00395\n2cJc\t0.130121\n6sAh\t0.313061\n6dAh\t0.313061\n7sJs\t0.487453\n7dJd\t0.487453\nThKd\t0.284108\nThKs\t0.284108\nTsKh\t0.216933\nTdKh\t0.216933\n4cJh\t0.050055\n7cJh\t0.113612\nJdKh\t0.119767\nJsKh\t0.119767\n4dTh\t0.074387\n4sTh\t0.074387\nThKc\t0.392161\n8cTh\t0.395134\nJhKs\t0.095369\nJhKd\t0.095369\n7sJh\t0.072911\n7dJh\t0.072911\n8cAh\t0.793549\n6cAh\t0.344281\n4dJh\t0.009256\n4sJh\t0.009256\nJcKh\t0.122454\n4dQd\t0.301753\n4sQs\t0.301753\nTcKh\t0.288389\nJhKc\t0.064511\n7sQs\t0.166611\n7dQd\t0.166611\n7hAs\t0.120704\n7hAd\t0.120704\n8sJs\t1.0\n8dJd\t1.0\n5d9d\t0.004281\n5s9s\t0.004281\n9sAd\t0.670271\n9dAs\t0.670271\n9sAc\t0.98371\n9dAc\t0.98371\n9cAs\t0.996905\n9cAd\t0.996905\n3s4s\t0.050704\n3d4d\t0.050704\nQdKh\t0.16917\nQsKh\t0.16917\n7dTd\t0.59285\n7sTs\t0.59285\n7hAc\t0.11673\n6cQc\t0.071691\n7s9s\t0.979811\n7d9d\t0.979811\n9hAs\t0.097754\n9hAd\t0.097754\nQhKs\t0.145851\nQhKd\t0.145851\n3d6d\t0.181929\n3s6s\t0.181929\n5d8d\t0.126323\n5s8s\t0.126323\n8sTs\t0.99998\n8dTd\t0.99998\nQcKh\t0.238365\n9sAh\t0.297461\n9dAh\t0.297461\nQhKc\t0.185222\n9cAh\t0.34224\n6cTc\t0.158978\n6hAd\t0.129174\n6hAs\t0.129174\n6sTs\t0.239982\n6dTd\t0.239982\n9hAc\t0.222999\n4cQh\t0.008509\n6hTh\t0.029482\n4c8c\t0.481243\n6hAc\t0.17409\n2s2d\t0.065175\n8cTc\t0.679599\nQcKs\t0.575361\nQcKd\t0.575361\n8cJc\t0.710125\n6c9c\t0.165487\n6d9d\t0.301487\n6s9s\t0.301487\n8d9d\t0.999906\n8s9s\t0.999906\n6h8h\t0.252305\nQsKc\t0.586199\nQdKc\t0.586199\n3d5d\t0.566697\n3s5s\t0.566697\n8sQs\t0.869797\n8dQd\t0.869797\n2s2c\t0.066527\n2d2c\t0.066527\n3s7s\t0.557516\n3d7d\t0.557516\nTsAd\t0.555883\nTdAs\t0.555883\nTsAc\t0.781149\nTdAc\t0.781149\n7d8d\t0.476335\n7s8s\t0.476335\nTcAs\t0.715185\nTcAd\t0.715185\nQdKs\t0.326483\nQsKd\t0.326483\n6h9h\t0.117428\n6s8s\t0.096711\n6d8d\t0.096711\n6c8c\t0.038704\nTcAh\t0.286361\nTdAh\t0.188743\nTsAh\t0.188743\n9dJd\t0.999681\n9sJs\t0.999681\n9cJc\t0.845093\n9sTs\t0.99983\n9dTd\t0.99983\n4d7d\t0.043146\n4s7s\t0.043146\nThAs\t0.162751\nThAd\t0.162751\n8c9c\t0.563958\n4c7d\t0.053904\n4c7s\t0.053904\n9cTc\t0.913975\nThAc\t0.290529\nJsAd\t0.400535\nJdAs\t0.400535\nJcAs\t0.656617\nJcAd\t0.656617\nJdAc\t0.664358\nJsAc\t0.664358\n6h7h\t0.09862\n6s7s\t0.11192\n6d7d\t0.11192\n6c7c\t0.112457\n6dKd\t0.437013\n6sKs\t0.437013\nJhAd\t0.180453\nJhAs\t0.180453\nJhAc\t0.252079\nJdAh\t0.08668\nJsAh\t0.08668\nAdAc\t0.146827\nJsJd\t0.230457\n8cKc\t0.032623\nJsJc\t0.339728\nJsQs\t1.0\n6cAc\t0.499908\nJsKs\t0.454858\n8sKs\t0.999783\n7sAs\t0.175029\n6sAs\t0.483072\nJsAs\t0.408229\n8sAs\t0.860818\n9sQs\t0.999783\nJhJd\t0.556002\nJhJc\t0.618049\n7hAh\t0.131257\nJhQh\t0.996181\n5s5d\t0.372318\n9cQc\t0.910015\nJhKh\t0.417914\n7dAd\t0.175029\n9cKc\t0.386251\n4c5c\t0.105699\n9cAc\t0.036749\nJhAh\t0.148733\nTsJs\t1.0\n4d7c\t0.054927\nJdJc\t0.339728\nTsQs\t1.0\n4d5d\t0.14437\nTsKs\t0.705848\nJdQd\t1.0\n9sAs\t0.691414\nTsAs\t0.557691\nJdKd\t0.454858\n4s4c\t0.009303\n8hAh\t0.041345\nJdAd\t0.408229\n8dKd\t0.999783\nJcQc\t1.0\n8dAd\t0.860818\nJcKc\t0.193321\nJcAh\t0.071483\nQsQh\t0.90616\nTcJc\t0.970424\nQsQd\t0.765069\nQsQc\t0.791112\nTcQc\t1.0\nQsKs\t0.372611\nTcKc\t0.174523\nQsAs\t0.32174\nQsAh\t0.042789\n9hKh\t0.074643\nQsAd\t0.321823\n7sKs\t0.608566\nQsAc\t0.570296\nQhQd\t0.90616\n9dQd\t0.999783\nQhQc\t1.0\n9dKd\t1.0\n9dAd\t0.691414\nQhKh\t0.559857\nQhAs\t0.336777\nQhAh\t0.038874\nQhAd\t0.336777\nQhAc\t0.458822\n7c9c\t0.031346\nQdQc\t0.791112\n4d4c\t0.009303\n4s7c\t0.054927\n4s5s\t0.14437\nQdKd\t0.372611\nThJh\t0.046726\n8cAc\t0.083064\nThQh\t0.241456\nQdAs\t0.321823\nThKh\t0.313879\nQdAh\t0.042789\nThAh\t0.155236\nQdAd\t0.32174\nQdAc\t0.570296\n8cQc\t0.412002\nQcKc\t0.100869\nQcAs\t0.583435\nQcAh\t0.061764\nQcAd\t0.583435\nJsJh\t0.556002\n6dAd\t0.483072\nKsKh\t1.0\nKsKd\t1.0\nKsKc\t1.0\n5d5c\t0.426142\nKsAs\t0.138113\n7dKd\t0.608566\nKsAh\t0.088275\nKsAd\t0.124245\nKsAc\t0.169566\n7cAc\t0.099207\nKhKd\t1.0\nKhKc\t1.0\nKhAs\t0.191619\nTdJd\t1.0\nKhAh\t0.030432\nTdKd\t0.705848\nKhAd\t0.191619\nKhAc\t0.099757\nKdKc\t1.0\n9hAh\t0.084663\nKdAs\t0.124245\nKdAh\t0.088275\n5s5c\t0.426142\nKdAd\t0.138113\nKdAc\t0.169566\nKcAs\t0.192207\n9sKs\t1.0\nKcAh\t0.096592\nTdAd\t0.557691\nKcAd\t0.192207\nKcAc\t0.245405\nTdQd\t1.0\nAsAc\t0.146827\nAsAd\t0.087461\n6hAh\t0.532644\n"
  },
  {
    "path": "Source/Lookahead/Tests/ranges/situation3-p2.txt",
    "content": "4s8c\t0.881958\n4d8c\t0.881958\n7c9d\t0.861573\n7c9s\t0.861573\n5c6h\t0.859565\n4c8d\t0.854665\n4c8s\t0.854665\n8dQc\t0.846896\n8cQd\t0.846896\n8sQd\t0.846896\n8dQs\t0.846896\n8cQs\t0.846896\n8sQc\t0.846896\n2dKc\t0.841781\n2sKc\t0.841781\n2hQd\t0.829355\n2hQs\t0.829355\n7s9d\t0.81952\n7d9s\t0.81952\n2hKd\t0.810361\n2hKs\t0.810361\n7s9c\t0.808142\n7d9c\t0.808142\n5d6h\t0.806732\n5s6h\t0.806732\n2sTd\t0.801388\n2dTs\t0.801388\n4c9s\t0.800455\n4c9d\t0.800455\n2hQc\t0.783974\n8sJc\t0.775972\n8dJc\t0.775972\n8dJs\t0.775972\n8cJs\t0.775972\n8sJd\t0.775972\n8cJd\t0.775972\n3s9d\t0.769837\n3d9s\t0.769837\n2cJs\t0.768696\n2cJd\t0.768696\n9dQc\t0.766948\n9sQc\t0.766948\n9cQs\t0.766948\n9sQd\t0.766948\n9cQd\t0.766948\n9dQs\t0.766948\n7cTd\t0.763856\n7cTs\t0.763856\n3d8d\t0.757138\n3s8s\t0.757138\n8dTc\t0.756533\n8cTs\t0.756533\n8sTd\t0.756533\n8cTd\t0.756533\n8sTc\t0.756533\n8dTs\t0.756533\n4cTd\t0.754814\n4cTs\t0.754814\n7dTs\t0.751536\n7sTd\t0.751536\n2dQc\t0.744011\n2sQc\t0.744011\n2sJc\t0.741821\n2dJc\t0.741821\n2hKc\t0.738867\n2cKs\t0.738122\n2cKd\t0.738122\n6cKd\t0.734634\n6cKs\t0.734634\n4d9c\t0.730726\n4s9c\t0.730726\n2d8d\t0.729593\n2s8s\t0.729593\n9cJd\t0.726804\n9dJc\t0.726804\n9sJc\t0.726804\n9dJs\t0.726804\n9cJs\t0.726804\n9sJd\t0.726804\n2cTd\t0.726795\n2cTs\t0.726795\n3s9h\t0.725011\n3d9h\t0.725011\n2cQd\t0.724142\n2cQs\t0.724142\n6sKc\t0.723886\n6dKc\t0.723886\n6cQd\t0.723544\n6cQs\t0.723544\n6dKs\t0.721497\n6sKd\t0.721497\n6hQd\t0.71565\n6hQs\t0.71565\n6hKd\t0.715036\n6hKs\t0.715036\n7sTc\t0.713413\n7dTc\t0.713413\n4s9d\t0.713244\n4d9s\t0.713244\n3dTh\t0.712363\n3sTh\t0.712363\n4sTd\t0.709956\n4dTs\t0.709956\n4sTc\t0.702201\n4dTc\t0.702201\n4cJd\t0.699521\n4cJs\t0.699521\n3dQh\t0.688411\n3sQh\t0.688411\nTdQc\t0.687123\nTsQc\t0.687123\nTcQd\t0.687123\nTcQs\t0.687123\nTdQs\t0.687123\nTsQd\t0.687123\n2hKh\t0.684846\n4c8h\t0.684784\n6dQc\t0.684341\n6sQc\t0.684341\n2dJs\t0.681606\n2sJd\t0.681606\n2sTc\t0.680903\n2dTc\t0.680903\n5cAh\t0.676354\n3sJd\t0.676227\n3dJs\t0.676227\n8cKd\t0.675704\n8cKs\t0.675704\n8c9d\t0.674819\n8d9s\t0.674819\n8s9d\t0.674819\n8s9c\t0.674819\n8d9c\t0.674819\n8c9s\t0.674819\n3sJc\t0.672359\n3dJc\t0.672359\n2sKd\t0.668517\n2dKs\t0.668517\n2dKd\t0.66715\n2sKs\t0.66715\n5dAh\t0.662678\n5sAh\t0.662678\n3d9c\t0.660672\n3s9c\t0.660672\n2sQd\t0.656557\n2dQs\t0.656557\n6hKc\t0.65313\n8h9d\t0.652331\n8h9s\t0.652331\n2dQd\t0.650591\n2sQs\t0.650591\n4dJc\t0.647619\n4sJc\t0.647619\n5d7h\t0.644339\n5s7h\t0.644339\n6hQc\t0.641382\n4s9s\t0.64116\n4d9d\t0.64116\n4d8s\t0.637148\n4s8d\t0.637148\n3sTc\t0.63494\n3dTc\t0.63494\nTsJd\t0.63339\nTdJc\t0.63339\nTdJs\t0.63339\nTcJs\t0.63339\nTcJd\t0.63339\nTsJc\t0.63339\n5cAs\t0.633095\n5cAd\t0.633095\n6sQd\t0.631843\n6dQs\t0.631843\n3dTs\t0.630206\n3sTd\t0.630206\n8dKc\t0.629777\n8sKc\t0.629777\n4dJs\t0.621776\n4sJd\t0.621776\n6sJd\t0.61969\n6dJs\t0.61969\n3dJh\t0.61941\n3sJh\t0.61941\n3sQd\t0.617987\n3dQs\t0.617987\n8dKs\t0.61711\n8sKd\t0.61711\n6hJs\t0.616595\n6hJd\t0.616595\n5sAc\t0.61611\n5dAc\t0.61611\n7c8s\t0.61482\n7c8d\t0.61482\n3dQc\t0.61357\n3sQc\t0.61357\n5c7h\t0.610477\n4s8h\t0.608517\n4d8h\t0.608517\n6dTs\t0.608188\n6sTd\t0.608188\n9hTc\t0.607465\n9sTd\t0.607465\n9dTc\t0.607465\n9sTh\t0.607465\n9dTs\t0.607465\n9hTs\t0.607465\n9cTd\t0.607465\n9dTh\t0.607465\n9cTs\t0.607465\n9sTc\t0.607465\n9hTd\t0.607465\n4s8s\t0.605972\n4d8d\t0.605972\n2hAh\t0.605116\n9cKd\t0.604811\n9cKs\t0.604811\n9dKc\t0.59754\n9sKc\t0.59754\n7s8c\t0.595891\n7d8c\t0.595891\n7cJs\t0.594581\n7cJd\t0.594581\nTdJh\t0.594114\nTsJh\t0.594114\n7d8s\t0.592579\n7s8d\t0.592579\n7sJd\t0.59141\n7dJs\t0.59141\n9sKd\t0.590182\n9dKs\t0.590182\n8hJs\t0.589286\n8hJd\t0.589286\n7dKs\t0.58673\n7sKd\t0.58673\n5sAd\t0.586005\n5dAs\t0.586005\nTcJh\t0.584357\n8s9h\t0.584066\n8d9h\t0.584066\n3s4d\t0.583234\n3d4s\t0.583234\nJcQd\t0.578568\nJdQs\t0.578568\nJsQd\t0.578568\nJsQc\t0.578568\nJcQs\t0.578568\nJdQc\t0.578568\n2sAc\t0.576387\n2dAc\t0.576387\n7cAs\t0.57586\n7cAd\t0.57586\n7sAc\t0.57586\n7dAs\t0.57586\n7sAd\t0.57586\n7dAc\t0.57586\n9cTh\t0.57584\n7dQs\t0.575241\n7sQd\t0.575241\n6cJs\t0.574339\n6cJd\t0.574339\n2s9d\t0.571157\n2d9s\t0.571157\n7dJc\t0.571117\n7sJc\t0.571117\n2c9s\t0.569907\n2c9d\t0.569907\n8hQd\t0.568713\n8hQs\t0.568713\n5s7d\t0.566817\n5d7s\t0.566817\n7cKd\t0.565582\n7cKs\t0.565582\nThJc\t0.564455\n6d9s\t0.563007\n6s9d\t0.563007\n8hTd\t0.560199\n8hTs\t0.560199\n4cQs\t0.554764\n4cQd\t0.554764\n7hKd\t0.553292\n7hKs\t0.553292\nThJs\t0.551742\nThJd\t0.551742\n8hJc\t0.551416\n2sAd\t0.549286\n2dAs\t0.549286\n2sAs\t0.548264\n2dAd\t0.548264\n6cTd\t0.548224\n6cTs\t0.548224\n9hQs\t0.546688\n9hQd\t0.546688\n6dJc\t0.544357\n6sJc\t0.544357\n6sAd\t0.543642\n6dAs\t0.543642\n6dKh\t0.54048\n6sKh\t0.54048\n3sJs\t0.536983\n3dJd\t0.536983\n2hQh\t0.53586\n6s8d\t0.534367\n6d8s\t0.534367\n7hKc\t0.534244\n5c7s\t0.532697\n5c7d\t0.532697\n6dTc\t0.531807\n6sTc\t0.531807\n7hTd\t0.530769\n7hTs\t0.530769\n2hJs\t0.530126\n2hJd\t0.530126\n7h8c\t0.527387\n3s9s\t0.526384\n3d9d\t0.526384\n7h9d\t0.523639\n7h9s\t0.523639\n7dKc\t0.523582\n7sKc\t0.523582\n2s6s\t0.522768\n2d6d\t0.522768\n3d4c\t0.522302\n3s4c\t0.522302\n3sAd\t0.521458\n3dAs\t0.521458\n6hJc\t0.521321\n6cKh\t0.52101\n6c9d\t0.520397\n6c9s\t0.520397\n2dQh\t0.519635\n2sQh\t0.519635\n6s8c\t0.518079\n6d8c\t0.518079\n5d9s\t0.515053\n5s9d\t0.515053\n6s9c\t0.513525\n6d9c\t0.513525\n6dAc\t0.513417\n6sAc\t0.513417\n5c9s\t0.508228\n5c9d\t0.508228\n7hTc\t0.507323\n5d7c\t0.507054\n5s7c\t0.507054\n3sKc\t0.503217\n3dKc\t0.503217\n5s9c\t0.502875\n5d9c\t0.502875\n4sQd\t0.500368\n4dQs\t0.500368\n8h9c\t0.498788\n9hQc\t0.497507\n3dQd\t0.49209\n3sQs\t0.49209\n2h6h\t0.49199\n7h9c\t0.491731\n3dKs\t0.490327\n3sKd\t0.490327\n2d9c\t0.488018\n2s9c\t0.488018\n6c8s\t0.487537\n6c8d\t0.487537\nThQc\t0.486874\n6cAs\t0.484979\n6cAd\t0.484979\n8hQc\t0.483452\n5s6c\t0.482801\n5d6c\t0.482801\n8hKd\t0.482753\n8hKs\t0.482753\nThQs\t0.478548\nThQd\t0.478548\n2cAd\t0.471578\n2cAs\t0.471578\n2c6c\t0.470016\nTcQh\t0.469512\n7cQd\t0.465349\n7cQs\t0.465349\n4sQc\t0.463569\n4dQc\t0.463569\n4cKs\t0.460243\n4cKd\t0.460243\n5s6d\t0.45998\n5d6s\t0.45998\n4sTs\t0.459872\n4dTd\t0.459872\n7dQc\t0.459599\n7sQc\t0.459599\n7h8s\t0.457556\n7h8d\t0.457556\n4d5c\t0.453388\n4s5c\t0.453388\n2hJc\t0.452567\n5c6s\t0.451708\n5c6d\t0.451708\n6hTd\t0.451543\n6hTs\t0.451543\n6s7d\t0.446832\n6d7s\t0.446832\n2h7h\t0.446739\n6s7h\t0.445689\n6d7h\t0.445689\n6c7h\t0.444657\n2cAc\t0.443942\n2hJh\t0.443548\n2d7d\t0.443153\n2s7s\t0.443153\nTsQh\t0.443119\nTdQh\t0.443119\n2cQh\t0.442182\n3dTd\t0.441837\n3sTs\t0.441837\n6h8c\t0.441356\n9hKd\t0.440807\n9hKs\t0.440807\n4sKc\t0.440131\n4dKc\t0.440131\n6hTc\t0.438427\n8c9h\t0.437888\n2sKh\t0.437283\n2dKh\t0.437283\n8hKc\t0.437028\n6c7s\t0.436142\n6c7d\t0.436142\nTdKc\t0.435839\nTsKc\t0.435839\n8cJh\t0.434557\nJhQs\t0.433714\nJhQd\t0.433714\n3sAc\t0.432159\n3dAc\t0.432159\n6s7c\t0.432005\n6d7c\t0.432005\nJcQh\t0.427511\n4c5s\t0.427249\n4c5d\t0.427249\nTcKd\t0.426329\nTcKs\t0.426329\n8cQh\t0.4259\nJhQc\t0.425862\n8dJh\t0.425836\n8sJh\t0.425836\n9cQh\t0.42563\n9dQh\t0.425267\n9sQh\t0.425267\n6h7d\t0.42203\n6h7s\t0.42203\n3dKd\t0.42179\n3sKs\t0.42179\nTdKs\t0.421001\nTsKd\t0.421001\n2c7c\t0.420599\n2sJs\t0.417717\n2dJd\t0.417717\n6h8d\t0.417381\n6h8s\t0.417381\n2sJh\t0.416781\n2dJh\t0.416781\n5c8s\t0.414821\n5c8d\t0.414821\n2sTh\t0.410692\n2dTh\t0.410692\n6sJh\t0.409772\n6dJh\t0.409772\n2hTc\t0.40791\n2hTd\t0.407358\n2hTs\t0.407358\n4dKs\t0.405428\n4sKd\t0.405428\n9hJd\t0.405137\n9hJs\t0.405137\n6h7c\t0.404542\nJdQh\t0.404515\nJsQh\t0.404515\n6h9c\t0.403489\n5s8d\t0.401791\n5d8s\t0.401791\n4d5s\t0.400943\n4s5d\t0.400943\n2c8c\t0.399809\n3sKh\t0.39807\n3dKh\t0.39807\n6dTh\t0.397227\n6sTh\t0.397227\n6d8h\t0.396358\n6s8h\t0.396358\n6cTh\t0.394384\n4c9h\t0.393598\n2cQc\t0.392485\n6c8h\t0.392341\n5d8c\t0.388593\n5s8c\t0.388593\n9dJh\t0.387233\n9sJh\t0.387233\n6cQh\t0.387233\n6sQh\t0.386894\n6dQh\t0.386894\n8cKh\t0.384867\n8hAs\t0.383148\n8hAd\t0.383148\n5cTc\t0.381417\n2cKc\t0.37809\n9hKc\t0.376966\n8hAc\t0.375766\n9hJc\t0.372838\n6cJh\t0.372686\n3sAs\t0.372198\n3dAd\t0.372198\n7dKh\t0.371631\n7sKh\t0.371631\n6h9s\t0.369473\n6h9d\t0.369473\n8dQh\t0.369035\n8sQh\t0.369035\n2s9s\t0.368913\n2d9d\t0.368913\n2h9c\t0.364873\n7dTh\t0.362978\n7sTh\t0.362978\n7cTh\t0.362317\n5dTs\t0.361281\n5sTd\t0.361281\n7hQs\t0.358753\n7hQd\t0.358753\n7dQh\t0.354952\n7sQh\t0.354952\n6s9h\t0.352637\n6d9h\t0.352637\n2hTh\t0.351357\n6hJh\t0.348217\n2c5c\t0.347294\n7cKh\t0.347005\n6cJc\t0.345294\n8sKh\t0.34523\n8dKh\t0.34523\n2dAh\t0.343125\n2sAh\t0.343125\n4s9h\t0.342893\n4d9h\t0.342893\n5d9h\t0.342683\n5s9h\t0.342683\n8cAs\t0.342452\n8cAd\t0.342452\n5sKh\t0.341696\n5dKh\t0.341696\n8sAd\t0.34136\n8dAs\t0.34136\n6dJd\t0.338814\n6sJs\t0.338814\n8sTh\t0.337533\n8dTh\t0.337533\n9dKh\t0.328731\n9sKh\t0.328731\n2cKh\t0.328257\n7c8h\t0.327815\n4dJd\t0.326977\n4sJs\t0.326977\n9cKh\t0.325952\n6dQd\t0.324619\n6sQs\t0.324619\n5dTh\t0.324302\n5sTh\t0.324302\n7cQh\t0.32257\n5sJh\t0.322057\n5dJh\t0.322057\n6c9h\t0.32193\n2cTc\t0.320232\n4c9c\t0.319251\n5sJd\t0.318142\n5dJs\t0.318142\n8sAc\t0.317203\n8dAc\t0.317203\n2d5d\t0.315707\n2s5s\t0.315707\n2dTd\t0.313139\n2sTs\t0.313139\n2cJh\t0.311784\n7d8h\t0.311479\n7s8h\t0.311479\nJcKs\t0.305074\nJcKd\t0.305074\n7hJd\t0.304085\n7hJs\t0.304085\n4cTc\t0.303031\nJsKc\t0.302803\nJdKc\t0.302803\n2hAd\t0.301026\n2hAs\t0.301026\n9cJh\t0.300179\nJdKs\t0.298841\nJsKd\t0.298841\n7hQc\t0.29871\n5cKh\t0.298153\n5c9h\t0.297453\n7hJc\t0.294925\n2hAc\t0.294798\n5cQc\t0.293607\n2cAh\t0.293424\n5cJh\t0.291386\n5cTs\t0.290873\n5cTd\t0.290873\n8sAh\t0.290692\n8dAh\t0.290692\n5sTs\t0.290161\n5dTd\t0.290161\n8hTc\t0.289911\n4cTh\t0.288751\n7sAh\t0.287937\n7dAh\t0.287937\n2cJc\t0.287415\n6sAh\t0.285472\n6dAh\t0.285472\n7sJs\t0.280879\n7dJd\t0.280879\n4c6h\t0.280003\n5cTh\t0.278633\n2h8h\t0.277092\n5cJc\t0.273145\n3s5d\t0.27137\n3d5s\t0.27137\n4c7c\t0.267779\nThKd\t0.267531\nThKs\t0.267531\n2c9c\t0.265985\nTsKh\t0.258355\nTdKh\t0.258355\n4cJh\t0.257402\n7cJh\t0.255882\nJdKh\t0.253222\nJsKh\t0.253222\n7c9h\t0.253169\n4dTh\t0.248875\n4sTh\t0.248875\n5sQd\t0.245573\n5dQs\t0.245573\nThKc\t0.243941\n6hQh\t0.243418\n8cTh\t0.243291\nJhKs\t0.243266\nJhKd\t0.243266\n7sJh\t0.242945\n7dJh\t0.242945\n5sQh\t0.242396\n5dQh\t0.242396\n2h9s\t0.240665\n2h9d\t0.240665\n8cAh\t0.240528\n3sAh\t0.238657\n3dAh\t0.238657\n5cQh\t0.238394\n6cAh\t0.235067\n2s9h\t0.234634\n2d9h\t0.234634\n3d5c\t0.234141\n3s5c\t0.234141\n4dJh\t0.232266\n4sJh\t0.232266\n2cTh\t0.231091\nJcKh\t0.222938\n4dQd\t0.222756\n4sQs\t0.222756\nTcKh\t0.221203\n4cAh\t0.220981\nJhKc\t0.2196\n4d6s\t0.217583\n4s6d\t0.217583\n7d9h\t0.216261\n7s9h\t0.216261\n7sQs\t0.211534\n7dQd\t0.211534\n5c9c\t0.211309\n4s6h\t0.211274\n4d6h\t0.211274\n7hAs\t0.207778\n7hAd\t0.207778\n8sJs\t0.207646\n8dJd\t0.207646\n5sTc\t0.207326\n5dTc\t0.207326\n5d9d\t0.204859\n5s9s\t0.204859\n2h9h\t0.200715\n9sAd\t0.1993\n9dAs\t0.1993\n4sAh\t0.198887\n4dAh\t0.198887\n9sAc\t0.196012\n9dAc\t0.196012\n9cAs\t0.193003\n9cAd\t0.193003\n4c6s\t0.186541\n4c6d\t0.186541\n3s4s\t0.1856\n3d4d\t0.1856\nQdKh\t0.180514\nQsKh\t0.180514\n4dKd\t0.178358\n4sKs\t0.178358\n7dTd\t0.175097\n7sTs\t0.175097\n4d6c\t0.174517\n4s6c\t0.174517\n7hAc\t0.174269\n3d6s\t0.173655\n3s6d\t0.173655\n5sKd\t0.171159\n5dKs\t0.171159\n6cQc\t0.16864\n7s9s\t0.166302\n7d9d\t0.166302\n9hAs\t0.16608\n9hAd\t0.16608\n4cJc\t0.165406\n5s8h\t0.16028\n5d8h\t0.16028\nQhKs\t0.158384\nQhKd\t0.158384\n5cJs\t0.156567\n5cJd\t0.156567\n3d6d\t0.156108\n3s6s\t0.156108\n7hQh\t0.155928\n5d8d\t0.153019\n5s8s\t0.153019\n8sTs\t0.151698\n8dTd\t0.151698\nQcKh\t0.151696\n9sAh\t0.148784\n9dAh\t0.148784\n5c8c\t0.148504\nQhKc\t0.146484\n9cAh\t0.14552\n6cTc\t0.144473\n5cKd\t0.140991\n5cKs\t0.140991\n7cQc\t0.139987\n6hAd\t0.136209\n6hAs\t0.136209\n2c9h\t0.135915\n4sAd\t0.133077\n4dAs\t0.133077\n3s6c\t0.132641\n3d6c\t0.132641\n6sTs\t0.131875\n6dTd\t0.131875\n7cAh\t0.130279\n9hAc\t0.128203\n4cQh\t0.126641\n6hTh\t0.125276\n4c8c\t0.122816\n6hAc\t0.122632\n5sJs\t0.121467\n5dJd\t0.121467\n4d7s\t0.120499\n4s7d\t0.120499\n5cKc\t0.118993\n2s2d\t0.11767\n5dJc\t0.113259\n5sJc\t0.113259\n8cTc\t0.111347\n3s3d\t0.108814\n4cKc\t0.108105\n5c8h\t0.106791\n4dAc\t0.10386\n4sAc\t0.10386\n4cAd\t0.100997\n4cAs\t0.100997\n4cQc\t0.100893\n5dKc\t0.099362\n5sKc\t0.099362\nQcKs\t0.098493\nQcKd\t0.098493\n8cJc\t0.095884\n7h9h\t0.09021\n7hJh\t0.088104\n6c9c\t0.086437\n7hTh\t0.082578\n4dQh\t0.082093\n4sQh\t0.082093\n6d9d\t0.079497\n6s9s\t0.079497\n8d9d\t0.077446\n8s9s\t0.077446\n6h8h\t0.076819\nQsKc\t0.076346\nQdKc\t0.076346\n5s7s\t0.073504\n5d7d\t0.073504\n3d5d\t0.07308\n3s5s\t0.07308\n8hJh\t0.071782\n5dQd\t0.071706\n5sQs\t0.071706\n8hQh\t0.070912\n8sQs\t0.070912\n8dQd\t0.070912\n2s2c\t0.070304\n2d2c\t0.070304\n3s7s\t0.068599\n3d7d\t0.068599\n5c7c\t0.067969\n3s6h\t0.067076\n3d6h\t0.067076\nTsAd\t0.064721\nTdAs\t0.064721\n4c6c\t0.06436\n7h8h\t0.062422\n8hTh\t0.058682\n5cQd\t0.058434\n5cQs\t0.058434\nTsAc\t0.056709\nTdAc\t0.056709\n7d8d\t0.056371\n7s8s\t0.056371\nTcAs\t0.055202\nTcAd\t0.055202\n5dQc\t0.054235\n5sQc\t0.054235\n2c4c\t0.052469\nQdKs\t0.052078\nQsKd\t0.052078\n6h9h\t0.04885\n6s8s\t0.048505\n6d8d\t0.048505\n2h5s\t0.044106\n2h5d\t0.044106\n6c8c\t0.043889\nTcAh\t0.040533\nTdAh\t0.039736\nTsAh\t0.039736\n7cJc\t0.039016\n9dJd\t0.038739\n9sJs\t0.038739\n9cJc\t0.038739\n2h5c\t0.038258\n2d4d\t0.037231\n2s4s\t0.037231\n9sTs\t0.033651\n9dTd\t0.033651\n4d7d\t0.031961\n4s7s\t0.031961\nThAs\t0.028638\nThAd\t0.028638\n2s5d\t0.026995\n2d5s\t0.026995\n9hJh\t0.02648\n2s3s\t0.026405\n2d3d\t0.026405\n2s2h\t0.026087\n2h2d\t0.026087\n5dKd\t0.025867\n5sKs\t0.025867\n4sKh\t0.024913\n4dKh\t0.024913\n8c9c\t0.022968\n4c7d\t0.022859\n4c7s\t0.022859\n4d6d\t0.021855\n4s6s\t0.021855\n4c7h\t0.021521\n9hTh\t0.021319\n9cTc\t0.017396\nThAc\t0.016293\n3s7d\t0.015654\n3d7s\t0.015654\n2h2c\t0.015472\n4d7h\t0.014897\n4s7h\t0.014897\n2d5c\t0.014503\n2s5c\t0.014503\nJsAd\t0.010391\nJdAs\t0.010391\n4cKh\t0.010012\n7cTc\t0.008745\nJcAs\t0.00834\nJcAd\t0.00834\nJdAc\t0.008115\nJsAc\t0.008115\n6h7h\t0.006856\n6s7s\t0.005127\n6d7d\t0.005127\n6c7c\t0.004914\n6dKd\t0.003541\n6hKh\t0.003541\n6sKs\t0.003541\nJhAd\t0.002695\nJhAs\t0.002695\nJhAc\t0.002533\nJdAh\t0.001386\nJsAh\t0.001386\n"
  },
  {
    "path": "Source/Lookahead/Tests/test_flop_nl.lua",
    "content": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nlocal card_tools = require 'Game.card_tools'\n\nrequire 'TerminalEquity.terminal_equity'\nrequire 'Lookahead.lookahead'\nrequire 'Lookahead.resolving'\n\nlocal current_node = {}\n\ncurrent_node.board = card_to_string:string_to_board('3cAdKc')\ncurrent_node.street = 2\ncurrent_node.current_player = constants.players.P2\ncurrent_node.bets = arguments.Tensor{600, 600}\ncurrent_node.num_bets = 0\n\nlocal te = TerminalEquity()\nte:set_board(current_node.board)\n\nlocal player_range = card_tools:get_file_range('Lookahead/Tests/ranges/flop-situation3-p2.txt')\nlocal opponent_range = card_tools:get_file_range('Lookahead/Tests/ranges/flop-situation3-p1.txt')\n\nlocal player_range_tensor = arguments.Tensor(1,player_range:size(1))\nlocal opponent_range_tensor = arguments.Tensor(1,opponent_range:size(1))\n\nplayer_range_tensor[1]:copy(player_range)\nopponent_range_tensor[1]:copy(opponent_range)\n\n\n--player_range_tensor[1]:copy(card_tools:get_uniform_range(current_node.board))\n--opponent_range_tensor[1]:copy(card_tools:get_uniform_range(current_node.board))\n\nlocal resolving = Resolving(te)\n\nlocal results = resolving:resolve_first_node(current_node, player_range_tensor, opponent_range_tensor)\n\n\nfor card1 = 1,game_settings.card_count do\n  for card2 = card1+1,game_settings.card_count do\n    local idx = card_tools:get_hole_index({card1,card2})\n\n    print(idx .. \": \" .. card_to_string:card_to_string(card1) .. card_to_string:card_to_string(card2))\n    print(\"  \" .. results.strategy[1][1][idx] .. \" \" .. results.strategy[2][1][idx] .. \" \" ..\n      results.strategy[3][1][idx] .. \" \" .. results.strategy[4][1][idx] .. \" \" .. results.strategy[5][1][idx] .. \" \" ..\n      results.root_cfvs_both_players[1][1][idx])\n  end\nend\n\n--print(results.strategy)\n--print(results.achieved_cfvs)\n\n--[[\nlocal resolving = Resolving(terminal_equity)\n\nprint(results.strategy)\nprint(results.achieved_cfvs)\n\nprint(results.root_cfvs)\n]]\n\n--resolving:resolve(current_node, player_range, opponent_range)\n\n--[[\nlocal lookahead = Lookahead()\n\nlocal current_node = {}\ncurrent_node.board = card_to_string:string_to_board('Ks')\ncurrent_node.street = 2\ncurrent_node.current_player = constants.players.P1\ncurrent_node.bets = arguments.Tensor{100, 100}\n\n\nlookahead:build_lookahead(current_node)\n]]\n\n--[[\nlocal starting_ranges = arguments.Tensor(constants.players_count, constants.card_count)\nstarting_ranges[1]:copy(card_tools:get_random_range(current_node.board, 2))\nstarting_ranges[2]:copy(card_tools:get_random_range(current_node.board, 4))\n\nlookahead:resolve_first_node(starting_ranges)\n\nlookahead:get_strategy()\n]]\n\n--[[\nlocal player_range = card_tools:get_random_range(current_node.board, 2)\nlocal opponent_cfvs = card_tools:get_random_range(current_node.board, 4)\n\nlookahead:resolve(player_range, opponent_cfvs)\n\n\nlookahead:get_results()\n]]\n"
  },
  {
    "path": "Source/Lookahead/Tests/test_preflop_nl.lua",
    "content": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nlocal card_tools = require 'Game.card_tools'\n\nrequire 'TerminalEquity.terminal_equity'\nrequire 'Lookahead.lookahead'\nrequire 'Lookahead.resolving'\n\nlocal current_node = {}\n\ncurrent_node.board = card_to_string:string_to_board('')\ncurrent_node.street = 1\ncurrent_node.current_player = constants.players.P1\ncurrent_node.bets = arguments.Tensor{50, 100}\ncurrent_node.num_bets = 1\n\nlocal te = TerminalEquity()\nte:set_board(current_node.board)\n\nlocal player_range_tensor = arguments.Tensor(1,game_settings.hand_count)\nlocal opponent_range_tensor = arguments.Tensor(1,game_settings.hand_count)\n\nplayer_range_tensor[1]:copy(card_tools:get_uniform_range(current_node.board))\nopponent_range_tensor[1]:copy(card_tools:get_uniform_range(current_node.board))\n\nlocal resolving = Resolving(te)\n\nlocal results = resolving:resolve_first_node(current_node, player_range_tensor, opponent_range_tensor)\n\n\nfor card1 = 1,game_settings.card_count do\n  for card2 = card1+1,game_settings.card_count do\n    local idx = card_tools:get_hole_index({card1,card2})\n\n    print(idx .. \": \" .. card_to_string:card_to_string(card1) .. card_to_string:card_to_string(card2))\n    print(\"  \" .. results.strategy[1][1][idx] .. \" \" .. results.strategy[2][1][idx] .. \" \" ..\n      results.strategy[3][1][idx] .. \" \" .. results.strategy[4][1][idx] .. \" \" ..\n      results.root_cfvs_both_players[1][1][idx])\n  end\nend\n\n--print(results.strategy)\n--print(results.achieved_cfvs)\n\n--[[\nlocal resolving = Resolving(terminal_equity)\n\nprint(results.strategy)\nprint(results.achieved_cfvs)\n\nprint(results.root_cfvs)\n]]\n\n--resolving:resolve(current_node, player_range, opponent_range)\n\n--[[\nlocal lookahead = Lookahead()\n\nlocal current_node = {}\ncurrent_node.board = card_to_string:string_to_board('Ks')\ncurrent_node.street = 2\ncurrent_node.current_player = constants.players.P1\ncurrent_node.bets = arguments.Tensor{100, 100}\n\n\nlookahead:build_lookahead(current_node)\n]]\n\n--[[\nlocal starting_ranges = arguments.Tensor(constants.players_count, constants.card_count)\nstarting_ranges[1]:copy(card_tools:get_random_range(current_node.board, 2))\nstarting_ranges[2]:copy(card_tools:get_random_range(current_node.board, 4))\n\nlookahead:resolve_first_node(starting_ranges)\n\nlookahead:get_strategy()\n]]\n\n--[[\nlocal player_range = card_tools:get_random_range(current_node.board, 2)\nlocal opponent_cfvs = card_tools:get_random_range(current_node.board, 4)\n\nlookahead:resolve(player_range, opponent_cfvs)\n\n\nlookahead:get_results()\n]]\n"
  },
  {
    "path": "Source/Lookahead/Tests/test_river_nl.lua",
    "content": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nlocal card_tools = require 'Game.card_tools'\nlocal bucketer = require 'Nn.bucketer'\n\nrequire 'TerminalEquity.terminal_equity'\nrequire 'Lookahead.lookahead'\nrequire 'Lookahead.resolving'\nrequire 'Nn.value_nn'\nrequire 'Nn.next_round_value'\n\nlocal current_node = {}\n\ncurrent_node.board = card_to_string:string_to_board('7d7c8s5sQd')\ncurrent_node.street = 4\ncurrent_node.current_player = constants.players.P2\ncurrent_node.bets = arguments.Tensor{8000, 8000}\ncurrent_node.num_bets = 0\n\nlocal te = TerminalEquity()\nte:set_board(current_node.board)\n\nlocal resolving = Resolving(te)\n\nlocal player_range = card_tools:get_file_range('Lookahead/Tests/ranges/situation-p2.txt')\nlocal opponent_range = card_tools:get_file_range('Lookahead/Tests/ranges/situation-p1.txt')\n\n\nlocal player_range_tensor = arguments.Tensor(1,player_range:size(1))\nlocal opponent_range_tensor = arguments.Tensor(1,opponent_range:size(1))\n\nplayer_range_tensor[1]:copy(player_range)\nopponent_range_tensor[1]:copy(opponent_range)\n--player_range_tensor[1]:copy(card_tools:get_uniform_range(current_node.board))\n--opponent_range_tensor[1]:copy(card_tools:get_uniform_range(current_node.board))\n\nlocal results = resolving:resolve_first_node(current_node, player_range_tensor, opponent_range_tensor)\n\nfor card1 = 1,game_settings.card_count do\n  for card2 = card1+1,game_settings.card_count do\n    local idx = card_tools:get_hole_index({card1,card2})\n    if player_range_tensor[1][idx] > 0 then\n      print(card_to_string:card_to_string(card1) .. card_to_string:card_to_string(card2)\n            .. \": \" .. results.root_cfvs_both_players[1][1][idx])\n    end\n  end\nend\nio.read()\nfor card1 = 1,game_settings.card_count do\n  for card2 = card1+1,game_settings.card_count do\n    local idx = card_tools:get_hole_index({card1,card2})\n    if opponent_range_tensor[1][idx] > 0 then\n      print(card_to_string:card_to_string(card1) .. card_to_string:card_to_string(card2))\n      print(results.strategy[{{},1,idx}])\n    end\n  end\nend\n\n--print(results.strategy)\n--print(results.achieved_cfvs)\n\n--[[\nlocal resolving = Resolving(terminal_equity)\n\nprint(results.strategy)\nprint(results.achieved_cfvs)\n\n]]\n\n--resolving:resolve(current_node, player_range, opponent_range)\n\n--[[\nlocal lookahead = Lookahead()\n\nlocal current_node = {}\ncurrent_node.board = card_to_string:string_to_board('Ks')\ncurrent_node.street = 2\ncurrent_node.current_player = constants.players.P1\ncurrent_node.bets = arguments.Tensor{100, 100}\n\n\nlookahead:build_lookahead(current_node)\n]]\n\n--[[\nlocal starting_ranges = arguments.Tensor(constants.players_count, constants.card_count)\nstarting_ranges[1]:copy(card_tools:get_random_range(current_node.board, 2))\nstarting_ranges[2]:copy(card_tools:get_random_range(current_node.board, 4))\n\nlookahead:resolve_first_node(starting_ranges)\n\nlookahead:get_strategy()\n]]\n\n--[[\nlocal player_range = card_tools:get_random_range(current_node.board, 2)\nlocal opponent_cfvs = card_tools:get_random_range(current_node.board, 4)\n\nlookahead:resolve(player_range, opponent_cfvs)\n\n\nlookahead:get_results()\n]]\n"
  },
  {
    "path": "Source/Lookahead/Tests/test_turn_nl.lua",
    "content": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nlocal card_tools = require 'Game.card_tools'\n\nrequire 'TerminalEquity.terminal_equity'\nrequire 'Lookahead.lookahead'\nrequire 'Lookahead.resolving'\n\nlocal current_node = {}\n\ncurrent_node.board = card_to_string:string_to_board('3c5h4h3h')\ncurrent_node.street = 3\ncurrent_node.current_player = constants.players.P2\ncurrent_node.bets = arguments.Tensor{600, 600}\ncurrent_node.num_bets = 0\n\nlocal te = TerminalEquity()\nte:set_board(current_node.board)\n\nlocal player_range = card_tools:get_file_range('Lookahead/Tests/ranges/situation3-p2.txt')\nlocal opponent_range = card_tools:get_file_range('Lookahead/Tests/ranges/situation3-p1.txt')\n\nlocal player_range_tensor = arguments.Tensor(1,player_range:size(1))\nlocal opponent_range_tensor = arguments.Tensor(1,opponent_range:size(1))\n\nplayer_range_tensor[1]:copy(player_range)\nopponent_range_tensor[1]:copy(opponent_range)\n\n\n--player_range_tensor[1]:copy(card_tools:get_uniform_range(current_node.board))\n--opponent_range_tensor[1]:copy(card_tools:get_uniform_range(current_node.board))\n\nlocal resolving = Resolving(te)\n\n\n\nlocal results = resolving:resolve_first_node(current_node, player_range_tensor, opponent_range_tensor)\n\n\nfor card1 = 1,game_settings.card_count do\n  for card2 = card1+1,game_settings.card_count do\n    local idx = card_tools:get_hole_index({card1,card2})\n    if player_range_tensor[1][idx] > 0 then\n      print(card_to_string:card_to_string(card1) .. card_to_string:card_to_string(card2))\n      print(\"  \" .. results.strategy[1][1][idx] .. \" \" .. results.strategy[2][1][idx] .. \" \" ..\n        results.strategy[3][1][idx] .. \" \" .. results.strategy[4][1][idx] .. \" \" .. results.strategy[4][1][idx])\n    end\n  end\nend\n\n--print(results.strategy)\n--print(results.achieved_cfvs)\n\n--[[\nlocal resolving = Resolving(terminal_equity)\n\nprint(results.strategy)\nprint(results.achieved_cfvs)\n\nprint(results.root_cfvs)\n]]\n\n--resolving:resolve(current_node, player_range, opponent_range)\n\n--[[\nlocal lookahead = Lookahead()\n\nlocal current_node = {}\ncurrent_node.board = card_to_string:string_to_board('Ks')\ncurrent_node.street = 2\ncurrent_node.current_player = constants.players.P1\ncurrent_node.bets = arguments.Tensor{100, 100}\n\n\nlookahead:build_lookahead(current_node)\n]]\n\n--[[\nlocal starting_ranges = arguments.Tensor(constants.players_count, constants.card_count)\nstarting_ranges[1]:copy(card_tools:get_random_range(current_node.board, 2))\nstarting_ranges[2]:copy(card_tools:get_random_range(current_node.board, 4))\n\nlookahead:resolve_first_node(starting_ranges)\n\nlookahead:get_strategy()\n]]\n\n--[[\nlocal player_range = card_tools:get_random_range(current_node.board, 2)\nlocal opponent_cfvs = card_tools:get_random_range(current_node.board, 4)\n\nlookahead:resolve(player_range, opponent_cfvs)\n\n\nlookahead:get_results()\n]]\n"
  },
  {
    "path": "Source/Lookahead/cfrd_gadget.lua",
    "content": "--- Uses the the CFR-D gadget to generate opponent ranges for re-solving.\n--\n-- See [Solving Imperfect Information Games Using Decomposition](http://poker.cs.ualberta.ca/publications/aaai2014-cfrd.pdf)\n-- @classmod cfrd_gadget\n\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal tools = require 'tools'\nlocal card_tools = require 'Game.card_tools'\n\nlocal CFRDGadget = torch.class('CFRDGadget')\n\n--- Constructor\n-- @param board board card\n-- @param player_range an initial range vector for the opponent\n-- @param opponent_cfvs the opponent counterfactual values vector used for re-solving\nfunction CFRDGadget:__init(board, player_range, opponent_cfvs)\n  assert(board)\n\n\n  self.input_opponent_range = player_range:clone()\n  self.input_opponent_value = opponent_cfvs:clone()\n\n  self.curent_opponent_values = arguments.Tensor(game_settings.hand_count)\n\n  self.regret_epsilon = 1.0/100000000\n\n  self.play_current_strategy = arguments.Tensor(game_settings.hand_count):fill(0)\n  self.terminate_current_strategy = arguments.Tensor(game_settings.hand_count):fill(1)\n\n  --holds achieved CFVs at each iteration so that we can compute regret\n  self.total_values = arguments.Tensor(game_settings.hand_count)\n\n  self.terminate_regrets = arguments.Tensor(game_settings.hand_count):fill(0)\n  self.play_regrets = arguments.Tensor(game_settings.hand_count):fill(0)\n\n  --init range mask for masking out impossible hands\n  self.range_mask = card_tools:get_possible_hand_indexes(board)\nend\n\n--- Uses one iteration of the gadget game to generate an opponent range for\n-- the current re-solving iteration.\n-- @param current_opponent_cfvs the vector of cfvs that the opponent receives\n-- with the current strategy in the re-solve game\n-- @param iteration the current iteration number of re-solving\n-- @return the opponent range vector for this iteration\nfunction CFRDGadget:compute_opponent_range(current_opponent_cfvs, iteration)\n\n  local play_values = current_opponent_cfvs\n  local terminate_values = self.input_opponent_value\n\n  --1.0 compute current regrets\n  torch.cmul(self.total_values, play_values, self.play_current_strategy)\n  self.total_values_p2 = self.total_values_p2 or self.total_values:clone():zero()\n  torch.cmul(self.total_values_p2, terminate_values, self.terminate_current_strategy)\n  self.total_values:add(self.total_values_p2)\n\n  self.play_current_regret = self.play_current_regret or play_values:clone():zero()\n  self.terminate_current_regret = self.terminate_current_regret or self.play_current_regret:clone():zero()\n\n  self.play_current_regret:copy(play_values)\n  self.play_current_regret:csub(self.total_values)\n\n  self.terminate_current_regret:copy(terminate_values)\n  self.terminate_current_regret:csub(self.total_values)\n\n  --1.1 cumulate regrets\n  self.play_regrets:add(self.play_current_regret)\n  self.terminate_regrets:add(self.terminate_current_regret)\n\n  --2.0 we use cfr+ in reconstruction\n  self.terminate_regrets:clamp(self.regret_epsilon, tools:max_number())\n  self.play_regrets:clamp(self.regret_epsilon, tools:max_number())\n\n  self.play_possitive_regrets = self.play_regrets\n  self.terminate_possitive_regrets = self.terminate_regrets\n\n  --3.0 regret matching\n  self.regret_sum = self.regret_sum or self.play_possitive_regrets:clone():zero()\n  self.regret_sum:copy(self.play_possitive_regrets)\n  self.regret_sum:add(self.terminate_possitive_regrets)\n\n  self.play_current_strategy:copy(self.play_possitive_regrets)\n  self.terminate_current_strategy:copy(self.terminate_possitive_regrets)\n\n  self.play_current_strategy:cdiv(self.regret_sum)\n  self.terminate_current_strategy:cdiv(self.regret_sum)\n\n  --4.0 for poker, the range size is larger than the allowed hands\n  --we need to make sure reconstruction does not choose a range\n  --that is not allowed\n  self.play_current_strategy:cmul(self.range_mask)\n  self.terminate_current_strategy:cmul(self.range_mask)\n\n  self.input_opponent_range = self.input_opponent_range or self.play_current_strategy:clone():zero()\n  self.input_opponent_range:copy(self.play_current_strategy)\n\n  return self.input_opponent_range\nend\n"
  },
  {
    "path": "Source/Lookahead/lookahead.lua",
    "content": "--- A depth-limited lookahead of the game tree used for re-solving.\n-- @classmod lookahead\n\nrequire 'Lookahead.lookahead_builder'\nrequire 'TerminalEquity.terminal_equity'\nrequire 'Lookahead.cfrd_gadget'\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal tools = require 'tools'\nlocal card_tools = require 'Game.card_tools'\nlocal card_to_string = require 'Game.card_to_string_conversion'\n\nlocal Lookahead = torch.class('Lookahead')\nlocal timings = {}\n--- Constructor\nfunction Lookahead:__init(terminal_equity, batch_size)\n  self.builder = LookaheadBuilder(self)\n  self.terminal_equity = terminal_equity\n  self.batch_size = batch_size\nend\n\n--- Constructs the lookahead from a game's public tree.\n--\n-- Must be called to initialize the lookahead.\n-- @param tree a public tree\nfunction Lookahead:build_lookahead(tree)\n  self.builder:build_from_tree(tree)\nend\n\nfunction Lookahead:reset()\n  self.builder:reset()\nend\n--- Re-solves the lookahead using input ranges.\n--\n-- Uses the input range for the opponent instead of a gadget range, so only\n-- appropriate for re-solving the root node of the game tree (where ranges\n-- are fixed).\n--\n-- @{build_lookahead} must be called first.\n--\n-- @param player_range a range vector for the re-solving player\n-- @param opponent_range a range vector for the opponent\nfunction Lookahead:resolve_first_node(player_range, opponent_range)\n  self.ranges_data[1][{{}, {}, {}, {}, 1, {}}]:copy(player_range)\n  self.ranges_data[1][{{}, {}, {}, {}, 2, {}}]:copy(opponent_range)\n  self:_compute()\nend\n\n--- Re-solves the lookahead using an input range for the player and\n-- the @{cfrd_gadget|CFRDGadget} to generate ranges for the opponent.\n--\n-- @{build_lookahead} must be called first.\n--\n-- @param player_range a range vector for the re-solving player\n-- @param opponent_cfvs a vector of cfvs achieved by the opponent\n-- before re-solving\nfunction Lookahead:resolve(player_range, opponent_cfvs)\n  assert(player_range)\n  assert(opponent_cfvs)\n\n  self.reconstruction_gadget = CFRDGadget(self.tree.board, player_range, opponent_cfvs)\n\n  self.ranges_data[1][{{}, {}, {}, {}, 1, {}}]:copy(player_range)\n  self.reconstruction_opponent_cfvs = opponent_cfvs\n  self:_compute()\nend\n\n--- Re-solves the lookahead.\n-- @local\nfunction Lookahead:_compute()\n  --1.0 main loop\n\n  for i=1,8 do\n    timings[i] = 0\n  end\n  for iter=1,arguments.cfr_iters do\n\n    local timer = torch.Timer()\n    timer:reset()\n    self:_set_opponent_starting_range(iter)\n    timings[1] = timings[1] + timer:time().real\n    timer:reset()\n    self:_compute_current_strategies()\n    timings[2] = timings[2] + timer:time().real\n    timer:reset()\n    self:_compute_ranges()\n    timings[3] = timings[3] + timer:time().real\n    timer:reset()\n    self:_compute_update_average_strategies(iter)\n    timings[4] = timings[4] + timer:time().real\n    timer:reset()\n    self:_compute_terminal_equities()\n    timings[5] = timings[5] + timer:time().real\n    timer:reset()\n    self:_compute_cfvs()\n    timings[6] = timings[6] + timer:time().real\n    timer:reset()\n    self:_compute_regrets()\n    timings[7] = timings[7] + timer:time().real\n    timer:reset()\n    self:_compute_cumulate_average_cfvs(iter)\n    timings[8] = timings[8] + timer:time().real\n    timer:reset()\n  end\n\n  for i=1,8 do\n    print(' ' .. i .. ': ' .. timings[i])\n  end\n  --2.0 at the end normalize average strategy\n  self:_compute_normalize_average_strategies()\n  --2.1 normalize root's CFVs\n  self:_compute_normalize_average_cfvs()\nend\n\n--- Uses regret matching to generate the players' current strategies.\n-- @local\nfunction Lookahead:_compute_current_strategies()\n  for d=2,self.depth do\n    self.positive_regrets_data[d]:copy(self.regrets_data[d])\n    self.positive_regrets_data[d]:clamp(self.regret_epsilon, tools:max_number())\n\n    --1.0 set regret of empty actions to 0\n    self.positive_regrets_data[d]:cmul(self.empty_action_mask[d])\n\n    --1.1  regret matching\n    --note that the regrets as well as the CFVs have switched player indexing\n    torch.sum(self.regrets_sum[d], self.positive_regrets_data[d], 1)\n    local player_current_strategy = self.current_strategy_data[d]\n    local player_regrets = self.positive_regrets_data[d]\n    local player_regrets_sum = self.regrets_sum[d]\n\n    player_current_strategy:cdiv(player_regrets, player_regrets_sum:expandAs(player_regrets))\n  end\nend\n\n--- Using the players' current strategies, computes their probabilities of\n-- reaching each state of the lookahead.\n-- @local\nfunction Lookahead:_compute_ranges()\n\n  for d=1,self.depth-1 do\n    local current_level_ranges = self.ranges_data[d]\n    local next_level_ranges = self.ranges_data[d+1]\n\n    local prev_layer_terminal_actions_count = self.terminal_actions_count[d-1]\n    local prev_layer_actions_count = self.actions_count[d-1]\n    local prev_layer_bets_count = self.bets_count[d-1]\n    local gp_layer_nonallin_bets_count = self.nonallinbets_count[d-2]\n    local gp_layer_terminal_actions_count = self.terminal_actions_count[d-2]\n\n\n    --copy the ranges of inner nodes and transpose\n    self.inner_nodes[d]:copy(current_level_ranges[{{prev_layer_terminal_actions_count+1, -1}, {1, gp_layer_nonallin_bets_count}, {}, {}, {}, {}}]:transpose(2,3))\n\n    local super_view = self.inner_nodes[d]\n    super_view = super_view:view(1, prev_layer_bets_count, -1, self.batch_size, constants.players_count, game_settings.hand_count)\n\n    super_view = super_view:expandAs(next_level_ranges)\n    local next_level_strategies = self.current_strategy_data[d+1]\n\n    next_level_ranges:copy(super_view)\n\n    --multiply the ranges of the acting player by his strategy\n    next_level_ranges[{{}, {}, {}, {}, self.acting_player[d], {}}]:cmul(next_level_strategies)\n  end\nend\n\n--- Updates the players' average strategies with their current strategies.\n-- @param iter the current iteration number of re-solving\n-- @local\nfunction Lookahead:_compute_update_average_strategies(iter)\n  if iter > arguments.cfr_skip_iters then\n    --no need to go through layers since we care for the average strategy only in the first node anyway\n    --note that if you wanted to average strategy on lower layers, you would need to weight the current strategy by the current reach probability\n    self.average_strategies_data[2]:add(self.current_strategy_data[2])\n  end\nend\n\n--- Using the players' reach probabilities, computes their counterfactual\n-- values at each lookahead state which is a terminal state of the game.\n-- @local\nfunction Lookahead:_compute_terminal_equities_terminal_equity()\n\n  -- copy in range data\n  for d=2,self.depth do\n    if d > 2 or self.first_call_terminal then\n      if self.tree.street ~= constants.streets_count then\n        self.ranges_data_call[{self.term_call_indices[d]}]:copy(self.ranges_data[d][2][-1])\n      else\n        self.ranges_data_call[{self.term_call_indices[d]}]:copy(self.ranges_data[d][2])\n      end\n    end\n    self.ranges_data_fold[{self.term_fold_indices[d]}]:copy(self.ranges_data[d][1])\n  end\n\n  self.terminal_equity:call_value(self.ranges_data_call:view(-1, game_settings.hand_count), self.cfvs_data_call:view(-1, game_settings.hand_count))\n  self.terminal_equity:fold_value(self.ranges_data_fold:view(-1, game_settings.hand_count), self.cfvs_data_fold:view(-1, game_settings.hand_count))\n\n  for d=2,self.depth do\n    if self.tree.street ~= constants.streets_count then\n      if game_settings.nl and (d>2 or self.first_call_terminal) then\n        self.cfvs_data[d][2][-1]:copy(self.cfvs_data_call[{self.term_call_indices[d]}])\n      end\n    else\n      if d>2 or self.first_call_terminal then\n        self.cfvs_data[d][2]:copy(self.cfvs_data_call[{self.term_call_indices[d]}])\n      end\n    end\n    self.cfvs_data[d][1]:copy(self.cfvs_data_fold[{self.term_fold_indices[d]}])\n\n    --correctly set the folded player by mutliplying by -1\n    local fold_mutliplier = (self.acting_player[d]*2 - 3)\n    self.cfvs_data[d][{1, {}, {}, {}, 1, {}}]:mul(fold_mutliplier)\n    self.cfvs_data[d][{1, {}, {}, {}, 2, {}}]:mul(-fold_mutliplier)\n  end\nend\n\n--- Using the players' reach probabilities, calls the neural net to compute the\n-- players' counterfactual values at the depth-limited states of the lookahead.\n-- @local\nfunction Lookahead:_compute_terminal_equities_next_street_box()\n\n  assert(self.tree.street ~= constants.streets_count)\n\n  if self.num_pot_sizes == 0 then\n    return\n  end\n\n  for d=2, self.depth do\n    if d > 2 or self.first_call_transition then\n\n      -- if there's only 1 parent, then it should've been an all in, so skip this next_street_box calculation\n      if self.ranges_data[d][2]:size(1) > 1 or (d == 2 and self.first_call_transition) or not game_settings.nl then\n        local parent_indices = {1, -2}\n        if d == 2 then\n          parent_indices = {1,1}\n        elseif not game_settings.nl then\n          parent_indices = {}\n        end\n        self.next_street_boxes_outputs[{self.indices[d], {}, {}, {}}]:copy(self.ranges_data[d][{2, parent_indices, {}, {}, {}, {}}])\n      end\n    end\n  end\n\n  if self.tree.current_player == 2 then\n    self.next_street_boxes_inputs:copy(self.next_street_boxes_outputs)\n  else\n    self.next_street_boxes_inputs[{{}, {}, 1, {}}]:copy(self.next_street_boxes_outputs[{{}, {}, 2, {}}])\n    self.next_street_boxes_inputs[{{}, {}, 2, {}}]:copy(self.next_street_boxes_outputs[{{}, {}, 1, {}}])\n  end\n\n  if self.tree.street == 1 then\n    self.next_street_boxes:get_value_aux(\n      self.next_street_boxes_inputs:view(-1, constants.players_count, game_settings.hand_count),\n      self.next_street_boxes_outputs:view(-1, constants.players_count, game_settings.hand_count),\n      self.next_board_idx)\n  else\n    self.next_street_boxes:get_value(\n      self.next_street_boxes_inputs:view(-1, constants.players_count, game_settings.hand_count),\n      self.next_street_boxes_outputs:view(-1, constants.players_count, game_settings.hand_count))\n  end\n\n  --now the neural net outputs for P1 and P2 respectively, so we need to swap the output values if necessary\n  if self.tree.current_player == 2 then\n    self.next_street_boxes_inputs:copy(self.next_street_boxes_outputs)\n\n    self.next_street_boxes_outputs[{{}, {}, 1, {}}]:copy(self.next_street_boxes_inputs[{{}, {}, 2, {}}])\n    self.next_street_boxes_outputs[{{}, {}, 2, {}}]:copy(self.next_street_boxes_inputs[{{}, {}, 1, {}}])\n  end\n\n  for d=2, self.depth do\n    if d > 2 or self.first_call_transition then\n      if self.ranges_data[d][2]:size(1) > 1 or (d == 2 and self.first_call_transition) or not game_settings.nl then\n        local parent_indices = {1, -2}\n        if d == 2 then\n          parent_indices = {1,1}\n        elseif not game_settings.nl then\n          parent_indices = {}\n        end\n        self.cfvs_data[d][{2, parent_indices, {}, {}, {}, {}}]:copy(self.next_street_boxes_outputs[{self.indices[d], {}, {}, {}}])\n      end\n    end\n  end\nend\n\n--- Gives the average counterfactual values for the opponent during re-solving\n-- after a chance event (the betting round changes and more cards are dealt).\n--\n-- Used during continual re-solving to track opponent cfvs. The lookahead must\n-- first be re-solved with @{resolve} or @{resolve_first_node}.\n--\n-- @param action_index the action taken by the re-solving player at the start\n-- of the lookahead\n-- @param board a tensor of board cards, updated by the chance event\n-- @return a vector of cfvs\nfunction Lookahead:get_chance_action_cfv(action, board)\n\n  local box_outputs = self.next_street_boxes_outputs:view(-1, constants.players_count, game_settings.hand_count)\n  local next_street_box = self.next_street_boxes\n  local batch_index = self.action_to_index[action]\n  assert(batch_index ~= nil)\n  local pot_mult = self.next_round_pot_sizes[batch_index]\n\n  if box_outputs == nil then\n    assert(false)\n  end\n  next_street_box:get_value_on_board(board, box_outputs)\n\n  local out = box_outputs[batch_index][self.tree.current_player]\n  out:mul(pot_mult)\n\n  return out\nend\n\n--- Using the players' reach probabilities, computes their counterfactual\n-- values at all terminal states of the lookahead.\n--\n-- These include terminal states of the game and depth-limited states.\n-- @local\nfunction Lookahead:_compute_terminal_equities()\n  if self.tree.street ~= constants.streets_count then\n    self:_compute_terminal_equities_next_street_box()\n  end\n\n  self:_compute_terminal_equities_terminal_equity()\n  --multiply by pot scale factor\n  for d=2,self.depth do\n    self.cfvs_data[d]:cmul(self.pot_size[d])\n  end\nend\n\n--- Using the players' reach probabilities and terminal counterfactual\n-- values, computes their cfvs at all states of the lookahead.\n-- @local\nfunction Lookahead:_compute_cfvs()\n  for d=self.depth,2,-1 do\n    local gp_layer_terminal_actions_count = self.terminal_actions_count[d-2]\n    local ggp_layer_nonallin_bets_count = self.nonallinbets_count[d-3]\n\n    self.cfvs_data[d][{{}, {}, {}, {}, {1}, {}}]:cmul(self.empty_action_mask[d])\n    self.cfvs_data[d][{{}, {}, {}, {}, {2}, {}}]:cmul(self.empty_action_mask[d])\n\n    self.placeholder_data[d]:copy(self.cfvs_data[d])\n\n    --player indexing is swapped for cfvs\n    self.placeholder_data[d][{{}, {}, {}, {}, self.acting_player[d], {}}]:cmul(self.current_strategy_data[d])\n\n    torch.sum(self.regrets_sum[d], self.placeholder_data[d], 1)\n\n    --use a swap placeholder to change {{1,2,3}, {4,5,6}} into {{1,2}, {3,4}, {5,6}}\n    local swap = self.swap_data[d-1]\n    swap:copy(self.regrets_sum[d])\n\n    self.cfvs_data[d-1][{{gp_layer_terminal_actions_count+1, -1}, {1, ggp_layer_nonallin_bets_count}, {}, {}, {}, {}}]:copy(swap:transpose(2,3))\n  end\n\nend\n\n--- Updates the players' average counterfactual values with their cfvs from the\n-- current iteration.\n-- @param iter the current iteration number of re-solving\n-- @local\nfunction Lookahead:_compute_cumulate_average_cfvs(iter)\n  if iter > arguments.cfr_skip_iters then\n    self.average_cfvs_data[1]:add(self.cfvs_data[1])\n\n    self.average_cfvs_data[2]:add(self.cfvs_data[2])\n  end\nend\n\n--- Normalizes the players' average strategies.\n--\n-- Used at the end of re-solving so that we can track un-normalized average\n-- strategies, which are simpler to compute.\n-- @local\nfunction Lookahead:_compute_normalize_average_strategies()\n\n  --using regrets_sum as a placeholder container\n  local player_avg_strategy = self.average_strategies_data[2]\n  local player_avg_strategy_sum = self.regrets_sum[2]\n\n\n  torch.sum(player_avg_strategy_sum, player_avg_strategy, 1)\n  player_avg_strategy:cdiv(player_avg_strategy_sum:expandAs(player_avg_strategy))\n\n  --if the strategy is 'empty' (zero reach), strategy does not matter but we need to make sure\n  --it sums to one -> now we set to always fold\n  player_avg_strategy[1][player_avg_strategy[1]:ne(player_avg_strategy[1])] = 1\n  player_avg_strategy[player_avg_strategy:ne(player_avg_strategy)] = 0\nend\n\n--- Normalizes the players' average counterfactual values.\n--\n-- Used at the end of re-solving so that we can track un-normalized average\n-- cfvs, which are simpler to compute.\n-- @local\nfunction Lookahead:_compute_normalize_average_cfvs()\n  self.average_cfvs_data[1]:div(arguments.cfr_iters - arguments.cfr_skip_iters)\nend\n\n--- Using the players' counterfactual values, updates their total regrets\n-- for every state in the lookahead.\n-- @local\nfunction Lookahead:_compute_regrets()\n  for d=self.depth,2,-1 do\n    local gp_layer_terminal_actions_count = self.terminal_actions_count[d-2]\n    local gp_layer_bets_count = self.bets_count[d-2]\n    local ggp_layer_nonallin_bets_count = self.nonallinbets_count[d-3]\n\n    local current_regrets = self.current_regrets_data[d]\n    current_regrets:copy(self.cfvs_data[d][{{}, {}, {}, {}, self.acting_player[d], {}}])\n\n    local next_level_cfvs = self.cfvs_data[d-1]\n\n    local parent_inner_nodes = self.inner_nodes_p1[d-1]\n    parent_inner_nodes:copy(next_level_cfvs[{{gp_layer_terminal_actions_count+1, -1}, {1, ggp_layer_nonallin_bets_count}, {}, {}, self.acting_player[d], {}}]:transpose(2,3))\n    parent_inner_nodes = parent_inner_nodes:view(1, gp_layer_bets_count, -1, self.batch_size, game_settings.hand_count)\n    parent_inner_nodes = parent_inner_nodes:expandAs(current_regrets)\n\n    current_regrets:csub(parent_inner_nodes)\n\n    self.regrets_data[d]:add(self.regrets_data[d], current_regrets)\n\n    --(CFR+)\n    self.regrets_data[d]:clamp(0,  tools:max_number())\n  end\nend\n\n\n--- Gets the results of re-solving the lookahead.\n--\n-- The lookahead must first be re-solved with @{resolve} or\n-- @{resolve_first_node}.\n--\n-- @return a table containing the fields:\n--\n-- * `strategy`: an AxK tensor containing the re-solve player's strategy at the\n-- root of the lookahead, where A is the number of actions and K is the range size\n--\n-- * `achieved_cfvs`: a vector of the opponent's average counterfactual values at the\n-- root of the lookahead\n--\n-- * `children_cfvs`: an AxK tensor of opponent average counterfactual values after\n-- each action that the re-solve player can take at the root of the lookahead\nfunction Lookahead:get_results()\n  local out = {}\n\n  local actions_count = self.average_strategies_data[2]:size(1)\n\n  --1.0 average strategy\n  --[actions x range]\n  --lookahead already computes the averate strategy we just convert the dimensions\n  out.strategy = self.average_strategies_data[2]:view(-1, self.batch_size, game_settings.hand_count):clone()\n\n  --2.0 achieved opponent's CFVs at the starting node\n  out.achieved_cfvs = self.average_cfvs_data[1]:view(self.batch_size, constants.players_count, game_settings.hand_count)[{{},1,{}}]:clone()\n\n  --3.0 CFVs for the acting player only when resolving first node\n  if self.reconstruction_opponent_cfvs then\n    out.root_cfvs = nil\n  else\n    out.root_cfvs = self.average_cfvs_data[1]:view(self.batch_size, constants.players_count, game_settings.hand_count)[{{},2,{}}]:clone()\n\n    --swap cfvs indexing\n    out.root_cfvs_both_players = self.average_cfvs_data[1]:view(self.batch_size, constants.players_count, game_settings.hand_count):clone()\n    out.root_cfvs_both_players[{{},2,{}}]:copy(self.average_cfvs_data[1]:view(self.batch_size, constants.players_count, game_settings.hand_count)[{{},1,{}}])\n    out.root_cfvs_both_players[{{},1,{}}]:copy(self.average_cfvs_data[1]:view(self.batch_size, constants.players_count, game_settings.hand_count)[{{},2,{}}])\n  end\n\n  --4.0 children CFVs\n  --[actions x range]\n  out.children_cfvs = self.average_cfvs_data[2][{{}, {}, {}, {}, 1, {}}]:clone():view(-1, game_settings.hand_count)\n\n  --IMPORTANT divide average CFVs by average strategy in here\n  local scaler = self.average_strategies_data[2]:view(-1, self.batch_size, game_settings.hand_count):clone()\n\n\n  local range_mul = self.ranges_data[1][{{}, {}, {}, {}, 1, {}}]:clone():view(1, self.batch_size, game_settings.hand_count):clone()\n  range_mul = range_mul:expandAs(scaler)\n\n  scaler = scaler:cmul(range_mul)\n  scaler = scaler:sum(3):expandAs(range_mul):clone()\n  scaler = scaler:mul(arguments.cfr_iters - arguments.cfr_skip_iters)\n\n  out.children_cfvs:cdiv(scaler)\n\n  assert(out.children_cfvs)\n  assert(out.strategy)\n  assert(out.achieved_cfvs)\n\n  return out\nend\n\n--- Generates the opponent's range for the current re-solve iteration using\n-- the @{cfrd_gadget|CFRDGadget}.\n-- @param iteration the current iteration number of re-solving\n-- @local\nfunction Lookahead:_set_opponent_starting_range(iteration)\n  if self.reconstruction_opponent_cfvs then\n    --note that CFVs indexing is swapped, thus the CFVs for the reconstruction player are for player '1'\n    local opponent_range = self.reconstruction_gadget:compute_opponent_range(self.cfvs_data[1][{{}, {}, {}, {}, 1, {}}], iteration)\n    self.ranges_data[1][{{}, {}, {}, {}, 2, {}}]:copy(opponent_range)\n  end\nend\n"
  },
  {
    "path": "Source/Lookahead/lookahead_builder.lua",
    "content": "--- Builds the internal data structures of a @{lookahead|Lookahead} object.\n-- @classmod lookahead_builder\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal tools = require 'tools'\nrequire 'Tree.tree_builder'\nrequire 'Tree.tree_visualiser'\nrequire 'Nn.next_round_value'\nrequire 'Nn.next_round_value_pre'\nrequire 'Nn.value_nn'\n\nlocal LookaheadBuilder = torch.class('LookaheadBuilder')\n\n--used to load NNs and next_round_value_pre only once\nlocal neural_net = {}\nlocal aux_net = nil\nlocal next_round_pre = nil\n\n--- Constructor\n-- @param lookahead the @{lookahead|Lookahead} to generate data structures for\nfunction LookaheadBuilder:__init(lookahead)\n  self.lookahead = lookahead\n  self.lookahead.ccall_action_index = 1\n  self.lookahead.fold_action_index = 2\nend\n\n--- Builds the neural net query boxes which estimate counterfactual values\n-- at depth-limited states of the lookahead.\n-- @local\nfunction LookaheadBuilder:_construct_transition_boxes()\n  if self.lookahead.tree.street == constants.streets_count then\n    return\n  end\n\n  --load neural nets if not already loaded\n  local nn = neural_net[self.lookahead.tree.street] or ValueNn(self.lookahead.tree.street)\n  neural_net[self.lookahead.tree.street] = nn\n  if self.lookahead.tree.street == 1 and game_settings.nl then\n    aux_net = aux_net or ValueNn(self.lookahead.tree.street, true)\n  end\n\n  self.lookahead.next_street_boxes = nil\n  self.lookahead.indices = {}\n  self.lookahead.num_pot_sizes = 0\n\n  if self.lookahead.tree.street == 1 then\n    self.lookahead.next_street_boxes = next_round_pre or NextRoundValuePre(nn, aux_net, self.lookahead.terminal_equity.board)\n    next_round_pre = self.lookahead.next_street_boxes\n  else\n    self.lookahead.next_street_boxes = NextRoundValue(nn, self.lookahead.terminal_equity.board)\n  end\n\n  --create the optimized data structures for batching next_round_value\n\n  for d = 2,self.lookahead.depth do\n    if d == 2 and self.lookahead.first_call_transition then\n      local before = self.lookahead.num_pot_sizes\n      self.lookahead.num_pot_sizes = self.lookahead.num_pot_sizes + 1\n      self.lookahead.indices[d] = {before + 1, self.lookahead.num_pot_sizes}\n    elseif not game_settings.nl and (d > 2 or self.lookahead.first_call_transition) then\n      local before = self.lookahead.num_pot_sizes\n      self.lookahead.num_pot_sizes = self.lookahead.num_pot_sizes + (self.lookahead.pot_size[d][2]:size(1)) * self.lookahead.pot_size[d][2]:size(2)\n      self.lookahead.indices[d] = {before + 1, self.lookahead.num_pot_sizes}\n    elseif self.lookahead.pot_size[d][2]:size(1) > 1 then\n      local before = self.lookahead.num_pot_sizes\n      self.lookahead.num_pot_sizes = self.lookahead.num_pot_sizes + (self.lookahead.pot_size[d][2]:size(1) - 1) * self.lookahead.pot_size[d][2]:size(2)\n      self.lookahead.indices[d] = {before + 1, self.lookahead.num_pot_sizes}\n    end\n  end\n\n  if self.lookahead.num_pot_sizes == 0 then\n    return\n  end\n\n  self.lookahead.next_round_pot_sizes = arguments.Tensor(self.lookahead.num_pot_sizes):zero()\n\n  self.lookahead.action_to_index = {}\n  for d = 2,self.lookahead.depth do\n    local parent_indices = {1, -2}\n    if self.lookahead.indices[d] ~= nil then\n      if d == 2 then\n        parent_indices = {1, 1}\n      elseif not game_settings.nl then\n        parent_indices = {}\n      end\n      self.lookahead.next_round_pot_sizes[{self.lookahead.indices[d]}]:copy(self.lookahead.pot_size[d][{2, parent_indices, {}, 1, 1, 1}])\n      if d <= 3 then\n        if d == 2 then\n          assert(self.lookahead.indices[d][1] == self.lookahead.indices[d][2])\n          self.lookahead.action_to_index[constants.actions.ccall] = self.lookahead.indices[d][1]\n        else\n          assert(self.lookahead.pot_size[d][{2, parent_indices}]:size(2) == 1, 'bad num_indices: ')\n          for parent_action_idx = 1, self.lookahead.pot_size[d][2]:size(1) do\n            local action_id = self.lookahead.parent_action_id[parent_action_idx]\n            assert(self.lookahead.action_to_index[action_id] == nil)\n            self.lookahead.action_to_index[action_id] = self.lookahead.indices[d][1] + parent_action_idx - 1\n          end\n        end\n      end\n    end\n  end\n  if self.lookahead.action_to_index[constants.actions.ccall] == nil then\n    print(self.lookahead.action_to_index)\n    print(self.lookahead.parent_action_id)\n    assert(false)\n  end\n  self.lookahead.next_street_boxes:start_computation(self.lookahead.next_round_pot_sizes, self.lookahead.batch_size)\n  self.lookahead.next_street_boxes_inputs = arguments.Tensor(self.lookahead.num_pot_sizes, self.lookahead.batch_size, constants.players_count, game_settings.hand_count):zero()\n  self.lookahead.next_street_boxes_outputs = self.lookahead.next_street_boxes_inputs:clone()\nend\n\n--- Computes the number of nodes at each depth of the tree.\n--\n-- Used to find the size for the tensors which store lookahead data.\n-- @local\nfunction LookaheadBuilder:_compute_structure()\n\n  assert(self.lookahead.tree.street >= 1 and self.lookahead.tree.street <= constants.streets_count)\n\n  self.lookahead.regret_epsilon = 1.0 / 1000000000\n\n  --which player acts at particular depth\n  self.lookahead.acting_player = torch.Tensor(self.lookahead.depth+1):fill(-1)\n  self.lookahead.acting_player[1] = 1 --in lookahead, 1 does not stand for player IDs, it's just the first player to act\n  for d=2,self.lookahead.depth+1 do\n    self.lookahead.acting_player[d] = 3 - self.lookahead.acting_player[d-1]\n  end\n\n\n  self.lookahead.bets_count[-1] = 1\n  self.lookahead.bets_count[0] = 1\n  self.lookahead.nonallinbets_count[-1] = 1\n  self.lookahead.nonallinbets_count[0] = 1\n  self.lookahead.terminal_actions_count[-1] = 0\n  self.lookahead.terminal_actions_count[0] = 0\n  self.lookahead.actions_count[-1] = 1\n  self.lookahead.actions_count[0] = 1\n\n  --compute the node counts\n  self.lookahead.nonterminal_nodes_count = {}\n  self.lookahead.nonterminal_nonallin_nodes_count = {}\n  self.lookahead.all_nodes_count = {}\n  self.lookahead.allin_nodes_count = {}\n  self.lookahead.inner_nodes_count = {}\n\n  self.lookahead.nonterminal_nodes_count[1] = 1\n  self.lookahead.nonterminal_nodes_count[2] = self.lookahead.bets_count[1]\n  self.lookahead.nonterminal_nonallin_nodes_count[0] = 1\n  self.lookahead.nonterminal_nonallin_nodes_count[1] = 1\n  self.lookahead.nonterminal_nonallin_nodes_count[2] = self.lookahead.nonterminal_nodes_count[2]\n  if game_settings.nl then\n    self.lookahead.nonterminal_nonallin_nodes_count[2] = self.lookahead.nonterminal_nonallin_nodes_count[2] - 1\n  end\n  self.lookahead.all_nodes_count[1] = 1\n  self.lookahead.all_nodes_count[2] = self.lookahead.actions_count[1]\n  self.lookahead.allin_nodes_count[1] = 0\n  self.lookahead.allin_nodes_count[2] = 1\n  self.lookahead.inner_nodes_count[1] = 1\n  self.lookahead.inner_nodes_count[2] = 1\n\n  for d=2,self.lookahead.depth do\n    self.lookahead.all_nodes_count[d+1] = self.lookahead.nonterminal_nonallin_nodes_count[d-1] * self.lookahead.bets_count[d-1] * self.lookahead.actions_count[d]\n    self.lookahead.allin_nodes_count[d+1] = self.lookahead.nonterminal_nonallin_nodes_count[d-1] * self.lookahead.bets_count[d-1] * 1\n\n    self.lookahead.nonterminal_nodes_count[d+1] = self.lookahead.nonterminal_nonallin_nodes_count[d-1] * self.lookahead.nonallinbets_count[d-1] * self.lookahead.bets_count[d]\n    self.lookahead.nonterminal_nonallin_nodes_count[d+1] = self.lookahead.nonterminal_nonallin_nodes_count[d-1] * self.lookahead.nonallinbets_count[d-1] * self.lookahead.nonallinbets_count[d]\n  end\nend\n\n--- Builds the tensors that store lookahead data during re-solving.\nfunction LookaheadBuilder:construct_data_structures()\n\n  self:_compute_structure()\n\n  --lookahead main data structures\n  --all the structures are per-layer tensors, that is, each layer holds the data in n-dimensional tensors\n  self.lookahead.pot_size = {}\n  self.lookahead.ranges_data = {}\n  self.lookahead.average_strategies_data = {}\n  self.lookahead.current_strategy_data = {}\n  self.lookahead.cfvs_data = {}\n  self.lookahead.average_cfvs_data = {}\n  self.lookahead.regrets_data = {}\n  self.lookahead.current_regrets_data = {}\n  self.lookahead.positive_regrets_data = {}\n  self.lookahead.placeholder_data = {}\n  self.lookahead.regrets_sum = {}\n  self.lookahead.empty_action_mask = {} --used to mask empty actions\n  --used to hold and swap inner (nonterminal) nodes when doing some transpose operations\n  self.lookahead.inner_nodes = {}\n  self.lookahead.inner_nodes_p1 = {}\n  self.lookahead.swap_data = {}\n\n\n  --create the data structure for the first two layers\n\n  --data structures [actions x parent_action x grandparent_id x batch x players x range]\n  self.lookahead.ranges_data[1] = arguments.Tensor(1, 1, 1, self.lookahead.batch_size, constants.players_count, game_settings.hand_count):fill(1.0 / game_settings.hand_count)\n  self.lookahead.ranges_data[2] = arguments.Tensor(self.lookahead.actions_count[1], 1, 1, self.lookahead.batch_size, constants.players_count, game_settings.hand_count):fill(1.0 / game_settings.hand_count)\n  self.lookahead.pot_size[1] = self.lookahead.ranges_data[1]:clone():fill(0)\n  self.lookahead.pot_size[2] = self.lookahead.ranges_data[2]:clone():fill(0)\n  self.lookahead.cfvs_data[1] = self.lookahead.ranges_data[1]:clone():fill(0)\n  self.lookahead.cfvs_data[2] = self.lookahead.ranges_data[2]:clone():fill(0)\n  self.lookahead.average_cfvs_data[1] = self.lookahead.ranges_data[1]:clone():fill(0)\n  self.lookahead.average_cfvs_data[2] = self.lookahead.ranges_data[2]:clone():fill(0)\n  self.lookahead.placeholder_data[1] = self.lookahead.ranges_data[1]:clone():fill(0)\n  self.lookahead.placeholder_data[2] = self.lookahead.ranges_data[2]:clone():fill(0)\n\n  --data structures for one player [actions x parent_action x grandparent_id x batch x 1 x range]\n  self.lookahead.average_strategies_data[1] = nil\n  self.lookahead.average_strategies_data[2] = arguments.Tensor(self.lookahead.actions_count[1], 1, 1, self.lookahead.batch_size, game_settings.hand_count):fill(0)\n  self.lookahead.current_strategy_data[1] = nil\n  self.lookahead.current_strategy_data[2] = self.lookahead.average_strategies_data[2]:clone():fill(0)\n  self.lookahead.regrets_data[1] = nil\n  self.lookahead.regrets_data[2] = self.lookahead.average_strategies_data[2]:clone():fill(0)\n  self.lookahead.current_regrets_data[1] = nil\n  self.lookahead.current_regrets_data[2] = self.lookahead.average_strategies_data[2]:clone():fill(0)\n  self.lookahead.positive_regrets_data[1] = nil\n  self.lookahead.positive_regrets_data[2] = self.lookahead.average_strategies_data[2]:clone():fill(0)\n  self.lookahead.empty_action_mask[1] = nil\n  self.lookahead.empty_action_mask[2] = self.lookahead.average_strategies_data[2]:clone():fill(1)\n\n  --data structures for summing over the actions [1 x parent_action x grandparent_id x batch x range]\n  self.lookahead.regrets_sum[1] = arguments.Tensor(1, 1, 1, self.lookahead.batch_size, game_settings.hand_count):fill(0)\n  self.lookahead.regrets_sum[2] = arguments.Tensor(1, self.lookahead.bets_count[1], 1, self.lookahead.batch_size, game_settings.hand_count):fill(0)\n\n  --data structures for inner nodes (not terminal nor allin) [bets_count x parent_nonallinbetscount x gp_id x batch x players x range]\n  self.lookahead.inner_nodes[1] = arguments.Tensor(1, 1, 1, self.lookahead.batch_size, constants.players_count, game_settings.hand_count):fill(0)\n  self.lookahead.swap_data[1] = self.lookahead.inner_nodes[1]:transpose(2,3):clone()\n  self.lookahead.inner_nodes_p1[1] = arguments.Tensor(1, 1, 1, self.lookahead.batch_size, 1, game_settings.hand_count):fill(0)\n\n  if self.lookahead.depth > 2 then\n    self.lookahead.inner_nodes[2] = arguments.Tensor(self.lookahead.bets_count[1], 1, 1, self.lookahead.batch_size, constants.players_count, game_settings.hand_count):fill(0)\n    self.lookahead.swap_data[2] = self.lookahead.inner_nodes[2]:transpose(2,3):clone()\n    self.lookahead.inner_nodes_p1[2] = arguments.Tensor(self.lookahead.bets_count[1], 1, 1, self.lookahead.batch_size, 1, game_settings.hand_count):fill(0)\n  end\n\n\n  --create the data structures for the rest of the layers\n  for d=3,self.lookahead.depth do\n\n    --data structures [actions x parent_action x grandparent_id x batch x players x range]\n    self.lookahead.ranges_data[d] = arguments.Tensor(self.lookahead.actions_count[d-1], self.lookahead.bets_count[d-2], self.lookahead.nonterminal_nonallin_nodes_count[d-2], self.lookahead.batch_size, constants.players_count, game_settings.hand_count):fill(0)\n    self.lookahead.cfvs_data[d] = self.lookahead.ranges_data[d]:clone()\n    self.lookahead.placeholder_data[d] = self.lookahead.ranges_data[d]:clone()\n    self.lookahead.pot_size[d] = self.lookahead.ranges_data[d]:clone():fill(arguments.stack)\n\n    --data structures [actions x parent_action x grandparent_id x batch x 1 x range]\n    self.lookahead.average_strategies_data[d] = arguments.Tensor(self.lookahead.actions_count[d-1], self.lookahead.bets_count[d-2], self.lookahead.nonterminal_nonallin_nodes_count[d-2], self.lookahead.batch_size, game_settings.hand_count):fill(0)\n    self.lookahead.current_strategy_data[d] = self.lookahead.average_strategies_data[d]:clone()\n    self.lookahead.regrets_data[d] = self.lookahead.average_strategies_data[d]:clone():fill(self.lookahead.regret_epsilon)\n    self.lookahead.current_regrets_data[d] = self.lookahead.average_strategies_data[d]:clone():fill(0)\n    self.lookahead.empty_action_mask[d] = self.lookahead.average_strategies_data[d]:clone():fill(1)\n    self.lookahead.positive_regrets_data[d] = self.lookahead.regrets_data[d]:clone()\n\n    --data structures [1 x parent_action x grandparent_id x batch x players x range]\n    self.lookahead.regrets_sum[d] = arguments.Tensor(1, self.lookahead.bets_count[d-2], self.lookahead.nonterminal_nonallin_nodes_count[d-2], self.lookahead.batch_size, constants.players_count, game_settings.hand_count):fill(0)\n\n    --data structures for the layers except the last one\n    if d < self.lookahead.depth then\n      self.lookahead.inner_nodes[d] = arguments.Tensor(self.lookahead.bets_count[d-1], self.lookahead.nonallinbets_count[d-2], self.lookahead.nonterminal_nonallin_nodes_count[d-2], self.lookahead.batch_size, constants.players_count, game_settings.hand_count):fill(0)\n      self.lookahead.inner_nodes_p1[d] = arguments.Tensor(self.lookahead.bets_count[d-1], self.lookahead.nonallinbets_count[d-2], self.lookahead.nonterminal_nonallin_nodes_count[d-2], self.lookahead.batch_size, 1, game_settings.hand_count):fill(0)\n\n      self.lookahead.swap_data[d] = self.lookahead.inner_nodes[d]:transpose(2, 3):clone()\n    end\n  end\n\n  --create the optimized data structures for terminal equity\n  self.lookahead.term_call_indices = {}\n  self.lookahead.num_term_call_nodes = 0\n  self.lookahead.term_fold_indices = {}\n  self.lookahead.num_term_fold_nodes = 0\n\n  -- calculate term_call_indices\n  for d = 2,self.lookahead.depth do\n    if self.lookahead.tree.street ~= constants.streets_count then\n      if game_settings.nl and (d>2 or self.lookahead.first_call_terminal) then\n        local before = self.lookahead.num_term_call_nodes\n        self.lookahead.num_term_call_nodes = self.lookahead.num_term_call_nodes + self.lookahead.ranges_data[d][2][-1]:size(1)\n        self.lookahead.term_call_indices[d] = {before + 1, self.lookahead.num_term_call_nodes}\n      end\n    else\n      if d>2 or self.lookahead.first_call_terminal then\n        local before = self.lookahead.num_term_call_nodes\n        self.lookahead.num_term_call_nodes = self.lookahead.num_term_call_nodes + self.lookahead.ranges_data[d][2]:size(1) * self.lookahead.ranges_data[d][2]:size(2)\n        self.lookahead.term_call_indices[d] = {before + 1, self.lookahead.num_term_call_nodes}\n      end\n    end\n  end\n\n  -- calculate term_fold_indices\n  for d = 2,self.lookahead.depth do\n    local before = self.lookahead.num_term_fold_nodes\n    self.lookahead.num_term_fold_nodes = self.lookahead.num_term_fold_nodes + self.lookahead.ranges_data[d][1]:size(1) * self.lookahead.ranges_data[d][1]:size(2)\n    self.lookahead.term_fold_indices[d] = {before + 1, self.lookahead.num_term_fold_nodes}\n  end\n\n  self.lookahead.ranges_data_call = arguments.Tensor(self.lookahead.num_term_call_nodes, self.lookahead.batch_size, constants.players_count, game_settings.hand_count)\n  self.lookahead.ranges_data_fold = arguments.Tensor(self.lookahead.num_term_fold_nodes, self.lookahead.batch_size, constants.players_count, game_settings.hand_count)\n\n  self.lookahead.cfvs_data_call = arguments.Tensor(self.lookahead.num_term_call_nodes, self.lookahead.batch_size, constants.players_count, game_settings.hand_count)\n  self.lookahead.cfvs_data_fold = arguments.Tensor(self.lookahead.num_term_fold_nodes, self.lookahead.batch_size, constants.players_count, game_settings.hand_count)\nend\n\nfunction LookaheadBuilder:reset()\n  for d = 1, self.lookahead.depth do\n    if self.lookahead.ranges_data[d] ~= nil then\n      self.lookahead.ranges_data[d]:fill(1.0 / game_settings.hand_count)\n    end\n    if self.lookahead.average_strategies_data[d] ~= nil then\n      self.lookahead.average_strategies_data[d]:fill(0)\n    end\n    if self.lookahead.current_strategy_data[d] ~= nil then\n      self.lookahead.current_strategy_data[d]:fill(0)\n    end\n    if self.lookahead.cfvs_data[d] ~= nil then\n      self.lookahead.cfvs_data[d]:fill(0)\n    end\n    if self.lookahead.average_cfvs_data[d] ~= nil then\n      self.lookahead.average_cfvs_data[d]:fill(0)\n    end\n    if self.lookahead.regrets_data[d] ~= nil then\n      self.lookahead.regrets_data[d]:fill(0)\n    end\n    if self.lookahead.current_regrets_data[d] ~= nil then\n      self.lookahead.current_regrets_data[d]:fill(0)\n    end\n    if self.lookahead.positive_regrets_data[d] ~= nil then\n      self.lookahead.positive_regrets_data[d]:fill(0)\n    end\n    if self.lookahead.placeholder_data[d] ~= nil then\n      self.lookahead.placeholder_data[d]:fill(0)\n    end\n    if self.lookahead.regrets_sum[d] ~= nil then\n      self.lookahead.regrets_sum[d]:fill(0)\n    end\n    if self.lookahead.inner_nodes[d] ~= nil then\n      self.lookahead.inner_nodes[d]:fill(0)\n    end\n    if self.lookahead.inner_nodes_p1[d] ~= nil then\n      self.lookahead.inner_nodes_p1[d]:fill(0)\n    end\n    if self.lookahead.swap_data[d] ~= nil then\n      self.lookahead.swap_data[d]:fill(0)\n    end\n  end\n  if self.lookahead.next_street_boxes ~= nil then\n    self.lookahead.next_street_boxes.iter = 0\n    self.lookahead.next_street_boxes:start_computation(self.lookahead.next_round_pot_sizes, self.lookahead.batch_size)\n  end\nend\n\n--- Traverses the tree to fill in lookahead data structures that summarize data\n-- contained in the tree.\n--\n-- For example, saves pot sizes and numbers of actions at each lookahead state.\n--\n-- @param node the current node of the public tree\n-- @param layer the depth of the current node\n-- @param action_id the index of the action that led to this node\n-- @param parent_id the index of the current node's parent\n-- @param gp_id the index of the current node's grandparent\n-- @local\nfunction LookaheadBuilder:set_datastructures_from_tree_dfs(node, layer, action_id, parent_id, gp_id, cur_action_id, parent_action_id)\n\n  --fill the potsize\n  assert(node.pot)\n  self.lookahead.pot_size[layer][{action_id, parent_id, gp_id, {}, {}}] = node.pot\n  if layer == 3 and cur_action_id == constants.actions.ccall then\n    self.lookahead.parent_action_id[parent_id] = parent_action_id\n  end\n\n  node.lookahead_coordinates = arguments.Tensor({action_id, parent_id, gp_id})\n\n  --transition call cannot be allin call\n  if node.current_player == constants.players.chance then\n    assert(parent_id <= self.lookahead.nonallinbets_count[layer-2])\n  end\n\n  if layer < self.lookahead.depth + 1 then\n    local gp_nonallinbets_count = self.lookahead.nonallinbets_count[layer-2]\n    local prev_layer_terminal_actions_count = self.lookahead.terminal_actions_count[layer-1]\n    local gp_terminal_actions_count = self.lookahead.terminal_actions_count[layer-2]\n    local prev_layer_bets_count = 0\n\n    prev_layer_bets_count = self.lookahead.bets_count[layer - 1]\n\n    --compute next coordinates for parent and grandparent\n    local next_parent_id = action_id - prev_layer_terminal_actions_count\n    local next_gp_id = (gp_id - 1) * gp_nonallinbets_count + (parent_id)\n\n    if (not node.terminal) and (node.current_player ~= constants.players.chance) then\n\n      --parent is not an allin raise\n      assert(parent_id <= self.lookahead.nonallinbets_count[layer-2])\n\n      --do we need to mask some actions for that node? (that is, does the node have fewer children than the max number of children for any node on this layer)\n      local node_with_empty_actions = (#node.children < self.lookahead.actions_count[layer])\n\n      if node_with_empty_actions then\n        --we need to mask nonexisting padded bets\n        assert(layer > 1)\n\n        local terminal_actions_count = self.lookahead.terminal_actions_count[layer]\n        assert(terminal_actions_count == 2)\n\n        local existing_bets_count = #node.children - terminal_actions_count\n\n        --allin situations\n        if existing_bets_count == 0 then\n          assert(action_id == self.lookahead.actions_count[layer-1])\n        end\n\n        for child_id = 1,terminal_actions_count do\n          local child_node = node.children[child_id]\n          --go deeper\n          self:set_datastructures_from_tree_dfs(child_node, layer+1, child_id, next_parent_id, next_gp_id, node.actions[child_id], cur_action_id)\n        end\n\n        --we need to make sure that even though there are fewer actions, the last action/allin is has the same last index as if we had full number of actions\n        --we manually set the action_id as the last action (allin)\n        for b = 1, existing_bets_count do\n          self:set_datastructures_from_tree_dfs(node.children[#node.children-b+1], layer+1, self.lookahead.actions_count[layer]-b+1, next_parent_id, next_gp_id, node.actions[#node.children-b+1], cur_action_id)\n        end\n\n        --mask out empty actions\n        self.lookahead.empty_action_mask[layer+1][{{terminal_actions_count+1,-(existing_bets_count+1)}, next_parent_id, next_gp_id, {}}] = 0\n\n      else\n        --node has full action count, easy to handle\n        for child_id = 1,#node.children do\n          local child_node = node.children[child_id]\n          --go deeper\n          self:set_datastructures_from_tree_dfs(child_node, layer+1, child_id, next_parent_id, next_gp_id, node.actions[child_id], cur_action_id)\n        end\n      end\n    end\n  end\nend\n\n\n--- Builds the lookahead's internal data structures using the public tree.\n-- @param tree the public tree used to construct the lookahead\nfunction LookaheadBuilder:build_from_tree(tree)\n\n  self.lookahead.tree = tree\n  self.lookahead.depth = tree.depth\n\n  --per layer information about tree actions\n  --per layer actions are the max number of actions for any of the nodes on the layer\n  self.lookahead.bets_count = {}\n  self.lookahead.nonallinbets_count = {}\n  self.lookahead.terminal_actions_count = {}\n  self.lookahead.actions_count = {}\n\n  self.lookahead.first_call_terminal = self.lookahead.tree.children[2].terminal\n  self.lookahead.first_call_transition = self.lookahead.tree.children[2].current_player == constants.players.chance\n  self.lookahead.first_call_check = (not self.lookahead.first_call_terminal) and (not self.lookahead.first_call_transition)\n\n  self:_compute_tree_structures({tree}, 1)\n  --construct the initial data structures using the bet counts\n  self:construct_data_structures()\n\n  -- action ids for first\n  self.lookahead.parent_action_id = {}\n\n  --traverse the tree and fill the datastructures (pot sizes, non-existin actions, ...)\n  --node, layer, action, parent_action, gp_id\n  self:set_datastructures_from_tree_dfs(tree, 1, 1, 1, 1, -100)\n\n  --set additional info\n  assert(self.lookahead.terminal_actions_count[1] == 1 or self.lookahead.terminal_actions_count[1] == 2)\n\n  --we mask out fold as a possible action when check is for free, due to\n  --1) fewer actions means faster convergence\n  --2) we need to make sure prob of free fold is zero because ACPC dealer changes such action to check\n  if self.lookahead.tree.bets[1] == self.lookahead.tree.bets[2] then\n    --TODO fix this\n    self.lookahead.empty_action_mask[2][1]:fill(0)\n  end\n\n  --construct the neural net query boxes\n  self:_construct_transition_boxes()\n\nend\n\n--- Computes the maximum number of actions at each depth of the tree.\n--\n-- Used to find the size for the tensors which store lookahead data. The\n-- maximum number of actions is used so that every node at that depth can\n-- fit in the same tensor.\n-- @param current_layer a list of tree nodes at the current depth\n-- @param current_depth the depth of the current tree nodes\n-- @local\nfunction LookaheadBuilder:_compute_tree_structures(current_layer, current_depth)\n\n  local layer_actions_count = 0\n  local layer_terminal_actions_count = 0\n  local next_layer = {}\n\n  for n = 1,#current_layer do\n    local node = current_layer[n]\n    layer_actions_count = math.max(layer_actions_count, #node.children)\n\n    local node_terminal_actions_count = 0\n    for c = 1,#current_layer[n].children do\n      if node.children[c].terminal or node.children[c].current_player == constants.players.chance then\n        node_terminal_actions_count = node_terminal_actions_count + 1\n      end\n    end\n\n    layer_terminal_actions_count = math.max(layer_terminal_actions_count, node_terminal_actions_count)\n\n    --add children of the node to the next layer for later pass of BFS\n    if not node.terminal  then\n      for c = 1,#node.children do\n        table.insert(next_layer, node.children[c])\n      end\n    end\n  end\n\n  assert((layer_actions_count == 0) == (#next_layer == 0))\n  assert((layer_actions_count == 0) == (current_depth == self.lookahead.depth))\n\n  --set action and bet counts\n  self.lookahead.bets_count[current_depth] = layer_actions_count - layer_terminal_actions_count\n\n\n  self.lookahead.nonallinbets_count[current_depth] = layer_actions_count - layer_terminal_actions_count\n  if game_settings.nl then\n    --remove allin\n    self.lookahead.nonallinbets_count[current_depth] = self.lookahead.nonallinbets_count[current_depth] - 1\n  end\n  --if no alllin...\n  if layer_actions_count == 2 then\n    assert(layer_actions_count == layer_terminal_actions_count, layer_terminal_actions_count .. \" \" .. current_depth)\n    self.lookahead.nonallinbets_count[current_depth] = 0\n  end\n\n  self.lookahead.terminal_actions_count[current_depth] = layer_terminal_actions_count\n  self.lookahead.actions_count[current_depth] = layer_actions_count\n\n  if #next_layer > 0 then\n    assert(layer_actions_count >= 2)\n    --go deeper\n    self:_compute_tree_structures(next_layer, current_depth + 1)\n  end\n\nend\n"
  },
  {
    "path": "Source/Lookahead/mock_resolving.lua",
    "content": "--- Implements the re-solving interface used by @{resolving} with functions\n-- that do nothing.\n-- \n-- Used for debugging.\n-- @classmod mock_resolving\n\nrequire 'Lookahead.lookahead'\nrequire 'Lookahead.cfrd_gadget'\nrequire 'Tree.tree_builder'\nrequire 'Tree.tree_visualiser'\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal tools = require 'tools'\nlocal card_tools = require 'Game.card_tools'\nlocal game_settings = require 'Settings.game_settings'\n\nlocal MockResolving = torch.class('MockResolving')\n\n--- Constructor\nfunction MockResolving:__init()\nend\n\n--- Does nothing.\n-- @param node the node to \"re-solve\"\n-- @param[opt] player_range not used\n-- @param[opt] opponent_range not used\n-- @see resolving.resolve_first_node\nfunction MockResolving:resolve_first_node(node, player_range, opponent_range)\n  self.node = node\n  self.action_count = self.node.actions:size(1)\nend\n\n--- Does nothing.\n-- @param node the node to \"re-solve\"\n-- @param[opt] player_range not used\n-- @param[opt] opponent_cfvs not used\n-- @see resolving.resolve\nfunction MockResolving:resolve(node, player_range, opponent_cfvs)\n  self.node = node\n  self.action_count = self.node.actions:size(1)\nend\n\n--- Gives the possible actions at the re-solve node.\n-- @return the actions that can be taken at the re-solve node\n-- @see resolving.get_possible_actions\nfunction MockResolving:get_possible_actions()\n  return self.node.actions\nend\n\n--- Returns an arbitrary vector.\n-- @return a vector of 1s\n-- @see resolving.get_root_cfv\nfunction MockResolving:get_root_cfv()\n  return arguments.Tensor(game_settings.card_count):fill(1)\nend\n\n--- Returns an arbitrary vector.\n-- @param[opt] action not used\n-- @return a vector of 1s\n-- @see resolving.get_action_cfv\nfunction MockResolving:get_action_cfv(action)\n  return arguments.Tensor(game_settings.card_count):fill(1)\nend\n\n--- Returns an arbitrary vector.\n-- @param[opt] player_action not used\n-- @param[opt] board not used\n-- @return a vector of 1s\n-- @see resolving.get_chance_action_cfv\nfunction MockResolving:get_chance_action_cfv(player_action, board)\n  return arguments.Tensor(game_settings.card_count):fill(1)\nend\n\n--- Returns an arbitrary vector.\n-- @param[opt] action not used\n-- @return a vector of 1s\n-- @see resolving.get_action_strategy\nfunction MockResolving:get_action_strategy(action)\n  return arguments.Tensor(game_settings.card_count):fill(1)\nend"
  },
  {
    "path": "Source/Lookahead/resolving.lua",
    "content": "--- Implements depth-limited re-solving at a node of the game tree.\n-- Internally uses @{cfrd_gadget|CFRDGadget} TODO SOLVER\n-- @classmod resolving\nrequire 'Lookahead.lookahead'\nrequire 'Lookahead.cfrd_gadget'\nrequire 'Tree.tree_builder'\nrequire 'Tree.tree_visualiser'\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal tools = require 'tools'\nlocal card_tools = require 'Game.card_tools'\n\nlocal Resolving = torch.class('Resolving')\n\n--- Constructor\nfunction Resolving:__init(terminal_equity)\n  self.tree_builder = PokerTreeBuilder()\n  self.terminal_equity = terminal_equity\nend\n\n--- Builds a depth-limited public tree rooted at a given game node.\n-- @param node the root of the tree\n-- @local\nfunction Resolving:_create_lookahead_tree(node)\n  local build_tree_params = {}\n  build_tree_params.root_node = node\n  build_tree_params.limit_to_street = true\n  self.lookahead_tree = self.tree_builder:build_tree(build_tree_params)\nend\n\n--- Re-solves a depth-limited lookahead using input ranges.\n--\n-- Uses the input range for the opponent instead of a gadget range, so only\n-- appropriate for re-solving the root node of the game tree (where ranges\n-- are fixed).\n--\n-- @param node the public node at which to re-solve\n-- @param player_range a range vector for the re-solving player\n-- @param opponent_range a range vector for the opponent\nfunction Resolving:resolve_first_node(node, player_range, opponent_range)\n  self.player_range = player_range\n  self.opponent_range = opponent_range\n  self.opponent_cfvs = nil\n  self:_create_lookahead_tree(node)\n\n  if player_range:dim() == 1 then\n    player_range = player_range:view(1, player_range:size(1))\n    opponent_range = opponent_range:view(1, opponent_range:size(1))\n  end\n  self.lookahead = Lookahead(self.terminal_equity, player_range:size(1))\n\n  local timer = torch.Timer()\n  timer:reset()\n  self.lookahead:build_lookahead(self.lookahead_tree)\n\n  print('build time: ' .. timer:time().real)\n  timer:reset()\n\n  self.lookahead:resolve_first_node(player_range, opponent_range)\n  print('resolve time: ' .. timer:time().real)\n\n  self.resolve_results = self.lookahead:get_results()\n  return self.resolve_results\nend\n\n--- Re-solves a depth-limited lookahead using an input range for the player and\n-- the @{cfrd_gadget|CFRDGadget} to generate ranges for the opponent.\n--\n-- @param node the public node at which to re-solve\n-- @param player_range a range vector for the re-solving player\n-- @param opponent_cfvs a vector of cfvs achieved by the opponent\n-- before re-solving\nfunction Resolving:resolve(node, player_range, opponent_cfvs)\n  assert(card_tools:is_valid_range(player_range, node.board))\n\n  local timer = torch.Timer()\n  timer:reset()\n  self.player_range = player_range\n  self.opponent_cfvs = opponent_cfvs\n  self:_create_lookahead_tree(node)\n\n  if player_range:dim() == 1 then\n    player_range = player_range:view(1, player_range:size(1))\n  end\n  self.lookahead = Lookahead(self.terminal_equity, player_range:size(1))\n\n  self.lookahead:build_lookahead(self.lookahead_tree)\n\n  print('build time: ' .. timer:time().real)\n  timer:reset()\n  self.lookahead:resolve(player_range, opponent_cfvs)\n\n  print('resolve time: ' .. timer:time().real)\n  self.resolve_results = self.lookahead:get_results()\n  return self.resolve_results\nend\n\n--- Gives the index of the given action at the node being re-solved.\n--\n-- The node must first be re-solved with @{resolve} or @{resolve_first_node}.\n-- @param action a legal action at the node\n-- @return the index of the action\n-- @local\nfunction Resolving:_action_to_action_id(action)\n  local actions = self:get_possible_actions(action)\n  local action_id = -1\n  for i=1,actions:size(1) do\n    if action == actions[i] then\n      action_id = i\n    end\n  end\n\n  assert(action_id ~= -1)\n\n  return action_id\nend\n\n--- Gives a list of possible actions at the node being re-solved.\n--\n-- The node must first be re-solved with @{resolve} or @{resolve_first_node}.\n-- @return a list of legal actions\nfunction Resolving:get_possible_actions()\n  return self.lookahead_tree.actions\nend\n\n--- Gives the average counterfactual values that the re-solve player received\n-- at the node during re-solving.\n--\n-- The node must first be re-solved with @{resolve_first_node}.\n--\n-- @return a vector of cfvs\nfunction Resolving:get_root_cfv()\n  return self.resolve_results.root_cfvs\nend\n\n--- Gives the average counterfactual values that each player received\n-- at the node during re-solving.\n--\n-- Usefull for data generation for neural net training\n--\n-- The node must first be re-solved with @{resolve_first_node}.\n--\n-- @return a 2xK tensor of cfvs, where K is the range size\nfunction Resolving:get_root_cfv_both_players()\n  return self.resolve_results.root_cfvs_both_players\nend\n\n--- Gives the average counterfactual values that the opponent received\n-- during re-solving after the re-solve player took a given action.\n--\n-- Used during continual re-solving to track opponent cfvs. The node must\n-- first be re-solved with @{resolve} or @{resolve_first_node}.\n--\n-- @param action the action taken by the re-solve player at the node being\n-- re-solved\n-- @return a vector of cfvs\nfunction Resolving:get_action_cfv(action)\n  local action_id = self:_action_to_action_id(action)\n  return self.resolve_results.children_cfvs[action_id]\nend\n\n--- Gives the average counterfactual values that the opponent received\n-- during re-solving after a chance event (the betting round changes and\n-- more cards are dealt).\n--\n-- Used during continual re-solving to track opponent cfvs. The node must\n-- first be re-solved with @{resolve} or @{resolve_first_node}.\n--\n-- @param action the action taken by the re-solve player at the node being\n-- re-solved\n-- @param board a vector of board cards which were updated by the chance event\n-- @return a vector of cfvs\nfunction Resolving:get_chance_action_cfv(action, board)\n  -- resolve to get next_board chance actions if flop\n  if board:dim() == 1 and board:size(1) == 3 then\n    self.lookahead:reset()\n\n    local board_idx = card_tools:get_flop_board_index(board)\n    self.lookahead.next_board_idx = board_idx\n\n    if self.opponent_cfvs ~= nil then\n      self.lookahead:resolve(self.player_range, self.opponent_cfvs)\n    else\n      self.lookahead:resolve_first_node(self.player_range, self.opponent_range)\n    end\n\n    self.lookahead.next_board_idx = nil\n  end\n  return self.lookahead:get_chance_action_cfv(action, board)\nend\n\n--- Gives the probability that the re-solved strategy takes a given action.\n--\n-- The node must first be re-solved with @{resolve} or @{resolve_first_node}.\n--\n-- @param action a legal action at the re-solve node\n-- @return a vector giving the probability of taking the action with each\n-- private hand\nfunction Resolving:get_action_strategy(action)\n  local action_id = self:_action_to_action_id(action)\n  return self.resolve_results.strategy[action_id][1]\nend\n"
  },
  {
    "path": "Source/Nn/Bucketing/.gitignore",
    "content": "unique*.dat\n"
  },
  {
    "path": "Source/Nn/Bucketing/flop_tools.lua",
    "content": "local M = {}\n\nfunction M:_suitcat_flop(s1,s2,s3,s4,s5)\n\tif(s1~=0) then return -1 end\n\n\tlocal ret = -1\n\n\tif(s2==0) then\n\t\tif(s3==0) then\n\t\t\tret = s4 * 2 + s5\n\t\telseif(s3==1) then\n\t\t\tret = 5 + s4 * 3 + s5\n\t\tend\n\telseif(s2==1) then\n\t\tif(s3==0) then\n\t\t\tret = 15 + s4 * 3 + s5\n\t\telseif(s3==1) then\n\t\t\tret = 25 + s4 * 3 + s5\n\t\telseif(s3==2) then\n\t\t\tret = 35 + s4 * 4 + s5\n\t\tend\n\tend\n\treturn ret;\nend\n\nfunction M:flopID(h, b)\n\n\tb = torch.sort(b)\n\n\t-- Get hand suits\n\tlocal os = {}\n  for i = 0,4 do\n\t\tif i <= 1 then\n\t\t\tos[i] = (h[i+1]-1)%4\n\t\telse\n\t\t\tos[i] = (b[i-1]-1)%4\n\t\tend\n\tend\n\n  -- Canonicalize suits\n\tlocal MM = 0\n\tlocal s = {}\n\tfor i=0,4 do\n\t\tlocal j = 0\n\t\twhile j < i do\n\t\t\tif os[j] == os[i] then\n\t\t\t\ts[i] = s[j]\n\t\t\t\tbreak\n\t\t\tend\n\t\t\tj = j + 1\n\t\tend\n\t\tif j == i then\n\t\t\ts[i] = MM\n\t\t\tMM = MM + 1\n\t\tend\n\n\t\tif i <= 1 then\n\t\t\tlocal suitdiff = s[i] - ((h[i+1] - 1) % 4)\n\t\t\th[i+1] = h[i+1] + suitdiff\n\t\telse\n\t\t\tlocal suitdiff = s[i] - ((b[i-1] - 1) % 4)\n\t\t\tb[i-1] = b[i-1] + suitdiff\n\t\tend\n\tend\n\n\tb = torch.sort(b)\n\tlocal base =\n         math.floor((h[1]-1)/4)*13*13*13*13 +\n\t\t\t\t math.floor((h[2]-1)/4)*13*13*13 +\n\t\t\t\t math.floor((b[1]-1)/4)*13*13 +\n\t\t\t\t math.floor((b[2]-1)/4)*13 +\n         math.floor((b[3]-1)/4)\n\n\tfor i = 0,4 do\n \t\tif i <= 1 then\n \t\t\ts[i] = (h[i+1]-1)%4\n \t\telse\n \t\t\ts[i] = (b[i-1]-1)%4\n \t\tend\n \tend\n\n\tlocal cat = self:_suitcat_flop(s[0],s[1],s[2],s[3],s[4])\n\n\tif cat==-1 then\n\t\tprint(\"error suit cat\")\n    io.read()\n\tend\n\tcat = cat*13*13*13*13*13 + base;\n\treturn cat\nend\n\nreturn M\n"
  },
  {
    "path": "Source/Nn/Bucketing/river_tools.lua",
    "content": "local arguments = require 'Settings.arguments'\n\nlocal M = {}\n\nfunction M:_suitcat_river(s1,s2,s3,s4,s5,s6,s7)\n\tlocal suit = {}\n  suit[0] = 0\n  suit[1] = 0\n  suit[2] = 0\n  suit[3] = 0\n\tsuit[s3] = suit[s3] + 1;\n\tsuit[s4] = suit[s4] + 1;\n\tsuit[s5] = suit[s5] + 1;\n\tsuit[s6] = suit[s6] + 1;\n\tsuit[s7] = suit[s7] + 1;\n\n\tif suit[0]<=2 and suit[1]<=2 and suit[2]<=2 and suit[3]<=2 then\n\t\treturn 0\n\tend\n\n\tif suit[0]==3 or suit[1]==3 or suit[2]==3 or suit[3]==3 then\n\t\tlocal thesuit = -1;\n\t\tfor i=0,3 do\n\t\t\tif suit[i]==3 then\n\t\t\t\tthesuit = i\n      end\n    end\n\n\t\tlocal mask = 0\n\t\tif s3==thesuit then mask = mask + 1 end\n\t\tif s4==thesuit then mask = mask + 2 end\n\t\tif s5==thesuit then mask = mask + 4 end\n\t\tif s6==thesuit then mask = mask + 8 end\n\t\tif s7==thesuit then mask = mask + 16 end\n\n\t\tlocal add = 0\n\t\tif s1==thesuit and s2==thesuit then add = 1\n    elseif s1==thesuit then add = 2\n\t\telseif s2==thesuit then add = 3 end\n\n\t\tif mask==7 then\n\t\t\treturn 1 + add\n\t\telseif mask==11 then\n\t\t\treturn 5 + add\n\t\telseif mask==19 then\n\t\t\treturn 9 + add\n\t\telseif mask==13 then\n\t\t\treturn 13 + add\n\t\telseif mask==21 then\n\t\t\treturn 17 + add\n\t\telseif mask==25 then\n\t\t\treturn 21 + add\n\t\telseif mask==14 then\n\t\t\treturn 25 + add\n\t\telseif mask==22 then\n\t\t\treturn 29 + add\n\t\telseif mask==26 then\n\t\t\treturn 33 + add\n\t\telseif mask==28 then\n\t\t\treturn 37 + add\n\t\tend\n\t\tprint(\"bad river suits\")\n\t\tio.read()\n\tend\n\n\tif suit[0]==4 or suit[1]==4 or suit[2]==4 or suit[3]==4 then\n\t\tlocal thesuit = -1;\n    for i=0,3 do\n\t\t\tif suit[i]==4 then\n\t\t\t\tthesuit = i\n      end\n    end\n\n\t\tif s3 ~= thesuit then\n\t\t\tif s1==thesuit and s2==thesuit then return 42 end\n\t\t\tif s1==thesuit then return 43 end\n\t\t\tif s2==thesuit then return 44 end\n\t\t\treturn 45\n\t\telseif s4~=thesuit then\n\t\t\tif s1==thesuit and s2==thesuit then return 46 end\n\t\t\tif s1==thesuit then return 47 end\n\t\t\tif s2==thesuit then return 48 end\n\t\t\treturn 49\n\t\telseif s5~=thesuit then\n\t\t\tif s1==thesuit and s2==thesuit then return 50 end\n\t\t\tif s1==thesuit then return 51 end\n\t\t\tif s2==thesuit then return 52 end\n\t\t\treturn 53\n\t\telseif s6~=thesuit then\n\t\t\tif s1==thesuit and s2==thesuit then return 54 end\n\t\t\tif s1==thesuit then return 55 end\n\t\t\tif s2==thesuit then return 56 end\n\t\t\treturn 57\n\t\telseif s7~=thesuit then\n\t\t\tif s1==thesuit and s2==thesuit then return 58 end\n\t\t\tif s1==thesuit then return 59 end\n\t\t\tif s2==thesuit then return 60 end\n\t\t\treturn 61;\n\t\tend\n\n\t\tprint(\"bad river suits\")\n\t\tio.read()\n\tend\n\tif suit[0]==5 or suit[1]==5 or suit[2]==5 or suit[3]==5 then\n    local thesuit = -1;\n    for i=0,3 do\n\t\t\tif suit[i]==5 then\n\t\t\t\tthesuit = i\n      end\n    end\n\n\t\tif s1==thesuit and s2==thesuit then return 62 end\n\t\tif s1==thesuit then return 63 end\n\t\tif s2==thesuit then return 64 end\n\t\treturn 65\n\tend\n\n\tprint(\"bad river suits\")\n\tio.read()\nend\n\nfunction M:riverID(h, b)\n\n  local hole = h\n  local board = torch.sort(b)\n\tlocal base =\n         math.floor((hole[1]-1)/4)*13*13*13*13*13*13 +\n\t\t\t\t math.floor((hole[2]-1)/4)*13*13*13*13*13 +\n\t\t\t\t math.floor((board[1]-1)/4)*13*13*13*13 +\n\t\t\t\t math.floor((board[2]-1)/4)*13*13*13 +\n         math.floor((board[3]-1)/4)*13*13 +\n         math.floor((board[4]-1)/4)*13 +\n         math.floor((board[5]-1)/4);\n\n\tlocal suitcode = self:_suitcat_river(\n    hole[1]%4,\n    hole[2]%4,\n    board[1]%4,\n    board[2]%4,\n    board[3]%4,\n    board[4]%4,\n    board[5]%4);\n\tif suitcode==-1 then\n\t\tprint(\"error suit cat\")\n    io.read()\n\tend\n\tsuitcode = suitcode * 815730722\n\treturn suitcode+base\nend\n\nreturn M\n"
  },
  {
    "path": "Source/Nn/Bucketing/turn_tools.lua",
    "content": "local M = {}\n\nfunction M:_suitcat_turn(s1,s2,s3,s4,s5,s6)\n\tif s1~=0 then return -1 end\n\n\tlocal ret = -1\n\n\tif s2==0 then\n\t\tif s3==0 then\n\t\t\tif s4==0 then\n\t\t\t  ret = s5 * 2 + s6\n\t\t\telseif s4==1 then\n\t\t\t\tret = 5 + s5 * 3 + s6\n\t\t\tend\n\t\telseif s3==1 then\n\t\t\tif s4==0 then\n\t\t\t\tret = 15 + s5 * 3 + s6\n\t\t\telseif s4==1 then\n\t\t\t\tret = 25 + s5 * 3 + s6\n\t\t\telseif s4==2 then\n\t\t\t\tret = 35 + s5 * 4 + s6\n\t\t\tend\n\t\tend\n\telseif s2==1 then\n\t\tif s3==0 then\n\t\t\tif s4==0 then\n\t\t\t\tret = 51 + s5 * 3 + s6\n\t\t\telseif s4==1 then\n\t\t\t\tret = 61 + s5 * 3 + s6\n\t\t\telseif s4==2 then\n\t\t\t\tret = 71 + s5 * 4 + s6\n\t\t\tend\n\t\telseif s3==1 then\n\t\t\tif s4==0 then\n\t\t\t\tret = 87 + s5 * 3 + s6\n\t\t\telseif s4==1 then\n\t\t\t\tret = 97 + s5 * 3 + s6\n\t\t\telseif s4==2 then\n\t\t\t\tret = 107 + s5 * 4 + s6\n\t\t\tend\n\t\telseif s3==2 then\n\t\t\tret = 123 + s4 * 16 + s5 * 4 + s6\n\t\tend\n\tend\n\treturn ret\nend\n\nfunction M:turnID(h, b)\n\n\tb = torch.sort(b)\n\n\t-- Get hand suits\n\tlocal os = {}\n  for i = 0,5 do\n\t\tif i <= 1 then\n\t\t\tos[i] = (h[i+1]-1)%4\n\t\telse\n\t\t\tos[i] = (b[i-1]-1)%4\n\t\tend\n\tend\n\n  -- Canonicalize suits\n\tlocal MM = 0\n\tlocal s = {}\n\tfor i=0,5 do\n\t\tlocal j = 0\n\t\twhile j < i do\n\t\t\tif os[j] == os[i] then\n\t\t\t\ts[i] = s[j]\n\t\t\t\tbreak\n\t\t\tend\n\t\t\tj = j + 1\n\t\tend\n\t\tif j == i then\n\t\t\ts[i] = MM\n\t\t\tMM = MM + 1\n\t\tend\n\n\t\tif i <= 1 then\n\t\t\tlocal suitdiff = s[i] - ((h[i+1] - 1) % 4)\n\t\t\th[i+1] = h[i+1] + suitdiff\n\t\telse\n\t\t\tlocal suitdiff = s[i] - ((b[i-1] - 1) % 4)\n\t\t\tb[i-1] = b[i-1] + suitdiff\n\t\tend\n\tend\n\n\tb = torch.sort(b)\n\tlocal base =\n         math.floor((h[1]-1)/4)*13*13*13*13*13 +\n\t\t\t\t math.floor((h[2]-1)/4)*13*13*13*13 +\n\t\t\t\t math.floor((b[1]-1)/4)*13*13*13 +\n\t\t\t\t math.floor((b[2]-1)/4)*13*13 +\n         math.floor((b[3]-1)/4)*13 +\n         math.floor((b[4]-1)/4)\n\n\tfor i = 0,5 do\n \t\tif i <= 1 then\n \t\t\ts[i] = (h[i+1]-1)%4\n \t\telse\n \t\t\ts[i] = (b[i-1]-1)%4\n \t\tend\n \tend\n\n\tlocal cat = self:_suitcat_turn(s[0],s[1],s[2],s[3],s[4],s[5])\n\n\tif cat==-1 then\n\t\tprint(\"error suit cat\")\n    io.read()\n\tend\n\tcat = cat*13*13*13*13*13*13 + base;\n\treturn cat\nend\n\nreturn M\n"
  },
  {
    "path": "Source/Nn/bucket_conversion.lua",
    "content": "--- Converts between vectors over private hands and vectors over buckets.\n-- @classmod bucket_conversion\n\nrequire 'torch'\nrequire 'math'\nlocal card_tools = require 'Game.card_tools'\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\nlocal bucketer = require 'Nn.bucketer'\nlocal tools = require 'tools'\n\nlocal BucketConversion = torch.class('BucketConversion')\n\n--- Constructor\nfunction BucketConversion:__init()\nend\n\n--- Sets the board cards for the bucketer.\n-- @param board a non-empty vector of board cards\nfunction BucketConversion:set_board(board, raw)\n  if raw ~= nil then\n    self.bucket_count = tools:choose(14, 2) + tools:choose(10, 2)\n  else\n    self.bucket_count = bucketer:get_bucket_count(card_tools:board_to_street(board))\n  end\n  self._range_matrix = arguments.Tensor(game_settings.hand_count, self.bucket_count ):zero()\n\n  local buckets = nil\n  if raw ~= nil then\n    buckets = bucketer:compute_rank_buckets(board)\n  else\n    buckets = bucketer:compute_buckets(board)\n  end\n  local class_ids = torch.range(1, self.bucket_count)\n\n  if arguments.gpu then\n    buckets = buckets:cuda()\n    class_ids = class_ids:cuda()\n  else\n    class_ids = class_ids:float()\n  end\n\n  class_ids = class_ids:view(1, self.bucket_count):expand(game_settings.hand_count, self.bucket_count)\n  local card_buckets = buckets:view(game_settings.hand_count, 1):expand(game_settings.hand_count, self.bucket_count)\n\n  --finding all strength classes\n  --matrix for transformation from card ranges to strength class ranges\n  self._range_matrix[torch.eq(class_ids, card_buckets)] = 1\n\n  --matrix for transformation form class values to card values\n  self._reverse_value_matrix = self._range_matrix:t():clone()\nend\n\n--- Converts a range vector over private hands to a range vector over buckets.\n--\n-- @{set_board} must be called first. Used to create inputs to the neural net.\n-- @param card_range a probability vector over private hands\n-- @param bucket_range a vector in which to save the resulting probability\n-- vector over buckets\nfunction BucketConversion:card_range_to_bucket_range(card_range, bucket_range)\n  bucket_range:mm(card_range, self._range_matrix)\nend\n\nfunction BucketConversion:hand_cfvs_to_bucket_cfvs(card_range, card_cfvs, bucket_range, bucketed_cfvs)\n  bucketed_cfvs:mm(torch.cmul(card_range,card_cfvs), self._range_matrix)\n\n  -- avoid divide by 0\n  bucketed_cfvs:cdiv(torch.cmax(bucket_range, 0.00001))\nend\n\n--- Converts a value vector over buckets to a value vector over private hands.\n--\n-- @{set_board} must be called first. Used to process neural net outputs.\n-- @param bucket_value a vector of values over buckets\n-- @param card_value a vector in which to save the resulting vector of values\n-- over private hands\nfunction BucketConversion:bucket_value_to_card_value(bucket_value, card_value)\n  card_value:mm(bucket_value, self._reverse_value_matrix)\nend\n\n--- Gives a vector of possible buckets on the the board.\n--\n-- @{set_board} must be called first.\n-- @return a mask vector over buckets where each entry is 1 if the bucket is\n-- valid, 0 if not\nfunction BucketConversion:get_possible_bucket_mask()\n  local mask = arguments.Tensor(1, self.bucket_count)\n  local card_indicator = arguments.Tensor(1, game_settings.hand_count):fill(1)\n\n  mask:mm(card_indicator, self._range_matrix)\n  mask[torch.gt(mask, 0)] = 1\n\n  return mask\nend\n"
  },
  {
    "path": "Source/Nn/bucketer.lua",
    "content": "--- Assigns hands to buckets on the given board.\n--\n-- For the Leduc implementation, we simply assign every possible set of\n-- private and board cards to a unique bucket.\n-- @classmod bucketer\nlocal game_settings = require 'Settings.game_settings'\nlocal card_tools = require 'Game.card_tools'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal river_tools = require 'Nn.Bucketing.river_tools'\nlocal turn_tools = require 'Nn.Bucketing.turn_tools'\nlocal flop_tools = require 'Nn.Bucketing.flop_tools'\nlocal card_to_string_conversion = require 'Game.card_to_string_conversion'\nlocal evaluator = require 'Game.Evaluation.evaluator'\nlocal tools = require 'tools'\n\nlocal M = {}\n\nfunction M:_init()\n  if self._ihr_pair_to_bucket == nil then\n    local f = assert(io.open(\"./Nn/Bucketing/riverihr.dat\", \"rb\"))\n    local data = f:read(\"*all\")\n\n    self._river_ihr = {}\n    for i = 1, string.len(data), 7 do\n      local key = 0\n      for j = i,i+4 do\n        key = key + data:byte(j) * (2 ^ ((4 - j + i) * 8))\n      end\n      local win = data:byte(i+5)\n      local tie = data:byte(i+6)\n      self._river_ihr[key] = win*200 + tie\n    end\n    f:close()\n\n    local f = assert(io.open(\"./Nn/Bucketing/rcats.dat\", \"r\"))\n    self.river_buckets = f:read(\"*number\")\n    self._ihr_pair_to_bucket = {}\n    for i = 1, self.river_buckets do\n      local win = f:read(\"*number\")\n      local tie = f:read(\"*number\")\n      self._ihr_pair_to_bucket[win * 1000 + tie] = i\n    end\n    f:close()\n  end\n\n  if self._turn_means == nil then\n    self._turn_means = {}\n    local f = assert(io.open(\"./Nn/Bucketing/turn_means.dat\"))\n    local num_means = f:read(\"*number\")\n    for i = 1,num_means do\n      local dist = {}\n      for j = 0,50 do\n        dist[j] = f:read(\"*number\")\n      end\n      self._turn_means[i] = dist\n    end\n    f:close()\n  end\n\n  if self._turn_cats == nil then\n    self._turn_cats = {}\n    local f = assert(io.open(\"./Nn/Bucketing/turn_dist_cats.dat\", \"rb\"))\n    local data = f:read(\"*all\")\n\n    for i = 1, string.len(data), 6 do\n      local key = 0\n      for j = i,i+3 do\n        key = key + data:byte(j) * (2 ^ ((j - i) * 8))\n      end\n      local cat = data:byte(i+4) + data:byte(i+5) * (2 ^ 8)\n      self._turn_cats[key] = cat\n\n      assert(cat <= 1000 and cat >= 1, \"cat = \" .. cat)\n    end\n    f:close()\n  end\n  if self._flop_cats == nil then\n    self._flop_cats = {}\n    local f = assert(io.open(\"./Nn/Bucketing/flop_dist_cats.dat\", \"rb\"))\n    local data = f:read(\"*all\")\n\n    for i = 1, string.len(data), 6 do\n      local key = 0\n      for j = i,i+3 do\n        key = key + data:byte(j) * (2 ^ ((j - i) * 8))\n      end\n      local cat = data:byte(i+4) + data:byte(i+5) * (2 ^ 8)\n      self._flop_cats[key] = cat\n\n      assert(cat <= 1000 and cat >= 1, \"cat = \" .. cat)\n    end\n    f:close()\n  end\nend\n\nM:_init()\n\n--- Gives the total number of buckets across all boards.\n-- @return the number of buckets\nfunction M:get_bucket_count(street)\n  if street == 4 then\n    return self.river_buckets\n  elseif street == 3 or street == 2 then\n    return 1000\n  elseif street == 1 then\n    return 169\n  end\n  return 169\nend\n\n--- Gives the maximum number of ranks across all boards.\n-- @return the number of buckets\nfunction M:get_rank_count()\n  return tools:choose(14, 2) + tools:choose(10, 2)\nend\n\nfunction M:emd(a,b)\n  local emds = {}\n  emds[0] = 0;\n  for i = 1, 51 do\n    emds[i] = a[i-1] + emds[i-1] - b[i-1];\n  end\n  local ret = 0;\n  for i = 0, 51 do\n    ret = ret + math.abs(emds[i]);\n  end\n  return ret\nend\n\nfunction M:_compute_turn_buckets(board)\n  local buckets = torch.Tensor(game_settings.hand_count):fill(-1)\n  local used = torch.ByteTensor(game_settings.card_count):fill(0)\n  local hand = torch.ByteTensor(7)\n  for i = 1, board:size(1) do\n    used[board[i]] = 1\n    hand[i + 2] = board[i]\n  end\n\n  for card1 = 1,game_settings.card_count do\n    if used[card1] == 0 then\n      used[card1] = 1\n      hand[1] = card1\n      for card2 = card1+1, game_settings.card_count do\n        if used[card2] == 0 then\n          used[card2] = 1\n          hand[2] = card2\n\n          local idx = card_tools:get_hole_index({card1,card2})\n\n          --print(card_to_string_conversion:cards_to_string(hand[{{1,6}}]))\n          local turn_code = turn_tools:turnID(hand[{{1,2}}]:clone(), hand[{{3,6}}]:clone())\n\n          local closest_mean = self._turn_cats[turn_code]\n          buckets[idx] = closest_mean\n\n          used[card2] = 0\n        end\n      end\n      used[card1] = 0\n    end\n  end\n\n  return buckets\nend\n\nfunction M:_compute_flop_buckets(board)\n  local buckets = torch.Tensor(game_settings.hand_count):fill(-1)\n  local used = torch.ByteTensor(game_settings.card_count):fill(0)\n  local hand = torch.ByteTensor(5)\n  for i = 1, board:size(1) do\n    used[board[i]] = 1\n    hand[i + 2] = board[i]\n  end\n\n  for card1 = 1,game_settings.card_count do\n    if used[card1] == 0 then\n      used[card1] = 1\n      hand[1] = card1\n      for card2 = card1+1, game_settings.card_count do\n        if used[card2] == 0 then\n          used[card2] = 1\n          hand[2] = card2\n\n          local idx = card_tools:get_hole_index({card1,card2})\n\n          local flop_code = flop_tools:flopID(hand[{{1,2}}]:clone(), hand[{{3,5}}]:clone())\n\n          local closest_mean = self._flop_cats[flop_code]\n          buckets[idx] = closest_mean\n\n          used[card2] = 0\n        end\n      end\n      used[card1] = 0\n    end\n  end\n  return buckets\nend\n\nfunction M:_compute_preflop_buckets()\n  if self._preflop_buckets == nil then\n    self._preflop_buckets = arguments.Tensor(game_settings.hand_count):fill(-1)\n\n    for card1 = 1,game_settings.card_count do\n      for card2 = card1+1, game_settings.card_count do\n\n        local idx = card_tools:get_hole_index({card1,card2})\n\n        local rank1 = math.floor((card1 - 1) / 4)\n        local rank2 = math.floor((card2 - 1) / 4)\n        if card1 % 4 == card2 % 4 then\n          self._preflop_buckets[idx] = rank1 * 13 + rank2 + 1\n        else\n          self._preflop_buckets[idx] = rank2 * 13 + rank1 + 1\n        end\n      end\n    end\n  end\n  return self._preflop_buckets\nend\n\nfunction M:_compute_river_buckets(board)\n  local buckets = torch.Tensor(game_settings.hand_count):fill(-1)\n  local used = torch.ByteTensor(game_settings.card_count):fill(0)\n  local board_size = board:size(1)\n  for i = 1, board_size do\n    used[board[i]] = 1\n  end\n  local hands = torch.ByteTensor(constants.players_count, board_size + game_settings.hand_card_count)\n  for i = 1, constants.players_count do\n    hands[{i,{1, - 1 - game_settings.hand_card_count}}]:copy(board)\n  end\n\n  for card1 = 1,game_settings.card_count do\n    if used[card1] == 0 then\n      used[card1] = 1\n      hands[1][-2] = card1\n      for card2 = card1+1, game_settings.card_count do\n        if used[card2] == 0 then\n          used[card2] = 1\n          hands[1][-1] = card2\n          local idx = card_tools:get_hole_index({card1,card2})\n\n          local code = river_tools:riverID(hands[1][{{6,7}}], hands[1][{{1,5}}])\n          local ihr = self._river_ihr[code]\n          local win_bucket = math.floor(ihr/200)\n          local tie_bucket = math.floor((ihr % 200)/2)\n\n          local r_bucket = self._ihr_pair_to_bucket[win_bucket * 1000 + tie_bucket]\n          assert(r_bucket ~= nil, 'bad win,tie ihr pair')\n          buckets[idx] = r_bucket\n          used[card2] = 0\n        end\n      end\n      used[card1] = 0\n    end\n  end\n\n  return buckets\nend\n\n--- Gives a vector which maps private hands to buckets on a given board.\n-- @param board a non-empty vector of board cards\n-- @return a vector which maps each private hand to a bucket index\nfunction M:compute_buckets(board)\n  local street = card_tools:board_to_street(board)\n\n  if street == 4 then\n    return self:_compute_river_buckets(board)\n  elseif street == 3 then\n    return self:_compute_turn_buckets(board)\n  elseif street == 2 then\n    return self:_compute_flop_buckets(board)\n  elseif street == 1 then\n    return self:_compute_preflop_buckets()\n  end\nend\n\nfunction M:compute_rank_buckets(board)\n  local buckets = arguments.Tensor(game_settings.hand_count):fill(-1)\n\n  local ranks = evaluator:batch_eval(board,-1)\n  local sorted_ranks, _ = torch.sort(ranks)\n  local rank_idx = 0\n  local rank_idxs = {}\n  for i = 1, sorted_ranks:size(1) do\n    if sorted_ranks[i] == -1 then\n      break\n    end\n    if (i > 1 and sorted_ranks[i] ~= sorted_ranks[i-1]) or i == 1 then\n      rank_idx = rank_idx + 1\n      rank_idxs[sorted_ranks[i]] = rank_idx\n    end\n  end\n\n  for i = 1, ranks:size(1) do\n    if ranks[i] ~= -1 then\n      ranks[i] = rank_idxs[ranks[i]]\n    end\n  end\n\n  return ranks\nend\n\nreturn M\n"
  },
  {
    "path": "Source/Nn/cpu_gpu_model_converter.lua",
    "content": "--- Generates a neural net model in CPU format from a neural net model saved\n-- in GPU format.\n-- @script cpu_gpu_model_converter\n\nrequire 'cunn'\nlocal arguments = require 'Settings.arguments'\n\n--- Generates a neural net model in CPU format from a neural net model saved\n-- in GPU format.\n-- @param gpu_model_path the prefix of the path to the gpu model, which is\n-- appended with `_gpu.info` and `_gpu.model`\nlocal function convert_gpu_to_cpu(gpu_model_path)\n  local info = torch.load(gpu_model_path .. '_gpu.info')\n  assert(info.gpu)\n  info.gpu = false\n\n  local model = torch.load(gpu_model_path .. '_gpu.model')\n  model = model:float()\n\n  torch.save(gpu_model_path .. '_cpu.info', info)\n  torch.save(gpu_model_path .. '_cpu.model', model)\nend\n\n--- Generates a neural net model in GPU format from a neural net model saved\n-- in CPU format.\n-- @param cpu_model_path the prefix of the path to the cpu model, which is\n-- appended with `_cpu.info` and `_cpu.model`\nlocal function convert_cpu_to_gpu(cpu_model_path)\n\n  local info = torch.load(cpu_model_path .. '_cpu.info')\n  assert(not info.gpu)\n  info.gpu = true\n\n  local model = torch.load(cpu_model_path .. '_cpu.model')\n  model = model:cuda()\n\n  torch.save(cpu_model_path .. '_gpu.info', info)\n  torch.save(cpu_model_path .. '_gpu.model', model)\nend\n\n\nconvert_cpu_to_gpu('../Data/Models/NoLimit/flop/final')\n"
  },
  {
    "path": "Source/Nn/masked_huber_loss.lua",
    "content": "--- Computes a Huber loss for neural net training and evaluation.\n--\n-- Computes the loss across buckets, but only on buckets that are\n-- possible on a given board.\n-- @classmod masked_huber_loss\n\nrequire 'nn'\nlocal arguments = require 'Settings.arguments'\n\nlocal MaskedHuberLoss = torch.class('MaskedHuberLoss')\n\n--- Constructor\nfunction MaskedHuberLoss:__init()\n  self.criterion = nn.SmoothL1Criterion()\nend\n\n--- Moves the torch criterion (used for loss and gradient computation)\n-- to the GPU.\n-- @return the MaskedHuberLoss object that `cuda()` is called on\nfunction MaskedHuberLoss:cuda()\n  self.criterion = self.criterion:cuda()\n  return self\nend\n\n--- Computes the loss over a batch of neural net outputs and targets.\n--\n-- @param outputs an NxM tensor containing N vectors of values over buckets,\n-- output by the neural net\n-- @param targets an NxM tensor containing N vectors of actual values over\n-- buckets, produced by @{data_generation_call}\n-- @param mask an NxM tensor containing N mask vectors generated with\n-- @{bucket_conversion.get_possible_bucket_mask}\n-- @return the sum of Huber loss applied elementwise on `outputs` and `targets`,\n-- masked so that only valid buckets are included\nfunction MaskedHuberLoss:forward(outputs, targets, mask)\n\n  local batch_size = outputs:size(1)\n  local feature_size = outputs:size(2)\n\n  --1.0 zero out the outputs/target so that the error does not depend on these\n  outputs:cmul(mask)\n  targets:cmul(mask)\n\n  local loss = self.criterion:forward(outputs, targets)\n\n  --2.0 if the batch size has changed, create new storage for the sum, otherwise reuse\n  if not self.mask_sum or (self.mask_sum:size(1) ~= batch_size) then\n    self.mask_placeholder = arguments.Tensor(mask:size()):fill(0)\n    self.mask_sum = arguments.Tensor(batch_size):fill(0)\n    self.mask_multiplier = self.mask_sum:clone():fill(0):view(-1, 1)\n  end\n\n  --3.0 compute mask sum for each batch\n  self.mask_placeholder:copy(mask)\n  torch.sum(self.mask_sum, self.mask_placeholder, 2)\n\n  --3.1 mask multiplier - note that mask is 1 for impossible features\n  self.mask_multiplier:fill(feature_size)\n  self.mask_multiplier:cdiv(self.mask_sum)\n\n  --4.0 multiply to get a new losss\n  --loss is not really computed batch-wise correctly,\n  --but that does not really matter now since gradients are correct\n  local loss_multiplier = (batch_size * feature_size) / self.mask_sum:sum()\n  local new_loss = loss_multiplier * loss\n\n  return new_loss\nend\n\n--- Computes the gradient of the loss function @{forward} with\n-- arguments `outputs`, `targets`, and `mask`.\n--\n-- Must be called after a @{forward} call with the same arguments.\n--\n-- @param outputs an NxM tensor containing N vectors of values over buckets,\n-- output by the neural net\n-- @param targets an NxM tensor containing N vectors of actual values over\n-- buckets, produced by @{data_generation_call}\n-- @param mask an NxM tensor containing N mask vectors generated with\n-- @{bucket_conversion.get_possible_bucket_mask}\n-- @return the gradient of @{forward} applied to the arguments\nfunction MaskedHuberLoss:backward(outputs, targets, mask)\n\n  local dloss_doutput = self.criterion:backward(outputs, targets)\n\n  --we use the multiplier computed with the mask during forward call\n  dloss_doutput:cmul(self.mask_multiplier:expandAs(dloss_doutput))\n\n  return dloss_doutput\nend\n"
  },
  {
    "path": "Source/Nn/mock_nn_terminal.lua",
    "content": "--- Implements the same interface as @{value_nn}, but without uses terminal\n-- equity evaluation instead of a neural net.\n-- \n-- Can be used to replace the neural net during debugging.\n-- @classmod mock_nn_terminal\n\nrequire 'torch'\nrequire 'Nn.bucketer'\nrequire 'TerminalEquity.terminal_equity'\nlocal game_settings = require  'Settings.game_settings'\nlocal card_tools = require 'Game.card_tools'\nlocal arguments = require 'Settings.arguments'\n\nlocal MockNnTerminal = torch.class('MockNnTerminal')\n\n--- Constructor. Creates an equity matrix with entries for every possible\n-- pair of buckets.\nfunction MockNnTerminal:__init()\n  self.bucketer = Bucketer()\n  self.bucket_count = self.bucketer:get_bucket_count()\n  self.equity_matrix = arguments.Tensor(self.bucket_count, self.bucket_count):zero()\n  --filling equity matrix\n  local boards = card_tools:get_second_round_boards()\n  self.board_count = boards:size(1)\n  self.terminal_equity = TerminalEquity()\n  for i = 1, self.board_count do \n    local board = boards[i]\n    self.terminal_equity:set_board(board)\n    local call_matrix = self.terminal_equity:get_call_matrix()\n    local buckets = self.bucketer:compute_buckets(board)\n    for c1 = 1, game_settings.card_count do \n      for c2 = 1, game_settings.card_count do \n        local b1 = buckets[c1]\n        local b2 = buckets[c2]\n        if( b1 > 0 and b2 > 0 ) then\n          local matrix_entry = call_matrix[c1][c2]\n          self.equity_matrix[b1][b2] = matrix_entry\n        end\n      end\n    end\n  end\nend\n\n--- Gives the expected showdown equity of the two players' ranges.\n-- @param inputs An NxI tensor containing N instances of neural net inputs. \n-- See @{net_builder} for details of each input.\n-- @param outputs An NxO tensor in which to store N sets of expected showdown\n-- counterfactual values for each player.\nfunction MockNnTerminal:get_value(inputs, outputs)\n\n  assert(outputs:dim() == 2 )\n  local bucket_count = outputs:size(2) / 2\n  local batch_size = outputs:size(1)\n  local player_indexes = {{1, self.bucket_count}, {self.bucket_count + 1, 2 * self.bucket_count}}\n  local players_count = 2\n  for player =1, players_count do \n    local player_idx = player_indexes[player]\n    local opponent_idx = player_indexes[3- player]\n    outputs[{{}, player_idx}]:mm(inputs[{{}, opponent_idx}], self.equity_matrix)\n  end\nend"
  },
  {
    "path": "Source/Nn/net_builder.lua",
    "content": "--- Builds the neural net architecture.\n--\n-- Uses torch's [nn package](https://github.com/torch/nn/blob/master/README.md).\n--\n-- For M buckets, the neural net inputs have size 2*M+1, containing range\n-- vectors over buckets for each player, as well as a feature capturing the\n-- pot size. These are arranged as [{p1\\_range}, {p2\\_range}, pot\\_size].\n--\n-- The neural net outputs have size 2*M, containing counterfactual value\n-- vectors over buckets for each player. These are arranged as\n-- [{p1\\_cfvs}, {p2\\_cfvs}].\n-- @module net_builder\nlocal M = {}\n\nprint \"Loading Net Builder\"\nlocal bucketer = require 'Nn.bucketer'\nlocal river_tools = require 'Nn.Bucketing.river_tools'\nrequire \"nn\"\nrequire 'torch'\nrequire 'math'\n\n\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\n\n--import GPU modules if needed\nif arguments.gpu then\n  require 'cunn'\n  require 'cutorch'\nend\n\n--- Builds a neural net with architecture specified by @{arguments.net}.\n-- @return a newly constructed neural net\nfunction M:build_net(street, raw)\n  local bucket_count = nil\n  if raw ~= nil then\n    bucket_count = bucketer:get_rank_count(street)\n  else\n    bucket_count = bucketer:get_bucket_count(street)\n  end\n  local player_count = 2\n  local output_size = bucket_count * player_count\n  local input_size = output_size + 1\n\n  --run the lua interpreter on the architecture from the command line to get the list of layers\n  local layers_text = 'return ' .. arguments.net\n  layers_text = string.gsub(layers_text, 'input_size', input_size)\n  layers_text = string.gsub(layers_text, 'output_size', output_size)\n  f = loadstring(layers_text)\n  local layers = f()\n\n  local feedforward_part = nn.Sequential()\n\n  --build the network from the layers\n  for _k, layer in pairs(layers) do\n    feedforward_part:add(layer)\n  end\n\n  local right_part = nn.Sequential()\n  right_part:add(nn.Narrow(2, 1, output_size))\n\n  local first_layer = nn.ConcatTable()\n  first_layer:add(feedforward_part)\n  first_layer:add(right_part)\n\n  local left_part_2 = nn.Sequential()\n  left_part_2:add(nn.SelectTable(1))\n\n  local right_part_2  = nn.Sequential()\n  right_part_2:add(nn.DotProduct())\n  right_part_2:add(nn.Replicate(output_size, 2))\n  right_part_2:add(nn.MulConstant(-0.5))\n\n  local second_layer = nn.ConcatTable()\n  second_layer:add(left_part_2)\n  second_layer:add(right_part_2)\n\n  local final_mlp = nn.Sequential()\n  final_mlp:add(first_layer)\n  final_mlp:add(second_layer)\n  --final layer that used delta\n  final_mlp:add(nn.CAddTable())\n\n  return final_mlp\nend\n\nreturn M\n"
  },
  {
    "path": "Source/Nn/next_round_value.lua",
    "content": "--- Uses the neural net to estimate value at the end of the first betting round.\n-- @classmod next_round_value\n\nrequire 'torch'\nrequire 'math'\nlocal bucketer = require 'Nn.bucketer'\nlocal card_tools = require 'Game.card_tools'\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\nlocal constants = require 'Settings.constants'\nlocal tools = require 'tools'\n\nlocal NextRoundValue = torch.class('NextRoundValue')\n\n--- Constructor.\n--\n-- Creates a tensor that can translate hand ranges to bucket ranges\n-- on any board.\n-- @param nn the neural network\n\nfunction NextRoundValue:__init(nn, board, nrv)\n  self.nn = nn\n  if nrv == nil then\n    self:_init_bucketing(board)\n  else\n    self._street = nrv._street\n    self.bucket_count = nrv.bucket_count\n    self.board_count = nrv.board_count\n    self._range_matrix = nrv._range_matrix:clone()\n    self._range_matrix_board_view = self._range_matrix:view(game_settings.hand_count, self.board_count, self.bucket_count)\n    self._reverse_value_matrix = nrv._reverse_value_matrix:clone()\n  end\nend\n\n--- Initializes the tensor that translates hand ranges to bucket ranges.\n-- @local\nfunction NextRoundValue:_init_bucketing(board)\n  local timer = torch.Timer()\n  timer:reset()\n  local street = card_tools:board_to_street(board)\n  self._street = street\n  self.bucket_count = bucketer:get_bucket_count(street+1)\n  local boards = card_tools:get_next_round_boards(board)\n\n  self.board_count = boards:size(1)\n  self._range_matrix = arguments.Tensor(game_settings.hand_count, self.board_count * self.bucket_count ):zero()\n  self._range_matrix_board_view = self._range_matrix:view(game_settings.hand_count, self.board_count, self.bucket_count)\n\n  for idx = 1, self.board_count do\n    local board = boards[idx]\n\n    local buckets = bucketer:compute_buckets(board)\n    local class_ids = torch.range(1, self.bucket_count)\n\n    if arguments.gpu then\n      buckets = buckets:cuda()\n      class_ids = class_ids:cuda()\n    else\n      class_ids = class_ids:float()\n    end\n\n    class_ids = class_ids:view(1, self.bucket_count):expand(game_settings.hand_count, self.bucket_count)\n    local card_buckets = buckets:view(game_settings.hand_count, 1):expand(game_settings.hand_count, self.bucket_count)\n\n    --finding all strength classes\n    --matrix for transformation from card ranges to strength class ranges\n    self._range_matrix_board_view[{{}, idx, {}}][torch.eq(class_ids, card_buckets)] = 1\n  end\n\n  --matrix for transformation from class values to card values\n  self._reverse_value_matrix = self._range_matrix:t():clone()\n  --we need to div the matrix by the sum of possible boards (from point of view of each hand)\n  local num_new_cards = game_settings.board_card_count[street+1] - game_settings.board_card_count[street]\n  local num_cur_cards = game_settings.board_card_count[street]\n\n  local den = tools:choose(\n    game_settings.card_count - num_cur_cards - 2*game_settings.hand_card_count,\n    num_new_cards)\n  local weight_constant = 1/den -- count\n  self._reverse_value_matrix:mul(weight_constant)\n  print(\"nextround init_bucket time: \" .. timer:time().real)\nend\n\n--- Converts a range vector over private hands to a range vector over buckets.\n-- @param card_range a probability vector over private hands\n-- @param bucket_range a vector in which to store the output probabilities\n--  over buckets\n-- @local\nfunction NextRoundValue:_card_range_to_bucket_range(card_range, bucket_range)\n  bucket_range:mm(card_range, self._range_matrix)\nend\n\n--- Converts a value vector over buckets to a value vector over private hands.\n-- @param bucket_value a value vector over buckets\n-- @param card_value a vector in which to store the output values over\n-- private hands\n\n-- @local\nfunction NextRoundValue:_bucket_value_to_card_value(bucket_value, card_value)\n  card_value:mm(bucket_value, self._reverse_value_matrix)\nend\n\n--- Converts a value vector over buckets to a value vector over private hands\n-- given a particular set of board cards.\n-- TODO: fix this\n-- @param board a non-empty vector of board cards\n-- @param bucket_value a value vector over buckets\n-- @param card_value a vector in which to store the output values over\n-- private hands\n-- @local\nfunction NextRoundValue:_bucket_value_to_card_value_on_board(board, bucket_value, card_value)\n  local board_idx = card_tools:get_board_index(board)\n  local board_matrix = self._range_matrix_board_view[{{}, board_idx, {}}]:t()\n  local serialized_card_value = card_value:view(-1, game_settings.hand_count)\n  local serialized_bucket_value = bucket_value[{{}, {}, board_idx, {}}]:clone():view(-1, self.bucket_count)\n  serialized_card_value:mm(serialized_bucket_value, board_matrix)\nend\n\n--- Initializes the value calculator with the pot size of each state that\n-- we are going to evaluate.\n--\n-- During continual re-solving, there is one pot size for each initial state\n-- of the second betting round (before board cards are dealt).\n-- @param pot_sizes a vector of pot sizes\n-- betting round ends\nfunction NextRoundValue:start_computation(pot_sizes, batch_size)\n  self.iter = 0\n  self.pot_sizes = pot_sizes:view(-1, 1):clone()\n  self.pot_sizes = self.pot_sizes:expand(self.pot_sizes:size(1),batch_size):clone()\n  self.pot_sizes = self.pot_sizes:view(-1, 1)\n  self.batch_size = self.pot_sizes:size(1)\nend\n\n--- Gives the predicted counterfactual values at each evaluated state, given\n-- input ranges.\n--\n-- @{start_computation} must be called first. Each state to be evaluated must\n-- be given in the same order that pot sizes were given for that function.\n-- Keeps track of iterations internally, so should be called exactly once for\n-- every iteration of continual re-solving.\n--\n-- @param ranges An Nx2xK tensor, where N is the number of states evaluated\n-- (must match input to @{start_computation}), 2 is the number of players, and\n-- K is the number of private hands. Contains N sets of 2 range vectors.\n-- @param values an Nx2xK tensor in which to store the N sets of 2 value vectors\n-- which are output\nfunction NextRoundValue:get_value(ranges, values)\n  assert(ranges and values)\n  assert(ranges:size(1) == self.batch_size)\n  self.iter = self.iter + 1\n  if self.iter == 1 then\n    --initializing data structures\n    self.next_round_inputs = arguments.Tensor(self.batch_size, self.board_count, (self.bucket_count * constants.players_count + 1)):zero()\n    self.next_round_values = arguments.Tensor(self.batch_size, self.board_count, constants.players_count,  self.bucket_count ):zero()\n    self.transposed_next_round_values = arguments.Tensor(self.batch_size, constants.players_count, self.board_count, self.bucket_count)\n    self.next_round_extended_range = arguments.Tensor(self.batch_size, constants.players_count, self.board_count * self.bucket_count ):zero()\n    self.next_round_serialized_range = self.next_round_extended_range:view(-1, self.bucket_count)\n    self.range_normalization = arguments.Tensor()\n    self.value_normalization = arguments.Tensor(self.batch_size, constants.players_count, self.board_count)\n    --handling pot feature for the nn\n    local den = 0\n    assert(self._street <= 3)\n    if game_settings.nl then\n      den = arguments.stack\n    else\n      if self._street == 4 then\n        den = 48\n      elseif self._street == 3 then\n        den = 48\n      elseif self._street == 2 then\n        den = 24\n      elseif self._street == 1 then\n        den = 10\n      else\n        den = -1\n      end\n    end\n    local nn_bet_input = self.pot_sizes:clone():mul(1/den)\n    nn_bet_input = nn_bet_input:view(-1, 1):expand(self.batch_size, self.board_count)\n    self.next_round_inputs[{{}, {}, {-1}}]:copy(nn_bet_input)\n  end\n\n  --we need to find if we need remember something in this iteration\n  local use_memory = self.iter > arguments.cfr_skip_iters\n  if use_memory and self.iter == arguments.cfr_skip_iters + 1 then\n    --first iter that we need to remember something - we need to init data structures\n    self.range_normalization_memory = arguments.Tensor(self.batch_size * self.board_count * constants.players_count, 1):zero()\n    self.counterfactual_value_memory = arguments.Tensor(self.batch_size, constants.players_count, self.board_count, self.bucket_count):zero()\n  end\n\n  --computing bucket range in next street for both players at once\n  self:_card_range_to_bucket_range(ranges:view(self.batch_size * constants.players_count, -1), self.next_round_extended_range:view(self.batch_size * constants.players_count, -1))\n  self.range_normalization:sum(self.next_round_serialized_range, 2)\n  local rn_view = self.range_normalization:view(self.batch_size, constants.players_count, self.board_count)\n  for player = 1, constants.players_count do\n    self.value_normalization[{{}, player, {}}]:copy(rn_view[{{}, 3 - player, {}}])\n  end\n  if use_memory then\n    self.range_normalization_memory:add(self.value_normalization)\n  end\n  --eliminating division by zero\n  self.range_normalization[torch.eq(self.range_normalization, 0)] = 1\n  self.next_round_serialized_range:cdiv(self.range_normalization:expandAs(self.next_round_serialized_range))\n  local serialized_range_by_player = self.next_round_serialized_range:view(self.batch_size, constants.players_count, self.board_count, self.bucket_count)\n  for player = 1, constants.players_count do\n    local player_range_index = {(player -1) * self.bucket_count + 1, player * self.bucket_count}\n    self.next_round_inputs[{{}, {}, player_range_index}]:copy(self.next_round_extended_range[{{},player, {}}])\n  end\n\n  --using nn to compute values\n  local serialized_inputs_view= self.next_round_inputs:view(self.batch_size * self.board_count, -1)\n  local serialized_values_view= self.next_round_values:view(self.batch_size * self.board_count, -1)\n\n  --computing value in the next round\n  self.nn:get_value(serialized_inputs_view, serialized_values_view)\n\n  --normalizing values back according to the orginal range sum\n  local normalization_view = self.value_normalization:view(self.batch_size, constants.players_count, self.board_count, 1):transpose(2,3)\n  self.next_round_values:cmul(normalization_view:expandAs(self.next_round_values))\n\n  self.transposed_next_round_values:copy(self.next_round_values:transpose(3,2))\n  --remembering the values for the next round\n  if use_memory then\n    self.counterfactual_value_memory:add(self.transposed_next_round_values)\n  end\n  --translating bucket values back to the card values\n  self:_bucket_value_to_card_value(self.transposed_next_round_values:view(self.batch_size * constants.players_count, -1), values:view(self.batch_size * constants.players_count, -1))\nend\n\n--- Gives the average counterfactual values on the given board across previous\n-- calls to @{get_value}.\n--\n-- Used to update opponent counterfactual values during re-solving after board\n-- cards are dealt.\n-- @param board a non-empty vector of board cards\n-- @param values a tensor in which to store the values\nfunction NextRoundValue:get_value_on_board(board, values)\n  --check if we have evaluated correct number of iterations\n  assert(self.iter == arguments.cfr_iters )\n  local batch_size = values:size(1)\n  assert(batch_size == self.batch_size)\n\n  self:_prepare_next_round_values()\n\n  self:_bucket_value_to_card_value_on_board(board, self.counterfactual_value_memory, values)\nend\n\n--- Normalizes the counterfactual values remembered between @{get_value} calls\n-- so that they are an average rather than a sum.\n-- @local\nfunction NextRoundValue:_prepare_next_round_values()\n\n  assert(self.iter == arguments.cfr_iters )\n\n  --do nothing if already prepared\n  if self._values_are_prepared then\n    return\n  end\n\n  --eliminating division by zero\n  self.range_normalization_memory[torch.eq(self.range_normalization_memory, 0)] = 1\n  local serialized_memory_view = self.counterfactual_value_memory:view(-1, self.bucket_count)\n  serialized_memory_view:cdiv(self.range_normalization_memory:expandAs(serialized_memory_view))\n\n  self._values_are_prepared = true\nend\n"
  },
  {
    "path": "Source/Nn/next_round_value_pre.lua",
    "content": "--- Uses the neural net to estimate value at the end of the first betting round.\n-- @classmod next_round_value\n\nrequire 'torch'\nrequire 'math'\nlocal bucketer = require 'Nn.bucketer'\nlocal card_tools = require 'Game.card_tools'\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\nlocal constants = require 'Settings.constants'\nlocal tools = require 'tools'\n\nlocal NextRoundValuePre = torch.class('NextRoundValuePre')\n\n--- Constructor.\n--\n-- Creates a tensor that can translate hand ranges to bucket ranges\n-- on any board.\n-- @param nn the neural network\n\nfunction NextRoundValuePre:__init(nn, aux_nn, board)\n  self.nn = nn\n  self.aux_nn = aux_nn\n  self:_init_bucketing(board)\nend\n\n--- Initializes the tensor that translates hand ranges to bucket ranges.\n-- @local\nfunction NextRoundValuePre:_init_bucketing(board)\n  local street = card_tools:board_to_street(board)\n  self._street = street\n  self.bucket_count = bucketer:get_bucket_count(street+1)\n  local boards = card_tools:get_next_round_boards(board)\n  self.boards = boards\n\n  self.board_count = boards:size(1)\n  self.board_buckets = arguments.Tensor(self.board_count, game_settings.hand_count)\n\n  for idx = 1, self.board_count do\n    if idx % 100 == 0 then\n      print(idx)\n    end\n    local board = self.boards[idx]\n    self.board_buckets[{idx,{}}]:copy(bucketer:compute_buckets(board))\n  end\n  self.impossible_mask = torch.lt(self.board_buckets,0)\n  self.board_indexes = self.board_buckets:clone()\n  self.board_indexes:maskedFill(self.impossible_mask, 1)\n  self.board_indexes_scatter = self.board_buckets:clone()\n  self.board_indexes_scatter:maskedFill(self.impossible_mask, self.bucket_count+1)\n\n  if arguments.gpu then\n    self.board_indexes = self.board_indexes:cudaLong()\n    self.board_indexes_scatter = self.board_indexes_scatter:cudaLong()\n  else\n    self.board_indexes = self.board_indexes:long()\n    self.board_indexes_scatter = self.board_indexes_scatter:long()\n  end\n\n  -- compute aux variables\n  self.bucket_count_aux = bucketer:get_bucket_count(street)\n  local pf_buckets = bucketer:compute_buckets(arguments.Tensor({}))\n\n  local class_ids = torch.range(1, self.bucket_count_aux)\n\n  if arguments.gpu then\n    class_ids = class_ids:cuda()\n  else\n    class_ids = class_ids:float()\n  end\n  class_ids = class_ids:view(1, self.bucket_count_aux):expand(game_settings.hand_count, self.bucket_count_aux)\n  local card_buckets = pf_buckets:view(game_settings.hand_count, 1):expand(game_settings.hand_count, self.bucket_count_aux)\n\n  self._range_matrix_aux = arguments.Tensor(game_settings.hand_count, self.bucket_count_aux):zero()\n  self._range_matrix_aux[torch.eq(class_ids, card_buckets)] = 1\n  self._reverse_value_matrix_aux = self._range_matrix_aux:t():clone()\n\n  local num_new_cards = game_settings.board_card_count[2] - game_settings.board_card_count[1]\n  local num_cur_cards = game_settings.board_card_count[1]\n\n  local den = tools:choose(\n    game_settings.card_count - num_cur_cards - 2*game_settings.hand_card_count,\n    num_new_cards)\n  self.weight_constant = 1/den\nend\n\n--- Converts a range vector over private hands to a range vector over buckets.\n-- @param card_range a probability vector over private hands\n-- @param bucket_range a vector in which to store the output probabilities\n--  over buckets\n-- @local\nfunction NextRoundValuePre:_card_range_to_bucket_range(card_range, bucket_range)\n  local other_bucket_range = bucket_range:view(-1,self.board_count,self.bucket_count + 1):zero()\n\n  local indexes = self.board_indexes_scatter:view(1,self.board_count, game_settings.hand_count)\n    :expand(bucket_range:size(1), self.board_count, game_settings.hand_count)\n  other_bucket_range:scatterAdd(\n    3,\n    indexes,\n    card_range\n      :view(-1,1,game_settings.hand_count)\n      :expand(card_range:size(1),self.board_count, game_settings.hand_count))\nend\n\nfunction NextRoundValuePre:_card_range_to_bucket_range_aux(card_range, bucket_range)\n  bucket_range:mm(card_range, self._range_matrix_aux)\nend\n\nfunction NextRoundValuePre:_card_range_to_bucket_range_on_board(board_idx, card_range, bucket_range)\n  local other_bucket_range = bucket_range:view(-1,self.bucket_count + 1):zero()\n\n  local indexes = self.board_indexes_scatter:view(1,self.board_count, game_settings.hand_count)[{{},board_idx,{}}]\n    :expand(bucket_range:size(1), game_settings.hand_count)\n  other_bucket_range:scatterAdd(\n    2,\n    indexes,\n    card_range\n      :view(-1,game_settings.hand_count)\n      :expand(card_range:size(1), game_settings.hand_count))\nend\n\n--- Converts a value vector over buckets to a value vector over private hands.\n-- @param bucket_value a value vector over buckets\n-- @param card_value a vector in which to store the output values over\n-- private hands\n\n-- @local\nfunction NextRoundValuePre:_bucket_value_to_card_value(bucket_value, card_value)\n  local indexes = self.board_indexes:view(1,self.board_count, game_settings.hand_count)\n    :expand(bucket_value:size(1), self.board_count, game_settings.hand_count)\n\n  self.values_per_board:gather(bucket_value:view(bucket_value:size(1), self.board_count, self.bucket_count), 3, indexes)\n  local impossible = self.impossible_mask:view(1,self.board_count, game_settings.hand_count)\n    :expand(bucket_value:size(1), self.board_count, game_settings.hand_count)\n  self.values_per_board:maskedFill(impossible,0)\n  card_value:sum(self.values_per_board,2)\n  card_value:mul(self.weight_constant)\nend\n\nfunction NextRoundValuePre:_bucket_value_to_card_value_aux(bucket_value, card_value)\n  card_value:mm(bucket_value, self._reverse_value_matrix_aux)\nend\n\n--- Converts a value vector over buckets to a value vector over private hands\n-- given a particular set of board cards.\n-- TODO: fix this\n-- @param board a non-empty vector of board cards\n-- @param bucket_value a value vector over buckets\n-- @param card_value a vector in which to store the output values over\n-- private hands\n-- @local\nfunction NextRoundValuePre:_bucket_value_to_card_value_on_board(board, bucket_value, card_value)\n  local board_idx = card_tools:get_flop_board_index(board)\n  local indexes = self.board_indexes:view(1,self.board_count, game_settings.hand_count)[{{},board_idx,{}}]\n    :expand(bucket_value:size(1), game_settings.hand_count)\n\n  self.values_per_board:gather(bucket_value:view(bucket_value:size(1), self.bucket_count), 2, indexes)\n  local impossible = self.impossible_mask:view(1,self.board_count, game_settings.hand_count)[{{},board_idx,{}}]\n    :expand(bucket_value:size(1), game_settings.hand_count)\n  self.values_per_board:maskedFill(impossible,0)\n  card_value:copy(self.values_per_board)\nend\n\n--- Initializes the value calculator with the pot size of each state that\n-- we are going to evaluate.\n--\n-- During continual re-solving, there is one pot size for each initial state\n-- of the second betting round (before board cards are dealt).\n-- @param pot_sizes a vector of pot sizes\n-- betting round ends\nfunction NextRoundValuePre:start_computation(pot_sizes, batch_size)\n  self.iter = 0\n  if pot_sizes:dim() == 0 then\n    return\n  end\n  self.pot_sizes = pot_sizes:view(-1, 1):clone()\n  self.pot_sizes = self.pot_sizes:expand(self.pot_sizes:size(1),batch_size):clone()\n  self.pot_sizes = self.pot_sizes:view(-1, 1)\n  self.batch_size = self.pot_sizes:size(1)\nend\n\nfunction NextRoundValuePre:get_value_aux(ranges, values, next_board_idx)\n  assert(ranges and values)\n  assert(ranges:size(1) == self.batch_size, self.batch_size .. \" \" .. ranges:size(1))\n  self.iter = self.iter + 1\n  if self.iter == 1 then\n    self.next_round_inputs = arguments.Tensor(self.batch_size, (self.bucket_count_aux * constants.players_count + 1)):zero()\n    self.next_round_values = arguments.Tensor(self.batch_size, constants.players_count, self.bucket_count_aux):zero()\n    self.next_round_extended_range = arguments.Tensor(self.batch_size, constants.players_count, self.bucket_count_aux):zero()\n    self.next_round_serialized_range = self.next_round_extended_range:view(-1, self.bucket_count_aux)\n    self.values_per_board = arguments.Tensor(self.batch_size * constants.players_count, game_settings.hand_count)\n    self.range_normalization = arguments.Tensor()\n    self.value_normalization = arguments.Tensor(self.batch_size, constants.players_count)\n\n    local den = 0\n    assert(self._street <= 3)\n\n    if game_settings.nl then\n      den = arguments.stack\n    else\n      if self._street == 4 then\n        den = 48\n      elseif self._street == 3 then\n        den = 48\n      elseif self._street == 2 then\n        den = 24\n      elseif self._street == 1 then\n        den = 10\n      else\n        den = -1\n      end\n    end\n\n    --handling pot feature for the nn\n    local nn_bet_input = self.pot_sizes:clone():mul(1/den)\n    self.next_round_inputs[{{}, {-1}}]:copy(nn_bet_input)\n  end\n  local use_memory = self.iter > arguments.cfr_skip_iters and next_board_idx ~= nil\n  if use_memory and self.iter == arguments.cfr_skip_iters + 1 then\n    --first iter that we need to remember something - we need to init data structures\n    self.bucket_range_on_board = arguments.Tensor(self.batch_size * constants.players_count, self.bucket_count)\n    self.range_normalization_on_board = arguments.Tensor()\n    self.value_normalization_on_board = arguments.Tensor(self.batch_size, constants.players_count)\n    self.range_normalization_memory = arguments.Tensor(self.batch_size * constants.players_count, 1):zero()\n    self.counterfactual_value_memory = arguments.Tensor(self.batch_size, constants.players_count, self.bucket_count):zero()\n    self.next_round_extended_range_on_board = arguments.Tensor(self.batch_size, constants.players_count, self.bucket_count + 1):zero()\n    self.next_round_serialized_range_on_board = self.next_round_extended_range_on_board:view(-1, self.bucket_count + 1)\n    self.next_round_inputs_on_board = arguments.Tensor(self.batch_size, (self.bucket_count * constants.players_count + 1)):zero()\n    self.next_round_values_on_board = arguments.Tensor(self.batch_size, constants.players_count, self.bucket_count):zero()\n\n    -- copy pot features over\n    self.next_round_inputs_on_board[{{}, {-1}}]:copy(self.next_round_inputs[{{},{-1}}])\n  end\n\n  --computing bucket range in next street for both players at once\n  self:_card_range_to_bucket_range_aux(\n    ranges:view(self.batch_size * constants.players_count, -1),\n    self.next_round_extended_range:view(self.batch_size * constants.players_count, -1))\n\n  self.range_normalization:sum(self.next_round_serialized_range[{{},{1,self.bucket_count_aux}}], 2)\n  local rn_view = self.range_normalization:view(self.batch_size, constants.players_count)\n  for player = 1, constants.players_count do\n    self.value_normalization[{{}, player}]:copy(rn_view[{{}, 3 - player}])\n  end\n\n  if use_memory then\n    self:_card_range_to_bucket_range_on_board(\n      next_board_idx,\n      ranges:view(self.batch_size * constants.players_count, -1),\n      self.next_round_extended_range_on_board:view(self.batch_size * constants.players_count, -1))\n\n    self.range_normalization_on_board:sum(self.next_round_serialized_range_on_board[{{},{1,self.bucket_count}}], 2)\n    local rnb_view = self.range_normalization_on_board:view(self.batch_size, constants.players_count)\n    for player = 1, constants.players_count do\n      self.value_normalization_on_board[{{}, player}]:copy(rnb_view[{{}, 3 - player}])\n    end\n    self.range_normalization_memory:add(self.value_normalization_on_board)\n  end\n\n  --eliminating division by zero\n  self.range_normalization[torch.eq(self.range_normalization, 0)] = 1\n  self.next_round_serialized_range:cdiv(self.range_normalization:expandAs(self.next_round_serialized_range))\n  for player = 1, constants.players_count do\n    local player_range_index = {(player -1) * self.bucket_count_aux + 1, player * self.bucket_count_aux}\n    self.next_round_inputs[{{}, player_range_index}]:copy(self.next_round_extended_range[{{},player, {1, self.bucket_count_aux}}])\n  end\n\n  --using nn to compute values\n  local serialized_inputs_view= self.next_round_inputs:view(self.batch_size, -1)\n  local serialized_values_view= self.next_round_values:view(self.batch_size, -1)\n\n  --computing value in the next round\n  self.aux_nn:get_value(serialized_inputs_view, serialized_values_view)\n\n  if use_memory then\n    --eliminating division by zero\n    self.range_normalization_on_board[torch.eq(self.range_normalization_on_board, 0)] = 1\n    self.next_round_serialized_range_on_board:cdiv(self.range_normalization_on_board:expandAs(self.next_round_serialized_range_on_board))\n    for player = 1, constants.players_count do\n      local player_range_index = {(player -1) * self.bucket_count + 1, player * self.bucket_count}\n      self.next_round_inputs_on_board[{{}, player_range_index}]:copy(self.next_round_extended_range_on_board[{{},player, {1, self.bucket_count}}])\n    end\n\n    --using nn to compute values\n    local serialized_inputs_view_on_board = self.next_round_inputs_on_board:view(self.batch_size, -1)\n    local serialized_values_view_on_board = self.next_round_values_on_board:view(self.batch_size, -1)\n\n    --computing value in the next round\n    self.nn:get_value(serialized_inputs_view_on_board, serialized_values_view_on_board)\n  end\n\n  --normalizing values back according to the orginal range sum\n  local normalization_view = self.value_normalization:view(self.batch_size, constants.players_count, 1)\n  self.next_round_values:cmul(normalization_view:expandAs(self.next_round_values))\n\n  if use_memory then\n    local normalization_view_on_board = self.value_normalization_on_board:view(self.batch_size, constants.players_count, 1)\n    self.next_round_values_on_board:cmul(normalization_view_on_board:expandAs(self.next_round_values_on_board))\n    self.counterfactual_value_memory:add(self.next_round_values_on_board)\n  end\n\n  --remembering the values for the next round\n\n  --translating bucket values back to the card values\n  self:_bucket_value_to_card_value_aux(\n    self.next_round_values:view(self.batch_size * constants.players_count, -1),\n    values:view(self.batch_size * constants.players_count, -1))\nend\n\n--- Gives the predicted counterfactual values at each evaluated state, given\n-- input ranges.\n--\n-- @{start_computation} must be called first. Each state to be evaluated must\n-- be given in the same order that pot sizes were given for that function.\n-- Keeps track of iterations internally, so should be called exactly once for\n-- every iteration of continual re-solving.\n--\n-- @param ranges An Nx2xK tensor, where N is the number of states evaluated\n-- (must match input to @{start_computation}), 2 is the number of players, and\n-- K is the number of private hands. Contains N sets of 2 range vectors.\n-- @param values an Nx2xK tensor in which to store the N sets of 2 value vectors\n-- which are output\nfunction NextRoundValuePre:get_value(ranges, values)\n  assert(ranges and values)\n  assert(ranges:size(1) == self.batch_size)\n  self.iter = self.iter + 1\n  print(self.iter)\n  if self.iter == 1 then\n    self.next_round_inputs = arguments.Tensor(self.batch_size, self.board_count, (self.bucket_count * constants.players_count + 1)):zero()\n    self.next_round_values = arguments.Tensor(self.batch_size, self.board_count, constants.players_count,  self.bucket_count ):zero()\n    self.transposed_next_round_values = arguments.Tensor(self.batch_size, constants.players_count, self.board_count, self.bucket_count)\n    self.next_round_extended_range = arguments.Tensor(self.batch_size, constants.players_count, self.board_count, self.bucket_count + 1):zero()\n    self.next_round_serialized_range = self.next_round_extended_range:view(-1, self.bucket_count + 1)\n    self.values_per_board = arguments.Tensor(self.batch_size * constants.players_count, self.board_count, game_settings.hand_count)\n    self.range_normalization = arguments.Tensor()\n    self.value_normalization = arguments.Tensor(self.batch_size, constants.players_count, self.board_count)\n\n    local den = 0\n    assert(self._street <= 3)\n\n    if game_settings.nl then\n      den = arguments.stack\n    else\n      if self._street == 4 then\n        den = 48\n      elseif self._street == 3 then\n        den = 48\n      elseif self._street == 2 then\n        den = 24\n      elseif self._street == 1 then\n        den = 10\n      else\n        den = -1\n      end\n    end\n\n    --handling pot feature for the nn\n    local nn_bet_input = self.pot_sizes:clone():mul(1/den)\n    nn_bet_input = nn_bet_input:view(-1, 1):expand(self.batch_size, self.board_count)\n    self.next_round_inputs[{{}, {}, {-1}}]:copy(nn_bet_input)\n  end\n\n  --computing bucket range in next street for both players at once\n  self:_card_range_to_bucket_range(\n    ranges:view(self.batch_size * constants.players_count, -1),\n    self.next_round_extended_range:view(self.batch_size * constants.players_count, -1))\n\n  self.range_normalization:sum(self.next_round_serialized_range[{{},{1,self.bucket_count}}], 2)\n  local rn_view = self.range_normalization:view(self.batch_size, constants.players_count, self.board_count)\n  for player = 1, constants.players_count do\n    self.value_normalization[{{}, player, {}}]:copy(rn_view[{{}, 3 - player, {}}])\n  end\n\n  --eliminating division by zero\n  self.range_normalization[torch.eq(self.range_normalization, 0)] = 1\n  self.next_round_serialized_range:cdiv(self.range_normalization:expandAs(self.next_round_serialized_range))\n  for player = 1, constants.players_count do\n    local player_range_index = {(player -1) * self.bucket_count + 1, player * self.bucket_count}\n    self.next_round_inputs[{{}, {}, player_range_index}]:copy(self.next_round_extended_range[{{},player, {}, {1, self.bucket_count}}])\n  end\n\n  --using nn to compute values\n  local serialized_inputs_view= self.next_round_inputs:view(self.batch_size * self.board_count, -1)\n  local serialized_values_view= self.next_round_values:view(self.batch_size * self.board_count, -1)\n\n  --computing value in the next round\n  self.nn:get_value(serialized_inputs_view, serialized_values_view)\n\n  --normalizing values back according to the orginal range sum\n  local normalization_view = self.value_normalization:view(self.batch_size, constants.players_count, self.board_count, 1):transpose(2,3)\n  self.next_round_values:cmul(normalization_view:expandAs(self.next_round_values))\n\n  self.transposed_next_round_values:copy(self.next_round_values:transpose(3,2))\n  --remembering the values for the next round\n\n  --translating bucket values back to the card values\n  self:_bucket_value_to_card_value(\n    self.transposed_next_round_values:view(self.batch_size * constants.players_count, -1),\n    values:view(self.batch_size * constants.players_count, -1))\n\nend\n\n--- Gives the average counterfactual values on the given board across previous\n-- calls to @{get_value}.\n--\n-- Used to update opponent counterfactual values during re-solving after board\n-- cards are dealt.\n-- @param board a non-empty vector of board cards\n-- @param values a tensor in which to store the values\nfunction NextRoundValuePre:get_value_on_board(board, values)\n  --check if we have evaluated correct number of iterations\n  assert(self.iter == arguments.cfr_iters )\n  local batch_size = values:size(1)\n  assert(batch_size == self.batch_size)\n\n  self.range_normalization_memory[torch.eq(self.range_normalization_memory, 0)] = 1\n  local serialized_memory_view = self.counterfactual_value_memory:view(-1, self.bucket_count)\n  serialized_memory_view:cdiv(self.range_normalization_memory:expandAs(serialized_memory_view))\n\n  self:_bucket_value_to_card_value_on_board(\n    board,\n    self.counterfactual_value_memory:view(self.batch_size * constants.players_count, -1),\n    values:view(self.batch_size * constants.players_count, -1))\nend\n"
  },
  {
    "path": "Source/Nn/next_round_value_test.lua",
    "content": "require 'Nn.next_round_value'\n--require 'Nn.mock_nn'\nrequire 'Nn.mock_nn_terminal'\nrequire 'TerminalEquity.terminal_equity'\n\n\nrequire 'Nn.value_nn'\n\n\n\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nlocal card_tools = require 'Game.card_tools'\n\n\n--local next_round_value =  NextRoundValue()\n--print(next_round_value._range_matrix)\n--[[ test of card to bucket range translation\nlocal range = torch.range(1, 6):float():view(1, -1)\nlocal next_round_range = arguments.Tensor(1, next_round_value.bucket_count * next_round_value.board_count)\nnext_round_value:_card_range_to_bucket_range(range, next_round_range)\nprint(next_round_range)\n]]\n\n--test of get_value functionality\nlocal mock_nn = MockNnTerminal()\n--local mock_nn = ValueNn()\nlocal next_round_value = NextRoundValue(mock_nn)\n\n--local bets = torch.range(1,1):float():mul(100)\nlocal bets = torch.Tensor(1):fill(1200)\n\nnext_round_value:start_computation(bets)\n\nlocal ranges = arguments.Tensor(1, 2, game_settings.card_count):fill(1/4)\nlocal values = arguments.Tensor(1, 2, game_settings.card_count)\n\n\nlocal x = arguments.Tensor()\ntorch.manualSeed(0)\nranges[1][1]:copy(torch.Tensor({1,1,0,0,0,0}))\nranges[1][2]:copy(torch.Tensor({1,1,1,1,1,1}))\n\nnext_round_value:get_value(ranges, values)\n\nprint(values)\n\n--[[\nlocal ranges_2 = ranges:view(2, game_settings.card_count):clone()\nlocal values_2 = ranges_2:clone():fill(-1)\n\nlocal terminal_equity = TerminalEquity()\nterminal_equity:set_board(torch.Tensor{})\nterminal_equity:call_value(ranges_2, values_2)\nprint('terminal_equity')\nprint(values_2)\n]]\n\n--[[\nlocal board = card_to_string:string_to_board('Ks')\n\nlocal values_3 = values:clone():fill(-1)\nnext_round_value:get_value_on_board(board, values_3)\n\nprint(values_3)\n]]\n"
  },
  {
    "path": "Source/Nn/value_nn.lua",
    "content": "--- Wraps the calls to the final neural net.\n-- @classmod value_nn\n\nrequire 'torch'\nrequire 'nn'\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\n\nlocal ValueNn = torch.class('ValueNn')\n\n--- Constructor. Loads the neural net from disk.\nfunction ValueNn:__init(street, aux)\n  local net_file = arguments.model_path\n  if game_settings.nl then\n    net_file = net_file .. \"NoLimit/\"\n  else\n    net_file = net_file .. \"Limit/\"\n  end\n\n  assert(street <= 3)\n\n  if aux then\n    assert(street == 1)\n    net_file = net_file .. \"preflop-aux/\"\n  else\n    if street == 3 then\n      net_file = net_file .. \"river/\"\n    elseif street == 2 then\n      net_file = net_file .. \"turn/\"\n    elseif street == 1 then\n      net_file = net_file .. \"flop/\"\n    end\n  end\n  net_file = net_file .. arguments.value_net_name\n\n  --0.0 select the correct model cpu/gpu\n  if arguments.gpu then\n    net_file = net_file .. '_gpu'\n  else\n    net_file = net_file .. '_cpu'\n  end\n\n  --1.0 load model information\n  local model_information = torch.load(net_file .. '.info')\n\n  print('NN information:')\n  for k, v in pairs(model_information) do\n    print(k, v)\n  end\n  --import GPU modules only if needed\n  if arguments.gpu then\n    require 'cunn'\n    require 'cutorch'\n  end\n\n  --2.0 try to load model\n  if pcall(torch.load, net_file .. '.model') then\n    self.mlp = torch.load(net_file .. '.model')\n    self.mlp:evaluate(true)\n    print('NN architecture:')\n    print(self.mlp)\n  end\nend\n\n--- Gives the neural net output for a batch of inputs.\n-- @param inputs An NxI tensor containing N instances of neural net inputs.\n-- See @{net_builder} for details of each input.\n-- @param output An NxO tensor in which to store N sets of neural net outputs.\n-- See @{net_builder} for details of each output.\nfunction ValueNn:get_value(inputs, output)\n  output:copy(self.mlp:forward(inputs))\nend\n"
  },
  {
    "path": "Source/Player/continual_resolving.lua",
    "content": "--- Performs the main steps of continual re-solving, tracking player range\n-- and opponent counterfactual values so that re-solving can be done at each\n-- new game state.\n-- @classmod continual_resolving\n\nrequire 'Lookahead.resolving'\nrequire 'TerminalEquity.terminal_equity'\n\nlocal arguments = require 'Settings.arguments'\nlocal constants = require \"Settings.constants\"\nlocal game_settings = require 'Settings.game_settings'\nlocal card_tools = require 'Game.card_tools'\nlocal card_to_string = require 'Game.card_to_string_conversion'\n\nlocal ContinualResolving = torch.class('ContinualResolving')\n\n--- Constructor. Does a depth-limited solve of the game's first node.\nfunction ContinualResolving:__init()\n  self.starting_player_range = card_tools:get_uniform_range(arguments.Tensor{})\n  self.terminal_equity = TerminalEquity()\n  self:resolve_first_node()\nend\n\n--- Solves a depth-limited lookahead from the first node of the game to get\n-- opponent counterfactual values.\n--\n-- The cfvs are stored in the field `starting_cfvs_p1`. Because this is the\n-- first node of the game, exact ranges are known for both players, so\n-- opponent cfvs are not necessary for solving.\nfunction ContinualResolving:resolve_first_node()\n  local first_node = {}\n  first_node.board = arguments.Tensor{}\n  first_node.street = 1\n  first_node.current_player = constants.players.P1\n  first_node.bets = arguments.Tensor{arguments.sb, arguments.bb}\n  first_node.num_bets = 1\n\n  self.terminal_equity:set_board(first_node.board)\n  --create the starting ranges\n  local player_range = card_tools:get_uniform_range(first_node.board)\n  local opponent_range = card_tools:get_uniform_range(first_node.board)\n\n  --create re-solving and re-solve the first node\n  self.first_node_resolving = Resolving(self.terminal_equity)\n  self.first_node_resolving:resolve_first_node(first_node, player_range, opponent_range)\n  --store the initial CFVs\n  self.starting_cfvs_p1 = self.first_node_resolving:get_root_cfv()\nend\n\n--- Re-initializes the continual re-solving to start a new game from the root\n-- of the game tree.\n-- @param state the first state where the re-solving player acts in the new\n-- game (a table of the type returned by @{protocol_to_node.parse_state})\nfunction ContinualResolving:start_new_hand(state)\n  self.last_node = nil\n  self.decision_id = 0\n  self.position = state.position\n  self.hand_id = state.hand_id\nend\n\n--- Re-solves a node to choose the re-solving player's next action.\n-- @param node the game node where the re-solving player is to act (a table of\n-- the type returned by @{protocol_to_node.parsed_state_to_node})\n-- @param state the game state where the re-solving player is to act\n-- (a table of the type returned by @{protocol_to_node.parse_state})\n-- @local\nfunction ContinualResolving:_resolve_node(node, state)\n  assert(self.decision_id)\n  --1.0 first node and P1 position\n  --no need to update an invariant since this is the very first situation\n  if self.decision_id == 0 and self.position == constants.players.P1 then\n    --the strategy computation for the first decision node has been already set up\n    self.current_player_range = self.starting_player_range:clone()\n    self.resolving = self.first_node_resolving\n  --2.0 other nodes - we need to update the invariant\n  else\n    assert(not node.terminal)\n    assert(node.current_player == self.position)\n\n    --2.1 update the invariant based on actions we did not make\n    self:_update_invariant(node, state)\n\n    local timer = torch.Timer()\n    timer:reset()\n\n    --2.2 re-solve\n    self.terminal_equity:set_board(node.board)\n\n    print('term equity time: ' .. timer:time().real)\n    timer:reset()\n    self.resolving = Resolving(self.terminal_equity)\n    self.resolving:resolve(node, self.current_player_range, self.current_opponent_cfvs_bound)\n  end\nend\n\n--- Updates the player's range and the opponent's counterfactual values to be\n-- consistent with game actions since the last re-solved state.\n-- Updates it only for actions we did not make, since we update the invariant for our action as soon as we make it.\n--\n-- @param node the game node where the re-solving player is to act (a table of\n-- the type returned by @{protocol_to_node.parsed_state_to_node})\n-- @param state the game state where the re-solving player is to act\n-- (a table of the type returned by @{protocol_to_node.parse_state})\n-- @local\nfunction ContinualResolving:_update_invariant(node, state)\n  --1.0 street has changed\n  if self.last_node and self.last_node.street ~= node.street then\n    assert(self.last_node.street + 1 == node.street)\n\n    --1.1 opponent cfvs\n    --if the street has changed, the resonstruction API simply gives us CFVs\n    self.current_opponent_cfvs_bound = self.resolving:get_chance_action_cfv(self.last_bet, node.board)\n\n    --1.2 player range\n    --if street has change, we have to mask out the colliding hands\n    self.current_player_range = card_tools:normalize_range(node.board, self.current_player_range)\n  --2.0 first decision for P2\n  elseif self.decision_id == 0 then\n    assert(self.position == constants.players.P2)\n    assert(node.street == 1)\n\n    self.current_player_range = self.starting_player_range:clone()\n    self.current_opponent_cfvs_bound = self.starting_cfvs_p1:clone()\n  --3.0 handle game within the street\n  else\n    assert(self.last_node.street == node.street)\n  end\nend\n\n--- Re-solves a node and chooses the re-solving player's next action.\n-- @param node the game node where the re-solving player is to act (a table of\n-- the type returned by @{protocol_to_node.parsed_state_to_node})\n-- @param state the game state where the re-solving player is to act\n-- (a table of the type returned by @{protocol_to_node.parse_state})\n-- @return an action sampled from the re-solved strategy at the given state,\n-- with the fields:\n--\n-- * `action`: an element of @{constants.acpc_actions}\n--\n-- * `raise_amount`: the number of chips to raise (if `action` is raise)\nfunction ContinualResolving:compute_action(node, state)\n  self:_resolve_node(node, state)\n  local sampled_bet = self:_sample_bet(node, state)\n\n  self.decision_id = self.decision_id + 1\n  self.last_bet = sampled_bet\n  self.last_node = node\n\n  local out = self:_bet_to_action(node, sampled_bet)\n  return out\nend\n\n--- Samples an action to take from the strategy at the given game state.\n-- @param node the game node where the re-solving player is to act (a table of\n-- the type returned by @{protocol_to_node.parsed_state_to_node})\n-- @param state the game state where the re-solving player is to act\n-- (a table of the type returned by @{protocol_to_node.parse_state})\n-- @return an index representing the action chosen\n-- @local\nfunction ContinualResolving:_sample_bet(node, state)\n  --1.0 get the possible bets in the node\n  local possible_bets = self.resolving:get_possible_actions()\n  local actions_count = possible_bets:size(1)\n\n  --2.0 get the strategy for the current hand since the strategy is computed for all hands\n  local hand_strategy = arguments.Tensor(actions_count)\n\n  for i = 1, actions_count do\n    local action_bet = possible_bets[i]\n    local action_strategy = self.resolving:get_action_strategy(action_bet)\n    hand_strategy[i] = action_strategy[self.hand_id]\n  end\n\n  assert(math.abs(1 - hand_strategy:sum()) < 0.001)\n\n  print(\"strategy:\")\n  print(hand_strategy)\n\n  --3.0 sample the action by doing cumsum and uniform sample\n  local hand_strategy_cumsum = torch.cumsum(hand_strategy)\n  local r = torch.uniform()\n\n  local sampled_bet = possible_bets[hand_strategy_cumsum:gt(r)][1]\n  print(\"playing action that has prob: \" .. hand_strategy[hand_strategy_cumsum:gt(r)][1])\n\n  --4.0 update the invariants based on our action\n  self.current_opponent_cfvs_bound = self.resolving:get_action_cfv(sampled_bet)\n\n  local strategy = self.resolving:get_action_strategy(sampled_bet)\n  self.current_player_range:cmul(strategy)\n  self.current_player_range = card_tools:normalize_range(node.board, self.current_player_range)\n\n  return sampled_bet\nend\n\n--- Converts an internal action representation into a cleaner format.\n-- @param node the game node where the re-solving player is to act (a table of\n-- the type returned by @{protocol_to_node.parsed_state_to_node})\n-- @param sampled_bet the index of the action to convert\n-- @return a table specifying the action, with the fields:\n--\n-- * `action`: an element of @{constants.acpc_actions}\n--\n-- * `raise_amount`: the number of chips to raise (if `action` is raise)\n-- @local\nfunction ContinualResolving:_bet_to_action(node, sampled_bet)\n  if sampled_bet == constants.actions.fold then\n    return {action = constants.acpc_actions.fold}\n  elseif sampled_bet == constants.actions.ccall then\n    return {action = constants.acpc_actions.ccall}\n  else\n    assert(sampled_bet >= 0)\n    return {action = constants.acpc_actions.raise, raise_amount = sampled_bet}\n  end\nend\n"
  },
  {
    "path": "Source/Player/deepstack.lua",
    "content": "--- Performs the main loop for DeepStack.\n-- @script deepstack\n\nlocal arguments = require 'Settings.arguments'\nrequire \"ACPC.acpc_game\"\nrequire \"Player.continual_resolving\"\n\nlocal port = 0\nif #arg > 0 then\n  port = tonumber(arg[1])\nelse\n  print(\"need port\")\n  return\nend\n\ntorch.manualSeed(0)\n\n--1.0 create the ACPC game and connect to the server\nlocal acpc_game = ACPCGame()\nacpc_game:connect(arguments.acpc_server, port)\n\nlocal continual_resolving = ContinualResolving()\n\nlocal last_state = nil\nlocal last_node = nil\n\n--2.0 main loop that waits for a situation where we act and then chooses an action\nwhile true do\n  local state\n  local node\n\n  --2.1 blocks until it's our situation/turn\n  state, node = acpc_game:get_next_situation()\n\n  --did a new hand start?\n  if not last_state or last_state.hand_number ~= state.hand_number or node.street < last_node.street then\n    continual_resolving:start_new_hand(state)\n  end\n\n  --2.2 use continual resolving to find a strategy and make an action in the current node\n  local adviced_action = continual_resolving:compute_action(node, state)\n\n  --2.3 send the action to the dealer\n  acpc_game:play_action(adviced_action)\n\n  last_state = state\n  last_node = node\n\n  collectgarbage();collectgarbage()\nend\n"
  },
  {
    "path": "Source/Player/deepstack_server.lua",
    "content": "--- Performs the main loop for DeepStack.\n-- @script deepstack\n\nlocal arguments = require 'Settings.arguments'\nlocal socket = require(\"socket\")\nlocal constants = require \"Settings.constants\"\n\nrequire \"ACPC.acpc_game\"\nrequire \"Player.continual_resolving\"\n\n--1.0 create the ACPC game and connect to the server\nlocal acpc_game = ACPCGame()\n\nlocal continual_resolving = ContinualResolving()\n\nlocal last_state = nil\nlocal last_node = nil\n-- load namespace\n-- create a TCP socket and bind it to the local host, at any port\nlocal server = assert(socket.bind(\"*\", 0))\nlocal ip, port = server:getsockname()\nprint(ip .. \": \" .. port)\n\nlocal client = server:accept()\nprint(\"accepted client\")\n\nwhile 1 do\n  local line, err = client:receive()\n  -- if there was no error, send it back to the client\n  if not err then\n    print(line)\n  else\n    print(err)\n  end\n\n  local state\n  local node\n  --2.1 blocks until it's our situation/turn\n  state, node = acpc_game:string_to_statenode(line)\n\n  --did a new hand start?\n  if not last_state or last_state.hand_number ~= state.hand_number or node.street < last_node.street then\n    continual_resolving:start_new_hand(state)\n  end\n  --2.2 use continual resolving to find a strategy and make an action in the current node\n  local adviced_action = continual_resolving:compute_action(node, state)\n  local action_id = adviced_action[\"action\"]\n  local betsize = adviced_action[\"raise_amount\"]\n  print(action_id)\n  print(betsize)\n  if betsize ~= nil then\n    client:send(tostring(betsize))\n  elseif action_id == constants.acpc_actions.fold then\n    client:send(\"f\")\n  elseif action_id == constants.acpc_actions.ccall then\n    client:send(\"c\")\n  else\n    client:send(\"WTF\")\n  end\n  last_state = state\n  last_node = node\n  collectgarbage();collectgarbage()\nend\n"
  },
  {
    "path": "Source/Player/manual_player.lua",
    "content": "local arguments = require 'Settings.arguments'\nlocal constants = require \"Settings.constants\"\nrequire \"ACPC.acpc_game\"\n\n--1.0 create the ACPC game and connect to the server\n\nlocal port = 0\nif #arg > 0 then\n  port = tonumber(arg[1])\nelse\n  print(\"need port\")\n  return\nend\n\nlocal acpc_game = ACPCGame()\nacpc_game:connect(arguments.acpc_server, port)\n\n--2.0 main loop that waits for a situation where we act and then chooses an action\nwhile true do\n  local state\n  local node\n\n  --2.1 blocks until it's our situation/turn\n  state, node = acpc_game:get_next_situation()\n\n  --print(state)\n  --io.read()\n  --print(node)\n  --io.read()\n\n  print(\"input action:\")\n  local action = io.read()\n\n  local acpc_action = nil\n\n  if action == \"f\" then\n    acpc_action = {action = constants.acpc_actions.fold}\n  elseif action == \"c\" then\n    acpc_action = {action = constants.acpc_actions.ccall}\n  else\n    local amount = tonumber(action)\n    acpc_action = {action = constants.acpc_actions.raise, raise_amount = amount}\n  end\n\n  --2.3 send the action to the dealer\n  acpc_game:play_action(acpc_action)\n\n  collectgarbage();collectgarbage()\nend\n"
  },
  {
    "path": "Source/Player/slum_util.py",
    "content": "def acpcify_board(board):\n  if len(board) == 6:\n    return board\n  if len(board) == 8:\n    return board[:6] + \"/\" + board[6:]\n  if len(board) == 10:\n    return board[:6] + \"/\" + board[6:8] + \"/\" + board[8:]\n  return \"WTF\"\n\ndef acpcify_actions(actions):\n    actions = actions.replace(\"b\",\"r\")\n    actions = actions.replace(\"k\",\"c\")\n    streets = actions.split(\"/\")\n    max_bet = 0\n    for i, street_actions in enumerate(streets):\n      bets = street_actions.split(\"r\")\n      max_street_bet = max_bet\n      for j, betstr in enumerate(bets):\n        try:\n          flag = False\n          if len(betstr) > 1 and betstr[-1] == 'c':\n            flag = True\n            betstr = betstr.replace(\"c\",\"\")\n          bet = int(betstr)\n          bet += max_bet\n          max_street_bet = max(max_street_bet, bet)\n          bets[j] = str(bet)\n          if flag:\n            bets[j] += \"c\"\n          bets[j] = \"r\" + bets[j]\n        except ValueError:\n          continue\n      max_bet = max_street_bet\n      if max_bet == 0:\n        max_bet = 100\n      good_string = \"\".join(bets)\n      streets[i] = good_string\n    return \"/\".join(streets), max_bet\n"
  },
  {
    "path": "Source/Player/slumbot_player.py",
    "content": "from selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\nfrom selenium.webdriver.support.ui import WebDriverWait\nfrom selenium.webdriver.support import expected_conditions as EC\nfrom selenium.webdriver.common.by import By\nfrom selenium.webdriver.common.desired_capabilities import DesiredCapabilities\nimport os\nimport sys\nimport time\nimport slum_util\nimport socket\n\nif len(sys.argv) < 3:\n  print(\"missing address port\")\n  sys.exit()\nclient_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\nclient_socket.connect((sys.argv[1], int(sys.argv[2])))\n\nchrome_options = Options()\n#chrome_options.add_argument(\"--headless\")\nchrome_options.binary_location = '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'\n\nd = DesiredCapabilities.CHROME\nd['loggingPrefs'] = { 'browser':'ALL' }\n\ndriver = webdriver.Chrome(executable_path=\"/Users/lawson/Downloads/chromedriver\", chrome_options=chrome_options, desired_capabilities=d)\ndriver.get(\"http://slumbot.com\")\n\ntime.sleep(2)\n\nresponse_fun = \"\"\"\nresponse = function(data) {\n    global_data = data\n    // We increment actionindex even when we get an error message back.\n    // If we didn't, then when we retried the action that triggered the error,\n    // it would get flagged as a duplicate.\n    ++actionindex;\n    if (\"errormsg\" in data) {\n\tvar errormsg = data[\"errormsg\"];\n\t$(\"#msg\").text(errormsg);\n\t// Some errors end the hand (e.g., server timeout)\n\t// Would it be cleaner to treat a server timeout like a client\n\t// timeout?  Return msg rather than errormsg?\n\tif (\"hip\" in data) {\n\t    handinprogress = (data[\"hip\"] === 1);\n\t}\n\t// Need this for server timeout.  Want to enable the \"Next Hand\"\n\t// button and disable all the other buttons.\n\tenableactions();\n\treturn;\n    } else if (\"msg\" in data) {\n\tvar msg = data[\"msg\"];\n\t$(\"#msg\").text(msg);\n\n    } else {\n\t$(\"#msg\").text(\"\");\n    }\n\n    if (actiontype === 1) {\n\taddourcheck();\n    } else if (actiontype === 2) {\n\taddourcall();\n    } else if (actiontype === 3) {\n\taddourfold();\n    } else if (actiontype === 4) {\n\taddourbet();\n    }\n    $(\"#betsize\").val(\"\");\n    potsize = data[\"ps\"];\n    ourbet = data[\"ourb\"];\n    oppbet = data[\"oppb\"];\n    var lastcurrentaction = currentaction;\n    currentaction = data[\"action\"];\n    var actiondisplay = currentaction;\n    $(\"#currentaction\").text(actiondisplay);\n    var overlap = currentaction.substring(0, lastcurrentaction.length);\n    if (overlap !== lastcurrentaction) {\n\tconsole.log(\"Overlap \" + overlap);\n\tconsole.log(\"Last current action \" + lastcurrentaction);\n    } else {\n\tvar newaction = currentaction.substring(lastcurrentaction.length,\n\t\t\t\t\t\tcurrentaction.length);\n\toppactionmessage(newaction);\n    }\n\n    parsedata(data);\n    drawall(aftershowdown);\n    lifetimetotal = data[\"ltotal\"];\n    lifetimeconf = data[\"lconf\"];\n    lifetimebaselinetotal = data[\"lbtotal\"];\n    lifetimebaselineconf = data[\"lbconf\"];\n    numlifetimehands = data[\"lhands\"];\n    showdowntotal = data[\"sdtotal\"];\n    showdownconf = data[\"sdconf\"];\n    numshowdownhands = data[\"sdhands\"];\n    blbshowdowntotal = data[\"blbsdtotal\"];\n    blbshowdownconf = data[\"blbsdconf\"];\n    blbnumshowdownhands = data[\"blbsdhands\"];\n    clbshowdowntotal = data[\"clbsdtotal\"];\n    clbshowdownconf = data[\"clbsdconf\"];\n    clbnumshowdownhands = data[\"clbsdhands\"];\n    if (username !== \"\") displaystats();\n    if (! handinprogress) {\n\tsessiontotal = data[\"stotal\"];\n\t$(\"#sessiontotal\").text(sessiontotal);\n\tnumsessionhands = data[\"shands\"];\n\t$(\"#numhands\").text(numsessionhands);\n\tvar outcome = data[\"outcome\"];\n\tif (outcome > 0) {\n\t    $(\"#outcome\").text(\"You won a pot of \" + outcome + \"!\");\n\t} else if (outcome < 0) {\n\t    $(\"#outcome\").text(\"Slumbot won a pot of \" + -outcome +\n\t\t\t       \"!\");\n\t} else {\n            $(\"#outcome\").text(\"You chopped!\");\n\t}\n    } else {\n\t$(\"#outcome\").text(\"\");\n\tstarttimer();\n    }\n    enableactions();\n};\n\"\"\"\ndriver.execute_script(response_fun)\nhand_no = 0\n\nwhile True:\n  nexthand_button = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, \"nexthand\")))\n  nexthand_button.click()\n  hand_no += 1\n\n  position = 0\n  while True:\n    fold_button = driver.find_element_by_id(\"fold\")\n    nexthand_button = driver.find_element_by_id(\"nexthand\")\n    action_td = driver.find_element_by_id(\"currentaction\")\n\n    if fold_button.is_displayed() and fold_button.is_enabled():\n      if action_td.text:\n        position = 1\n      break\n    if nexthand_button.is_displayed() and nexthand_button.is_enabled():\n      break\n    time.sleep(1)\n\n  # new hand\n  while True:\n    nexthand_button = driver.find_element_by_id(\"nexthand\")\n    if nexthand_button.is_displayed() and nexthand_button.is_enabled():\n      break\n    hole = driver.execute_script(\"return global_data[\\\"holes\\\"]\")\n    actions = driver.execute_script(\"return global_data[\\\"action\\\"]\")\n    board = driver.execute_script(\"return global_data[\\\"board\\\"]\")\n\n    fold_button = driver.find_element_by_id(\"fold\")\n    call_button = driver.find_element_by_id(\"call\")\n    check_button = driver.find_element_by_id(\"check\")\n    halfpot_button = driver.find_element_by_id(\"halfpot\")\n    pot_button = driver.find_element_by_id(\"pot\")\n    allin_button = driver.find_element_by_id(\"allin\")\n\n    while True:\n      if (call_button.is_displayed() and call_button.is_enabled()) or (allin_button.is_displayed() and allin_button.is_enabled()):\n        break\n      time.sleep(1)\n\n    # ready to make the action\n    actions, max_bet = slum_util.acpcify_actions(actions)\n    msg = \"MATCHSTATE:\" + str(position) + \":\" + str(hand_no) +\":\" + actions + \":\"\n    if position == 0:\n      msg += hole + \"|\"\n    elif position == 1:\n      msg += \"|\" + hole\n    if len(board) > 0:\n      msg += \"/\" + slum_util.acpcify_board(board)\n    msg += \"\\n\"\n\n    client_socket.send(msg)\n    sys.stdout.write(\"sent \" + msg + \":\")\n    advice = client_socket.recv(100)\n\n    # click button\n    print(advice)\n\n    if advice == \"c\":\n      if call_button.is_displayed() and call_button.is_enabled():\n        call_button.click()\n      elif check_button.is_displayed() and check_button.is_enabled():\n        check_button.click()\n    elif advice == \"f\":\n      fold_button.click()\n    elif advice == \"20000\":\n      allin_button.click()\n    elif advice == str(max_bet*3):\n      pot_button.click()\n    else:\n      halfpot_button.click()\n\n    while True:\n      time.sleep(1)\n      if (call_button.is_displayed() and call_button.is_enabled()) or (allin_button.is_displayed() and allin_button.is_enabled()):\n        break\n      if nexthand_button.is_displayed() and nexthand_button.is_enabled():\n        break\n\n#signup_button = driver.find_element_by_id(\"login_trigger\")\n#signup_button.click()\n"
  },
  {
    "path": "Source/Settings/arguments.lua",
    "content": "--- Parameters for DeepStack.\n--@module arguments\n\nlocal torch = require 'torch'\n\ntorch.setdefaulttensortype('torch.FloatTensor')\n\nlocal params = {}\n\n--- whether to run on GPU\nparams.gpu = false\n--- list of pot-scaled bet sizes to use in tree\n-- @field params.bet_sizing\nparams.bet_sizing = {{1},{1},{1}}\n--- server running the ACPC dealer\nparams.acpc_server = \"localhost\"\n--- server port running the ACPC dealer\nparams.acpc_server_port = 16177\n--- the tensor datatype used for storing DeepStack's internal data\nparams.Tensor = torch.FloatTensor\n--- the directory for data files\nparams.data_directory = '../Data/'\n--- the size of the game's ante, in chips\nparams.ante = 100\nparams.sb = 50\nparams.bb = 100\n--- the size of each player's stack, in chips\nparams.stack = 20000\n--- the number of iterations that DeepStack runs CFR for\nparams.cfr_iters = 1000\n--- the number of preliminary CFR iterations which DeepStack doesn't factor into the average strategy (included in cfr_iters)\nparams.cfr_skip_iters = 500\n--- how many poker situations are solved simultaneously during data generation\nparams.gen_batch_size = 10\n--- how many poker situations are used in each neural net training batch\nparams.train_batch_size = 1000\n--- path to the solved poker situation data used to train the neural net\nparams.data_path = '../Data/TrainSamples/'\n--- path to the neural net model\nparams.model_path = '../Data/Models/'\n--- the name of the neural net file\nparams.value_net_name = 'final'\n--- the neural net architecture\nparams.net = '{nn.Linear(input_size, 500), nn.BatchNormalization(500), nn.PReLU(), nn.Linear(500, 500), nn.BatchNormalization(500), nn.PReLU(), nn.Linear(500, 500), nn.BatchNormalization(500), nn.PReLU(), nn.Linear(500, output_size)}'\n--- how often to save the model during training\nparams.save_epoch = 1\n--- how many epochs to train for\nparams.epoch_count = 200\n--- how many solved poker situations are generated for use as training examples\nparams.train_data_count = 150000\n--- how many solved poker situations are generated for use as validation examples\nparams.valid_data_count = 150000\n--- learning rate for neural net training\nparams.learning_rate = 0.001\n\nassert(params.cfr_iters > params.cfr_skip_iters)\nif params.gpu then\n  require 'cutorch'\n  params.Tensor = torch.CudaTensor\nend\n\nreturn params\n"
  },
  {
    "path": "Source/Settings/constants.lua",
    "content": "--- Various constants used in DeepStack.\n-- @module constants\n\nlocal constants = {}\n\n--- the number of players in the game\nconstants.players_count = 2\n--- the number of betting rounds in the game\nconstants.streets_count = 4\n\n--- IDs for each player and chance\n-- @field chance `0`\n-- @field P1 `1`\n-- @field P2 `2`\nconstants.players = {}\nconstants.players.chance = 0\nconstants.players.P1 = 1\nconstants.players.P2 = 2\n\n--- IDs for terminal nodes (either after a fold or call action) and nodes that follow a check action\n-- @field terminal_fold (terminal node following fold) `-2`\n-- @field terminal_call (terminal node following call) `-1`\n-- @field chance_node (node for the chance player) `0`\n-- @field check (node following check) `-1`\n-- @field inner_node (any other node) `1`\nconstants.node_types = {}\nconstants.node_types.terminal_fold = -2\nconstants.node_types.terminal_call = -1\nconstants.node_types.check = -1\nconstants.node_types.chance_node = 0\nconstants.node_types.inner_node = 1\n\n--- IDs for fold and check/call actions\n-- @field fold `-2`\n-- @field ccall (check/call) `-1`\nconstants.actions = {}\nconstants.actions.fold = -2\nconstants.actions.ccall = -1\nconstants.actions.raise = -3\n\n--- String representations for actions in the ACPC protocol\n-- @field fold \"`fold`\"\n-- @field ccall (check/call) \"`ccall`\"\n-- @field raise \"`raise`\"\nconstants.acpc_actions = {}\nconstants.acpc_actions.fold = \"fold\"\nconstants.acpc_actions.ccall = \"ccall\"\nconstants.acpc_actions.raise = \"raise\"\n\nreturn constants\n"
  },
  {
    "path": "Source/Settings/game_settings.lua",
    "content": "--- Game constants which define the game played by DeepStack.\n-- @module game_settings\n\nrequire 'torch'\n\nlocal tools = require 'tools'\n\n--leduc defintion\nlocal M = {}\n--- the number of card suits in the deck\nM.suit_count = 4\n--- the number of card ranks in the deck\nM.rank_count = 13\n--- the total number of cards in the deck\nM.card_count = M.suit_count * M.rank_count\n--- the number of public cards dealt in the game (revealed after the first\n-- betting round)\nM.hand_card_count = 2\n\nM.hand_count = tools:choose(M.card_count, M.hand_card_count)\n\nM.board_card_count = {0, 3, 4, 5}\n\nM.limit_bet_sizes = {2, 2, 4, 4}\n\nM.limit_bet_cap = 4\n\nM.nl = true\n\nreturn M\n"
  },
  {
    "path": "Source/TerminalEquity/terminal_equity.lua",
    "content": "--- Evaluates player equities at terminal nodes of the game's public tree.\n-- @classmod terminal_equity\n\nrequire 'torch'\nlocal evaluator = require 'Game.Evaluation.evaluator'\nlocal game_settings = require 'Settings.game_settings'\nlocal arguments = require 'Settings.arguments'\nlocal card_tools = require 'Game.card_tools'\nlocal constants = require 'Settings.constants'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nlocal tools = require 'tools'\n\nlocal TerminalEquity = torch.class('TerminalEquity')\n\n--- Constructor\nfunction TerminalEquity:__init()\n  self._block_matrix = arguments.Tensor(game_settings.hand_count, game_settings.hand_count):fill(1);\n  if game_settings.hand_card_count == 2 then\n    for i = 1, game_settings.card_count do\n      for j = i+1, game_settings.card_count do\n        local idx1 = card_tools:get_hole_index({i,j})\n        for k = 1, game_settings.card_count do\n          for l = k+1, game_settings.card_count do\n            local idx2 = card_tools:get_hole_index({k,l})\n            if i == k or i == l or j == k or j == l then\n              self._block_matrix[idx1][idx2] = 0\n              self._block_matrix[idx2][idx1] = 0\n            end\n          end\n        end\n      end\n    end\n  end\n  self.matrix_mem = arguments.Tensor()\n\n  if self._pf_equity == nil then\n    local f = assert(io.open(\"./TerminalEquity/pf_equity.dat\", \"rb\"))\n    local data = f:read(\"*all\")\n    self._pf_equity = arguments.Tensor(game_settings.hand_count,game_settings.hand_count):fill(0)\n\n    assert(string.len(data) == 1326*1326*4, 'bad length')\n\n    local byteidx = 1\n    for i = 1, 1326 do\n      for j = 1, 1326 do\n        local num = 0\n        for k = 0,3 do\n          num = num + data:byte(byteidx) * (2 ^ (k * 8))\n          byteidx = byteidx + 1\n        end\n        num = (num > 2147483647) and (num - 4294967296) or num\n        -- negative because of how equity matrix is set up\n        self._pf_equity[i][j] = -num / 1712304\n      end\n    end\n\n    f:close()\n  end\n  self.batch_size = 10\nend\n\n--- Constructs the matrix that turns player ranges into showdown equity.\n--\n-- Gives the matrix `A` such that for player ranges `x` and `y`, `x'Ay` is the equity\n-- for the first player when no player folds.\n--\n-- @param board_cards a non-empty vector of board cards\n-- @param call_matrix a tensor where the computed matrix is stored\n-- @local\nfunction TerminalEquity:get_last_round_call_matrix(board_cards, call_matrix)\n  assert(board_cards:dim() == 0 or board_cards:size(1) == 1 or board_cards:size(1) == 2 or board_cards:size(1) == 5,\n    'Only Leduc, extended Leduc, and Texas Holdem are supported ' .. board_cards:size(1))\n\n  local strength = evaluator:batch_eval_fast(board_cards)\n  --handling hand stregths (winning probs);\n  local strength_view_1 = strength:view(game_settings.hand_count, 1):expandAs(call_matrix)\n  local strength_view_2 = strength:view(1, game_settings.hand_count):expandAs(call_matrix)\n\n  call_matrix:copy(torch.gt(strength_view_1, strength_view_2))\n  call_matrix:csub(torch.lt(strength_view_1, strength_view_2):typeAs(call_matrix))\n\n  self:_handle_blocking_cards(call_matrix, board_cards);\nend\n\n--- Constructs the matrix that turns player ranges into showdown equity.\n--\n-- Gives the matrix `A` such that for player ranges `x` and `y`, `x'Ay` is the equity\n-- for the first player when no player folds.\n--\n-- @param board_cards a non-empty vector of board cards\n-- @param call_matrix a tensor where the computed matrix is stored\n-- @local\nfunction TerminalEquity:get_inner_call_matrix(board_cards, call_matrix)\n  assert(board_cards:dim() == 0 or board_cards:size(2) == 1 or board_cards:size(2) == 2 or board_cards:size(2) == 5,\n    'Only Leduc, extended Leduc, and Texas Holdem are supported ' .. board_cards:size(2))\n  local strength = evaluator:batch_eval_fast(board_cards)\n  local num_boards = board_cards:size(1)\n  --handling hand stregths (winning probs);\n  local strength_view_1 = strength:view(num_boards, game_settings.hand_count, 1):expand(num_boards, game_settings.hand_count, game_settings.hand_count)\n  local strength_view_2 = strength:view(num_boards, 1, game_settings.hand_count):expandAs(strength_view_1)\n\n  local possible_mask = torch.lt(strength,0):typeAs(call_matrix)\n  for i = 1, num_boards, self.batch_size do\n    local indices = {i, i + self.batch_size - 1}\n    local sz = self.batch_size\n    if i + self.batch_size - 1 > num_boards then\n      indices = {i, num_boards}\n      sz = num_boards - i + 1\n    end\n    self.matrix_mem[{{1, sz}}]:copy(torch.gt(strength_view_1[{indices}], strength_view_2[{indices}]))\n    self.matrix_mem[{{1, sz}}]:cmul(possible_mask[{indices}]:view(sz, 1, game_settings.hand_count):expand(sz, game_settings.hand_count, game_settings.hand_count))\n    self.matrix_mem[{{1, sz}}]:cmul(possible_mask[{indices}]:view(sz, game_settings.hand_count, 1):expand(sz, game_settings.hand_count, game_settings.hand_count))\n    call_matrix:add(torch.sum(self.matrix_mem[{{1,sz}}],1))\n\n    self.matrix_mem[{{1, sz}}]:copy(torch.lt(strength_view_1[{indices}], strength_view_2[{indices}]))\n    self.matrix_mem[{{1, sz}}]:cmul(possible_mask[{indices}]:view(sz, 1, game_settings.hand_count):expand(sz, game_settings.hand_count, game_settings.hand_count))\n    self.matrix_mem[{{1, sz}}]:cmul(possible_mask[{indices}]:view(sz, game_settings.hand_count, 1):expand(sz, game_settings.hand_count, game_settings.hand_count))\n    call_matrix:csub(torch.sum(self.matrix_mem[{{1,sz}}],1))\n  end\n\n  self:_handle_blocking_cards(call_matrix, board_cards);\nend\n\n--- Zeroes entries in an equity matrix that correspond to invalid hands.\n--\n-- A hand is invalid if it shares any cards with the board.\n--\n-- @param equity_matrix the matrix to modify\n-- @param board a possibly empty vector of board cards\n-- @local\nfunction TerminalEquity:_handle_blocking_cards(equity_matrix, board)\n  local possible_hand_indexes = card_tools:get_possible_hand_indexes(board);\n  local possible_hand_matrix = possible_hand_indexes:view(1, game_settings.hand_count):expandAs(equity_matrix);\n\n  equity_matrix:cmul(possible_hand_matrix);\n  possible_hand_matrix = possible_hand_indexes:view(game_settings.hand_count,1):expandAs(equity_matrix);\n  equity_matrix:cmul(possible_hand_matrix);\n\n  if game_settings.hand_card_count == 2 then\n    equity_matrix:cmul(self._block_matrix)\n  elseif game_settings.hand_card_count == 1 then\n    for i = 1, game_settings.card_count do\n      equity_matrix[i][i] = 0\n    end\n  end\nend\n\n--- Sets the evaluator's fold matrix, which gives the equity for terminal\n-- nodes where one player has folded.\n--\n-- Creates the matrix `B` such that for player ranges `x` and `y`, `x'By` is the equity\n-- for the player who doesn't fold\n-- @param board a possibly empty vector of board cards\n-- @local\n\nfunction TerminalEquity:_set_fold_matrix(board)\n  self.fold_matrix = arguments.Tensor(game_settings.hand_count, game_settings.hand_count);\n  self.fold_matrix:fill(1);\n  --setting cards that block each other to zero\n  self:_handle_blocking_cards(self.fold_matrix, board);\nend\n\n--- Sets the evaluator's call matrix, which gives the equity for terminal\n-- nodes where no player has folded.\n--\n-- For nodes in the last betting round, creates the matrix `A` such that for player ranges\n-- `x` and `y`, `x'Ay` is the equity for the first player when no player folds. For nodes\n-- in the first betting round, gives the weighted average of all such possible matrices.\n--\n-- @param board a possibly empty vector of board cards\n-- @local\n-- TODO finish this\nfunction TerminalEquity:_set_call_matrix(board)\n  local street = card_tools:board_to_street(board);\n\n  self.equity_matrix = arguments.Tensor(game_settings.hand_count, game_settings.hand_count):zero();\n  if street == constants.streets_count then\n    --for last round we just return the matrix\n    self:get_last_round_call_matrix(board, self.equity_matrix);\n  elseif street == 3 or street == 2 then\n    --iterate through all possible next round streets\n    --TODO(go to the last street)\n    local next_round_boards = card_tools:get_last_round_boards(board);\n  --  assert(false, 'hey')\n    local boards_count = next_round_boards:size(1);\n\n    if self.matrix_mem:dim() ~= 3 or self.matrix_mem:size(2) ~= game_settings.hand_count or self.matrix_mem:size(3) ~= game_settings.hand_count then\n      self.matrix_mem = arguments.Tensor(self.batch_size, game_settings.hand_count, game_settings.hand_count)\n    end\n    self:get_inner_call_matrix(next_round_boards, self.equity_matrix)\n\n    --averaging the values in the call matrix\n    local cards_to_come = game_settings.board_card_count[constants.streets_count] - game_settings.board_card_count[street]\n    local cards_left = game_settings.card_count - game_settings.hand_card_count*2 - game_settings.board_card_count[street]\n    local den = tools:choose(cards_left, cards_to_come)\n\n    local weight_constant = 1/den\n\n    self.equity_matrix:mul(weight_constant);\n  elseif street == 1 then\n    self.equity_matrix:copy(self._pf_equity)\n  else\n    --impossible street\n    assert(false, 'impossible street ' .. street);\n  end\nend\n\nfunction TerminalEquity:get_hand_strengths()\n  local a = arguments.Tensor(1, game_settings.hand_count):fill(1)\n  return torch.mm(a,self.equity_matrix)\nend\n\n--- Sets the board cards for the evaluator and creates its internal data structures.\n-- @param board a possibly empty vector of board cards\nfunction TerminalEquity:set_board(board)\n  self.board = board\n  self:_set_call_matrix(board);\n  self:_set_fold_matrix(board);\nend\n\n--- Computes (a batch of) counterfactual values that a player achieves at a terminal node\n-- where no player has folded.\n--\n-- @{set_board} must be called before this function.\n--\n-- @param ranges a batch of opponent ranges in an NxK tensor, where N is the batch size\n-- and K is the range size\n-- @param result a NxK tensor in which to save the cfvs\nfunction TerminalEquity:call_value( ranges, result )\n  result:mm(ranges, self.equity_matrix);\nend\n\n--- Computes (a batch of) counterfactual values that a player achieves at a terminal node\n-- where a player has folded.\n--\n-- @{set_board} must be called before this function.\n--\n-- @param ranges a batch of opponent ranges in an NxK tensor, where N is the batch size\n-- and K is the range size\n-- @param result A NxK tensor in which to save the cfvs. Positive cfvs are returned, and\n-- must be negated if the player in question folded.\nfunction TerminalEquity:fold_value( ranges, result )\n  result:mm(ranges, self.fold_matrix);\nend\n\n--- Returns the matrix which gives showdown equity for any ranges.\n--\n-- @{set_board} must be called before this function.\n--\n-- @return For nodes in the last betting round, the matrix `A` such that for player ranges\n-- `x` and `y`, `x'Ay` is the equity for the first player when no player folds. For nodes\n-- in the first betting round, the weighted average of all such possible matrices.\nfunction TerminalEquity:get_call_matrix()\n  return self.equity_matrix\nend\n\n--- Computes the counterfactual values that both players achieve at a terminal node\n-- where no player has folded.\n--\n-- @{set_board} must be called before this function.\n--\n-- @param ranges a 2xK tensor containing ranges for each player (where K is the range size)\n-- @param result a 2xK tensor in which to store the cfvs for each player\nfunction TerminalEquity:tree_node_call_value( ranges, result )\n  assert(ranges:dim() == 2)\n  assert(result:dim() == 2)\n  self:call_value(ranges[1]:view(1,  -1), result[2]:view(1,  -1))\n  self:call_value(ranges[2]:view(1,  -1), result[1]:view(1,  -1))\nend\n\n--- Computes the counterfactual values that both players achieve at a terminal node\n-- where either player has folded.\n--\n-- @{set_board} must be called before this function.\n--\n-- @param ranges a 2xK tensor containing ranges for each player (where K is the range size)\n-- @param result a 2xK tensor in which to store the cfvs for each player\n-- @param folding_player which player folded\nfunction TerminalEquity:tree_node_fold_value( ranges, result, folding_player )\n  assert(ranges:dim() == 2)\n  assert(result:dim() == 2)\n  self:fold_value(ranges[1]:view(1,  -1), result[2]:view(1,  -1))\n  self:fold_value(ranges[2]:view(1,  -1), result[1]:view(1,  -1))\n\n  result[folding_player]:mul(-1)\nend\n\nTerminalEquity:__init()\n--TerminalEquity:set_board(torch.Tensor({48,52,44, 1}))\n"
  },
  {
    "path": "Source/Training/data_stream.lua",
    "content": "--- Handles the data used for neural net training and validation.\n-- @classmod data_stream\n\nrequire 'torch'\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\nlocal bucketer = require 'Nn.bucketer'\nlocal constants = require 'Settings.constants'\nlocal DataStream = torch.class('DataStream')\n\n-- Lua implementation of PHP scandir function\nfunction DataStream:_scandir(directory)\n    local i, t, popen = 0, {}, io.popen\n    local pfile = popen('ls -a \"'..directory..'\"')\n    for filename in pfile:lines() do\n        i = i + 1\n        t[filename] = 1\n    end\n    pfile:close()\n    return t\nend\n\n--- Constructor.\n--\n-- Reads the data from training and validation files generated with\n-- @{data_generation_call.generate_data}.\nfunction DataStream:__init(street)\n  self.folder = \"xxx/\"\n  if street == 4 then\n    self.folder = \"river/\"\n  elseif street == 3 then\n    self.folder = \"turn/\"\n  elseif street == 2 then\n    self.folder = \"flop/\"\n  elseif street == 1 then\n    self.folder = \"preflop-aux/\"\n  end\n  self.path = arguments.data_path\n  if game_settings.nl then\n    self.path = self.path .. \"NoLimit/\"\n  else\n    self.path = self.path .. \"Limit/\"\n  end\n  self.path = self.path .. self.folder\n  filenames = self:_scandir(self.path)\n  local numfiles = 0\n\n  local goodfiles = {}\n\n  for filename,_ in pairs(filenames) do\n    local res = string.find(filename, \".inputs\")\n    if res ~= nil then\n      local targetname = filename:sub(0,res) .. \"targets\"\n      if filenames[targetname] ~= nil then\n        numfiles = numfiles + 1\n        goodfiles[numfiles] = filename:sub(0,res)\n      end\n    end\n  end\n\n  self.goodfiles = goodfiles\n  print(numfiles .. \" good files\")\n\n  self.bucket_count = bucketer:get_bucket_count(street)\n  self.target_size = self.bucket_count * constants.players_count\n  self.input_size = self.bucket_count * constants.players_count + 1\n\n  local num_train = math.floor(numfiles * 0.9)\n  local num_valid = numfiles - num_train\n\n  local train_count = num_train * arguments.gen_batch_size\n  local valid_count = num_valid * arguments.gen_batch_size\n\n  self.train_data_count = train_count\n  assert(self.train_data_count >= arguments.train_batch_size, 'Training data count has to be greater than a train batch size!')\n  self.train_batch_count = self.train_data_count / arguments.train_batch_size\n  self.valid_data_count = valid_count\n  assert(self.valid_data_count >= arguments.train_batch_size, 'Validation data count has to be greater than a train batch size!')\n  self.valid_batch_count = self.valid_data_count / arguments.train_batch_size\n\n  --loading train data\n\n  --transfering data to gpu if needed\nend\n\n--- Gives the number of batches of validation data.\n--\n-- Batch size is defined by @{arguments.train_batch_size}.\n-- @return the number of batches\nfunction DataStream:get_valid_batch_count()\n  return self.valid_batch_count\nend\n\n--- Gives the number of batches of training data.\n--\n-- Batch size is defined by @{arguments.train_batch_size}\n-- @return the number of batches\nfunction DataStream:get_train_batch_count()\n  return self.train_batch_count\nend\n\nfunction DataStream:shuffle(tbl, n)\n  for i = n, 1, -1 do\n    local rand = math.random(n)\n    tbl[i], tbl[rand] = tbl[rand], tbl[i]\n  end\n  return tbl\nend\n\n--- Randomizes the order of training data.\n--\n-- Done so that the data is encountered in a different order for each epoch.\nfunction DataStream:start_epoch()\n  --data are shuffled each epoch]\n  self:shuffle(self.goodfiles, self.train_data_count / arguments.gen_batch_size)\nend\n\n--- Returns a batch of data from a specified data set.\n-- @param inputs the inputs set for the given data set\n-- @param targets the targets set for the given data set\n-- @param mask the masks set for the given data set\n-- @param batch_index the index of the batch to return\n-- @return the inputs set for the batch\n-- @return the targets set for the batch\n-- @return the masks set for the batch\n-- @local\nfunction  DataStream:get_batch(batch_index)\n\n  local inputs = arguments.Tensor(arguments.train_batch_size, self.input_size)\n  local targets = arguments.Tensor(arguments.train_batch_size, self.target_size)\n  local masks = arguments.Tensor(arguments.train_batch_size, self.target_size):zero()\n\n  for i = 1, arguments.train_batch_size / arguments.gen_batch_size do\n    local idx = (batch_index - 1) * arguments.train_batch_size / arguments.gen_batch_size + i\n    idx = math.floor(idx + 0.1)\n    local filebase = self.goodfiles[idx]\n\n    local inputname = filebase .. \"inputs\"\n    local targetname = filebase .. \"targets\"\n\n    local input_batch = torch.load(self.path .. inputname)\n    local target_batch = torch.load(self.path .. targetname)\n\n    data_index = {{(i - 1) * arguments.gen_batch_size + 1, i * arguments.gen_batch_size}, {}}\n\n    inputs[data_index]:copy(input_batch)\n    targets[data_index]:copy(target_batch)\n    masks[data_index][torch.gt(input_batch[{{}, {1, self.bucket_count * 2}}], 0)] = 1\n  end\n\n  if arguments.gpu then\n    inputs = inputs:cuda()\n    targets = targets:cuda()\n    masks = masks:cuda()\n  end\n  return inputs, targets, masks\nend\n\n--- Returns a batch of data from the training set.\n-- @param batch_index the index of the batch to return\n-- @return the inputs set for the batch\n-- @return the targets set for the batch\n-- @return the masks set for the batch\nfunction  DataStream:get_train_batch(batch_index)\n    return self:get_batch(batch_index)\nend\n\n--- Returns a batch of data from the validation set.\n-- @param batch_index the index of the batch to return\n-- @return the inputs set for the batch\n-- @return the targets set for the batch\n-- @return the masks set for the batch\nfunction  DataStream:get_valid_batch(batch_index)\n  return self:get_batch(self.train_batch_count + batch_index)\nend\n"
  },
  {
    "path": "Source/Training/main_train.lua",
    "content": "--- Script that trains the neural network.\n--\n-- Uses data previously generated with @{data_generation_call}.\n-- @script main_train\n\nlocal nnBuilder = require 'Nn.net_builder'\nrequire 'Training.data_stream'\nlocal train = require 'Training.train'\nlocal arguments = require 'Settings.arguments'\n\nif #arg == 0 then\n  print(\"Please specify the street. 1 = preflop, 4 = river\")\n  return\nend\n\nlocal street = tonumber(arg[1])\nlocal network = nnBuilder:build_net(street)\n\nif arguments.gpu then\n  network = network:cuda()\nend\n\nlocal data_stream = DataStream(street)\ntrain:train(network, data_stream, arguments.epoch_count)\n"
  },
  {
    "path": "Source/Training/raw_converter.lua",
    "content": "if #arg == 0 then\n  print(\"Please specify the street. 1 = preflop, 4 = river\")\n  return\nend\n\nrequire 'torch'\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\nlocal bucketer = require 'Nn.bucketer'\nlocal river_tools = require 'Nn.Bucketing.river_tools'\nlocal constants = require 'Settings.constants'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nlocal card_tools = require 'Game.card_tools'\nlocal evaluator = require 'Game.Evaluation.evaluator'\nlocal threads = require 'threads'\n\nlocal DataStreamMem = torch.class('RawConverter')\n\nrequire 'Nn.bucket_conversion'\n\n-- Lua implementation of PHP scandir function\nfunction scandir(directory)\n    local i, t, popen = 0, {}, io.popen\n    local pfile = popen('ls -a \"'..directory..'\"')\n    for filename in pfile:lines() do\n        i = i + 1\n        t[filename] = 1\n    end\n    pfile:close()\n    return t\nend\n\nfunction convert(street, srcfolder, destfolder)\n  --loadind valid data\n  local path = arguments.data_path\n  if game_settings.nl then\n    path = path .. \"NoLimit/\"\n  else\n    path = path .. \"Limit/\"\n  end\n  filenames = scandir(path .. srcfolder)\n  local numfiles = 0\n  local goodfiles = {}\n  for filename,_ in pairs(filenames) do\n    local res = string.find(filename, \".inputs\")\n    if res ~= nil then\n      local targetname = filename:sub(0,res) .. \"targets\"\n      if filenames[targetname] ~= nil then\n        goodfiles[filename:sub(0,res)] = 1\n        numfiles = numfiles + 1\n      end\n    end\n  end\n\n  local bucket_conversion = BucketConversion()\n\n  print(numfiles .. \" good files\")\n  local bucket_count = bucketer:get_bucket_count(street)\n  local target_size = bucket_count * constants.players_count\n\n  -- ranges, termvalues, potsize\n  local input_size = bucket_count * constants.players_count + 1\n\n  local num_train = math.floor(numfiles * 0.9)\n  local num_valid = numfiles - num_train\n\n  local train_count = num_train * arguments.gen_batch_size\n  local valid_count = num_valid * arguments.gen_batch_size\n\n  local idx = 1\n  local fileidx = 1\n  local file_pattern = \"[-](......\"\n  if street == 1 then\n    file_pattern = \"\"\n  elseif street == 2 then\n    file_pattern = file_pattern .. \")\"\n  elseif street == 3 then\n    file_pattern = file_pattern .. \"..)\"\n  elseif street == 4 then\n    file_pattern = file_pattern .. \"....)\"\n  end\n\n  local input_batch = arguments.Tensor(arguments.gen_batch_size, input_size)\n  local target_batch = arguments.Tensor(arguments.gen_batch_size, target_size)\n\n  for filebase, _ in pairs(goodfiles) do\n    local inputname = filebase .. \"inputs\"\n    local targetname = filebase .. \"targets\"\n\n    if street > 1 then\n      local board = card_to_string:string_to_board(string.match(filebase, file_pattern))\n      bucket_conversion:set_board(board)\n    else\n      bucket_conversion:set_board(arguments.Tensor())\n    end\n\n    local raw_input_batch = torch.load(path .. srcfolder .. inputname)\n    local raw_target_batch = torch.load(path .. srcfolder .. targetname)\n\n    --input_batch\n\n    idx = idx + arguments.gen_batch_size\n    if fileidx == num_train then\n      idx = 1\n    end\n    fileidx = fileidx + 1\n    if fileidx % 100 == 0 then\n      print(fileidx)\n    end\n\n    local raw_indexes = {{1, game_settings.hand_count}, {game_settings.hand_count + 1, game_settings.hand_count * 2}}\n    local bucket_indexes = {{1, bucket_count}, {bucket_count + 1, bucket_count * 2}}\n\n    --[[\n    print(string.match(filebase, file_pattern))\n    for card1 = 1,game_settings.card_count do\n      for card2 = card1+1,game_settings.card_count do\n        local idx = card_tools:get_hole_index({card1,card2})\n        print(card_to_string:card_to_string(card1) .. card_to_string:card_to_string(card2)\n              .. \": \" .. term_values1[{1,idx}])\n      end\n    end\n\n    io.read()\n]]\n    for player = 1, constants.players_count do\n      local player_index = raw_indexes[player]\n      local bucket_index = bucket_indexes[player]\n      bucket_conversion:card_range_to_bucket_range(raw_input_batch[{{},player_index}],input_batch[{{}, bucket_index}])\n    end\n\n    for player = 1, constants.players_count do\n      local player_index = raw_indexes[player]\n      local bucket_index = bucket_indexes[player]\n      bucket_conversion:hand_cfvs_to_bucket_cfvs(\n        raw_input_batch[{{}, player_index}],\n        raw_target_batch[{{}, player_index}],\n        input_batch[{{}, bucket_index}],\n        target_batch[{{}, bucket_index}])\n    end\n    input_batch[{{}, -1}]:copy(raw_input_batch[{{},-1}])\n\n    if arguments.gpu then\n      torch.save(path .. destfolder .. targetname, target_batch:cuda())\n      torch.save(path .. destfolder .. inputname, input_batch:cuda())\n    else\n      torch.save(path .. destfolder .. targetname, target_batch:float())\n      torch.save(path .. destfolder .. inputname, input_batch:float())\n    end\n\n  end\nend\n\nconvert(tonumber(arg[1]), \"srcfolder/\", \"destfolder/\")\n"
  },
  {
    "path": "Source/Training/train.lua",
    "content": "--- Trains the neural network.\n--\n-- Uses data generated by @{data_generation_call}.\n-- @module train\n\nrequire 'optim'\nlocal arguments = require 'Settings.arguments'\nlocal game_settings = require 'Settings.game_settings'\nrequire 'Nn.masked_huber_loss'\n\nlocal M = {}\n\n--- Saves a neural net model to disk.\n--\n-- The model is saved to `arguments.model_path` and labelled with the epoch\n-- number.\n-- @param model the neural net to save\n-- @param epoch the current epoch number\n-- @param valid_loss the validation loss of the current network\n-- @local\nfunction  M:_save_model(model, epoch, valid_loss)\n\n  local model_information = {}\n  model_information.epoch = epoch\n  model_information.valid_loss = valid_loss\n  model_information.gpu = arguments.gpu\n\n  local path = arguments.model_path\n  if game_settings.nl then\n    path = path .. \"NoLimit/\"\n  else\n    path = path .. \"Limit/\"\n  end\n  local net_type_str = arguments.gpu and '_gpu' or '_cpu'\n  local model_file_name = path .. '/epoch_' .. epoch .. net_type_str .. '.model'\n  local information_file_name = path .. '/epoch_' .. epoch .. net_type_str .. '.info'\n  torch.save(model_file_name, model)\n  torch.save(information_file_name, model_information)\nend\n\n--- Function passed to torch's [optim package](https://github.com/torch/optim).\n-- @param params_new the neural network params\n-- @param inputs the neural network inputs\n-- @param targets the neural network targets\n-- @param mask the mask vectors used for the loss function\n-- @return the masked Huber loss on `inputs` and `targets`\n-- @return the gradient of the loss function\n-- @see masked_huber_loss\n-- @local\nlocal function feval(params_new, inputs, targets, mask)\n  -- set x to x_new, if different\n  -- (in this simple implementation, x_new will typically always point to x,\n  -- so the copy is really useless)\n  if M.params ~= params_new then\n    M.params:copy(params_new)\n  end\n\n  M.grads:zero()\n  local outputs = M.network:forward(inputs)\n  local loss = M.criterion:forward(outputs, targets, mask)\n\n  -- backward\n  local dloss_doutput = M.criterion:backward(outputs, targets)\n  M.network:backward(inputs, dloss_doutput)\n\n  return loss, M.grads\nend\n\n--- Trains the neural network.\n-- @param network the neural network (see @{net_builder})\n-- @param data_stream a @{data_stream|DataStream} object which provides the\n-- training data\n-- @param epoch_count the number of epochs (passes of the training data) to train for\nfunction M:train(network, data_stream, epoch_count)\n\n  M.network = network\n  M.data_stream = data_stream\n\n  M.params, M.grads = network:getParameters()\n  M.criterion = MaskedHuberLoss()\n  if(arguments.gpu) then\n    M.criterion = M.criterion:cuda()\n  end\n\n  local state = {learningRate = arguments.learning_rate}\n  local lossSum = 0\n  local optim_func = optim.adam\n\n  -- optimization loop\n  local timer = torch.Timer()\n  for epoch = 1, epoch_count do\n    timer:reset()\n    data_stream:start_epoch(epoch)\n    lossSum = 0\n\n    if epoch == 50 then\n      state.learningRate = state.learningRate / 10\n    end\n    M.network:evaluate(false)\n    for i=1, data_stream:get_train_batch_count() do\n      local inputs, targets, mask = data_stream:get_train_batch(i)\n      assert(mask)\n      local _, loss = optim_func(function (x) return feval(x, inputs, targets, mask) end, M.params, state)\n      lossSum = lossSum + loss[1]\n    end\n\n    print(string.format(\"Training loss: %f\", lossSum / data_stream.train_batch_count))\n\n    M.network:evaluate(true)\n    --check validation loss\n    local valid_loss_sum = 0\n    for i=1, data_stream:get_valid_batch_count() do\n\n      local inputs, targets, mask = data_stream:get_valid_batch(i)\n      assert(mask)\n      local outputs = M.network:forward(inputs)\n      local loss = M.criterion:forward(outputs, targets, mask)\n      valid_loss_sum = valid_loss_sum + loss\n    end\n\n    local valid_loss = valid_loss_sum / data_stream.valid_batch_count\n    print(string.format(\"Validation loss: %f\", valid_loss))\n    print('Epoch took: ', timer:time().real)\n\n    --saving the model\n    print(epoch)\n    if epoch % arguments.save_epoch == 0 then\n      print(\"SAVING MODEL\")\n      self:_save_model(network, epoch, valid_loss)\n    end\n  end\n  --end of train loop\n\nend\n\nreturn M\n"
  },
  {
    "path": "Source/Tree/Tests/test_tree_builder.lua",
    "content": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nrequire 'Tree.tree_builder'\n\n\nlocal builder = PokerTreeBuilder()\n\nlocal params = {}\n\nparams.root_node = {}\nparams.root_node.board = card_to_string:string_to_board('')\nparams.root_node.street = 1\nparams.root_node.current_player = constants.players.P1\nparams.root_node.bets = arguments.Tensor{50, 100}\nparams.root_node.num_bets = 1\nparams.limit_to_street = true\n\nlocal tree = builder:build_tree(params)\n"
  },
  {
    "path": "Source/Tree/Tests/test_tree_cfr.lua",
    "content": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_tools = require 'Game.card_tools'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nrequire 'Tree.tree_builder'\nrequire 'Tree.tree_visualiser'\nrequire 'Tree.tree_values'\nrequire 'Tree.tree_cfr'\n\nlocal builder = PokerTreeBuilder()\n\nlocal params = {}\n\nparams.root_node = {}\nparams.root_node.board = card_to_string:string_to_board('6c6d2c2d3h')--card_to_string:string_to_board('Ks')\nparams.root_node.street = 4\nparams.root_node.current_player = constants.players.P1\nparams.root_node.bets = arguments.Tensor{4, 4}\nparams.root_node.num_bets = 0\n\nlocal tree = builder:build_tree(params)\n\nlocal starting_ranges = arguments.Tensor(constants.players_count, game_settings.hand_count)\n\nstarting_ranges[1]:copy(card_tools:get_uniform_range(params.root_node.board))\nstarting_ranges[2]:copy(card_tools:get_uniform_range(params.root_node.board))\n--starting_ranges[1]:copy(card_tools:get_random_range(params.root_node.board, 2))\n--starting_ranges[2]:copy(card_tools:get_random_range(params.root_node.board, 4))\n\nlocal tree_cfr = TreeCFR()\ntree_cfr:run_cfr(tree, starting_ranges)\n\nprint(tree.cf_values)\n\nlocal tree_values = TreeValues()\ntree_values:compute_values(tree, starting_ranges)\n\nprint('Exploitability: ' .. tree.exploitability .. '[chips]' )\n\nlocal visualiser = TreeVisualiser()\nvisualiser:graphviz(tree, 'simple_tree')\n"
  },
  {
    "path": "Source/Tree/Tests/test_tree_strategy_fillings.lua",
    "content": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal card_tools = require 'Game.card_tools'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nlocal game_settings = require 'Settings.game_settings'\nrequire 'Tree.tree_builder'\nrequire 'Tree.tree_visualiser'\nrequire 'Tree.tree_values'\nrequire 'Tree.tree_cfr'\nrequire 'Tree.tree_strategy_filling'\nrequire 'Tree.tree_visualiser'\nrequire 'Tree.tree_values'\n\nlocal builder = PokerTreeBuilder()\n\nlocal params = {}\nparams.root_node = {}\nparams.root_node.board = card_to_string:string_to_board('')\nparams.root_node.street = 1\nparams.root_node.current_player = constants.players.P1\nparams.root_node.bets = arguments.Tensor{100, 100}\n\nlocal tree = builder:build_tree(params)\n\nlocal filling = TreeStrategyFilling()\n\nlocal range1 = card_tools:get_uniform_range(params.root_node.board)\nlocal range2 = card_tools:get_uniform_range(params.root_node.board)\n\nfilling:fill_strategies(tree, 1, range1, range2)\nfilling:fill_strategies(tree, 2, range1, range2)\n\n\nlocal starting_ranges = arguments.Tensor(constants.players_count, game_settings.card_count)\nstarting_ranges[1]:copy(range1)\nstarting_ranges[2]:copy(range2)\n\nlocal tree_values = TreeValues()\ntree_values:compute_values(tree, starting_ranges)\n\nprint('Exploitability: ' .. tree.exploitability .. '[chips]' )\n\nlocal visualiser = TreeVisualiser()\nvisualiser:graphviz(tree)\n"
  },
  {
    "path": "Source/Tree/Tests/test_tree_values.lua",
    "content": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nrequire 'Tree.tree_builder'\nrequire 'Tree.tree_visualiser'\nrequire 'Tree.tree_values'\n\n\nlocal builder = PokerTreeBuilder()\n\nlocal params = {}\n\nparams.root_node = {}\nparams.root_node.board = card_to_string:string_to_board('')\nparams.root_node.street = 1\nparams.root_node.current_player = constants.players.P1\nparams.root_node.bets = arguments.Tensor{100, 100}\n\nlocal tree = builder:build_tree(params)\n\n\nlocal tree_values = TreeValues()\ntree_values:compute_values(tree)\n\nprint('Exploitability: ' .. tree.exploitability .. '[chips]' )\n\nlocal visualiser = TreeVisualiser()\nvisualiser:graphviz(tree)"
  },
  {
    "path": "Source/Tree/Tests/test_tree_visualiser.lua",
    "content": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nrequire 'Tree.tree_builder'\nrequire 'Tree.tree_visualiser'\n\nlocal builder = PokerTreeBuilder()\n\nlocal params = {}\n\nparams.root_node = {}\nparams.root_node.board = card_to_string:string_to_board('')\nparams.root_node.street = 1\nparams.root_node.current_player = constants.players.P1\nparams.root_node.bets = arguments.Tensor{50, 100}\nparams.root_node.num_bets = 0\nparams.limit_to_street = true\n\nlocal tree = builder:build_tree(params)\n\nlocal visualiser = TreeVisualiser()\n\nvisualiser:graphviz(tree, \"simple_tree\")\n"
  },
  {
    "path": "Source/Tree/strategy_filling.lua",
    "content": "--- Fills a game's public tree with a uniform strategy. In particular, fills\n-- the chance nodes with the probability of each outcome.\n--\n-- A strategy is represented at each public node by a NxK tensor where:\n--\n-- * N is the number of possible child nodes.\n--\n-- * K is the number of information sets for the active player in the public\n-- node. For the Leduc Hold'em variants we implement, there is one for each\n-- private card that the player could hold.\n--\n-- For a player node, `strategy[i][j]` gives the probability of taking the\n-- action that leads to the `i`th child when the player holds the `j`th card.\n--\n-- For a chance node, `strategy[i][j]` gives the probability of reaching the\n-- `i`th child for either player when that player holds the `j`th card.\n-- @classmod strategy_filling\n\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal math = require 'math'\nlocal card_tools = require 'Game.card_tools'\nlocal tools = require 'tools'\n\nlocal StrategyFilling = torch.class('StrategyFilling')\n\n--- Constructor\nfunction StrategyFilling:__init()\nend\n\n--- Fills a chance node with the probability of each outcome.\n-- @param node the chance node\n-- @local\nfunction StrategyFilling:_fill_chance(node)\n  assert(not node.terminal)\n\n  --filling strategy\n  --we will fill strategy with an uniform probability, but it has to be zero for hands that are not possible on\n  --corresponding board\n\n  num_boards = tools:choose(game_settings.card_count - game_settings.hand_card_count * constants.players_count,\n    game_settings.board_card_count[node.street+1] - game_settings.board_card_count[node.street])\n\n  node.strategy = arguments.Tensor(#node.children, game_settings.hand_count):fill(0)\n  --setting probability of impossible hands to 0\n  for i = 1,#node.children do\n    local child_node = node.children[i]\n    local mask = card_tools:get_possible_hand_indexes(child_node.board):byte()\n    node.strategy[i]:fill(0)\n    --remove 2 because each player holds one card\n    node.strategy[i][mask] = 1.0 / (game_settings.card_count - 2)\n  end\nend\n\n--- Fills a player node with a uniform strategy.\n-- @param node the player node\n-- @local\nfunction StrategyFilling:_fill_uniformly(node)\n  assert(node.current_player == constants.players.P1 or node.current_player == constants.players.P2)\n\n  if(node.terminal) then\n    return\n  end\n\n  node.strategy = arguments.Tensor(#node.children, game_settings.hand_count):fill(1.0 / #node.children)\nend\n\n--- Fills a node with a uniform strategy and recurses on the children.\n-- @param node the node\n-- @local\nfunction StrategyFilling:_fill_uniform_dfs(node)\n  if node.current_player == constants.players.chance then\n    self:_fill_chance(node)\n  else\n    self:_fill_uniformly(node)\n  end\n\n  for i=1,#node.children do\n    self:_fill_uniform_dfs(node.children[i])\n  end\nend\n\n--- Fills a public tree with a uniform strategy.\n-- @param tree a public tree for Leduc Hold'em or variant\nfunction StrategyFilling:fill_uniform(tree)\n  self:_fill_uniform_dfs(tree)\nend\n"
  },
  {
    "path": "Source/Tree/tree_builder.lua",
    "content": "--- Builds a public tree for Leduc Hold'em or variants.\n--\n-- Each node of the tree contains the following fields:\n--\n-- * `node_type`: an element of @{constants.node_types} (if applicable)\n--\n-- * `street`: the current betting round\n--\n-- * `board`: a possibly empty vector of board cards\n--\n-- * `board_string`: a string representation of the board cards\n--\n-- * `current_player`: the player acting at the node\n--\n-- * `bets`: the number of chips that each player has committed to the pot\n--\n-- * `pot`: half the pot size, equal to the smaller number in `bets`\n--\n-- * `children`: a list of children nodes\n-- @classmod tree_builder\n\nlocal math = require 'math'\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_tools = require 'Game.card_tools'\nlocal card_to_string = require 'Game.card_to_string_conversion'\nrequire 'Tree.strategy_filling'\nrequire 'Game.bet_sizing'\n\nlocal PokerTreeBuilder = torch.class('PokerTreeBuilder')\n\n--- Constructor\nfunction PokerTreeBuilder:__init()\nend\n\n--- Creates the children nodes after a chance node.\n-- @param parent_node the chance node\n-- @return a list of children nodes\n-- @local\nfunction PokerTreeBuilder:_get_children_nodes_chance_node(parent_node)\n  assert(parent_node.current_player == constants.players.chance)\n\n  if self.limit_to_street then\n    return {}\n  end\n\n  local next_boards = card_tools:get_boards(parent_node.street+1)\n  local next_boards_count = next_boards:size(1)\n\n  local subtree_height = -1\n  local children = {}\n\n  --1.0 iterate over the next possible boards to build the corresponding subtrees\n  for i=1,next_boards_count do\n    local next_board = next_boards[i]\n    local next_board_string = card_to_string:cards_to_string(next_board)\n\n    local child = {}\n\n    child.node_type = constants.node_types.inner_node\n    child.parent = parent_node\n    child.current_player = constants.players.P1\n    child.street = parent_node.street + 1\n    child.board = next_board\n    child.board_string = next_board_string\n    child.bets = parent_node.bets:clone()\n\n    table.insert(children, child)\n  end\n\n  return children\nend\n\n--- Fills in additional convenience attributes which only depend on existing\n-- node attributes.\n-- @param node the node\n-- @local\nfunction PokerTreeBuilder:_fill_additional_attributes(node)\n  node.pot = node.bets:min()\nend\n\n--- Creates the children nodes after a player node.\n-- @param parent_node the chance node\n-- @return a list of children nodes\n-- @local\nfunction PokerTreeBuilder:_get_children_player_node(parent_node)\n  assert(parent_node.current_player ~= constants.players.chance)\n\n  local children = {}\n\n  --1.0 fold action\n  --if parent_node.bets[1] ~= parent_node.bets[2] then\n    local fold_node = {}\n    fold_node.type = constants.node_types.terminal_fold\n    fold_node.terminal = true\n    fold_node.current_player = 3 - parent_node.current_player\n    fold_node.street = parent_node.street\n    fold_node.board = parent_node.board\n    fold_node.board_string = parent_node.board_string\n    fold_node.bets = parent_node.bets:clone()\n    table.insert(children, fold_node)\n  --end\n\n  --2.0 check/call action\n  if  (parent_node.street == 1 and parent_node.current_player == constants.players.P1 and\n       parent_node.num_bets == 1 and (game_settings.limit_bet_cap > 1 or game_settings.nl)) or\n      ((parent_node.street ~= 1 or constants.streets_count == 1) and parent_node.current_player == constants.players.P2 and parent_node.bets[1] == parent_node.bets[2]) then\n    local check_node = {}\n    check_node.type = constants.node_types.check\n    check_node.terminal = false\n    check_node.current_player = 3 - parent_node.current_player\n    check_node.street = parent_node.street\n    check_node.board = parent_node.board\n    check_node.board_string = parent_node.board_string\n    check_node.bets = parent_node.bets:clone():fill(parent_node.bets:max())\n    check_node.num_bets = parent_node.num_bets\n    table.insert(children, check_node)\n  --transition check/call\n  elseif parent_node.street ~= constants.streets_count and (\n    (parent_node.bets[1] == parent_node.bets[2] and\n      ((parent_node.street == 1 and parent_node.current_player == constants.players.P2) or\n       (parent_node.street ~= 1 and parent_node.current_player == constants.players.P1))) or\n    (parent_node.bets[1] ~= parent_node.bets[2] and parent_node.bets:max() < arguments.stack)) then\n    local chance_node = {}\n    chance_node.node_type = constants.node_types.chance_node\n    chance_node.street = parent_node.street\n    chance_node.board = parent_node.board\n    chance_node.board_string = parent_node.board_string\n    chance_node.current_player = constants.players.chance\n    chance_node.bets = parent_node.bets:clone():fill(parent_node.bets:max())\n    chance_node.num_bets = 0\n    table.insert(children, chance_node)\n  else\n  --2.0 terminal call - either last street or allin\n    local terminal_call_node = {}\n    terminal_call_node.type = constants.node_types.terminal_call\n    terminal_call_node.terminal = true\n    terminal_call_node.current_player = 3 - parent_node.current_player\n    terminal_call_node.street = parent_node.street\n    terminal_call_node.board = parent_node.board\n    terminal_call_node.board_string = parent_node.board_string\n    terminal_call_node.bets = parent_node.bets:clone():fill(parent_node.bets:max())\n    table.insert(children, terminal_call_node)\n  end\n\n  --3.0 bet actions\n\n  if not game_settings.nl then\n    if parent_node.num_bets < game_settings.limit_bet_cap then\n      local child = {}\n      child.parent = parent_node\n      child.current_player = 3 - parent_node.current_player\n      child.street = parent_node.street\n      child.board = parent_node.board\n      child.board_string = parent_node.board_string\n      child.bets = parent_node.bets:clone()\n      betsize = game_settings.limit_bet_sizes[parent_node.street]\n      if parent_node.current_player == constants.players.P1 then\n        child.bets[1] = child.bets[2] + betsize\n      else\n        child.bets[2] = child.bets[1] + betsize\n      end\n      child.num_bets = parent_node.num_bets + 1\n      table.insert(children, child)\n    end\n  else\n    local possible_bets = self.bet_sizing:get_possible_bets(parent_node)\n\n    if possible_bets:dim() ~= 0 then\n      assert(possible_bets:size(2) == 2)\n\n      for i=1, possible_bets:size(1) do\n        local child = {}\n        child.parent = parent_node\n        child.current_player = 3 - parent_node.current_player\n        child.street = parent_node.street\n        child.board = parent_node.board\n        child.board_string = parent_node.board_string\n        child.bets = possible_bets[i]\n        table.insert(children, child)\n      end\n    end\n  end\n\n  return children\nend\n\n--- Creates the children after a node.\n-- @param parent_node the node to create children for\n-- @return a list of children nodes\n-- @local\nfunction PokerTreeBuilder:_get_children_nodes(parent_node)\n  local chance_node = parent_node.current_player == constants.players.chance\n  --transition call -> create a chance node\n  if parent_node.terminal then\n    return {}\n  --chance node\n  elseif chance_node then\n    return self:_get_children_nodes_chance_node(parent_node)\n  --inner nodes -> handle bet sizes\n  else\n    return self:_get_children_player_node(parent_node)\n  end\n\n  assert(false)\nend\n\n--- Recursively build the (sub)tree rooted at the current node.\n-- @param current_node the root to build the (sub)tree from\n-- @return `current_node` after the (sub)tree has been built\n-- @local\nfunction PokerTreeBuilder:_build_tree_dfs(current_node)\n\n  self:_fill_additional_attributes(current_node)\n  local children = self:_get_children_nodes(current_node)\n  current_node.children = children\n\n  local depth = 0\n\n  current_node.actions = arguments.Tensor(#children)\n  for i=1,#children do\n    children[i].parent = current_node\n    self:_build_tree_dfs(children[i])\n    depth = math.max(depth, children[i].depth)\n\n    if i == 1 then\n      current_node.actions[i] = constants.actions.fold\n    elseif i == 2 then\n      current_node.actions[i] = constants.actions.ccall\n    else\n      if not game_settings.nl then\n        assert(i == 3, 'wtf child')\n        current_node.actions[i] = constants.actions.raise\n      else\n        current_node.actions[i] = children[i].bets:max()\n      end\n    end\n  end\n\n  current_node.depth = depth + 1\n\n  return current_node\nend\n\n--- Builds the tree.\n-- @param params table of tree parameters, containing the following fields:\n--\n-- * `street`: the betting round of the root node\n--\n-- * `bets`: the number of chips committed at the root node by each player\n--\n-- * `current_player`: the acting player at the root node\n--\n-- * `board`: a possibly empty vector of board cards at the root node\n--\n-- * `limit_to_street`: if `true`, only build the current betting round\n--\n-- * `bet_sizing` (optional): a @{bet_sizing} object which gives the allowed\n-- bets for each player\n-- @return the root node of the built tree\nfunction PokerTreeBuilder:build_tree(params)\n  local root = {}\n  --copy necessary stuff from the root_node not to touch the input\n  root.street = params.root_node.street\n  root.bets = params.root_node.bets:clone()\n  root.num_bets = params.root_node.num_bets\n  root.current_player = params.root_node.current_player\n  root.board = params.root_node.board:clone()\n\n  params.bet_sizing = params.bet_sizing or\n    BetSizing(arguments.bet_sizing)\n  assert(params.bet_sizing)\n  self.bet_sizing = params.bet_sizing\n  self.limit_to_street = params.limit_to_street\n\n  self:_build_tree_dfs(root)\n\n  local strategy_filling = StrategyFilling()\n  strategy_filling:fill_uniform(root)\n\n  return root\nend\n"
  },
  {
    "path": "Source/Tree/tree_cfr.lua",
    "content": "--- Runs Counterfactual Regret Minimization (CFR) to approximately\n-- solve a game represented by a complete game tree.\n--\n-- As this class does full solving from the root of the game with no\n-- limited lookahead, it is not used in continual re-solving. It is provided\n-- simply for convenience.\n-- @classmod tree_cfr\n\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_tools = require 'Game.card_tools'\nrequire 'TerminalEquity.terminal_equity'\n\nlocal TreeCFR = torch.class('TreeCFR')\n\n--- Constructor\nfunction TreeCFR:__init()\n  --for ease of implementation, we use small epsilon rather than zero when working with regrets\n  self.regret_epsilon = 1/1000000000\n  self._cached_terminal_equities = {}\nend\n\n--- Gets an evaluator for player equities at a terminal node.\n--\n-- Caches the result to minimize creation of @{terminal_equity|TerminalEquity}\n-- objects.\n-- @param node the terminal node to evaluate\n-- @return a @{terminal_equity|TerminalEquity} evaluator for the node\n-- @local\nfunction TreeCFR:_get_terminal_equity(node)\n  local cached = self._cached_terminal_equities[node.board]\n  if cached == nil then\n    cached = TerminalEquity()\n    cached:set_board(node.board)\n    self._cached_terminal_equities[node.board] = cached\n  end\n\n  return cached\nend\n\n--- Recursively walks the tree, applying the CFR algorithm.\n-- @param node the current node in the tree\n-- @param iter the current iteration number\n-- @local\nfunction TreeCFR:cfrs_iter_dfs( node, iter )\n\n  assert(node.current_player == constants.players.P1 or node.current_player == constants.players.P2 or node.current_player == constants.players.chance)\n\n  local opponent_index = 3 - node.current_player\n\n  --dimensions in tensor\n  local action_dimension = 1\n  local card_dimension = 2\n\n  --compute values using terminal_equity in terminal nodes\n  if(node.terminal) then\n\n    local terminal_equity = self:_get_terminal_equity(node)\n\n    local values = node.ranges_absolute:clone():fill(0)\n\n    if(node.type == constants.node_types.terminal_fold) then\n      terminal_equity:tree_node_fold_value(node.ranges_absolute, values, opponent_index)\n    else\n      terminal_equity:tree_node_call_value(node.ranges_absolute, values)\n    end\n\n    --multiply by the pot\n    values = values * node.pot\n    node.cf_values = values:viewAs(node.ranges_absolute)\n  else\n\n    local actions_count = #node.children\n    local current_strategy = nil\n\n    if node.current_player == constants.players.chance then\n      current_strategy = node.strategy\n    else\n      --we have to compute current strategy at the beginning of each iteraton\n\n      --initialize regrets in the first iteration\n      node.regrets = node.regrets or arguments.Tensor(actions_count, game_settings.hand_count):fill(self.regret_epsilon) --[[actions_count x hand_count]]\n      node.possitive_regrets = node.possitive_regrets or arguments.Tensor(actions_count, game_settings.hand_count):fill(self.regret_epsilon)\n\n      --compute positive regrets so that we can compute the current strategy fromm them\n      node.possitive_regrets:copy(node.regrets)\n      node.possitive_regrets[torch.le(node.possitive_regrets, self.regret_epsilon)] = self.regret_epsilon\n\n      --compute the current strategy\n      local regrets_sum = node.possitive_regrets:sum(action_dimension)\n      current_strategy = node.possitive_regrets:clone()\n      current_strategy:cdiv(regrets_sum:expandAs(current_strategy))\n    end\n\n\t--current cfv [[actions, players, ranges]]\n    local cf_values_allactions = arguments.Tensor(actions_count, constants.players_count, game_settings.hand_count):fill(0)\n\n    local children_ranges_absolute = {}\n\n    if node.current_player == constants.players.chance then\n      local ranges_mul_matrix = node.ranges_absolute[1]:repeatTensor(actions_count, 1)\n      children_ranges_absolute[1] = torch.cmul(current_strategy, ranges_mul_matrix)\n\n      ranges_mul_matrix = node.ranges_absolute[2]:repeatTensor(actions_count, 1)\n      children_ranges_absolute[2] = torch.cmul(current_strategy, ranges_mul_matrix)\n    else\n      local ranges_mul_matrix = node.ranges_absolute[node.current_player]:repeatTensor(actions_count, 1)\n      children_ranges_absolute[node.current_player] = torch.cmul(current_strategy, ranges_mul_matrix)\n\n      children_ranges_absolute[opponent_index] = node.ranges_absolute[opponent_index]:repeatTensor(actions_count, 1):clone()\n    end\n\n    for i = 1,#node.children do\n      local child_node = node.children[i]\n      --set new absolute ranges (after the action) for the child\n      child_node.ranges_absolute = node.ranges_absolute:clone()\n\n      child_node.ranges_absolute[1]:copy(children_ranges_absolute[1][{i}])\n      child_node.ranges_absolute[2]:copy(children_ranges_absolute[2][{i}])\n      self:cfrs_iter_dfs(child_node, iter, hand_count)\n      cf_values_allactions[i] = child_node.cf_values\n    end\n\n    node.cf_values = arguments.Tensor(constants.players_count, game_settings.hand_count):fill(0)\n\n    if node.current_player ~= constants.players.chance then\n      local strategy_mul_matrix = current_strategy:viewAs(arguments.Tensor(actions_count, game_settings.hand_count))\n\n      node.cf_values[node.current_player] = torch.cmul(strategy_mul_matrix, cf_values_allactions[{{}, node.current_player, {}}]):sum(1)\n      node.cf_values[opponent_index] = (cf_values_allactions[{{}, opponent_index, {}}]):sum(1)\n    else\n      node.cf_values[1] = (cf_values_allactions[{{}, 1, {}}]):sum(1)\n      node.cf_values[2] = (cf_values_allactions[{{}, 2, {}}]):sum(1)\n    end\n\n    if node.current_player ~= constants.players.chance then\n      --computing regrets\n      local current_regrets = cf_values_allactions[{{}, {node.current_player}, {}}]:reshape(actions_count, game_settings.hand_count):clone()\n      current_regrets:csub(node.cf_values[node.current_player]:view(1, game_settings.hand_count):expandAs(current_regrets))\n\n      self:update_regrets(node, current_regrets)\n\n      --accumulating average strategy\n      self:update_average_strategy(node, current_strategy, iter)\n    end\n  end\nend\n\n--- Update a node's total regrets with the current iteration regrets.\n-- @param node the node to update\n-- @param current_regrets the regrets from the current iteration of CFR\n-- @local\nfunction TreeCFR:update_regrets(node, current_regrets)\n  --node.regrets:add(current_regrets)\n  --local negative_regrets = node.regrets[node.regrets:lt(0)]\n  --node.regrets[node.regrets:lt(0)] = negative_regrets\n  node.regrets:add(current_regrets)\n  node.regrets[torch.le(node.regrets, self.regret_epsilon)] = self.regret_epsilon\nend\n\n--- Update a node's average strategy with the current iteration strategy.\n-- @param node the node to update\n-- @param current_strategy the CFR strategy for the current iteration\n-- @param iter the iteration number of the current CFR iteration\nfunction TreeCFR:update_average_strategy(node, current_strategy, iter)\n  if iter > arguments.cfr_skip_iters then\n    node.strategy = node.strategy or arguments.Tensor(actions_count, game_settings.hand_count):fill(0)\n    node.iter_weight_sum = node.iter_weight_sum or arguments.Tensor(game_settings.hand_count):fill(0)\n    local iter_weight_contribution = node.ranges_absolute[node.current_player]:clone()\n    iter_weight_contribution[torch.le(iter_weight_contribution, 0)] = self.regret_epsilon\n    node.iter_weight_sum:add(iter_weight_contribution)\n    local iter_weight = torch.cdiv(iter_weight_contribution, node.iter_weight_sum)\n\n    local expanded_weight = iter_weight:view(1, game_settings.hand_count):expandAs(node.strategy)\n    local old_strategy_scale = expanded_weight * (-1) + 1 --same as 1 - expanded weight\n    node.strategy:cmul(old_strategy_scale)\n    local strategy_addition = current_strategy:cmul(expanded_weight)\n    node.strategy:add(strategy_addition)\n  end\nend\n\n--- Run CFR to solve the given game tree.\n-- @param root the root node of the tree to solve.\n-- @param[opt] starting_ranges probability vectors over player private hands\n-- at the root node (default uniform)\n-- @param[opt] iter_count the number of iterations to run CFR for\n-- (default @{arguments.cfr_iters})\nfunction TreeCFR:run_cfr( root, starting_ranges, iter_count )\n\n  assert(starting_ranges)\n  local iter_count = iter_count or arguments.cfr_iters\n\n  root.ranges_absolute =  starting_ranges\n\n  for iter = 1,iter_count do\n    self:cfrs_iter_dfs(root, iter)\n  end\nend\n"
  },
  {
    "path": "Source/Tree/tree_strategy_filling.lua",
    "content": "--- Recursively performs continual re-solving at every node of a public tree to\n-- generate the DeepStack strategy for the entire game.\n-- \n-- A strategy is represented at each public node by a NxK tensor where:\n-- \n-- * N is the number of possible child nodes.\n-- \n-- * K is the number of information sets for the active player in the public \n-- node. For the Leduc Hold'em variants we implement, there is one for each\n-- private card that the player could hold.\n-- \n-- For a player node, `strategy[i][j]` gives the probability of taking the\n-- action  that leads to the `i`th child when the player holds the `j`th card.\n-- \n-- For a chance node, `strategy[i][j]` gives the probability of reaching the\n-- `i`th child for either player when that player holds the `j`th card.\n-- @classmod tree_strategy_filling\n\nrequire 'math'\nlocal arguments = require 'Settings.arguments'\nlocal card_tools = require 'Game.card_tools'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nrequire 'Lookahead.mock_resolving'\nrequire 'Lookahead.resolving'\n\nlocal TreeStrategyFilling = torch.class('TreeStrategyFilling')\n\n--- Constructor\nfunction TreeStrategyFilling:__init()\n  self.board_count = card_tools:get_boards_count()\nend\n\n--- Fills all chance nodes of a subtree with the probability of each outcome.\n-- @param node the root of the subtree\n-- @local\nfunction TreeStrategyFilling:_fill_chance(node)\n  if(node.terminal) then\n    return\n  end\n  if node.current_player == constants.players.chance then --chance node, we will fill uniform strategy \n    --works only for chance node at start of second round\n    assert(#node.children == self.board_count)\n    --filling strategy\n    --we will fill strategy with an uniform probability, but it has to be zero for hands that are not possible on\n    --corresponding board\n    node.strategy = arguments.Tensor(#node.children, game_settings.card_count):fill(0)\n    --setting strategy for impossible hands to 0\n    for i = 1,#node.children do\n      local child_node = node.children[i]\n      local mask = card_tools:get_possible_hand_indexes(child_node.board):byte()\n      node.strategy[i][mask] = 1.0/(self.board_count - 2)\n    end\n  end\n\n  for i = 1,#node.children do\n    local child_node = node.children[i]\n    self:_fill_chance(child_node)\n  end\nend\n\n--- Recursively fills a subtree with a uniform random strategy for the given\n--  player.\n-- \n-- Used in sections of the game to which the player doesn't play.\n--\n-- @param node the root of the subtree\n-- @param player the player which is given the uniform random strategy\n-- @local\nfunction TreeStrategyFilling:_fill_uniformly(node, player)\n  if(node.terminal) then\n    return\n  end\n  if node.current_player == player then\n    --fill uniform strategy\n    node.strategy = arguments.Tensor(#node.children, game_settings.card_count):fill(1.0 / #node.children)\n  end\n\n  for i = 1,#node.children do\n    local child_node = node.children[i]\n    self:_fill_uniformly(child_node, player)\n  end\nend\n\n--- Recursively fills a player's strategy for the subtree rooted at an \n-- opponent node.\n-- \n-- @param params tree walk parameters (see @{_fill_strategies_dfs})\n-- @local\nfunction TreeStrategyFilling:_process_opponent_node(params)\n  --  node, player, range, cf_values, strategy_computation, our_last_action\n  local node = params.node\n  local player = params.player\n  local range = params.range\n  local cf_values = params.cf_values\n  local resolving = params.resolving\n  local our_last_action = params.our_last_action\n\n  assert(not node.terminal and node.current_player ~= player)\n  \n  --when opponent plays, we will do nothing except sending cf_values to the child nodes\n  for i = 1,#node.children do\n    local child_node = node.children[i]\n    if not child_node.terminal then\n      local child_params = {}\n      child_params.node = child_node\n      child_params.range = range\n      child_params.player = player\n      child_params.cf_values = cf_values\n      child_params.resolving = params.resolving\n      child_params.our_last_action = our_last_action\n\n      self:_fill_strategies_dfs(child_params)\n    end\n  end\nend\n\n--- Recursively fills a player's strategy in a tree.\n-- \n-- @param node the root of the tree\n-- @param player the player to calculate a strategy for\n-- @param p1_range a probability vector of the first player's private hand \n-- at the root\n-- @param p2_range a probability vector of the second player's private hand\n-- at the root\n-- @local\nfunction TreeStrategyFilling:_fill_starting_node(node, player, p1_range, p2_range)\n\n  assert(not node.terminal)\n  assert(node.current_player == constants.players.P1)\n\n  --re-solving the node\n  local resolving = Resolving()\n  resolving:resolve_first_node(node, p1_range, p2_range)\n  --check which player plays first\n  if node.current_player == player then\n    self:_fill_computed_node(node, player, p1_range, resolving)\n  else\n    --opponent plays in this node. we need only cf-values at the beginning and we will just copy them\n    local cf_values = resolving:get_root_cfv()\n    local child_params = {}\n    child_params.node = node\n    child_params.range = p2_range\n    child_params.player = player\n    child_params.cf_values = cf_values\n    self:_process_opponent_node(child_params)\n  end\nend\n\n--- Recursively fills a player's strategy for the subtree rooted at a \n-- player node.\n--\n-- Re-solves to generate a strategy for the player node.\n-- \n-- @param params tree walk parameters (see @{_fill_strategies_dfs})\n-- @local\nfunction TreeStrategyFilling:_fill_player_node(params)\n  local node = params.node\n  local player = params.player\n  local range = params.range\n  local cf_values = params.cf_values\n  local opponent_range = params.opponent_range\n  assert(not node.terminal and node.current_player == player)\n  --now player plays, we have to compute his strategy\n  local resolving = Resolving()\n  resolving:resolve(node, range, cf_values)\n  --we will send opponent range to adjust range also in our second action in the street \n  self:_fill_computed_node(node, player, range, resolving)\nend\n\n--- Recursively fills a player's strategy for the subtree rooted at a \n-- player node.\n-- \n-- @param node the player node\n-- @param player the player to fill the strategy for\n-- @param range a probability vector giving the player's range at the node\n-- @param resolving a @{resolving|Resolving} object which has been used to\n-- re-solve the node\n-- @local\nfunction TreeStrategyFilling:_fill_computed_node(node, player, range, resolving)\n\n  assert(resolving)\n  assert(node.current_player == player)\n  local player_actions = resolving:get_possible_actions()\n\n  local actions_count = #node.children\n  assert(actions_count == node.actions:size(1))\n\n  --find which bets are used by player\n  local used_bets = torch.ByteTensor(actions_count):zero()\n  for i = 1, player_actions:size(1) do\n    local player_action = player_actions[i]\n    local bet_indicator = torch.eq(node.actions, player_action)\n    --there has to be exactly one equivalent bet\n    assert(bet_indicator:sum(1)[1] == 1)\n    used_bets:add(bet_indicator:typeAs(used_bets))\n  end\n  --check if terminal actions are used and if all player bets are used\n  assert(used_bets[1] == 1 and used_bets[2] == 1)\n  assert(used_bets:sum(1)[1] == player_actions:size(1))\n\n  --fill the strategy\n  node.strategy = arguments.Tensor(actions_count, game_settings.card_count):zero()\n  local cf_values = arguments.Tensor(actions_count, game_settings.card_count):zero()\n\n  --we need to compute all values and ranges before dfs call, becasue\n  --re-solving will be built from different node in the recursion\n\n  --in first cycle, fill nodes we do not play in and fill strategies and cf-values\n  for i=1, actions_count do\n    local child_node = node.children[i]\n    --check if the bet is possible\n    if used_bets[i] == 0 then\n      self:_fill_uniformly(child_node, player)\n    else\n      local action = node.actions[i]\n      local values_after_action = resolving:get_action_cfv(action)\n      cf_values[i]:copy(values_after_action)\n      node.strategy[i] = resolving:get_action_strategy(action)\n    end\n  end\n\n  --compute ranges for each action\n  local range_after_action = node.strategy:clone()\n  range_after_action:cmul(range:view(1, game_settings.card_count):expandAs(range_after_action)) -- new range = range * strategy\n  --normalize the ranges\n  local normalization_factor = range_after_action:sum(2)\n  normalization_factor[torch.eq(normalization_factor, 0)] = 1\n  range_after_action:cdiv(normalization_factor:expandAs(range_after_action))\n\n  --in second cycle, run dfs computation\n  for action = 1, actions_count do\n    local child_node = node.children[action]\n    if used_bets[action] ~= 0 then\n\n      if not (math.abs(range_after_action[action]:sum(1)[1] - 1) < 0.001) then\n        assert(range_after_action[action]:sum() == 0, range_after_action[action]:sum())\n        self:_fill_uniformly(child_node, player)\n      else\n        assert(math.abs(range_after_action[action]:sum(1)[1] - 1) < 0.001)\n\n        local params = {}\n        params.node = child_node\n        params.range = range_after_action[action]\n        params.player = player\n        params.cf_values =  cf_values[action]\n        params.resolving = resolving\n        params.our_last_action = node.actions[action]\n        params.opponent_range = opponent_range\n        self:_fill_strategies_dfs(params)\n      end\n    end\n  end\nend\n\n--- Recursively fills a player's strategy for the subtree rooted at a \n-- chance node.\n-- \n-- @param params tree walk parameters (see @{_fill_strategies_dfs})\n-- @local\nfunction TreeStrategyFilling:_process_chance_node(params)\n  local resolving = params.resolving\n  local node = params.node\n  local player = params.player\n  local range = params.range\n  local cf_values = params.cf_values\n  local our_last_action = params.our_last_action\n  assert(resolving)\n  assert(our_last_action)\n  assert(not node.terminal and node.current_player == constants.players.chance)\n  --on chance node we need to recompute values in next round\n  for i = 1,#node.children do\n    local child_node = node.children[i]\n\n    assert(child_node.current_player == constants.players.P1)\n    assert(not child_node.terminal)\n    --computing cf_values for the child node\n    local child_cf_values = resolving:get_chance_action_cfv(our_last_action, child_node.board)\n    --we need to remove impossible hands from the range and then renormalize it\n    local child_range = range:clone()\n    local mask = card_tools:get_possible_hand_indexes(child_node.board)\n    child_range:cmul(mask)\n    local range_weight = child_range:sum(1)[1] --weight should be single number\n    child_range:mul(1/range_weight)\n\n    --we should never touch same re-solving again after the chance action, set it to nil\n    local params = {}\n    params.node = child_node\n    params.range = child_range\n    params.player = player\n    params.cf_values = child_cf_values\n    params.resolving = nil\n    params.our_last_action = nil\n    self:_fill_strategies_dfs(params)\n  end\nend\n\n--- Recursively fills a player's strategy for a subtree.\n-- \n-- @param params a table of tree walk parameters with the following fields:\n-- \n-- * `node`: the root of the subtree\n--\n-- * `player`: the player to fill the strategy for\n-- \n-- * `range`: a probability vector over the player's private hands at the node\n-- \n-- * `cf_values`: a vector of opponent counterfactual values at the node\n-- \n-- * `resolving`: a @{resolving|Resolving} object which was used to\n-- re-solve the last player node\n-- \n-- * `our_last_action`: the action taken by the player at their last node\n-- @local\nfunction TreeStrategyFilling:_fill_strategies_dfs(params)\n  assert(params.player == constants.players.chance or params.player == constants.players.P1 or params.player == constants.players.P2)\n  if(params.node.terminal) then\n    return\n  elseif(params.node.current_player == constants.players.chance) then --chance node\n    self:_process_chance_node(params)\n  elseif(params.node.current_player == params.player ) then\n    self:_fill_player_node(params)\n  else\n    self:_process_opponent_node(params)\n  end\nend\n\n--- Fills a tree with a player's strategy generated with continual re-solving.\n-- \n-- Recursively does continual re-solving on every node of the tree to generate\n-- the strategy for that node.\n--\n-- @param root the root of the tree\n-- @param player the player to fill the strategy for\n-- @param p1_range a probability vector over the first player's private hands\n-- at the root of the tree\n-- @param p2_range a probability vector over the second player's private hands\n-- at the root of the tree\nfunction TreeStrategyFilling:fill_strategies( root, player, p1_range, p2_range )\n  self.current_filling_player = player\n  if player == constants.players.chance then\n    self:_fill_chance(root)\n  else\n    assert(player == constants.players.P1 or player == constants.players.P2)\n    self:_fill_starting_node(root, player, p1_range, p2_range)\n  end\nend\n\n--- Fills a tree with uniform random strategies for both players.\n-- @param root the root of the tree\nfunction TreeStrategyFilling:fill_uniform_strategy(root)\n  self:_fill_uniformly(root, constants.players.P1)\n  self:_fill_uniformly(root, constants.players.P2)\nend"
  },
  {
    "path": "Source/Tree/tree_values.lua",
    "content": "--- Computes the expected value of a strategy profile on a game's public tree,\n-- as well as the value of a best response against the profile.\n-- @classmod tree_values\n\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = require 'Settings.game_settings'\nlocal card_tools = require 'Game.card_tools'\nrequire 'TerminalEquity.terminal_equity'\n\nlocal TreeValues = torch.class('TreeValues')\n\n--- Constructor\nfunction TreeValues:__init()\n  self.terminal_equity = TerminalEquity()\nend\n\n--- Recursively walk the tree and calculate the probability of reaching each\n-- node using the saved strategy profile.\n--\n-- The reach probabilities are saved in the `ranges_absolute` field of each\n-- node.\n-- @param node the current node of the tree\n-- @param ranges_absolute a 2xK tensor containing the probabilities of each\n-- player reaching the current node with each private hand\n-- @local\nfunction TreeValues:_fill_ranges_dfs(node, ranges_absolute)\n  node.ranges_absolute = ranges_absolute:clone()\n\n  if(node.terminal) then\n    return\n  end\n\n  assert(node.strategy)\n\n  local actions_count = #node.children\n\n  --check that it's a legal strategy\n  local strategy_to_check = node.strategy\n\n  local hands_mask = card_tools:get_possible_hand_indexes(node.board)\n\n  if node.current_player ~= constants.players.chance then\n    local checksum = strategy_to_check:sum(1)\n    assert(not torch.any(strategy_to_check:lt(0)))\n    assert(not torch.any(checksum:gt(1.001)))\n    assert(not torch.any(checksum:lt(0.999)))\n    assert(not torch.any(checksum:ne(checksum)))\n  end\n\n  assert(node.ranges_absolute:lt(0):sum() == 0)\n  assert(node.ranges_absolute:gt(1):sum() == 0)\n\n  --check if the range consists only of cards that don't overlap with the board\n  local impossible_hands_mask = hands_mask:clone():fill(1) - hands_mask\n  local impossible_range_sum = node.ranges_absolute:clone():cmul(impossible_hands_mask:view(1, game_settings.card_count):expandAs(node.ranges_absolute)):sum()\n  assert(impossible_range_sum == 0, impossible_range_sum)\n\n  local children_ranges_absolute = arguments.Tensor(#node.children, constants.players_count, game_settings.card_count)\n\n  --chance player\n  if node.current_player == constants.players.chance then\n    --multiply ranges of both players by the chance prob\n    children_ranges_absolute[{{}, constants.players.P1, {}}]:copy(node.ranges_absolute[constants.players.P1]:repeatTensor(actions_count, 1))\n    children_ranges_absolute[{{}, constants.players.P2, {}}]:copy(node.ranges_absolute[constants.players.P2]:repeatTensor(actions_count, 1))\n\n    children_ranges_absolute[{{}, constants.players.P1, {}}]:cmul(node.strategy)\n    children_ranges_absolute[{{}, constants.players.P2, {}}]:cmul(node.strategy)\n  --player\n  else\n    --copy the range for the non-acting player\n    children_ranges_absolute[{{}, 3-node.current_player, {}}] = node.ranges_absolute[3-node.current_player]:clone():repeatTensor(actions_count, 1)\n\n    --multiply the range for the acting player using his strategy\n    local ranges_mul_matrix = node.ranges_absolute[node.current_player]:repeatTensor(actions_count, 1)\n    children_ranges_absolute[{{}, node.current_player, {}}] = torch.cmul(node.strategy, ranges_mul_matrix)\n  end\n\n  --fill the ranges for the children\n  for i = 1,#node.children do\n    local child_node = node.children[i]\n    local child_range = children_ranges_absolute[i]\n\n    --go deeper\n    self:_fill_ranges_dfs(child_node, child_range)\n  end\nend\n\n--- Recursively calculate the counterfactual values for each player at each\n-- node of the tree using the saved strategy profile.\n--\n-- The cfvs for each player in the given strategy profile when playing against\n-- each other is stored in the `cf_values` field for each node. The cfvs for\n-- a best response against each player in the profile are stored in the\n-- `cf_values_br` field for each node.\n-- @param node the current node\n-- @local\nfunction TreeValues:_compute_values_dfs(node)\n\n  --compute values using terminal_equity in terminal nodes\n  if(node.terminal) then\n\n    assert(node.type == constants.node_types.terminal_fold or node.type == constants.node_types.terminal_call)\n\n    self.terminal_equity:set_board(node.board)\n\n    local values = node.ranges_absolute:clone():fill(0)\n\n    if(node.type == constants.node_types.terminal_fold) then\n      self.terminal_equity:tree_node_fold_value(node.ranges_absolute, values, 3-node.current_player)\n    else\n      self.terminal_equity:tree_node_call_value(node.ranges_absolute, values)\n    end\n\n    --multiply by the pot\n    values = values * node.pot\n\n    node.cf_values = values:viewAs(node.ranges_absolute)\n    node.cf_values_br = values:viewAs(node.ranges_absolute)\n  else\n\n    local actions_count = #node.children\n    local ranges_size = node.ranges_absolute:size(2)\n\n    --[[actions, players, ranges]]\n    local cf_values_allactions = arguments.Tensor(#node.children, 2, ranges_size):fill(0)\n    local cf_values_br_allactions = arguments.Tensor(#node.children, 2, ranges_size):fill(0)\n\n    for i = 1,#node.children do\n      local child_node = node.children[i]\n      self:_compute_values_dfs(child_node)\n      cf_values_allactions[i] = child_node.cf_values\n      cf_values_br_allactions[i] = child_node.cf_values_br\n    end\n\n    node.cf_values = arguments.Tensor(2, ranges_size):fill(0)\n    node.cf_values_br = arguments.Tensor(2, ranges_size):fill(0)\n\n    --strategy = [[actions x range]]\n    local strategy_mul_matrix = node.strategy:viewAs(arguments.Tensor(actions_count, ranges_size))\n\n    --compute CFVs given the current strategy for this node\n    if node.current_player == constants.players.chance then\n      node.cf_values = cf_values_allactions:sum(1)[1]\n      node.cf_values_br = cf_values_br_allactions:sum(1)[1]\n    else\n      node.cf_values[node.current_player] = torch.cmul(strategy_mul_matrix, cf_values_allactions[{{}, node.current_player, {}}]):sum(1)\n      node.cf_values[3-node.current_player] = (cf_values_allactions[{{}, 3-node.current_player, {}}]):sum(1)\n\n      --compute CFVs given the BR strategy for this node\n      node.cf_values_br[3 - node.current_player] = cf_values_br_allactions[{{}, 3 - node.current_player, {}}]:sum(1)\n      node.cf_values_br[node.current_player] = cf_values_br_allactions[{{}, node.current_player, {}}]:max(1)\n    end\n  end\n\n  --counterfactual values weighted by the reach prob\n  node.cfv_infset = arguments.Tensor(2)\n  node.cfv_infset[1] = node.cf_values[1] * node.ranges_absolute[1]\n  node.cfv_infset[2] = node.cf_values[2] * node.ranges_absolute[2]\n\n  --compute CFV-BR values weighted by the reach prob\n  node.cfv_br_infset = arguments.Tensor(2)\n  node.cfv_br_infset[1] = node.cf_values_br[1] * node.ranges_absolute[1]\n  node.cfv_br_infset[2] = node.cf_values_br[2] * node.ranges_absolute[2]\n\n  node.epsilon = node.cfv_br_infset - node.cfv_infset\n  node.exploitability = node.epsilon:mean()\nend\n\n--- Compute the self play and best response values of a strategy profile on\n-- the given game tree.\n--\n-- The cfvs for each player in the given strategy profile when playing against\n-- each other is stored in the `cf_values` field for each node. The cfvs for\n-- a best response against each player in the profile are stored in the\n-- `cf_values_br` field for each node.\n--\n-- @param root The root of the game tree. Each node of the tree is assumed to\n-- have a strategy saved in the `strategy` field.\n-- @param[opt] starting_ranges probability vectors over player private hands\n-- at the root node (default uniform)\nfunction TreeValues:compute_values( root, starting_ranges )\n\n  --1.0 set the starting range\n  local uniform_ranges = arguments.Tensor(constants.players_count, game_settings.card_count):fill(1.0/game_settings.card_count)\n  local starting_ranges = starting_ranges or uniform_ranges\n\n  --2.0 check the starting ranges\n  local checksum = starting_ranges:sum(2)[{{}, 1}]\n  assert(math.abs(checksum[1] - 1) < 0.0001, 'starting range does not sum to 1')\n  assert(math.abs(checksum[2] - 1) < 0.0001, 'starting range does not sum to 1')\n  assert(starting_ranges:lt(0):sum() == 0)\n\n  --3.0 compute the values\n  self:_fill_ranges_dfs(root, starting_ranges)\n  self:_compute_values_dfs(root)\nend\n"
  },
  {
    "path": "Source/Tree/tree_visualiser.lua",
    "content": "--- Generates visual representations of game trees.\n-- @classmod tree_visualiser\nlocal TreeVisualiser = torch.class('TreeVisualiser')\nlocal arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal card_to_string = require 'Game.card_to_string_conversion'\n\n--TODO: README\n--dot tree_2.dot -Tpng -O\n\n--- Constructor\nfunction TreeVisualiser:__init()\n    self.node_to_graphviz_counter = 0\n    self.edge_to_graphviz_counter = 0\nend\n\n--- Generates a string representation of a tensor.\n-- @param tensor a tensor\n-- @param[opt] name a name for the tensor\n-- @param[opt] format a format string to use with @{string.format} for each\n-- element of the tensor\n-- @param[opt] labels a list of labels for the elements of the tensor\n-- @return a string representation of the tensor\n-- @local\nfunction TreeVisualiser:add_tensor(tensor, name, format, labels)\n\n  local out = ''\n  if name then\n    out = '| ' .. name .. ': '\n  end\n\n  if not format then\n    format = \"%.3f\"\n  end\n\n  out = out .. \" | \" .. \"\" .. tensor:size(1) .. \" hands | \"\n  for i = 1, --[[tensor:size(1) do -- ]]math.min(2,tensor:size(1)) do\n    if labels then\n      out = out .. labels[i] .. \":\"\n    end\n    out = out .. string.format(format, tensor[i]) .. \", \"\n  end\n\n  out = out .. \"..\"\n\n  return out\nend\n\n--- Generates a string representation of any range or value fields that are set\n-- for the given tree node.\n-- @param node the node\n-- @return a string containing concatenated representations of any tensors\n-- stored in the `ranges_absolute`, `cf_values`, or `cf_values_br` fields of\n-- the node.\n-- @local\nfunction TreeVisualiser:add_range_info(node)\n  local out = \"\"\n\n  if(node.ranges_absolute) then\n    out = out .. self:add_tensor(node.ranges_absolute[1], 'abs_range1')\n    out = out .. self:add_tensor(node.ranges_absolute[2], 'abs_range2')\n  end\n\n  if(node.cf_values) then\n    --cf values computed by real tree dfs\n    out = out .. self:add_tensor(node.cf_values[1], 'cf_values1')\n    out = out .. self:add_tensor(node.cf_values[2], 'cf_values2')\n  end\n\n  if(node.cf_values_br) then\n    --cf values that br has in real tree\n    out = out .. self:add_tensor(node.cf_values_br[1], 'cf_values_br1')\n    out = out .. self:add_tensor(node.cf_values_br[2], 'cf_values_br2')\n  end\n\n  return out\nend\n\n--- Generates data for a graphical representation of a node in a public tree.\n-- @param node the node to generate data for\n-- @return a table containing `name`, `label`, and `shape` fields for graphviz\n-- @local\nfunction TreeVisualiser:node_to_graphviz(node)\n  local out = {}\n\n  --1.0 label\n  out.label = '\"<f0>' .. node.current_player\n\n  if node.terminal then\n    if node.type == constants.node_types.terminal_fold then\n      out.label = out.label .. '| TERMINAL FOLD'\n    elseif node.type == constants.node_types.terminal_call then\n      out.label = out.label .. '| TERMINAL CALL'\n    else\n      assert('unknown terminal node type')\n    end\n  else\n    out.label = out.label .. '| bet1: ' .. node.bets[constants.players.P1] .. '| bet2: ' .. node.bets[constants.players.P2]\n\n    if node.street then\n      out.label = out.label .. '| street: ' .. node.street\n      out.label = out.label .. '| board: ' .. card_to_string:cards_to_string(node.board)\n      out.label = out.label .. '| depth: ' .. node.depth\n    end\n  end\n\n  if node.margin then\n    out.label = out.label ..  '| margin: ' .. node.margin\n  end\n\n  out.label = out.label .. self:add_range_info(node)\n\n  if(node.cfv_infset) then\n    out.label = out.label ..  '| cfv1: ' .. node.cfv_infset[1]\n    out.label = out.label ..  '| cfv2: ' .. node.cfv_infset[2]\n    out.label = out.label ..  '| cfv_br1: ' .. node.cfv_br_infset[1]\n    out.label = out.label ..  '| cfv_br2: ' .. node.cfv_br_infset[2]\n    out.label = out.label ..  '| epsilon1: ' .. node.epsilon[1]\n    out.label = out.label ..  '| epsilon2: ' .. node.epsilon[2]\n  end\n\n  if node.lookahead_coordinates then\n    out.label = out.label ..  '| COORDINATES '\n    out.label = out.label ..  '| action_id: ' .. node.lookahead_coordinates[1]\n    out.label = out.label ..  '| parent_action_id: ' .. node.lookahead_coordinates[2]\n    out.label = out.label ..  '| gp_id: ' .. node.lookahead_coordinates[3]\n  end\n\n  out.label = out.label .. '\"'\n\n  --2.0 name\n  out.name = '\"node' .. self.node_to_graphviz_counter .. '\"'\n\n  --3.0 shape\n  out.shape = '\"record\"'\n\n  self.node_to_graphviz_counter = self.node_to_graphviz_counter + 1\n  return out\nend\n\n--- Generates data for graphical representation of a public tree action as an\n-- edge in a tree.\n-- @param from the graphical node the edge comes from\n-- @param to the graphical node the edge goes to\n-- @param node the public tree node before at which the action is taken\n-- @param child_node the public tree node that results from taking the action\n-- @return a table containing fields `id_from`, `id_to`, `id` for graphviz and\n-- a `strategy` field to use as a label for the edge\n-- @local\nfunction TreeVisualiser:nodes_to_graphviz_edge(from, to, node, child_node)\n  local out = {}\n\n  out.id_from = from.name\n  out.id_to = to.name\n  out.id = self.edge_to_graphviz_counter\n\n  --get the child id of the child node\n  local child_id = -1\n  for i=1,#node.children do\n    if node.children[i] == child_node then\n      child_id = i\n    end\n  end\n\n  assert(child_id ~= -1)\n  out.strategy = self:add_tensor(node.strategy[child_id], nil, \"%.2f\")\n\n  self.edge_to_graphviz_counter = self.edge_to_graphviz_counter + 1\n  return out\nend\n\n--- Recursively generates graphviz data from a public tree.\n-- @param node the current node in the public tree\n-- @param nodes a table of graphical nodes generated so far\n-- @param edges a table of graphical edges generated so far\n-- @local\nfunction TreeVisualiser:graphviz_dfs(node, nodes, edges)\n\n  local gv_node = self:node_to_graphviz(node)\n  table.insert(nodes, gv_node)\n\n  for i = 1,#node.children do\n    local child_node = node.children[i]\n    local gv_node_child = self:graphviz_dfs(child_node, nodes, edges)\n    local gv_edge = self:nodes_to_graphviz_edge(gv_node, gv_node_child, node, child_node)\n    table.insert(edges, gv_edge)\n  end\n\n  return gv_node\nend\n\n--- Generates `.dot` and `.svg` image files which graphically represent\n-- a game's public tree.\n--\n-- Each node in the image lists the acting player, the number of chips\n-- committed by each player, the current betting round, public cards,\n-- and the depth of the subtree after the node, as well as any probabilities\n-- or values stored in the `ranges_absolute`, `cf_values`, or `cf_values_br`\n-- fields of the node.\n--\n-- Each edge in the image lists the probability of the action being taken\n-- with each private card.\n--\n-- @param root the root of the game's public tree\n-- @param filename a name used for the output files\nfunction TreeVisualiser:graphviz(root, filename)\n  filename = filename or 'tree_2.dot'\n  local out = 'digraph g {  graph [ rankdir = \"LR\"];node [fontsize = \"16\" shape = \"ellipse\"]; edge [];'\n\n  local nodes = {}\n  local edges = {}\n  self:graphviz_dfs(root, nodes, edges)\n\n  for i = 1, #nodes do\n    local node = nodes[i]\n    local node_text = node.name .. '[' .. 'label=' .. node.label .. ' shape = ' .. node.shape .. '];'\n\n    out = out .. node_text\n  end\n\n  for i = 1, #edges do\n    local edge = edges[i]\n    local edge_text = edge.id_from .. ':f0 -> ' .. edge.id_to .. ':f0 [ id = ' .. edge.id .. ' label = \"' .. edge.strategy .. '\"];'\n\n    out = out .. edge_text\n  end\n\n  out = out .. '}'\n\n  --write into dot file\n  local file = io.open (arguments.data_directory .. 'Dot/' .. filename, 'w')\n  file:write(out)\n  file:close()\n\n  --run graphviz program to generate image\n  os.execute( 'dot ' .. arguments.data_directory .. 'Dot/' .. filename .. ' -Tsvg -O')\nend\n"
  },
  {
    "path": "Source/tools.lua",
    "content": "--- Assorted tools.\n--@module tools\nlocal M = {C = {}, max_choose = 55}\n\n--- Generates a string representation of a table.\n--@param table the table\n--@return the string\nfunction M:table_to_string(table)\n  local out = \"{\"\n  for key,value in pairs(table) do\n\n    local val_string = ''\n\n    if type(value) == 'table' then\n      val_string = self:table_to_string(value)\n    else\n      val_string = tostring(value)\n    end\n\n    out = out .. tostring(key) .. \":\" .. val_string .. \", \"\n  end\n\n  out = out .. \"}\"\n  return out\nend\n\n--- An arbitrarily large number used for clamping regrets.\n--@return the number\nfunction M:max_number()\n  return 999999\nend\n\n--- Initializes the choose table.\n-- @local\nfunction M:_init_choose()\n  for i = 0,self.max_choose do\n    for j = 0,self.max_choose do\n      self.C[i*self.max_choose + j] = 0\n    end\n  end\n\n  for i = 0,self.max_choose do\n    self.C[i*self.max_choose] = 1\n    self.C[i*self.max_choose + i] = 1\n  end\n\n  for i = 1,self.max_choose do\n    for j = 1,i do\n      self.C[i*self.max_choose + j] = self.C[(i-1)*self.max_choose + j-1] + self.C[(i-1)*self.max_choose + j]\n    end\n  end\nend\n\nM:_init_choose()\n\nfunction M:choose(n, k)\n  return self.C[n*self.max_choose + k]\nend\n\nreturn M\n"
  },
  {
    "path": "readme.md",
    "content": "# DeepHoldem\n\nThis is an implementation of [DeepStack](https://www.deepstack.ai/s/DeepStack.pdf)\nfor No Limit Texas Hold'em, extended from [DeepStack-Leduc](https://github.com/lifrordi/DeepStack-Leduc).\n\n## Setup\n\nRunning any of the DeepHoldem code requires [Lua](https://www.lua.org/) and [torch](http://torch.ch/). Please install torch with lua version 5.2 instead of LuaJIT. Torch is only officially supported for \\*NIX based systems (i.e. Linux and Mac\nOS X).\n\nConnecting DeepHoldem to a server or running DeepHoldem on a server will require the [luasocket](http://w3.impa.br/~diego/software/luasocket/)\npackage. This can be installed with [luarocks](https://luarocks.org/) (which is\ninstalled as part of the standard torch distribution) using the command\n`luarocks install luasocket`. Visualising the trees produced by DeepHoldem\nrequires the [graphviz](http://graphviz.org/) package, which can be installed\nwith `luarocks install graphviz`. Running the code on the GPU requires\n[cutorch](https://github.com/torch/cutorch) which can be installed with\n`luarocks install cutorch`.\n\nThe HandRanks file was too big for github, so you will need to unzip it: `cd Source/Game/Evaluation && unzip HandRanks.zip`\n\n#### scatterAdd\nWhen you try to run DeepHoldem, you will eventually run into a problem where `scatterAdd` is not defined.\nTorch7 actually includes a C++ implementation of scatterAdd but for whatever reason, doesn't include a lua\nwrapper for it.\n\nI've included `TensorMath.lua` files in the torch folder of this repository that include the wrapper functions for both CPU and GPU. Copy them to their corresponding torch installation folders.\n\nNow, from your torch installation directory, run:\n\n    ./clean.sh\n    TORCH_LUA_VERSION=LUA52 ./install.sh\n\nand you should be good to go.\n\n## Performance\n\nThis implementation was tested against Slumbot 2017, the only publicly playable bot as of June 2018. The action abstraction used was half pot, pot and all in for first action, pot and all in for second action onwards. It achieved a baseline winrate of **42bb/100** after 2616 hands (equivalent to ~5232 duplicate hands). Notably, it achieved this playing inside of Slumbot's action abstraction space.\n\n![](Data/Images/slumbot_stats.png)\n\nA comparison of preflop ranges was also done against [DeepStack's hand history](https://www.deepstack.ai/s/DeepStack_vs_IFP_pros.zip), showing similar results.\n\n|    |DeepStack | DeepHoldem|\n|--- |--- | ---|\n|Open fold |![](Data/Images/deepstack_folds.png) | ![](Data/Images/my_folds.png)|\n|Open pot |![](Data/Images/deepstack_pots.png) | ![](Data/Images/my_pots.png)|\n|3bet pot after pot open |![](Data/Images/deepstack_3bets.png) | ![](Data/Images/my_3bets.png)|\n\nAverage thinking times on NVIDIA Tesla P100:\n\nStreet | Thinking Speed (s)\n--- | ---\nPreflop | 2.69\nFlop | 12.42\nTurn | 7.57\nRiver | 3.33\n\nTraining details:\n\n||# samples | Validation huber loss|\n| --- | --- | --- |\n|River network|1,000,000| 0.0415|\n|Turn network|1,000,000| 0.045|\n|Flop network|1,000,000| 0.013|\n|Preflop aux network|1,000,000| 0.0017|\n\n## Creating your own models\n\nOther than the preflop auxiliary network, the counterfactual value networks are not included as part of this release, you will need to generate them yourself. The model generation pipeline is a bit different from the Leduc-Holdem implementation in that the data generated is saved to disk as raw solutions rather than bucketed solutions. This makes it easier to experiment with different bucketing methods.\n\nHere's a step by step guide to creating models:\n\n1. `cd Source && th DataGeneration/main_data_generation.lua 4`\n2. Wait for enough data to be generated.\n3. Modify the last line of `Training/raw_converter.lua` to specify the folders where the raw training data (source folder) you got from step 1 is and where you want the bucketed training data (dest folder) to be.\n4. `th Training/raw_converter.lua 4`\n5. `th Training/main_train.lua 4`\n6. Models will be generated under `Data/Models/NoLimit`. Pick the model you like best and place it inside\n   `Data/Models/NoLimit/river` along with its .info file. Rename them to `final_cpu.info` and `final_cpu.model`.\n   Please refer to the [DeepStack-Leduc](https://github.com/lifrordi/DeepStack-Leduc/blob/master/doc/manual/tutorial.md) tutorial if you want to convert them to GPU models.\n7. Repeat steps 1-6 for turn and flop by replacing `4` with `3` or `2` and placing the models under the\nturn and flop folders.\n\nIf you want to speed up data generation with a GPU, make sure to modify `Settings/arguments.lua` so that `params.gpu = true`\n\n## Playing against DeepHoldem\n\n`Player/manual_player.lua` is supplied so you can play against DeepHoldem for preflop situations. If you want\nDeepHoldem to work for flop, turn and river, you will need to create your own models.\n\n1. `cd ACPCServer && make`\n2. `./dealer testMatch holdem.nolimit.2p.reverse_blinds.game 1000 0 Alice Bob`\n3. 2 ports will be output, note them down as port1 and port2\n4. Open a second terminal and `cd Source && th Player/manual_player.lua <port1>`\n5. Open a third terminal and `cd Source && th Player/deepstack.lua <port2>`. It will take about 20 minutes to\nload all the flop buckets, but this is actually not necessary until you've created your own flop model. You can\nskip the flop bucket computation by commenting out line 44 of `Source/Nn/next_round_value_pre.lua`.\n6. Once the deepstack player is done loading, you can play against it using manual_player terminal. `f` = fold,\n`c` = check/call, `450` = raise my total pot commitment to 450 chips.\n\n## Differences from the original paper\n\n- A river model was used instead of solving directly from the turn\n- Different neural net architecture\n  - Batch normalization layers were added in between hidden layers because they were found to improve huber loss\n  - Only 3 hidden layers were used. Additional layers didn't improve huber loss, in agreement with the paper.\n- Preflop solving was done with auxiliary network only, whereas paper used 20 iterations of flop network\n  - Because of this, the cfvs for a given flop must be calculated after seeing it by solving the preflop again with the current flop in mind\n- During re-solving, the opponent ranges were not warm started\n\n## Future work\n\n- Warm start opponent ranges for re-solving\n- Cache flop buckets so initializing next_round_value_pre doesn't take 20 minutes\n- Speed up flop solving (use flop network during preflop solving?)\n- Support LuaJIT\n- C++ implementation?\n"
  },
  {
    "path": "torch/extra/cutorch/TensorMath.lua",
    "content": "local wrap = require 'cwrap'\n\nlocal interface = wrap.CInterface.new()\nlocal method = wrap.CInterface.new()\nlocal argtypes = wrap.CInterface.argtypes\n\nargtypes['ptrdiff_t'] = {\n\n  helpname = function(arg)\n                return 'ptrdiff_t'\n             end,\n\n  declare = function(arg)\n               -- if it is a number we initialize here\n               local default = tonumber(tostring(arg.default)) or 0\n               return string.format(\"%s arg%d = %g;\", 'ptrdiff_t', arg.i, default)\n            end,\n\n  check = function(arg, idx)\n             return string.format(\"lua_isinteger(L, %d)\", idx)\n          end,\n\n  read = function(arg, idx)\n            return string.format(\"arg%d = (%s)lua_tointeger(L, %d);\", arg.i, 'ptrdiff_t', idx)\n         end,\n\n  init = function(arg)\n            -- otherwise do it here\n            if arg.default then\n               local default = tostring(arg.default)\n               if not tonumber(default) then\n                  return string.format(\"arg%d = %s;\", arg.i, default)\n               end\n            end\n         end,\n\n  carg = function(arg)\n            return string.format('arg%d', arg.i)\n         end,\n\n  creturn = function(arg)\n               return string.format('arg%d', arg.i)\n            end,\n\n  precall = function(arg)\n               if arg.returned then\n                  return string.format('lua_pushinteger(L, (lua_Integer)arg%d);', arg.i)\n               end\n            end,\n\n  postcall = function(arg)\n                if arg.creturned then\n                   return string.format('lua_pushinteger(L, (lua_Integer)arg%d);', arg.i)\n                end\n             end\n}\n\ninterface:print('/* WARNING: autogenerated file */')\ninterface:print('')\ninterface:print('#include \"THC.h\"')\ninterface:print('#include \"luaT.h\"')\ninterface:print('#include \"torch/utils.h\"')\ninterface:print('')\ninterface:print('')\n\ninterface:print([[\nstatic int torch_isnonemptytable(lua_State *L, int idx)\n{\n  int empty;\n  if (!lua_istable(L, idx)) return 0;\n\n  lua_rawgeti(L, idx, 1);\n  empty = lua_isnil(L, -1);\n  lua_pop(L, 1);\n  return !empty;\n}\n]])\n\n-- Lua 5.2 compatibility\nlocal unpack = unpack or table.unpack\n\n-- specific to CUDA\nlocal typenames = {\n   'CudaByteTensor',\n   'CudaCharTensor',\n   'CudaShortTensor',\n   'CudaIntTensor',\n   'CudaLongTensor',\n   'CudaTensor',\n   'CudaDoubleTensor',\n   'CudaHalfTensor'\n}\n\nfor _, typename in ipairs(typenames) do\n-- cut and paste from wrap/types.lua\nwrap.types[typename] = {\n\n   helpname = function(arg)\n      if arg.dim then\n         return string.format('%s~%dD', typename, arg.dim)\n      else\n         return typename\n      end\n   end,\n\n   declare = function(arg)\n      local txt = {}\n      table.insert(txt, string.format(\"TH%s *arg%d = NULL;\", typename, arg.i))\n      if arg.returned then\n         table.insert(txt, string.format(\"int arg%d_idx = 0;\", arg.i));\n      end\n      return table.concat(txt, '\\n')\n   end,\n\n   check = function(arg, idx)\n      if arg.dim then\n         return string.format('(arg%d = luaT_toudata(L, %d, \"torch.%s\")) && (arg%d->nDimension == %d)', arg.i, idx, typename, arg.i, arg.dim)\n      else\n         return string.format('(arg%d = luaT_toudata(L, %d, \"torch.%s\"))', arg.i, idx, typename)\n      end\n   end,\n\n   read = function(arg, idx)\n      if arg.returned then\n         return string.format(\"arg%d_idx = %d;\", arg.i, idx)\n      end\n   end,\n\n   init = function(arg)\n      if type(arg.default) == 'boolean' then\n         return string.format('arg%d = TH%s_new(cutorch_getstate(L));', arg.i, typename)\n      elseif type(arg.default) == 'number' then\n         return string.format('arg%d = %s;', arg.i, arg.args[arg.default]:carg())\n      else\n         error('unknown default tensor type value')\n      end\n   end,\n\n   carg = function(arg)\n      return string.format('arg%d', arg.i)\n   end,\n\n   creturn = function(arg)\n      return string.format('arg%d', arg.i)\n   end,\n\n   precall = function(arg)\n      local txt = {}\n      if arg.default and arg.returned then\n         table.insert(txt, string.format('if(arg%d_idx)', arg.i)) -- means it was passed as arg\n         table.insert(txt, string.format('lua_pushvalue(L, arg%d_idx);', arg.i))\n         table.insert(txt, string.format('else'))\n         if type(arg.default) == 'boolean' then -- boolean: we did a new()\n            table.insert(txt, string.format('luaT_pushudata(L, arg%d, \"torch.%s\");', arg.i, typename))\n         else  -- otherwise: point on default tensor --> retain\n            table.insert(txt, string.format('{'))\n            table.insert(txt, string.format('TH%s_retain(arg%d);', typename, arg.i)) -- so we need a retain\n            table.insert(txt, string.format('luaT_pushudata(L, arg%d, \"torch.%s\");', arg.i, typename))\n            table.insert(txt, string.format('}'))\n         end\n      elseif arg.default then\n         -- we would have to deallocate the beast later if we did a new\n         -- unlikely anyways, so i do not support it for now\n         if type(arg.default) == 'boolean' then\n            error('a tensor cannot be optional if not returned')\n         end\n      elseif arg.returned then\n         table.insert(txt, string.format('lua_pushvalue(L, arg%d_idx);', arg.i))\n      end\n      return table.concat(txt, '\\n')\n   end,\n\n   postcall = function(arg)\n      local txt = {}\n      if arg.creturned then\n         -- if a tensor is returned by a wrapped C function, the refcount semantics\n         -- are ambiguous (transfer ownership vs. shared ownership).\n         -- We never actually do this, so lets just not allow it.\n         error('a tensor cannot be creturned')\n      end\n      return table.concat(txt, '\\n')\n   end\n}\n\nwrap.types[typename .. 'Array'] = {\n\n   helpname = function(arg)\n                 return string.format('{%s+}', typename)\n            end,\n\n   declare = function(arg)\n                local txt = {}\n                table.insert(txt, string.format('TH%s **arg%d_data = NULL;', typename, arg.i))\n                table.insert(txt, string.format('long arg%d_size = 0;', arg.i))\n                table.insert(txt, string.format('int arg%d_i = 0;', arg.i))\n                return table.concat(txt, '\\n')\n           end,\n\n   check = function(arg, idx)\n              return string.format('torch_isnonemptytable(L, %d)', idx)\n         end,\n\n   read = function(arg, idx)\n             local txt = {}\n             -- Iterate over the array to find its length, leave elements on stack.\n             table.insert(txt, string.format('do'))\n             table.insert(txt, string.format('{'))\n             table.insert(txt, string.format('  arg%d_size++;', arg.i))\n             table.insert(txt, string.format('  lua_checkstack(L, 1);'))\n             table.insert(txt, string.format('  lua_rawgeti(L, %d, arg%d_size);', idx, arg.i))\n             table.insert(txt, string.format('}'))\n             table.insert(txt, string.format('while (!lua_isnil(L, -1));'))\n             table.insert(txt, string.format('arg%d_size--;', arg.i))\n             -- Pop nil element from stack.\n             table.insert(txt, string.format('lua_pop(L, 1);'))\n             -- Allocate tensor pointers and read values from stack backwards.\n             table.insert(txt, string.format('arg%d_data = (TH%s**)THAlloc(arg%d_size * sizeof(TH%s*));', arg.i, typename, arg.i, typename))\n             table.insert(txt, string.format('for (arg%d_i = arg%d_size - 1; arg%d_i >= 0; arg%d_i--)', arg.i, arg.i, arg.i, arg.i))\n             table.insert(txt, string.format('{'))\n             table.insert(txt, string.format('  if (!(arg%d_data[arg%d_i] = luaT_toudata(L, -1, \"torch.%s\")))', arg.i, arg.i, typename))\n             table.insert(txt, string.format('    luaL_error(L, \"expected %s in tensor array\");', typename))\n             table.insert(txt, string.format('  lua_pop(L, 1);'))\n             table.insert(txt, string.format('}'))\n             table.insert(txt, string.format(''))\n             return table.concat(txt, '\\n')\n          end,\n\n   init = function(arg)\n          end,\n\n   carg = function(arg)\n             return string.format('arg%d_data,arg%d_size', arg.i, arg.i)\n          end,\n\n   creturn = function(arg)\n                error('TensorArray cannot be returned.')\n             end,\n\n   precall = function(arg)\n             end,\n\n   postcall = function(arg)\n                 return string.format('THFree(arg%d_data);', arg.i)\n              end\n}\nend\n\nlocal function interpretdefaultvalue(arg)\n    local default = arg.default\n    if type(default) == 'boolean' then\n        if default then\n            return '1'\n        else\n            return '0'\n        end\n    elseif type(default) == 'number' then\n        return tostring(default)\n    elseif type(default) == 'string' then\n        return default\n    elseif type(default) == 'function' then\n        default = default(arg)\n        assert(type(default) == 'string', 'a default function must return a string')\n        return default\n    elseif type(default) == 'nil' then\n        return nil\n    else\n        error('unknown default type value')\n    end\nend\n\nwrap.types.half = {\n\n    helpname = function(arg)\n        return \"half\"\n    end,\n\n    declare = function(arg)\n        -- if it is a number we initialize here\n        local default = tonumber(interpretdefaultvalue(arg)) or 0\n        return string.format(\"half arg%d = THC_float2half((float) %d);\", arg.i, tonumber(default))\n    end,\n\n    check = function(arg, idx)\n        return string.format(\"lua_isnumber(L, %d)\", idx)\n    end,\n\n    read = function(arg, idx)\n        return string.format(\"arg%d = THC_float2half((float) lua_tonumber(L, %d));\", arg.i, idx)\n    end,\n\n    init = function(arg)\n        -- otherwise do it here\n        if arg.default then\n            local default = interpretdefaultvalue(arg)\n            if not tonumber(default) then\n                return string.format(\"arg%d = THC_float2half((float) %s);\", arg.i, default)\n            end\n        end\n    end,\n\n    carg = function(arg)\n        return string.format('arg%d', arg.i)\n    end,\n\n    creturn = function(arg)\n        return string.format('arg%d', arg.i)\n    end,\n\n    precall = function(arg)\n        if arg.returned then\n            return string.format('lua_pushnumber(L, (lua_Number) THC_half2float(arg%d));', arg.i)\n        end\n    end,\n\n    postcall = function(arg)\n        if arg.creturned then\n            return string.format('lua_pushnumber(L, (lua_Number) THC_half2float(arg%d));', arg.i)\n        end\n    end\n\n}\n\nwrap.types.LongArg = {\n\n   vararg = true,\n\n   helpname = function(arg)\n      return \"(LongStorage | dim1 [dim2...])\"\n   end,\n\n   declare = function(arg)\n      return string.format(\"THLongStorage *arg%d = NULL;\", arg.i)\n   end,\n\n   init = function(arg)\n      if arg.default then\n         error('LongArg cannot have a default value')\n      end\n   end,\n\n   check = function(arg, idx)\n      return string.format(\"cutorch_islongargs(L, %d)\", idx)\n   end,\n\n   read = function(arg, idx)\n      return string.format(\"arg%d = cutorch_checklongargs(L, %d);\", arg.i, idx)\n   end,\n\n   carg = function(arg, idx)\n      return string.format('arg%d', arg.i)\n   end,\n\n   creturn = function(arg, idx)\n      return string.format('arg%d', arg.i)\n   end,\n\n   precall = function(arg)\n      local txt = {}\n      if arg.returned then\n         table.insert(txt, string.format('luaT_pushudata(L, arg%d, \"torch.LongStorage\");', arg.i))\n      end\n      return table.concat(txt, '\\n')\n   end,\n\n   postcall = function(arg)\n      local txt = {}\n      if arg.creturned then\n         -- this next line is actually debatable\n         table.insert(txt, string.format('THLongStorage_retain(arg%d);', arg.i))\n         table.insert(txt, string.format('luaT_pushudata(L, arg%d, \"torch.LongStorage\");', arg.i))\n      end\n      if not arg.returned and not arg.creturned then\n         table.insert(txt, string.format('THLongStorage_free(arg%d);', arg.i))\n      end\n      return table.concat(txt, '\\n')\n   end\n}\n\nwrap.types.charoption = {\n\n   helpname = function(arg)\n                 if arg.values then\n                    return \"(\" .. table.concat(arg.values, '|') .. \")\"\n                 end\n              end,\n\n   declare = function(arg)\n                local txt = {}\n                table.insert(txt, string.format(\"const char *arg%d = NULL;\", arg.i))\n                if arg.default then\n                   table.insert(txt, string.format(\"char arg%d_default = '%s';\", arg.i, arg.default))\n                end\n                return table.concat(txt, '\\n')\n           end,\n\n   init = function(arg)\n             return string.format(\"arg%d = &arg%d_default;\", arg.i, arg.i)\n          end,\n\n   check = function(arg, idx)\n              local txt = {}\n              local txtv = {}\n              table.insert(txt, string.format('(arg%d = lua_tostring(L, %d)) && (', arg.i, idx))\n              for _,value in ipairs(arg.values) do\n                 table.insert(txtv, string.format(\"*arg%d == '%s'\", arg.i, value))\n              end\n              table.insert(txt, table.concat(txtv, ' || '))\n              table.insert(txt, ')')\n              return table.concat(txt, '')\n         end,\n\n   read = function(arg, idx)\n          end,\n\n   carg = function(arg, idx)\n             return string.format('arg%d', arg.i)\n          end,\n\n   creturn = function(arg, idx)\n             end,\n\n   precall = function(arg)\n             end,\n\n   postcall = function(arg)\n              end\n}\n\ncutorch_state_code = function(varname)\n  local txt = {}\n  table.insert(txt, 'lua_getglobal(L, \"cutorch\");')\n  table.insert(txt, 'lua_getfield(L, -1, \"_state\");')\n  table.insert(txt, string.format('THCState *%s = lua_touserdata(L, -1);', varname))\n  table.insert(txt, 'lua_pop(L, 2);')\n  return table.concat(txt, '\\n');\nend\ninterface:registerDefaultArgument(cutorch_state_code)\nmethod:registerDefaultArgument(cutorch_state_code)\n\nlocal function wrap(...)\n   local args = {...}\n\n   -- interface\n   interface:wrap(...)\n\n   -- method: we override things possibly in method table field\n   for _,x in ipairs(args) do\n      if type(x) == 'table' then -- ok, now we have a list of args\n         for _, arg in ipairs(x) do\n            if arg.method then\n               for k,v in pairs(arg.method) do\n                  if v == 'nil' then -- special case, we erase the field\n                     arg[k] = nil\n                  else\n                     arg[k] = v\n                  end\n               end\n            end\n         end\n      end\n   end\n   method:wrap(unpack(args))\nend\n\nlocal Tensor\n\n-- functions to help take in arguments that are Tensor or CudaLongTensor (for backward compatibility)\n-- used in scatter / gather for example\nlocal function TensorToCudaLong_declare(dummy)\n      return function(arg)\n\t local txt = {}\n\t table.insert(txt, string.format(\"THCudaLongTensor *arg%d = NULL;\", arg.i))\n\t if dummy then\n\t    table.insert(txt, string.format(\"THCudaLongTensor *indexLongTensor = NULL;\"))\n\t    table.insert(txt, string.format(\"TH%s *dummyIndexTensor = NULL;\", Tensor))\n\t end\n\t return table.concat(txt, '\\n')\n      end\nend\nlocal function TensorToCudaLong_check(arg, idx)\n   return string.format('(dummyIndexTensor = luaT_toudata(L, %d, \"torch.%s\"))', idx, Tensor)\nend\nlocal function TensorToCudaLong_read(arg, idx)\n   local copyname = Tensor:match(\"(%a+)Tensor\")\n   if copyname == 'Cuda' then\n      copyname = 'CudaFloat'\n   end\n   local txt = {}\n   table.insert(txt, string.format('arg%d = THCudaLongTensor_new(default_arg1);', arg.i))\n   table.insert(txt, string.format('THLongStorage *indexSize = TH%s_newSizeOf(default_arg1, dummyIndexTensor);', Tensor))\n   table.insert(txt, string.format('THCudaLongTensor_resize(default_arg1, arg%d, indexSize, NULL);', arg.i))\n   table.insert(txt, string.format('THLongStorage_free(indexSize);'))\n   table.insert(txt, string.format('THCudaLongTensor_copy%s(default_arg1, arg%d, dummyIndexTensor);', copyname, arg.i))\n   table.insert(txt, string.format('indexLongTensor = arg%d;', arg.i))\n   return table.concat(txt, '\\n')\nend\n\nlocal function TensorToCudaLong_postcall(arg)\n   return \"if (indexLongTensor != NULL) THCudaLongTensor_free(default_arg1, indexLongTensor);\\n\"\nend\n\n-- function to initialize the gather call\nlocal function gatherInit(arg)\n   return table.concat(\n      {\n\t arg.__metatable.init(arg),\n\t string.format(\"TH%s_checkGPU(cutorch_getstate(L), 1, %s);\",\n\t\t       Tensor, arg.args[4]:carg()),\n\t string.format(\n\t    [[\n\t\t  THCState *state = cutorch_getstate(L);\n\t\t  THLongStorage *indicesSize = THCudaLongTensor_newSizeOf(state, %s);\n\t\t  TH%s_resize(state, %s, indicesSize, NULL);\n\t\t  THLongStorage_free(indicesSize);\n\t    ]], arg.args[4]:carg(), Tensor, arg:carg()),\n      }, '\\n')\nend\n\n--\n-- Non-CudaTensor type math, since these are less fully implemented than\n-- CudaTensor\n--\n\nlocal handledTypenames = {\n   'CudaByteTensor',\n   'CudaCharTensor',\n   'CudaShortTensor',\n   'CudaIntTensor',\n   'CudaLongTensor',\n   'CudaDoubleTensor',\n   'CudaHalfTensor',\n}\nlocal handledTypereals = {\n   'unsigned char',\n   'char',\n   'short',\n   'int',\n   'long',\n   'double',\n   'half'\n}\nlocal handledTypeaccreals = {\n   'long',\n   'long',\n   'long',\n   'long',\n   'long',\n   'double',\n   'float'\n}\n\nfor k, Tensor_ in pairs(handledTypenames) do\n    Tensor = Tensor_\n    if Tensor == 'CudaHalfTensor' then\n        interface:print(\"#ifdef CUDA_HALF_TENSOR\")\n    end\n    local real = handledTypereals[k]\n    local accreal = handledTypeaccreals[k]\n\n    function interface.luaname2wrapname(self, name)\n        return string.format('cutorch_%s_%s', Tensor, name)\n    end\n\n    function method.luaname2wrapname(self, name)\n        return string.format('m_cutorch_%s_%s', Tensor, name)\n    end\n\n    local function cname(name)\n        return string.format('TH%s_%s', Tensor, name)\n    end\n\n    local function lastdim(argn)\n        return function(arg)\n            return string.format('TH%s_nDimension(cutorch_getstate(L), %s)',\n                                 Tensor, arg.args[argn]:carg())\n        end\n    end\n\n    local function lastdimarray(argn)\n        return function(arg)\n            return string.format('TH%s_nDimension(cutorch_getstate(L), arg%d_data[0])',\n                                 Tensor, arg.args[argn].i)\n        end\n    end\n\n    wrap(\"fill\",\n         cname(\"fill\"),\n         {{name=Tensor, returned=true},\n             {name=real}})\n\n    wrap(\"zero\",\n         cname(\"zero\"),\n         {{name=Tensor, returned=true}})\n\n    wrap(\"zeros\",\n         cname(\"zeros\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=\"LongArg\"}})\n\n    wrap(\"ones\",\n         cname(\"ones\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=\"LongArg\"}})\n\n    wrap(\"reshape\",\n         cname(\"reshape\"),\n         {{name=Tensor, default=true, returned=true},\n            {name=Tensor},\n            {name=\"LongArg\"}})\n\n    wrap(\"numel\",\n         cname(\"numel\"),\n         {{name=Tensor},\n            {name=\"ptrdiff_t\", creturned=true}})\n\n    wrap(\"add\",\n         cname(\"add\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}},\n         cname(\"cadd\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real, default=1},\n            {name=Tensor}})\n\n    wrap(\"csub\",\n         cname(\"sub\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}},\n         cname(\"csub\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real, default=1},\n            {name=Tensor}})\n\n    wrap(\"mul\",\n         cname(\"mul\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}})\n\n    wrap(\"clamp\",\n         cname(\"clamp\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n          {name=Tensor, method={default=1}},\n          {name=real},\n          {name=real}})\n\n    wrap(\"cross\",\n        cname(\"cross\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor},\n         {name=Tensor},\n         {name=\"index\", default=0}})\n\n    wrap(\"div\",\n         cname(\"div\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}})\n\n    wrap(\"lshift\",\n         cname(\"lshift\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}})\n\n    wrap(\"rshift\",\n         cname(\"rshift\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}})\n\n    wrap(\"fmod\",\n         cname(\"fmod\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}})\n\n    wrap(\"remainder\",\n         cname(\"remainder\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}})\n\n    wrap(\"bitand\",\n         cname(\"bitand\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}})\n\n    wrap(\"bitor\",\n         cname(\"bitor\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}})\n\n    wrap(\"bitxor\",\n         cname(\"bitxor\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}})\n\n    wrap(\"equal\",\n         cname(\"equal\"),\n         {{name=Tensor},\n          {name=Tensor},\n          {name=\"boolean\", creturned=true}})\n\n    local cfuncs = {\"cmul\", \"cpow\", \"cdiv\", \"cremainder\", \"cfmod\",\n                    \"clshift\", \"crshift\", \"cbitand\", \"cbitor\", \"cbitxor\"}\n    for _, name in ipairs(cfuncs) do\n       wrap(name,\n            cname(name),\n            {{name=Tensor, default=true, returned=true, method={default='nil'}},\n               {name=Tensor, method={default=1}},\n               {name=Tensor}})\n    end\n\n    wrap(\"addcmul\",\n         cname(\"addcmul\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real, default=1},\n            {name=Tensor},\n            {name=Tensor}})\n\n    wrap(\"addcdiv\",\n         cname(\"addcdiv\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real, default=1},\n            {name=Tensor},\n            {name=Tensor}})\n\n    for _,name in ipairs({\"min\", \"max\"}) do\n       wrap(name,\n            cname(name .. \"all\"),\n            {{name=Tensor},\n               {name=real, creturned=true}},\n            cname(name),\n            {{name=Tensor, default=true, returned=true},\n               {name='CudaLongTensor', default=true, returned=true},\n               {name=Tensor},\n               {name=\"index\"},\n               {name=\"boolean\", default=true, invisible=true}})\n    end\n\n    for _,name in ipairs({\"cmin\", \"cmax\"}) do\n       wrap(name,\n            cname(name),\n            {{name=Tensor, default=true, returned=true},\n             {name=Tensor, method={default=1}},\n             {name=Tensor}},\n            cname(name .. \"Value\"),\n            {{name=Tensor, default=true, returned=true},\n             {name=Tensor, method={default=1}},\n             {name=real}})\n    end\n\n    if Tensor == 'CudaByteTensor' then\n       for _,name in pairs({'all', 'any'}) do\n          wrap(name,\n               cname('logical' .. name),\n               {{name=Tensor},\n                  {name=\"boolean\", creturned=true}})\n       end\n    end\n\n   for _,name in pairs({'lt','gt','le','ge','eq','ne'}) do\n      wrap(name,\n           cname(name .. 'Value'),\n           {{name='CudaByteTensor',default=true, returned=true},\n            {name=Tensor},\n            {name=real}},\n           cname(name .. 'ValueT'),\n           {{name=Tensor, returned=true},\n            {name=Tensor},\n            {name=real}},\n           cname(name .. 'Tensor'),\n           {{name='CudaByteTensor',default=true, returned=true},\n            {name=Tensor},\n            {name=Tensor}},\n           cname(name .. 'TensorT'),\n           {{name=Tensor, returned=true},\n            {name=Tensor},\n            {name=Tensor}})\n   end\n\n    wrap(\"sum\",\n         cname(\"sumall\"),\n         {{name=Tensor},\n            {name=accreal, creturned=true}},\n         cname(\"sum\"),\n         {{name=Tensor, default=true, returned=true},\n            {name=Tensor},\n            {name=\"index\"},\n            {name=\"boolean\", default=true, invisible=true}})\n\n    for _, name in ipairs({\"cumsum\", \"cumprod\"}) do\n        wrap(name,\n             cname(name),\n             {{name=Tensor, default=true, returned=true},\n                 {name=Tensor},\n                 {name=\"index\", default=1}})\n    end\n\n    wrap(\"prod\",\n         cname(\"prodall\"),\n         {{name=Tensor},\n            {name=accreal, creturned=true}},\n         cname(\"prod\"),\n         {{name=Tensor, default=true, returned=true},\n            {name=Tensor},\n            {name=\"index\"},\n            {name=\"boolean\", default=true, invisible=true}})\n\n    wrap(\"mean\",\n         cname(\"meanall\"),\n         {{name=Tensor},\n          {name=accreal, creturned=true}},\n         cname(\"mean\"),\n         {{name=Tensor, default=true, returned=true},\n            {name=Tensor},\n            {name=\"index\"},\n            {name=\"boolean\", default=true, invisible=true}})\n\n    wrap(\"maskedFill\",\n         cname(\"maskedFill\"),\n         {{name=Tensor, returned=true, method={default='nil'}},\n            {name='CudaByteTensor'},\n            {name=real}})\n\n    wrap(\"maskedCopy\",\n         cname(\"maskedCopy\"),\n         {{name=Tensor, returned=true, method={default='nil'}},\n            {name='CudaByteTensor'},\n            {name=Tensor}})\n\n    wrap(\"maskedSelect\",\n         cname(\"maskedSelect\"),\n         {{name=Tensor, returned=true, default=true},\n            {name=Tensor},\n            {name='CudaByteTensor'}})\n\n    wrap(\"gather\",\n\t cname(\"gather\"),\n\t {{name=Tensor, default=true, returned=true, init=gatherInit},\n\t    {name=Tensor},\n\t    {name=\"index\"},\n\t    {name='CudaLongTensor'}},\n\t cname(\"gather\"), -- this is for backward-compatibility, and takes in \"Tensor\" as the indexing tensor\n\t {{name=Tensor, default=true, returned=true, init=gatherInit},\n\t    {name=Tensor},\n\t    {name=\"index\"},\n\t    {name=Tensor, declare=TensorToCudaLong_declare(true), check=TensorToCudaLong_check, read=TensorToCudaLong_read, postcall=TensorToCudaLong_postcall}})\n\n    wrap(\"scatter\",\n\t cname(\"scatter\"),\n\t {{name=Tensor, returned=true},\n\t    {name=\"index\"},\n\t    {name='CudaLongTensor'},\n\t    {name=Tensor}},\n\t cname(\"scatter\"), -- this is for backward-compatibility, and takes in \"Tensor\" as the indexing tensor\n\t {{name=Tensor, returned=true},\n\t    {name=\"index\"},\n\t    {name=Tensor, declare=TensorToCudaLong_declare(true), check=TensorToCudaLong_check, read=TensorToCudaLong_read, postcall=TensorToCudaLong_postcall},\n\t    {name=Tensor}},\n\t cname(\"scatterFill\"),\n\t {{name=Tensor, returned=true},\n\t    {name=\"index\"},\n\t    {name='CudaLongTensor'},\n\t    {name=real}},\n\t cname(\"scatterFill\"), -- this is for backward-compatibility, and takes in \"Tensor\" as the indexing tensor\n\t {{name=Tensor, returned=true},\n\t    {name=\"index\"},\n\t    {name=Tensor, declare=TensorToCudaLong_declare(false), check=TensorToCudaLong_check, read=TensorToCudaLong_read, postcall=TensorToCudaLong_postcall},\n\t    {name=real}}\n    )\n\n    wrap(\"scatterAdd\",\n      cname(\"scatterAdd\"),\n        {{name=Tensor, returned=true},\n         {name=\"index\"},\n         {name='CudaLongTensor'},\n         {name=Tensor}})\n    wrap(\"sort\",\n         cname(\"sort\"),\n         {{name=Tensor, default=true, returned=true},\n             {name=\"CudaLongTensor\", default=true, returned=true, noreadadd=true},\n             {name=Tensor},\n             {name=\"index\", default=lastdim(3)},\n             {name=\"boolean\", default=0}}\n    )\n\n   wrap(\"topk\",\n        cname(\"topk\"),\n        {{name=Tensor, default=true, returned=true},\n          {name=\"CudaLongTensor\", default=true, returned=true, noreadadd=true},\n          {name=Tensor},\n          {name=\"long\", default=1},\n          {name=\"index\", default=lastdim(3)},\n          {name=\"boolean\", default=0},\n          {name=\"boolean\", default=0}})\n\n    wrap(\"mode\",\n         cname(\"mode\"),\n         {{name=Tensor, default=true, returned=true, noreadadd=true},\n             {name=\"CudaLongTensor\", default=true, returned=true, noreadadd=true},\n             {name=Tensor},\n             {name=\"index\", default=lastdim(3)},\n             {name=\"boolean\", default=true, invisible=true}})\n\n    wrap(\"squeeze\",\n         cname(\"squeeze\"),\n         {{name=Tensor, default=true, returned=true, postcall=function(arg)\n              local txt = {}\n              if arg.returned then\n                 table.insert(txt, string.format('if(arg%d->nDimension == 1 && arg%d->size[0] == 1)', arg.i, arg.i)) -- number\n                 if Tensor == 'CudaHalfTensor' then\n                    table.insert(txt, string.format('lua_pushnumber(L, (lua_Number)THC_half2float(TH%s_get1d(cutorch_getstate(L), arg%d, 0)));', Tensor, arg.i))\n                 else\n                    table.insert(txt, string.format('lua_pushnumber(L, (lua_Number)(TH%s_get1d(cutorch_getstate(L), arg%d, 0)));', Tensor, arg.i))\n                 end\n              end\n              return table.concat(txt, '\\n')\n          end},\n            {name=Tensor}},\n         cname(\"squeeze1d\"),\n         {{name=Tensor, default=true, returned=true,\n           postcall=\n              function(arg)\n                 local txt = {}\n                 if arg.returned then\n                    table.insert(txt, string.format('if(!hasdims && arg%d->nDimension == 1 && arg%d->size[0] == 1)', arg.i, arg.i)) -- number\n                    if Tensor == 'CudaHalfTensor' then\n                       table.insert(txt, string.format('lua_pushnumber(L, (lua_Number)THC_half2float(TH%s_get1d(cutorch_getstate(L), arg%d, 0)));}', Tensor, arg.i))\n                    else\n                       table.insert(txt, string.format('lua_pushnumber(L, (lua_Number)(TH%s_get1d(cutorch_getstate(L), arg%d, 0)));}', Tensor, arg.i))\n                    end\n                 end\n                 return table.concat(txt, '\\n')\n          end},\n\n            {name=Tensor,\n             precall=\n                function(arg)\n                   return string.format('{int hasdims = arg%d->nDimension > 1;', arg.i)\n            end},\n            {name=\"index\"}})\n\n    wrap(\"abs\",\n         cname(\"abs\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n             {name=Tensor, method={default=1}}})\n\n    wrap(\"sign\",\n         cname(\"sign\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n\t    {name=Tensor, method={default=1}}})\n\n    wrap(\"cat\",\n\t cname(\"cat\"),\n\t {{name=Tensor, default=true, returned=true},\n\t    {name=Tensor},\n\t    {name=Tensor},\n\t    {name=\"index\", default=-1}},\n\t cname(\"catArray\"),\n\t {{name=Tensor, default=true, returned=true},\n\t    {name=Tensor .. \"Array\"},\n\t    {name=\"index\", default=-1}})\n\n    wrap(\"geometric\",\n        cname(\"geometric\"),\n        {{name=Tensor, returned=true},\n            {name='double'}})\n\n    wrap(\"bernoulli\",\n        cname(\"bernoulli\"),\n        {{name=Tensor, returned=true},\n            {name='double', default=0.5}},\n        cname(\"bernoulli_FloatTensor\"),\n        {{name=Tensor, returned=true},\n            {name=\"CudaTensor\"}},\n        cname(\"bernoulli_DoubleTensor\"),\n        {{name=Tensor, returned=true},\n            {name=\"CudaDoubleTensor\"}})\n\n    wrap(\"nonzero\",\n         cname(\"nonzero\"),\n         {{name=\"CudaLongTensor\", default=true, returned=true},\n             {name=Tensor}})\n\n    wrap(\"range\",\n         cname(\"range\"),\n         {{name=Tensor, default=true, returned=true, method={default='nil'}},\n             {name=accreal},\n             {name=accreal},\n             {name=accreal, default=1}})\n\n    if real == 'float' or real == 'double' or real == 'half' then\n       for _,name in ipairs({\"log\", \"log1p\", \"exp\",\n                             \"cos\", \"acos\", \"cosh\",\n                             \"sin\", \"asin\", \"sinh\",\n                             \"tan\", \"atan\", \"tanh\",\n                             \"sqrt\", \"rsqrt\", \"sigmoid\",\n                             \"cinv\", \"ceil\", \"floor\",\n                             \"neg\", \"round\", \"trunc\", \"frac\"}) do\n\n          wrap(name,\n               cname(name),\n               {{name=Tensor, default=true, returned=true, method={default='nil'}},\n                  {name=Tensor, method={default=1}}})\n\n       end\n\n       wrap(\"linspace\",\n            cname(\"linspace\"),\n            {{name=Tensor, default=true, returned=true, method={default='nil'}},\n                {name=real},\n                {name=real},\n                {name=\"long\", default=100}})\n\n       wrap(\"logspace\",\n            cname(\"logspace\"),\n            {{name=Tensor, default=true, returned=true, method={default='nil'}},\n                {name=real},\n                {name=real},\n                {name=\"long\", default=100}})\n\n       wrap(\"pow\",\n            cname(\"pow\"),\n            {{name=Tensor, default=true, returned=true, method={default='nil'}},\n                {name=Tensor, method={default=1}},\n                {name=real}},\n            cname(\"tpow\"),\n            {{name=Tensor, default=true, returned=true, method={default='nil'}},\n                {name = real},\n                {name=Tensor, method={default=1}}})\n\n     wrap(\"rand\",\n          cname(\"rand\"),\n          {{name=Tensor, default=true, returned=true, method={default='nil'}},\n           {name=\"LongArg\"}})\n\n     wrap(\"randn\",\n          cname(\"randn\"),\n          {{name=Tensor, default=true, returned=true, method={default='nil'}},\n           {name=\"LongArg\"}})\n\n     wrap(\"multinomial\",\n          cname(\"multinomial\"),\n          {{name='CudaLongTensor', default=true, returned=true, method={default='nil'}},\n           {name=Tensor},\n           {name=\"int\"},\n           {name=\"boolean\", default=false}})\n\n     wrap(\"multinomialAliasSetup_\",\n\t  cname(\"multinomialAliasSetup\"),\n\t  {{name=Tensor},\n\t     {name='CudaLongTensor', default=true, returned=true, method={default='nil'}},\n\t     {name=Tensor, default=true, returned=true, method={default='nil'}}})\n\n\n     wrap(\"multinomialAlias_\",\n\t  cname(\"multinomialAliasDraw\"),\n\t  {{name=\"CudaLongTensor\", default=true, returned=true, method={default='nil'}},\n\t     {name=\"CudaLongTensor\"},\n\t     {name=Tensor}\n})\n     for _,f in ipairs({{name='uniform', a=0, b=1},\n                        {name='cauchy', a=0, b=1},\n                        {name='normal', a=0, b=1},\n                        {name='logNormal', a=1, b=2}}) do\n\n        wrap(f.name,\n             cname(f.name),\n             {{name=Tensor, returned=true},\n              {name='double', default=f.a},\n              {name='double', default=f.b}})\n     end\n\n     wrap('exponential',\n          cname('exponential'),\n          {{name=Tensor, returned=true},\n           {name='double', default=nil}})\n\n      wrap(\"norm\",\n           cname(\"normall\"),\n           {{name=Tensor},\n            {name=real, default=2},\n            {name=accreal, creturned=true}},\n           cname(\"norm\"),\n           {{name=Tensor, default=true, returned=true},\n            {name=Tensor},\n            {name=real},\n            {name=\"index\"},\n            {name=\"boolean\", default=true, invisible=true}})\n\n      wrap(\"renorm\",\n           cname(\"renorm\"),\n          {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real},\n            {name=\"index\"},\n            {name=real}})\n\n      wrap(\"dist\",\n           cname(\"dist\"),\n           {{name=Tensor},\n               {name=Tensor},\n               {name=real, default=2},\n               {name=accreal, creturned=true}})\n\n\n      for _,name in ipairs({\"var\", \"std\"}) do\n         wrap(name,\n              cname(name .. \"all\"),\n              {{name=Tensor},\n               {name=\"boolean\", default=false},\n               {name=accreal, creturned=true}},\n              cname(name),\n              {{name=Tensor, default=true, returned=true},\n               {name=Tensor},\n               {name=\"index\"},\n               {name=\"boolean\", default=false},\n               {name=\"boolean\", default=true, invisible=true}})\n      end\n\n      wrap(\"tril\",\n           cname(\"tril\"),\n           {{name=Tensor, default=true, returned=true},\n               {name=Tensor},\n               {name=\"int\", default=0}})\n\n      wrap(\"triu\",\n           cname(\"triu\"),\n           {{name=Tensor, default=true, returned=true},\n               {name=Tensor},\n               {name=\"int\", default=0}})\n\n      wrap(\"diag\",\n           cname(\"diag\"),\n           {{name=Tensor, default=true, returned=true},\n               {name=Tensor},\n               {name=\"int\", default=0}})\n\n      wrap(\"trace\",\n           cname(\"trace\"),\n           {{name=Tensor},\n               {name=accreal, creturned=true}})\n\n      wrap(\"lerp\",\n        cname(\"lerp\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor},\n         {name=real}})\n\n       -- BLAS functions\n       wrap(\"mv\",\n            cname(\"addmv\"),\n            {{name=Tensor, default=true, returned=true, method={default='nil'},\n              init=function(arg)\n                 return table.concat(\n                    {\n                       arg.__metatable.init(arg),\n                       string.format(\"TH%s_checkGPU(cutorch_getstate(L), 1, %s);\",\n                                     Tensor, arg.args[5]:carg()),\n                       string.format(\"TH%s_resize1d(cutorch_getstate(L), %s, %s->size[0]);\", Tensor, arg:carg(), arg.args[5]:carg())\n                    }, '\\n')\n              end,\n              precall=function(arg)\n                 return table.concat(\n                    {\n                       string.format(\"TH%s_zero(cutorch_getstate(L), %s);\", Tensor, arg:carg()),\n                       arg.__metatable.precall(arg)\n                    }, '\\n')\n              end\n             },\n               {name=real, default=1, invisible=true},\n               {name=Tensor, default=1, invisible=true},\n               {name=real, default=1, invisible=true},\n               {name=Tensor, dim=2},\n               {name=Tensor, dim=1}}\n       )\n\n       wrap(\"mm\",\n            cname(\"addmm\"),\n            {{name=Tensor, default=true, returned=true, method={default='nil'},\n              init=function(arg)\n                 return table.concat(\n                    {\n                       arg.__metatable.init(arg),\n                       string.format(\"TH%s_checkGPU(cutorch_getstate(L), 2, %s, %s);\",\n                                     Tensor, arg.args[5]:carg(), arg.args[6]:carg()),\n                       string.format(\"TH%s_resize2d(cutorch_getstate(L), %s, %s->size[0], %s->size[1]);\",\n                                     Tensor, arg:carg(), arg.args[5]:carg(), arg.args[6]:carg())\n                    }, '\\n')\n              end,\n             },\n               {name=real, default=0, invisible=true},\n               {name=Tensor, default=1, invisible=true},\n               {name=real, default=1, invisible=true},\n               {name=Tensor, dim=2},\n               {name=Tensor, dim=2}}\n       )\n\n       wrap(\"bmm\",\n            cname(\"baddbmm\"),\n            {{name=Tensor, default=true, returned=true, method={default='nil'},\n              init=function(arg)\n                 return table.concat(\n                    {\n                       arg.__metatable.init(arg),\n                       string.format(\"TH%s_checkGPU(cutorch_getstate(L), 2, %s, %s);\",\n                                     Tensor, arg.args[5]:carg(), arg.args[6]:carg()),\n                       string.format(\"TH%s_resize3d(cutorch_getstate(L), %s, %s->size[0], %s->size[1], %s->size[2]);\",\n                                     Tensor, arg:carg(), arg.args[5]:carg(), arg.args[5]:carg(), arg.args[6]:carg())\n                    }, '\\n')\n              end,\n             },\n               {name=real, default=0, invisible=true},\n               {name=Tensor, default=1, invisible=true},\n               {name=real, default=1, invisible=true},\n               {name=Tensor, dim=3},\n               {name=Tensor, dim=3}}\n       )\n\n       wrap(\"ger\",\n            cname(\"addr\"),\n            {{name=Tensor, default=true, returned=true, method={default='nil'},\n              init=function(arg)\n                 return table.concat(\n                    {\n                       arg.__metatable.init(arg),\n                       string.format(\"TH%s_checkGPU(cutorch_getstate(L), 2, %s, %s);\",\n                                     Tensor, arg.args[5]:carg(), arg.args[6]:carg()),\n                       string.format(\"TH%s_resize2d(cutorch_getstate(L), %s, %s->size[0], %s->size[0]);\", Tensor, arg:carg(), arg.args[5]:carg(), arg.args[6]:carg())\n                    }, '\\n')\n              end,\n              precall=function(arg)\n                 return table.concat(\n                    {\n                       string.format(\"TH%s_zero(cutorch_getstate(L), %s);\", Tensor, arg:carg()),\n                       arg.__metatable.precall(arg)\n                    }, '\\n')\n              end\n             },\n               {name=real, default=1, invisible=true},\n               {name=Tensor, default=1, invisible=true},\n               {name=real, default=1, invisible=true},\n               {name=Tensor, dim=1},\n               {name=Tensor, dim=1}}\n       )\n\n       for _,f in ipairs({\n             {name=\"addmv\",   dim1=1, dim2=2, dim3=1},\n             {name=\"addmm\",   dim1=2, dim2=2, dim3=2},\n             {name=\"addr\",    dim1=2, dim2=1, dim3=1},\n             {name=\"baddbmm\", dim1=3, dim2=3, dim3=3},\n             {name=\"addbmm\",  dim1=2, dim2=3, dim3=3},\n                         }\n       ) do\n\n          interface:wrap(f.name,\n                         cname(f.name),\n                         {{name=Tensor, default=true, returned=true},\n                            {name=real, default=1},\n                            {name=Tensor, dim=f.dim1},\n                            {name=real, default=1},\n                            {name=Tensor, dim=f.dim2},\n                            {name=Tensor, dim=f.dim3}})\n\n          -- there is an ambiguity here, hence the more complicated setup\n          method:wrap(f.name,\n                      cname(f.name),\n                      {{name=Tensor, returned=true, dim=f.dim1},\n                         {name=real, default=1, invisible=true},\n                         {name=Tensor, default=1, dim=f.dim1},\n                         {name=real, default=1},\n                         {name=Tensor, dim=f.dim2},\n                         {name=Tensor, dim=f.dim3}},\n                      cname(f.name),\n                      {{name=Tensor, returned=true, dim=f.dim1},\n                         {name=real},\n                         {name=Tensor, default=1, dim=f.dim1},\n                         {name=real},\n                         {name=Tensor, dim=f.dim2},\n                         {name=Tensor, dim=f.dim3}})\n       end\n    end\n\n    if real == 'float' or real == 'double' then\n\n        for _,name in ipairs({\"gesv\", \"gels\"}) do\n           wrap(name,\n                cname(name),\n                {{name=Tensor, returned=true},\n                 {name=Tensor, returned=true},\n                 {name=Tensor},\n                 {name=Tensor}},\n                cname(name),\n                {{name=Tensor, default=true, returned=true, invisible=true},\n                 {name=Tensor, default=true, returned=true, invisible=true},\n                 {name=Tensor},\n                 {name=Tensor}})\n        end\n\n        wrap(\"symeig\",\n             cname(\"syev\"),\n             {{name=Tensor, returned=true},\n              {name=Tensor, returned=true},\n              {name=Tensor},\n              {name='charoption', values={'N', 'V'}, default='N'},\n              {name='charoption', values={'U', 'L'}, default='U'}},\n             cname(\"syev\"),\n             {{name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor},\n              {name='charoption', values={'N', 'V'}, default='N'},\n              {name='charoption', values={'U', 'L'}, default='U'}})\n\n        wrap(\"eig\",\n             cname(\"geev\"),\n             {{name=Tensor, returned=true},\n              {name=Tensor, returned=true},\n              {name=Tensor},\n              {name='charoption', values={'N', 'V'}, default='N'}},\n             cname(\"geev\"),\n             {{name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor},\n              {name='charoption', values={'N', 'V'}, default='N'}})\n\n        wrap(\"svd\",\n             cname(\"gesvd\"),\n             {{name=Tensor, returned=true},\n              {name=Tensor, returned=true},\n              {name=Tensor, returned=true},\n              {name=Tensor},\n              {name='charoption', values={'A', 'S'}, default='S'}},\n             cname(\"gesvd\"),\n             {{name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor},\n              {name='charoption', values={'A', 'S'}, default='S'}})\n\n        wrap(\"inverse\",\n             cname(\"getri\"),\n             {{name=Tensor, returned=true},\n              {name=Tensor}},\n             cname(\"getri\"),\n             {{name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor}})\n\n        wrap(\"potri\",\n             cname(\"potri\"),\n             {{name=Tensor, returned=true},\n              {name=Tensor},\n              {name='charoption', values={'U', 'L'}, default='U'}},\n             cname(\"potri\"),\n             {{name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor},\n              {name='charoption', values={'U', 'L'}, default='U'}})\n\n        wrap(\"potrf\",\n             cname(\"potrf\"),\n             {{name=Tensor, returned=true},\n              {name=Tensor},\n              {name='charoption', values={'U', 'L'}, default='U'}},\n             cname(\"potrf\"),\n             {{name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor},\n              {name='charoption', values={'U', 'L'}, default='U'}})\n\n        wrap(\"potrs\",\n             cname(\"potrs\"),\n             {{name=Tensor, returned=true},\n              {name=Tensor},\n              {name=Tensor},\n              {name='charoption', values={'U', 'L'}, default='U'}},\n             cname(\"potrs\"),\n             {{name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor},\n              {name=Tensor},\n              {name='charoption', values={'U', 'L'}, default='U'}})\n\n        wrap(\"qr\",\n             cname(\"qr\"),\n             {{name=Tensor, returned=true},\n              {name=Tensor, returned=true},\n              {name=Tensor}},\n             cname(\"qr\"),\n             {{name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor, default=true, returned=true, invisible=true},\n              {name=Tensor}})\n\n    end\n\n    wrap(\"dot\",\n         cname(\"dot\"),\n         {{name=Tensor},\n            {name=Tensor},\n            {name=accreal, creturned=true}})\n\n    method:register(\"m_cutorch_\" .. Tensor .. \"Math__\")\n    interface:print(method:tostring())\n    method:clearhistory()\n    method:registerDefaultArgument(cutorch_state_code)\n    interface:register(\"cutorch_\" .. Tensor .. \"Math__\")\n\n    interface:print(string.format([[\nvoid cutorch_%sMath_init(lua_State *L)\n{\n  luaT_pushmetatable(L, \"torch.%s\");\n\n  /* register methods */\n  luaL_setfuncs(L, m_cutorch_%sMath__, 0);\n\n  /* register functions into the \"torch\" field of the tensor metaclass */\n  lua_pushstring(L, \"torch\");\n  lua_newtable(L);\n  luaL_setfuncs(L, cutorch_%sMath__, 0);\n  lua_rawset(L, -3);\n  lua_pop(L, 1);\n}\n]], Tensor, Tensor, Tensor, Tensor))\n\n    if Tensor == 'CudaHalfTensor' then\n        interface:print(\"#endif\")\n    end\nend\n\n\n--\n-- CudaTensor special handling, since it is more fully implemented\n--\n\nTensor = \"CudaTensor\"\nlocal real = \"float\"\n\nfunction interface.luaname2wrapname(self, name)\n   return string.format('cutorch_%s_%s', Tensor, name)\nend\n\nfunction method.luaname2wrapname(self, name)\n    return string.format('m_cutorch_%s_%s', Tensor, name)\nend\n\nlocal function cname(name)\n   return string.format('TH%s_%s', Tensor, name)\nend\n\nlocal function lastdim(argn)\n   return function(arg)\n       return string.format('TH%s_nDimension(cutorch_getstate(L), %s)',\n                            Tensor, arg.args[argn]:carg())\n   end\nend\n\nlocal function lastdimarray(argn)\n   return function(arg)\n       return string.format('TH%s_nDimension(cutorch_getstate(L), arg%d_data[0])',\n                            Tensor, arg.args[argn].i)\n   end\nend\n\nwrap(\"zero\",\n     cname(\"zero\"),\n     {{name=Tensor, returned=true}})\n\nwrap(\"fill\",\n     cname(\"fill\"),\n     {{name=Tensor, returned=true},\n         {name=real}})\n\nwrap(\"zeros\",\n     cname(\"zeros\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n        {name=\"LongArg\"}})\n\n   wrap(\"ones\",\n        cname(\"ones\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n           {name=\"LongArg\"}})\n\nwrap(\"linspace\",\n     cname(\"linspace\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=real},\n         {name=real},\n         {name=\"long\", default=100}})\n\nwrap(\"logspace\",\n     cname(\"logspace\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=real},\n         {name=real},\n         {name=\"long\", default=100}})\n\n   wrap(\"reshape\",\n        cname(\"reshape\"),\n        {{name=Tensor, default=true, returned=true},\n           {name=Tensor},\n           {name=\"LongArg\"}})\n\n   wrap(\"numel\",\n        cname(\"numel\"),\n        {{name=Tensor},\n           {name=\"long\", creturned=true}})\n\nwrap(\"add\",\n     cname(\"add\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n      {name=Tensor, method={default=1}},\n      {name=real}},\n     cname(\"cadd\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n        {name=Tensor, method={default=1}},\n        {name=real, default=1},\n        {name=Tensor}})\n\n\nwrap(\"csub\",\n     cname(\"sub\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n      {name=Tensor, method={default=1}},\n      {name=real}},\n     cname(\"csub\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n        {name=Tensor, method={default=1}},\n        {name=real, default=1},\n        {name=Tensor}})\n\nwrap(\"mul\",\n     cname(\"mul\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n        {name=Tensor, method={default=1}},\n        {name=real}})\n\nwrap(\"div\",\n     cname(\"div\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n        {name=Tensor, method={default=1}},\n        {name=real}})\n\nwrap(\"fmod\",\n     cname(\"fmod\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n        {name=Tensor, method={default=1}},\n        {name=real}})\n\nwrap(\"remainder\",\n     cname(\"remainder\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n        {name=Tensor, method={default=1}},\n        {name=real}})\n\nwrap(\"equal\",\n     cname(\"equal\"),\n     {{name=Tensor},\n      {name=Tensor},\n      {name=\"boolean\", creturned=true}})\n\nlocal cfuncs = {\"cmul\", \"cpow\", \"cdiv\", \"cremainder\", \"cfmod\",\n                \"clshift\", \"crshift\", \"cbitand\", \"cbitor\", \"cbitxor\"}\nfor _, name in ipairs(cfuncs) do\n  wrap(name,\n       cname(name),\n       {{name=Tensor, default=true, returned=true, method={default='nil'}},\n          {name=Tensor, method={default=1}},\n        {name=Tensor}})\nend\n\nwrap(\"addcmul\",\n     cname(\"addcmul\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n        {name=Tensor, method={default=1}},\n        {name=real, default=1},\n        {name=Tensor},\n        {name=Tensor}})\n\nwrap(\"addcdiv\",\n     cname(\"addcdiv\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n        {name=Tensor, method={default=1}},\n        {name=real, default=1},\n        {name=Tensor},\n        {name=Tensor}})\n\nwrap(\"maskedFill\",\n     cname(\"maskedFill\"),\n     {{name=Tensor, returned=true, method={default='nil'}},\n      {name='CudaByteTensor'},\n      {name=real}})\n\nwrap(\"maskedCopy\",\n     cname(\"maskedCopy\"),\n     {{name=Tensor, returned=true, method={default='nil'}},\n\t{name='CudaByteTensor'},\n\t{name=Tensor}})\n\nwrap(\"maskedSelect\",\n     cname(\"maskedSelect\"),\n     {{name=Tensor, returned=true, default=true},\n      {name=Tensor},\n      {name='CudaByteTensor'}})\n\nwrap(\"gather\",\n     cname(\"gather\"),\n     {{name=Tensor, default=true, returned=true, init=gatherInit},\n\t{name=Tensor},\n\t{name=\"index\"},\n\t{name='CudaLongTensor'}},\n     cname(\"gather\"), -- this is for backward-compatibility, and takes in \"Tensor\" as the indexing tensor\n     {{name=Tensor, default=true, returned=true, init=gatherInit},\n\t{name=Tensor},\n\t{name=\"index\"},\n\t{name=Tensor, declare=TensorToCudaLong_declare(true), check=TensorToCudaLong_check, read=TensorToCudaLong_read, postcall=TensorToCudaLong_postcall}})\n\nwrap(\"scatter\",\n     cname(\"scatter\"),\n     {{name=Tensor, returned=true},\n\t{name=\"index\"},\n\t{name='CudaLongTensor'},\n\t{name=Tensor}},\n     cname(\"scatter\"), -- this is for backward-compatibility, and takes in \"Tensor\" as the indexing tensor\n     {{name=Tensor, returned=true},\n\t{name=\"index\"},\n\t{name=Tensor, declare=TensorToCudaLong_declare(true), check=TensorToCudaLong_check, read=TensorToCudaLong_read, postcall=TensorToCudaLong_postcall},\n\t{name=Tensor}},\n     cname(\"scatterFill\"),\n     {{name=Tensor, returned=true},\n\t{name=\"index\"},\n\t{name='CudaLongTensor'},\n\t{name=real}},\n     cname(\"scatterFill\"), -- this is for backward-compatibility, and takes in \"Tensor\" as the indexing tensor\n     {{name=Tensor, returned=true},\n\t{name=\"index\"},\n\t{name=Tensor, declare=TensorToCudaLong_declare(false), check=TensorToCudaLong_check, read=TensorToCudaLong_read, postcall=TensorToCudaLong_postcall},\n\t{name=real}}\n)\n\nwrap(\"scatterAdd\",\n  cname(\"scatterAdd\"),\n    {{name=Tensor, returned=true},\n     {name=\"index\"},\n     {name='CudaLongTensor'},\n     {name=Tensor}})\nwrap(\"sort\",\n     cname(\"sort\"),\n     {{name=Tensor, default=true, returned=true},\n      {name=\"CudaLongTensor\", default=true, returned=true, noreadadd=true},\n      {name=Tensor},\n      {name=\"index\", default=lastdim(3)},\n      {name=\"boolean\", default=0}})\n\nwrap(\"topk\",\n     cname(\"topk\"),\n     {{name=Tensor, default=true, returned=true},\n       {name=\"CudaLongTensor\", default=true, returned=true, noreadadd=true},\n       {name=Tensor},\n       {name=\"long\", default=1},\n       {name=\"index\", default=lastdim(3)},\n       {name=\"boolean\", default=0},\n       {name=\"boolean\", default=0}})\n\nwrap(\"mode\",\n     cname(\"mode\"),\n     {{name=Tensor, default=true, returned=true, noreadadd=true},\n       {name=\"CudaLongTensor\", default=true, returned=true, noreadadd=true},\n       {name=Tensor},\n       {name=\"index\", default=lastdim(3)},\n       {name=\"boolean\", default=true, invisible=true}})\n\ndo\n   local Tensor = Tensor\n   local real = real\n   wrap(\"mv\",\n        cname(\"addmv\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'},\n          init=function(arg)\n             return table.concat(\n                {\n                   arg.__metatable.init(arg),\n                   string.format(\"TH%s_checkGPU(cutorch_getstate(L), 1, %s);\",\n                                 Tensor, arg.args[5]:carg()),\n                   string.format(\"TH%s_resize1d(cutorch_getstate(L), %s, %s->size[0]);\", Tensor, arg:carg(), arg.args[5]:carg())\n                }, '\\n')\n          end,\n          precall=function(arg)\n             return table.concat(\n                {\n                   string.format(\"TH%s_zero(cutorch_getstate(L), %s);\", Tensor, arg:carg()),\n                   arg.__metatable.precall(arg)\n                }, '\\n')\n          end\n         },\n           {name=real, default=1, invisible=true},\n           {name=Tensor, default=1, invisible=true},\n           {name=real, default=1, invisible=true},\n           {name=Tensor, dim=2},\n           {name=Tensor, dim=1}}\n   )\n\n   wrap(\"mm\",\n        cname(\"addmm\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'},\n          init=function(arg)\n             return table.concat(\n                {\n                   arg.__metatable.init(arg),\n                   string.format(\"TH%s_checkGPU(cutorch_getstate(L), 2, %s, %s);\",\n                                 Tensor, arg.args[5]:carg(), arg.args[6]:carg()),\n                   string.format(\"TH%s_resize2d(cutorch_getstate(L), %s, %s->size[0], %s->size[1]);\",\n                                 Tensor, arg:carg(), arg.args[5]:carg(), arg.args[6]:carg())\n                }, '\\n')\n          end,\n         },\n           {name=real, default=0, invisible=true},\n           {name=Tensor, default=1, invisible=true},\n           {name=real, default=1, invisible=true},\n           {name=Tensor, dim=2},\n           {name=Tensor, dim=2}}\n   )\n\n   wrap(\"bmm\",\n        cname(\"baddbmm\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'},\n          init=function(arg)\n             return table.concat(\n                {\n                   arg.__metatable.init(arg),\n                   string.format(\"TH%s_checkGPU(cutorch_getstate(L), 2, %s, %s);\",\n                                 Tensor, arg.args[5]:carg(), arg.args[6]:carg()),\n                   string.format(\"TH%s_resize3d(cutorch_getstate(L), %s, %s->size[0], %s->size[1], %s->size[2]);\",\n                                 Tensor, arg:carg(), arg.args[5]:carg(), arg.args[5]:carg(), arg.args[6]:carg())\n                }, '\\n')\n          end,\n         },\n           {name=real, default=0, invisible=true},\n           {name=Tensor, default=1, invisible=true},\n           {name=real, default=1, invisible=true},\n           {name=Tensor, dim=3},\n           {name=Tensor, dim=3}}\n   )\n\n   wrap(\"ger\",\n        cname(\"addr\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'},\n          init=function(arg)\n             return table.concat(\n                {\n                   arg.__metatable.init(arg),\n                   string.format(\"TH%s_checkGPU(cutorch_getstate(L), 2, %s, %s);\",\n                                 Tensor, arg.args[5]:carg(), arg.args[6]:carg()),\n                   string.format(\"TH%s_resize2d(cutorch_getstate(L), %s, %s->size[0], %s->size[0]);\", Tensor, arg:carg(), arg.args[5]:carg(), arg.args[6]:carg())\n                }, '\\n')\n          end,\n          precall=function(arg)\n             return table.concat(\n                {\n                   string.format(\"TH%s_zero(cutorch_getstate(L), %s);\", Tensor, arg:carg()),\n                   arg.__metatable.precall(arg)\n                }, '\\n')\n          end\n         },\n           {name=real, default=1, invisible=true},\n           {name=Tensor, default=1, invisible=true},\n           {name=real, default=1, invisible=true},\n           {name=Tensor, dim=1},\n           {name=Tensor, dim=1}}\n   )\n\n   for _,f in ipairs({\n         {name=\"addmv\",   dim1=1, dim2=2, dim3=1},\n         {name=\"addmm\",   dim1=2, dim2=2, dim3=2},\n         {name=\"addr\",    dim1=2, dim2=1, dim3=1},\n         {name=\"baddbmm\", dim1=3, dim2=3, dim3=3},\n         {name=\"addbmm\",  dim1=2, dim2=3, dim3=3},\n                     }\n   ) do\n\n      interface:wrap(f.name,\n                     cname(f.name),\n                     {{name=Tensor, default=true, returned=true},\n                        {name=real, default=1},\n                        {name=Tensor, dim=f.dim1},\n                        {name=real, default=1},\n                        {name=Tensor, dim=f.dim2},\n                        {name=Tensor, dim=f.dim3}})\n\n      -- there is an ambiguity here, hence the more complicated setup\n      method:wrap(f.name,\n                  cname(f.name),\n                  {{name=Tensor, returned=true, dim=f.dim1},\n                     {name=real, default=1, invisible=true},\n                     {name=Tensor, default=1, dim=f.dim1},\n                     {name=real, default=1},\n                     {name=Tensor, dim=f.dim2},\n                     {name=Tensor, dim=f.dim3}},\n                  cname(f.name),\n                  {{name=Tensor, returned=true, dim=f.dim1},\n                     {name=real},\n                     {name=Tensor, default=1, dim=f.dim1},\n                     {name=real},\n                     {name=Tensor, dim=f.dim2},\n                     {name=Tensor, dim=f.dim3}})\n   end\nend\n\nwrap(\"dot\",\n     cname(\"dot\"),\n     {{name=Tensor},\n      {name=Tensor},\n      {name=real, creturned=true}})\n\nwrap(\"sum\",\n     cname(\"sumall\"),\n     {{name=Tensor},\n        {name=real, creturned=true}},\n     cname(\"sum\"),\n     {{name=Tensor, default=true, returned=true},\n        {name=Tensor},\n        {name=\"index\"},\n        {name=\"boolean\", default=true, invisible=true}})\n\nfor _, name in ipairs({\"cumsum\", \"cumprod\"}) do\n  wrap(name,\n       cname(name),\n       {{name=Tensor, default=true, returned=true},\n        {name=Tensor},\n        {name=\"index\", default=1}})\nend\n\nwrap(\"prod\",\n     cname(\"prodall\"),\n     {{name=Tensor},\n        {name=real, creturned=true}},\n     cname(\"prod\"),\n     {{name=Tensor, default=true, returned=true},\n        {name=Tensor},\n        {name=\"index\"},\n        {name=\"boolean\", default=true, invisible=true}})\n\nfor _,name in ipairs({\"min\", \"max\"}) do\n   wrap(name,\n        cname(name .. \"all\"),\n        {{name=Tensor},\n           {name=real, creturned=true}},\n        cname(name),\n        {{name=Tensor, default=true, returned=true},\n           {name='CudaLongTensor', default=true, returned=true},\n           {name=Tensor},\n           {name=\"index\"},\n           {name=\"boolean\", default=true, invisible=true}})\nend\n\nfor _,name in ipairs({\"cmin\", \"cmax\"}) do\n   wrap(name,\n        cname(name),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}},\n        cname(name .. \"Value\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor, method={default=1}},\n         {name=real}})\nend\n\nwrap(\"cross\",\ncname(\"cross\"),\n    {{name=Tensor, default=true, returned=true},\n     {name=Tensor},\n     {name=Tensor},\n     {name=\"index\", default=0}})\n\nwrap(\"tril\",\n     cname(\"tril\"),\n     {{name=Tensor, default=true, returned=true},\n      {name=Tensor},\n      {name=\"int\", default=0}})\n\nwrap(\"triu\",\n     cname(\"triu\"),\n     {{name=Tensor, default=true, returned=true},\n      {name=Tensor},\n      {name=\"int\", default=0}})\n\nwrap(\"diag\",\n     cname(\"diag\"),\n     {{name=Tensor, default=true, returned=true},\n      {name=Tensor},\n      {name=\"int\", default=0}})\n\nwrap(\"trace\",\n     cname(\"trace\"),\n     {{name=Tensor},\n      {name=real, creturned=true}})\n\nfor _,name in ipairs({\"log\", \"log1p\", \"exp\",\n                      \"cos\", \"acos\", \"cosh\",\n                      \"sin\", \"asin\", \"sinh\",\n                      \"tan\", \"atan\", \"tanh\",\n                      \"sqrt\", \"rsqrt\", \"sigmoid\",\n                      \"cinv\", \"ceil\", \"floor\",\n                      \"neg\", \"abs\", \"sign\",\n                      \"round\", \"trunc\", \"frac\"}) do\n\n   wrap(name,\n        cname(name),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}}})\n\nend\n\nwrap(\"atan2\",\n     cname(\"atan2\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n      {name=Tensor, method={default=1}},\n      {name=Tensor}}\n)\n\nwrap(\"lerp\",\n     cname(\"lerp\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n      {name=Tensor, method={default=1}},\n      {name=Tensor},\n      {name=real}}\n)\n\nwrap(\"pow\",\n     cname(\"pow\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n      {name=Tensor, method={default=1}},\n      {name=real}},\n     cname(\"tpow\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n      {name = real},\n      {name=Tensor, method={default=1}}})\n\nwrap(\"rand\",\n     cname(\"rand\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n      {name=\"LongArg\"}})\n\nwrap(\"randn\",\n     cname(\"randn\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n      {name=\"LongArg\"}})\n\nwrap(\"multinomial\",\n     cname(\"multinomial\"),\n     {{name='CudaLongTensor', default=true, returned=true, method={default='nil'}},\n        {name=Tensor},\n        {name=\"int\"},\n        {name=\"boolean\", default=false}})\n\nwrap(\"multinomialAliasSetup_\",\n     cname(\"multinomialAliasSetup\"),\n     {{name=Tensor},\n\t{name='CudaLongTensor', default=true, returned=true, method={default='nil'}},\n\t{name=Tensor, default=true, returned=true, method={default='nil'}}})\n\n\nwrap(\"multinomialAlias_\",\n     cname(\"multinomialAliasDraw\"),\n     {{name=\"CudaLongTensor\", default=true, returned=true, method={default='nil'}},\n\t{name=\"CudaLongTensor\"},\n\t{name=Tensor}\n})\n\nwrap(\"clamp\",\n     cname(\"clamp\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n      {name=Tensor, method={default=1}},\n      {name=real},\n      {name=real}})\n\nfor _,name in pairs({'lt','gt','le','ge','eq','ne'}) do\n   wrap(name,\n        cname(name .. 'Value'),\n        {{name='CudaByteTensor',default=true, returned=true},\n           {name=Tensor},\n           {name=real}},\n        cname(name .. 'ValueT'),\n        {{name=Tensor, returned=true},\n           {name=Tensor},\n           {name=real}},\n        cname(name .. 'Tensor'),\n        {{name='CudaByteTensor',default=true, returned=true},\n           {name=Tensor},\n           {name=Tensor}},\n        cname(name .. 'TensorT'),\n        {{name=Tensor, returned=true},\n           {name=Tensor},\n           {name=Tensor}})\nend\n\nwrap(\"cat\",\n     cname(\"cat\"),\n     {{name=Tensor, default=true, returned=true},\n      {name=Tensor},\n      {name=Tensor},\n      {name=\"index\", default=-1}},\n     cname(\"catArray\"),\n     {{name=Tensor, default=true, returned=true},\n      {name=Tensor .. \"Array\"},\n      {name=\"index\", default=-1}})\n\nwrap(\"nonzero\",\n     cname(\"nonzero\"),\n     {{name=\"CudaLongTensor\", default=true, returned=true},\n         {name=Tensor}})\n\nwrap(\"range\",\n     cname(\"range\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=real},\n         {name=real},\n         {name=real, default=1}})\n\nwrap(\"geometric\",\n    cname(\"geometric\"),\n    {{name=Tensor, returned=true},\n        {name='double'}})\n\nwrap(\"bernoulli\",\n    cname(\"bernoulli\"),\n    {{name=Tensor, returned=true},\n        {name='double', default=0.5}},\n    cname(\"bernoulli_FloatTensor\"),\n    {{name=Tensor, returned=true},\n        {name=\"CudaTensor\"}},\n    cname(\"bernoulli_DoubleTensor\"),\n    {{name=Tensor, returned=true},\n        {name=\"CudaDoubleTensor\"}})\n\nfor _,f in ipairs({{name='uniform', a=0, b=1},\n                   {name='normal', a=0, b=1},\n                   {name='cauchy', a=0, b=1},\n                   {name='logNormal', a=1, b=2}}) do\n\n   wrap(f.name,\n        cname(f.name),\n        {{name=Tensor, returned=true},\n         {name=real, default=f.a},\n         {name=real, default=f.b}})\nend\n\nfor _,f in ipairs({{name='exponential'}}) do\n\n   wrap(f.name,\n        cname(f.name),\n        {{name=Tensor, returned=true},\n         {name=real, default=f.a}})\nend\n\nfor _,name in ipairs({\"gesv\",\"gels\"}) do\n   wrap(name,\n        cname(name),\n        {{name=Tensor, returned=true},\n         {name=Tensor, returned=true},\n         {name=Tensor},\n         {name=Tensor}},\n        cname(name),\n        {{name=Tensor, default=true, returned=true, invisible=true},\n         {name=Tensor, default=true, returned=true, invisible=true},\n         {name=Tensor},\n         {name=Tensor}})\nend\n\nwrap(\"symeig\",\n     cname(\"syev\"),\n     {{name=Tensor, returned=true},\n      {name=Tensor, returned=true},\n      {name=Tensor},\n      {name='charoption', values={'N', 'V'}, default='N'},\n      {name='charoption', values={'U', 'L'}, default='U'}},\n     cname(\"syev\"),\n     {{name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor},\n      {name='charoption', values={'N', 'V'}, default='N'},\n      {name='charoption', values={'U', 'L'}, default='U'}})\n\nwrap(\"eig\",\n     cname(\"geev\"),\n     {{name=Tensor, returned=true},\n      {name=Tensor, returned=true},\n      {name=Tensor},\n      {name='charoption', values={'N', 'V'}, default='N'}},\n     cname(\"geev\"),\n     {{name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor},\n      {name='charoption', values={'N', 'V'}, default='N'}})\n\nwrap(\"svd\",\n     cname(\"gesvd\"),\n     {{name=Tensor, returned=true},\n      {name=Tensor, returned=true},\n      {name=Tensor, returned=true},\n      {name=Tensor},\n      {name='charoption', values={'A', 'S'}, default='S'}},\n     cname(\"gesvd\"),\n     {{name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor},\n      {name='charoption', values={'A', 'S'}, default='S'}})\n\nwrap(\"inverse\",\n     cname(\"getri\"),\n     {{name=Tensor, returned=true},\n      {name=Tensor}},\n     cname(\"getri\"),\n     {{name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor}})\n\nwrap(\"potri\",\n     cname(\"potri\"),\n     {{name=Tensor, returned=true},\n      {name=Tensor},\n      {name='charoption', values={'U', 'L'}, default='U'}},\n     cname(\"potri\"),\n     {{name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor},\n      {name='charoption', values={'U', 'L'}, default='U'}})\n\nwrap(\"potrf\",\n     cname(\"potrf\"),\n     {{name=Tensor, returned=true},\n      {name=Tensor},\n      {name='charoption', values={'U', 'L'}, default='U'}},\n     cname(\"potrf\"),\n     {{name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor},\n      {name='charoption', values={'U', 'L'}, default='U'}})\n\nwrap(\"potrs\",\n     cname(\"potrs\"),\n     {{name=Tensor, returned=true},\n      {name=Tensor},\n      {name=Tensor},\n      {name='charoption', values={'U', 'L'}, default='U'}},\n     cname(\"potrs\"),\n     {{name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor},\n      {name=Tensor},\n      {name='charoption', values={'U', 'L'}, default='U'}})\n\nwrap(\"qr\",\n     cname(\"qr\"),\n     {{name=Tensor, returned=true},\n      {name=Tensor, returned=true},\n      {name=Tensor}},\n     cname(\"qr\"),\n     {{name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor, default=true, returned=true, invisible=true},\n      {name=Tensor}})\n\nwrap(\"mean\",\n     cname(\"meanall\"),\n     {{name=Tensor},\n      {name=real, creturned=true}},\n     cname(\"mean\"),\n     {{name=Tensor, default=true, returned=true},\n        {name=Tensor},\n        {name=\"index\"},\n        {name=\"boolean\", default=true, invisible=true}})\n\nfor _,name in ipairs({\"var\", \"std\"}) do\n   wrap(name,\n        cname(name .. \"all\"),\n        {{name=Tensor},\n         {name=\"boolean\", default=false},\n         {name=real, creturned=true}},\n        cname(name),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor},\n         {name=\"index\"},\n         {name=\"boolean\", default=false},\n         {name=\"boolean\", default=true, invisible=true}})\nend\n\nwrap(\"norm\",\n     cname(\"normall\"),\n     {{name=Tensor},\n      {name=real, default=2},\n      {name=real, creturned=true}},\n     cname(\"norm\"),\n     {{name=Tensor, default=true, returned=true},\n      {name=Tensor},\n      {name=real},\n      {name=\"index\"},\n      {name=\"boolean\", default=true, invisible=true}})\n\nwrap(\"renorm\",\n     cname(\"renorm\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n      {name=Tensor, method={default=1}},\n      {name=real},\n      {name=\"index\"},\n      {name=real}})\n\nwrap(\"dist\",\n     cname(\"dist\"),\n     {{name=Tensor},\n      {name=Tensor},\n      {name=real, default=2},\n      {name=real, creturned=true}})\n\nwrap(\"squeeze\",\n     cname(\"squeeze\"),\n     {{name=Tensor, default=true, returned=true, postcall=function(arg)\n          local txt = {}\n          if arg.returned then\n             table.insert(txt, string.format('if(arg%d->nDimension == 1 && arg%d->size[0] == 1)', arg.i, arg.i)) -- number\n             table.insert(txt, string.format('lua_pushnumber(L, (lua_Number)(THCudaTensor_get1d(cutorch_getstate(L), arg%d, 0)));', arg.i))\n          end\n          return table.concat(txt, '\\n')\n     end},\n      {name=Tensor}},\n     cname(\"squeeze1d\"),\n     {{name=Tensor, default=true, returned=true,\n       postcall=\n          function(arg)\n             local txt = {}\n             if arg.returned then\n                table.insert(txt, string.format('if(!hasdims && arg%d->nDimension == 1 && arg%d->size[0] == 1)', arg.i, arg.i)) -- number\n                table.insert(txt, string.format('lua_pushnumber(L, (lua_Number)(THCudaTensor_get1d(cutorch_getstate(L), arg%d, 0)));}', arg.i))\n             end\n             return table.concat(txt, '\\n')\n          end},\n\n      {name=Tensor,\n       precall=\n          function(arg)\n             return string.format('{int hasdims = arg%d->nDimension > 1;', arg.i)\n          end},\n      {name=\"index\"}})\n\nmethod:register(\"m_cutorch_\" .. Tensor .. \"Math__\")\ninterface:print(method:tostring())\nmethod:clearhistory()\ninterface:register(\"cutorch_\" .. Tensor .. \"Math__\")\n\ninterface:print(string.format([[\nvoid cutorch_%sMath_init(lua_State *L)\n{\n  luaT_pushmetatable(L, \"torch.%s\");\n\n  /* register methods */\n  luaL_setfuncs(L, m_cutorch_%sMath__, 0);\n\n  /* register functions into the \"torch\" field of the tensor metaclass */\n  lua_pushstring(L, \"torch\");\n  lua_newtable(L);\n  luaL_setfuncs(L, cutorch_%sMath__, 0);\n  lua_rawset(L, -3);\n  lua_pop(L, 1);\n}\n]], Tensor, Tensor, Tensor, Tensor))\n\ninterface:tofile(arg[1])\n"
  },
  {
    "path": "torch/pkg/torch/TensorMath.lua",
    "content": "local wrap = require 'cwrap'\n\nrequire 'torchcwrap'\n\nlocal interface = wrap.CInterface.new()\nlocal method = wrap.CInterface.new()\nlocal argtypes = wrap.CInterface.argtypes\n\nargtypes['ptrdiff_t'] = wrap.types.ptrdiff_t\n\ninterface:print([[\n#include \"TH.h\"\n#include \"THMath.h\"\n#include \"luaT.h\"\n#include \"utils.h\"\n]])\n\n-- specific to torch: we generate a 'dispatch' function\n-- first we create a helper function\n-- note that it let the \"torch\" table on the stack\ninterface:print([[\nstatic const void* torch_istensortype(lua_State *L, const char *tname)\n{\n  if(!tname)\n    return NULL;\n\n  if(!luaT_pushmetatable(L, tname))\n    return NULL;\n\n  lua_pushstring(L, \"torch\");\n  lua_rawget(L, -2);\n  if(lua_istable(L, -1))\n    return tname;\n  else\n  {\n    lua_pop(L, 2);\n    return NULL;\n  }\n\n  return NULL;\n}\n]])\n\ninterface:print([[\nstatic int torch_isnonemptytable(lua_State *L, int idx)\n{\n  int empty;\n  if (!lua_istable(L, idx)) return 0;\n\n  lua_rawgeti(L, idx, 1);\n  empty = lua_isnil(L, -1);\n  lua_pop(L, 1);\n  return !empty;\n}\n]])\n\n\ninterface:print([[\nstatic const void* torch_istensorarray(lua_State *L, int idx)\n{\n  const char* tname;\n  int tensor_idx;\n  if (!torch_isnonemptytable(L, idx)) return 0;\n\n  lua_checkstack(L, 3);\n  lua_rawgeti(L, idx, 1);\n  tensor_idx = lua_gettop(L);\n  tname = (torch_istensortype(L, luaT_typename(L, -1)));\n  lua_remove(L, tensor_idx);\n  return tname;\n}\n]])\n\ninterface.dispatchregistry = {}\nfunction interface:wrap(name, ...)\n   -- usual stuff\n   wrap.CInterface.wrap(self, name, ...)\n\n   -- dispatch function\n   if not interface.dispatchregistry[name] then\n      interface.dispatchregistry[name] = true\n      table.insert(interface.dispatchregistry, {name=name, wrapname=string.format(\"torch_%s\", name)})\n\n      interface:print(string.gsub([[\nstatic int torch_NAME(lua_State *L)\n{\n  int narg = lua_gettop(L);\n  const void *tname;\n  if(narg >= 1 && (tname = torch_istensortype(L, luaT_typename(L, 1)))) /* first argument is tensor? */\n  {\n  }\n  else if(narg >= 2 && (tname = torch_istensortype(L, luaT_typename(L, 2)))) /* second? */\n  {\n  }\n  else if(narg >= 1 && (tname = torch_istensorarray(L, 1))) /* torch table argument? */\n  {\n  }\n  else if(narg >= 1 && lua_type(L, narg) == LUA_TSTRING\n\t  && (tname = torch_istensortype(L, lua_tostring(L, narg)))) /* do we have a valid tensor type string then? */\n  {\n    lua_remove(L, -2);\n  }\n  else if(!(tname = torch_istensortype(L, torch_getdefaulttensortype(L))))\n    luaL_error(L, \"internal error: the default tensor type does not seem to be an actual tensor\");\n\n  lua_pushstring(L, \"NAME\");\n  lua_rawget(L, -2);\n  if(lua_isfunction(L, -1))\n  {\n    lua_insert(L, 1);\n    lua_pop(L, 2); /* the two tables we put on the stack above */\n    lua_call(L, lua_gettop(L)-1, LUA_MULTRET);\n  }\n  else\n    return luaL_error(L, \"%s does not implement the torch.NAME() function\", tname);\n\n  return lua_gettop(L);\n}\n]], 'NAME', name))\n  end\nend\n\nfunction interface:dispatchregister(name)\n   local txt = self.txt\n   table.insert(txt, string.format('static const struct luaL_Reg %s [] = {', name))\n   for _,reg in ipairs(self.dispatchregistry) do\n      table.insert(txt, string.format('{\"%s\", %s},', reg.name, reg.wrapname))\n   end\n   table.insert(txt, '{NULL, NULL}')\n   table.insert(txt, '};')\n   table.insert(txt, '')\n   self.dispatchregistry = {}\nend\n\ninterface:print('/* WARNING: autogenerated file */')\ninterface:print('')\n\nlocal function wrap(...)\n   local args = {...}\n\n   -- interface\n   interface:wrap(...)\n\n   -- method: we override things possibly in method table field\n   for _,x in ipairs(args) do\n      if type(x) == 'table' then -- ok, now we have a list of args\n         for _, arg in ipairs(x) do\n            if arg.method then\n               for k,v in pairs(arg.method) do\n                  if v == 'nil' then -- special case, we erase the field\n                     arg[k] = nil\n                  else\n                     arg[k] = v\n                  end\n               end\n            end\n         end\n      end\n   end\n   local unpack = unpack or table.unpack\n    method:wrap(unpack(args))\nend\n\nlocal reals = {ByteTensor='unsigned char',\n               CharTensor='char',\n               ShortTensor='short',\n               IntTensor='int',\n               LongTensor='long',\n               FloatTensor='float',\n               HalfTensor='half',\n               DoubleTensor='double'}\n\nlocal accreals = {ByteTensor='long',\n               CharTensor='long',\n               ShortTensor='long',\n               IntTensor='long',\n               LongTensor='long',\n               FloatTensor='double',\n               HalfTensor='float',\n               DoubleTensor='double'}\n\nfor _,Tensor in ipairs({\"ByteTensor\", \"CharTensor\",\n                        \"ShortTensor\", \"IntTensor\", \"LongTensor\",\n                        \"FloatTensor\", \"HalfTensor\", \"DoubleTensor\"}) do\n\n   local real = reals[Tensor]\n   local accreal = accreals[Tensor]\n\n   function interface.luaname2wrapname(self, name)\n      return string.format('torch_%s_%s', Tensor, name)\n   end\n\n   function method.luaname2wrapname(self, name)\n      return string.format('m_torch_%s_%s', Tensor, name)\n   end\n\n   local function cname(name)\n      return string.format('TH%s_%s', Tensor, name)\n   end\n\n   local function lastdim(argn)\n      return function(arg)\n                return string.format(\"TH%s_nDimension(%s)\", Tensor, arg.args[argn]:carg())\n             end\n   end\n\n   local function lastdimarray(argn)\n      return function(arg)\n                return string.format(\"TH%s_nDimension(arg%d_data[0])\", Tensor, arg.args[argn].i)\n             end\n   end\n\n   if Tensor ~= 'HalfTensor' then\n   wrap(\"zero\",\n        cname(\"zero\"),\n        {{name=Tensor, returned=true}})\n\n   wrap(\"fill\",\n        cname(\"fill\"),\n        {{name=Tensor, returned=true},\n         {name=real}})\n\n   wrap(\"zeros\",\n        cname(\"zeros\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=\"LongArg\"}})\n\n   wrap(\"ones\",\n        cname(\"ones\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=\"LongArg\"}})\n\n   wrap(\"reshape\",\n        cname(\"reshape\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor},\n         {name=\"LongArg\"}})\n\n   wrap(\"gather\",\n        cname(\"gather\"),\n        {{name=Tensor, default=true, returned=true,\n          init=function(arg)\n                  return table.concat(\n                     {\n                        arg.__metatable.init(arg),\n                        string.format(\"THLongStorage* %s_size = THLongTensor_newSizeOf(%s);\", arg:carg(), arg.args[4]:carg()),\n                        string.format(\"TH%s_resize(%s, %s_size, NULL);\", Tensor, arg:carg(), arg:carg()),\n                        string.format(\"THLongStorage_free(%s_size);\", arg:carg())\n                     }, '\\n')\n               end\n         },\n         {name=Tensor},\n         {name=\"index\"},\n         {name=\"IndexTensor\", noreadadd=true}})\n\n   wrap(\"scatter\",\n        cname(\"scatter\"),\n        {{name=Tensor, returned=true},\n         {name=\"index\"},\n         {name=\"IndexTensor\", noreadadd=true},\n         {name=Tensor}},\n        cname(\"scatterFill\"),\n        {{name=Tensor, returned=true},\n         {name=\"index\"},\n         {name=\"IndexTensor\", noreadadd=true},\n         {name=real}})\n\n   wrap(\"scatterAdd\",\n        cname(\"scatterAdd\"),\n        {{name=Tensor, returned=true},\n         {name=\"index\"},\n         {name=\"IndexTensor\", noreadadd=true},\n         {name=Tensor}})\n\n   wrap(\"dot\",\n        cname(\"dot\"),\n        {{name=Tensor},\n         {name=Tensor},\n         {name=accreal, creturned=true}})\n\n   wrap(\"equal\",\n        cname(\"equal\"),\n        {{name=Tensor},\n         {name=Tensor},\n         {name=\"boolean\", creturned=true}})\n\n   wrap(\"add\",\n        cname(\"add\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real}},\n        cname(\"cadd\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real, default=1},\n         {name=Tensor}})\n\n   wrap(\"csub\",\n     cname(\"sub\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n       {name=Tensor, method={default=1}},\n       {name=real}},\n     cname(\"csub\"),\n     {{name=Tensor, default=true, returned=true, method={default='nil'}},\n       {name=Tensor, method={default=1}},\n       {name=real, default=1},\n       {name=Tensor}})\n\n   wrap(\"mul\",\n        cname(\"mul\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real}})\n\n   wrap(\"div\",\n        cname(\"div\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real}})\n\n   wrap(\"lshift\",\n        cname(\"lshift\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real}})\n\n   wrap(\"rshift\",\n        cname(\"rshift\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real}})\n\n   wrap(\"fmod\",\n        cname(\"fmod\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real}})\n\n   wrap(\"remainder\",\n        cname(\"remainder\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real}})\n\n   wrap(\"bitand\",\n        cname(\"bitand\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real}})\n\n   wrap(\"bitor\",\n        cname(\"bitor\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real}})\n\n   wrap(\"bitxor\",\n        cname(\"bitxor\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real}})\n\n   -- mod alias\n   wrap(\"mod\",\n        cname(\"fmod\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real}})\n\n   wrap(\"clamp\",\n        cname(\"clamp\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real},\n         {name=real}})\n\n\n   wrap(\"match\",\n        cname(\"match\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor},\n         {name=Tensor},\n         {name=real, default=1}\n        })\n\n   wrap(\"cmul\",\n        cname(\"cmul\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}})\n\n   wrap(\"cpow\",\n        cname(\"cpow\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}})\n\n   wrap(\"cdiv\",\n        cname(\"cdiv\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}})\n\n   wrap(\"clshift\",\n        cname(\"clshift\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}})\n\n   wrap(\"crshift\",\n        cname(\"crshift\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}})\n\n   wrap(\"cfmod\",\n        cname(\"cfmod\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}})\n\n   wrap(\"cremainder\",\n        cname(\"cremainder\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}})\n\n   wrap(\"cbitand\",\n        cname(\"cbitand\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}})\n\n   wrap(\"cbitor\",\n        cname(\"cbitor\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}})\n\n   wrap(\"cbitxor\",\n        cname(\"cbitxor\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}})\n\n   -- cmod alias\n   wrap(\"cmod\",\n        cname(\"cfmod\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=Tensor}})\n\n   wrap(\"addcmul\",\n        cname(\"addcmul\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real, default=1},\n         {name=Tensor},\n         {name=Tensor}})\n\n   wrap(\"addcdiv\",\n        cname(\"addcdiv\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}},\n         {name=real, default=1},\n         {name=Tensor},\n         {name=Tensor}})\n\n   wrap(\"mv\",\n        cname(\"addmv\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'},\n          init=function(arg)\n                  return table.concat(\n                     {\n                        arg.__metatable.init(arg),\n                        string.format(\"TH%s_resize1d(%s, %s->size[0]);\", Tensor, arg:carg(), arg.args[5]:carg())\n                     }, '\\n')\n               end,\n          precall=function(arg)\n                  return table.concat(\n                     {\n                        string.format(\"TH%s_zero(%s);\", Tensor, arg:carg()),\n                        arg.__metatable.precall(arg)\n                     }, '\\n')\n               end,\n       },\n         {name=real, default=0, invisible=true},\n         {name=Tensor, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=2},\n         {name=Tensor, dim=1}}\n     )\n\n   wrap(\"mm\",\n        cname(\"addmm\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'},\n          init=function(arg)\n                  return table.concat(\n                     {\n                        arg.__metatable.init(arg),\n                        string.format(\"TH%s_resize2d(%s, %s->size[0], %s->size[1]);\", Tensor, arg:carg(), arg.args[5]:carg(), arg.args[6]:carg())\n                     }, '\\n')\n               end,\n          precall=function(arg)\n                  return table.concat(\n                     {\n                        string.format(\"TH%s_zero(%s);\", Tensor, arg:carg()),\n                        arg.__metatable.precall(arg)\n                     }, '\\n')\n               end,\n       },\n         {name=real, default=0, invisible=true},\n         {name=Tensor, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=2},\n         {name=Tensor, dim=2}}\n     )\n\n   wrap(\"bmm\",\n        cname(\"baddbmm\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'},\n          init=function(arg)\n                  return table.concat(\n                     {\n                        arg.__metatable.init(arg),\n                        string.format(\"TH%s_resize3d(%s, %s->size[0], %s->size[1], %s->size[2]);\",\n                                      Tensor, arg:carg(), arg.args[5]:carg(), arg.args[5]:carg(), arg.args[6]:carg())\n                     }, '\\n')\n               end,\n          precall=function(arg)\n                  return table.concat(\n                     {\n                        string.format(\"TH%s_zero(%s);\", Tensor, arg:carg()),\n                        arg.__metatable.precall(arg)\n                     }, '\\n')\n               end,\n       },\n         {name=real, default=0, invisible=true},\n         {name=Tensor, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=3},\n         {name=Tensor, dim=3}}\n     )\n\n   wrap(\"ger\",\n        cname(\"addr\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'},\n          init=function(arg)\n                  return table.concat(\n                     {\n                        arg.__metatable.init(arg),\n                        string.format(\"TH%s_resize2d(%s, %s->size[0], %s->size[0]);\", Tensor, arg:carg(), arg.args[5]:carg(), arg.args[6]:carg())\n                     }, '\\n')\n               end,\n          precall=function(arg)\n                     return table.concat(\n                        {\n                           string.format(\"TH%s_zero(%s);\", Tensor, arg:carg()),\n                           arg.__metatable.precall(arg)\n                        }, '\\n')\n                  end\n       },\n        {name=real, default=1, invisible=true},\n        {name=Tensor, default=1, invisible=true},\n        {name=real, default=1, invisible=true},\n        {name=Tensor, dim=1},\n        {name=Tensor, dim=1}}\n     )\n\n   for _,f in ipairs({\n                        {name=\"addmv\",   dim1=1, dim2=2, dim3=1},\n                        {name=\"addmm\",   dim1=2, dim2=2, dim3=2},\n                        {name=\"addr\",    dim1=2, dim2=1, dim3=1},\n                        {name=\"addbmm\",  dim1=2, dim2=3, dim3=3},\n                        {name=\"baddbmm\", dim1=3, dim2=3, dim3=3},\n                     }\n                  ) do\n\n      interface:wrap(f.name,\n                     cname(f.name),\n                     {{name=Tensor, default=true, returned=true},\n                      {name=real, default=1},\n                      {name=Tensor, dim=f.dim1},\n                      {name=real, default=1},\n                      {name=Tensor, dim=f.dim2},\n                      {name=Tensor, dim=f.dim3}})\n\n      -- there is an ambiguity here, hence the more complicated setup\n      method:wrap(f.name,\n                  cname(f.name),\n                  {{name=Tensor, returned=true, dim=f.dim1},\n                   {name=real, default=1, invisible=true},\n                   {name=Tensor, default=1, dim=f.dim1},\n                   {name=real, default=1},\n                   {name=Tensor, dim=f.dim2},\n                   {name=Tensor, dim=f.dim3}},\n                  cname(f.name),\n                  {{name=Tensor, returned=true, dim=f.dim1},\n                   {name=real},\n                   {name=Tensor, default=1, dim=f.dim1},\n                   {name=real},\n                   {name=Tensor, dim=f.dim2},\n                   {name=Tensor, dim=f.dim3}})\n   end\n\n   wrap(\"numel\",\n        cname(\"numel\"),\n        {{name=Tensor},\n         {name=\"ptrdiff_t\", creturned=true}})\n\n   for _,name in ipairs({\"cumsum\", \"cumprod\"}) do\n      wrap(name,\n           cname(name),\n           {{name=Tensor, default=true, returned=true},\n            {name=Tensor},\n            {name=\"index\", default=1}})\n   end\n\n   wrap(\"sum\",\n        cname(\"sumall\"),\n        {{name=Tensor},\n         {name=accreal, creturned=true}},\n        cname(\"sum\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor},\n         {name=\"index\"},\n         {name=\"boolean\", default=true, invisible=true}})\n\n   wrap(\"prod\",\n        cname(\"prodall\"),\n        {{name=Tensor},\n         {name=accreal, creturned=true}},\n        cname(\"prod\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor},\n         {name=\"index\"},\n         {name=\"boolean\", default=true, invisible=true}})\n\n   for _,name in ipairs({\"min\", \"max\"}) do\n      wrap(name,\n           cname(name .. \"all\"),\n           {{name=Tensor},\n            {name=real, creturned=true}},\n           cname(name),\n           {{name=Tensor, default=true, returned=true},\n            {name=\"IndexTensor\", default=true, returned=true, noreadadd=true},\n            {name=Tensor},\n            {name=\"index\"},\n            {name=\"boolean\", default=true, invisible=true}})\n   end\n\n   for _,name in ipairs({\"cmin\", \"cmax\"}) do\n      wrap(name,\n           cname(name),\n           {{name=Tensor, default=true, returned=true},\n            {name=Tensor, method={default=1}},\n            {name=Tensor}},\n           cname(name .. \"Value\"),\n           {{name=Tensor, default=true, returned=true},\n            {name=Tensor, method={default=1}},\n            {name=real}})\n   end\n\n   wrap(\"trace\",\n        cname(\"trace\"),\n        {{name=Tensor},\n         {name=accreal, creturned=true}})\n\n   wrap(\"cross\",\n        cname(\"cross\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor},\n         {name=Tensor},\n         {name=\"index\", default=0}})\n\n   wrap(\"diag\",\n        cname(\"diag\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor},\n         {name=\"long\", default=0}})\n\n   wrap(\"eye\",\n        cname(\"eye\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=\"long\"},\n         {name=\"long\", default=0}})\n\n   wrap(\"range\",\n        cname(\"range\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=accreal},\n         {name=accreal},\n         {name=accreal, default=1}})\n\n   wrap(\"randperm\",\n        cname(\"randperm\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'},\n          postcall=function(arg)\n                      return table.concat(\n                         {\n                            arg.__metatable.postcall(arg),\n                            string.format(\"TH%s_add(%s, %s, 1);\", Tensor, arg:carg(), arg:carg())\n                         }, '\\n')\n                   end},\n         {name=\"Generator\", default=true},\n         {name=\"long\"}})\n\n   wrap(\"sort\",\n        cname(\"sort\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=\"IndexTensor\", default=true, returned=true, noreadadd=true},\n         {name=Tensor},\n         {name=\"index\", default=lastdim(3)},\n         {name=\"boolean\", default=0}})\n\nwrap(\"topk\",\n     cname(\"topk\"),\n     {{name=Tensor, default=true, returned=true},\n        {name=\"IndexTensor\", default=true, returned=true, noreadadd=true},\n        {name=Tensor},\n        {name=\"long\", default=1},\n        {name=\"index\", default=lastdim(3)},\n        {name=\"boolean\", default=0},\n        {name=\"boolean\", default=0}})\n\n   wrap(\"kthvalue\",\n        cname(\"kthvalue\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=\"IndexTensor\", default=true, returned=true, noreadadd=true},\n         {name=Tensor},\n         {name=\"long\"},\n         {name=\"index\", default=lastdim(3)},\n         {name=\"boolean\", default=true, invisible=true}})\n\n   wrap(\"mode\",\n       cname(\"mode\"),\n       {{name=Tensor, default=true, returned=true},\n           {name=\"IndexTensor\", default=true, returned=true, noreadadd=true},\n           {name=Tensor},\n           {name=\"index\", default=lastdim(3)},\n           {name=\"boolean\", default=true, invisible=true}})\n\n   wrap(\"median\",\n        cname(\"median\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=\"IndexTensor\", default=true, returned=true, noreadadd=true},\n         {name=Tensor},\n         {name=\"index\", default=lastdim(3)},\n         {name=\"boolean\", default=true, invisible=true}})\n\n   wrap(\"tril\",\n        cname(\"tril\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor},\n         {name=\"int\", default=0}})\n\n   wrap(\"triu\",\n        cname(\"triu\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor},\n         {name=\"int\", default=0}})\n\n   wrap(\"cat\",\n        cname(\"cat\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor},\n         {name=Tensor},\n         {name=\"index\", default=-1}},\n        cname(\"catArray\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=Tensor .. \"Array\"},\n         {name=\"index\", default=-1}})\n\n   if Tensor == 'ByteTensor' then -- we declare this only once\n      interface:print(\n         [[\nstatic long THRandom_random2__(THGenerator *gen, long a, long b)\n{\n  THArgCheck(b >= a, 2, \"upper bound must be larger than lower bound\");\n  return((THRandom_random(gen) % (b+1-a)) + a);\n}\n\nstatic long THRandom_random1__(THGenerator *gen, long b)\n{\n  THArgCheck(b > 0, 1, \"upper bound must be strictly positive\");\n  return(THRandom_random(gen) % b + 1);\n}\n         ]])\n   end\n\n   interface:print(string.gsub(\n                      [[\nstatic void THTensor_random2__(THTensor *self, THGenerator *gen, long a, long b)\n{\n  THArgCheck(b >= a, 2, \"upper bound must be larger than lower bound\");\n  TH_TENSOR_APPLY(real, self, *self_data = ((THRandom_random(gen) % (b+1-a)) + a);)\n}\n\nstatic void THTensor_random1__(THTensor *self, THGenerator *gen, long b)\n{\n  THArgCheck(b > 0, 1, \"upper bound must be strictly positive\");\n  TH_TENSOR_APPLY(real, self, *self_data = (THRandom_random(gen) % b + 1);)\n}\n]], 'Tensor', Tensor):gsub('real', real))\n\n   wrap('random',\n        'THRandom_random2__',\n        {{name='Generator', default=true},\n         {name='long'},\n         {name='long'},\n         {name='long', creturned=true}},\n        'THRandom_random1__',\n        {{name='Generator', default=true},\n         {name='long'},\n         {name='long', creturned=true}},\n        'THRandom_random',\n        {{name='Generator', default=true},\n         {name='long', creturned=true}},\n        cname(\"random2__\"),\n        {{name=Tensor, returned=true},\n         {name='Generator', default=true},\n         {name='long'},\n         {name='long'}},\n        cname(\"random1__\"),\n        {{name=Tensor, returned=true},\n         {name='Generator', default=true},\n         {name='long'}},\n        cname(\"random\"),\n        {{name=Tensor, returned=true},\n         {name='Generator', default=true}})\n\n   wrap(\"geometric\",\n     \"THRandom_geometric\",\n     {{name=\"Generator\", default=true},\n      {name=\"double\"},\n      {name=\"double\", creturned=true}},\n     cname(\"geometric\"),\n     {{name=Tensor, returned=true},\n      {name=\"Generator\", default=true},\n      {name=\"double\"}})\n\n   wrap(\"bernoulli\",\n      \"THRandom_bernoulli\",\n      {{name=\"Generator\", default=true},\n       {name=\"double\", default=0.5},\n       {name=\"double\", creturned=true}},\n      cname(\"bernoulli\"),\n      {{name=Tensor, returned=true},\n       {name=\"Generator\", default=true},\n       {name=\"double\", default=0.5}},\n      cname(\"bernoulli_FloatTensor\"),\n      {{name=Tensor, returned=true},\n       {name=\"Generator\", default=true},\n       {name=\"FloatTensor\"}},\n      cname(\"bernoulli_DoubleTensor\"),\n      {{name=Tensor, returned=true},\n       {name=\"Generator\", default=true},\n       {name=\"DoubleTensor\"}})\n\n   wrap(\"squeeze\",\n        cname(\"squeeze\"),\n        {{name=Tensor, default=true, returned=true, postcall=function(arg)\n                                                                local txt = {}\n                                                                if arg.returned then\n                                                                   table.insert(txt, string.format('if(arg%d->nDimension == 1 && arg%d->size[0] == 1)', arg.i, arg.i)) -- number\n                                                                   table.insert(txt, string.format('lua_pushnumber(L, (lua_Number)(*TH%s_data(arg%d)));', Tensor, arg.i))\n                                                                end\n                                                                return table.concat(txt, '\\n')\n                                                             end},\n         {name=Tensor}},\n        cname(\"squeeze1d\"),\n        {{name=Tensor, default=true, returned=true,\n\n          postcall=\n             function(arg)\n                local txt = {}\n                if arg.returned then\n                   table.insert(txt, string.format('if(!hasdims && arg%d->nDimension == 1 && arg%d->size[0] == 1)', arg.i, arg.i)) -- number\n                   table.insert(txt, string.format('lua_pushnumber(L, (lua_Number)(*TH%s_data(arg%d)));}', Tensor, arg.i))\n                end\n                return table.concat(txt, '\\n')\n             end},\n\n         {name=Tensor,\n\n          precall=\n             function(arg)\n                return string.format('{int hasdims = arg%d->nDimension > 1;', arg.i)\n             end},\n\n         {name=\"index\"}})\n\n   wrap(\"sign\",\n        cname(\"sign\"),\n        {{name=Tensor, default=true, returned=true, method={default='nil'}},\n         {name=Tensor, method={default=1}}})\n\n   wrap(\"conv2\",\n        cname(\"conv2Dmul\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=2},\n         {name=Tensor, dim=2},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"C\", invisible=true}},\n        cname(\"conv2Dcmul\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=3},\n         {name=Tensor, dim=3},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"C\", invisible=true}},\n        cname(\"conv2Dmv\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=3},\n         {name=Tensor, dim=4},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"C\", invisible=true}}\n     )\n\n   wrap(\"xcorr2\",\n        cname(\"conv2Dmul\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=2},\n         {name=Tensor, dim=2},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"X\", invisible=true}},\n        cname(\"conv2Dcmul\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=3},\n         {name=Tensor, dim=3},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"X\", invisible=true}},\n        cname(\"conv2Dmv\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=3},\n         {name=Tensor, dim=4},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"X\", invisible=true}}\n     )\n\n   wrap(\"conv3\",\n        cname(\"conv3Dmul\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=3},\n         {name=Tensor, dim=3},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"C\", invisible=true}},\n        cname(\"conv3Dcmul\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=4},\n         {name=Tensor, dim=4},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"C\", invisible=true}},\n        cname(\"conv3Dmv\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=4},\n         {name=Tensor, dim=5},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"C\", invisible=true}}\n     )\n\n   wrap(\"xcorr3\",\n        cname(\"conv3Dmul\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=3},\n         {name=Tensor, dim=3},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"X\", invisible=true}},\n        cname(\"conv3Dcmul\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=4},\n         {name=Tensor, dim=4},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"X\", invisible=true}},\n        cname(\"conv3Dmv\"),\n        {{name=Tensor, default=true, returned=true},\n         {name=real, default=0, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=Tensor, dim=4},\n         {name=Tensor, dim=5},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name=real, default=1, invisible=true},\n         {name='charoption', values={'V', 'F'}, default='V'},\n         {name='charoption', default=\"X\", invisible=true}}\n     )\n\n   for _,name in pairs({'lt','gt','le','ge','eq','ne'}) do\n      wrap(name,\n           cname(name .. 'Value'),\n           {{name='ByteTensor',default=true, returned=true},\n            {name=Tensor},\n            {name=real}},\n           cname(name .. 'ValueT'),\n           {{name=Tensor, returned=true},\n            {name=Tensor},\n            {name=real}},\n           cname(name .. 'Tensor'),\n           {{name='ByteTensor',default=true, returned=true},\n            {name=Tensor},\n            {name=Tensor}},\n           cname(name .. 'TensorT'),\n           {{name=Tensor, returned=true},\n            {name=Tensor},\n            {name=Tensor}})\n   end\n\n   wrap(\"nonzero\",\n        cname(\"nonzero\"),\n        {{name=\"IndexTensor\", default=true, returned=true},\n         {name=Tensor}})\n  end  -- ~= HalfTensor\n\n   if Tensor == 'ByteTensor' then\n     -- Logical accumulators only apply to ByteTensor\n      for _,name in ipairs({'all', 'any'}) do\n        wrap(name,\n             cname('logical' .. name),\n             {{name=Tensor},\n\t\t{name=\"boolean\", creturned=true}})\n      end\n   end\n\n   if Tensor == 'IntTensor' then\n         wrap(\"abs\",\n              cname(\"abs\"),\n              {{name=Tensor, default=true, returned=true, method={default='nil'}},\n               {name=Tensor, method={default=1}}},\n              \"abs\",\n              {{name=real},\n               {name=real, creturned=true}})\n   elseif Tensor == 'LongTensor' then\n         wrap(\"abs\",\n              cname(\"abs\"),\n              {{name=Tensor, default=true, returned=true, method={default='nil'}},\n               {name=Tensor, method={default=1}}},\n              \"labs\",\n              {{name=real},\n               {name=real, creturned=true}})\n   end\n\n   if Tensor == 'FloatTensor' or Tensor == 'DoubleTensor' then\n\n      wrap(\"mean\",\n           cname(\"meanall\"),\n           {{name=Tensor},\n            {name=accreal, creturned=true}},\n           cname(\"mean\"),\n           {{name=Tensor, default=true, returned=true},\n            {name=Tensor},\n            {name=\"index\"},\n            {name=\"boolean\", default=true, invisible=true}})\n\n      for _,name in ipairs({\"var\", \"std\"}) do\n         wrap(name,\n              cname(name .. \"all\"),\n              {{name=Tensor},\n               {name=\"boolean\", default=false},\n               {name=accreal, creturned=true}\n              },\n              cname(name),\n              {{name=Tensor, default=true, returned=true},\n               {name=Tensor},\n               {name=\"index\"},\n               {name=\"boolean\", default=false},\n               {name=\"boolean\", default=true, invisible=true}})\n      end\n      wrap(\"histc\",\n           cname(\"histc\"),\n           {{name=Tensor, default=true, returned=true},\n            {name=Tensor},\n            {name=\"long\",default=100},\n            {name=\"double\",default=0},\n            {name=\"double\",default=0}})\n\n      wrap(\"bhistc\",\n           cname(\"bhistc\"),\n           {{name=Tensor, default=true, returned=true},\n            {name=Tensor},\n            {name=\"long\",default=100},\n            {name=\"double\",default=0},\n            {name=\"double\",default=0}})\n\n      wrap(\"norm\",\n           cname(\"normall\"),\n           {{name=Tensor},\n            {name=real, default=2},\n            {name=accreal, creturned=true}},\n           cname(\"norm\"),\n           {{name=Tensor, default=true, returned=true},\n            {name=Tensor},\n            {name=real},\n            {name=\"index\"},\n            {name=\"boolean\", default=true, invisible=true}})\n\n      wrap(\"renorm\",\n           cname(\"renorm\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real},\n            {name=\"index\"},\n            {name=real}})\n\n      wrap(\"dist\",\n           cname(\"dist\"),\n           {{name=Tensor},\n            {name=Tensor},\n            {name=real, default=2},\n            {name=accreal, creturned=true}})\n\n      wrap(\"linspace\",\n           cname(\"linspace\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=real},\n            {name=real},\n            {name=\"long\", default=100}})\n\n      wrap(\"logspace\",\n           cname(\"logspace\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=real},\n            {name=real},\n            {name=\"long\", default=100}})\n\n      for _,name in ipairs({\"log\", \"log1p\", \"exp\",\n                            \"cos\", \"acos\", \"cosh\",\n                            \"sin\", \"asin\", \"sinh\",\n                            \"tan\", \"atan\", \"tanh\",\n                            \"sqrt\", \"round\", \"ceil\",\n                            \"floor\", \"trunc\", }) do\n         wrap(name,\n              cname(name),\n              {{name=Tensor, default=true, returned=true, method={default='nil'}},\n               {name=Tensor, method={default=1}}},\n              name,\n              {{name=real},\n               {name=real, creturned=true}})\n      end\n\n      wrap(\"abs\",\n           cname(\"abs\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}}},\n           \"fabs\",\n           {{name=real},\n            {name=real, creturned=true}})\n\n      wrap(\"frac\",\n           cname(\"frac\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}}},\n           \"TH_frac\",\n           {{name=real},\n            {name=real, creturned=true}})\n\n      wrap(\"rsqrt\",\n           cname(\"rsqrt\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}}},\n           \"TH_rsqrt\",\n           {{name=real},\n            {name=real, creturned=true}})\n\n      wrap(\"sigmoid\",\n           cname(\"sigmoid\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}}},\n           \"TH_sigmoid\",\n           {{name=real},\n            {name=real, creturned=true}})\n\n      wrap(\"neg\",\n           cname(\"neg\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}}})\n\n      wrap(\"cinv\",\n           cname(\"cinv\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}}})\n\n      wrap(\"lerp\",\n           cname(\"lerp\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=Tensor},\n            {name=real}},\n           \"TH_lerp\",\n           {{name=real},\n            {name=real},\n            {name=real},\n            {name=real, creturned=true}})\n\n      wrap(\"atan2\",\n           cname(\"atan2\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=Tensor}},\n           \"atan2\",\n           {{name=real},\n            {name=real},\n            {name=real, creturned=true}})\n\n      wrap(\"pow\",\n           cname(\"pow\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=Tensor, method={default=1}},\n            {name=real}},\n           cname(\"tpow\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name=real},\n            {name=Tensor, method={default=1}}},\n           \"pow\",\n           {{name=real},\n            {name=real},\n            {name=real, creturned=true}})\n\n      wrap(\"rand\",\n           cname(\"rand\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name='Generator', default=true},\n            {name=\"LongArg\"}})\n\n      wrap(\"randn\",\n           cname(\"randn\"),\n           {{name=Tensor, default=true, returned=true, method={default='nil'}},\n            {name='Generator', default=true},\n            {name=\"LongArg\"}})\n\n      wrap(\"multinomial\",\n           cname(\"multinomial\"),\n           {{name=\"IndexTensor\", default=true, returned=true, method={default='nil'}},\n              {name='Generator', default=true},\n              {name=Tensor},\n              {name=\"int\"},\n              {name=\"boolean\", default=false}})\n\n      wrap(\"multinomialAliasSetup_\",\n           cname(\"multinomialAliasSetup\"),\n           {{name=Tensor},\n              {name=\"IndexTensor\", default=true, returned=true, method={default='nil'}},\n              {name=Tensor, default=true, returned=true, method={default='nil'}}})\n\n      wrap(\"multinomialAlias_\",\n           cname(\"multinomialAliasDraw\"),\n           {{name=\"IndexTensor\", default=true, returned=true, method={default='nil'}},\n              {name='Generator', default=true},\n              {name=\"IndexTensor\"},\n              {name=Tensor}\n              })\n\n      for _,f in ipairs({{name='uniform', a=0, b=1},\n            {name='normal', a=0, b=1},\n            {name='cauchy', a=0, b=1},\n            {name='logNormal', a=1, b=2}}) do\n\n         wrap(f.name,\n              string.format(\"THRandom_%s\", f.name),\n              {{name='Generator', default=true},\n               {name=\"double\", default=f.a},\n               {name=\"double\", default=f.b},\n               {name=\"double\", creturned=true}},\n              cname(f.name),\n              {{name=Tensor, returned=true},\n               {name='Generator', default=true},\n               {name=real, default=f.a},\n               {name=real, default=f.b}})\n      end\n\n      for _,f in ipairs({{name='exponential'}}) do\n\n         wrap(f.name,\n              string.format(\"THRandom_%s\", f.name),\n              {{name='Generator', default=true},\n               {name=\"double\", default=f.a},\n               {name=\"double\", creturned=true}},\n              cname(f.name),\n              {{name=Tensor, returned=true},\n               {name='Generator', default=true},\n               {name=real, default=f.a}})\n      end\n\n      for _,name in ipairs({\"gesv\",\"gels\"}) do\n         interface:wrap(name,\n                        cname(name),\n                        {{name=Tensor, returned=true},\n                         {name=Tensor, returned=true},\n                         {name=Tensor},\n                         {name=Tensor}},\n                        cname(name),\n                        {{name=Tensor, default=true, returned=true, invisible=true},\n                         {name=Tensor, default=true, returned=true, invisible=true},\n                         {name=Tensor},\n                         {name=Tensor}}\n                     )\n      end\n      interface:wrap(\"trtrs\",\n                     cname(\"trtrs\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor, returned=true},\n                      {name=Tensor},\n                      {name=Tensor},\n                      {name='charoption', values={'U', 'L'}, default='U'},  -- uplo\n                      {name='charoption', values={'N', 'T'}, default='N'},  -- trans\n                      {name='charoption', values={'N', 'U'}, default='N'}}, -- diag\n                     cname(\"trtrs\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor},\n                      {name=Tensor},\n                      {name='charoption', values={'U', 'L'}, default='U'},  -- uplo\n                      {name='charoption', values={'N', 'T'}, default='N'},  -- trans\n                      {name='charoption', values={'N', 'U'}, default='N'}}  -- diag\n                  )\n\n      interface:wrap(\"symeig\",\n                     cname(\"syev\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor, returned=true},\n                      {name=Tensor},\n                      {name='charoption', values={'N', 'V'}, default='N'},\n                      {name='charoption', values={'U', 'L'}, default='U'}},\n                     cname(\"syev\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor},\n                      {name='charoption', values={'N', 'V'}, default='N'},\n                      {name='charoption', values={'U', 'L'}, default='U'}}\n                  )\n      interface:wrap(\"eig\",\n                     cname(\"geev\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor, returned=true},\n                      {name=Tensor},\n                      {name='charoption', values={'N', 'V'}, default='N'}},\n                     cname(\"geev\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor},\n                      {name='charoption', values={'N', 'V'}, default='N'}}\n                  )\n\n      interface:wrap(\"svd\",\n                     cname(\"gesvd\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor, returned=true},\n                      {name=Tensor, returned=true},\n                      {name=Tensor},\n                      {name='charoption', values={'A', 'S'}, default='S'}},\n                     cname(\"gesvd\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor},\n                      {name='charoption', values={'A', 'S'}, default='S'}}\n                  )\n      interface:wrap(\"inverse\",\n                     cname(\"getri\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor}},\n                     cname(\"getri\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor}}\n                  )\n      interface:wrap(\"potrf\",\n                     cname(\"potrf\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor},\n                      {name='charoption', values={'U', 'L'}, default='U'}}, -- uplo\n                     cname(\"potrf\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor},\n                      {name='charoption', values={'U', 'L'}, default='U'}}\n                  )\n      interface:wrap(\"potrs\",\n                     cname(\"potrs\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor},\n                      {name=Tensor},\n                      {name='charoption', values={'U', 'L'}, default='U'}}, -- uplo\n                     cname(\"potrs\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor},\n                      {name=Tensor},\n                      {name='charoption', values={'U', 'L'}, default='U'}}\n                  )\n      interface:wrap(\"potri\",\n                     cname(\"potri\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor},\n                      {name='charoption', values={'U', 'L'}, default='U'}}, -- uplo\n                     cname(\"potri\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor},\n                      {name='charoption', values={'U', 'L'}, default='U'}} -- uplo\n                    )\n      interface:wrap(\"pstrf\",\n                     cname(\"pstrf\"),\n                     {{name=Tensor, returned=true},\n                      {name='IntTensor', returned=true},\n                      {name=Tensor},\n                      {name='charoption', values={'U', 'L'}, default='U'},  -- uplo\n                      {name=real, default=-1}},\n                     cname(\"pstrf\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name='IntTensor', default=true, returned=true, invisible=true},\n                      {name=Tensor},\n                      {name='charoption', values={'U', 'L'}, default='U'},  -- uplo\n                      {name=real, default=-1}}\n                  )\n      interface:wrap(\"qr\",\n                     cname(\"qr\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor, returned=true},\n                      {name=Tensor}},\n                     cname(\"qr\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor}}\n                  )\n      interface:wrap(\"geqrf\",\n                     cname(\"geqrf\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor, returned=true},\n                      {name=Tensor}},\n                     cname(\"geqrf\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor}}\n                  )\n      interface:wrap(\"orgqr\",\n                     cname(\"orgqr\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor},\n                      {name=Tensor}},\n                     cname(\"orgqr\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor},\n                      {name=Tensor}}\n                  )\n      interface:wrap(\"ormqr\",\n                     cname(\"ormqr\"),\n                     {{name=Tensor, returned=true},\n                      {name=Tensor},\n                      {name=Tensor},\n                      {name=Tensor},\n                      {name='charoption', values={'L', 'R'}, default='L'},\n                      {name='charoption', values={'N', 'T'}, default='N'}},\n                     cname(\"ormqr\"),\n                     {{name=Tensor, default=true, returned=true, invisible=true},\n                      {name=Tensor},\n                      {name=Tensor},\n                      {name=Tensor},\n                      {name='charoption', values={'L', 'R'}, default='L'},\n                      {name='charoption', values={'N', 'T'}, default='N'}}\n                  )\n   end\n\n   method:register(string.format(\"m_torch_%sMath__\", Tensor))\n   interface:print(method:tostring())\n   method:clearhistory()\n   interface:register(string.format(\"torch_%sMath__\", Tensor))\n\n   interface:print(string.gsub([[\nstatic void torch_TensorMath_init(lua_State *L)\n{\n  luaT_pushmetatable(L, \"torch.Tensor\");\n\n  /* register methods */\n  luaT_setfuncs(L, m_torch_TensorMath__, 0);\n\n  /* register functions into the \"torch\" field of the tensor metaclass */\n  lua_pushstring(L, \"torch\");\n  lua_newtable(L);\n  luaT_setfuncs(L, torch_TensorMath__, 0);\n  lua_rawset(L, -3);\n  lua_pop(L, 1);\n}\n]], 'Tensor', Tensor))\nend\n\ninterface:dispatchregister(\"torch_TensorMath__\")\n\ninterface:print([[\nvoid torch_TensorMath_init(lua_State *L)\n{\n  torch_ByteTensorMath_init(L);\n  torch_CharTensorMath_init(L);\n  torch_ShortTensorMath_init(L);\n  torch_IntTensorMath_init(L);\n  torch_LongTensorMath_init(L);\n  torch_FloatTensorMath_init(L);\n  torch_DoubleTensorMath_init(L);\n  luaT_setfuncs(L, torch_TensorMath__, 0);\n}\n]])\n\nif arg[1] then\n   interface:tofile(arg[1])\nelse\n   print(interface:tostring())\nend\n"
  }
]