Or at least a set of engine-framework-commons-utils.
There have been a few games and simulations in Clojure before, a few notable ones:
The grandmother of all Clojure games is probably ants.clj by Rich himself, mostly a demonstration of concurrency in Clojure.
Ironclad is a game that deserves to be noted for its completeness; It's more than just an example.
And finally, this unnamed(and likely unfinished as well) RPG, not so much for the game as for the blog post that describes the process of writing it.
Just like Brian, I went through the process of agents and OpenGL, but let us begin with the begin.
It's as simple as that. A nice and simple 2D game in Clojure. I started googling for game engines in Java and Clojure. The only ones I found that I liked and that did not look like they came from a past century where Slick and PulpCore.
Problem is, I did not even manage to compile Slick, and PulpCore is for applets only. Besides, they both use very OOP models that I suppose would feel awkward in Clojure.
So after reading a few opinions about Swing vs OpenGL, I decided to write my own game in Clojure based on Swing.
My initial design philosophy was very simple. It should be
So I set up an agent with a vector, made a Swing frame and overwrote its paintComponent to draw the objects in the vector to the frame.
Then I added a watcher to the agent to mark all changed objects dirty on the Swing frame, so they would be redrawn.
Okay, which object changed? Hard to tell. I turned the vector into a map, a set, and a map again, so that I could use clojure.set/difference to tell what happened.
Wait, we need collision detection. Simple, right?
Doing this the naive way would mean a quadratical increase in comparisons. I was well on my way implementing a quad tree when it hit me: For any non-huge number of objects, it's not worth the trouble.
I changed whatever I had at that moment into a sorted variant, so that I only had to check objects that where at least close in one dimension.
At this moment I had changed every single line of code around 3 times. I had atoms, refs and agents, containing vectors, sets, maps, calling multimethods and protocols, I was knee-deep in thread pools and transactions when I remembered my second 2 goals.
This beautiful, concurrent, asynchronous design that I had was just not functional and easy at all. It had mutable state and transactions everywhere.
After a few more sidetracks, I switched to active rendering and reduced my game loop to something like this pseudo-code.
After all this theorizing and experimenting, I finally got my stuff stable enough to actually write a little game; pong.
Let me say this about it: Few lines of the original pong game and my engine where left unchanged, but they where more subtle changes than before.
Next, I wrote a simple platform game. Again, changes where made.
I feel like what I have now is nearly ready to share with the world. I do believe that an event, or message processing based system could work, but what I have now does so too.
Begame currently provides:
Upon reading the Prolog chapter in Seven Languages in Seven Weeks, I wanted to attempt the Sudoku example in Logos.
I quickly found out that Logos had quite a few less helpers than Prolog. In Prolog, you just say fd_all_different on all the rows and columns, not so in Logos. Then I read fd_all_different is implemented as ≢'ing all elements. But then again, Logos does not yet support negation.
So rather than saying “a number can not be on the same row twice” I had to say “this row must contain all numbers from 1 to 9 once”. This is done in permutation-o.
The beauty of Logos and logic programming in general is that it allows you to tell the computer the data and the rules, instead of telling it what to do. You’d imagine this to be shorter as well. Furthermore, miniKanren is quite efficient, and Logos equally so.
So, how does this code compare to a regular Clojure version? To tell you the truth, not good. The plain Clojure version is both shorter and faster. By how much?
The Clojure code is just a tad shorter, but not significantly so. With pattern matching and negation in place(more on that later), I think the difference becomes negligible.
In speed, however, the difference is huge. The Clojure version can solve a Sudoku in a matter of seconds, I had to leave the Logos version running overnight. Truth be told, for smaller fields or very, very easy boards, Logos can do it in half a second as well. This is why most examples implement mini-sudoku.
There is light at the end of the tunnel though! A recent update to Logos adds pattern matching, which allows for a more Prolog-ish way to express relations.
Negation is also planned, which would make it a lot faster to express the relation the numbers in a Sudoku row have.
Last but not least, cond-a and cond-u will return, allowing me to cut away useless branches. Cond-a quits after the first match, rather than searching for alternate solutions.