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.  If the user takes back moves while the engine is thinking, the engine's move is discarded. If the user takes back the engine's move, and plays another move, the engine changes sides. Setting up the start position 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 ser.inWaiting() == 0: # Check that the input buffer is empty
        if not make_move(move):
            break
    if not get_reply():
        break

ser.close()


Everything appears to work satisfactorily.

No comments:

Post a Comment