Victory!

The Logic Games project now officially solves its first game! It's admittedly a pretty manual process right now. I still have to break the logic game up into all the initial rules and facts. But then it successfully runs through the rule engine and generates all the facts that can be inferred, and answers the question.

Here's the game it solves right now:

Seven consecutive time slots for a broadcast, numbered in chronological order 1 through 7, will be filled by six song tapes - G, H, L, O, P, S - and exactly one news tape. Each tape is to be assigned to a different time slot, and no tape is longer than any other tape. The broadcast is subject to the following restrictions:

  • L must be played immediately before O
  • The news tape must be played at some time after L
  • There must be exactly two time slots between G and P, regardless of whether G comes before P or whether G comes after P
If G is played second, which one of the following tapes must be played third?
  • The news
  • H
  • L
  • O
  • S
If you grab the code from github, and run

ruby logic_games.rb games

it will correctly tell you L is in the 3rd position.
Yay!

It was interesting to me that there were a lot of rules that I was using intuitively when I solved the problem by hand, but that I neglected to add to rule base because I never explicitly acknowledged the rule in my head. An example of this is the rules and facts generated by the combination of the fact that L must be played immediately before O, and the News must be played some time after L. What that implicitly means is that the News must be at least 2 slots after L, because the slot immediately after L is taken up by O. These types of rules will be the hardest to generalize, because they need to take external knowledge (previous statements) into account.

So the next step is to start generifying the logic for creating rules and facts. I would like to come up with some sort of DSL for specifying knowledge in a way that approximates the written game statements. So, for example, to specify that L must be played immediately before O, you might have something like

"L".before("O", 1)

which would translate into "The entity with the name of 'L', must be positionally before the entity named 'O', by 1 position." This would then generate the 20 or so rules that this implies, like "If L is in position 1, then O is in position 2", etc.

So, to accomplish this, I'm going to work on implementing several other games so I can start getting a feel for the types of generalizations I'll need to implement. Then I'll go from there.

Good times.