2009-06-10 6 views
18

Estoy creando un juego que permite al jugador ingresar, cambia algunos estados y luego verifica si el "valor objetivo" es verdadero (obviamente esta descripción se simplifica mucho), y quiero poder hacer que el valor objetivo sea cualquier cosa si la vida de los jugadores está por debajo de un cierto valor si la cantidad de enemigos restantes es igual a cero. ¿Hay alguna "clase de expresión" que pueda contener un simple "value1 compare-operator value2" y verificarlo? es decir:¿Existe algún tipo de "clase de expresión" (C++)

expression goal(x = 4); 

si no, ¿alguien tiene alguna sugerencia sobre cómo podría desarrollar una clase de expresión?

EDIT: otra (más hacia lo que estoy tratando de lograr) ejemplo:

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); }; 

Respuesta

22

expresiones dinámicas

Si desea recibir una cadena del usuario y construyó una expresión de eso, tal vez el C++ Mathematical Expression Library se adapte a su proyecto de ley?

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); 
    } 
} 

Hay también la posibilidad de incrustar un lenguaje de script, como Lua o Python, que le dará (incluso) más potencia. Esto es algo que debes tener en cuenta si estás escribiendo un juego, ya que es probable que quieras guionar grandes partes de él.

Si está utilizando Qt, puede usar QtScript (Javascript-ish) para ejecutar expresiones que leen propiedades (estáticas o dinámicas) de sus objetos derivados de QObject.

El uso de uno de los anteriores le evita tener que escribir su propio analizador, AST y evaluador, sin embargo, para un pequeño grupo de operadores no debería ser demasiado difícil de hackear algo si usa Boost.Spirit o algún otro análisis decente biblioteca.

expresiones estáticas

para seleccionar entre un conjunto de expresiones predefinidas (es decir conocido en tiempo de compilación), debe almacenar la expresión en un objeto de función polimórfica.

Para C++ 11, si está disponible para usted, use std::function y expresiones lambda.

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

Para compiladores anteriores, recomiendo función y se unen, ya sea en Boost (impulso: :) o C++ 0x TR1 (std: :), dependiendo de su compilador. Además, Boost.Lambda será de ayuda aquí, ya que le permite construir y almacenar expresiones para su posterior evaluación. Sin embargo, si no está familiarizado con C++ y las plantillas (o programación funcional), es probable que le asuste bastante.

Con eso se podría escribir

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); 

con bind, se vería como:

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(); } 
+0

desafortunadamente, esto es completamente impráctico para expresiones arbitrarias. Lo cual creo que es lo que realmente quiere el afiche (a pesar de que su ejemplo sea "val1 op val2"). –

+0

¿Lo es? Usando boost :: lambda puede combinar todo tipo de expresiones e incluso declaraciones y todo. ¿Qué quieres decir? – Macke

+0

bien, ya que las lambdas de refuerzo se construyen en tiempo de compilación y solo son utilizadas por la persona que llama. ¿Qué harías si el usuario ingresara una combinación de operaciones que no hayas tenido en cuenta? Dado que hay un número infinito de combinaciones de operaciones matemáticas ... ciertamente no se puede explicar de manera estática para todas. –

0

No, no hay nada de eso. Quizás una clase de expresión es un poco demasiado abstracta. ¿Qué hay de definir varias clases de Goal con un método IsReached()?

0

C++ no tiene esto como parte del lenguaje: no hay forma de, en tiempo de ejecución, obtener acceso a las mismas cosas que analizaron su programa.

Estoy seguro de que hay numerosas bibliotecas de analizadores aritméticos de terceros que podría utilizar, sin embargo.

+0

No creo que sea eso lo que quiso decir. – dss539

0

Por qué no construir sus propias clases de expresión?

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; 
} 

Otras clases podrían tener otros métodos, parámetros, operadores, etc. Utilice su imaginación.

-3

No parece haber muchas bibliotecas de evaluación de expresiones reconocidas para C++. Escribí el mío para CSVfix, que puede persuadir mirando los archivos a_expr.h y a_expr.cpp en la biblioteca ALib que forma parte del origen de CSVfix. El evaluador no tiene mucho que recomendar, salvo que hace el trabajo y es (en mi humilde opinión) bastante simple de entender.

Desgraciadamente, actualmente no hay documentación pública para el evaluador, y según mi propia regla general, lo que no está documentado no puede reutilizarse. Sin embargo, las pruebas unitarias muestran cómo se puede utilizar, y la fuente puede brindarle algunas ideas sobre la implementación de su propio evaluador, en caso de que le apetezca.

1

No hay una forma estándar de compilar expresiones durante el tiempo de ejecución. Tendrás que hacerlo de otra manera.

Puede considerar el uso de un lenguaje de scripting, como Lua o Python, e incrustarlo en su C++. Eso les permitiría a sus jugadores la posibilidad de programar en la medida en que lo deseen.

+0

+1 para la recomendación de Lua. Lua se está volviendo casi omnipresente como el motor liviano e incrustado de elección para juegos y dispositivos móviles. –

0

No hay una forma estándar de hacerlo en C++. Una solución es escribir tu propio analizador.

Otra solución, que yo recomendaría: insertar un intérprete Lua en su programa. Lua es un lenguaje de programación simple pero poderoso, que también tiene un intérprete extremadamente ligero (< 300kB) y fácil de usar. Leer un artículo introductorio aquí: http://www.ibm.com/developerworks/linux/library/l-embed-lua/index.html

Habiendo Lua incrustado en su juego tiene una serie de buenas ventajas secundarios:

  • se puede utilizar como un potente lenguaje de configuración para su juego
  • con Lua, puede crear fácilmente un entorno interactivo de línea de comandos , que es bueno para pruebas y experimentos. Por ejemplo, puede cambiar los parámetros del motor de juego y ver el efecto inmediatamente, sin volver a compilar. Eso es especialmente conveniente para proyectos de "investigación" o programación de juegos.
0

expresiones estáticas

(modificación posterior Macke 's)

Cuando sus expresiones son conocidos en tiempo de compilación, puede utilizar std::function. Sin embargo, el rendimiento puede no ser óptimo.

Puede registrar automáticamente la prueba en tiempo de compilación y ejecutarlas en tiempo de ejecución con (presumambly) sobrecarga de tiempo de ejecución mínima, usando plantillas y macros de C++ 11. Se puede encontrar una implementación de prueba de concepto en here.

En el largo plazo, una función de idioma llamada "Contracts" podría hacer el trabajo. (N4415, N4435, N4378) Hoy en día, hay varias bibliotecas disponibles para admitir la programación de contratos.

Cuestiones relacionadas