Есть ли какой-нибудь «класс выражений» (C ++) - PullRequest
18 голосов
/ 11 июня 2009

Я создаю игру, которая позволяет игроку вводить данные, изменяет некоторые состояния, затем проверяет, истинно ли «значение цели» (очевидно, это описание сильно упрощено), и я хочу, чтобы это значение цели что угодно, если жизнь игрока ниже определенного значения, если количество оставшихся врагов равно нулю. Есть ли «класс выражений», который может содержать простой «оператор сравнения value1 value2» и проверять его? то есть:

expression goal(x = 4);

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

РЕДАКТИРОВАТЬ: другой (больше к тому, что я пытаюсь достичь) пример:

game.init(){ expression goal = FileRead(goalfile); }
game.checkstate(){ if(goal) exit(1); } //exit 1 is the games win state

//another more specific eg.:
class level1 { public: expression goal(total_enemies == 0); };
class level2 { public: expression goal(player.x == goal.x && player.y == goal.y); };

Ответы [ 9 ]

22 голосов
/ 11 июня 2009

Динамические выражения

Если вы хотите получить строку от пользователя и построить из нее выражение, может быть, Библиотека математических выражений C ++ подходит для вашего счета?

template<typename T>
void trig_function()
{
   std::string expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(x / 2 * pi),+1.0)";
   T x;
   exprtk::symbol_table<T> symbol_table;
   symbol_table.add_variable("x",x);
   symbol_table.add_constants();

   exprtk::expression<T> expression;
   expression.register_symbol_table(symbol_table);

   exprtk::parser<T> parser;
   parser.compile(expression_string,expression);

   for (x = T(-5.0); x <= T(+5.0); x += 0.001)
   {
      T y = expression.value();
      printf("%19.15f\t%19.15f\n",x,y);
   }
}

Существует также возможность встроить язык сценариев, например Lua или Python , что даст вам (даже) больше возможностей. Это то, что нужно учитывать, если вы пишете игру, так как вы, вероятно, захотите написать сценарий для больших ее частей.

Если вы используете Qt , вы можете использовать QtScript (Javascript-ish) для запуска выражений, которые читают (статические или динамические) свойства из ваших производных от QObject объектов.

Использование одного из вышеперечисленных избавляет вас от необходимости писать собственный синтаксический анализатор, AST и оценщик, однако для небольшого набора операторов не составит труда собрать что-то вместе, если вы используете Boost.Spirit или какая-то другая приличная библиотека для разбора.

Статические выражения

Для выбора между набором предопределенных выражений (т.е. известных во время компиляции) вы должны сохранить выражение в объекте полиморфной функции.

Для C ++ 11, если это доступно для вас, используйте std::function и лямбда-выражения.

std::function<bool (int, int)> expr = [](int a, int b) { a*2 < b };

Для более ранних компиляторов я рекомендую function и bind либо в Boost (boost: :) или C ++ 0x TR1 (std: :), в зависимости от вашего компилятора. Также здесь поможет Boost.Lambda, поскольку он позволяет создавать и хранить выражения для последующей оценки. Однако, если вы не знакомы с C ++ и шаблонами (или функциональным программированием), это, скорее всего, вас немного напугает.

С этим вы могли бы написать

using namespace boost::lambda;
boost::function<bool (int, int)> myexpr1 = (_1 + _2) > 20;
boost::function<bool (int, int)> myexpr2 = (_1 * _2) > 42;
std::cout << myexpr1(4,7) << " " << myexpr2(2,5);

с привязкой, это будет выглядеть так:

boost::function<bool (Player&)> check = bind(&Player::getHealth, _1) > 20;
Player p1;
if (check(p1)) { dostuff(); }

check = bind(&Player::getGold, _1) < 42;
if (check(p1)) { doOtherStuff(); }
1 голос
/ 11 июня 2009

Не существует стандартного способа компилировать выражения во время выполнения. Тебе придется сделать это другим способом.

Вы можете рассмотреть возможность использования языка сценариев, такого как Lua или Python, и встроить его в свой C ++. Это даст вашим игрокам возможность программировать настолько, насколько вы этого хотите.

0 голосов
/ 27 июля 2017

Статические выражения

(поправка к сообщению Macke )

Когда ваши выражения известны во время компиляции, вы можете использовать std::function. Однако производительность может быть не оптимальной.

Вы можете автоматически зарегистрировать тест во время компиляции и выполнить его во время выполнения с минимальными накладными расходами времени выполнения (предварительно), используя шаблоны C ++ 11 и макросы. Реализацию концепции можно найти здесь .

В долгосрочной перспективе, языковая функция с именем " Контракты " может выполнить эту работу. ( N4415 , N4435 , N4378 ) В настоящее время существуют различные библиотеки для поддержки программирования по контракту.

0 голосов
/ 11 июня 2009

Нет стандартного способа сделать это в C ++. Одно из решений - написать свой собственный парсер.

Еще одно решение, которое я бы порекомендовал: встроить интерпретатор Lua в вашу программу. Lua - простой, но мощный язык программирования, который также имеет чрезвычайно легкий (<300 КБ) и простой в использовании интерпретатор. Прочитайте вступительную статью здесь: <a href="http://www.ibm.com/developerworks/linux/library/l-embed-lua/index.html" rel="nofollow noreferrer">http://www.ibm.com/developerworks/linux/library/l-embed-lua/index.html

Наличие Lua в вашей игре имеет ряд приятных побочных преимуществ:

  • вы можете использовать его как мощный язык конфигурации для вашей игры
  • с Луа, ты может легко создать командную строку интерактивная среда, которая хорош для тестирования и экспериментов. Например, вы будете быть в состоянии изменить игровой движок параметры и увидеть эффект немедленно, без перекомпиляции. Это особенно удобно для «исследовательских» проектов или программирования игр.
0 голосов
/ 11 июня 2009

Похоже, не так много признанных библиотек оценки выражений для C ++. Я написал свой собственный для CSVfix , который вы можете просмотреть, просмотрев файлы a_expr.h и a_expr.cpp в библиотеке ALib, которая является частью источника CSVfix. Оценщик не может много рекомендовать себя, за исключением того, что он выполняет свою работу и (ИМХО) довольно прост для понимания.

К сожалению, в настоящее время нет общедоступной документации для оценщика, и, по моему собственному эмпирическому правилу, то, что не задокументировано, не может быть использовано повторно. Тем не менее, модульные тесты показывают, как его можно использовать, и источник может дать вам некоторые идеи по реализации собственного оценщика, если вам захочется.

0 голосов
/ 11 июня 2009

Почему бы не создать свои собственные классы выражений?

class GoalBase
{
    virtual bool goal() = 0;
};

class Enemies : public GoalBase 
{
   // ..
   private:
      int enemies_;

   public:
      Enemies(int start) : enemies_(start) {}
      void kill() { if (enemies_) --enemies_; }
      bool goal() { return enemies_ == 0; }
};

int main()
{
    Enemies enemiesToKill(5);
    enemiesToKill.kill();    

    // ..
    if (enemiesToKill.goal()) {
        // ..
    }

    return 0;
}

Другие классы могут иметь другие методы, параметры, операторы и т. Д. Используйте свое воображение.

0 голосов
/ 11 июня 2009

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

http://www.cplusplus.com/reference/clibrary/cassert/assert/

0 голосов
/ 11 июня 2009

C ++ не имеет этого как часть языка - во время выполнения нет никакого способа получить доступ к тому же материалу, который анализировал вашу программу.

Я уверен, что есть множество сторонних библиотек арифметического анализатора, которые вы можете использовать.

0 голосов
/ 11 июня 2009

Нет, ничего подобного нет. Возможно, класс выражений слишком абстрактен. Как насчет определения различных классов целей с помощью метода IsReached ()?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...