User:Brian Schott/code/EinsteinSolver

From J Wiki
Jump to navigation Jump to search

Einstein Puzzle Solver

File:Einsteinsolver.ijs
File:Einsteinsolverloopless.ijs

According to Wikipedia WikiPedia:Zebra_Puzzle the Einstein puzzle is patterned after the Zebra puzzle, but is played on a 6 by 6 board containing rowwise symbols and in some ways resembles Sudoku. A completed puzzle looks like the following one, but with each row permuted according to the clues provided.

123456
ABCDEF
ⅠⅡⅢⅣⅤⅥ
⚀⚁⚂⚃⚄⚅
∆∇◻◇∧∨
+-÷=×√

Einstein.png

Versions of the puzzle have been mentioned in the J forum for Windows [1] and for Macintosh [2].

Clues and their coding

The puzzle starts with a nearly empty board and some clues as to the positional relations between or among the puzzle "markers" or "icons" on the finished board. There are two classes of clues and in the latter class there are three distinct types of clues:


vertical clues in pairs:

Two marker icons are displayed in each clue. The clue tells that the two markers are in the same column and you know what row each icon belongs in because each icon only goes in one predetermined row.

horizontal clues come in pairs except one type that comes in triplets:

One of the pair type rules shows two icons and informs you that those two icons must appear in adjacent columns in the final puzzle board, but you cannot be sure which icon will be on the left or right from their order in the clue. Similarly, the triplet type clues present adjacent icons, but there are three icons instead of two. In the case of the triplet clues you can be sure the three icons are either in the order shown or in the reverse of the order shown, but not which one. Finally, the last type of horizontal clue contains just two icons, and limits the left to right order of the icons in the final puzzle board, but does not imply any adjacency between the icons.

In some puzzles you are also told at the beginning where a few of the icons reside exactly and those icons are typically placed for you by the computer program. In the script provided here, these exact positions are also provided as clues so that the script verb can be naturally dyadic.


Because the unicode glyphs are difficult to manage, the current script substitutes the following ascii characters which are not as pleasant.

   number=: '123456'
   alpha=: 'ABCDEF'
   greek=: 'abcdef'
   chess=: 'rstuvw'
   poly=: '^V#$[]'
   math=: '+-%*=/'
   icons=: ;:'number alpha greek chess poly math'
   ".&>icons
123456
ABCDEF
abcdef
rstuvw
^V#$[]
+-%*=/

As described elsewhere there are various clues provided and typically those clues are shown with coloring and positioning to simplify their use. To make the clues easier to enter into the J verb einstein they are coded in ascii, suggested by the following noun clues. Each clue begins with -- is prefixed by -- a single ordinal number (or 0).

clues=: ];._2 noun define
0+1
11A
2+=
3+-
41BC
)

The zeroth clue 0+1 is of type 0 (it is an "exact" fact and should not be called a clue, really). The clue says that a plus sign goes in column 1. It needn't say what row the icon belongs in because all such math symbols are in the bottom row of all boards.

The first clue 11A is an "order" clue, as signalled by the leading 1 and informs us that the numeral 1 and the capital letter A are in the same column (in their respective rows).

The second clue 2+= is an "order" rule requiring the plus sign to be to the left of the equals sign. Coincidentally here the two icons would be literally next to one another because they are in the same row, but that is unusual for a clue.

The third clue 3+- is an adjacency clue, referred to as adj2 to distinguish it from the last clue type, adj3. This clue limits the plus and minus signs icons to being in columns next to one another, but in either +- or -+ order.

The fourth clue 41BC is an adjacency clue, referred to as adj3. This clue restricts the icons to being either 1BC or CB1 on the board. Notice that the three icons may be all be in one row, or in two rows as here, or in three different rows.

The einstein script attempts to solve puzzles in a very brute force way by generating potential board results pbsr from a list of existing potential boards pbs, starting with a rank 3 board provided as its left hand argument, which is usually 1 6 6$' '. If the noun clues above is supplied to einstein with a typical 6 by 6 board of spaces, 56 potential boards result. Many more clues would be required to produce a unique solution board. In fact einstein does not necessarily produce a single resulting board, but likely produces a single completed board (one with no remaining spaces) among other boards.

      #boards einstein clues
56
      _16]\;/ boards einstein clues
┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│1     │1     │1     │1     │1     │1     │1     │ 1    │ 1    │ 1    │ 1    │ 1    │ 1    │ 1    │  1   │  1   │
│ABC   │ABC   │ABC   │ABC   │ABC   │ABC   │ABC   │ ABC  │ ABC  │ ABC  │ ABC  │ ABC  │ ABC  │ ABC  │  ABC │CBA   │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│-+=   │ +-=  │-+ =  │ +- = │-+  = │ +-  =│-+   =│-+=   │ +-=  │-+ =  │ +- = │-+  = │ +-  =│-+   =│-+=   │-+=   │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│  1   │  1   │  1   │  1   │  1   │  1   │  1   │  1   │  1   │  1   │  1   │  1   │   1  │   1  │   1  │   1  │
│  ABC │CBA   │  ABC │CBA   │  ABC │CBA   │  ABC │CBA   │  ABC │CBA   │  ABC │CBA   │   ABC│ CBA  │   ABC│ CBA  │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│ +-=  │ +-=  │-+ =  │-+ =  │ +- = │ +- = │-+  = │-+  = │ +-  =│ +-  =│-+   =│-+   =│-+=   │-+=   │ +-=  │ +-=  │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│   1  │   1  │   1  │   1  │   1  │   1  │   1  │   1  │   1  │   1  │    1 │    1 │    1 │    1 │    1 │    1 │
│   ABC│ CBA  │   ABC│ CBA  │   ABC│ CBA  │   ABC│ CBA  │   ABC│ CBA  │  CBA │  CBA │  CBA │  CBA │  CBA │  CBA │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│-+ =  │-+ =  │ +- = │ +- = │-+  = │-+  = │ +-  =│ +-  =│-+   =│-+   =│-+=   │ +-=  │-+ =  │ +- = │-+  = │ +-  =│
├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│    1 │     1│     1│     1│     1│     1│     1│     1│      │      │      │      │      │      │      │      │
│  CBA │   CBA│   CBA│   CBA│   CBA│   CBA│   CBA│   CBA│      │      │      │      │      │      │      │      │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
│-+   =│-+=   │ +-=  │-+ =  │ +- = │-+  = │ +-  =│-+   =│      │      │      │      │      │      │      │      │
└──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘

Real puzzles usually require multiple passes through einstein so that commonly it is employed in an infinite iteration as follows (typically it takes only two iterations).

#z=: einstein&clues^:_ boards

Processing approach

einstein processes each clue in a while. loop and inside of that it processes each existing potential board in another while. loop. The internal loop is controlled by select. which chooses its case. using the type of clue presented, so there are 5 major banks of code. Internal to each code block another select. is based upon the number of icons in the clue which match the icons in the potential boards pbs currently being processed. At the bottom of each pass of boards for a clue, pbsr replaces pbs.

I am considering removing some of the for. loops and other repetitious code, but that is not a high priority.

I am more interested in a way to use unicode characters instead of ascii characters in the clues, which means in the processing as well, but I need suggestions on introducing unicode.

I am also considering adding a user interface that allows for clicking and dragging.

Any other comments would be most welcome.

Sample clue sets

A couple of sample clue sets are provided below. Resequencing of the clues can effect the amount of processing required quite dramatically.

         clues=: ];._2 noun define
0b1
0r0
3rt
1t#
4*4#
4#dv
4=$*
3fv
2v]
4%eD
35A
3%5
15/
4^V+
2+s
2u2
2$F
1u3
1Ca
11B
)

clues=: ];._2 noun define
0D4
0]5
44ta
3w1
2A$
2rV
4=3v
4EAv
3Bd
4f1^
3=+
4%#a
3d5
2-]
4V%/
261
3#w
41db
2BF
4vus
1a-
1=c
1A%
)

The following J code produced the canonical final puzzle board shown above, but does not solve any puzzle.

   roman0=: 16b2160
   dice0=: 16b2680
   poly0=: 16b2206 16b2207 16b25fb 16b25c7 16b2227 16b2228
   math0=: 0 1 2 4 3 5{16b002b 16b002d 16b00f7 16b00d7 16b003d 16b221a
   t=: 4&u:  NB. unicode from hex
   seq6=: +&0 1 2 3 4 5
   number=: '123456'
   alpha=: 'ABCDEF'
   roman=: t seq6 roman0
   dice=: t seq6 dice0
   poly=: t poly0
   math=: t math0
   chess=: t chess0
   icons=: ;:'number alpha roman dice poly math'
   ".&>icons
123456
ABCDEF
ⅠⅡⅢⅣⅤⅥ
⚀⚁⚂⚃⚄⚅
∆∇◻◇∧∨
+-÷=×√

Of course a real puzzle would result in a permutation of each of the rows in the canonical display above, and the objective is to discover the correct permutations.

Clue sorting

Sorting the clues can improve processing speed. At one time I thought dramatic speed enhancements could be achieved and so I developed a primitive way to sort clues, only to discover that so far the differential is slight, and rather that some coding bugs were causing most of the problem. In any case, below I am posting the code.

NB. einsteinsolvercluesorter.ijs
NB. 2/14/10

types=: {."1 clues
masktypes=: 1 1 1,~'01' e. types
cluegroups=: ~.types


NB. this para produces sorted trimmed type groups
righttrim=: masktypes#2 1 1 1 0
rtrim=: -righttrim/:cluegroups
typegroups=: masktypes expand rtrim}."1 each ({."1@] </.])clues
typeorder=: masktypes#0 1 4 3 2
s=: typegroups{~"."0 cluegroups/:typeorder

NB. this para produces sorted whole trimmed type groups
wholerighttrim=: masktypes#1 1 1 1 0
wholertrim=:  -(masktypes expand wholerighttrim){~"."0 cluegroups
wholetypegroups=: wholertrim}."1 each ({."1@] </.])clues
swhole=: (masktypes expand wholetypegroups){~"."0 cluegroups/:typeorder

NB. this para computes a markers frequency count
t=: ;<"1&.> s  NB. boxed clue markers
f=: (\: {:"1)@(~. ,. ":@#/.~);, each}."1 &.> s   NB. marker freq counts
b=: </."1/ |.|:f    NB. markers boxed by freq count
fb=: +/+/"1 (|.@(>:@i.@#)*])(}.each t) e.  &>"_ 0  b  NB. clue rank order

NB. this para enables type 0 clues to be first, regardless
zerocluemask=: '0'={.&>t
cluemask=: '0'~:{.&>t
nonzerocluesingroups=: ((\:~@]) </. (]\:~i.@#))cluemask#fb
twhole=: (<"1 ;swhole)/:cluemask   NB. zero clues to front

NB. this para collects information to sort clues
cluesingroups=: (<i. +/zerocluemask),(+/zerocluemask)+ each nonzerocluesingroups
cluesortorder=: typeorder i.".@{.&> twhole
order=: ;cluesingroups /: each cluesingroups{each"0 1 <cluesortorder
clues2=: >order {twhole

NB. the global list `clues` is sorted in the global list `clues2`
NB. when this script is run
NB. the script attempts to sort according to the hueristic
NB. I described and revised in the jforums
NB. http://www.jsoftware.com/pipermail/programming/2010-February/018476.html

There seems to be some confusion in the code above between a "dice" (shown) and "chess" (not shown) set of icons. -- Devon McCormick <<DateTime(2010-02-17T17:48:30-0200)>>