Exemple #1
0
Move AIPlayer::alpha_beta(GameBoard* game, int lookahead, int alpha, int beta, int player)
{
    vector<Move> all_moves = get_all_moves(game, player);
    //cout << "Moves are: " << endl;
        //cout << m.x +1  << ", " << m.y + 1 << " Score: " << m.score << endl;
    if (all_moves.empty())
        return Move(-1, -1, maximizing_player(player) * 35);
    if (lookahead == 0) {
        //return heuristic value of previous player
        if (!is_maximizing(player)) {
            Move temp = *(std::max_element(all_moves.begin(), all_moves.end(), [](Move m1, Move m2){return m1.score < m2.score;}));
            //cout << "return: "<< temp.x +1  << ", " << temp.y + 1 << " Score: " << temp.score << endl;
            return temp;
        }
            
        else {
            Move temp =  *(min_element(all_moves.begin(), all_moves.end(), [](Move m1, Move m2){return m1.score < m2.score;}));
            //cout << "return: "<< temp.x +1  << ", " << temp.y + 1 << " Score: " << temp.score << endl;
            return temp;
        }
    }
    Move return_move;
    if (is_maximizing(player)) {
        for (auto m : all_moves) {
            GameBoard temp_board(game);
            temp_board.make_move(m.x, m.y, player);
            Move temp_move = alpha_beta(&temp_board, lookahead - 1, alpha, beta, other_player(player));
            
            if (temp_move.score > alpha) {
                return_move = m;
                alpha = temp_move.score;
            }
            if (alpha >= beta) {
                break;
            }
        }
        return return_move;
    } else {
        for (auto m : all_moves) {
            GameBoard temp_board(game);
            temp_board.make_move(m.x, m.y, player);
            Move temp_move = alpha_beta(&temp_board, lookahead - 1, alpha, beta, other_player(player));
            
            if (temp_move.score < beta) {
                beta = temp_move.score;
                return_move = m;
            }
            if (alpha >= beta) {
                break;
            }
        }
        return return_move;
    }

}
int search_a_goodmove(int color, MoveType * bestMove,int alpha,int beta,int dep) {		//alpha-beta根节点函数
	int i,best=-INF;
	int bestmove=-1;
	memset(history,0,sizeof(history));
	int stacklen=createmove(color,dep);
	if(stacklen==0){
		return 0;
	}
	for(i=0;i<stacklen;i++){
	movestack[dep][i].score=history[movestack[dep][i].x[0]][movestack[dep][i].y[0]][movestack[dep][i].x[1]][movestack[dep][i].y[1]][movestack[dep][i].x[2]][movestack[dep][i].y[2]];
	}
	qsort(movestack[dep],stacklen,sizeof(movestack[dep][0]),cmp);
	for(i=0;i<stacklen;i++){
		movechess(movestack[dep][i]);
		best=-alpha_beta(color^3,-beta,-alpha,dep+1);
		unmovechess(movestack[dep][i]);
		if(best>alpha){
			alpha=best;
			*bestMove=movestack[dep][i];
			bestmove=i;
		}
		if(alpha>=beta){
			bestmove=i;
			break;
		}
	}
	if(bestmove!=-1){
	history[movestack[dep][bestmove].x[0]][movestack[dep][bestmove].y[0]][movestack[dep][bestmove].x[1]][movestack[dep][bestmove].y[1]][movestack[dep][bestmove].x[2]][movestack[dep][bestmove].y[2]]+=2<<(MAX_DEEP-dep);
	}
	return 1;
}
int alpha_beta(int color,int alpha,int beta,int depth){
	int i,best=-INF;
	int bestmove=-1;
	if(depth==MAX_DEEP){  
		return evaluate(color); 
	} 
	int stacklen=createmove(color,depth);
	if(stacklen==0){
		return evaluate(color);
	}
	for(i=0;i<stacklen;i++){
		movestack[depth][i].score=history[movestack[depth][i].x[0]][movestack[depth][i].y[0]][movestack[depth][i].x[1]][movestack[depth][i].y[1]][movestack[depth][i].x[2]][movestack[depth][i].y[2]];
	}
	qsort(movestack[depth],stacklen,sizeof(movestack[depth][0]),cmp);
	for(i=0;i<stacklen;i++){
		movechess(movestack[depth][i]);
		best=-alpha_beta(color^3,-beta,-alpha,depth+1);
		unmovechess(movestack[depth][i]);
		if(best>alpha){
			alpha=best;
			bestmove=i;
		}
		if(alpha>=beta){
			bestmove=i;
			break;
		}
	}
	if(bestmove!=-1){
		history[movestack[depth][bestmove].x[0]][movestack[depth][bestmove].y[0]][movestack[depth][bestmove].x[1]][movestack[depth][bestmove].y[1]][movestack[depth][bestmove].x[2]][movestack[depth][bestmove].y[2]]+=2<<(MAX_DEEP-depth);
	}
	return alpha;
}
Exemple #4
0
ChessAI::ChessAI(Chess* chess, int level)
	:m_level(level), m_fromPos(-1), m_toPos(-1)
{
	m_board = new Chess(*chess);
	//Chess* board = new Chess(*chess);
	//m_boards.push_back(board);
	int alpha = -10000;
	int beta = 10000;
	c = 0;
	
	/*
    for(int i = 0; i < m_level; i++)
	{
		Chess* board = new Chess();
		m_boards.push_back(board);
	}*/
	
    //DWORD  dw = GetTickCount();//timeGetTime(); time(NULL);
	t1 = 0;
	t2 = 0;
	t3 = 0;
	t4 = 0;
	clock_t cc = clock();

	alpha_beta(0, alpha, beta);
	
	CCLog("calulator times: %d", c);
	cc = clock() - cc;
	CCLog("all time: %f", (float)cc/1000);
	if(t1!=0) CCLog("t1: %f", (float)t1/1000);
	if(t2!=0) CCLog("t2: %f", (float)t2/1000);
	if(t3!=0) CCLog("t3: %f", (float)t3/1000);
	if(t4!=0) CCLog("t4: %f", (float)t4/1000);
}
Exemple #5
0
/* ---------------------------------------------------------------------------
	void iterative_deepening(CHESS_STATE *cs, int max_depth)
   
   Purpose: An iterative deepening function
            The idea is to repeat search at each depth from 1 to n.
            At start of each search > 1, the best result from the previous
            search is performed first. This improves the performance of
            alpha beta.
   Returns: 3 structures are returned by reference as output parameters:
   			1. ITERATIVE_DEEPENING_INFO structure
   			2. Legal Move Count
   			3. Legal Moves 
   --------------------------------------------------------------------------- */
void iterative_deepening(CHESS_STATE *cs,
				 int time_limit,
				 int *id_count,
				 ITERATIVE_DEEPENING_INFO *id_info,
				 int debug_mode)
{
	int depth;
	depth=0;
	
	if (debug_mode==1)
	{
		printf("\nDepth\tValue\tCount\tPlay\tTime\tRate\n");
		printf("-----\t-----\t-----\t----\t----\t----\n");
	}
	
	while (depth < MAX_ITERATIVE_DEEPENING_DEPTH)
	{
		depth++;
		id_info[depth].depth = depth;
		
		// start stopwatch
		clock_t start, end;
		start = clock();
		id_info[depth].value = alpha_beta(cs, 0, depth, -999999, 999999, id_info);
		end = clock();
		
		double elapsed;
		elapsed = ((double)(end-start)) / CLOCKS_PER_SEC;
		int rate;
		rate = (elapsed==0) ? 0 : (float)id_info[depth].moves_evaluated / elapsed;
		
		// display best values
		if (debug_mode==1)
			printf("%d\t%d\t%d\t%s\t%.2f\t%d\n",id_info[depth].depth,id_info[depth].value, id_info[depth].moves_evaluated, id_info[depth].best_move, elapsed, rate);
	
		// check time limit elapsed
		if (time_limit==0 || id_info[1].legal_move_count * elapsed > (double)time_limit)
		{
			*id_count = depth;
			break;
		}
	}
	
	// print legal moves
	if (debug_mode==1)
	{
		printf("\nLegal move count: %d\nMoves: ", id_info[1].legal_move_count);
		int i;
		for (i=0; i<id_info[1].legal_move_count; i++)
			printf("%s ", id_info[1].legal_moves[i]);
	
		printf("\n\n");
	}
}
Exemple #6
0
/**
 * The search is controlled by the think() function.  This function initializes
 * all variables needed for search, sets up thread pools, and then performs a
 * search starting at the root node.  A root node search is fundamentally
 * different from searches at other depths because we know for sure that we
 * should not perform a qsearch or a null-move search.
 */
void think(app_t *app)
{
	int i, val;
	node_t root;

	assert(app);
	assert(app->game.board);

	init_node(&root);
	root.flags |= NODE_ROOT;

	/* reset our node count board->ply */
	app->game.board->ply = 0;
	app->search.nodes = 0;
	app->hash.generations++;

	/* clear the stop bit */
	app->search.flags &= ~SEARCH_STOPPED;

	/* clear search heuristics */
	memset(app->search.pv, 0, SEARCH_MAXDEPTH * sizeof(move_t));
	memset(app->game.board->killers, 0, 2 * SEARCH_MAXDEPTH * sizeof(int));
	memset(app->game.board->history, 0, 2 * 6 * 64 * sizeof(int));

	/* set the start time */
	get_current_tick(&app->search.start);

	/* iterative deepening */
	for (i = 1; i < app->search.depth; i++) {
		root.depth = i;

		val = alpha_beta(app, &root, -MATE, MATE, i);

		if (app->mode == IUCI) {
			print_uci_info(app, i, val);
		}
	}
}
Exemple #7
0
/**
 *  Use brute force to evaluate every possible move, and find the best one.
 *  Once the best move is found, play it.
 */
void AIPlayer::play()
{
    int x = 0,
        y = 0,
        cur_max = 0,
        best_x = 0,
        best_y = 0,
        temp = 0,
        rand_n = 0;
    if (diff_ == 1){
        Move best_move = alpha_beta(game_, lookahead_, std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), player_);
        best_x = best_move.x;
        best_y = best_move.y;
    }
    else{    
        for (x = 0; x < game_->get_size(); x++) {
            for (y = 0; y < game_->get_size(); y++) {
                temp = rate_move(x, y, game_, player_);
                // if this move is better, choose it
                if (temp > cur_max) {
                    cur_max = temp;
                    best_x = x;
                    best_y = y;
                }
                // otherwise flip a coin to make a decision
                else if (temp == cur_max) {
                    rand_n = rand() % 2;
                    if (rand_n  == 1) {
                        best_x = x;
                        best_y = y;
                    }
                }
            }
        }
    }
    //cout << "Making Move: " << best_x + 1  << ", " << best_y + 1 << endl;
    game_->make_move(best_x, best_y, player_);  
}
Exemple #8
0
int alpha_beta(app_t *app, cnodeptr_t parent, int alpha, int beta, int depth)
{
	int palpha = alpha;
	int i, score = -MATE, highest = -MATE;
	node_t node;
	move_t cutoff = 0;
	piece_t p;

	init_node(&node);

	assert(app);

	app->search.nodes++;
	node.depth = depth;

	/* max depth */
	if (app->game.board->ply > (SEARCH_MAXDEPTH - 1)) {
		/* return evaluate(app->board); */
		return quiescent(app, parent, alpha, beta);
	}

	/* recursive base */
	if (depth == 0) {
		return evaluate(app->game.board);
	}

	/* draws */
	if (repetitions(app) || (app->game.board->half >= 100)) {
		return 0;
	}

	/* if we are checked, set the nodes checked flag */
	if (check(app->game.board, app->game.board->side)) {
		node.flags |= NODE_CHECK;
		/* extend our search by 1 depth if we are in check */
		/* NOTES: we may want to NOT extend our search here if the parent
		   is in check, because the means we already extended once */
		depth++;
	}

	/* TODO:
	     - NULL moves
	     - Late-move reduction
	     - Tactical extensions (pins & forks -> depth++)
	 */

	/* probe our table */
	if (probe_hash(&app->hash, app->game.board, &cutoff, &score, depth, alpha, beta) == TRUE) {
		app->hash.cut++;
		return score;
	}

	/* generate moves */
	generate_moves(app->game.board, &node.ml, &node.ml);

	/* reset score */
	score = -MATE;

	/* try to match our hash hit move */
	if (cutoff != 0) {
		for (i = 0; i < node.ml.count; i++) {
			if (node.ml.moves[i] == cutoff) {
				node.ml.scores[i] = 20000;
				break;
			}
		}
	}

	/* search negamax */
	for (i = 0; i < node.ml.count; i++) {
		/* get the next move ordered */
		next_move(i, &node.ml);

		if (!(do_move(app->game.board, &app->game.undo, node.ml.moves[i])))
			continue;

		score = -alpha_beta(app, &node, -beta, -alpha, depth - 1);

		node.made++;
		undo_move(app->game.board, &app->game.undo);

		/* score whatever is best so far */
		if (score > highest) {
			node.best = node.ml.moves[i];
			highest = score;

			/* update alpha */
			if (score > alpha) {
				if (score >= beta) {

					/* non-captures causing beta cutoffs (killers) */
					if (!is_capture(node.ml.moves[i])) {
						app->game.board->killers[1][app->game.board->ply] =
							app->game.board->killers[0][app->game.board->ply];
						app->game.board->killers[0][app->game.board->ply] = node.ml.moves[i];
					}

					/* store this beta in our transposition table */
					store_hash(&app->hash, app->game.board, node.best, beta, HASH_BETA, depth);

					return beta;
				}

				/* update alpha */
				alpha = score;

				/* update our history */
				if (!is_capture(node.best)) {
					p = app->game.board->pos.squares[move_from(node.best)];
					app->game.board->history[piece_color(p)][piece_type(p)][move_to(node.best)] += depth;
				}
			}
		}
	}

	/* check for checkmate or stalemate */
	if (!node.made) {
		if (node.flags & NODE_CHECK) {
			return -MATE + app->game.board->ply;
		} else {
			return 0;
		}
	}

	if (alpha != palpha) {
		/* store this as an exact, since we beat alpha */
		store_hash(&app->hash, app->game.board, node.best, highest, HASH_EXACT, depth);
	} else {
		/* store the current alpha */
		store_hash(&app->hash, app->game.board, node.best, alpha, HASH_ALPHA, depth);
	}

	return alpha;
}
Exemple #9
0
/* Find the confidence score and dump the confidence output into the file */
static void
confidence_utt(char *uttid, FILE * _confmatchsegfp)
{
    seg_hyp_line_t s_hypline;
    char line[16384];
    char dagfile[16384];
    const char *fmt;
    const char *latdir;
    const char *latext;
    E_INFO("Processing %s\n", uttid);
    if (fgets(line, sizeof(line), _confmatchsegfp) == NULL)
        E_FATAL("Fail to read a line in the matchsegfp for uttid %s\n",
                uttid);

    /* Read the hypseg */
    if (read_s3hypseg_line(line, &s_hypline, lmset->cur_lm, dict) ==
        HYPSEG_FAILURE)
        E_FATAL("Fail to parse matchseg in utt ID %s\n", uttid);

    E_INFO("Matchseg file name %s\n", s_hypline.seq);
    if (strcmp(uttid, s_hypline.seq))
        E_FATAL("Uttids in control file and matchseg file mismatches\n");

    /* Read the lattice */
    latdir = cmd_ln_str_r(config, "-inlatdir");
    latext = cmd_ln_str_r(config, "-latext");

    if (latdir)
        sprintf(dagfile, "%s/%s.%s", latdir, uttid, latext);
    else
        sprintf(dagfile, "%s.%s", uttid, latext);

    E_INFO("Reading DAG file: %s\n", dagfile);

    if (confidence_word_posterior(dagfile,
                                  &s_hypline,
                                  uttid,
                                  lmset->cur_lm,
                                  dict, fpen) == CONFIDENCE_FAILURE) {
        E_INFO("Fail to compute word posterior probability \n");
    }


#if 0
    if (ca_dag_load_lattice
        (dagfile, &word_lattice, lmset->cur_lm, dict,
         fpen) == CONFIDENCE_FAILURE)
        E_FATAL("Unable to load dag %s for uttid %s\n", dagfile, uttid);

    /* Compute Alpha-beta */
    if (alpha_beta(&word_lattice, lmset->cur_lm, dict) ==
        CONFIDENCE_FAILURE)
        E_FATAL("Unable to compute alpha beta score for uttid %s\n",
                uttid);

    /* Compute Posterior WORD probability */
    if (pwp(&s_hypline, &word_lattice) == CONFIDENCE_FAILURE)
        E_FATAL("Unable to compute pwp for uttid %s\n", uttid);
#endif

    /* Compute LM type */
    if (compute_lmtype(&s_hypline, lmset->cur_lm, dict) ==
        CONFIDENCE_FAILURE)
        E_FATAL("Fail to compute lm type\n");

    /* combined LM type */
    if (compute_combined_lmtype(&s_hypline) == CONFIDENCE_FAILURE)
        E_FATAL("Fail to compute lm type\n");

    /* Dump pwp line */
    fmt = cmd_ln_str_r(config, "-confoutputfmt");
    if (!strcmp(fmt, "scores")) {
        dump_line(stdout, &s_hypline, dict);
        dump_line(outconfmatchsegfp, &s_hypline, dict);
    }
    else {
        glist_t hyp;
        srch_hyp_t *s;
        conf_srch_hyp_t *h;

        hyp = NULL;
        for (h = (conf_srch_hyp_t *) s_hypline.wordlist; h; h = h->next) {
            s = &(h->sh);
            hyp = glist_add_ptr(hyp, (void *) s);
        }
        matchseg_write(stdout, hyp, uttid, NULL,
                       lmset->cur_lm, dict, 0, NULL, 0);
        matchseg_write(outconfmatchsegfp, hyp, uttid, NULL,
                       lmset->cur_lm, dict, 0, NULL, 0);
    }

#if 0
    /* Delete lattice, delete hypsegline */
    if (ca_dag_free_lattice(&word_lattice) == CONFIDENCE_FAILURE) {
        E_WARN("Fail to free lattice.\n");
        return CONFIDENCE_FAILURE;
    }
#endif

    if (free_seg_hyp_line(&s_hypline) != HYPSEG_SUCCESS)
        E_FATAL("Fail to free the segment hypothesis line structure. \n");
}
Exemple #10
0
Move AIPlayer_fork::alpha_beta(GameBoard* game, int lookahead, int alpha, int beta, int player)
{
    concurrent_vector<Move> all_moves = concurrent_get_all_moves(game, player);
    //cout << "Moves are: " << endl;
    //cout << m.x +1  << ", " << m.y + 1 << " Score: " << m.score << endl;
    if (all_moves.empty())
        return Move(-1, -1, maximizing_player(player) * 35);
    if (lookahead == 0) {
        //return heuristic value of previous player
        if (!is_maximizing(player)) {
            Move temp = *(std::max_element(all_moves.begin(), all_moves.end(), [](Move m1, Move m2) {
                return m1.score < m2.score;
            }));
            //cout << "return: "<< temp.x +1  << ", " << temp.y + 1 << " Score: " << temp.score << endl;
            return temp;
        }

        else {
            Move temp =  *(std::min_element(all_moves.begin(), all_moves.end(), [](Move m1, Move m2) {
                return m1.score < m2.score;
            }));
            //cout << "return: "<< temp.x +1  << ", " << temp.y + 1 << " Score: " << temp.score << endl;
            return temp;
        }
    }
    Move return_move;
    if (is_maximizing(player)) {

        task_group g;
        for (unsigned int i = 0; i < all_moves.size(); i++) {
            g.run([=, &all_moves, &return_move, &alpha, & beta] {
                GameBoard temp_board(game);
                temp_board.make_move(all_moves[i].x, all_moves[i].y, player);
                Move temp_move;
                temp_move = alpha_beta(&temp_board, lookahead - 1, alpha, beta, other_player(player));
                if (temp_move.score > alpha) {
                    return_move = all_moves[i];
                    alpha = temp_move.score;
                }
                if (alpha >= beta) {
                    //g.cancel();
                }
            });
        }
        g.wait();
        return return_move;
    } else {
        task_group g;
        for (unsigned int i = 0; i < all_moves.size(); i++) {
            g.run([=, &all_moves, &return_move, &alpha, &beta] {
                GameBoard temp_board(game);
                temp_board.make_move(all_moves[i].x, all_moves[i].y, player);
                Move temp_move;
                temp_move = alpha_beta(&temp_board, lookahead - 1, alpha, beta, other_player(player));

                if (temp_move.score < beta) {
                    beta = temp_move.score;
                    return_move = all_moves[i];
                }
                if (alpha >= beta) {
                    //g.cancel();
                }
            });
        }
        g.wait();
        return return_move;
    }
}
/**
 * Alph-Beta Pruning
 *@param depth how deep to search the tree
 *@param alpha the minimax value for alpha
 *@param beta the minimax value for beta
 *@return x y coordinates for move
 */
int AlphaBetaAI::alpha_beta(AlphaBetaNode* node, int depth, int maxPlayer, int myScore, int otherScore, int pointsRemaining)
{
    node->myScore = myScore;
    node->otherScore = otherScore;

    node->generateBoard(heapBoard);

    if (depth <= 0 || pointsRemaining == 0) // or is a terminal node?
    {
        //printf("leaf node!\n");
        int eval = evaluate(heapBoard, myScore, otherScore, maxPlayer);
        return eval;
    }

    vector<int> legalMoves(node->getMoves());
    //std::vector<int> moves;
    //generateLegalMoves(_board, legalMoves);  //vector of all possible legal moves to make

    while (legalMoves.size()) //for each child node of max and min player
    {
        //printf("legal moves: %d\n", legalMoves.size());
        int myPoints = myScore;
        int otherPoints = otherScore;
        int pointsLeft = pointsRemaining;

        bool scored = makeNextMove(heapBoard, legalMoves[legalMoves.size()-1], maxPlayer, myPoints, otherPoints, pointsLeft);
        AlphaBetaNode* kid = find_root(heapBoard, node, pointsLeft);
        node->hasKid(kid);
        kid->hasParent(node);

        //printf("getting eval %d\n", kid);
        float eval = alpha_beta(kid, 0, scored?maxPlayer:!maxPlayer, myPoints, otherPoints, pointsLeft);
        /*if (scored) {
            eval += eval+1;
        }*/
        //printf("got! eval %d\n", kid);

        if (maxPlayer)
        {
            if (eval > node->alpha) {
                node->alpha = eval;
            }
            //printf("%d  %d\n", node->alpha, node->beta);
            if (node->beta <= node->alpha) {
                //printf("max-cut\n");
                unmakeLastMove(heapBoard, legalMoves[legalMoves.size()-1]);
                break; //beta cut-off
            }
        }
        else
        {
            if (eval < node->beta) {
                node->beta = eval;
            }
            //printf("\t\t\t%d  %d\n", node->alpha, node->beta);
            if (node->beta <= node->alpha) {
                //printf("min-cut\n");
                unmakeLastMove(heapBoard, legalMoves[legalMoves.size()-1]);
                break; //alpha cut-off
            }
        }
        //while (moves.size()) {
            unmakeLastMove(heapBoard, legalMoves[legalMoves.size()-1]);
        //    moves.pop_back();
        //}
        legalMoves.pop_back();
        break;
    }//end while loop of all legalMoves

    //printf("about to return thingy\n");
    if (maxPlayer) {
        return node->alpha;
    }
    return node->beta;
}
Exemple #12
0
static int alpha_beta(int field[][MAX_FIELD_ROWS], int x, int y, int depth,
		int alpha, int beta, int maximizing_player)
{
	int done = FALSE;

	int their_longest = get_longest_line(x, y, game.settings.their_botid, field);
	int your_longest = get_longest_line(x, y, game.settings.your_botid, field);

	int last_player;

	int chldx;
	int chldy;

	int v;

	if (depth <= 0 || their_longest >= WIN_LENGTH ||
			your_longest >= WIN_LENGTH) {
		if (maximizing_player)
			last_player = 2;
		else
			last_player = 1;

		if (their_longest >= WIN_LENGTH)
			return evaluate(game.settings.your_botid,
					game.settings.their_botid,
					x, y, last_player, field)
				+ (ALPHABETA_LEVEL - depth);
		else if (your_longest >= WIN_LENGTH)
			return evaluate(game.settings.your_botid,
					game.settings.your_botid,
					x, y, last_player, field)
				- (ALPHABETA_LEVEL - depth);
		else
			return evaluate(game.settings.your_botid, 0,
					x, y, last_player, field)
				- (ALPHABETA_LEVEL - depth);
	} else if (board_full(game.round + ALPHABETA_LEVEL - depth))
		return 0;

	if (maximizing_player) {
		v = INT_MIN;

		for (chldx = 0; chldx < game.settings.field_columns; ++chldx) {
			for (chldy = 0; chldy < game.settings.field_rows; ++chldy) {
				if (can_be_placed(chldx, chldy, field)) {
					field[chldx][chldy] = game.settings.your_botid;

					v = max(v, alpha_beta(field, chldx, chldy, depth - 1, alpha, beta, FALSE));
					alpha = max(alpha, v);

					field[chldx][chldy] = 0;

					if (beta <= alpha) {
						done = TRUE;
						break;
					}
				}
			}

			if (done)
				break;
		}

		return v;
	} else {
		v = INT_MAX;

		for (chldx = 0; chldx < game.settings.field_columns; ++chldx) {
			for (chldy = 0; chldy < game.settings.field_rows; ++chldy) {
				if (can_be_placed(chldx, chldy, field)) {
					field[chldx][chldy] = game.settings.their_botid;

					v = min(v, alpha_beta(field, chldx, chldy, depth - 1, alpha, beta, TRUE));
					beta = min(beta, v);

					field[chldx][chldy] = 0;

					if (beta <= alpha) {
						done = TRUE;
						break;
					}
				}
			}

			if (done)
				break;
		}

		return v;
	}
}
Exemple #13
0
int calc_best_column(void)
{
	struct Player me;
	struct Player them;

	int col_to_drop = game.settings.field_columns / 2;

	int ordering[MAX_FIELD_COLUMNS];
	int col;

	int i;
	int j;

	int maxAB = INT_MIN;
	int resAB;

	int x;
	int y;

	me.id = game.settings.your_botid;
	them.id = game.settings.their_botid;

	me.attacks = ATTACK_POINTS_DEFAULT;
	them.attacks = ATTACK_POINTS_DEFAULT;

	get_attack_point_counts(&me, &them, game.field);

	fprintf(stderr, "Your shared odd count: %d\n", me.attacks.shared_odd_count);
	fprintf(stderr, "Their shared odd count: %d\n", them.attacks.shared_odd_count);
	fprintf(stderr, "Your shared even count: %d\n", me.attacks.shared_even_count);
	fprintf(stderr, "Their shared even count: %d\n", them.attacks.shared_even_count);
	fprintf(stderr, "Your unshared odd count: %d\n", me.attacks.unshared_odd_count);
	fprintf(stderr, "Their unshared odd count: %d\n", them.attacks.unshared_odd_count);
	fprintf(stderr, "Your unshared even count: %d\n", me.attacks.unshared_even_count);
	fprintf(stderr, "Their unshared even count: %d\n", them.attacks.unshared_even_count);

	if (has_advantage(me, them, FALSE))
		fprintf(stderr, "Your advantage!\n");
	else if (has_advantage(them, me, FALSE))
		fprintf(stderr, "Their advantage...\n");

	i = game.settings.field_columns / 2;
	ordering[0] = i;

	for (j = 1; j < game.settings.field_columns; ++j) {
		if (j % 2 == 0)
			ordering[j] = i + j;
		else
			ordering[j] = i - j;
		i = ordering[j];
	}

	for (x = 0; x < game.settings.field_columns; ++x) {
		for (y = 0; y < game.settings.field_rows; ++y) {
			col = ordering[x];

			if (can_be_placed(col, y, game.field)) {
				game.field[col][y] = game.settings.your_botid;
				if (game.time_remaining > TIMEBANK_LOW && game.round > 11)
					resAB = alpha_beta(game.field, col, y,
							ALPHABETA_LEVEL, INT_MIN, INT_MAX, FALSE);
				else
					resAB = alpha_beta(game.field, col, y,
							ALPHABETA_LEVEL - 1, INT_MIN, INT_MAX, FALSE);
				game.field[col][y] = 0;

				fprintf(stderr, "(%d, %d): %d\n", col, y, resAB);

				if (resAB > maxAB) {
					maxAB = resAB;
					col_to_drop = col;
				}
			}
		}
	}

	return col_to_drop;
}
Exemple #14
0
/* --------------------------------------------------------------------------------------
	int alpha_beta(CHESS_STATE *node, int depth, int alpha, int beta)
    
    purpose: alpha-beta pruning evaluation of minimax algorithm
			 the algorithm always returns an absolute number
			 regardless of player's color.
			 + = good
			 - = bad

			beta represents previous player's best choice. Doesn't want it
			if alpha would worsen it.
   ---------------------------------------------------------------------------------------*/
int alpha_beta(CHESS_STATE *node, int current_depth, int fixed_depth_horizon, int alpha, int beta, ITERATIVE_DEEPENING_INFO *id_info)
{
	// leaf node test (include quiescence search)
	// note that we extend the current depth to go 1 PAST
	// the fixed depth horizon, to allow for check validation
	// at the leaf node. The quiescence search will automatically
	// cater for check validation
	if (current_depth>fixed_depth_horizon && !node->flg_is_noisy)
	{
		id_info[current_depth-1].moves_evaluated++;
		return node->board_value;
	}
	
	// otherwise, get opponents moves
	generate_moves(node);
	current_depth++;

	CHESS_STATE *p;
	CHESS_STATE *q;

	for (p = node->child_head; p != NULL; p = q) 
	{
		q = p->next;

		if (node->flg_is_white_move)
		{
			// maximiser
			if (alpha>=beta)
			{
				break;		// cutoff
			}
			int ab = alpha_beta(p, current_depth, fixed_depth_horizon, alpha, beta, id_info);
			if (ab > alpha)
			{
				alpha=ab;
				int d;
				
				if (current_depth==1)
					id_info[fixed_depth_horizon].best_move = get_move(p,0);
			}
		}
		else
		{
			// minimiser
			if (alpha>=beta)
			{
				break;		// cutoff
			}
			int ab = alpha_beta(p, current_depth, fixed_depth_horizon, alpha, beta, id_info);
			if (ab < beta)//
			{
				beta=ab;
				int d;
				if (current_depth==1)
					id_info[fixed_depth_horizon].best_move = get_move(p,0);
			}
		}
	}

	// legal moves (only required for depth 1)
	if (current_depth==1)
	{
		CHESS_STATE *child;

		int i=0;
		for (child=node->child_head; child!=NULL; child=child->next)
		{
			if (child->flg_is_illegal==0)
			{
				id_info[1].legal_moves[i] = get_move(child,0);
				i++;
			}
		}
		id_info[1].legal_move_count=i;
	}
	
	delete_nodes(node);
	
	if (node->flg_is_white_move)
	{
		// maximier
		return alpha;
	}
	else
	{
		return beta;
	}
}
Exemple #15
0
int ChessAI::alpha_beta(int depth, int& alpha, int& beta)
{
	if(depth == m_level)
	{
		c++;
		//m_boards[depth].nextTurn();
		//int value = m_boards[depth]->getBoardValue();
		m_board->nextTurn();
		int value = m_board->getBoardValue();
		m_board->nextTurn();
		return value;
	}
	vector<pair<int,int> > allMovable;
	allMovable.clear();
	m_board->getAllMovable(allMovable);
	//m_boards[depth]->getAllMovable(allMovable);
	//if(m_boards[depth]->isTurnA())
	if(m_board->isTurnA())
	{
		//CCLog("A depth:%d", depth);
		for(size_t i = 0; i < allMovable.size(); i++)
		{
			clock_t c3 = clock();
			//*m_boards[depth+1] = *m_boards[depth];
			c3 = clock() - c3;
			t3+=c3;
			clock_t c4 = clock();
			pair<int,int> move = allMovable[i];
			//m_boards[depth+1]->move(move.first, move.second);
			//m_boards[depth+1]->check();
			m_board->move(move.first, move.second);
			m_board->check();
			vector<int> deads = m_board->getDeadChessmen();
			c4 = clock() - c4;
			t4+=c4;
			//if(depth == 0 && m_boards[depth+1]->checkFinish())
			if(depth == 0 && m_board->checkFinish())
			{
				m_fromPos = move.first;
				m_toPos = move.second;
				return 3000;
			}
			//m_boards[depth+1]->nextTurn();
			m_board->nextTurn();
			int a = alpha;
			int b = beta;
			int value = alpha_beta(depth+1, alpha, beta);
			alpha = a;
			beta = b;
			m_board->move(move.second, move.first);
			m_board->revive(deads, false);
			m_board->nextTurn();
			//CCLog("A move:%d->%d, value:%d", move.first,move.second, value);
			if(value > alpha)
			{
				//CCLog("A biggerbiggerbigger alpha: %d", value);
				//CCLog("A better move:%d->%d", move.first,move.second);
				alpha = value;
				if(depth == 0)
				{
					m_fromPos = move.first;
					m_toPos = move.second;
				}
			}
			if(alpha >= beta || value == 3000)
			{
				//CCLog("alpha>=beta, %d > %d", alpha, beta);
				break;
			}
		}
		//CCLog("A return alpha: %d", alpha);
		return alpha;
	}
	else
	{
		//CCLog("B depth:%d", depth);
		for(size_t i = 0; i < allMovable.size(); i++)
		{
			clock_t c3 = clock();
			//*m_boards[depth+1] = *m_boards[depth];
			c3 = clock() - c3;
			t3+=c3;
			clock_t c4 = clock();
			pair<int,int> move = allMovable[i];
			//m_boards[depth+1]->move(move.first, move.second);
			//m_boards[depth+1]->check();
			m_board->move(move.first, move.second);
			m_board->check();
			vector<int> deads = m_board->getDeadChessmen();
			c4 = clock() - c4;
			t4+=c4;
			//if(depth == 0 && m_boards[depth+1]->checkFinish())
			if(depth == 0 && m_board->checkFinish())
			{
				m_fromPos = move.first;
				m_toPos = move.second;
				return -3000;
			}
			//m_boards[depth+1]->nextTurn();
			m_board->nextTurn();
			int a = alpha;
			int b = beta;
			int value = alpha_beta(depth+1, alpha, beta);
			alpha = a;
			beta = b;
			m_board->move(move.second, move.first);
			m_board->revive(deads, true);
			m_board->nextTurn();
			//CCLog("B move:%d->%d, value:%d", move.first,move.second, value);
			if(value < beta)
			{
				//CCLog("B smallersmallersmaller beta: %d", value);
				//CCLog("B better move:%d->%d", move.first,move.second);
				beta = value;
				if(depth == 0)
				{
					m_fromPos = move.first;
					m_toPos = move.second;
				}
			}
			if(alpha >= beta || value == -3000)
			{
				//CCLog("alpha>=beta, %d > %d", alpha, beta);
				break;
			}
		}
		//CCLog("B return beta: %d", beta);
		return beta;
	}
}
Exemple #16
0
/* Alpha Beta Pruning - Minimax Search Algorithm */
move_t alpha_beta(board_t *b, int32_t alpha, int32_t beta, uint32_t ply) {
    uint8_t i, type;
    move_list_t *list;
    move_t m, best;

    /* Query ECO tree */
    if(atoi(config->name) >= 50)
        if(query_eco(&m))	    
    	    return m;

    /* Query transposition table */
    type = query_transposition(b->hash, alpha, beta, ply, &m);
    switch(type) {
    case TYPE_ALPHA:
    	/* Chooses the best alpha between the old and the one from the table */
        alpha = MAX(alpha, m.eval);
    	/* If we have a Beta cutoff, returns */
    	if(alpha >= beta)
    	    return m;
    	break;
    case TYPE_BETA:
    	/* Chooses the best beta between the old and the one from the table */
    	beta = MIN(beta, m.eval);
    	/* If we have a Beta cutoff, returns */
    	if(alpha >= beta)
    	    return m;
    	break;
    case TYPE_EXACT:
    	/* If the table had an exact evaluation, returns it */
    	return m;
    case TYPE_INVALID:
    	/* If the transposition is invalid, just ignore and keep going*/
    	break;
    }

    /* If it's a leaf node, evaluate it properly */
    if(ply == 0) {
    	m.eval = heuristic(b, onmove);
    	return m;
    }

    /* Default type of the value to be inserted in the Transposition table */
    type = TYPE_ALPHA;

    /* Initialize the best possible move as blank */
    SET_BLANK_MOVE(best);

    /* Get the possible next moves */
    list = gen_move_list(b, FALSE);
    /* For each possible next move... */
    for(i = 0; i < list->size; i++) {
    	/* Let's see the board after that move... */
    	move(b, list->move[i]);

    	/* Did we reach any end game condition? */
    	switch(end(b)) {
    	case CHECK_MATE:
    	    m.eval = (onmove == b->onmove) ? -MAX_HEU : MAX_HEU;
    	    break;
    	case STALE_MATE:
    	case REPETITION:
    	case FIFTY_MOVES:
    	case TWO_KINGS:
    	    m.eval = -MAX_HEU;
    	    break;
    	case NO_MATE:
    	default:
    	    /* If not, keep searching down in the search tree */
    	    m = alpha_beta(b, -beta, -alpha, ply - 1);
    	    m.eval = -m.eval;
    	    break;
    	}

    	/* Restores the previous board (before the possible move) */
    	unmove(b);

    	/* Beta cutoff */
    	if(m.eval >= beta) {
    	    best = list->move[i];
    	    best.eval = m.eval;
    	    type = TYPE_BETA;
    	    break;
    	/* Alpha cutoff */
    	} else if(m.eval > alpha) {
    	    best = list->move[i];
    	    alpha = best.eval = m.eval;
    	    type = TYPE_EXACT;
    	/* Best possible move until now */
    	} else if(i == 0 || m.eval > best.eval) {
    	    best = list->move[i];
    	    best.eval = m.eval;
    	}

    	/* If our time's up, return immediately */
    	if(get_timeout()) {
    	    clear_move_list(list);
    	    return best; /*break;*/
    	}
    }

    /* Update the Transposition table */
    add_transposition(b->hash, type, ply, best);

    /* Clear temporary information and return */
    clear_move_list(list);
    return best;
}
Exemple #17
0
/* Search thread main function */
void *search_loop(void *arg) {
    uint8_t ply;
    move_t mv, mv_tmp;

    SET_BLANK_MOVE(mv);
    SET_BLANK_MOVE(mv_tmp);

    pthread_mutex_lock(&mutex);

    /* Initializations */
    precompute_moves();
    precompute_distances();
    init_zobrist_keys();
    init_history();
    init_transposition_table();
    config_alarm(config->max_seconds);
    max_depth = config->max_depth;

    /* Setup board */
    board = set_board("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
    if(board == NULL)
    	quit("Error: Could not setup new board!\n");

    /* ECO = encyclopedia of chess openings */

    if(atoi(config->name) >= 50)
        if(!load_eco(board))
            quit("Error: Could not load Encyclopedia of Chess Openings!\n");

    pthread_mutex_unlock(&mutex);
 
    /* Keep alive until the status changes to QUIT */
    while(status != QUIT) {
    	switch(status) {
    	case NOP:
    	    /* NOP: just wait for a change in status */
    	    pthread_mutex_lock(&mutex);
    	    while(status == NOP)
    	    	pthread_cond_wait(&cond, &mutex);
    	    pthread_mutex_unlock(&mutex);
    	    break;
    	case FORCE:
    	    /* FORCE: wait for a change in status but don't start searches */
    	    pthread_mutex_lock(&mutex);
    	    while(status == FORCE)
    	    	pthread_cond_wait(&cond, &mutex);
    	    pthread_mutex_unlock(&mutex);
    	    break;
    	case SEARCH:
    	    /* Iterative Deepening Search */
    	    /* Save the on-move color */
    	    onmove = board->onmove;
    	    /* Sets as blank the move to be played*/
    	    SET_BLANK_MOVE(mv);
    	    /* Starts counting the time */
    	    start_alarm();
    	    /* For each depth, search with alpha-beta minimax */
    	    for(ply = 2; ply <= max_depth; ply += 2) {
    	    	mv_tmp = alpha_beta(board, -MAX_HEU, MAX_HEU, ply);
    	    	/* Did we run out of time? If so, stops deepening iterations */
    	    	if(get_timeout())
    	    	    break;
    	    	mv = mv_tmp;
    	    }
    	    /* Stops counting the time, if it hasn't already reached limit */
    	    stop_alarm();
    	    /* If the move is still blank, use the partial move found */
    	    if(IS_BLANK_MOVE(mv))
    	    	mv = mv_tmp;
    	    /* Perform the move found in the search */
    	    move(board, mv);
    	    /* Returns to the NOP status */
    	    set_status(NOP);
    	    break;
    	case PONDER:
    	    /* Reserved for future use */
    	    set_status(NOP);
    	    break;
    	default:
    	    quit("Error: Invalid search status!\n");
    	}
    }
    
    /* Clean up memory */
    clear_eco();
    clear_transposition_table();
    clear_history();
    clear_board(board);

    /* Exit Search Thread */
    return NULL;
}