Recollecting My Thoughts

Common methods in uncommon ways

GAME TREE SEARCH

MijitR - Telling The Story: A tribute to Earl.

1/1/202511 min read

There are a lot of resources available to help understand this topic, so I will try to present this in some fancy fashion.

You awaken in an alleyway with a chess fairy and, as per usual, a nearly overwhelmingly strong sense of self love. The fairy begins chirping:

Genny :: You're awake! Finally! Solver! We must away!

As the panicked fairy guides you out of the alley, you come across a gate blocking your path with a sign reading
"Make the right move to continue :: rnbqkbnr/pppppppp/8/P1B3P1/2B2P2/2N2N2/7P/R2QK2R w - -"

A hole in the gate opens and somebody throws through it a pencil and paper. The paper has room for your written answer and little more.

Genny :: You know what I'm capable of. Solver, you know what you must do.

The fairy is as a chess board, able to represent a position, provide a static score for the position, and list moves available from said position, while providing a palette upon which to paint a few paths of play. You must devise a plan to solve not only this gate's problem, but the many problems of this type that shall follow it along your path. Damn good thing your attention span is second only to your force of will.

I offer you my notes on a general 'solution.' The core method is known as NegaMax. Let's get started.


Zero Sum - Chess is considered a zero sum game. We can abuse this by taking it literally in the sense that "what change is good for you must be proportionately bad for me, per change." If the change were my move to capture a pawn from a state of prior equilibrium, the +1 for me is a -1 for you according to a static score involving material. Note: It is not my score maintaining itself while yours drops to zero, but mine statically improving between two measured positions for some measured reasons. If I query the fairy for a position score, and then pass my turn and query again on the same position, I will get the negative of the score I got before passing my turn. One's loss is the other's immediate gain, and light's score is always opposite that of dark's, at any given instance.

Do note that the fairy doesn't really have to respect such things, but donchya know, fate saddled you with quite the "fair-y", one that doesn't enjoy such destabilization.

Deterministic - Moves in chess are well defined. Decisions, while many, are well defined. There is little effective chance that when you want to play e2e4 the h pawn spontaneously moves instead, and when you go to make the same move on the same position twice the outcome is going to be the same. Chess may not throw dice, while chess players may. This is central and will be used as a backbone for the solution.

Static Positional Scoring - The fairy, whose job it is to hold the current state of the chessboard for you, will always respond to an evaluation query with a score relative to the side to move. A positive value indicates that the side to move is up in score, even if dark is the side to move. This score will include positional, strategy analyzing, and material balance metrics, and will ALWAYS only be based on the immediate position.

If dark is to move and up 25 points on this score but light got fortunate and landed a checkmate last turn, the returned static score for the position will be 25. EVEN IF LIGHT HAS A CHECKMATE AGAINST DARK ACTIVELY, the static score is 25 with dark to move. In fact, on the turn prior, as light lands the checkmate, the score would have been negative. Given no major board disturbance and no capture on the mate, it's likely that the static score was around -25 for light as they are landing checkmate.

Moves - This fairy is incredible. Can list legal moves from any position it shows and adapt itself to suit any one of those moves played. A move generator / static score provider. You only get one.

Game Tree Search

"Given a chessboard and being asked to make a move is the equivalent of being inside a maze and deciding which of the directions to go next. Sometimes there may be easily readable signs telling you precisely which way to go. I argue that there always are signs, and it depends on your ability to read them. Chess is its own cheat sheet." - Some... body once told me the world is gon...

Since we were granted with this fairy, and since chess can be described as zero sum and deterministic, we have the tools to come to an absolute conclusion to the problem presented by the gate, even if we aren't yet sure that we an accomplish the task within our lifetime. In fact, I find that the entire problem becomes about time to solution on the outset, since solution is guaranteed given long enough.

This is because we can apply a methodology known as NegaMax.
Other ways to determine piece moves could be things like:

Static Score hillclimbing:

One possible approach to chess. Also known as lookAheadOne, is a method where, from each position, every possible move is played and a resulting evaluation notated corresponding to the root node and the move played. I.E. if I could push two pawns or move my king one square, I would have some mapping like "(e3,e4-> +120) (h4,h5-> +125) (h3,g3-> +220)", each score determined by making the move, querying a positional value, unmaking the move on the board, and inverting the score received (remember the score measures the opponent's favor on their turn, but we need to maximize favor relative to us). These scores indicate to me that all moves are winning and the lateral king move likely captures a pawn. The scoring is then used in a greedy fashion and the highest score can be used to represent the score of the position. Do note, this will likely fail to find checkmates explicitly, since the static score is never one of mate (see earlier). This can be assisted in some fashion via the evaluation function and some piece mobility metrics. (That is to say, the opponent having no moves left is a good thing, but that may require further analysis and with it time spent.)

Statically planned graph traversal:

I argue that if we make each available move on the board, chaining each available response upon each available response, and record the score for each position somewhere in our amazing memory, we can come up with a static mapping of the game tree from the board's current state as the root node, some potentially cyclic graph, lest I overreach.

We could then highlight all the winning/won positions and plan routes to get to them from the root node.

We would likely be rudely awakened by deploying such a strategy, however, since the opposing player will not decide moves based on where we want them to go for us to win. If I have a move that compromises me but I see leads to a win, but requires that they make a horrendous move in order for me to secure that win, I am quickly thwarted and weakened now as they don't follow my devious plan.

- UNLOCKED NEW ACHIEVEMENT :::

  • Understanding the concept of hope chess, the bane of chess players across the globe.

Dynamically planned static graph traversal using static score hillclimbing (NegaMax territory):

In order to continue I need to re-scope what it means for a move to be good. A good move now is not one that simply leads to a favorable static score for the player, but one that equally well limits the opps from achieving a better score. This implies a lookAheadOne search for the opponent after each of my possible moves. If I capture a knight with my pawn (normally good) but it allows my giga opps to capture my queen with a rook (their one-move look-ahead), the move should correspond to a worse score for the position, replacing the value I perceived with the value realized by the opponent. Chaining lookAheadOnes like this should result in realistic lines of play leading to realistic scores for each possible move. Again, a greedy approach can be taken: the move corresponding to the highest score for the position can be chosen. A mate score can be generated once a position is queried for moves and produces none.

Mate score: Equal to +/- 10000 or 0, depending on who is in check, if anybody. Notably only provided as a result of 'failed' move generation, performed here only during search. This will never be returned as a value from the Static Score from before.

Depth First By Nature:
Even on a single lookAheadOne search, even as each available move from the root position is investigated in direct series (widthy), each move is first played to full depth (depth 1) before being scored: depth before width. Chaining these lookAheadOnes will inherently be a depth-first endeavor, and the first possible static score for the root position, sans optimizations, will come from a position 'depth' ply of play removed into a possible future from the root. Assuming a depth 2 search, only the nodes reached after each of the opponents responses to our moves, on our turn again, will be queried for a static score. The score from each leaf is handed back to its parent and inverted in value (negated). This allows our theoretical opponent to choose the best value position of ours that they could reach with a simple max() function. Once each leafs parents have decided on a score that we now believe the opponent would make on their turn, each parent reports its score back to the root, which negates it again and corresponds the negated score to the move that created the parent originally. From the root then, we simply choose the move with the highest score with our ubiquitous max() function, and that score comes to define the value of the position given that depth of search.
Hence the name "
Negamax", which leaves us with an educated guess to claim the winningest move in the position.. where the deeper the search completed, the more educated the guess and informed the claim.

Note: so far, we need to 'campus the map', so to speak, by evaluating a score at each of the terminal, or 'leaf' (because it looks like a tree), nodes reached at the end of each chaining of lookAheadOne searches. This method should be trivially parallelize-able, but be warned:
EVEN AT SEEMINGLY LOW DEPTH, THE TREE CAN GROW INCREDIBLY LARGE, WITH BILLIONS ON BILLIONS OF LEAF NODES.
Your patience is one of two things stopping you from solving chess.. that and the heat death of the universe.

Combination space grows considerably faster than the counting numbers from which it is defined.


Alpha Beta and the ironically effective single threaded search
(Genny - The Luck of The Solver : The Representer of Boards : The Oracle's Guiderails):

The greatest claim:
If offered one million non-communicative workers to help search the tree together, or Genny, the fairy you were lucky enough to have stumbled upon you, it would behoove one to get fairied.

This is because we can exploit the fact that we have a single worker very easily, with a bit of 'memory', so to speak. As Genny plays out the positions which you, The Solver, request from her move by move, she can keep track of two especially important values for you; which can help make your decisions by recognizing both hope chess and fruitlessness. We can call these hopeBound and rotBound (as bad fruit is want to do), and they can be as simple as two individual numbers, each a board evaluation made at some point during the search. Consider them labels for each position you enter. Upon discovery of a golden apple, the now-golden parent can abandon the rest of its children (successfully, remember - this is a good thing here.. we're talking chess.) and return to its parent, ultimately as a rotten apple (after negation).
"Fool me once" - People, repeatedly


If a position triggers hopeBound, we must have entered the position with too much 'hope', and can actually immediately stop searching the position any further. We know, by the hopeBound definition, that the opponent would have to work against their own favor for us to arrive there, and I've heard you prefer the smell of fresh air to that of colon.
Sadly, a rotBound position cannot even be successfully determined until each possible move has been searched, as there is always some hope stemming from the fact that we're even searching.. for anything. This is not to say that a rotBound position is not useful in reducing search effort. In fact, due to the Negamax framework, a rotBound position at a depth of some ply from the root node will report its out-of-bounds (failing low) score to its parent, who can then, in turn, realize that the golden apple (negated rotting apple) it sees is in fact no realistic fruit and simply a product of hope.

A parent discovering all rotten apples defines itself as rotten, and reports to its parents, in their eyes as a golden apple.


I.E. - Successfully discovered rotting children allow their grandparents to know when to abandon their entire lineage...
"Chess is love! Chess is life!" - The angry guy in a hat won't quit yelling things from the back

Move Ordering: Wut du? How so?:

There's one caveat to the useful, fruit coloring glasses offered by Genny; every time you step into a new position, the glasses cannot discern of the fresh fruit. You can imagine, Solver, that if the prize fruit of the batch were the last piece of fruit you analyzed, each of the others would have been thoroughly searched already, leading to complete knowledge of their rotten state or potential juicyness (remember, if a golden apple is found, we abandon the children and report to our parents (us in the past) as a failure (fail-low, after negation). We've also established that, should the final fruit come back rotten in addition to all the others, your parents can leave the rest of their children behind, because you are a golden fruit (fail-high after negation). This implies that, with the absolutely worst-case of choosing which moves to search from each given position, you're going to wind up searching the entire game tree to that depth, as each child will be a slightly juicier fruit (please sue me).

The glasses will work most optimally for you if you can identify golden apples quickly. Remember, we're trying to trim the tree, by abandoning as many children as possible. Remember also: the value of the position is defined by the highest scoring fruit child of a move.
If a golden apple is so high scoring as to be unrealistic in nature, and we desperately want to find those first, I argue that we should put the most 'promising' moves at the front of our 'list to search', so that when we begin our depth-first analysis of them, we are likely to find higher scores sooner.


Don't take the child-abandonment solves game theory thing too far.. different aspects of life may yield, and ipso facto, call for, different solutions.

-- The Truth: Alpha-Beta Negamax ("Glow-Fruit Sifting" [powered by node abandonment]) relies heavily on a devious and accurate move-sorting protocol.

How do you sort moves without searching them? Perhaps static positional analysis.
Take a quick look at the board at the locations of the moves themselves. Is the move a low value piece capturing a high value piece? Probably belongs somewhere higher on the list. Does the move put your queen directly in the line of fire of the enemy? Sit on it for a bit by putting it lower on the list. Move promotes? Promote the move.

In fact, I would argue that an investment here would benefit a stable Fruit Sifting in finery of details, despite accompanying compute time, more than most optimizations, due to its compounding effects with most other operations.. if you have a move scoring oracle, you have a direct line out of the maze. By never suggesting more than one, or occasionally two, sub-optimal moves to search, the greater the branching factor the less we exert in ratio to potential, with continuous gains relatively. This has an effect across the search width, while several other optimizations act upon the depth. This seems like a multiplicative influence.. compounding in the event of inclusion.

Let me speak more literally on the function I'm trying to describe: