The 80s come back in reactive style

Simon is an electronic game of memory skill in which the device creates a series of tones and lights and requires a user to repeat the sequence. If the user succeeds, the series becomes progressively longer and more complex. (wikipedia)

Over the next three articles I will show how I implemented the game Simon in Flutter. The game is currently available in Google Play under the name Simon Says. I think it makes for an interesting use case for Flutter because I wanted to use reactive programming for it and Flutter has excellent support for it. I will share the full version of the game in my github account in the last article of the series.

How does the game work?

The mechanics of the game are pretty straightforward. The device consists of four buttons, each one with a particular color and sound, which will be activated in a random sequence that the user will then need to replicate. The game is played in rounds, and in each round the length of the sequence is increased in one.

You can check the following video if you need more details.

Simon (and Back to the Future), the best of the 80s

What does the game look like?

From a user perspective, the game is very simple: a black canvas and four colored buttons which will be highlighted and also produce a sound when pressed. We also want some way to show the current round and to indicate whose turn it is.

Show me how it’s done!

What are the basics?

These are the things that I cover in this article:

UI elements: board, buttons, status bar and score.

App architecture: widgets, models and how they interact together.

The final version of the application has some extra elements and features that I don’t explain here, as the overlay screen used before and after the game.

Architecture

Anyone said BLoC?

As you can see, GameBloc is the heart of the game. It will be the source of truth for our data and will use streams and sinks to communicate with the presentation layer (widgets). Also, I defined a few simple models to represent the data and encapsulate some business logic. Let’s start with them.

This is how I understand the game in pseudocode in an imperative way:

state = SimonSays

gamePlays = [] while (state != GameOver) { play = generateRandomPlay()

gamePlays.add(play) gamePlays.forEach(simonPlays$.add) state = UserSays

userPlayIndex = 0 userPlays.listen((play) { if (!isValidPlay(play, userPlayIndex)) state = GameOver

else id (userPlayIndex == gamePlays.length) state = SimonPlays userPlayIndex++ })

}

Now we need to implement this using reactive programming. Let’s do it!

Data models

SimonColor encapsulates information needed for each button in the game; the color used normally and when pressed, and also the name of the file with the related sound.

GamePlay represents a single play (color) plus some extra information that I use to check if it’s the last play in the sequence and if it was successful or not. For the complete sequence of plays in the game, I use GamePlays. Other than the list of plays I have some functions to deal with the contents of the list and also validate user plays agains the sequence.

Finally, GameState holds the current state in the game, plus some extra information about the duration and the round which I use for the score when the game is over.

The board

The board is fairly simple, I just draw the buttons and include a rounded container in the middle to display the current round. Please note that I’m using the stream score$ to reactively change the score value during the game.

The buttons

There is some complexity to the SimonButton widget, but for this first iteration I stripped down everything related to the game itself so that we can focus on the design and the animation. At this point, only the user can interact with the button, but that’s not wired to GameBloc.

Notice how I use the AnimationController to change the padding on the button when the user taps on it to give the feeling of it being pressed. Also, I used the current value in the padding on every render during the animation to chose the primary color or the accent color so it seems as if the button is highlighted.

In my next article I will focus on the GameBloc and wiring it to the buttons.

Thanks for reading!