Создайте умный игровой плеер Specker

Я создаю игру под названием Specker в c ++.

Правила просты:

  

Есть \ $ p \ $ players \ $ \ left (0 \ to p - 1 \ right) \ $ и \ $ n \ $ heaps \ $ \ left (0 \ to n - 1 \ right) \ $ .

     

Начиная с игрока \ $ 0 \ $ каждый игрок принимает \ $ k> 0 \ $ из кучи \ $ x \ $ и помещает \ $ m \ $ монеты \ $ \ left (0 \ le m <k \ right) \ $ на кучу \ $ y \ $.

     

Победителем является тот, который играет последний раз, когда удаляются все монеты из всех куч.

Итак, я создал игру и некоторые классы игроков (GreedyPlayer, SpartanPlayer и т. д.), но все они немного предсказуемы в отношении того, что они будут делать. Они не умны .

У вас есть идеи о том, как создать более умного игрока AI, который на самом деле попытается победить в каждой игре?

Вот мой код:

#include <iostream>
#include <stdexcept>

using namespace std;

class Move {
private:
    int source_heap, source_coins, target_heap, target_coins;

public:
    Move(int sh, int sc, int th, int tc) {
        source_heap = sh;
        source_coins = sc;
        target_heap = th;
        target_coins = tc;
    }

    int getSource() const {
        return source_heap;
    }
    int getSourceCoins() const {
        return source_coins;
    }
    int getTarget() const {
        return target_heap;
    }
    int getTargetCoins() const {
        return target_coins;
    }

    // Let's do some operator overloading
    friend ostream &operator<<(ostream &out, const Move &move) {
        if (move.getTargetCoins()) {
            out << "takes " << move.getSourceCoins() << " coins from heap "
                << move.getSource() << " and puts " << move.getTargetCoins()
                << " coins to heap " << move.getTarget();

        } else {
            out << "takes " << move.getSourceCoins() << " coins from heap "
                << move.getSource() << " and puts nothing";
        }
    }
};

class State {
    // State with h heaps, where the i-th heap starts with c[i] coins.
private:
    int heaps, *heap_coins;

public:
    State(int h, const int c[]) {
        heaps = h;
        heap_coins = new int[heaps];
        for (int i = 0; i < heaps; i++)
            heap_coins[i] = c[i];
    }

    ~State() {
        delete[] heap_coins;
        return;
    }

    int getCoins(int h) const throw(logic_error) {
        if (h < 0 || h > heaps) {
            throw logic_error(
                "Invalid heap number, enter a number between 1 and heaps!");
            return 1;
        } else {
            return heap_coins[h];
        }
    }
    void next(const Move &move) throw(logic_error) {
        if ((move.getSource() < 0) || (move.getSource() > heaps) ||
            (move.getTarget() < 0) || (move.getTarget() > heaps)) {
            throw logic_error("Invalid Heap!");
            return;
        } else if (
            (move.getSourceCoins() < 1) || (move.getTargetCoins() < 0) ||
            (move.getSourceCoins() <= move.getTargetCoins()) ||
            (move.getSourceCoins() > getCoins(move.getSource()))) {
            throw logic_error("Invalid Coin number!");
        } else {
            heap_coins[move.getSource()] -= move.getSourceCoins();
            heap_coins[move.getTarget()] += move.getTargetCoins();
        }
    }

    bool winning() const {
        int s = 0;
        for (int i = 0; i < heaps; i++)
            s += getCoins(i);
        return not s; // yeah i know how booleans work :P
    }

    int getHeaps() const {
        return heaps;
    }

    friend ostream &operator<<(ostream &out, const State &state) {
        for (int i = 0; i < state.getHeaps(); i++) {
            out << state.heap_coins[i];
            if (i != state.getHeaps() - 1)
                out << ", ";
        }
        return out;
    }
};

class Player {
public:
    Player(const string &n);
    virtual ~Player();

    virtual const string &getType() const = 0;
    virtual Move play(const State &s) = 0;

    friend ostream &operator<<(ostream &out, const Player &player);

protected:
    string player_name;
};

class GreedyPlayer : public Player {
private:
    string player_type;

public:
    GreedyPlayer(const string &n) : Player(n) {
        player_type = "Greedy";
    }
    virtual const string &getType() const override {
        return player_type;
    }
    virtual Move play(const State &s) override {
        int source_heap = 0;
        int source_coins = 0;
        for (int i = 0; i < s.getHeaps(); i++) {
            if (s.getCoins(i) > source_coins) {
                source_heap = i;
                source_coins = s.getCoins(i);
            }
        }
        Move GreedyObject(source_heap, source_coins, 0, 0);
        return GreedyObject;
    }
};

class SpartanPlayer : public Player {
public:
    SpartanPlayer(const string &n) : Player(n) {
        player_type = "Spartan";
    }
    virtual const string &getType() const override {
        return player_type;
    }

    virtual Move play(const State &s) override {
        int source_heap = 0;
        int source_coins = 0;
        for (int i = 0; i < s.getHeaps(); i++) {
            if (s.getCoins(i) > source_coins) {
                source_heap = i;
                source_coins = s.getCoins(i);
            }
        }
        Move SpartanObject(source_heap, 1, 0, 0);
        return SpartanObject;
    }

private:
    string player_type;
};

class SneakyPlayer : public Player {
public:
    SneakyPlayer(const string &n) : Player(n) {
        player_type = "Sneaky";
    }
    virtual const string &getType() const override {
        return player_type;
    }

    virtual Move play(const State &s) override {
        int j = 0;
        while (s.getCoins(j) == 0) {
            j++;
        }
        int source_heap = j;
        int source_coins = s.getCoins(j);
        for (int i = j + 1; i < s.getHeaps(); i++) {
            if ((s.getCoins(i) < source_coins) && (s.getCoins(i) > 0)) {
                source_heap = i;
                source_coins = s.getCoins(i);
            }
        }
        Move SneakyObject(source_heap, source_coins, 0, 0);
        return SneakyObject;
    }

private:
    string player_type;
};

class RighteousPlayer : public Player {
public:
    RighteousPlayer(const string &n) : Player(n) {
        player_type = "Righteous";
    }
    virtual const string &getType() const override {
        return player_type;
    }

    virtual Move play(const State &s) override {
        int target_heap = 0;
        int source_heap = 0;
        int source_coins = s.getCoins(0);
        int target_coins = source_coins;

        for (int i = 1; i < s.getHeaps(); i++) {
            if (s.getCoins(i) > source_coins) {
                source_heap = i;
                source_coins = s.getCoins(i);
            } else if (s.getCoins(i) < target_coins) {
                target_heap = i;
                target_coins = s.getCoins(i);
            }
        }
        source_coins -= source_coins / 2;
        Move RighteousObject(
            source_heap, source_coins, target_heap, source_coins - 1);
        return RighteousObject;
    }

private:
    string player_type;
};

Player::Player(const string &n) {
    player_name = n;
}

Player::~Player() {
    player_name.clear();
}

ostream &operator<<(ostream &out, const Player &player) {
    out << player.getType() << " player " << player.player_name;
    return out;
}

class Game {
private:
    int game_heaps, game_players, current_heap, current_player;
    int *heap_coins;
    Player **players_list;

public:
    Game(int heaps, int players) {
        heap_coins= new int [heaps];
        game_heaps = heaps;
        game_players = players;
        current_heap = 0;
        current_player = 0;
        players_list = new Player*[players];
    }
    ~Game() {
        delete[] heap_coins;
        delete[] players_list;
    }
    void addHeap(int coins) throw(logic_error) {
        if (current_heap > game_heaps)
            throw logic_error("All heaps are full with coins!");
        else if (coins < 0)
            throw logic_error("Coins must be a positive number!"); 
        else {
                heap_coins[current_heap++] = coins;
            }
    }
    void addPlayer(Player *player) throw(logic_error) {
        if (current_player > game_players)
            throw logic_error("All players are added!");
        else {
            players_list[current_player++] = player;
        }
    }
    void play(ostream &out) throw(logic_error) {
        if ((current_player != game_players) && (current_heap != game_heaps)) {
            throw logic_error("Have you added all heaps and players?");
        } else {
            int i = 0;
            State currentState(game_heaps, heap_coins);
            while (!currentState.winning()) {
                out << "State: " << currentState << endl;
                out << *players_list[i % game_players] << " "
                    << players_list[i % game_players]->play(currentState) << endl;
                currentState.next(
                    players_list[i % game_players]->play(currentState));

                i++;
            }
            out << "State: " << currentState << endl;
            i--;
            out << *players_list[i % game_players] << " wins" << endl;
        }
    }
};


int main() {
 Game specker(3, 4);
 specker.addHeap(10);
 specker.addHeap(20);
 specker.addHeap(17);
 specker.addPlayer(new SneakyPlayer("Tom"));
 specker.addPlayer(new SpartanPlayer("Mary"));
 specker.addPlayer(new GreedyPlayer("Alan"));
 specker.addPlayer(new RighteousPlayer("Robin"));
 specker.play(cout);

}
8 голосов | спросил Stavros Avramidis 14 MaramWed, 14 Mar 2018 10:38:48 +03002018-03-14T10:38:48+03:0010 2018, 10:38:48

2 ответа


8

Несколько вещей, которые можно улучшить.

  • В соответствии с GDB строка << players_list[i % game_players]->play(currentState) << endl; вызывает ошибку сегментации.

  • Если вы скомпилируете больше предупреждений, например -Weffc++ -pedantic вы получите много подсказок о вещах, которые можно улучшить.
    Вы должны всегда включать как можно больше предупреждений и исправить их все. Некоторые люди даже рассматривают предупреждения как ошибки для обеспечения этого.

  • Не используйте using namespace std

  • Избегайте объявления более чем одной переменной в строке. Не нужно быть скупой с вашим вертикальным пространством.
    Также в C ++ * и & обычно рассматривается как часть типа, поэтому вы должны предпочесть int* foo over int *foo

  • Предпочитают интеллектуальные указатели над необработанными указателями. Ручное управление памятью трудно получить даже для профессионалов. Начиная с C ++ 11 и выше у вас почти никогда не будет причины использовать new.

  • Если вы хотите сбросить выходной буфер, предпочитайте \n over endl. Если вы хотите очистить его, используйте flush(), чтобы ваше намерение было понятным.

  • Некоторые из ваших имен переменных могут быть улучшены. Старайтесь всегда использовать имена, описывающие, для чего используется переменная.

  • Ваши комментарии на самом деле ничего не добавляют к коду, поэтому вы также можете их удалить.

ответил yuri 14 MarpmWed, 14 Mar 2018 15:36:42 +03002018-03-14T15:36:42+03:0003 2018, 15:36:42
-2

Вы можете попытаться сделать Агента, который будет использовать более абстрактный метод, который не использует функцию характеристики (оценки). Метод как таковой может быть Поиск по дереву Монте-Карло . Вам нужно всего лишь предоставить вашему агенту все доступные ходы, и с помощью случайной выборки агент будет расширять дерево и давать награду каждому набору действий.

Я думаю, вы могли бы найти достаточную документацию здесь .

ответил Emmanouil Karamalegos 14 MarpmWed, 14 Mar 2018 18:57:15 +03002018-03-14T18:57:15+03:0006 2018, 18:57:15

Похожие вопросы

0
Если актеры в игре несут ответственность за рисование себя? Разница между ортогональной картой и изометрическим mapLearning для создания лучшего искусства (2D-игры) Почему радианы предпочитают более чем в градусах развития игры? Обнаружение столкновений шестиугольников для быстро движущихся объектов? ? В движке Entity-Component-System, как я могу работать с группами зависимых объектов? Должен ли я использовать текстуры, не имеющие размера 2? Почему этот код обнаружения биений не позволяет правильно зарегистрировать некоторые удары? он подходит к наградам и статистике? Как сделать прыжок персонажа? Что мне нужно для законного использования музыки, защищенной авторским правом, в моей игре? Какие-нибудь советы по созданию кросс-платформенных игр? [closed] Максимальная звуковая задержка до того, как игрок заметит? Как создать частицы, которые реагируют на игрока и врагов? Как именно работает Xrit SpriteBatch? Можно ли вычислить или математически доказать, сбалансирована ли игра? FPSHow я могу сделать «случайный» генератор, который предвзято предшествует событиям? Дизайн MMORPG для ограниченных по времени игроков. В эти дни нужны установки для установки? Каков наилучший способ устранения размола в играх? [закрыто] Моделирование и физика воды /океанаИзготовление игрового процесса для программиста «все-все»

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132