Showing posts with label games. Show all posts
Showing posts with label games. Show all posts

Sunday, February 10, 2019

Rust helped me escape Cthulhu!

I just downloaded the game Lovecraft Quest on my Android tablet, and was enjoying the puzzles, until I got to the final one, and that got me, ahem, *frustrated*. I found a walk-through where the reviewers admitted to more or less clicking randomly on the screen for one hour until it worked:

I actually managed to solve the puzzle the first time quickly with sheer luck, but on the second run I was stumped. So I followed the only reasonable course of action: let the computer solve the puzzle for me!

The puzzle is as follows: there is a square (4 rows, 4 columns) of gold bars that can be either in horizontal or vertical position. You can make one bar pivot, but when you do that all the bars in the same row and column pivot too! You need to get all bars to the vertical position for the door to open to reveal... Cthulhu itself!

So let us use Rust for this puzzle, and see if a brute force approach can work. 
Let's first define a few types. A grid is a 4x4 array of booleans and a position is a tuple. We'll have positions ranging from (0,0) to (3,3). A grid is solved is all elements are true (so true means vertical position for a bar).
Then let's implement the swapping operation. We'll take one Grid reference and return a new Grid with the proper bars swapped.
Note that we swap again the position we chose since we swapped it twice already, one for the columns and once for the rows. Not very elegant maybe but simple

The main solving function is as follows: we're given a grid and we return a list of positions to swap to solve the puzzle. If the grid is already solved we return an empty vec. Otherwise we keep two structures: a map of grids to a vector of positions (showing how we got to that particular grid from the start grid) and a list of grids to process. We use a Deque here so we can put new grids at the end but process grids from the start, to do a breadth-first traversal of all possible grids.
The try_all function will do all possible swaps on the given grid and store all the results with the path used to get to them. We store for all grids the shortest path we used to get to it. New grids get added at the end of the todo list. We return the path if we end up with a winning grid.
To simplify calling the program, we'll just pass a string made of 16 characters, with 1s and 0s indicating the position of the bars we see on the screen. Parsing this string into a Grid instance is easy enough with the help of chunks():
And we can pass then that string as a argument to our binary program, and print the result:
In my case, the program ran and gave me the solution: only 12 moves!

This Rust code is probably fairly naive in places, since I only have a couple of weeks of evenings learning it. I'm not too happy with the number of clone() calls I had to add to make the borrow checker happy, on top of the ones I thought I needed anyway. Maybe immutable structures would in fact be easier to use here! Of course this code could be made parallel but since it gave me my answer in a few seconds I didn't need to improve it further.

Happy Rust Hacking!


Wednesday, December 03, 2014

Circling through ideas

I can't make my mind up about what to do in my free time (I have some, yes yes). I keep circling between the same ideas, thinking "that would be good", then jumping to the next one.

  • Keep on working on EclipseFP and other Haskell IDE related ideas. I would like for example to unify the storage of metadata between buildwrapper, scion-browser and eclipsefp, to have one database to would keep library information (definitions, documentations) like scion-browser, AST with types like buildwrapper, usage references like the usage DB in EclipseFP. It could be interesting to try to use that database to drive an IDE and have a clear repository of metadata. But then I'm tired of working on my own on EclipseFP, and when I see that Leksah really has also one active maintainer, I think people are really not interested in advancing Haskell IDEs, they must be happy with Emacs/vi and ghc-mod at a push, so why bother?
  • Then I think working on games is fun! I had fun writing Mazes of Monad, and other little games, and I do enjoy playing role playing or adventure games (I can really recommend the last one I've completed, the Longest Journey), so maybe writing a game the reactive way or even for Android like the guys at Keera Studios do would be a good use of my time. Then I remember I'm a programmer that sucks at graphics design and would probably suck as much at game design.
  • Games are too trivial, let's do something that will change the world, like work on AI! A few books I've read like Kurzweil's and Hawkins' have been truly inspirational, so maybe I could write some HMM neural temporal gizmo that would become sentient over night!! Then I wake up. People smarter than me and with more time than me are already working on that, so I would not contribute anything anyway. Why don't I help these people by providing a better programming experience, for example a Haskell IDE? Back to idea 1!
Ah well, I'll go back to browsing Reddit!

Thursday, November 28, 2013

Reactive-banana-SDL on Hackage!

I've uploaded to Hackage the reactive-banana-sdl library. This library was developed by R. Kyle Murphy(orclev), and I've just added a couple of functions and some documentation in the code. Orclev didn't want to maintain it anymore so I've taken the maintainer role, but I'm certainly not a FRP expert (in fact I started to use the library to learn about FRP), so be gentle...

I have a little typing game called TypeClass, which uses the library. You can have a look at the code, it may help you get started.

There's not that much there, but hopefully this can be of use to some people, and let me know what goodies we could add!

Happy Reactive SDL Hacking!

Friday, October 26, 2012

OpenAlchemist: the start of an AI in Haskell

Lately I've been quite addicted to OpenAlchemist, a Tetris-like game developed by I think a couple of French developers (cocorico!). The code is in C++, there doesn't seem to be a clear API to integrate with the engine, the forums are closed, but I still wanted to write an AI for the game..

So I've written a little something in Haskell and posted it on Github just in case it's of interest to somebody. I basically use the Win32 API to capture the game window and save it as a BMP, then I use the bmp library to open the BMP, and some home grown image recognition to see which shapes are displayed on the screen. Then comes the "easy" part, checking the possible combinations and seeing which one yields the higher score. So far the AI hasn't beaten my own high score, so there's still work to do!

I'm still struggling with shape recognition sometimes, so this is an area that needs an improvement. I probably need to read up a bit on the proper algorithms that people have found to do this kind of things instead of just writing my own, but hey, one needs to have fun!

Monday, April 18, 2011

Pirates 0.2: fixes and a chat interface

I released a little update to my Pirates Yesod/Canvas game. Nothing too dramatic, but the new version, still at http://pirates.dyndns-free.com boasts:

  • Fixes in the collision detection code
  • A chat interface, so you can talk to the other ship you're fighting with. Stock up on pirates insults!
  • Fixes in handling of games when a ship leaves the game before it's finished
As I said, nothing too fancy, but I find that polishing off bugs and adding unplanned features is often a good exercise, especially for personal projects where the temptation is great to just move to something else when it kinda works. The chat interface was interesting: the server side code was done in a few minutes, using the same event system as the rest, but I struggled longer with the HTML to get the right positions for everything, as usual... Now it's on the right hand side, outside of the canvas area, which makes the full game area much bigger than the original 800x600, but I don't think I get a lot of mobile users anyways (-;.

I could probably make the game more appealing long term by having a bigger area where more than 2 ships could battle, and have more of a RPG feel to it (maybe be able to log in and out so you keep your ship, be able to repair it in harbours, etc...). I'll see what I have time to do. Any suggestions welcome!

Friday, April 08, 2011

Pirates!! A multi-player browser game with Yesod and Canvas

I can finally open to the public a little game I've made! You can now go to http://pirates.dyndns-free.com and play!
The game is simple: you're sailing a pirate ship, and you have to sink your opponent. You can use cannons, ram the other ship, board it with your blood-thirsty crew. Your speed depends of course on the direction and strength of the wind. You can play alone versus a very dumb AI (mainly to get the hang of the controls), against a friend in a private game, or against any dog on the internet. 
The technology stack is as follows:

  • Hosting is on a free Amazon EC2 instance. Performance is probably not going to be great, but should be sufficient I hope for the traffic I'll be getting!
  • Server side is Yesod 0.7. Coming from the Java/JSP/Struts world it was such a pleasure to work in Haskell, with type safe templates. I have no web server, just warp, since there are very few static files (a few sprites and the tile image).
  • Client side uses Canvas with a sprinkling of JQuery.

As you can see, no database. Information about current games is purely in memory, and I don't keep any long term information about players. I suppose that allowing players to log in with their Google or Facebook id, and keep statistics on their battles would be good, but I'm not sure this little game will get enough traction to warrant it, really... 
The AI also is not great shake, there are only two bots: The Sitting Duck turns to face the wind and stays there. The Drunken Sailor just goes randomly through all possible actions. But hey, it's a multi-player game!
I'm not too sure if I chose the best route for concurrency. I use MVars and modifyMVar.
In fact the more difficult bit was to design the control. I didn't want to a do a full 3D environment, and opted for a top view, but the velocity of the ships was essential, and so providing just direction keys as in more static games wouldn't have worked. Hopefully the way the control works, being disposed on a copy of the boat icon at the top of screen, that turns when you boat turns, will work well. The icons are probably a bit small, it's fine for a mouse but I don't think it could work on a touch screen, unless you have tiny fingers.


A little bit of personal info: inspiration from this game comes from the French magazine "Jeux et Stratégies", that my dad used to get when I was young, and that got me into games. We have still kept all the issues, and issue 22 from August 1983 describes a simple ship battle game, rules written by Michel Brassinne (French warning!). Thanks!


Still it was fun to do!! Hope you enjoy playing it a little!

Thursday, November 25, 2010

A simple game in Haskell + SDL

I wanted to play a bit with SDL, and it's always good to step away from actually working on EclipseFP to use it for a "real" project. So I wrote a very primitive game using SDL and SDL_TTF. It's a typing speed game (hence the, ahem, clever pun on the name: TypeClass): you see letters scrolling down the screen and you need to type them, and of course they go faster and faster. Maybe my children will learn to type with it. Maybe not.


I had SDL installed earlier, but of course SDL_TTF proved challenging on my windows machine, but I think it's was all my fault, I probably didn't read the instructions properly or something. Anyway, I only forgotten to set the LIBS variable. When I ran export LIBS=/usr/local/lib/libSDL_ttf.dll.a in my MSYS environment then configure worked fine!


Afterwards it was all plain sailing, really. Just remember to add enableUnicode True in your initialization code so you can get the actual Unicode character typed (I'm on a French keyboard, so typing M gives me the SDL key ;). And of course you need a font file, so I include a GNU FreeFont file with the package. It needs to be in the same folder as the executable.


For some reason, after seeing code that was blocking for SDL events in a loop, I started building the game with two threads, one blocking for events and one looping and drawing, and a MVar in the middle. It worked, but rewriting it in a single normal game loop: process event, update game state, draw made things a lot easier.


This brilliant piece of software that has already made its mark in video game history can be found on Hackage here!


As usual, all feedback is welcome. Possible enhancements are a high score screen, difficulty levels, choosing letters by frequency in English, using Markov chains so that the flow of letters look more natural... The list is infinite!

Wednesday, May 05, 2010

Haskell SDL on Windows, check! (hacking required)

Things looked grim. Even though Timothy could get it to work, the SDL Haskell library wouldn't build for me. libSDL itself installed ok and the samples compiled and ran. But I couldn't compile the hsc files because of a linker error: gcc couldn't find SDLMain or whatever. In desperation, I posted to Haskell-cafe. I didn't get a single answer or hint. I was truly alone.
OK, it was time to either give up or take drastic action. And I never give up.

By then I had narrowed the problem. The order of arguments to gcc were wrong for linking, according to the gcc manual: the .o file should be referenced before the SDL libraries on the command line. It would work like that for other people, but for me, on my system, in my corner of the universe, the order was wrong, and that was it. If I tried the same order of arguments on the SDL samples, they would fail to link. If I reverted the arguments, they would succeed.
So I was left with the straight and narrow: I managed to get the source code for hsc2hs from darcs. I fiddled for a while with the include-dirs and extra-lib options so I could get it to compile and produce the same error than I had with the Haskell Platform version, and not some stupid errors about hsFFI.h not found or so.

Then I opened up, hands trembling and sweat pouring from my forehead, Main.hs in an editor. Found the offending lines:
    rawSystemL ("linking " ++ oProgName) beVerbose linker
( [f | LinkFlag f <- flags]
++ [oProgName]
++ ["-o", progName]
)

Changed them to:

      rawSystemL ("linking " ++ oProgName) beVerbose linker
( [oProgName]
++ [f | LinkFlag f <- flags]
++ ["-o", progName]
)
So that the name of the o file would be before the libraries.
Recompiled, copied the exe in the Haskell Platform bin folder...
Relaunched the SDL build...
And watched SDL build and install properly!
Gaped at the first sample of Timothy opening up a blank window that would close when I press a key! (OK, the last print fails, but by now little errors are not going to disturb my feeling of invulnerability).
Danced around my desk!
Had a beer!

Thursday, February 11, 2010

Waterloo Contest and Human Intelligence

I've entered the Waterloo university Google AI Challenge, hiding under a cunning nickname, since I saw that you could develop in Haskell, and a few others Haskellers are on it too! At the moment, I'm cruising at around the 110th position, which is not too bad given that I only worked a few hours at night on it (I have a day job, you know...) and that I implemented everything myself since the starter pack wasn't ready when I started working. I've played a bit with the standard strategies, implemented some flood fill, reuse some A* implementation I have.
All of this is interesting, of course, but there is no AI as such. The only intelligence in my code is the one I put in, and the strategies I devised. So I'm thinking of playing around with genetic programming and evolution techniques to try to get my code to find the right strategies at the right time. I have the feeling the trick will be to design something that is not too restricted and is truly able to evolve into some more advanced and complex than what I've designed myself. But hey, I'll learn, even if my program doesn't (-:

Friday, October 09, 2009

What client for an Haskell Multi Player Game?

I've been thinking again, in between working on eclipsefp, about writing a multi player role-playing game in Haskell. OK, I'm not going to write something the size of WoW by myself in my free time (unfortunately my day job doesn't involve any game programming nor any Haskell hacking :-(), but since I enjoyed writing Mazes of Monad, I figured that a game is a good way to learn things. A MMORPG should get me into concurrency, persistence, graphics, performance etc...

What I'm trying to figure out at the moment is what architecture to use. Mainly, if I have no doubt there is going to be a server somewhere running Haskell code, I wonder about the client. Should I try to write a browser based game coupled with a Haskell web server? That way, users could easily play the game when (if) it gets to a usable state, and I won't have to worry about cross platform issues for the client. Getting proper server side events or push should be fun, and of course if I end up using something like web sockets I will probably require a fairly cutting edge browser, which negates the advantage. I'm not too sure meddling with AJAX long polling and dynamic HTML is such a attractive option.
The other path is to write a Haskell client. Granted, users will have to download it, which means either me dealing with cross platform issues (provide several exes) or restricting my users to people happy to use cabal install. But I'll get maybe into stuff like OpenGL in Haskell, and do everything in Haskell instead of mixing Haskell with HTML and JavaScript (I've just stumbled upon jmacro, which could be cool I guess).

I'm sure everybody has faced that question at some stage. Ah well, for the moment I'm still wondering what my game will do, so I guess I have time to play with a few things before I make my mind up.

Friday, May 15, 2009

Adding a Writer Monad transformer

I'm still working on MazesOfMonad, my Haskell RPG, now on code.haskell.org. It's actually fun to now have a working program and think about extensions in functionality, and then how to implement them in Haskell, instead of just playing around with the language.
I wanted to give the user more feedback that they currently got about what was going on in the game, and at the same time I wasn't happy with what I had written previously: I had the output messages as part of the method signature:

myFunction :: Type1 -> Type2 -> (Type3,[String])

So I decided a Monad was called for. The Writer Monad, in this case, which lets us append stuff together to get it all back at the end. I already had most of my game running in a monad transformer, so it was **just** a matter of figuring out how to wrap everything in a WriterT. I had a bit of fun at first, then got it working. So now my game runs in a

WriterT a (RandT (StateT b IO)) c

Where a b a are various types for the things I need: a is the type of messages I write, b the state I keep, and c the return value. RandT gives me random numbers, StateT gives me a state, IO allows me to do IO operations when I need to save the game or something like that.

The amazing thing, well, for me, is that a lot of my functions do not need to be aware of the whole transformer stack, but of only the type classes that they care about. My final transformer is an instance of both MonadWriter and MonadRandom. So my method that needs to write messages becomes:

myFunction :: (MonadWriter [String] m)=>Type1 -> Type2 -> m Type3

And I can write my code calling the MonadWriter methods to add messages. It's in a monad, but it's still purely functional: I return a Type3 object and write Strings. If my function needs random numbers:

myFunction :: (MonadRandom m, MonadWriter [String] m)=>Type1 -> Type2 -> m Type3

and I get random numbers capabilities!

The final code is now much cleaner than before (I actually don't use [String] directly for the MonadWriter type but an alias for it, so I can replace it with Seq String or something faster the day I fancy it). I think I now understand monads and monad type classes better, and I understand better how using a monad doesn't automatically mean using the IO Monad and lose purity. Haskell Nirvana is not far off, says he naively...

Monday, April 27, 2009

Haskell RPG Game uploaded on Hackage!

I've worked on it on and off for months, I've rewritten parts of it entirely, it gave me the opportunity to knock together a real, complete application in Haskell, and it's finally done! I've uploaded my console based RPG game (read: nethack clone) to Hackage (get it here). You create a character and walk through mazes, trading, stealing, casting spells and fighting monsters.
You can look at the source code (no documentation, sorry) and see what I've used. I've used a monad to abstract away the state and the random generator (so I can plug a non random generator for testing, one that for example will guarantee that the next throw of the D20 die will give 8). I have developped my own little framework for console handling (executing actions from what the user typed in and displaying results) maybe I should look at the existing libraries and try to plug one in instead.
What I found was the most awkward was the record syntax for nested structures, I'll have to investigate to find an easier way to read and update my structures.
There are a few HUnit tests to verify that the most basic functionality works, so hopefully there is no huge bug.
It was fun to play around with Haskell and with game concepts. I hope I'll have time to work on even cooler stuff like adding AI for the monsters (so they can decide when to run away, etc...).
Any feedback on the game mechanism or on the code itself is welcome!

Friday, November 28, 2008

Predictable random for testing

In my Haskell RPG game, the results of actions are random: I use the standard random generator to simulate the throw of a dice in a table top RPG.
However for writing unit tests that is not ideal, since I would like to be able to test the outcome of an action for a given result of the dice. I didn't
want to clutter the code (even if using a State monad) with something used only for testing, so I experimented with IORef and a custom Test Generator.

First of all, we need a data type to store our non random random generator. It will store a list of results and the index it's at in that list. It's
basically a circular list, so that when we reach the end we start again. If the list is one element long, then the same result will be given for all
dice throws:

data TestGen = TestGen [Int] Int


mkTestGen is just a helper function to initialise the index to 0

mkTestGen l=TestGen l 0


This is the real magic: I thought you needed to pass around an IORef as any other variable to be able to read its results, but in fact this is not necessary,
if somewhat of a kludge:

testGen :: IORef (TestGen)
{-# NOINLINE testGen #-}
testGen=unsafePerformIO (newIORef (mkTestGen []))


This means that testGen is initialized only once as a TestGen with an empty list, no matter how many time it's called. It seemed to work in ghci even
without the NOINLINE pragma. Don't ask me why. So, given a simple setter function:


setTestGen l=do
writeIORef testGen (mkTestGen l)


We can specify what we want as the random generator. If we have an empty list, we use the standard random generator, otherwise we return the current element
in the list, and increment the index, going back to zero if we overrun the list:


randomInt ::(Int,Int) -> IO (Int)
randomInt (l,h)=do
(TestGen list ix)<-readIORef testGen
if null list
then getStdRandom (randomR (l,h))
else do
let e=list!!ix
let ix'=ix+1
let ix''=if ix'==(length list)
then 0
else ix'
writeIORef testGen (TestGen list ix'')
if e<l || e>h
then error (printf "%d not in range (%d,%d)" e l h)
else return e


And this works, amazingly:


setTestGen [2]
l<-replicateM 3 (randomInt (1,6))
assertEqual ("l is not 3 2s") [2,2,2] l
setTestGen [2,3,4]
l<-replicateM 4 (randomInt (1,6))
assertEqual ("l is not 2,3,4,2") [2,3,4,2] l
setTestGen []


(Notice how I reset the test generator to standard at the end by passing an empty list).

So now I can test my code with predictable results, that will be still random in production use.
Oops, already found a bug on the first test written with that technique!

Friday, March 30, 2007

A Haskell GUI in Flex

In an earlier post I mentioned a little Haskell game I developed where you had to navigate in a maze. I used HGL as the GUI framework, and noted it wasn't very clear what was the functional GUI framework of choice for Haskell. So I decided to give Flex a go and to hook it up with my Haskell back-end. I'm quite please with the result, I have to say.
The setup is as follows:
1) I've implemented a very simple single-threaded HTTP server in Haskell, using as an inspiration code that I found here and there (using Parsec for parsing HTTP messages, etc.). The server can server static HTML and SWF files as well as having a dynamic component: you can register Haskell methods that take a JSON object as a parameter, some internal state and return a new JSON object and the new state (yes I know, there is a monad for that...). I used the code here for JSON in Haskell. I thus expose a method that generates a Maze and a method to move to a cell, validating that there is no wall in between the current cell and the target cell and checking to see if we reached the exit.
2) I use Flex and ActionScript to create the GUI. The compiled SWF file will be served by the Haskell server and will call it back through asynchronous calls. I was a bit taken aback when I realized that Flex doesn't come with JSON support out of the box, but luckily there's a library for it. So you connect via your browser to a page on the server that embeds the SWF, Flex ask for the maze data to the server and displays it, and let you navigate using the keyboards or the mouse.
And that's it! So I have a nice, platform independent GUI and functional business code. I was thinking, who needs a special GUI framework for the desktop when an application could be made easily with a very lightweight local HTTP server and a web based interface? I even thought that Flex was a bit too much: why do I need a GUI technology that requires compilation when I can do nice stuff with pure HTML/Javascript frameworks like Dojo? So I can use a UI technology that is purely for UIs, and a functional language with the goodies Haskell provide for all the back-end, computation-heavy work.
The code for Haskell is here (start from Framework.hs), the Flex code is here.

Friday, February 02, 2007

Haskell User Interface???

It's been a long time since I've last posted, the fault to Christmas and holidays. In the meantime though I have done some more Haskell. I have used Prim's algorithms described here to generate a random maze. That forced me to use Random to generate the maze and HGL to display it, and allow the user to navigate from the entrance to the exit with direction keys. Works great, but I was looking at Haskell UIs to see what I could use, and there doesn't seem to be a consensus on a functional GUI library in Haskell. HGL is fairly low level and limited, wxwidgets ports have an imperative air about them and some of the ground breaking frameworks still seem to be experimental (and to be honest, I don't think I'm ready to deal with arrow-based frameworks yet, I'm still struggling with the monads...). So maybe the solution is elsewhere? I've seen in the Java world people talk about Flex, has anybody done anything integrating a Flex front end with a Haskell back-end?