I began the first exercise of Automata with an exploration of two subjects that interest me: the game of chess and horror fiction. These subjects brought me to a simple question: how to make the game of chess terrifying?
Here are the elements that I decided on, which could be implemented separately or all at once, presented in ascending order of difficulty (or my perception thereof):
- Pieces fly off the board when the game becomes “angry” at the players — this could be due to a variety of factors, including players taking too much time to make a move, overall game duration, or chess engine analytics.
- The game generates music and noises that become more terrifying when you start to lose (using a music template engine).
- The game generates visual elements on a screen.
- LEDs show that the move you should’ve made (using the Stockfish open source chess engine).
- The game generates a story (using natural language processing & generation) that you can read afterwards.
My first study involved using a square on the board as a switch in a circuit. I decided to focus on the most common opening move for white: pawn to e4.
I began by gluing a conductive washer to the base of a white pawn, inserting wires into a vinyl chess board, and fashioning makeshift conductive pads with pools of solder.
I then connected each square to an LED.
A few observations I made after conducting this initial study:
- Tracking the game will not require electronic IDs for individual pieces, so long as the game always begins in the standard starting position.
- 64 inputs will (probably) be required (unless there’s a simple, elegant solution that I’m not seeing at the moment).
- I need to order a lot of parts.
I started by ordering some parts. At present, I have ordered:
- 4 12V DC Solenoids with Spring-Return Clappers
- 100 Super Bright Blue LEDs
- 140 1/4″ Crimp Terminals (to use as conductive pads)
- 16 MCP23S17-E/SP Input/Output Expander Chips
- 40 CD4021BE Parallel-to-Serial Shift Register Chips
- 1 Giant Breadboard
- 1 Raspberry Pi Model B+ (see software investigation below).
Sam Levign wisely pointed out that I could use a video camera + OpenCV to accomplish the piece tracking, but in the spirit of investigating automata, I am pursuing the mechanical route for now. In theory, the hardware listed above should give me far more than enough General Purpose I/O pins.
In my second study, I investigated the software component of the device. Stockfish, the world’s most powerful chess engine, is open source. and provides an ideal solution to the problems of gathering and interpreting game analysis data. I also concluded that the Raspberry Pi would likely provide the best scripting platform for Stockfish.
The terminal interface for Stockfish:
I was relieved to find that the interface does not rely on chess notation. Instead, it uses a much more straightforward [originSquare][destinationSquare] notation. The relevant commands to manipulate the interface are:
1 2 |
position startpos moves e2e4 d7d5 ... go movetime 5000 |
The first line sets the board position. The second line specifies how long the computer should spend analyzing the position. (In this case, 5000 = 5 seconds.)
In the console, the program prints its output in real time. It is fun to watch, especially if you type “go infinite”, in which case the computer will analyze indefinitely until you enter “stop”. This is what the output looks like:
Using Python’s subprocess library, I was able to manipulate the engine and its output using Python scripts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import subprocess from time import sleep engine = subprocess.Popen( 'stockfish', stdin=subprocess.PIPE, stdout=subprocess.PIPE, ) def put(command): engine.stdin.write(command+'\n') def move(coords): game.append(coords) game_string = ' '.join(game) put("position startpos moves " + game_string) def analyze(m): last_line = "" move(m) put("go infinite") nextmove = raw_input('> ') if bool(nextmove) == True: put("stop") while True: text = engine.stdout.readline().strip() split_text = text.split(' ') if len(split_text) > 6 and split_text[5] == 'score': score = split_text[7] if split_text[0] == 'bestmove': return {'rightmove': split_text[1], 'ponder': split_text[3], 'info': last_line, 'score': int(score), 'movemade': nextmove} break last_line = text game = [] first_move = raw_input('> ') while True: analysis = analyze(first_move) print analysis first_move = analysis['movemade'] |
The script above analyzes each move the players make and stops analyzing once the next move has been made, at which point it prints out the best move the player could have made along with a “score” for the game so far. The best move will be mapped onto the board’s LEDs and the score will generate auditory/visual feedback. When the score dips below (or above) a certain threshold, one or more of the solenoids beneath the board will activate.
I am very excited to be working on this project. I plan to experiment with various aspects of the overall design until I arrive at the best solutions for each part of it.
Edit: This fictional story I wrote a while back may serve as fodder for the narrative aspect of the project, but I don’t want to give too much away w/r/t specifics at the moment.
Edit2: And these photographs may serve as visual fodder.