4 ms·
Wizards and warriors, part five
- archimedespi 11y agoNice approach; this is a common sort of dilemma for API design.
- Retra 11y agoThis seems to me to be a classic example of poorly implementing first-class functions in an OO language to solve a simple problem. Or rather, this solution bestows a level of needless complexity and jargon that would make a LISPer cry. As soon as you want to start encoding "rules" for "encoding the allowed transformations of your data," then congratulations, you've invented something called a "function." Functions are rules for expressing what you are allowed to do. fn wield(Wizard, Wand) // Wizards can wield wands. fn wield(Warrior, Sword) // Warriors can wield swords. fn capability(Player, wield_fn=wield(Player, Weapon)) // Players can wield weapons. Now there's no way to violate these rules unless your users can compile functions and pass them into your code. >There is no need to figure out “which class does the rule about paladins vs werewolves go in?” The rule goes in a rulebook, end of story. Like I said, Inform7 is amazing. I've never seen someone so impressed by global functions before.
- Guvante 11y agoWhat language would that work in? C# only does compile time dispatch of overloaded methods and Common LISP doesn't have overloaded methods at all. I honestly can't think of a language that even support overloading of methods based on run time types. And the moment you don't have overloaded methods based on run time types you have to do something interesting like this to do the work.
- ajuc 11y ago> I honestly can't think of a language that even support overloading of methods based on run time types. Clojure does with multimethods ( http://clojure.org/runtime_polymorphism http://clojure.org/runtime_polymorphism ). I suspect lisp with meta object protocol does too, but I only heard about it, so can't confirm. EDIT: deleted my solution that worked without method overloading at all, cause I missed some constraints.
- ajuc 11y agoJust an example: (derive ::wizard ::person) (derive ::warior ::person) (derive ::weapon ::thing) (derive ::dagger ::weapon) (derive ::sword ::weapon) (derive ::staff ::weapon) ;; defines dispatch function that returns (inheritable) categories to dispath ;; it's very simple in this case (defmulti wield! (fn [p1 p2 thing] [(type p2) (type thing)])) (defmethod wield! [::person ::thing] [p1 p2 thing] (say! p1 p2 " refuse")) (defmethod wield! [::person ::dagger] [p1 p2 thing] (take! p2 p1 thing) (say! p1 p2 "accepts.")) (defmethod wield! [::wizard ::staff] [p1 p2 thing] (take! p2 p1 thing) (say! p1 p2 " gladly accepts.")) (defmethod wield! [::warrior ::sword] [p1 p2 thing] (take! p2 p1 thing) (say! p1 p2 " gladly accepts.")) It obviously could be done in half the lines without using multimethods, but the result would be much less extensible. BTW, with just 2 lines you can add gandalf and it just works (because there are no conflicting methods right now). (derive ::gandalf ::wizard) (derive ::gandalf ::warrior) If there were any - you can set preferences to avoid errors.
- junke 11y agoStrictly speaking, yes, there are no method overloading in Common Lisp. On the other hand, you have optional arguments and generic functions. Now, what happens when a vampire or a werewolf bites a warrior? Here is a rough sketch: http://pastebin.com/raw.php?i=Uu7fAx6p http://pastebin.com/raw.php?i=Uu7fAx6p
- junke 11y agoOf course, metamorphosis should happen only once: (unless (typep target 'werewolf) (with-scheduling ...))
- gpderetta 11y agoSurprisingly, C# does natively support multimethods, thanks to 'dynamic'.
- BruceM 11y agoDylan (http://opendylan.org/ http://opendylan.org/) does that via generic functions / multiple dispatch. The object system in Dylan is derived from CLOS from Common Lisp. Dylan allows sealing of generic functions to limit extensibility where needed and can use that information (along with other information) to optimize, generate warnings, etc. define class <weapon> (<object>) end; define class <sword> (<weapon>) end; define class <wand> (<weapon>) end; define class <person> (<object>) end; define class <wizard> (<person>) end; define class <warrior> (<person>) end; define method wield (who :: <wizard>, what :: <wand>) => () ... end; define method wield (who :: <warrior>, what :: <sword>) => () ... end;
- dbpokorny 11y agoA wild UC Berkeley CS 61A adventure appears! https://inst.eecs.berkeley.edu/~cs61a/su13/lab/lab06a/lab06a.txt https://inst.eecs.berkeley.edu/~cs61a/su13/lab/lab06a/lab06a... You can stick your pseudocode into the "give" function: https://inst.eecs.berkeley.edu/~cs61a/sp15/lab/lab10/adventure.py https://inst.eecs.berkeley.edu/~cs61a/sp15/lab/lab10/adventu... I'm not sure it's explicit in the original article, but I tend to agree with the sentiment that it's a lot more fun to learn about interpreters and databases when you're making games rather than corporate infrastructure (although I can't deny that building corporate infrastructure has its moments) Joel Spolsky talks about using the compiler to catch errors on p. 68 of "The Best Software Writing I" https://books.google.com/books?id=vPvhzDqZlaAC&pg=PA68&lpg=PA68&dq=joel+spolsky+type+compiler&source=bl&ots=cm2hRdP9W5&sig=I3gcA35aUfqoKCcQoiIm-CM6CvY&hl=en&sa=X&ved=0CFUQ6AEwCGoVChMI2YzG6KSUyQIVBcNjCh1oQAcK#v=onepage&q=joel%20spolsky%20type%20compiler&f=false https://books.google.com/books?id=vPvhzDqZlaAC&pg=PA68&lpg=P...
- askafriend 11y agoFor anyone else who got excited about basketball...this isn't about the NBA :(
- inglor 11y agoI don't understand this post at all. He started with wanting compile time validation of the invariant ("A wizard cannot wield a sword") - then talked about how runtime solutions were not good and then ended up with a solution that does not verify that invariant in compile time at all. He just ended up with a language where all code is written in a specific language programmers have to learn and errors are in another language. The generic constraint solution he had in the middle (part 2) was actually pretty decent because hey: if Wizards and Warriors can't yield the same weapons - and the weapon is a property of the supertype then __they are not interchangeable as players__. You need a different interface.