| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 | #include <iostream>#include "Game.h"#include "Types.h"std::array<Vector, 8> Game::neighbours;std::array<Vector, 9 * 5> Game::fieldVectors;Game::Game() : active(-1, -1), mustTake(false) {    std::cout << "0\n1\n0\n";    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);    uint index = 0;    for(uint y = 0; y < 5; y++) {        for(uint x = 0; x < 9; x++) {            fieldVectors[index++].set(x, y);        }    }}char Game::getChar(int x, int y) const {    if(active.compare(x, y)) {        return '*';    }    static const char map[] = {'#', 'O', '.'};    return map[fields[x][y]];}void Game::toString(String& s) const {    s.append("  0 1 2 3 4 5 6 7 8\n");    lineToString(s, 0);    s.append("  |\\|/|\\|/|\\|/|\\|/|\n");    lineToString(s, 1);    s.append("  |/|\\|/|\\|/|\\|/|\\|\n");    lineToString(s, 2);    s.append("  |\\|/|\\|/|\\|/|\\|/|\n");    lineToString(s, 3);    s.append("  |/|\\|/|\\|/|\\|/|\\|\n");    lineToString(s, 4);    s.append("\n");}void Game::lineToString(String& s, int y) const {    s.append(y + '0').append(' ');    for(int x = 0; x < 8; x++) {        s.append(getChar(x, y)).append('-');    }    s.append(getChar(8, y)).append("\n\r");}void Game::readLine() {    String line;    while(true) {        char c = std::cin.get();        if(c == '\n') {            if(parseLine(line)) {                return;            }            line.clear();        } else if(c != '\r') {            line.append(c);        }    }}bool Game::parseLine(const String& line) {    if(line == "   0   1   2   3   4   5   6   7   8") {        readFields();        printFields();    } 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]?") {        std::cout << "Y\n";    } else if(line == "************************Player 1 won!**********************" ||            line == "************************Player 2 won!**********************") {        std::cerr << line << "\n";        return true;    }    return false;}void Game::consumeLine() const {    // skip until newline    while(std::cin.get() != '\n');    // skip any trailing line carriage    while(true) {        char c = std::cin.peek();        if(c != '\r') {            break;        }        std::cin.get();    }}void Game::readLine(uint y) {    // skip line heading    std::cin.get();    std::cin.get();    std::cin.get();    for(uint x = 0; x < 9; x++) {        // read field state        char c = std::cin.get();        if(c == '2') {            fields[x][y] = BLACK;        } else if(c == '0') {            fields[x][y] = EMPTY;        } else if(c == '1') {            fields[x][y] = WHITE;        } else {            std::cerr << "game field parsing error\n";        }        // skip " - " until the next field (or the next line for x = 8)        std::cin.get();        std::cin.get();        std::cin.get();    }}void Game::readFields() {    for(uint i = 0; i < 5; i++) {        consumeLine();        readLine(i);    }}void Game::printFields() const {    String s;    toString(s);    std::cerr << s;}bool Game::isInRange(const Vector& v) const {    return v.x >= 0 && v.x <= 8 && v.y >= 0 && v.y <= 4;}bool Game::areNeighbours(const Vector& from, const Vector& to) const {    if(from == to) {        return false;    }    Vector diff = from - to;    if(diff.x < -1 || diff.x > 1 || diff.y < -1 || diff.y > 1) {        return false;    }    if(diff.x == 0 || diff.y == 0) {        return true;    }    return !((from.x & 1) ^ (from.y & 1));}void Game::removeLine(const Vector& from, const Vector& to, FieldState state) {    Vector current = to;    Vector diff = to - from;    while(true) {        current += diff;        if(!isInRange(current) || !hasState(current, state)) {            return;        }        setState(current, EMPTY);    }}uint Game::getRank(const Vector& from, const Vector& to, FieldState state) const {    Vector current = to;    Vector diff = to - from;    uint rank = 0;    while(true) {        current += diff;        if(!isInRange(current) || !hasState(current, state)) {            return rank;        }        rank++;    }}uint Game::getStoneTakes(const Vector& from, const Vector& to) const {    if(!isInRange(to) || !hasState(to, EMPTY) || !areNeighbours(from, to) || lastLocations.contains(to) || (to - from) == direction) {        return 0;    }    FieldState enemy = (hasState(from, BLACK) ? WHITE : BLACK);    uint rankA = getRank(from, to, enemy);    uint rankB = getRank(to, from, enemy);    if(rankA == 0 && rankB == 0) {        return 0;    }    Game copy = *this;    uint rank = 0;    if(rankA >= rankB) {        copy.removeLine(from, to, enemy);        rank = rankA;    } else {        copy.removeLine(to, from, enemy);        rank = rankB;    }    copy.lastLocations.add(from);    copy.move(from, to);    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) const {    if(hasState(from, EMPTY)) {        return 0;    }    uint counter = 0;    for(const Vector& m : neighbours) {        Vector to = from + m;        if(!isInRange(to) || !areNeighbours(from, to) || !hasState(to, EMPTY)) {            continue;        }        counter++;    }    return counter;}uint Game::getFreedom(FieldState state) const {    int sum = 0;    for(const Vector& v : fieldVectors) {        if(hasState(v, state)) {            sum += getStoneFreedom(v);        }    }    return sum;}bool Game::hasState(const Vector& v, FieldState state) const {    return fields[v.x][v.y] == state;}Game::FieldState Game::getState(const Vector& v) const {    return fields[v.x][v.y];}void Game::setState(const Vector& v, FieldState state) {    fields[v.x][v.y] = state;}void Game::move(const Vector& from, const Vector& to) {    direction = to - from;    setState(to, getState(from));    setState(from, EMPTY);}void Game::makeSelection() {    lastLocations.clear();    direction.set(0, 0);    mustTake = isTakingPossible();    Vector selection(0, 0);    int maxRank = -100000;    for(Vector& to : fieldVectors) {        if(!hasState(to, EMPTY)) {            continue;        }        for(Vector& m : neighbours) {            Vector from = to + m;            if(!isInRange(from) || !hasState(from, WHITE) || !areNeighbours(from, to)) {                continue;            }            if(mustTake && getRank(from, to, BLACK) + getRank(to, from, BLACK) == 0) {                continue;            }            int rank = getQuality(from, to);            if(rank > maxRank) {                maxRank = rank;                selection = from;            }        }    }    active = selection;    std::cerr << "Selecting (" << selection.x << ", " << selection.y << ")\n";    String s;    toString(s);    std::cerr << s;    std::cout << selection.x << "\n" << selection.y << "\n";}void Game::makeMove() {    Vector maxTo(0, 0);    int maxRank = -100000;    for(Vector& m : neighbours) {        Vector to = active + m;        if(!isInRange(to) || !hasState(to, EMPTY) || lastLocations.contains(to) || !areNeighbours(active, to) || m == direction) {            continue;        }        if(!lastLocations.isEmpty() || mustTake) {            int rank = getRank(active, to, BLACK) + getRank(to, active, BLACK);            if(rank == 0) {                continue;            }        }        int rank = getQuality(active, to);        if(rank > maxRank) {            maxRank = rank;            maxTo = to;        }    }    lastLocations.add(active);    direction = maxTo - active;    active = maxTo;    std::cerr << "Move to (" << maxTo.x << ", " << maxTo.y << ")\n";    std::cout << maxTo.x << "\n" << maxTo.y << "\n";}void Game::takeStone() {    uint rankA = getRank(active, active + direction, BLACK);    uint rankB = getRank(active + direction, active, BLACK);    if(rankA >= rankB) {        std::cout << "W\n";    } else {        std::cout << "A\n";    }}int Game::getQuality(const Vector& from, const Vector& to) const {    int quality = getStoneTakes(from, to);    Game copy = *this;    copy.move(from, to);    uint rankA = copy.getRank(from, to, BLACK);    uint rankB = copy.getRank(to, from, BLACK);    if(rankA >= rankB) {        copy.removeLine(from, to, BLACK);    } else {        copy.removeLine(to, from, BLACK);    }    copy.lastLocations.clear();    copy.direction.set(0, 0);    int whiteFreedom = copy.getFreedom(WHITE);    int blackFreedom = copy.getFreedom(BLACK);    int maxRank = -1;    for(Vector& to : fieldVectors) {        if(!copy.hasState(to, EMPTY)) {            continue;        }        for(Vector& m : neighbours) {            Vector from = to + m;            if(!copy.isInRange(from) || !copy.hasState(from, BLACK)) {                continue;            }            int rank = copy.getStoneTakes(from, to);            if(rank > maxRank) {                maxRank = rank;            }        }    }    int black = countBlack();    if(black >= 8) {        black = 1;    }    return quality - maxRank * black + (whiteFreedom - blackFreedom) / 4;}int Game::countBlack() const {    int blackCounter = 0;    for(Vector& v : fieldVectors) {        blackCounter += hasState(v, BLACK);    }    return blackCounter;}bool Game::isTakingPossible() const {    for(Vector& to : fieldVectors) {        if(!hasState(to, EMPTY)) {            continue;        }        for(Vector& m : neighbours) {            Vector from = to + m;            if(!isInRange(from) || !areNeighbours(from, to) || !hasState(from, WHITE)) {                continue;            }            if(getRank(from, to, BLACK) + getRank(to, from, BLACK) > 0) {                return true;            }        }    }    return false;}
 |