When is the observer method rowsCompleted called?


all my daily test for the Autoplayer give me essentially this stack trace:

java.lang.IllegalArgumentException: score delta was 0
	at tetris.autoplay.Statistician.inferRowsCleared(Statistician.java:23)
	at tetris.autoplay.Statistician.rowsCompleted(Statistician.java:30)
	at prog2.tetris.game.MyTetrisGame.updateCompleteRowsAndScore(MyTetrisGame.java:134)
	at prog2.tetris.game.MyTetrisGame.newPiece(MyTetrisGame.java:168)
	at prog2.tetris.game.MyTetrisGame.step(MyTetrisGame.java:213)
	at prog2.tests.tetris.daily.AutoPlayerTest.performMove(AutoPlayerTest.java:51)
	at prog2.tests.tetris.daily.AutoPlayerTest.getAutoPlayerRows(AutoPlayerTest.java:82)
	at prog2.tests.tetris.daily.AutoPlayerTest.getMaxRows(AutoPlayerTest.java:91)
    // up to and including the previous line all stack traces for the autoplayer daily tests are the same
	at prog2.tests.tetris.daily.AutoPlayerTest.testGame3(AutoPlayerTest.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	...[cut after 10 lines]

I.e. they start by doing a step, spawning a new piece and then they call a method which is not in the TetrisGame interface, namely updateCompleteRowsAndScore. The very next action is my AI being informed of this via rowsCompleted and it then tries to infer the number of rows cleared via the score difference. However the method I created for this only accepts 100, 300, 500 and 1000 as valid inputs, everything else is counted as illegal.

I implemented it that way because I was under the impression that the observer method rowsCompleted would only be called if rows were actually completed. From the stack trace I can only surmise that the game had just started and no rows were cleared so far.

So when is rowsCompleted actually called? Only when rows are cleared or also at other times? (maybe to check for tampering from our side)

I will change my inference method to also accept a score of 0 but I would still like to know the answer to this.

The rowsCompleted event is only triggered when rows are completed.

But the specification does not specify that the score has to be incremented beforehand.
It just says that the event is triggered after rows are completed.
The score might be updated after the notification was sent.

Why is the observer so weak?
The method piecePositionChanged is useless because I plan moves ahead.
As you just explained rowsCompleted is unsuitable for getting feedback about reward, because I would have to compare the board. I can of course use pieceLanded to get a copy of the board and then compare after rowsCompleted, but why make it so annoying?
And finally gameOver is unusable by the autoplayer because you kill it before I can act on the signal.

It has basic methods for some important events.

I agree that one would probably implement a more advanced and dependent observer for more complex event interactions.

The current observer is good enough for the current handler like the GUI (for instance, piecePositionChanged is very important for the GUI and logging).
For some implementations of the autoplayer, some events are not really useful. But the autoplayer has full access to the game to alleviate this shortcoming.
Another aspect is that the observer should teach the basics of the observer pattern without being overwhelming or unnecessarily increasing the project’s difficulty.

You could use custom game instances with sophisticated logging, notification, and reporting mechanisms (as long as it is not too computationally expensive).

If the game is lost, there isn’t really anything you can do anymore.

1 Like