5. Game logic in the template game

5.1. Modify the game logic

(found in logic.py)

For most games, the game logic is just a few lines of code. In such a case the code should be placed directly in function _decide_on_problem_instance. In a minority of cases the game logic requires additional functions and/or modules. In such a case these functions should be called from _decide_on_problem_instance. There is no other way for the CTGames framework to find your code except if you call it from here.

5.1.1. Modify _decide_on_problem_instance

The function _decide_on_problem_instance contains the main logic of the game. It is passed a SublevelBehaviour as its argument. It uses the parameters in SublevelBehaviour to specify a randomly-generated instance of the game that is returned to the caller.

This is the hardest function to write because it will look so different from game to game. The only common features between this function in each of the games are

  • its parameter is round_behaviour: SublevelBehaviour

  • it uses a function imported from module random, such as randrange or sample

  • it returns custom game fields and the logical correct answer to the game instance

In the template, this looks like:

def _decide_on_problem_instance(round_behaviour: SublevelBehaviour) -> tuple:
    """Construct the data that defines the problem instance, and the answer.

    Takes the round behaviour and returns the target and the elements
    that populate the GameStateCustom for this game.
    """
    param1, param2 = round_behaviour

    # Randomly generate a list of length `param1` of numbers with
    # `param2` digits in each.
    custom_field1 = sample(range(10 ** (param2 - 1), 10 ** param2), param1)

    # The correct answer is the maximum value in the list
    target_long = max(custom_field1)

    return custom_field1, target_long

The same code is used for both Game Template Int and Game Template MCQ, except in the latter to refer to the logical answer as target_long, because, as mentioned earlier, in MCQ-type games we want to make a distinction between the logical answer and the letter corresponding to the correct answer in the list of multiple answers.

There is not much help that a document such as this can give you to help you write this function for your game. The best advice is to read how game developers did it for their games. As of 2020, there are almost 100 previous games, so you have plenty of examples to choose from.

Tip

There are one common mistake that a game developer can make writing this function. During the random generation the developer might use an approach with a while (unbounded) loop that randomly generates possibilities, discarding inappropriate possibilities and recording appropriate possibilities, until the required number of appropriate possibilities is found. This is unsafe. All loops should be bounded (e.g. a for loop or list comprehension) so that your code does not “lock up” the web app. Sometimes it is easy to fix and sometimes a developer has to think carefully and creatively how to do this.

5.2. Update the function _decide_on_answers

(found in logic.py)

This section is only relevant for MCQ-type games.

Tip

There are one common mistake that a game developer can make writing this function. During the random generation the developer might use an approach with a while (unbounded) loop that randomly generates possibilities, discarding inappropriate possibilities and recording appropriate possibilities, until the required number of appropriate possibilities is found. This is unsafe. All loops should be bounded (e.g. a for loop or list comprehension) so that your code does not “lock up” the web app. Sometimes it is easy to fix and sometimes a developer has to think carefully and creatively how to do this.