The difficulty of programming a chess clock

This is not about setting your Chronos for 40/90 inc/30 d/5; 20/30 inc/15 d/3; SD/15 inc/10 d/2.

It’s about the difficulty clock manufacturers have in programming their clocks to operate correctly.

Let’s assume we have individual buttons for each side, like the Chronos or Zmart, rather than a rocker arm like the DGTs.

As a start, the main loop in the program might look like this:

    1. Is left button pressed?
    1. If no, go back to step 11 and keep checking.
    1. If yes, add the increment, bump the move count, stop the left clock, start the right clock, and continue with step 21 below.
    1. Is right button pressed?
    1. If no, go back to step 21 and keep checking.
    1. If yes, add the increment, bump the move count, stop the right clock, start the left clock, and loop back to step 11 above.

Of course I’ve left out a few things, including what happens at the start of the game, but I’m simply trying to lay out some main ideas.

The above looks as though it should work, right? When the left clock is running, it should wait for a left button press, then do its thing(s), then repeat the same steps with the right button, etc.

But what happens in a double time scramble? It would not be uncommon for the player on the left side to press his clock, hold it down for a second or two, and then for the player on the right side to move quickly and press his clock, perhaps also holding it down for a second or two. In that case, for a fraction of a second, both buttons are likely to be pressed down at the same time.

What happens during this fraction of a second? Well, the left button is pressed, so (step 13) the left-side increment is added and the move count is bumped, so we go to step 21. The right button is also pressed, so (step 23) the right-side increment is added and the move count is bumped, and we loop back to step 11. We’re in a loop, so all the steps keep being executed, rapidly, even though no further moves have been played. The clock could easily add a dozen increments and a dozen move-bumps, all in that fraction of a second during which both buttons are down.

Holy time scramble, Batman! This clock is crazy.

In fact, that’s what can actually happen, as has been documented in that Official Chess Clock thread.

So what logic can be developed to curb this manic behavior? I propose the following:

    1. Is left button pressed?
    1. If yes, go back to step 31 and keep checking.
    1. If no, proceed with the next step, step 34.
    1. Is left button pressed?
    1. If no, go back to step 34 and keep checking.
    1. If yes, add the increment, bump the move count, stop the left clock, start the right clock, and continue with step 41 below.
    1. Is right button pressed?
    1. If yes, go back to step 41 and keep checking.
    1. If no, proceed with the next step, step 44.
    1. Is right button pressed?
    1. If no, go back to step 44 and keep checking.
    1. If yes, add the increment, bump the move count, stop the right clock, start the left clock, and loop back to step 31 above.

This would seem to fix the problem. Step through it and see if you are convinced. By first waiting until the button is not pressed, and then waiting until it is pressed again, we’re bringing that endless speedy loop to a screeching halt. Now we are testing for the action of the button being pressed, rather than the static state of whether the button is currently pressed.

Any comments?

Of course, another solution would be to use a rocker arm instead of individual buttons, because then it is not possible for both buttons to be in a pressed-down state simultaneously.

Bill Smythe

The problem with a rocker arm is making sure that it can physically handle simultaneous presses.

So far as I can tell, there should be no “still down” or “button release” processing necessary for the two player buttons when in game mode. (There might be in set mode, but that would be a completely different part of the program).

[code]lastbutton=nothing

Event loop

On left button press
if lastbutton==left
continue
lastbutton=left
do on left button
continue

On right button press
if lastbutton==right
continue
lastbutton=right
do on right button
continue[/code]

What about touch sensors?

Presumably touch sensors are like individual push buttons, in that it is possible for both buttons to be pressed simultaneously. Therefore the programming precautions necessary with push buttons would also be necessary with touch sensors.

Bill Smythe

Your code is virtually the same as mine in terms of complexity (or lack thereof). Both take care of the problem of both buttons being down at the same time. Your lastbutton variable is essentially “still down” or “button release” processing, as is my checking first for the button being down and then for it not being down. And both are about the same number of steps.

Bill Smythe

The touch sensor should act the same way as a “button”—it’s the hardware (not the software) that determines what a “press” means.

No. No. 1000 x No. If the only events that matter are button down, you process only button down and don’t monkey with anything else—that’s how you get bugs.

In my humble opinion (having done real-time security software engineering for about 20 years), the best way to tackle programming for a chess clock is to use a state machine. It’s a natural way to deal with asynchronous events (not only button presses but also expiration of time in a time control period, handling resumption after adjusting time for a penalty (the state would determine, for instance, whether to just resume subtracting time from the running clock or adding an increment/delay, depending on which side is started)).

I’ve tried doing this sort of programming with loops of “if” statements, and it gets very hairy very quickly.

Um, my version processed only button down and nothing else – unless you are talking about my steps 36 and 46, which also appeared in your version, abbreviated as “do on left button” and “do on right button”.

Bill Smythe

Except yours (your second proposal) is wrong. You’re acting on the button release, not on the button press. It’s the button press (which is a discrete action, at a specific time) that should stop one clock and start the other. Once White has hit his button, Black should be able to push her own, whether or not White has released yet.

And that’s what my (second) proposal accomplishes – as does yours.

Bill Smythe

The issue with the Tap N Set clock, the “official” clock of US Chess, adding too many moves to its count and thus too much increment if both clocks are pressed at about the same time was only an issue with the button version of the clock and not the touch sensor version.

I hope no one who is programming chess clocks looks at your second proposal. It doesn’t fix the problem you raise (what happens if the left button is held down—doesn’t it lock out the right button while looping between 31 and 32?) and, of course, will sit forever waiting for a complete down-up on the left button before it even looks at the right one).

You are overlooking something.

Here is my proposal again:

    1. Is left button pressed?
    1. If yes, go back to step 31 and keep checking.
    1. If no, proceed with the next step, step 34.
    1. Is left button pressed?
    1. If no, go back to step 34 and keep checking.
    1. If yes, add the increment, bump the move count, stop the left clock, start the right clock, and continue with step 41 below.
    1. Is right button pressed?
    1. If yes, go back to step 41 and keep checking.
    1. If no, proceed with the next step, step 44.
    1. Is right button pressed?
    1. If no, go back to step 44 and keep checking.
    1. If yes, add the increment, bump the move count, stop the right clock, start the left clock, and loop back to step 31 above.

Except for the very first move of the game, the only way to arrive at step 31 is from step 46. (And similarly, the only way to arrive at step 41 is from step 36.)

Let’s say white’s button is on the left, black’s is on the right, and we arrive at step 31 with white’s button already down. That means that white’s button was already down when black completed his previous move at step 46.

That can happen in only two possible ways. Either (1) white held his button down after completing his previous move, and was still holding it down when black then completed his move, or (2) white pressed his button while it was black’s move.

In case (1), it’s only fair that white, after completing his subsequent move, would be required to release his button and then press it again in order to register the subsequent move. No fair allowing a single, sustained button press to count for two moves!

In case (2), white has acted improperly, and, again, it’s only fair that he be required to release his button and press it again to register the subsequent move.

I gotcha, Tom! :smiley: :smiling_imp: :smiley: :smiling_imp: :smiley:

Now, what happens if the game has just started, and it’s white’s first move? The game should then begin by pressing the Start button (on DGT-type clocks) or by pressing black’s button (on Chronos-type clocks). In neither case should white’s button already be down, unless white is doing something improper.

I gotcha again, Tom! :smiley: :smiling_imp: :smiley: :smiling_imp: :smiley:

Bill Smythe

You seem incredibly proud of truly godawful bad pseudo-code (which still doesn’t work correctly if the game starts with right button press). You could have simply said (several posts ago) that you don’t think yours is as bad as all that, but that you see where what I wrote is a lot cleaner.

Except that I don’t agree that yours is “a lot cleaner”, nor that mine is “truly godawful”. Mine at least avoids the introduction of an unnecessary variable.

Whether mine works if the game starts with a right button press depends on where you start in the first place. Perhaps my presentation would have been more intuitive if I had presented it in two parallel columns of six steps each, rather than in one column of 12:

  1. . . . . . . . . . . . . . . . . . . .@@@@@@41. . . . . . . . . . . . . . . . . . . .
  2. . . . . . . . . . . . . . . . . . . .@@@@@@42. . . . . . . . . . . . . . . . . . . .
  3. . . . . . . . . . . . . . . . . . . .@@@@@@43. . . . . . . . . . . . . . . . . . . .
  4. . . . . . . . . . . . . . . . . . . .@@@@@@44. . . . . . . . . . . . . . . . . . . .
  5. . . . . . . . . . . . . . . . . . . .@@@@@@45. . . . . . . . . . . . . . . . . . . .
  6. . . . . . . . . . . . . . . . . . . .@@@@@@46. . . . . . . . . . . . . . . . . . . .

It would still be true that, after the first move, step 31 could be arrived at only from step 46, and step 41 could be arrived at only from step 36, but now that concept looks more natural because of the symmetry, and because of the parallel columns.

Of course, there would have to be a start-up sequence up front, that would decide whether to start at step 31 or step 41. (You’d need a start-up sequence in yours, too.) Mine could look like this:

  1. Add the increment time to the main time, and set both players’ total time to this sum.
  2. Set both players’ move counts to zero.
  3. Display both players’ total time and move counts.
  4. Is right button pressed? If so, start the left clock and go to step 31.
  5. Is left button pressed? If so, start the right clock and go to step 41.
  6. Go back to step 04 and keep checking.

(Alternatively, at step 04, we could start with step 34 instead of step 31, or at step 05, we could start with step 44 instead of step 41.)

The above should work if there is a start button (a la DGT), in which case the sequence at step 01 would start when the start button is pressed. It should also work if there is no start button (a la Chronos), in which case the sequence at step 01 would start as soon as the clock is set.

I still think my version is at least as clean as yours.

Bill Smythe

Seriously??? Doubling the code (and doubling the complexity) to avoid adding a one byte (not 1 Tb, not even 1 Kb, but 1b) data element (whose meaning is self-explanatory, BTW). Note that there are already probably a dozen state variables needed anyway for move counters, time remaining, delay remaining, # of T/C’s, descriptions of time controls, etc. What’s the big deal with one more, other than it wasn’t your idea? (That’s rhetorical—I have no interest in seeing another 500 word essay justifying bad design).

No matter how much you want to deny it, it’s not symmetrical left button vs right button, when it has to be, plus it’s very brittle. For instance, how would you handle pause/resume processing, when you have each button with its own loop? Depending upon the way that the clock is designed, you could have additional states for paused/left active; paused/right active (if a resume event automatically restarts the active clock), or (as is done with the Chronos) a general paused state which is exited by hitting either player button. A single event loop can handle those easily (for either way of handling it), which is the whole reason for that design.

That’s not true at all, as can be seen more easily if you list the two halves of the code in separate columns, as I illustrated in my most recent post. The left side steps would then be:

    1. Is left button pressed?
    1. If yes, go back to step 31 and keep checking.
    1. If no, proceed with the next step, step 34.
    1. Is left button pressed?
    1. If no, go back to step 34 and keep checking.
    1. If yes, add the increment, bump the move count, stop the left clock, start the right clock, and continue with step 41.

– and the right side steps would be mirror images (numbered 41 through 46), interchanging left with right throughout. And there would be a symmetric start-up routine (numbered 01 through 06 in my previous post) that would start the main routine at step 31 or step 41, depending on which button was pressed. So the whole thing would absolutely be symmetrical left button vs right button.

Keep in my mind that this thread was originally intended to point out a flaw in the programming of the Tap N Set clock, and to lay out alternative programming steps that would remove the flaw.

Also, I deliberately wrote my pseudo-code in “lay” style, thinking there might be some lay people interested in following it. If I had predicted that you would be the only person checking in, I might have used more of a “programmer” pseudo-code style, in which the above six steps 31-36 would reduce to three:

    1. If left button is pressed, go to 31.
    1. If left button is not pressed, go to 34.
    1. Add the increment, bump the move count, stop the left clock, start the right clock, and go to 41.

I’ll have to take your word for it there. Obviously, both my code and yours, as presented, would cover only the basics, and would be far from adequate to handle all the things a clock really needs to do.

Bill Smythe