Tuesday, 24 May 2016

Rudimentary Novag Citrine Interface

My next experiment was to write a rudimentary interface for the Novag Citrine, using Python 3. With this simple interface, the user has to type the moves of an external engine onto the command line. The Citrine's responses are also written to the command line. I found that it was necessary to impose a 0.1 second delay between commands, to prevent some of the commands being lost. As noted previously, moves have to be sent to the Citrine twice. It is necessary to wait for the user to reply. The error checking appears to be sufficient to allow the program to terminate gracefully, when the user does something unexpected, e.g. taking back moves while the "engine" is thinking. Setting up the start position also terminates the program, when "New Game" is received from the Citrine. Here is the program:

import serial, time
port = '/dev/ttyUSB0'
ser = serial.Serial(port, 57600, timeout=0.05)
print(ser.name, 'opened')

def send_command(command):
    ''' Send a command from the PC to the Citrine.
    '''
    ser.write((command + '\r\n').encode(encoding='UTF-8'))
    time.sleep(0.1)

def make_move(move):
    ''' Tell the Citrine to make a move, and return True if a valid reply is
    received. 'j' tells the Citrine to use its own engine to make the move.
    '''
    if move == 'j':
        send_command('j')
    else:
        send_command('m' + move)
        send_command('m' + move)
    line = ser.readline().decode(encoding='UTF-8')[:-1]
    print(line)
    return line != '' and line[0] == 'M'

def get_reply():
    ''' Get the reply, which should be a move, optionally preceded by one or
    more take backs. Return True if a valid reply is received.
    '''
    while True:
        line = ser.readline().decode(encoding='UTF-8')[:-1]
        if line != '':
            print(line)
            if line[0] != 'T':
                break
        time.sleep(0.1)
    return line[0] == 'M'

send_command('u on') # Turn Referee Mode on.
send_command('x on') # Turn Xmit on.
send_command('l tr8') # Set the Level.
ser.flushInput() # Flush the input buffer.

while True:
    move = input('Engine move? ')
    if not make_move(move):
        break
    if not get_reply():
        break

ser.close()


Everything appears to work satisfactorily.

Friday, 20 May 2016

Connecting to the Novag Citrine using Python

I have been learning Python 3, and wrote a simple program to connect to the Novag Citrine:

import serial
port = '/dev/ttyUSB0'
ser = serial.Serial(port, 57600, timeout=0.05)
print(ser.name, 'opened')
print("When prompted, enter a Novag command, '' to read, or q to quit")

while True:

    while True:
        byteline = ser.readline()
        if byteline == b'':
            break
        print(byteline.decode(encoding='UTF-8')[:-1])

    command = input('Command? ')

    if command == 'q':
        break
    elif command != '':
        command += '\r\n'
        ser.write(command.encode(encoding='UTF-8'))

ser.close()


I tested this program on Ubuntu Linux. It should also work on Windows, a Mac and any other platform that supports Python 3. The variable "port" has to be set to the serial port that you are using to connect to the Citrine. Here is a sample session, in which the moves for white are entered on the Citrine, and the moves for black are sent from the PC:

/dev/ttyUSB0 opened
When prompted, enter a Novag command, '' to read, or q to quit
Command?
New Game
Command? u on
.Referee on
Command? x on
Xmit on
Command? l tr8
Level tr 8
Command?
M   1   e2-e4
Command? me7e5
Command? me7e5
M   1,  e7-e5
Command?
M   2   g1-f3
Command? mb8c6
Command? mb8c6
M   2,  b8-c6
Command?
M   3   d2-d4
Command? me5d4
Command? me5d4
M   3,  e5xd4
Command?
M   4   d1xd4
Command?
T   4   d1xd4
Command?
M   4   f3xd4
Command? q

Everything appears to work. After entering a move for white on the Citrine, enter an empty line as a command to read the reply from the PC. As noted previously, it is necessary to send the moves for black twice from the PC. Typing 'q' ends the session. Responses from the Citrine are buffered, and can be read after more commands have been sent.

Monday, 16 May 2016

Communicating with the Novag Citrine

I have done some experiments in communicating with the Novag Citrine via CuteCom. I found that the commands are not case sensitive, and that invalid commands are simply ignored. The Citrine sends "New Game" at the start of a new game. Setting up the pieces or sending the N command from the PC starts a new game. If the Citrine has been disconnected from the mains for long enough for it to lose its internal memory, it beeps and sends New Game when it is switched on. The Citrine forgets any user settings for the new game. The following enquiries successfully send information back to the PC:

C shows the Clocks.
G shows the Game.
P shows the Position.
I shows the ID of the Citrine.
L shows the Level (time limit).
U shows whether Referee Mode is on.
X shows whether Xmit is on or off.

In Referee Mode, the user plays both sides, and Citrine just checks for the legality of moves. When Xmit is on, moves made on the board are echoed back to the PC. Here is an example game score:

Game   6
.      white       black
.   1  e2-e4       e7-e5
.   2  f2-f4       f8-c5
.   3  f4xe5       d8-h4
.   4  e1-e2       h4-f2
.   5  e2-d3       f2-d4
.   6  d3-e2       d4xe4

The default Level is TR1 (TouRnament Level 1), i.e. 40 moves in 5 minutes. (When I exceed the time limit, the Citrine shows "Flag" but lets me play on.) I found that the undocumented L AT1 (Average Time Level 1) works, setting the Level to an average of 2 seconds per move, and the other Levels appear to work too.

Xmit is off by default, but can be turned on with X ON, so that moves made by the user are echoed back to the PC, e.g.:

M   7   g1-f3
M   7,  c5xd4
M   5   d7-d8/N
M   4   O-O
M   5,  O-O-O

The comma indicates a move for black. Checks are not shown. Move when a move is taken back, this is indicated by a T in place of the M, e.g.:

M   1,  e7-e5
T   1,  e7-e5

The following codes are used to indicate the end of a game:

M#1 Draw by repetition.
M#2 Draw by the 50 move rule.
M#3 Draw by insufficient material.
M#4 Stalemate.
M#5 Checkmate.
M#6 Citrine resigns.

(There is no way for the user to resign, but he can just start a new game.)

Putting the Citrine into Referee Mode with U ON works, but sending a move from the PC to the Citrine once does not work at all well. The LEDs flash so quickly as to be almost invisible, and when the piece has been moved, the LEDs on the destination square are illuminated until either the piece is lifted again or an information request is sent from the PC. The move is echoed back to the PC. Miraculously, sending the same move twice works as it should, except that the LCD shows an error, which can be ignored. The move is not echoed a second time. Taking a move back by sending T (once) works as it should. The Citrine's behaviour is not ideal, but it is worth noting that the more expensive DGT boards do not even have LEDs to indicate the moves on the board.

MG1F3 and MNG1F3 both work. MO-O and MO-O-O both work. When taking back castling, it is necessary to move the king before the rook. ME7E8/N works for promotion to a knight, and I expect that the other under-promotions work too.

The J (Go) command causes the Citrine to make a single move, which is echoed back to the PC, as does, lifting the king of the side without the move. Neither action turns Referee Mode off. F (Flip) works at the start of a new game. it is also possible to set up a custom start position. If a custom start position has been set, O (Origin starting position) successfully reverts to that custom start position.

Some of the other functions listed in the Novag documentation do not work. The key functions do not work. There does not appear to be any way of setting Easy mode remotely. V (video mode) and R (Replay) are both ignored. It does not appear to be possible to set separate Levels for white and black. Autoclock does not work. Send Info does not work. I expect that the problem here is that the documentation covers several Novag machines, and not just the Citrine.