unsigned int JS_MinimaxBestMove(unsigned int f00, unsigned int f01, unsigned int f02, unsigned int f03,
								unsigned int f10, unsigned int f11, unsigned int f12, unsigned int f13,
								unsigned int f20, unsigned int f21, unsigned int f22, unsigned int f23,
								unsigned int f30, unsigned int f31, unsigned int f32, unsigned int f33) {
	Board board = MakeBoard(
		MakeRow(f00, f01, f02, f03),
		MakeRow(f10, f11, f12, f13),
		MakeRow(f20, f21, f22, f23),
		MakeRow(f30, f31, f32, f33)
	);
	HeuristicParameters parameters;
	GetDefaultHeuristicParameters(&parameters);
	auto p = FindBestMove(board, parameters);
	return p.first;
}
extern void EvaluateRoll(float ar[NUM_ROLLOUT_OUTPUTS], int nDie1, int nDie2, const TanBoard anBoard,
             const cubeinfo * pci, const evalcontext * pec)
{
    TanBoard anBoardTemp;
    cubeinfo ciOpp;

    memcpy(&ciOpp, pci, sizeof(cubeinfo));
    ciOpp.fMove = !pci->fMove;

    memcpy(&anBoardTemp[0][0], &anBoard[0][0], 2 * 25 * sizeof(int));

    if (FindBestMove(NULL, nDie1, nDie2, anBoardTemp, pci, NULL, defaultFilters) < 0)
        g_assert_not_reached();

    SwapSides(anBoardTemp);

    GeneralEvaluationE(ar, (ConstTanBoard) anBoardTemp, &ciOpp, pec);

    return;
}
unsigned int PlayTest(const HeuristicParameters& parameters, unsigned int rollbacks, BoardDB* boarddb, std::mutex* boarddb_mutex) {
	std::mt19937 rng(RandomSeed());

	struct HistoryData {
		Board board;
		unsigned int moves, score;
	};
	std::vector<HistoryData> history;
	std::vector<BoardScore> extra_db;

	Board board{0};

	auto t1 = std::chrono::high_resolution_clock::now();
	unsigned int moves = 0, score = 0;
	for( ; ; ) {

		history.push_back(HistoryData{board, moves, score});
		//PrintBoard(board);

		// computer
		unsigned int locations[16], location_count = 0;
		for(unsigned int location = 0; location < 16; ++location) {
			if(GetCell(board, location) == 0) {
				locations[location_count] = location;
				++location_count;
			}
		}
		if(location_count == 0) {
			std::cout << "Can't insert!" << std::endl;
			exit(1);
		}
		board = SetCell(board, locations[rng() % location_count], (rng() % 10 == 0)? 2 : 1);

		//PrintBoard(board);

		// player
		auto move = FindBestMove(board, parameters);
		extra_db.push_back(BoardScore{board, move.second});
		if(move.first == DIRECTION_NONE) {
			if(rollbacks == 0)
				break;
			--rollbacks;
			unsigned int back = 10 + rng() % 90;
			unsigned int p = (history.size() > back)? history.size() - back : 0;
			board = history[p].board;
			moves = history[p].moves;
			score = history[p].score;
			history.resize(p);
		} else {
			BoardScore result = Collapse(board, move.first);
			if(result.m_board.m_data == board.m_data) {
				std::cout << "Invalid move!" << std::endl;
				exit(1);
			}
			board = result.m_board;
			score += result.m_score * 2;
			++moves;
		}

	}
	auto t2 = std::chrono::high_resolution_clock::now();
	unsigned int time = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count();
	unsigned int time_per_move = time / moves;

	std::cout << "Game over - Move: " << moves << ", Time per move: " << time_per_move << ", Score: " << score << std::endl;

	if(boarddb != NULL) {
		std::lock_guard<std::mutex> lock(*boarddb_mutex);
		boarddb->m_results.insert(boarddb->m_results.end(), extra_db.begin(), extra_db.end());
		//unsigned int back = 100;
		//for(size_t i = (history.size() > back)? history.size() - back : 0; i < history.size(); ++i) {
		/*for(size_t i = 0; i < history.size(); ++i) {
			BoardScore result;
			result.m_board = history[i].board;
			result.m_score = score - history[i].score;
			boarddb->m_results.push_back(result);
		}*/
	}

	return score;
}
Beispiel #4
0
static void
add_level(GtkTreeStore * model, GtkTreeIter * iter,
          const int n, const TanBoard anBoard,
          evalcontext * pec, cubeinfo * pci, const gboolean fInvert, float arOutput[NUM_ROLLOUT_OUTPUTS])
{

    int n0, n1;
    GtkTreeIter child_iter;
    cubeinfo ci;
    TanBoard an;
    float ar[NUM_ROLLOUT_OUTPUTS];
    int anMove[8];
    int i;

    char szRoll[3], szMove[100], *szEquity;

    /* cubeinfo for opponent on roll */

    memcpy(&ci, pci, sizeof(cubeinfo));
    ci.fMove = !pci->fMove;

    for (i = 0; i < NUM_ROLLOUT_OUTPUTS; ++i)
        arOutput[i] = 0.0f;

    for (n0 = 0; n0 < 6; ++n0) {
        for (n1 = 0; n1 <= n0; ++n1) {

            memcpy(an, anBoard, sizeof(an));

            if (FindBestMove(anMove, n0 + 1, n1 + 1, an, pci, pec, defaultFilters) < 0)
                return;

            SwapSides(an);

            gtk_tree_store_append(model, &child_iter, iter);

            if (n) {

                add_level(model, &child_iter, n - 1, (ConstTanBoard) an, pec, &ci, !fInvert, ar);
                if (fInterrupt)
                    return;

            } else {

                /* evaluate resulting position */

                ProgressValueAdd(1);

                if (GeneralEvaluationE(ar, (ConstTanBoard) an, &ci, pec) < 0)
                    return;

            }

            if (fInvert)
                InvertEvaluationR(ar, &ci);

            sprintf(szRoll, "%d%d", n0 + 1, n1 + 1);
            FormatMove(szMove, anBoard, anMove);

            szEquity = OutputMWC(ar[OUTPUT_CUBEFUL_EQUITY], fInvert ? pci : &ci, TRUE);

            gtk_tree_store_set(model, &child_iter, 0, szRoll, 1, szMove, 2, szEquity, -1);

            for (i = 0; i < NUM_ROLLOUT_OUTPUTS; ++i)
                arOutput[i] += (n0 == n1) ? ar[i] : 2.0f * ar[i];

        }

    }

    for (i = 0; i < NUM_ROLLOUT_OUTPUTS; ++i)
        arOutput[i] /= 36.0f;

    /* add average equity */

    szEquity = OutputMWC(arOutput[OUTPUT_CUBEFUL_EQUITY], fInvert ? pci : &ci, TRUE);

    gtk_tree_store_append(model, &child_iter, iter);

    gtk_tree_store_set(model, &child_iter, 0, _("Average equity"), 1, "", 2, szEquity, -1);

    if (!fInvert)
        InvertEvaluationR(arOutput, pci);

}
static char *
ExtFIBSBoard(scancontext * pec)
{
    ProcessedFIBSBoard processedBoard;
    TanBoard anBoardOrig;
    int anScore[2], anMove[8], fTurn;
    float arDouble[NUM_CUBEFUL_OUTPUTS], aarOutput[2][NUM_ROLLOUT_OUTPUTS], aarStdDev[2][NUM_ROLLOUT_OUTPUTS];
    rolloutstat aarsStatistics[2][2];
    cubeinfo ci;
    char *szResponse;

    if (ProcessFIBSBoardInfo(&pec->bi, &processedBoard)) {
        szResponse = g_strdup_printf("Error: badly formed board\n");
    } else {

        anScore[0] = processedBoard.nScoreOpp;
        anScore[1] = processedBoard.nScore;

        /* If the session isn't using Crawford rule, set crawford flag to false */
        processedBoard.fCrawford = pec->fCrawfordRule ? processedBoard.fCrawford : FALSE;
        /* Set the Jacoby flag appropriately from the external interface settings */
        processedBoard.fJacoby = pec->fJacobyRule;

        /* printf ("Crawford Setting: %d\n", fCrawford); */
        /* printf ("Jacoby Setting: %d\n", fJacoby); */

        fTurn = 1;
        SetCubeInfo(&ci, processedBoard.nCube, processedBoard.fCubeOwner, fTurn, processedBoard.nMatchTo,
                    anScore, processedBoard.fCrawford, processedBoard.fJacoby, nBeavers, bgvDefault);

        memcpy(anBoardOrig, processedBoard.anBoard, sizeof(processedBoard.anBoard));

        if (processedBoard.fDoubled) {

            /* take decision */
            if (GeneralCubeDecision(aarOutput, aarStdDev,
                                    aarsStatistics, (ConstTanBoard) processedBoard.anBoard, &ci, GetEvalCube(), NULL,
                                    NULL) < 0)
                return NULL;

            switch (FindCubeDecision(arDouble, aarOutput, &ci)) {
            case DOUBLE_PASS:
            case TOOGOOD_PASS:
            case REDOUBLE_PASS:
            case TOOGOODRE_PASS:
                szResponse = g_strdup("drop\n");
                break;

            case NODOUBLE_BEAVER:
            case DOUBLE_BEAVER:
            case NO_REDOUBLE_BEAVER:
                szResponse = g_strdup("beaver\n");
                break;

            default:
                szResponse = g_strdup("take\n");
            }

        } else if (pec->nResignation) {

            /* if opp wants to resign (extension to FIBS board) */

            float arOutput[NUM_ROLLOUT_OUTPUTS];
            float rEqBefore, rEqAfter;
            const float epsilon = 1.0e-6f;

            getResignation(arOutput, processedBoard.anBoard, &ci, &esEvalCube);

            getResignEquities(arOutput, &ci, pec->nResignation, &rEqBefore, &rEqAfter);

            /* if opponent gives up equity by resigning */
            if ((rEqAfter - epsilon) < rEqBefore)
                szResponse = g_strdup("accept\n");
            else
                szResponse = g_strdup("reject\n");

        } else if (processedBoard.anDice[0]) {
            /* move */
            char szMove[64];
            if (FindBestMove(anMove, processedBoard.anDice[0], processedBoard.anDice[1],
                             processedBoard.anBoard, &ci, &GetEvalChequer()->ec, *GetEvalMoveFilter()) < 0)
                return NULL;

            FormatMovePlain(szMove, anBoardOrig, anMove);
            szResponse = g_strconcat(szMove, "\n", NULL);
        } else {
            /* double decision */
            if (GeneralCubeDecision(aarOutput, aarStdDev,
                                    aarsStatistics, (ConstTanBoard) processedBoard.anBoard, &ci, GetEvalCube(),
                                    NULL, NULL) < 0)
                return NULL;

            switch (FindCubeDecision(arDouble, aarOutput, &ci)) {
            case DOUBLE_TAKE:
            case DOUBLE_PASS:
            case DOUBLE_BEAVER:
            case REDOUBLE_TAKE:
            case REDOUBLE_PASS:
                szResponse = g_strdup("double\n");
                break;

            default:
                szResponse = g_strdup("roll\n");
            }
        }

    }

    return szResponse;

}
Beispiel #6
0
int main(int argc, char *argv[])
{
    char buf[1028],move[12];
    int len,mlen;

    /* Convert command line parameters */
    SecPerMove = (float) atof(argv[1]); /* Time allotted for each move */
    MaxDepth = (argc == 4) ? atoi(argv[3]) : -1;

fprintf(stderr, "%s SecPerMove == %lg\n", argv[0], SecPerMove);

    /* Determine if I am player 1 (red) or player 2 (white) */
    //fgets(buf, sizeof(buf), stdin);
    len=read(STDIN_FILENO,buf,1028);
    buf[len]='\0';
    if(!strncmp(buf,"Player1", strlen("Player1"))) 
    {
        fprintf(stderr, "I'm Player 1\n");
        player1 = 1; 
    }
    else 
    {
        fprintf(stderr, "I'm Player 2\n");
        player1 = 0;
    }
    if(player1) me = 1; else me = 2;

    /* Set up the board */ 
    ResetBoard();
    srand((unsigned int)time(0));

    if (player1) {
        start = times(&bff);
        goto determine_next_move;
    }

    for(;;) {
        /* Read the other player's move from the pipe */
        //fgets(buf, sizeof(buf), stdin);
        len=read(STDIN_FILENO,buf,1028);
        buf[len]='\0';
        start = times(&bff);
        memset(move,0,12*sizeof(char));

        /* Update the board to reflect opponents move */
        mlen = TextToMove(buf,move);
        PerformMove(board,move,mlen);
        
determine_next_move:
        /* Find my move, update board, and write move to pipe */
        if(player1) FindBestMove(1); else FindBestMove(2);
        if(bestmove[0] != 0) { /* There is a legal move */
            mlen = MoveLength(bestmove);
            PerformMove(board,bestmove,mlen);
            MoveToText(bestmove,buf);
        }
        else exit(1); /* No legal moves available, so I have lost */

        /* Write the move to the pipe */
        //printf("%s", buf);
        write(STDOUT_FILENO,buf,strlen(buf));
        fflush(stdout);
    }

    return 0;
}
void IterativeDeepener::Search(const IDSParams& ids_params, Move* best_move,
                               int* best_move_score,
                               SearchStats* id_search_stats) {
  std::ostream& out = ids_params.thinking_output ? std::cout : nullstream;
  ClearState();

  StopWatch stop_watch;
  stop_watch.Start();

  movegen_->GenerateMoves(&root_move_array_);
  out << "# Number of moves at root: " << root_move_array_.size() << std::endl;

  // No moves to make. Just return by setting invalid move. This can happen if
  // Search() is called after game ends.
  if (root_move_array_.size() == 0) {
    *best_move = Move();
    *best_move_score = INF;
    return;
  }

  // Caller provided move ordering and pruning takes priority over move orderer.
  if (ids_params.pruned_ordered_moves.size()) {
    root_move_array_ = ids_params.pruned_ordered_moves;
  } else if (extensions_->move_orderer) {
    extensions_->move_orderer->Order(&root_move_array_);
  }
  assert(root_move_array_.size() > 0);
  out << "# Number of root moves being searched: " << root_move_array_.size()
      << std::endl;

  // If there is only one move to be made, make it without hesitation as search
  // won't yield anything new.
  if (root_move_array_.size() == 1) {
    *best_move = root_move_array_.get(0);
    *best_move_score = INF;
    return;
  }

  // Iterative deepening starts here.
  for (unsigned depth = 1; depth <= ids_params.search_depth; ++depth) {
    // Do not use transposition table moves at the root if ordered/pruned
    // movelist is passed by the caller as we expect input ordering to be of
    // highest quality. Also, this avoids transposition table moves that are
    // not in the list to be brought to the front.
    if (ids_params.pruned_ordered_moves.size() == 0) {
      TranspositionTableEntry* tentry = transpos_->Get(board_->ZobristKey());
      if (tentry && tentry->best_move.is_valid()) {
        root_move_array_.PushToFront(tentry->best_move);
      }
    } else if (!iteration_stats_.empty()) {
      root_move_array_.PushToFront(iteration_stats_.back().best_move);
    }

    // This will return immediately when timer expires but updates the
    // iteration_stats_ nevertheless. Results from the last iteration are
    // acceptable only if search of at least the first root move subtree was
    // completed. Due to the move-ordering done above, the first root move that
    // is searched is guaranteed to be the best known move before beginning of
    // this iteration. So, if a different best move is found before timer
    // expiry, it is at least better than the previously known best move
    // (though it might not be the overall best move at this depth because all
    // the root moves might not be covered).
    FindBestMove(depth);

    double elapsed_time = stop_watch.ElapsedTime();

    const IterationStat& last_istat = iteration_stats_.back();

    // If FindMove could not complete at least the first root move subtree
    // completely, don't report stats or update best_move as the results are
    // likely to be incorrect.
    if (timer_->Lapsed() && last_istat.root_moves_covered == 0) {
      break;
    }

    // Update best_move and stats.
    *best_move = last_istat.best_move;
    *best_move_score = last_istat.score;
    id_search_stats->nodes_searched += last_istat.search_stats.nodes_searched;
    id_search_stats->nodes_researched +=
        last_istat.search_stats.nodes_researched;
    id_search_stats->nodes_evaluated += last_istat.search_stats.nodes_evaluated;
    id_search_stats->search_depth = last_istat.depth;

    // XBoard style thinking output.
    if (ids_params.thinking_output) {
      char output[256];
      snprintf(output, 256, "%2d\t%5d\t%5d\t%10d\t%s", depth, last_istat.score,
               int(elapsed_time), id_search_stats->nodes_evaluated,
               PV(*best_move).c_str());
      std::cout << output << std::endl;
    }

    // Don't go any deeper if a win is confirmed or timer has lapsed.
    if (last_istat.score == WIN || timer_->Lapsed()) {
      break;
    }
  }
  stop_watch.Stop();
  out << "# Time taken for ID search: " << stop_watch.ElapsedTime() << " centis"
      << std::endl;
}
Beispiel #8
0
static char *
ExtFIBSBoard( extcmd *pec ) {

  char szName[ MAX_NAME_LEN ], szOpp[ MAX_NAME_LEN ];
  int nMatchTo, anScore[ 2 ],
    anDice[ 2 ], nCube, fCubeOwner, fDoubled, fCrawford, fJacoby,
    anMove[ 8 ], fTurn;
  TanBoard anBoard, anBoardOrig;
  float arDouble[ NUM_CUBEFUL_OUTPUTS ],
    aarOutput[ 2 ][ NUM_ROLLOUT_OUTPUTS ],
    aarStdDev[ 2 ][ NUM_ROLLOUT_OUTPUTS ];
  rolloutstat aarsStatistics[ 2 ][ 2 ];
  cubeinfo ci;
  int nScore, nScoreOpponent;
  char *szResponse;
 
  if( ParseFIBSBoard( pec->szFIBSBoard, anBoard, szName, szOpp, &nMatchTo,
                      &nScore, &nScoreOpponent, anDice, &nCube,
                      &fCubeOwner, &fDoubled, &fCrawford ) ) {
    outputl( _("Warning: badly formed board from external controller.") );
    szResponse = 
      g_strdup_printf( "Error: badly formed board ('%s')\n", pec->szFIBSBoard );
  }
  else {
    
    anScore[ 0 ] = nScoreOpponent;
    anScore[ 1 ] = nScore;

	/* If the session isn't using Crawford rule, set crawford flag to false */
	fCrawford = pec->fCrawfordRule ? fCrawford : FALSE;
	/* Set the Jacoby flag appropriately from the external interface settings */
	fJacoby   = pec->fJacobyRule;

	/* printf ("Crawford Setting: %d\n", fCrawford); */
	/* printf ("Jacoby Setting: %d\n", fJacoby); */
    
    fTurn = 1;
    SetCubeInfo ( &ci, nCube, fCubeOwner, fTurn, nMatchTo, anScore,
                  fCrawford, fJacoby, nBeavers, bgvDefault ); 
    
#if 0 
    {
      char *asz[ 7 ] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
      char szBoard[ 10000 ];
      outputl( DrawBoard( szBoard, anBoard, 1, asz,
                          "no matchid", 15 ) );

      printf( "score %d-%d to %d ", anScore[ 0 ], anScore[ 1 ],
              nMatchTo );
      printf( "dice %d %d ", anDice[ 0 ], anDice[ 1 ] );
      printf( "cubeowner %d cube %d turn %d crawford %d doubled %d\n",
              fCubeOwner, nCube, fTurn, fCrawford, fDoubled );
    }
#endif

    memcpy( anBoardOrig, anBoard, sizeof( anBoard ) );

    if ( fDoubled  ) {

      /* take decision */
      if( GeneralCubeDecision( aarOutput, aarStdDev,
                               aarsStatistics, (ConstTanBoard)anBoard, &ci,
                               GetEvalCube(), NULL, NULL ) < 0 )
        return NULL;
	  
      switch( FindCubeDecision( arDouble,  aarOutput, &ci )) {
      case DOUBLE_PASS:
      case TOOGOOD_PASS:
      case REDOUBLE_PASS:
      case TOOGOODRE_PASS:
        szResponse = g_strdup( "drop\n" );
        break;

      case NODOUBLE_BEAVER:
      case DOUBLE_BEAVER:
      case NO_REDOUBLE_BEAVER:
        szResponse = g_strdup( "beaver\n" );
        break;
		    
      default:
        szResponse = g_strdup( "take\n" );
      }

#if 0
      /* this code is broken as the sign of fDoubled 
         indicates who doubled */
    } else if ( fDoubled < 0 ) {
              
      /* if opp wants to resign (extension to FIBS board) */

      float arOutput[ NUM_ROLLOUT_OUTPUTS ];
      float rEqBefore, rEqAfter;
      const float epsilon = 1.0e-6;

      getResignation( arOutput, anBoard, &ci, &esEvalCube );

      getResignEquities ( arOutput, &ci, -fDoubled,
                          &rEqBefore, &rEqAfter );

      /* if opponent gives up equity by resigning */
      if( ( rEqAfter - epsilon ) < rEqBefore )
        szResponse = g_strdup( "accept\n" );
      else
        szResponse = g_strdup( "reject\n" );

#endif /* broken */
    } else if( anDice[ 0 ] ) {
      /* move */
      char szMove[ 64 ];
      if( FindBestMove( anMove, anDice[ 0 ], anDice[ 1 ],
                        anBoard, &ci, &GetEvalChequer()->ec,
                        *GetEvalMoveFilter() ) < 0 )
        return NULL;

      FormatMovePlain( szMove, anBoardOrig, anMove );
      szResponse = g_strconcat( szMove, "\n", NULL );
    } else {
      /* double decision */
      if( GeneralCubeDecision( aarOutput, aarStdDev,
                               aarsStatistics, (ConstTanBoard)anBoard, &ci,
                               GetEvalCube(), NULL, NULL ) < 0 )
        return NULL;
		
      switch( FindCubeDecision( arDouble,  aarOutput, &ci )) {
      case DOUBLE_TAKE:
      case DOUBLE_PASS:
      case DOUBLE_BEAVER:
      case REDOUBLE_TAKE:
      case REDOUBLE_PASS:
        szResponse = g_strdup( "double\n" );
        break;
		    
      default:
        szResponse = g_strdup( "roll\n" );
      }
    }
	    
  }

  return szResponse;

}