Help me learn to build snake: Menu Pages with Brick

Hi all,

As a personal project, I’ve been trying to build and extend the game of Snake in Haskell and practice my workflow and my understanding of the language. This project is heavily inspired by this blog: - however Brick has changed substantially since then.

The next part is going to go back to Brick and making a more standard UI with keyboard/mouse navigation and selectable buttons/entries in the terminal.

(ASIDE: I want the “PAUSED” text appears when the game is paused to appear overlaid on top of the game. I haven’t been able to find a way to do this yet but will research more today as I work on this)

I want to use this thread as a long-running place for asking questions/asking for critiques or pointers while I learn and implement various aspects of the infrastructure around the game.

Current state:

  • The game is playable, pausable and unbeatable. It can be run with cabal run. nix-build requires me to import vty someway apparently but that’s not my priority right now.
  • A very simple highscores database has been made as well with sqlite-simple as some helper functions to manage the database.

Desired state by next post:

  • Creation of a highscores page using brick
  • Highscores page can be browsed:
    • Shows 10, 20 or 50 results per page, can be toggled with key
    • Pages are changeable using left/right arrows
    • Go to page feature so user can quickly jump to a page that is up to the maximum divisor of Database.Highscores.maxDbSize.
  • Integration of results of the query calls onto the page.

Progress (Updated 2024-05-11):

2024-05-11: Highscore database implemented

Objectives

  • [X] Database implemented to keep track of local high scores.
  • [X] Database (can) prunes itself to keep only top {amount} high scores.

Database.SQLite.Simple did the job and simple SQL makes sense. It occurred to me that I used this package two years ago in the Haskell MooC. And so it was nice to reference that. I reckon I’ll need a more complex database task to really challenge myself but that’s a future task and this seems more than powerful enough to do what I needed it to do so far.

Thanks in advance,

T

6 Likes

Just a small thing: with most SQL databases you just need a query that picks the top scores and returns them in descending order. Something like

SELECT TOP 10 name, score FROM scores ORDER BY score DESC;
1 Like

Single player (more precisely, single machine): a database for high scores is probably an overkill, but you are doing this to learn so it is ok to complicate stuff.

I am far from an expert; the last time I had to use a SQL database I chose HDBC, I am sure more options are present nowadays!

@tobz619 great! Perhaps you want to learn how to use a database in haskell, in addition to building a game. In that case go for it. sqlite is a very common choice for small rdbms.

If you’re interested in a simpler, pure haskell solution, which also makes sharing your game easier, if that’s a goal: the simplest “database” for a haskell program is to show values (which all must derive or implement the Show class) and save that as a text file. And at program startup read them back from there (they also must derive or implement the Read class).

You might also be interested in my experiments here when I had the same need; this is a more robust (overengineered) form of the above, where scores and other state are reconstructed from a log of game events.

2 Likes

I second the recommendation of using sqlite, as it doesn’t require a server and it’s very easy to get started from the command line. For this simple case, it’s ideal.

I would prototype the schemas and the queries from the sqlite CLI itself, and then choose some simple Haskell sqlite library. There are more sophisticated libraries that hide the generation of the SQL for the sake of composability and type safety, but if the OP is learning SQL for the first time, it’s better to grapple directly with it.

2 Likes

simple

heh like sqlite-simple Database.SQLite.Simple

+1 to this though. Learning SQL directly is a hugely useful skill. Even if you use a fancy SQL-in-Haskell library, you will be mucking around in sqlite3 or psql or w/e client to debug/explore data. We use esqueleto at work and I use psql and Metabase constantly.

1 Like

Thanks all for your inputs, I’ll press ahead with learning SQL and Database.SQLite.Simple :slight_smile: HDBC seems cool but I guess I should properly learn the underlying queries by working with it more directly!

1 Like

Update:

I have created a database and some functions to manipulate the database as far as I have scope for right now. I can also see how I could achieve this all with a standard text file.

For the next part I want to do more Brick work and create a standard menu/UI with selectable elements.

My current strategy is to evaluate the example Brick programs for inspiration. But what would be helpful is if anyone has some insight into some good or helpful patterns that is appreciated :slight_smile:

Update:

I’ve finished with the Database stuff for now and am now trying to work on creating a logging framework.

The purpose of this is learn how different kind of effect systems work and if they can be synergized together. i.e. can I stick together Bluefin's effect system and Brick's ReaderT .. IO and work on either part independently.

So far, the approach looks like so.

EventM handles all the State parts and so I could just get the state of the game and run Bluefin style effects from there by passing through the necessary info as parameters.

For example: handleMovement will log any movement actions and requires the BrickEvent n e among others.

BrickEvents are handled here and I’m thinking that I could run the Bluefin effects in here?

The dispatchers and altConfigs will be ‘globally’ defined elsewhere, but the events which are needed are part of the handleGameplayEvent' :: BrickEvent n1 Tick -> EventM n2 GameState () function and can be passed to any writeLog function.

Does this approach make sense?