Putting the 'role' back in role-playing games since 2002.
Donate to Codex
Good Old Games
  • Welcome to rpgcodex.net, a site dedicated to discussing computer based role-playing games in a free and open fashion. We're less strict than other forums, but please refer to the rules.

    "This message is awaiting moderator approval": All new users must pass through our moderation queue before they will be able to post normally. Until your account has "passed" your posts will only be visible to yourself (and moderators) until they are approved. Give us a week to get around to approving / deleting / ignoring your mundane opinion on crap before hassling us about it. Once you have passed the moderation period (think of it as a test), you will be able to post normally, just like all the other retards.

Predicates and Special Cases in Game Programming

Alex

Arcane
Joined
Jun 14, 2007
Messages
8,754
Location
São Paulo - Brasil
Hi people. Lately, I have been wracking my head over an idea I had for a more friendly computer language paradigm for implementing game rules. I have come up with a few concepts and decided to share them over here, as other people may have other ideas, or know of similar ones.

So, the way I see things, it isn't very comfortable to implement tabletop rpg or strategy game rules, or rules like those, in an object oriented language. These kind of rules are written with a different mindset. When you write in object oriented languages (at least traditional ones), you have various little "objects" that have a "type". These types determine its object behavior, what it is capable of. The type defines what its objects do and how they do it. This, however, means that the types must somehow feature in the rules you describe in your system. If an object is supposed to be able to attack another, the type must have a "method" that allows it to do so. In other words, there should be something like "attack(target)" defined in the class, which will have rules for dealing with an attack from an object of that class to a provided target.

My problem with this model is that this isn't how people think when they are coming up with rules. For example, in a wargame like Warhammer, there could be simple rules describing how units go about attacking. So far so good, the attack routine depends mostly on attributes of the unit itself, each unit having things like strength, number of attacks, hit points, etc. But then, it will probably start complicating things with exceptions. It might have special rules for when ranged units enter hand to hand, like their attack strength is reduced by two. Then it might have special rules for orcs, like orcs doubling their strength when charging. Then it might have special rules for orc ranged units, that different from normal ranged units, are able to charge, but they don't get the doubled strength effect. Then it might have special rules for spellcaster, which might happen to be an orc ranged unit as well.

My point here is that rules, as we think of them, don't depend so much on fixed types, but usually depends on predicates. Predicates are simply something that can be said about game elements. For example, I might say an element x is an orc, or a ranged unit or a spellcaster, or all of these, or even none. Each is verifiable in some way, though this verification may rely on axioms. For example, the orc predicate might be based on an axiom (elements either are or are not orcs), while the ranged unit predicate might be based on checking to see if the unit has any attack with range greater than one. Based on these predicates, we define the basic behavior and exceptions of this basic behavior. So, my idea is to make a computer language that follows this paradigm, so that programming in it is more natural and debugging it is easier.

The basic idea is, then, that we have these various "typeless" objects. These objects already have the inherent capacity to store fields in a key->value mapping way. So, a given object might store in the key "name" the value "Albert", and then, if asked the value of the field "name", it would answer "Albert". Also, let's assume we have a few basic objects from out of the system that provide us with functionalities such as numbers, arrays and strings (this isn't really necessary, but will make the idea easier to follow).

Besides these objects, we also have "predicates". Predicates are special in that they are able to check if an object is part of it. For example, the predicate "orc(x)" might tell if an object x is an orc, possibly by checking if the field "race" of x is set to "orc". Predicates aren't limited to one object, either. A predicate enemy(x,y) might tell if x is an enemy of y (which might be important in a wargame when determining issues such as friendly fire, etc). Predicates are also semi-ordered, meaning that some more specific predicates have greater precedence than less specific ones. For example, we might have "orc" as a predicate and "black orc" as a more specific predicate, so black orc is "greater" than orc, but another predicate, like "spellcaster" might not be comparable to either "orc" or "black orc". By the way, if we have two predicates, p and q, and q is greater than p, then if q(x) is true, then p(x) is also true.

Also, we have methods. Methods are associated with four things. First, methods have a name, such as attack, or defend, or getStrength. Second, methods are associated to a cardinality, which is the number of arguments it receives. For example, a method like "defend" might receive only one argument, so that defend(x) means that the object x will try to defend itself, while "attack" might receive two, attack(x,y) meaning that x is attacking y.

Third, each method is associated with a "body", a description of some kind of how to run the method. A method called "getStrength(x)" might simply return the value of the "strength" property of x, while a method getStrengthBonus(x), might take the value given by getStrength(x), divide it by two, subtract five and return the total. Finally (and most interesting), each method is associated with a predicate of equal cardinality. This association means that the method is available to all objects where the predicate hods true. For example, a method like "getSpellPoints(x)" might be associated with a "spellcaster(x)" predicate, so only spellcasters have that method available, whereas "attack(x,y)" might be associated with "enemy(x,y)", so it is only legal for x to attack y if he is an enemy of y. There is also polymorphism in the case that a predicate is greater than another. So, in the orc(x) and black_orc(x) predicate examples, if both have methods called "blood_lust(x)", then the method associated with black_orc will be used instead of the more general one if x is a black_orc.

Finally, the last element we add are special cases. Special cases are all associated with one (or, in a simple extension, one or more) methods. Each special case is comprised of one predicate (possibly a composite one) over the method's variables and a "body". The idea behind special cases is that, whenever you are executing a method it is associated to, if its predicate is valid, then its body is executed. The predicate's body may alter or substitute the original body of the method. So, you might have a method, say, damage(x,y), where x is a character and y is a damage (a special object that encapsulates damage amount and type). We might have a special rule for this method with the predicate (undead(x) & fire(y)) (meaning x is an undead and y is fire damage) and the body "damage(x, 2*y). Note that rules are only applied once, so this doesn't end up in an endless loop.

Each method orders its special cases, so they are executed in the desired sequence (useful when, for example, a few cases add to values whereas others multiply them). Also, one special case may override another, meaning that if its predicate is true, the overridden one isn't checked or executed. Any and all special cases that apply for a particular method are executed in the defined order. So, for example, in the getStrength(x) method, the special case {ghost(x) :- return 0} might override all other considerations, so if x is a ghost, its strength will always be 0.

Finally, we may determine that predicates are able to check the execution stack. This is useful for creating rules like "the strength of orc units double when charging". Simply implement a special case for getStrength(x) whose predicate checks to see if charge(x,y) is further up in the stack. The predicate might be something like charging_orcs(x, y), and it checks if there is a method call charge(x,y) with x being orcs in the stack.

Well, this is it. I am sure I m forgetting something, but I need to sleep now and there is no point in posting every detail in one go. I hope you people forgive my poor communication skills. If anything in the post is unintelligible, ask about it and I will be happy to try to clarify. My objective with this is creating a language where it is easy to create and modify rule sets for games on the fly, where it is easy to test different rule designs before one sets for something definitive or even to allow the rule set to evolve as one develops new games in the same engine.
 

Antihero

Liturgist
Joined
May 8, 2010
Messages
859
Maybe not what you're looking for, but why not just do something more data-driven? So you have some sort of core that uses the data, but then if you want more flexibility use something like lua or some other scripting language for specialized behaviour that you can attach to things.
 

Alex

Arcane
Joined
Jun 14, 2007
Messages
8,754
Location
São Paulo - Brasil
@Kosmonaut

A million thanks, man. It seems very similar to what I was thinking of. It also raises a few issues I haven't gotten around thinking. I think the way I propose it, with fixed predicates and rule order being determined by methods (more or less what he calls atoms) might make things simpler to work with, though. Also, sometimes I want more than one rule to apply. I think I will send this guy an email. Once again, thanks.

@Antihero

If I understand you correctly, there are a few problems with simply making things data-driven. The biggest problem I see is like this: suppose you have a system core hard coded and are able to expand on it through scripts, with all the methods checking to see if a script is overriding it. You might add various special cases to the methods in the core system, but you can't add special cases to the methods in the script. Your game rules end up divided in core rules and exceptions. I want to be able to define exceptions to the exceptions if necessary.
 

Fowyr

Arcane
Vatnik
Joined
Mar 29, 2009
Messages
7,671
Interesting. The firstly I was wondering, why you starting invent bycicle, when procedural language with OOP support is enough for your needs, and when I understand. You need script language for easy modability and changing of rules. Hm. Conception looks for me solid enough. The only thing what l may propose, you need several special debugging tools, what will search for every predicate, referring to particular object and so on. With good debugger this may work. Without - you will tangle in the web of predicates/objects/methods, jumping back and forth, and will crave for language, where you add one string in Undead.Loss_of_Hits(damage,type,source) method and mummies start to writhe in fire.
Hope this helps. Not very bright I am.
 

Castanova

Prophet
Joined
Jan 11, 2006
Messages
2,949
Location
The White Visitation
Interesting concept. I do have to ask though - under what circumstance are you programming a game where you need such efficiency in modifying game rules? Or are you envisioning the creation of some kind of base game engine and then using this language to generate a huge number of entirely different games over a relatively short period of time? I guess I could see the value there, to basically rip through a ton of game prototypes while trying to design a final product.
 

Alex

Arcane
Joined
Jun 14, 2007
Messages
8,754
Location
São Paulo - Brasil
@Fowyr

That is a good observation. Actually, this is the point of having predicates in first place, instead of simply having conditionals. By having predicates, we are able to view everything that relies on it, each method and special case is tightly bounded to one or more predicates. Therefore, it is easy to make a "predicate browser" that shows all information related to that predicate.

@Castanova

This is useful when you want to grow your game organically, or add new rules to an engine as you go along developing games in it (think of something like the gold-box games). For example, if I was going to make a 4X game like Master Of Magic, I could start small, with only a race, a magic color and a few spells. Then, I would be able to add in new elements one at a time, without much fear that something I want to do with one of the elements might require me to rework my entire system. Even radical changes are possible. You might, for example, have picking the starting race of orc changing the magic colors available to little Waaagh! and big Waaagh!, without having to think beforehand that picking a race might have such effect.

People, the link Kosmonaut posted helped me a lot. I will try to create a new description of the system that handles a bit more than the one I just proposed. It will probably be better written and there will also be figures, so if what I wrote didn't seem to make sense, hold on for a bit. However, if you can se problems or holes in the current system, or have any doubts, feel free to post now, as this will help me.
 

SCO

Arcane
In My Safe Space
Joined
Feb 3, 2009
Messages
16,320
Shadorwun: Hong Kong
Ĩs this a troll or something? Whoever hasn't programmed or heard on prolog in innumerable "Introduction to AI" shitty courses?
 

Alex

Arcane
Joined
Jun 14, 2007
Messages
8,754
Location
São Paulo - Brasil
Thanks for the link, SCO, but this isn't really what I had in mind. First, the language I am proposing isn't declarative, it is imperative. While the language I am proposing has predicates, they have a very different role than the one in Prolog.

In Prolog, you use predicates to determine methods. You set what a predicate means and the system somehow looks for an answer when you make questions based on those predicates. For example, I might say grandfather(X,Y) :- father(X, Z) & father(Z,Y). So, if you ask grandfather(X, SCO) would list all (presumably two) grandfathers of SCO that the system can find. From what I understand (I admit I have not much experience with it, so feel free to correct me if I am missing something), constraint logic programming is just regular logic programming with a few predicates defined over number properties, instead of over other predicates.

Now, what I am proposing has way less to do with predicates. What I am talking about is much more similar to object oriented programming, except instead of defining functionality over classes, it is defined over predicates. These "predicates" can be implemented in a variety of ways, including constraint logic programming. But they might as well (and, in a first version, probably would) be implemented with a simple boolean method from outside the system (or maybe from inside, if it could be done). By the way, by saying the method is from outside the system, I simply mean that it would not be affected by the rules the system is setting up for methods, such as special cases.

Anyway, independently of how predicates are implemented, their role is to aggregate methods and special cases. In oo languages, each object belongs to one and exactly one class. So, it is very easy and fast to find what methods apply to a object. What I am proposing has methods and special cases defined over predicates, which may not only be defined over one object, but also over any tuple. So, each object may have various predicates that apply to it specifically, and any tuple of objects would have even more so. This means that the system will be slower than a normal oo language, possibly much more so if I don't find a way to program this right, but I think that the closeness to how people thing about rules would make it worth the cost.

Anyway, sorry if I wasn't very clear on my first post. I will be posting about this again once I have worked out a few ideas Kosmonaut's link gave me. But feel free to comment meanwhile, specially if the above explanation didn't make sense.
 

Shemar

Educated
Joined
Oct 16, 2010
Messages
260
To be honest I don't see anything you describe that I could not easily (and pretty cleanly) do with C++ class inheritance and function pointers (which means that each creature object could have its own custom stats, attacks, damage functions even if they all are derived form the same base class). In fact C++ class inheritance is exactly exception based logic. Every function that is not re-defined is derived from the base class, so you re-define just the exceptions and inherit everything else.

Unless you are looking to create an end user scripting language or something of course and not a game programming language...
 

Flatlander

Liturgist
Joined
Aug 11, 2009
Messages
242
Location
Paradise Valley
Sounds like what you are talking about is multimethods with predicate dispatch. At least Clojure has those but it shouldn't be hard to implement with other Lisps either (for example CLOS already has multimethods and I guess the MOP could be used to implement predicate dispatch). Might look at those for ideas.

Edit: I think it's actually a good idea and I have been thinking about something similar (which of course ensures the ideas validity). But I still think there might be some problems with it and there might be better ways to achieve similar effects.
 

Alex

Arcane
Joined
Jun 14, 2007
Messages
8,754
Location
São Paulo - Brasil
@Shemar

If by scripting language you mean a second language running over a core on a primary one, then nope. My objective here is for a language where a game creator could easily design rules for his game. Though the language might or might not be pre-compiled (too early to tell how it would be better).

The problem with doing something like you said is that it works well... as long as the creature type is the only thing that really matters. It doesn't work so cleanly when you have extra rules in the form of "when a dwarf attacks a giant, roll in the dwarf rage roll for results" and then "when a green giant is attacked by a dwarf, roll in the green giant blunder table. Twice if it is a critical hit" and then even "when combat occurs over slippery floor, roll in the blunder table for both attacker and defender".

When these types of extra rules begin to appear, it becomes harder to make clear methods. You begin needing a lot of ifs and getters in the code to see if it fall in a specific situation because the inheritance logic is based on only one property of one object. You may try to go around the other properties of an object by using classes that know how to deal with things for each object, so you might have a "race" class that is able to execute methods that run differently for each race. But again, this only works if you know beforehand which methods are going to use race, and it is kind of a sticky situation if more than one of these objects might interfere in the same method.

Another solution is to use an observer, where various objects inside a character "observe" the methods called on the character and possibly call their own modifications, so you might have the dwarf object observe the character object, and if a call for getConstitution was made, it could intercept it and add 2 to the result. This might work well, but only if the objects don't need to work together. For example, a orc mage might have a lot of little specific rules that aren't in either or or mage.

My objective then is to capture the rules one might use when creating a PnP RPG in a simple and intuitive way. I don`t know yet if this idea is able to do it, but I think it might at least be a step forward.
 

Alex

Arcane
Joined
Jun 14, 2007
Messages
8,754
Location
São Paulo - Brasil
@Flatlander:

This is pretty close, except I want my special cases to work with other special cases, not simply for the system to chose one. So, if two special cases apply, by default, they should both be applied. For example, a character might have a +1 to his strength because he is an orc and another +1 because he was born under the lion sign. Then I want both special cases to apply. But I also want special cases to be able to "deactivate" other special cases when necessary. So, using an example from Kosmonaut's link, in an IF game, when it is dark, most actions should be canceled (trumping almost any other special case) and the message "It is too dark to see" should be shown.

But thanks for the heads up. I was going to look into look into lisp like languages and Haskell during the holidays, so knowing that some of them have predicate dispatch helps a lot. Do you know what Clojure (or other lisp-likes) does when more than one predicate applies in predicate dispatch?
 

Shemar

Educated
Joined
Oct 16, 2010
Messages
260
Alex said:
@Shemar

The problem with doing something like you said is that it works well... as long as the creature type is the only thing that really matters. It doesn't work so cleanly when you have extra rules in the form of "when a dwarf attacks a giant, roll in the dwarf rage roll for results" and then "when a green giant is attacked by a dwarf, roll in the green giant blunder table. Twice if it is a critical hit" and then even "when combat occurs over slippery floor, roll in the blunder table for both attacker and defender".

Well, no matter how you slice it you will need code that says "if the attacker is X do A" and "if the defender is Y do B" and "if the attacker is X and the defender is Y do C". In my opinion if you try to 'facilitate' that in a meta-language you will most likely remove flexibility rather than add it.

To go a little more specifically any Attack function should include a pointer to the defending creature so it will have access to all its stats and preditates. The dwarf attack function would be somethng like:

- Check this specific dwarf's predicates to see if they match any of the attacked creature's. If yes, perform the specialized attack otherwise pass to the 'generic dwarf' attack function.
- The generic dwarf function will also check if there is a match between the generic dwarf predicates and the attacked creature and if yes activate the specific attack, otherwise pass to the generic creature to creature attack.
- Generic creature attack

That way you do not have a huge "if" function for all possible preditaes for all possible creatures; it is broken down to the specific exceptions for the specific creatures (or creature groups) and is very easily extendable because each new exception is a new function that just passes over to the immediately higher level if the exception does not apply.

And you are not limited in how many such levels to use. You could do this if you want:

Creature
Humanoid
Dwarf
Mountain Dwarf
Mountain Dwarf Footman

where each level inherits everything from above and can overwrite any of the above functionality with more specialized one, but still fall back to the more generic functiuonality if the special cases do not apply.

Edit: By scripting I meant a language that runs on top of the game engine and does not compile into the executable, so it is available to the end users of the product, not just the developers. I take it that is not your goal.
 

Flatlander

Liturgist
Joined
Aug 11, 2009
Messages
242
Location
Paradise Valley
Alex said:
Another solution is to use an observer, where various objects inside a character "observe" the methods called on the character and possibly call their own modifications, so you might have the dwarf object observe the character object, and if a call for getConstitution was made, it could intercept it and add 2 to the result. This might work well, but only if the objects don't need to work together. For example, a orc mage might have a lot of little specific rules that aren't in either or or mage.
That's basically how the CLOS is usually used. You define multimethods which can be specialized on all their arguments (not by just the "self" argument) and you can define additional specifiers to the method (the usual ones being after/before/around methods) which control how the actual generic function works. Common technique is to define mixin classes through multiple inheritance which then modify the generic functions behaviour.

It's functionally a bit like reversed component based system, which is of course something that could also be used for something like this.
 

Flatlander

Liturgist
Joined
Aug 11, 2009
Messages
242
Location
Paradise Valley
Alex said:
@Flatlander:

This is pretty close, except I want my special cases to work with other special cases, not simply for the system to chose one. So, if two special cases apply, by default, they should both be applied. For example, a character might have a +1 to his strength because he is an orc and another +1 because he was born under the lion sign. Then I want both special cases to apply. But I also want special cases to be able to "deactivate" other special cases when necessary. So, using an example from Kosmonaut's link, in an IF game, when it is dark, most actions should be canceled (trumping almost any other special case) and the message "It is too dark to see" should be shown.
The first one is exactly the kind of thing that can be readily done with Common Lisp Object System.

You define a Strong mixin class (think of it as an empty, abstract class). Then you define an "around" getStats (or getStr or whatever) method specialized to the Strong class that returns the super methods (Edit: including possibly other "around" methods, they get all called in reverse order) value +1. The actual Orc class would then be defined just by inheriting from Creature, Strong, Stupid etc. where the Creature would be the actual base class and the rest just mixins. Most of the creatures special properties (the adjectives) would come from the mixin classeses.

As CLOS doesn't have predicate dispatch out the box that would still need to be added (through the meta object protocol) to achieve the rest of what you described. That's actually something I have been planning sometimes but never bothered trying.

Do you know what Clojure (or other lisp-likes) does when more than one predicate applies in predicate dispatch?
That is one of the problems with predicate dispatch. I think Clojure (I'm not that familiar with it and it has been evolving quite fast lately) has some added functionality/hacks to define the order in conflicting cases. Like I said, CL (or other non-Clojure Lisps that I'm aware of) doesn't have predicate dispatch out the box so it would be up to developer to decide.
 

Alex

Arcane
Joined
Jun 14, 2007
Messages
8,754
Location
São Paulo - Brasil
Shemar said:
Well, no matter how you slice it you will need code that says "if the attacker is X do A" and "if the defender is Y do B" and "if the attacker is X and the defender is Y do C". In my opinion if you try to 'facilitate' that in a meta-language you will most likely remove flexibility rather than add it.

Yes, the complexity is inherent to the system, but I think my way os slicing is better, at least for this case. By having predicates and methods and special cases relating to them, it becomes easier to visualize special cases. For example, if you want to deal with what is special about orcs, all you need to do is brows methods and special cases with the orc predicate.

Shemar said:
To go a little more specifically any Attack function should include a pointer to the defending creature so it will have access to all its stats and preditates. The dwarf attack function would be somethng like:

- Check this specific dwarf's predicates to see if they match any of the attacked creature's. If yes, perform the specialized attack otherwise pass to the 'generic dwarf' attack function.
- The generic dwarf function will also check if there is a match between the generic dwarf predicates and the attacked creature and if yes activate the specific attack, otherwise pass to the generic creature to creature attack.
- Generic creature attack

That way you do not have a huge "if" function for all possible preditaes for all possible creatures; it is broken down to the specific exceptions for the specific creatures (or creature groups) and is very easily extendable because each new exception is a new function that just passes over to the immediately higher level if the exception does not apply.

And you are not limited in how many such levels to use. You could do this if you want:

Creature
Humanoid
Dwarf
Mountain Dwarf
Mountain Dwarf Footman

where each level inherits everything from above and can overwrite any of the above functionality with more specialized one, but still fall back to the more generic functiuonality if the special cases do not apply.

If I understand you well, this is a class hierarchy with dispatching done by hand on cases where more than one class needs to interfere. This can work, but the dispatching logic can get pretty annoying and cluttered if it begins to grow, possibly because there isn't any clear class responsible for the method. For example, who is the primary responsible for attacking? Race, class, weapon or what? I think the way I proposed can help in these cases, and thus help developers explore new rules in a easier way.

Shemar said:
Edit: By scripting I meant a language that runs on top of the game engine and does not compile into the executable, so it is available to the end users of the product, not just the developers. I take it that is not your goal.

Well, I am a big fan of the smalltalk language, so if the language could be altered from within at run time, all the better! But right now this isn't a concern. The only restriction I am putting is that the language should be able to run by itself. If it would use editable scripts and be called from inside another language through a dynamic library or something is a little too early to think about, I think.
 

Flatlander

Liturgist
Joined
Aug 11, 2009
Messages
242
Location
Paradise Valley
Alex said:
Well, I am a big fan of the smalltalk language
:love:
I'm strongly of the opinion that if the main language is expressive and fast enough (a lot of high level languages actually are) you don't really need a separate scripting language. The less you mix different languages with different semantics the better.
 

Shemar

Educated
Joined
Oct 16, 2010
Messages
260
Alex said:
If I understand you well, this is a class hierarchy with dispatching done by hand on cases where more than one class needs to interfere. This can work, but the dispatching logic can get pretty annoying and cluttered if it begins to grow, possibly because there isn't any clear class responsible for the method. For example, who is the primary responsible for attacking? Race, class, weapon or what? I think the way I proposed can help in these cases, and thus help developers explore new rules in a easier way.

C++ allows for multiple inheritance so your Dwarf Fighter may be a class derived from both the Fighter class and the Dwarf class. Most of the functionality I describe happens automatically by the language. Whether the generic Dwarf, or the Generic Fighter attack would be at the top level is up to the programmer (in most rulesets it is the class that defines the basic attack modes), but the point is that all the rules/exceptions applied to a dwarf and all the rules/exceptions applied to the fighter would be automatically inherited by a class derived from both the base classes.

Basically what you are describing is a big table of exceptions which while doable would mean that the program would have to check through all the possible exceptions for every single action or calculation. That is extremly wasteful. In addition you would have to manually manage 'exceptions to exceptions'. Object hierarchy can manage this in a much more efficient way.
 

Alex

Arcane
Joined
Jun 14, 2007
Messages
8,754
Location
São Paulo - Brasil
@Flatlander

What you described in the CLOS is almost exactly what I tried to implement in Smalltalk at the beginning of the year. I tried to implement this as the decorator pattern, but it wasn't pretty when I realized I sometimes might want the unmodified values and sometimes I wanted the real values.

@Shemar

I may be very wrong here, but I think it is possible to restrict the special cases that apply to any single method before method invocation (at least if I create the predicates smartly enough) and what is the optimal order to test them. This means that the rules should run as quickly (asymptotically speaking) as if they were written by hand. There will be an overhead for all methods, but this may be set off by the fact that rule calculation is hardly as costly as other parts of the game, such as graphics or sound.

By the way, I don`t think that multiple inheritance alone can solve the problem. Well, it can solve a lot of the rules, but a few predicates aren't inherent about the object, just circumstantial. Stuff like "are you over forested terrain" or "is this an important battle". So, these would need to still be checked separated in each function.

By the way, I have about the C++ multiple inheritance. Do I need to declare each possible combination of classes in the source code, or is it possible to create them dynamically? Like, if I have a Dwarf class and a warrior class and I want to create a warrior dwarf, do I need to create a class that inherits from both by hand? I think I read about a way using generics to create the class on the spot, but I think they still needed to be created during compile time.
 

Flatlander

Liturgist
Joined
Aug 11, 2009
Messages
242
Location
Paradise Valley
Alex said:
First, the language I am proposing isn't declarative, it is imperative. While the language I am proposing has predicates, they have a very different role than the one in Prolog.

In Prolog, you use predicates to determine methods. You set what a predicate means and the system somehow looks for an answer when you make questions based on those predicates. For example, I might say grandfather(X,Y) :- father(X, Z) & father(Z,Y). So, if you ask grandfather(X, SCO) would list all (presumably two) grandfathers of SCO that the system can find. From what I understand (I admit I have not much experience with it, so feel free to correct me if I am missing something), constraint logic programming is just regular logic programming with a few predicates defined over number properties, instead of over other predicates.
Prolog isn't purely declarative as predicates can have imperative parts. Which, I think, means that it isn't necessarily that far from what you are looking for. Maybe have a closer look at it and see what you would need to "fix" in it. At least some of you examples can be conveniently expressed in regular Prolog.

I don't know if you would need a full logic programming language with backtracking and all but I think it is important to have the ability to easily define the predicates in the same language, you know, for composability.
 

Alex

Arcane
Joined
Jun 14, 2007
Messages
8,754
Location
São Paulo - Brasil
I haven't used Prolog nearly as much as I wished to, but I think that at the very least the logic would need to support defeasible logic, or else I wouldn't be able to state special cases as, well, special cases. Considering how many prolog extensions there are, maybe there is something like that I could use to make a mock up of my idea, though.
 

SCO

Arcane
In My Safe Space
Joined
Feb 3, 2009
Messages
16,320
Shadorwun: Hong Kong
Alex said:
@Flatlander:

This is pretty close, except I want my special cases to work with other special cases, not simply for the system to chose one. So, if two special cases apply, by default, they should both be applied. For example, a character might have a +1 to his strength because he is an orc and another +1 because he was born under the lion sign. Then I want both special cases to apply. But I also want special cases to be able to "deactivate" other special cases when necessary. So, using an example from Kosmonaut's link, in an IF game, when it is dark, most actions should be canceled (trumping almost any other special case) and the message "It is too dark to see" should be shown.

Transitivity and precedence problems naturally follow (eg: infinite cycles and different order of execution giving different results), but they are implicit not explicit if a order of application is chosen by default (prolog is like that i guess).

Sounds like you are trying to conceptualize a arithmetic of game rules. (something i think is quite crazy, but potentially useful, like "the compiler says NO" to your incomplete/ambiguous rules)
 

Shemar

Educated
Joined
Oct 16, 2010
Messages
260
Double Post
 

As an Amazon Associate, rpgcodex.net earns from qualifying purchases.
Back
Top Bottom