https://thingspool.net/morsels/page-11.html (part 2)
https://thingspool.net/morsels/page-12.html (part 3)
https://thingspool.net/morsels/page-13.html (part 4)
https://thingspool.net/morsels/page-14.html (part 5)
(and keeps going!)
It will take me to read this book, but I love it! I'll be following along in https://github.com/mthom/scryer-prolog (written in Rust) so one should be able to take these techniques into Rust game programming.
The Youtube link is here: https://www.youtube.com/watch?v=QyMsF31NdNc&t=2354s
It seems like most rule-based stuff in games is just hand-coded, as it's relatively simple and doesn't need to be general. When I asked the author of Baba is You, if he implemented a datalog engine for it, he said 'no'. I suspect it's the same for Breath of the Wild.
But still, I've often wondered if that sort of chemistry engine would be best implemented in a logic language like Prolog or Datalog, for fast experimentation. Just like how we use SQL to keep the flexibility of our queries, and we end up just shipping that. I'm sure, back in the day, lots of people lamented how slow SQL queries were. The flexibility was useful enough that we ended up pouring man-centuries into making them fast. Now, we think that's just the way you ship things, and (almost) never think, "I can hand-roll imperative code that will be faster than this query".
It's one of the more interesting games I have ever played.
Here is someone using a (really complex) wand to beat the game in 2 seconds (some spoilers): https://youtu.be/YYTB5_zBANg?feature=shared&t=309
Also, probably, MUDs.
What graphical games are trying do to at something 'revolutionary' text games did that before 40 years ago with interactive fiction (more in the 90's with the reinassance of astounding amatur games such as Curses/Jigsaw/Anchorhead/Devours/Spider and Werb than the former Infocom games); roguelikes like Nethack/Slashem and CDDA:Bright Nights and online MUDs far beyond the usual fantasy settings, such as cyberpunk or scifi settings with weird materials and interactions.
The best game creators such as Warren Spector surely played with libre games/indie/geeky games too to bring new ideas to the gameplay.
I think referencing Nethack in the original Deus Ex wasn't just a happy easter egg, but a homage to the emergent gameplay probably inspired by it.
The best about Deus Ex weren't neither the graphics or lore, but what you could do in-game, breaking the linear settings on FPS' and making them accesible unlike System Shock 1 and 2, where they tried and failed because the game difficulty didn't scaled well and the gameplay wasn't as polished. Ditto with Arx Fatalix (now Libertatis) and Ultima Underworld.
The resolution algorithm(s) implemented by a general purpose logic programming or relational language are not the only ones possible, and being more general may not be efficient for the type of problem you want the game engine to solve efficiently. Conversely extending a logic programming language to natively include these features may invalidate simplifying assumptions or require a change in evaluation order that makes the language impossible to implement as simply or efficiently.
A concrete example (of extending logic programming with game specific features):
I wanted to both use logic programming relations and also linear constraints, so that you could say something like "A <= (B-10.0) .OR. B <= (A-10.0)" which you could picture as constraining the position of the centers of two width=10.0 game objects so that their boundaries do not overlap, but you don't care which is in front of the other. (Statements like this would be used to build up a scene or more complex game object qualitatively, without pinning down exact coordinates rather letting the linear constraint solver pick them.)
Since running the linear constraint solver to resolve something like "f(A) <= g(B)" actually (potentially) updates all of the interrelated variables (A or B might also have constraints against C,D,E,F), running it as soon as you pick the LHS or RHS of the logic expression "prop(X) .OR. prop(Y)" could potentially invalidate propositions elsewhere previously committed to. So what you probably want to do is, rather than interpreting the "<=" on linear variables as a test with a boolean result, interpret it as a command to add "f(A) <= g(B)" to the global store of linear constraints, and then at some later time run the solver on the complete matrix of linear variables.
That leads to design questions like how does the language know when it's done adding constraints and time to solve, what if we really do need a logic clause to depend on testing a value not constraining it, etc. But all of that's just a distraction from the real issue, which is that for the case of BOTH the linear constraint solving and the logic programming, in the context of a game engine we really need to have more control over both when lengthy computation is run and how long it runs.
That is, even if we design a good way for the extension features to run from the POV of the logic language, from the POV of the outer system we still have the problem of sometimes the search time to resolve part of a logic program blows up and it's difficult for the programmer to always predict when/where that will happen. In this sense it's not even required that hand-rolled imperative code be faster, it can be slower - as long as it's predictable.
And in reality you wouldn't even necessarily be hand-rolling it; what I'm talking about is whether the rules engine is a solver that is externally driven (and pre-emptible) by imperative game code, or the whole game runs within the "solver" (i.e. relational language). As tempting as it is to imagine what could be done if literally "the whole" game were relational, the fact is using that technology for a whole game implies a magic relation solver that doesn't actually exist.
But with Inform6, the OOP applied to game design and literal ingame objects' relation (as the ZMachine) states it's when the difficulty plummets down to the point to be trivial.
http://logicmazes.com/alice.html
alice.html:353 Uncaught TypeError: Cannot read properties of undefined (reading 'play')
at playSound (alice.html:353:30)
at finalize2 (alice.html:347:1)
at <anonymous>:1:1
Not sure if I'm missing anything, but nothing yet has been concerned with any kind of user interaction which would seem to be a pre-requisite for a game, although there was a brief discussion about sending messages so maybe that's what he was intending.
Adventures in Rule-Based Programming: A CLIPS Tutorial https://a.co/d/7wVOcZp
I personally experiment in Datascript as a gamestate db, but it's still quite an early attempt to conclude if it's a success. It's great seeing how ideas in this tutorial map 1-to-1 to that idea.
1. https://www.gamedevs.org/uploads/data-driven-game-object-sys...
I am still not clear whether there isn't a more succinct rule definition than what I have there. In the Stanford paper you have rules like:
(<= (column ?n ?x)
(true (cell 1 ?n ?x))
(true (cell 2 ?n ?x))
(true (cell 3 ?n ?x)))
But in Datascript I have to do much more rigmarole around shuffling the data around: [(column ?n ?x)
[?current "ident" "current"]
[?coord0 "type" "coord"]
[?coord1 "type" "coord"]
[?coord2 "type" "coord"]
[?coord0 "m" 0]
[?coord1 "m" 1]
[?coord2 "m" 2]
[?coord0 "n" ?n]
[?coord1 "n" ?n]
[?coord2 "n" ?n]
[?coord0 "name" ?key0] [?current ?key0 ?x]
[?coord1 "name" ?key1] [?current ?key1 ?x]
[?coord2 "name" ?key2] [?current ?key2 ?x]]
I don't know if this is down to Datascript/Datomic Datalog limitations or more the limitations of my understanding.How do you approach your experiments? If you have any of your work to share or some tips on what I am doing I'd be very interested.
[1]: https://www.cs.uic.edu/~hinrichs/papers/love2006general.pdf
Would you be able to recommend a Datalog implementation that allows independant n-ary relations. Ideally one I can use from Python or Javascript in a sort of sandboxed way, as I am doing with Datascript, but if you have any recommendation at all it would be helpful to me.
If you want to try something more exotic I would be tempted by https://logica.dev/ + some flavour of SQLite (potentially in-memory/WASM).
Bravo!
SQL: Postgres, SQLite, MySql, etc. all have different features. Prolog: SWI-Prolog, GNU Prolog, Scryer Prolog, etc. same thing.
It's true that Datalog is better for pure data querying. But there's no theoretical reason it couldn't be implemented in Prolog as well.
At first guess, I would imagine this could look like writing down known constraints on the solution as a kind of "type declaration".
Prolog's evaluator backtracks when it hits a conflict while trying to expand a predicate. It evaluates queries top-down, and tries predicate definitions/clauses in order. It's basically eager. This isn't a good fit for math, so CLPFD fixed this by making arithmetic constraints lazy. This works really well, but you're ultimately using Prolog to build a model, then (invisibly) solving the model separately.
Ultimately, the problem is that Prolog looks like a DSL but is Turing-complete. You can weave other solvers into the language, but there's a seam between the evaluators. I like the alternative, which is to sacrifice Prolog's Turing-completeness for a ridiculously powerful DSL. Answer Set Programming (clasp) and Datalog are fine examples of this.
Markus Triska has probably the best resources on modern Prolog.
Just search for "Power of Prolog" on YouTube or the internets.
I think you get access to their engine if you buy one of their games through steam and you can mess with Osiris (not sure if that's still true for BG3, but it was the case for Divinity: Original Sin).
Or any anecdotes from more experienced prologgers about the experience of writing a real game? At face value it looks like it would be very easy to accidentally tie yourself up in a knot of logical contradictions, but I guess there are tools in prolog land for debugging this kind of thing?
And what prolog implementation should one pick?
For good habits and a good introduction: https://www.metalevel.at/prolog
I like "Prolog Programming for Artificial Intelligence" as a great print book with interesting projects that is fairly modern but be warned that much of the code is not idiomatic, so please refer to the first resource if you are looking to write too quality stuff.
http://minikanren.org/ - MiniKanren, a different language in the same vein, small and embedded into lots of host languages.
https://microsoft.github.io/z3guide/docs/logic/intro/ - Z3, again a different language but hits many of the same areas and use cases along with plenty of others. Also usable as a library (probably how most people access it, often through Python).
SWI Prolog seems to use global state, which becomes no-no without using GILs and whatnot. Z3 I've use before in college, but it wasn't really a scripting tool, unless something changed in the meantime.
That being said, it seems to get quite convoluted when trying to introduce dynamism (i.e. time) to the system. I was about to wonder if a hybrid of functional and logic programming could address this, and then I remembered Verse [0] exists ;-)
[0]: https://github.com/UnrealVerseGuru/VerseProgrammingLanguage
Imagine if you can be in "dynamic mode" where you can add rules, facts, etc. in an adhoc way.
Then, once your game is better defined, you can compile the Prolog to native code so that it is highly optimized, executed in parallel, etc. The compiler could apply all sorts of optimizations we see in commercial game engines automatically.
This compiled object could then be embedded into a game engine with native performance.
Done right, this could even outperform imperative game engines, but be very easy to debug and modify.
That said, there's plenty of research in the DB world on precompiled and JITted query execution plans. All of that would apply to a Prolog or Datalog engine as well.
Also, a personal interest of mine I keep wanting to come back to is how much one can make use of GPU and TPU hardware to accelerate the joins that go on in these systems. There are people working in this space already: https://arxiv.org/html/2311.02206v3 but I believe their emphasis is on large scale data sets (e.g. big data graphs) whereas I'm curious to see if there's a way that an approach using HW acceleration could make low latency "OLTP" type applications possible for applications like robotics/vehicle autonomy/games, using complex rule sets.
I watch my son play Dwarf Fortress and I'm like... it needs a Prolog.
[0] https://en.wikipedia.org/wiki/Mercury_(programming_language)