Law-abiding decks

Topics: validation, Raise, error accumulation

Handling errors is one of the scenarios where a functional approach shines. Using types like Either and contexts like Raise, we can easily compose larger validations from smaller ones.

This topic is well documented in the official Arrow documentation, we suggest the reader to check the following material:

Feel free to use any style that you prefer in this section. When in doubt, using Raise (as opposed to Either) is the preferred option when using Arrow.

Your task in this section is to implement the rules for a legal deck, that is, one that can be used to play Pokémon TCG. The tcg/validation.kt file contains a barebones implementation of validate, which simply checks the number of cards in the deck, and a non-empty title.

The main rules for the legality of a deck are:

  • The deck must contain exactly 60 cards,
  • There must be at most 4 cards with the same name,
    • Note that cards with different identifiers but the same name are added together,
    • The only exception to this rule are basic Energy cards, of which you can have an unlimited amount,
  • There must be at least one basic Pokémon.

Implement this validation using Either or Raise, and try to break the process in different functions. The notion of fail-first vs. accumulation is important here, so you can squeeze as much information as possible.

Extra task: implement a rule to check that you can always evolve every Pokémon in your deck. This means you if you have a Stage 1 or Stage 2 Pokémon, you should have a card for the Pokémon it evolves from.

Problems tied to specific cards

This first task simply gives back a list of string for each problem, but this approach goes against our aim of precise types. Your task here is introduce an error hierarchy that represents each possible problem with the deck. The transformation to string should now happen in the DeckPane view instead.

Extra task: show problems related to specific cards directly on them. For example, by showing the name in the MaterialTheme.colorScheme.error color. Think about how the information required in the error hierarchy.

Reactive problems

The current implementation has a potential problem: you need to update _problems every time you update _deck. But actually, the problems of a deck directly derive from the contents of the deck itself. Reactive frameworks like RxJava allow expressing this connection directly, and we can easily do the same using MutableState.

Your task is to replace each update to the _problems mutable state with a new definition based on _deck. You can use the function map in utils/mutableState.kt.

Map as in lists

An intuitive understanding for this operation arises if we look at a MutableState as a list of all the values as the time flows. In that way, the problems arise as mapping the validation over each element of that list.

Gym Leader Challenge

The rules described above correspond to the Standard format, which is the one sanctioned for tournaments. However, fans of the game have come with other formats, like Gym Leader Challenge (GLC). As an extra task, you may implement GLC rules.

  • You may need to add some UI element to specify the format your deck is in.
  • GLC forbids some sorts of cards, namely those with a Rule Box and ACE SPECs. This information is available from the API, but currently not reflected in the domain model.