Crisis of Faith



  • So I read this.

    It has sequels, and it all seems very reasonable and so on and so forth and by the end I became quite convinced the appropriate way to model wizards, warriors, werewolves, and the various attacks between and among them and their equipment was with a completely new domain-specific language. Or just redevelop inform 7.

    The whole point of developing a class system is to catch wizards holding swords at compile time (I think that was what he said) but in a rule system there are no compile time rule enforcements, unless you compile your rule system that then compiles the DSL or something stupid and insane.

    Am I falling prey to the inner-platform effect or just misled or missing some detail or is it just "yes you have to navigate between those extremes, that's why it's a job"?



  • @AyGeePlus I wouldn't refactor stuff like "a wizard can't use swords" until you've 100% determined it's actually a problem.

    In the meantime, just make parent classes like, "BladedWeapon, Axe, Wand, Staff", and have the wizard class keep a list of types it's not allowed to use, then check the list of types against the weapon's parent type when the player attempts to equip it.


    LET'S SEE IF I CAN POST TO THIS GARBAGE PIECE OF SHIT FORUM WHICH IS UTTER ASS WITHOUT IT CRASHING FOR FUCKING ONCE YOUR SOFTWARE IS SHITTY GARBAGE NODEBB DEVELOPERS!!!!!



  • It also might help to remember that some of the greatest RPGs of all time, including the Wizardry series (well, except perhaps the last one), were written in languages that had barely any types at all. And Wizardry had multi-classing, it had restricted weapon and armor types, it had all the goodness.

    Just because you can't translate your intent into the type system doesn't mean you can't or shouldn't implement it.


  • area_can

    @blakeyrat said in Crisis of Faith:

    LET'S SEE IF I CAN POST TO THIS GARBAGE PIECE OF SHIT FORUM WHICH IS UTTER ASS WITHOUT IT CRASHING FOR FUCKING ONCE

    ?



  • I haven't read the article, but it sounds like a bad idea to abuse the type system to enforce business logic.


  • kills Dumbledore

    @AyGeePlus said in Crisis of Faith:

    The whole point of developing a class system is to catch wizards holding swords at compile time (I think that was what he said) but in a rule system there are no compile time rule enforcements, unless you compile your rule system that then compiles the DSL or something stupid and insane.

    The point is that compile time resolution of what amount to rules isn't possible, and that exception based handling also isn't nice. Having the rules engine means that the command wizard equips sword always returns successfully after doing whatever the rules say is the result of the action. In this case it might be wizard cuts his hand, drops the sword and goes back to his staff, but if the wizard later gets the hold a sword by the right end feat, the result will be wizard equips the sword.

    None of the objects encode the rules of what they're allowed to do, that's handled in the new rules class. You don't get compile time resolution, but that's OK because breaking the rules just gives you a bad or empty action.



  • @Jaloopa could just have a minimum of str and dex to use a sword and not enforce it by classes, it would be more realistic


  • Winner of the 2016 Presidential Election

    @Jaloopa said in Crisis of Faith:

    None of the objects encode the rules of what they're allowed to do

    I think that might be a good idea regardless of whether you want to build a complicated rules engine or not. I can imagine that trying to encode the rules of the game in the objects leads to incomprehensible code in the long term, because you're splitting logic into hundreds of classes, more or less arbitrarily. (Does the weapon or player know which combinations work? etc.)

    Making the domain objects pretty lightweight and putting the game logic elsewhere just seems like the right thing to do from a SW engineering perspective.



  • @Jaloopa So instead of moving inter-object interaction into one of the objects and relying on multiple dispatch semantics to control resolution you control resolution explicitly with the rules engine.

    On the one hand yay how clean, on the other hand wtf you have to make a new DSL to express your rules, and you know someone's going to add conditionals and functions and now you have a language inside a language.



  • As long as your rules are syntax checked and possibly checked for semantic errors at some point during the build, it doesn't matter if they're interpreted in the final product or part of the code.


  • kills Dumbledore

    @AyGeePlus said in Crisis of Faith:

    on the other hand wtf you have to make a new DSL to express your rules, and you know someone's going to add conditionals and functions and now you have a language inside a language

    Not necessarily, depends how complicated you want to allow the rules to get? You could do a basic rules engine with a DLL exposing a handful of methods, or you could put on your complicator's gloves and inner platform the fuck out of it. You'd probably want something in the middle depending on what the rules actually do.

    I'd probably do something like call an action with initiator, target, and some collection of relevant objects/modifiers. The rules would have conditions (for action equip weapon, if initiator is wizard and target is sword, perform this outcome. Another rule says if the initiator has the sword training perk modifier we have this different outcome) Some sort of ranking of rules so the perk outweighs the class and you're done. This could be stored in a db quite easily.



  • I'm freaked out by the DSL advice, because it seems so reasonable but
    wizbonk = Attack(attacked=wizard,defender=werewolf) ;
    wizbonk.resolve();

    Seems better. That .resolve() method is going to get really long, and I guess that would be how you would call into the rules engine anyway.

    I'm having a hard time seeing how a DSL is ever a good idea. For a game engine, maybe? Or for a new problem space? Someone had to write XML the first time?


  • kills Dumbledore

    @AyGeePlus said in Crisis of Faith:

    I'm having a hard time seeing how a DSL is ever a good idea.

    Probably similar to NoSQL. For most people it isn't and if you need to ask it isn't. But occasionally it is and nothing else will do


  • I survived the hour long Uno hand

    @AyGeePlus You're overthinking it. I mean, this is tidier:

    ActionEngine.resolve(action=attack, actor=wizard, actee=werewolf)
    

    Because all your business logic lives in one spot, where it's easily tested, easily updated, easily maintained. It's very DRY. The only way that resolve() throws is if there's absolutely no way it can possible resolve the action due to a fundamental error in the program; attempting to do illegal actions within the game's framework just gets a resolution of "denied" and the program chugs on. That much is 100% solid, right?

    So then you sit down to write this rules engine, this action resolver that has a bunch of rules and needs to resolve actions based on the rules. And the rules are mutable; you'll want to be able to tweak things as you go. So it makes sense to put the rules in data, and the resolver just applies them in a generic manner. I've never written a game, but I've been on a project where we had to do that; we used database rows to encapsulate business rules like this.

    That's all the article's talking about. At the end, it discusses a few ways in which the rules can be persisted. If it makes sense to do so, you can put them in a database like we did, maybe with an admin screen to change them. If it makes more sense, you can create a DSL so that people who do not understand programming can learn the DSL and write rules for you; their expertise is game balance and design, not programming, so they can focus on the game balance and design and never touch code. But it's not always the case that a DSL is better than database rows for this.

    Think of it this way: in webdev, CSS is a DSL for tweaking the way a page looks without changing how it works. Now you can have web devs and web designers and they can specialize in different things without having to learn each others' crafts. That's all.


  • Discourse touched me in a no-no place

    @AyGeePlus said in Crisis of Faith:

    That .resolve() method is going to get really long

    That resolve() method is the core of the logic that makes the game interesting, and it may well be entangled into all sorts of things. However, it's the part that actually matters to the software: it's the freaking business logic. The type system isn't that. It's just there to help you describe what the current state of the world is, what the actions that players and NPCs wish to perform are, and what the outcomes of those actions are. Putting the business logic into the type system just makes the type system as complicated as the business logic, and that just makes everyone unhappy as it spreads the complexity much more widely.

    The whole point of the series is “stop trying to get the type system to do everything for you; some things don't belong there”.


  • Winner of the 2016 Presidential Election

    @dkf said in Crisis of Faith:

    The whole point of the series is “stop trying to get the type system to do everything for you; some things don't belong there”.

    INB4 flamewar with Haskell enthusiasts 🍿


  • Discourse touched me in a no-no place

    @asdf said in Crisis of Faith:

    INB4 flamewar with Haskell enthusiasts

    They already know the fundamental truth (or should): if you make your type decidability algorithm turing-complete, you've not really gained all that much.


  • Winner of the 2016 Presidential Election

    @dkf OK, that's pretty obvious. Even those who program in languages with a turing-complete type system (C++ or Scala) won't disagree. Your original statement was a bit different.


  • Discourse touched me in a no-no place

    @asdf said in Crisis of Faith:

    Your original statement was a bit different.

    You think so? Hmm…



  • @dkf said in Crisis of Faith:

    The whole point of the series is “stop trying to get the type system to do everything for you; some things don't belong there”.

    The weird part is that more or less throws out polymorphism, doesn't it? Polymorphism is using the type system to track business objects otherwise what is it good for?

    And if you implement your own type system or system of type membership or whatever for keeping track of what BusinessObject() actually represents you're just rewriting Erlang, kind of. Inside your application.


  • Winner of the 2016 Presidential Election

    @dkf I was mostly 🚎 ing, but your initial statement was a bit vague. There are definitely grey areas: Should a type system enforce thread safety and exclusive ownership (Rust)? Are algebraic data types a good idea in an object-oriented language? Etc.


  • Discourse touched me in a no-no place

    @asdf said in Crisis of Faith:

    There are definitely grey areas

    Yes, but you either resolve them by leaving things lax, or by restricting yourself from certain actions that are actually safe, or you make your type system impossibly complicated and your compiler really annoying. The point of a type system is that it reduces the scope for errors in a way that is simpler to work with than the main logic of the program. People have done things with dependent types to allow more of the gnarliness of reality to be captured, but it turns out to not help that much. Heck, even with the severely restricted form of generic types that the JVM has (not even as sophisticated as that of the .NET ecosystem) you can get into a horrible mess.

    I've seen some really nasty code written by my colleagues. They loved their complicated types, but the result was really annoying to code against.



  • @AyGeePlus said in Crisis of Faith:

    The weird part is that more or less throws out polymorphism, doesn't it? Polymorphism is using the type system to track business objects otherwise what is it good for?

    Polymorphism is a polymorphism word that is polymorphism popular with polymorphism universities. Polymorphism.

    As far as I'm concerned, if you take anything other than a minimal approach to it, the absolute minimum you can get away with, the better. While there are certainly cases where inheritance beats out having a reference, it takes an enormous amount of thought to do it remotely well.

    This all sounds like I never want anyone to implement or inherit anything ever, but it's really just a kneejerk reaction to what looks like 'wont somebody think of the polymorphism?' - and likely a result of inheritance being the one tool they gave us in uni in nz: not even a very well built hammer,


  • Discourse touched me in a no-no place

    @Magus said in Crisis of Faith:

    it takes an enormous amount of thought to do it remotely well

    Composition and delegation are easier to use.


Log in to reply