This is probably beyond your scope as you notice that the class has not yet covered Runnable . This is an interesting question, and the challenge is to come up with a concise and elegant way to present it, while avoiding as many repetitions as possible. It uses a solution using Java 8 and functional programming methods.
The first understanding is to see that every action or step in a game can be represented as a lambda expression or a method reference. I assume you have a Game class. Each such step takes a Game instance as an argument (or receiver), and thus can be introduced as a βconsumerβ of Game instances. Thus, we can introduce them into the data structure:
List<Consumer<Game>> actions = Arrays.asList( Game::wakeUp, Game::goToSchool, Game::beforeLunch, Game::lunchActivity, Game::afterLunch, Game::afterSchool, Game::home, Game::sleep);
Now that we have them in the data structure, we can iterate over them:
for (Consumer<Game> action : actions) { action.accept(game); }
Of course, we want to check if the game is over after each action. Suppose you have an isOver method in the Game class that checks for the correct termination conditions. Then you can:
for (Consumer<Game> a : actions) { a.accept(game); if (game.isOver()) { break; } }
It runs through just one day of the game. Presumably, you want to start the game indefinitely until you reach your completion condition. To do this, you need an external loop, and the completion check should exit the outer loop:
outer: while (true) { for (Consumer<Game> a : actions) { a.accept(game); if (game.isOver()) { break outer; } } }
This may be enough: you have a list of game actions and a loop that runs indefinitely, checking the termination condition after each action.
But wait, there still! There are still quite a few templates here that can be eliminated using some functions of the Java 8 stream. Note that each element of the stream can be tested against the predicate using the noneMatch method. This method exits when one of the predicates returns true.
Since each action is of the Consumer<Game> , we need a small helper function that turns each action into a predicate:
static Predicate<Consumer<Game>> stepAndCheck(Game game) { return c -> { c.accept(game); return game.isOver(); }; }
Now we can run all the actions of the day as follows:
actions.stream().noneMatch(stepAndCheck(game))
To start the game endlessly, we simply transfer this to the while loop. Since noneMatch returns true if, as they say, none of the predicates match, we make this loop condition and leave the loop body empty:
while (actions.stream().noneMatch(stepAndCheck(game))) {
This may seem unnecessarily hidden. Indeed, this can be, for example, for toy examples. However, for more complex problems, such methods are very valuable.