After successfully threading A.Q. Squares and getting it cleaned up for release, I discovered an unfortunate truth: the threaded version is slower than the single-threaded version. Right now my guess is that the reason for the slower performance is due to how to work with threads. Rather than keeping a pool of threads to assign work, I create threads when there is a semaphore free. It is possible the thread creation is slow. But I haven't tested this theory.

Snow!!

At long last, snow! I only first saw furies on November 30 which is quite late in the season. The weather had mentioned a chance for snow today, but we ended up with over 2 inches which is far more than I was expecting. Fired up the snowblower and made quick work of the walks and driveway. Then biked down to the coffee shop so I could sit in front of the fire while I enjoyed the snowfall.

I have had nothing but trouble getting this motherboard to work, but it finally runs now. I did an extended RAM test with it a few days ago and with the RAM checking out it is time to test the hard drives. I don't have the case free these drives will be using, so I have made something much more make-shift. Just using the box the drives arrived in. All the drives passes the quick test. Now it is time for the extended testing.

December 05, 2016 at 7:38 PM

Happy December!

Added some new fetchers to my game A.Q. Squares. In brainstorming some ideas with my coworker Chris, I found I could avoid having to return a list of best moves by multiplying up the score of a move and adding some random amount to it. It works like this: the score of the game is an integer. Thus the closest two scores can be to one an other is a single digit apart (1 to 2, or 14 to 15). If we add a random number between 0 but less than 1 to the score, it won't really have an effect on what score is higher when traversing the game tree. However, by adding a random value, two moves that have the same integer score will (very likely) not have the same actual score. Say three moves produce a score of 15. Let's say the random numbers for the scores are a:15.563, b: 15.942, c: 15.231. Here, score b is chosen because it is the highest. This allows the selection to be done while the game tree is being traversed rather than when the traverse is finished.
The first change was fairly trivial. The second change I made was adding the ability to stop an AI evaluation before it finishes. This is accomplished by adding a thread that sleeps for some timeout period and then signals the worker threads to stop searching. I knew that if I implemented this, the AI would only ever traverse moves toward the top left which is where the playing field begins. I needed the AI to traverse the game tree in a more random fashion. That isn't hard. As the evaluation loops through possible moves, it could use an array that has shuffled the move indexes. However, shuffling an array each time a field of moves needs to be evaluated is costly. So rather than have a completely random shuffle, I thought about reusing a per-computed shuffle table. That would at least keep the AI from doing the exact same thing each time. Better still is selecting randomly from a set of shuffle tables. The shuffle sets are created each time before recursion begins so there isn't any way of knowing what the set will be. In addition, the set selection is chosen at random.
The results: not too impressive. Cutting off the AI early seems to just mean the AI plays extremely poor when there are a lot of moves to consider. But it was an interesting exercise.

Steve and Tyson

The month has finished up, and I ended up logging 318 miles over 14 different rides. This is a significant increase from last year's 109 miles. November has been exceedingly warm, allowing many more rides than what I would typically be able to do. Today was the first day I saw snow furies which is kind of crazy--I typically see furies in late October, not the last day of November.

Threads!

Noir Dragon Fireside

Since releasing the GUI interface of A.Q. Squares, I have been working on threading the AI. Over the weekend, Tyson delivered what has earned the right to become my new laptop. It is called the Noir Dragon, and accompanied me this weekend to a local coffee shop so that it could prove its worthiness. I was pleased with the performance and the newest dragon has joined the hive.
Threading A.Q. Squares has been a tricky task. The AI unit is what will primarily benefit from the threading. The question is, how does one thread the mimimax algorithm? For this application, the answer is fairly simple: start a thread for each node at the top of the search tree. Each thread will then traverse that branch of the tree. Each moves usually has a dozen or two top level moves, so most of the time there are plenty of threads. To utilize threads efficiently I wanted to employ a semaphore that allows only a specified number of threads to run at a time. I used this in my prime number counter, having the number of threads running at once equal to the number of CPU cores available.
One thing I didn't want to do was duplicate code. So I went through several iterations of rearranging the recursive minimax loop to see how to I could inject something that could separate the top level from the remaining levels without duplicating code. What I came up with was to have the search state specify the recurse function. The first time though, the recurse function will dispatch the nodes to worker threads. The remaining searches will simply recurse.
This evening I got the system working. Letting the game play itself in demo mode will pound the processor pretty good. Removing delays from the game and letting it run wide open without animation taxed my 8-core CPU 100%, but the results are clear being calculated in parallel. I added one more thread level. When an AI evaluation is to take place, a dispatch thread is created. This keeps the AI from blocking the user interface during the calculations. When the AI completes, an event is posted just like the UI. That allow the game state machine to always be momentary, and UI run independent from the AI.
The code is pretty clean but I don't have time to release it tonight. Since the game is playable to the general public I'm not too worried about getting this one online. We can take our time and get the testing done correctly.

The crew loaded up with food and supplies and set sail from Absalom with the river lands as the destination. While sailing the crew spotted a huge sea creature, and the sea-elf, Kint, and wereshark, Tavon, were sent into the water to investigate. The crew was put on alert with cannons pointed toward the water. They discovered a strange slim that when Tavon entered it he began to choke a bit, then breath normally underwater. But when Tavon come to the surface, he began to choke until he went back under water. A dingy was dispatched to collect Tavon as well as a small barrel to collect some of this strange ooze. Once back on the ship, Tavon was placed in the bilge which had been flooded with sea water for the crew members who require seawater to survive (we destine for freshwater rivers). Vothwin, the closest we have to a medic, looked into Tavon. With no other signs of the sea creature the ship again set sail but keeping a closer eye on the water. In a few hours, the effects of the ooze wore off and Tavon was again able to breather normally out of water.
At the mouth of the rivers we ported and the crew went for shore-leave. Vishtorian and the kids stayed on the ship and the rest of the crew went to the pub. Naturally, they got into a bar brawl. It started when someone pushed over Vothwin and called him a half-bread. Not a good idea in a bar full of drunk shipmates who are all half-breads. Kint started with a return push and knocked the offender to the ground, but by this time people we grabbing weapons. Zilrock, a half-ork/half-dwarf, was looking to set an example for the would-be scrappers. Seeing one people with a sword he grabbed his maul spear and in a very impressive feat with a loud outburst shattered the swoard in a single swing. It was such an effective show of force that several people tried to runaway. Crampas followed up shooting an other in the head and with a good role managed to shoot through the adversary and also hit the one behind him, killing them both. The enmey did try and fight back, and Zilrock was hit for a pretty serious blow. But the remaining people scattered, which, coincidentally, condensed with having to finish up for the evening.
While all these shenanigans going on in the bar, Vistorian was busy back on the ship putting the kids to work and trying to gain some information about the river lands and local politics. Upon her return to her quarters, she entered to find a large Cambion sitting at her desk. Vishtorian can telepathically talk to creatures aligned evil and quickly called the kid—a scrag, an ettien, and a cyclops, all young but still quite large. The Cambion could hear this summons and stated as much, and to discourage any interruption summered some kind of fire monster on deck. Vishtorian could tell the creature was far more powerful than anything she could handle and went about finding out what it wanted. The creature was her father. Vishtorian is a tiefling. Her mother had been raped by a daemon under the command of the Cheliax. This left her mother unable to have any more children. Vishtorian's mother's husband raised Vishtorian as his own, but never let her forget who and what she was. It was this man she called father, not the daemon who stood before her. And she had nothing but distant for this creature who had killed her mother and robbed her father of his legitimate heir. Vishtorian had never met her actual father before this, but wasn't happy about it. She demanded to know what he wanted, where upon the Cambion stated he was proud to see what Vishtorian had become. He was of course referring to Vishtorian's habit of regularly kidnapping Cheliax and torturing them to death despite their pleas for mercy. Vishtorian was neither apologetic or defensive. She asked if that was all, then told the Cambion to get the hell out. With that, the Cambion did depart, leaving the ship on fire. Vishtorian and the kids then had to scramble to subdue the flames.
When the crew returned, they found a smoldering ship, and Vishtorian a battered crew. But the explanations will have to wait until next time.

A.Q. Square v1.2

I have finished my GUI version of A.Q. Squares and released it. This has been a couple weeks in the making. Since I released A.Q. Squares I have been thinking about adding a GUI front-end. The problem I had was which one? While I have no problem running something in Linux, most people I know wouldn't be able to. So I would need a GUI that worked in both Linux and Windows.
Initially I looked at FLTK. It was suppose to be very light weight and allow for static compiling into a single executable. That seemed like just the thing, but alas, while it worked fine in Linux I couldn't get it to compile correctly in Windows. So I abandon this route and continued my search.
My next tests were with OpenGL Utility Toolkit (GLUT), and more specifically freeglut. This time I was able to get builds compiled and run just fine on both operating systems. With the compile working, it was time to create a user interface.
The implementation required a paradigm shift in the game state machine. With ncurses there was a main loop that waited for keystrokes before advancing. GLUT takes over completely once it is told to run. I could get callbacks from the library, but the state machine as it stood would not work. So I transitioned to an event-driven setup. The game state machine would be in a number of states (waiting for user to select a cell, waiting for animation to complete, etc). Each state advances when an event is received using a master event handler. The user interface then just fires off events for things such as key presses, clicks, and when timers go off. While a bit of rework was required, it wasn't a bad shift and I'm pretty happy with it.
The interface isn't 100% complete. There is no support for arrow keys and I would like the game to be fully functional with keyboard only. I've also toyed with the idea of having both the ncurses and GLUT user interfaces included. But like when I wanted release 1.0 to come out, I wanted 1.2 to go live.
This time, the distribution comes not only with source code, but two binaries for Windows: a 32-bit and a 64-bit. This should allow most other people to download and play the game. I currently have no method for compiling for Mac OSX, so no binary there. But this should be a good start.