Download
$ Black Hole 

$ starting from 17 stacks of 3 cards and the spades ace in the middle 
$ (the black hole), cards are put on top  of the black hole. 
$ It will accept a card if its rank is one greater or one less than 
$ the rank of the card currently on top of it. The objective is to 
$ remove all the cards from the stacks onto the black hole.
$
$ modelled by Andrea Rendl
$ after the model in 'Search in the Patience Game 'Black Hole'.'
$ I. Gent, C. Jefferson, I. Lynce, I. Miguel, P. Nightingale, B. Smith and A. Tarim

language ESSENCE' 1.0

letting noSteps be 51
letting STEPS be domain int(0..noSteps)
letting STEPS1 be domain int(1..noSteps)

letting SPADES be 0
letting HEARTS be 1
letting CLUBS be 2
letting DIAMONDS be 3

letting CARDS_NO_ACE be domain int(1..51) 
letting SUITS be domain int(0..3)
letting CARDS be domain int(0..51)
letting CARDS_ZERO be domain int(0..50)

given initialStacks : matrix indexed by [CARDS_ZERO] of CARDS_NO_ACE 

letting CONSECUTIVE_CARD_TABLE = 
     [  [0,1], [0,14], [0,27], [0,40], [0,51], [0,12], [0,25], [0,38], 
        [1,2], [1,15], [1,28], [1,41], [1,0], [1,13], [1,26], [1,39], 
        [2,3], [2,16], [2,29], [2,42], [2,1], [2,14], [2,27], [2,40], 
        [3,4], [3,17], [3,30], [3,43], [3,2], [3,15], [3,28], [3,41], 
        [4,5], [4,18], [4,31], [4,44], [4,3], [4,16], [4,29], [4,42], 
        [5,6], [5,19], [5,32], [5,45], [5,4], [5,17], [5,30], [5,43], 
        [6,7], [6,20], [6,33], [6,46], [6,5], [6,18], [6,31], [6,44], 
        [7,8], [7,21], [7,34], [7,47], [7,6], [7,19], [7,32], [7,45], 
        [8,9], [8,22], [8,35], [8,48], [8,7], [8,20], [8,33], [8,46], 
        [9,10], [9,23], [9,36], [9,49], [9,8], [9,21], [9,34], [9,47], 
        [10,11], [10,24], [10,37], [10,50], [10,9], [10,22], [10,35], [10,48], 
        [11,12], [11,25], [11,38], [11,51], [11,10], [11,23], [11,36], [11,49], 
        [12,13], [12,26], [12,39], [12,0], [12,11], [12,24], [12,37], [12,50], 
        [13,14], [13,27], [13,40], [13,1], [13,12], [13,25], [13,38], [13,51], 
        [14,15], [14,28], [14,41], [14,2], [14,13], [14,26], [14,39], [14,0], 
        [15,16], [15,29], [15,42], [15,3], [15,14], [15,27], [15,40], [15,1], 
        [16,17], [16,30], [16,43], [16,4], [16,15], [16,28], [16,41], [16,2], 
        [17,18], [17,31], [17,44], [17,5], [17,16], [17,29], [17,42], [17,3], 
        [18,19], [18,32], [18,45], [18,6], [18,17], [18,30], [18,43], [18,4], 
        [19,20], [19,33], [19,46], [19,7], [19,18], [19,31], [19,44], [19,5], 
        [20,21], [20,34], [20,47], [20,8], [20,19], [20,32], [20,45], [20,6], 
        [21,22], [21,35], [21,48], [21,9], [21,20], [21,33], [21,46], [21,7], 
        [22,23], [22,36], [22,49], [22,10], [22,21], [22,34], [22,47], [22,8], 
        [23,24], [23,37], [23,50], [23,11], [23,22], [23,35], [23,48], [23,9], 
        [24,25], [24,38], [24,51], [24,12], [24,23], [24,36], [24,49], [24,10], 
        [25,26], [25,39], [25,0], [25,13], [25,24], [25,37], [25,50], [25,11], 
        [26,27], [26,40], [26,1], [26,14], [26,25], [26,38], [26,51], [26,12], 
        [27,28], [27,41], [27,2], [27,15], [27,26], [27,39], [27,0], [27,13], 
        [28,29], [28,42], [28,3], [28,16], [28,27], [28,40], [28,1], [28,14], 
        [29,30], [29,43], [29,4], [29,17], [29,28], [29,41], [29,2], [29,15], 
        [30,31], [30,44], [30,5], [30,18], [30,29], [30,42], [30,3], [30,16], 
        [31,32], [31,45], [31,6], [31,19], [31,30], [31,43], [31,4], [31,17], 
        [32,33], [32,46], [32,7], [32,20], [32,31], [32,44], [32,5], [32,18], 
        [33,34], [33,47], [33,8], [33,21], [33,32], [33,45], [33,6], [33,19], 
        [34,35], [34,48], [34,9], [34,22], [34,33], [34,46], [34,7], [34,20], 
        [35,36], [35,49], [35,10], [35,23], [35,34], [35,47], [35,8], [35,21], 
        [36,37], [36,50], [36,11], [36,24], [36,35], [36,48], [36,9], [36,22], 
        [37,38], [37,51], [37,12], [37,25], [37,36], [37,49], [37,10], [37,23], 
        [38,39], [38,0], [38,13], [38,26], [38,37], [38,50], [38,11], [38,24], 
        [39,40], [39,1], [39,14], [39,27], [39,38], [39,51], [39,12], [39,25], 
        [40,41], [40,2], [40,15], [40,28], [40,39], [40,0], [40,13], [40,26], 
        [41,42], [41,3], [41,16], [41,29], [41,40], [41,1], [41,14], [41,27], 
        [42,43], [42,4], [42,17], [42,30], [42,41], [42,2], [42,15], [42,28], 
        [43,44], [43,5], [43,18], [43,31], [43,42], [43,3], [43,16], [43,29], 
        [44,45], [44,6], [44,19], [44,32], [44,43], [44,4], [44,17], [44,30], 
        [45,46], [45,7], [45,20], [45,33], [45,44], [45,5], [45,18], [45,31], 
        [46,47], [46,8], [46,21], [46,34], [46,45], [46,6], [46,19], [46,32], 
        [47,48], [47,9], [47,22], [47,35], [47,46], [47,7], [47,20], [47,33], 
        [48,49], [48,10], [48,23], [48,36], [48,47], [48,8], [48,21], [48,34], 
        [49,50], [49,11], [49,24], [49,37], [49,48], [49,9], [49,22], [49,35], 
        [50,51], [50,12], [50,25], [50,38], [50,49], [50,10], [50,23], [50,36], 
        [51,0], [51,13], [51,26], [51,39], [51,50], [51,11], [51,24], [51,37]]


$ the sequence of ranks for each step
find blackHole : matrix indexed by [STEPS] of CARDS
$ the cards and their position in the sequence
find cardSequence : matrix indexed by [CARDS] of STEPS

such that 

$ initial state: the spades ace in in the middle
blackHole[0] = 0,
cardSequence[0] = 0, 
      
allDiff(cardSequence),
allDiff(blackHole),

forAll step : STEPS1 . 
   table([blackHole[step-1],blackHole[step]], CONSECUTIVE_CARD_TABLE),

$ precedence constraint
   forAll card : int(0..50) . 
       (card % 3 != 2) ->
          (cardSequence[initialStacks[card]] < cardSequence[initialStacks[card+1]]),

$ channelling constraint
forAll step : STEPS . 
  forAll card : CARDS . 
     (blackHole[step] = card) <-> (cardSequence[card] = step),


$ Barbara's constraint or what I interpreted from it
$ if we have the choice between 2 cards of the same rank, pick the one with higher height
$forAll card1,card2 : CARDS_NO_ACE .
    $ 2 cards of the same rank but different suits 
$    ((card1 % 13 = card2 % 13) /\ (card1 != card2)) -> 
       $ the card that is on top of a pile should be picked first 
$        ((height[card1] > height[card2]) -> (cardSequence[card1] > cardSequence[card2])),



$ conditional symmetry breaking


$ if two cards of the same rank are on the bottom of a stack then take the smaller one
$ CASE A of Barbara's model
forAll stack1, stack2 : int(0..16) . 
      ( (stack1 < stack2) /\  $ the 3rd cards have the same rank
        (initialStacks[stack1*3+2] % 13 = initialStacks[stack2*3+2] % 13)
      ) -> 

             $ y[cover[c1] < y[c2]   ->  y[c1] < y[c2]
        (   (cardSequence[initialStacks[stack1*3+1]] < cardSequence[initialStacks[stack2*3+2]] 
                 ) -> 
            (cardSequence[initialStacks[stack1*3+2]] < cardSequence[initialStacks[stack2*3+2]])   
        ),


$ if two cards of the same rank are on top of a stack
$ CASE B of Barbara's model
forAll stack1, stack2 : int(0..16) . 
      ( (stack1 < stack2) /\  $ the 1st cards have the same rank
        (initialStacks[stack1*3] % 13 = initialStacks[stack2*3] % 13)
      ) -> 

             $ y[c1] < y[coveredby[c2]]  ->  y[c1] < y[c2]
        (  ( cardSequence[initialStacks[stack1*3]] < cardSequence[initialStacks[stack2*3+1]]  
                 ) -> 
             ( cardSequence[initialStacks[stack1*3]] < cardSequence[initialStacks[stack2*3]] )
           
        ),

$ 2 cards are in the middle 
$ CASE C of Barbara's model
forAll stack1, stack2 : int(0..16) . 
    ( (stack1 < stack2)  /\  $ different stacks and cards in the midle are of the same rank
            (initialStacks[stack1*3+1] % 13 = initialStacks[stack2*3+1] % 13) 
    ) -> 
       $ (y[c1] < y[coveredby[c2]  &&  y[cover[c1]] < y[c2] )  ->  y[c1] < y[c2]
    ( ( (cardSequence[initialStacks[stack1*3+1]] < cardSequence[initialStacks[stack2*3+2]]) /\
        (cardSequence[initialStacks[stack1*3]] < cardSequence[initialStacks[stack2*3+1]])
      )  ->
         ( cardSequence[initialStacks[stack1*3+1]] < cardSequence[initialStacks[stack2*3+1]])
    ),


$ if two cards have the same rank and one is on top and the other the last of a stack take the top one first
$ CASE D in Barbara's model
forAll stack1, stack2 : int(0..16) . 
    ( (stack1 != stack2)  /\  $ different stacks and cards on top of stack1 and bottom of stack2 are of the same rank
            (initialStacks[stack1*3] % 13 = initialStacks[stack2*3+2] % 13) 
    ) -> 
        ( cardSequence[initialStacks[stack1*3]] < cardSequence[initialStacks[stack2*3+2]]),


$ ADDs more SEARCH for instance 106
$ one card on top, the other in the middle
$ CASE E in barbara's model
forAll stack1, stack2 : int(0..16) . 
    ( (stack1 != stack2)  /\  $ different stacks and cards on top of stack1 and middle of stack2 are of the same rank
            (initialStacks[stack1*3] % 13 = initialStacks[stack2*3+1] % 13) 
    ) -> 
       (   $ y[c1] < y[coveredby[c2] && y[c2] < y[coveredby[c1]]  -> y[c1] < y[c2]
         ( (cardSequence[initialStacks[stack1*3]] < cardSequence[initialStacks[stack2*3+2]] ) /\
           (cardSequence[initialStacks[stack2*3+1]] < cardSequence[initialStacks[stack1*3+1]] )
         ) ->
          ( cardSequence[initialStacks[stack1*3]] < cardSequence[initialStacks[stack2*3+1]])
      ),


$ one card in middle, other on bottom
$ CASE F in barbara's model
forAll stack1, stack2 : int(0..16) . 
    ( (stack1 != stack2)  /\ 
            (initialStacks[stack1*3+1] % 13 = initialStacks[stack2*3+2] % 13) 
    ) -> 
       (   $ y[cover[c1]] < y[c2] && y[cover[c2]] < y[c1]  -> y[c1] < y[c2]
         ( (cardSequence[initialStacks[stack1*3]] < cardSequence[initialStacks[stack2*3+2]] ) /\
           (cardSequence[initialStacks[stack2*3+1]] < cardSequence[initialStacks[stack1*3+1]] )
         ) ->
          ( cardSequence[initialStacks[stack1*3+1]] < cardSequence[initialStacks[stack2*3+2]])
      )