Exemple #1
0
int quiescent(app_t *app, cnodeptr_t parent, int alpha, int beta)
{
	int i, score = -MATE;
	node_t node;
	int delta = 200;

	init_node(&node);

	assert(app);

	app->search.nodes++;

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

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

	score = evaluate(app->game.board);

	if (score >= beta) return beta;
	/* delta pruning based on a material value of delta (this should be disabled
	   in the endgame) */
	/* The idea here is that, even if our score can improve alpha, it doesn't
	   improve it by a significant amount, so don't bother searching these nodes */
	if (score < (alpha - delta)) return alpha;
	if (score > alpha) alpha = score;


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

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

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

		score = -quiescent(app, &node, -beta, -alpha);

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

		if (score > alpha) {
			if (score >= beta) {
				return beta;
			}

			/* update alpha */
			alpha = score;
		}
	}

	return alpha;
}
Exemple #2
0
// -------------------------------------------------------------------------- //
//
void Test_Configuration::testPerformProcess()
{
    // Setup a realistic system.
    std::vector< std::vector<double> > basis(3, std::vector<double>(3,0.0));
    basis[1][0] = 0.25;
    basis[1][1] = 0.25;
    basis[1][2] = 0.25;
    basis[2][0] = 0.75;
    basis[2][1] = 0.75;
    basis[2][2] = 0.75;

    std::vector<int> basis_sites(3);
    basis_sites[0] = 0;
    basis_sites[1] = 1;
    basis_sites[2] = 2;
    std::vector<std::string> basis_elements(3);
    basis_elements[0] = "A";
    basis_elements[1] = "B";
    basis_elements[2] = "B";

    // Make a 37x18x19 structure.
    const int nI = 37;
    const int nJ = 18;
    const int nK = 19;
    const int nB = 3;

    // Coordinates and elements.
    std::vector<std::vector<double> > coordinates;
    std::vector<std::string> elements;

    for (int i = 0; i < nI; ++i)
    {
        for (int j = 0; j < nJ; ++j)
        {
            for (int k = 0; k < nK; ++k)
            {
                for (int b = 0; b < nB; ++b)
                {
                    std::vector<double> c(3);
                    c[0] = i + basis[b][0];
                    c[1] = j + basis[b][1];
                    c[2] = k + basis[b][2];
                    coordinates.push_back(c);
                    elements.push_back(basis_elements[b]);
                }
            }
        }
    }

    elements[0]    = "V";
    elements[216]  = "V";   // These affects process 0,1 and 3
    elements[1434] = "V";
    elements[2101] = "V";   // This affects process 0,1 and 2

    // Possible types.
    std::map<std::string, int> possible_types;
    possible_types["*"] = 0;
    possible_types["A"] = 1;
    possible_types["B"] = 2;
    possible_types["V"] = 3;

    // Setup the configuration.
    Configuration configuration(coordinates, elements, possible_types);

    // Setup the lattice map.
    std::vector<int> repetitions(3);
    repetitions[0] = nI;
    repetitions[1] = nJ;
    repetitions[2] = nK;
    std::vector<bool> periodicity(3, true);
    LatticeMap lattice_map(nB, repetitions, periodicity);

    // Init the match lists.
    configuration.initMatchLists(lattice_map, 1);

    // Get a process that finds a V between two B and turns one of
    // the Bs into an A.
    std::vector<std::string> process_elements1(3);
    process_elements1[0] = "V";
    process_elements1[1] = "B";
    process_elements1[2] = "B";

    std::vector<std::string> process_elements2(3);
    process_elements2[0] = "B";
    process_elements2[1] = "A";
    process_elements2[2] = "B";

    std::vector<std::vector<double> > process_coordinates(3, std::vector<double>(3, 0.0));

    process_coordinates[1][0] = -0.25;
    process_coordinates[1][1] = -0.25;
    process_coordinates[1][2] = -0.25;
    process_coordinates[2][0] =  0.25;
    process_coordinates[2][1] =  0.25;
    process_coordinates[2][2] =  0.25;

    const double rate = 13.7;
    Configuration c1(process_coordinates, process_elements1, possible_types);
    Configuration c2(process_coordinates, process_elements2, possible_types);
    Process p(c1, c2, rate, basis_sites);

    // Now, add index 1434 to the process.
    // We know by construction that these match.
    p.addSite(1434, 0.0);

    // For site 1434
    // 350 changes from 1 to 0
    // 1434 changes from 2 to 1
    // All other must remain unchanged.
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1434], 3 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[350],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1433], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[349],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[351],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[2517], 1 );

    // Peform the process.
    configuration.performProcess(p, 1434);

    // Check that the types were correctly updated.
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1434], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[350],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1433], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[349],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[351],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[2517], 1 );

    // Check that the correct indices were added to the list of affected.
    const std::vector<int> affected = p.affectedIndices();
    CPPUNIT_ASSERT_EQUAL( affected[0], 1434 );
    CPPUNIT_ASSERT_EQUAL( affected[1], 350  );

}
Exemple #3
0
// -------------------------------------------------------------------------- //
//
void Test_Configuration::testMatchLists()
{
    // Setup a configuration.
    std::vector< std::vector<double> > basis(3, std::vector<double>(3,0.0));
    basis[1][0] = 0.25;
    basis[1][1] = 0.25;
    basis[1][2] = 0.25;
    basis[2][0] = 0.75;
    basis[2][1] = 0.75;
    basis[2][2] = 0.75;

    std::vector<int> basis_sites(3);
    basis_sites[0] = 0;
    basis_sites[1] = 1;
    basis_sites[2] = 2;

    std::vector<std::string> basis_elements(3);
    basis_elements[0] = "A";
    basis_elements[1] = "B";
    basis_elements[2] = "B";

    // Make a 37x18x19 structure.
    const int nI = 37;
    const int nJ = 18;
    const int nK = 19;
    const int nB = 3;

    // Coordinates and elements.
    std::vector<std::vector<double> > coordinates;
    std::vector<std::string> elements;

    for (int i = 0; i < nI; ++i)
    {
        for (int j = 0; j < nJ; ++j)
        {
            for (int k = 0; k < nK; ++k)
            {
                for (int b = 0; b < nB; ++b)
                {
                    std::vector<double> c(3);
                    c[0] = i + basis[b][0];
                    c[1] = j + basis[b][1];
                    c[2] = k + basis[b][2];
                    coordinates.push_back(c);
                    elements.push_back(basis_elements[b]);
                }
            }
        }
    }

    elements[0]    = "V";
    elements[216]  = "V";
    elements[1434] = "V";
    elements[2101] = "V";

    // Possible types.
    std::map<std::string, int> possible_types;
    possible_types["*"] = 0;
    possible_types["A"] = 1;
    possible_types["B"] = 2;
    possible_types["V"] = 3;

    // Setup the configuration.
    Configuration configuration(coordinates, elements, possible_types);

    // Setup the lattice map.
    std::vector<int> repetitions(3);
    repetitions[0] = nI;
    repetitions[1] = nJ;
    repetitions[2] = nK;
    std::vector<bool> periodicity(3, true);
    LatticeMap lattice_map(nB, repetitions, periodicity);

    // Try to access the match lists before initialization. They should be
    // empty.
    CPPUNIT_ASSERT( configuration.minimalMatchList(10).empty()   );
    CPPUNIT_ASSERT( configuration.minimalMatchList(2101).empty() );
    CPPUNIT_ASSERT( configuration.minimalMatchList(1434).empty() );

    // Init the match lists.
    configuration.initMatchLists(lattice_map, 1);

    // This did something.
    CPPUNIT_ASSERT( !configuration.minimalMatchList(10).empty()   );
    CPPUNIT_ASSERT( !configuration.minimalMatchList(2101).empty() );
    CPPUNIT_ASSERT( !configuration.minimalMatchList(1434).empty() );

    // Get the match list the hard way.
    const std::vector<MinimalMatchListEntry> ref_1434 = \
        configuration.minimalMatchList( 1434,
                                        lattice_map.neighbourIndices(1434),
                                        lattice_map);
    // Check the size.
    CPPUNIT_ASSERT_EQUAL( static_cast<int>(ref_1434.size()),
                          static_cast<int>(configuration.minimalMatchList(1434).size()) );

    // Check the values.
    for (size_t i = 0; i < ref_1434.size(); ++i)
    {
        CPPUNIT_ASSERT_EQUAL( ref_1434[i].match_type,
                              configuration.minimalMatchList(1434)[i].match_type );
        CPPUNIT_ASSERT_EQUAL( ref_1434[i].update_type,
                              configuration.minimalMatchList(1434)[i].update_type );
        CPPUNIT_ASSERT_EQUAL( ref_1434[i].index,
                              configuration.minimalMatchList(1434)[i].index );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref_1434[i].distance,
                                      configuration.minimalMatchList(1434)[i].distance,
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref_1434[i].coordinate.x(),
                                      configuration.minimalMatchList(1434)[i].coordinate.x(),
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref_1434[i].coordinate.y(),
                                      configuration.minimalMatchList(1434)[i].coordinate.y(),
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref_1434[i].coordinate.z(),
                                      configuration.minimalMatchList(1434)[i].coordinate.z(),
                                      1.0e-14 );

    }

    // Setup a process that changes V to B.

    // Get a process that finds a V between two B and turns one of
    // the Bs into an A.
    std::vector<std::string> process_elements1(3);
    process_elements1[0] = "V";
    process_elements1[1] = "B";
    process_elements1[2] = "B";

    std::vector<std::string> process_elements2(3);
    process_elements2[0] = "B";
    process_elements2[1] = "A";
    process_elements2[2] = "B";

    std::vector<std::vector<double> > process_coordinates(3, std::vector<double>(3, 0.0));

    process_coordinates[1][0] = -0.25;
    process_coordinates[1][1] = -0.25;
    process_coordinates[1][2] = -0.25;
    process_coordinates[2][0] =  0.25;
    process_coordinates[2][1] =  0.25;
    process_coordinates[2][2] =  0.25;

    const double rate = 13.7;
    Configuration c1(process_coordinates, process_elements1, possible_types);
    Configuration c2(process_coordinates, process_elements2, possible_types);
    Process p(c1, c2, rate, basis_sites);

    // Now, add index 1434 to the process.
    // We know by construction that these match.
    p.addSite(1434, 0.0);

    // For site 1434
    // 350 changes from 1 to 0
    // 1434 changes from 2 to 1
    // All other must remain unchanged.
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1434], 3 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[350],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1433], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[349],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[351],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[2517], 1 );

    // Peform the process.
    configuration.performProcess(p, 1434);

    // Check that the types were correctly updated.
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1434], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[350],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1433], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[349],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[351],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[2517], 1 );

    // Check that updating the matchlist gets us the correct values.
    configuration.updateMatchList(1434);

    // Reference.
    const std::vector<MinimalMatchListEntry> ref2_1434 =        \
        configuration.minimalMatchList( 1434,
                                        lattice_map.neighbourIndices(1434),
                                        lattice_map);
    // Check the size.
    CPPUNIT_ASSERT_EQUAL( static_cast<int>(ref2_1434.size()),
                          static_cast<int>(configuration.minimalMatchList(1434).size()) );

    // Check the values.
    for (size_t i = 0; i < ref2_1434.size(); ++i)
    {
        CPPUNIT_ASSERT_EQUAL( ref2_1434[i].match_type,
                              configuration.minimalMatchList(1434)[i].match_type );
        CPPUNIT_ASSERT_EQUAL( ref2_1434[i].update_type,
                              configuration.minimalMatchList(1434)[i].update_type );
        CPPUNIT_ASSERT_EQUAL( ref2_1434[i].index,
                              configuration.minimalMatchList(1434)[i].index );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref2_1434[i].distance,
                                      configuration.minimalMatchList(1434)[i].distance,
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref2_1434[i].coordinate.x(),
                                      configuration.minimalMatchList(1434)[i].coordinate.x(),
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref2_1434[i].coordinate.y(),
                                      configuration.minimalMatchList(1434)[i].coordinate.y(),
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref2_1434[i].coordinate.z(),
                                      configuration.minimalMatchList(1434)[i].coordinate.z(),
                                      1.0e-14 );

    }
}
Exemple #4
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;
}