| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 | 
							- #include <iostream>
 
- #include <climits>
 
- #include <chrono>
 
- #include "Game.h"
 
- #include "Types.h"
 
- std::array<Vector, 8> Game::neighbours;
 
- std::array<Vector, 9 * 5> Game::fieldVectors;
 
- long int Game::selectionTime = 0;
 
- long int Game::moveTime = 0;
 
- int Game::turns = 0;
 
- int Game::moves = 0;
 
- Game::Game() : active(-1, -1), mustTake(false) {
 
-     // sets the basic game up:
 
-     // 0 - start game
 
-     // 1 - player vs ai
 
-     // 0 - player starts
 
-     std::cout << "0\n1\n0\n";
 
-     
 
-     // allows for each neighbor iterating
 
-     neighbours[0].set(1, 0);
 
-     neighbours[1].set(0, 1);
 
-     neighbours[2].set(-1, 0);
 
-     neighbours[3].set(0, -1);
 
-     neighbours[4].set(1, 1);
 
-     neighbours[5].set(-1, 1);
 
-     neighbours[6].set(1, -1);
 
-     neighbours[7].set(-1, -1);
 
-     // allows for each for all fields 
 
-     uint index = 0;
 
-     for(uint y = 0; y < 5; y++) {
 
-         for(uint x = 0; x < 9; x++) {
 
-             fieldVectors[index++].set(x, y);
 
-         }
 
-     }
 
- }
 
- void Game::readLine() {
 
-     String line;
 
-     while(true) {
 
-         // read input by each character
 
-         char c = std::cin.get();
 
-         if(c == '\n') {
 
-             // parse the command if the line ended
 
-             if(parseLine(line)) {
 
-                 return;
 
-             }
 
-             // clear the buffer for the next command
 
-             line.clear();
 
-         } else if(c != '\r') {
 
-             // line carriages are ignored
 
-             line.append(c);
 
-         }
 
-     }
 
- }
 
- bool Game::parseLine(const String& line) {
 
-     // identify when the server expects an answer or a new game field is available
 
-     if(line == "   0   1   2   3   4   5   6   7   8") {
 
-         fields.read();
 
-         fields.print(active);
 
-     } else if(line == "Please enter origin x-axis") {
 
-         makeSelection();
 
-     } else if(line == "Please enter destination x-axis") {
 
-         makeMove();
 
-     } else if(line == "Please enter wether you want to Withdraw or Approach [W/A]") {
 
-         takeStone();
 
-     } else if(line == "Do you want to continue with your turn [Y/N]?") {
 
-         // we always want to continue if possible
 
-         std::cout << "Y\n";
 
-     } else if(line == "************************Player 1 won!**********************" ||
 
-             line == "************************Player 2 won!**********************") {
 
-         // stop the game if anybody wins - the server does not do that
 
-         std::cerr << line << "\n";
 
-         std::cerr << turns << "," << moves << "," << selectionTime << "," << moveTime << "\n";
 
-         return true;
 
-     }
 
-     return false;
 
- }
 
- bool Game::isInRange(const Vector& v) const {
 
-     return v.x >= 0 && v.x <= 8 && v.y >= 0 && v.y <= 4;
 
- }
 
- bool Game::areNeighbors(const Vector& from, const Vector& to) const {
 
-     // fields are not neighbors with themselves
 
-     if(from == to) {
 
-         return false;
 
-     }
 
-     Vector diff = from - to;
 
-     // fields with a bigger distance than one cannot be neighbors
 
-     if(diff.x < -1 || diff.x > 1 || diff.y < -1 || diff.y > 1) {
 
-         return false;
 
-     }
 
-     // either left, right, upper or lower neighbor
 
-     if(diff.x == 0 || diff.y == 0) {
 
-         return true;
 
-     }
 
-     // check if the field has diagonal connections (both coords are either even or uneven numbers)
 
-     return (from.x & 1) == (from.y & 1);
 
- }
 
- uint Game::removeLine(const Vector& from, const Vector& to, Fields::State state) {
 
-     // walk along the line and removes opponent stones
 
-     Vector current = to;
 
-     Vector unit = to - from;
 
-     // counter for removed stones
 
-     uint rank = 0;
 
-     while(true) {
 
-         current += unit;
 
-         // stop removing on wrong stones or the end of the game field
 
-         if(!isInRange(current) || !fields.hasState(current, state)) {
 
-             return rank;
 
-         }
 
-         fields.setState(current, Fields::EMPTY);
 
-         rank++;
 
-     }
 
- }
 
- uint Game::getRank(const Vector& from, const Vector& to, Fields::State state) const {
 
-     // same as removeLine but the removable stones are only counted
 
-     Vector current = to;
 
-     Vector unit = to - from;
 
-     uint rank = 0;
 
-     while(true) {
 
-         current += unit;
 
-         if(!isInRange(current) || !fields.hasState(current, state)) {
 
-             return rank;
 
-         }
 
-         rank++;
 
-     }
 
- }
 
- uint Game::getStoneTakes(const Vector& from, const Vector& to) const {
 
-     // an invalid turn cannot take any stones
 
-     if(!isInRange(to) || !fields.hasState(to, Fields::EMPTY) || !areNeighbors(from, to) ||
 
-             lastLocations.contains(to) || (to - from) == direction) {
 
-         return 0;
 
-     }
 
-     // the turn must take stones
 
-     Fields::State enemy = (fields.hasState(from, Fields::BLACK) ? Fields::WHITE : Fields::BLACK);
 
-     if(getRank(from, to, enemy) == 0 && getRank(to, from, enemy) == 0) {
 
-         return 0;
 
-     }
 
-     // actually do the turn on a copied game, store the rank (= taken stones)
 
-     Game copy = *this;
 
-     uint rank = copy.move(from, to);
 
-     // recursively check all neighbors on the copied game for another move, take the best move
 
-     uint maxRank = 0;
 
-     for(Vector& m : neighbours) {
 
-         uint rank = copy.getStoneTakes(to, to + m);
 
-         if(rank > maxRank) {
 
-             maxRank = rank;
 
-         }
 
-     }
 
-     return rank + maxRank;
 
- }
 
- uint Game::getStoneFreedom(const Vector& from, Fields::State state) const {
 
-     // no freedom if the stone is not yours
 
-     if(!fields.hasState(from, state)) {
 
-         return 0;
 
-     }
 
-     // count directions the stone can move to
 
-     uint counter = 0;
 
-     for(const Vector& m : neighbours) {
 
-         Vector to = from + m;
 
-         if(isInRange(to) && areNeighbors(from, to) && fields.hasState(to, Fields::EMPTY)) {
 
-             counter++;
 
-         }
 
-     }
 
-     return counter;
 
- }
 
- uint Game::getFreedom(Fields::State state) const {
 
-     uint sum = 0;
 
-     for(const Vector& v : fieldVectors) {
 
-         sum += getStoneFreedom(v, state);
 
-     }
 
-     return sum;
 
- }
 
- uint Game::move(const Vector& from, const Vector& to) {
 
-     // remember direction to block the same move
 
-     direction = to - from;
 
-     // remember the old location to block moving to it again
 
-     lastLocations.add(from);
 
-     // actually move the stone
 
-     fields.setState(to, fields.getState(from));
 
-     fields.setState(from, Fields::EMPTY);
 
-     // get the enemy by inverting the goal state
 
-     Fields::State enemy = (fields.hasState(to, Fields::BLACK) ? Fields::WHITE : Fields::BLACK);
 
-     // compare quality of the two sides, take better side
 
-     uint rankA = getRank(from, to, enemy);
 
-     uint rankB = getRank(to, from, enemy);
 
-     if(rankA >= rankB) {
 
-         return removeLine(from, to, enemy);
 
-     }
 
-     return removeLine(to, from, enemy);
 
- }
 
- void Game::makeSelection() {
 
-     // add statistics
 
-     ssize_t time = getNanos();
 
-     turns++;
 
-     // new turn starts - reset previously blocked turns
 
-     lastLocations.clear();
 
-     direction.set(0, 0);
 
-     // remember if the following turn must take a stone
 
-     mustTake = isTakingPossible();
 
-     // calculate rank for all possible selections, take best selection
 
-     Vector selection(0, 0);
 
-     int maxRank = INT_MIN;
 
-     for(Vector& to : fieldVectors) {
 
-         if(!fields.hasState(to, Fields::EMPTY)) {
 
-             continue;
 
-         }
 
-         // scan neighbors of empty fields for white stones
 
-         for(Vector& m : neighbours) {
 
-             Vector from = to + m;
 
-             // prevent invalid stone locations
 
-             if(!isInRange(from) || !fields.hasState(from, Fields::WHITE) || !areNeighbors(from, to)) {
 
-                 continue;
 
-             }
 
-             // prevent non taking turns if taking is a must
 
-             if(mustTake && getRank(from, to, Fields::BLACK) + getRank(to, from, Fields::BLACK) == 0) {
 
-                 continue;
 
-             }
 
-             // calculate rank and potentially store the new max value
 
-             int rank = getQuality(from, to);
 
-             if(rank > maxRank) {
 
-                 maxRank = rank;
 
-                 selection = from;
 
-             }
 
-         }
 
-     }
 
-     // mark the stone as active
 
-     active = selection;
 
-     // add selection time to statistics, do not measure IO
 
-     selectionTime += getNanos() - time;
 
-     // send the selection to the server
 
-     std::cerr << "Selecting (" << selection.x << ", " << selection.y << ")\n";
 
-     // print the selection and the current game field for logging purposes
 
-     fields.print(active);
 
-     std::cout << selection.x << "\n" << selection.y << "\n";
 
- }
 
- void Game::makeMove() {
 
-     // add statistics
 
-     ssize_t time = getNanos();
 
-     moves++;
 
-     // check all neighbors of active selection and choose the move with the highest rank
 
-     Vector maxTo(0, 0);
 
-     int maxRank = INT_MIN;
 
-     for(Vector& m : neighbours) {
 
-         Vector to = active + m;
 
-         // prevent invalid moves
 
-         if(!isInRange(to) || !fields.hasState(to, Fields::EMPTY) || lastLocations.contains(to) ||
 
-                 !areNeighbors(active, to) || m == direction) {
 
-             continue;
 
-         }
 
-         // if this is not the first move or a must take move - prevent non taking move
 
-         if(!lastLocations.isEmpty() || mustTake) {
 
-             int rank = getRank(active, to, Fields::BLACK) + getRank(to, active, Fields::BLACK);
 
-             if(rank == 0) {
 
-                 continue;
 
-             }
 
-         }
 
-         // calculate rank and potentially store the new max value
 
-         int rank = getQuality(active, to);
 
-         if(rank > maxRank) {
 
-             maxRank = rank;
 
-             maxTo = to;
 
-         }
 
-     }
 
-     // remember the old location to prevent moving to it
 
-     lastLocations.add(active);
 
-     // remember the direction to prevent moving in it again
 
-     direction = maxTo - active;
 
-     // mark the location as active
 
-     active = maxTo;
 
-     // add selection time to statistics, do not measure IO
 
-     moveTime += getNanos() - time;
 
-     // send the move to the server
 
-     std::cerr << "Move to (" << maxTo.x << ", " << maxTo.y << ")\n";
 
-     // log the move
 
-     std::cout << maxTo.x << "\n" << maxTo.y << "\n";
 
- }
 
- void Game::takeStone() {
 
-     // calculate the better taking side ...
 
-     uint rankA = getRank(active, active + direction, Fields::BLACK);
 
-     uint rankB = getRank(active + direction, active, Fields::BLACK);
 
-     // and send it to the server
 
-     if(rankA >= rankB) {
 
-         std::cout << "W\n";
 
-     } else {
 
-         std::cout << "A\n";
 
-     }
 
- }
 
- int Game::getQuality(const Vector& from, const Vector& to) const {
 
-     // base quality is how much stones this turn can take (+ following moves)
 
-     int quality = getStoneTakes(from, to);
 
-     // actually do the turn on a copy
 
-     Game copy = *this;
 
-     copy.move(from, to);
 
-     // reset previous location and direction to simulate an opponent turn
 
-     copy.lastLocations.clear();
 
-     copy.direction.set(0, 0);
 
-     // calculate white and black freedom on the potential new board
 
-     int whiteFreedom = copy.getFreedom(Fields::WHITE);
 
-     int blackFreedom = copy.getFreedom(Fields::BLACK);
 
-     // calculates the strongest opponent turn
 
-     uint maxRank = copy.getBestEnemyRank();
 
-     // opponent count is important in the endgame
 
-     int black = countBlack();
 
-     if(black >= 8) {
 
-         black = 1;
 
-     }
 
-     // finalize the quality formula
 
-     return quality - maxRank * black + (whiteFreedom - blackFreedom) / 4;
 
- }
 
- int Game::countBlack() const {
 
-     int counter = 0;
 
-     for(Vector& v : fieldVectors) {
 
-         counter += fields.hasState(v, Fields::BLACK);
 
-     }
 
-     return counter;
 
- }
 
- bool Game::isTakingPossible() const {
 
-     // scan all fields for possible taking moves
 
-     for(Vector& to : fieldVectors) {
 
-         if(!fields.hasState(to, Fields::EMPTY)) {
 
-             continue;
 
-         }
 
-         // check if any white neighbored stone can move to the found empty stone
 
-         for(Vector& m : neighbours) {
 
-             Vector from = to + m;
 
-             // prevent invalid moves
 
-             if(!isInRange(from) || !areNeighbors(from, to) || !fields.hasState(from, Fields::WHITE)) {
 
-                 continue;
 
-             }
 
-             // return true if the white stone can take black stones in any direction
 
-             if(getRank(from, to, Fields::BLACK) + getRank(to, from, Fields::BLACK) > 0) {
 
-                 return true;
 
-             }
 
-         }
 
-     }
 
-     return false;
 
- }
 
- uint Game::getBestEnemyRank() const {
 
-     uint maxRank = 0;
 
-     // scan all fields for best rank
 
-     for(Vector& to : fieldVectors) {
 
-         if(!fields.hasState(to, Fields::EMPTY)) {
 
-             continue;
 
-         }
 
-         // scan neighbors of found empty fields
 
-         for(Vector& m : neighbours) {
 
-             Vector from = to + m;
 
-             // prevent invalid moves
 
-             if(!isInRange(from) || !fields.hasState(from, Fields::BLACK)) {
 
-                 continue;
 
-             }
 
-             // calculate and store the potentially better rank
 
-             uint rank = getStoneTakes(from, to);
 
-             if(rank > maxRank) {
 
-                 maxRank = rank;
 
-             }
 
-         }
 
-     }
 
-     return maxRank;
 
- }
 
- long int Game::getNanos() {
 
-     return std::chrono::high_resolution_clock::now().time_since_epoch().count();
 
- }
 
 
  |