object GroupStage extends App { //team left digit vs team right digit
  val games = Array("12", "13", "14", "23", "24", "34")
  val points = Array.ofDim[Int](4, 10) //playing 3 games, points range from 0 to 9
  var results = "000000" //start with left teams all losing

  private def nextResult: Boolean = {
    if (results == "222222") false
    else {
      results = Integer.toString(Integer.parseInt(results, 3) + 1, 3)
      while (results.length < 6) results = "0" + results //left pad with 0s
      true
    }
  }

  do {
    val records = Array(0, 0, 0, 0)
    for (i <- results.indices.reverse by -1) {
      results(i) match {
        case '2' => records(games(i)(0) - '1') += 3
        case '1' => //draw
          records(games(i)(0) - '1') += 1
          records(games(i)(1) - '1') += 1
        case '0' => records(games(i)(1) - '1') += 3
      }
    }
    java.util.Arrays.sort(records) //sort ascending, first place team on the right

    points(0)(records(0)) += 1
    points(1)(records(1)) += 1
    points(2)(records(2)) += 1
    points(3)(records(3)) += 1
  } while (nextResult)

  println("First place: " + points(3).mkString("[",", ","]"))
  println("Second place: " + points(2).mkString("[",", ","]"))
  println("Third place: " + points(1).mkString("[",", ","]"))
  println("Fourth place: " + points(0).mkString("[",", ","]"))

}


package require Tcl 8.6
proc groupStage {} {
    foreach n {0 1 2 3} {
	set points($n) {0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0}
    }
    set results 0
    set games {0 1 0 2 0 3 1 2 1 3 2 3}
    while true {
	set R {0 0 1 0 2 0 3 0}
	foreach r [split [format %06d $results] ""] {A B} $games {
	    switch $r {
		2 {dict incr R $A 3}
		1 {dict incr R $A; dict incr R $B}
		0 {dict incr R $B 3}
	    }
	}
	foreach n {0 1 2 3} r [lsort -integer [dict values $R]] {
	    dict incr points($n) $r
	}

	if {$results eq "222222"} break
	while {[regexp {[^012]} [incr results]]} continue
    }
    return [lmap n {3 2 1 0} {dict values $points($n)}]
}

foreach nth {First Second Third Fourth} nums [groupStage] {
    puts "$nth place:\t[join [lmap n $nums {format %3s $n}] {, }]"
}


import Constraint (allC, anyC)
import Findall (findall)

data House  =  H Color Man Pet Drink Smoke

data Color  =  Red    | Green | Blue  | Yellow | White
data Man    =  Eng    | Swe   | Dan   | Nor    | Ger
data Pet    =  Dog    | Birds | Cats  | Horse  | Zebra
data Drink  =  Coffee | Tea   | Milk  | Beer   | Water
data Smoke  =  PM     | DH    | Blend | BM     | Prince

houses :: [House] -> Success
houses [email protected][H1,_,H3,_,_] =                         --  1
    H  _ _ _ Milk _  =:=  H3                      --  9
  & H  _ Nor _ _ _   =:=  H1                      -- 10
  & allC (`member` hs)
  [ H  Red Eng _ _ _                              --  2
  , H  _ Swe Dog _ _                              --  3
  , H  _ Dan _ Tea _                              --  4
  , H  Green _ _ Coffee _                         --  6
  , H  _ _ Birds _ PM                             --  7
  , H  Yellow _ _ _ DH                            --  8
  , H  _ _ _ Beer BM                              -- 13
  , H  _ Ger _ _ Prince                           -- 14
  ]
  & H  Green _ _ _ _  `leftTo`  H  White _ _ _ _  --  5
  & H  _ _ _ _ Blend  `nextTo`  H  _ _ Cats _ _   -- 11
  & H  _ _ Horse _ _  `nextTo`  H  _ _ _ _ DH     -- 12
  & H  _ Nor _ _ _    `nextTo`  H  Blue _ _ _ _   -- 15
  & H  _ _ _ Water _  `nextTo`  H  _ _ _ _ Blend  -- 16
 where
    x `leftTo` y = _ ++ [x,y] ++ _ =:= hs
    x `nextTo` y = x `leftTo` y
                 ? y `leftTo` x

member :: a -> [a] -> Success
member = anyC . (=:=)

main = findall $ \(hs,who) -> houses hs & H _ who Zebra _ _ `member` hs


import std.stdio, std.traits, std.algorithm, std.math;

enum Content { Beer, Coffee, Milk, Tea, Water,
               Danish, English, German, Norwegian, Swedish,
               Blue, Green, Red, White, Yellow,
               Blend, BlueMaster, Dunhill, PallMall, Prince,
               Bird, Cat, Dog, Horse, Zebra }
enum Test { Drink, Person, Color, Smoke, Pet }
enum House { One, Two, Three, Four, Five }

alias TM = Content[EnumMembers!Test.length][EnumMembers!House.length];

bool finalChecks(in ref TM M) pure nothrow @safe @nogc {
  int diff(in Content a, in Content b, in Test ca, in Test cb)
  nothrow @safe @nogc {
    foreach (immutable h1; EnumMembers!House)
      foreach (immutable h2; EnumMembers!House)
        if (M[ca][h1] == a && M[cb][h2] == b)
          return h1 - h2;
    assert(0); // Useless but required.
  }

  with (Content) with (Test)
    return abs(diff(Norwegian, Blue, Person, Color)) == 1 &&
           diff(Green, White, Color, Color) == -1 &&
           abs(diff(Horse, Dunhill, Pet, Smoke)) == 1 &&
           abs(diff(Water, Blend, Drink, Smoke)) == 1 &&
           abs(diff(Blend, Cat, Smoke, Pet)) == 1;
}

bool constrained(in ref TM M, in Test atest) pure nothrow @safe @nogc {
  with (Content) with (Test) with (House)
    final switch (atest) {
      case Drink:
        return M[Drink][Three] == Milk;
      case Person:
        foreach (immutable h; EnumMembers!House)
          if ((M[Person][h] == Norwegian && h != One) ||
              (M[Person][h] == Danish && M[Drink][h] != Tea))
            return false;
        return true;
      case Color:
        foreach (immutable h; EnumMembers!House)
          if ((M[Person][h] == English && M[Color][h] != Red) ||
              (M[Drink][h] == Coffee && M[Color][h] != Green))
            return false;
        return true;
      case Smoke:
        foreach (immutable h; EnumMembers!House)
          if ((M[Color][h] == Yellow && M[Smoke][h] != Dunhill) ||
              (M[Smoke][h] == BlueMaster && M[Drink][h] != Beer) ||
              (M[Person][h] == German && M[Smoke][h] != Prince))
            return false;
        return true;
      case Pet:
        foreach (immutable h; EnumMembers!House)
          if ((M[Person][h] == Swedish && M[Pet][h] != Dog) ||
              (M[Smoke][h] == PallMall && M[Pet][h] != Bird))
            return false;
        return finalChecks(M);
    }
}

void show(in ref TM M) {
  foreach (h; EnumMembers!House) {
    writef("%5s: ", h);
    foreach (immutable t; EnumMembers!Test)
      writef("%10s ", M[t][h]);
    writeln;
  }
}

void solve(ref TM M, in Test t, in size_t n) {
  if (n == 1 && constrained(M, t)) {
    if (t < 4) {
      solve(M, [EnumMembers!Test][t + 1], 5);
    } else {
      show(M);
      return;
    }
  }
  foreach (immutable i; 0 .. n) {
    solve(M, t, n - 1);
    swap(M[t][n % 2 ? 0 : i], M[t][n - 1]);
  }
}

void main() {
  TM M;
  foreach (immutable t; EnumMembers!Test)
    foreach (immutable h; EnumMembers!House)
      M[t][h] = EnumMembers!Content[t * 5 + h];

  solve(M, Test.Drink, 5);
}


Imports System.Text

Module Module1

    Dim games As New List(Of String) From {"12", "13", "14", "23", "24", "34"}
    Dim results = "000000"

    Function FromBase3(num As String) As Integer
        Dim out = 0
        For Each c In num
            Dim d = Asc(c) - Asc("0"c)
            out = 3 * out + d
        Next
        Return out
    End Function

    Function ToBase3(num As Integer) As String
        Dim ss As New StringBuilder

        While num > 0
            Dim re = num Mod 3
            num \= 3
            ss.Append(re)
        End While

        Return New String(ss.ToString().Reverse().ToArray())
    End Function

    Function NextResult() As Boolean
        If results = "222222" Then
            Return False
        End If

        Dim res = FromBase3(results)

        Dim conv = ToBase3(res + 1)
        results = conv.PadLeft(6, "0"c)

        Return True
    End Function

    Sub Main()
        Dim points(0 To 3, 0 To 9) As Integer
        Do
            Dim records(0 To 3) As Integer
            For index = 0 To games.Count - 1
                Select Case results(index)
                    Case "2"c
                        records(Asc(games(index)(0)) - Asc("1"c)) += 3
                    Case "1"c
                        records(Asc(games(index)(0)) - Asc("1"c)) += 1
                        records(Asc(games(index)(1)) - Asc("1"c)) += 1
                    Case "0"c
                        records(Asc(games(index)(1)) - Asc("1"c)) += 3
                End Select
            Next

            Array.Sort(records)
            For index = 0 To records.Length - 1
                Dim t = records(index)
                points(index, t) += 1
            Next
        Loop While NextResult()

        Console.WriteLine("POINTS       0    1    2    3    4    5    6    7    8    9")
        Console.WriteLine("-------------------------------------------------------------")
        Dim places As New List(Of String) From {"1st", "2nd", "3rd", "4th"}
        For i = 0 To places.Count - 1
            Console.Write("{0} place", places(i))
            For j = 0 To 9
                Console.Write("{0,5}", points(3 - i, j))
            Next
            Console.WriteLine()
        Next
    End Sub

End Module


(lib 'hash)
(lib 'amb)

;; return #f or house# for thing/category
;; houses := (0 1 2 3 4)
(define (house-get H  category thing houses)
        (for/or ((i houses)) #:continue (!equal? (hash-ref (vector-ref H i) category) thing)
        i))

 ;; return house # for thing (eg cat) in category (eq animals)
 ;; add thing if not already here
(define-syntax-rule (house-set thing category)
    	(or
    	 (house-get H 'category 'thing houses)
         (dispatch H 'category 'thing context houses )))

;; we know that thing/category is in a given house
(define-syntax-rule (house-force thing category house)
        (dispatch H 'category 'thing context houses  house))

;; return house# or fail if impossible
(define (dispatch H category thing  context houses  (forced #f))
        (define house (or forced  (amb context houses))) ;; get a house number
        (when (hash-ref (vector-ref H house) category) (amb-fail)) ;; fail if occupied
        (hash-set (vector-ref H house) category thing) ;; else remember house contents
        house)

(define (house-next h1 h2)
 	(amb-require (or (= h1 (1+ h2)) (= h1 (1- h2)))))

(define (zebra-puzzle context houses  )
    (define H (build-vector 5 make-hash)) ;; house[i] :=  hash(category) -> thing
; In the middle house they drink milk.
    (house-force milk drinks 2)
;The Norwegian lives in the first house.
    (house-force norvegian people 0)
;  The English man lives in the red house.
    (house-force red colors(house-set english people))
; The Swede has a dog.
    (house-force dog animals (house-set swede people))
;  The Dane drinks tea.
    (house-force tea drinks (house-set dane people))
;  The green house is immediately to the left of the white house.
   (amb-require (=   (house-set green colors) (1- (house-set white colors))))
;  They drink coffee in the green house.
    (house-force coffee drinks (house-set green colors))
;  The man who smokes Pall Mall has birds.
    (house-force birds  animals (house-set pallmall smoke))
;  In the yellow house they smoke Dunhill.
    (house-force dunhill smoke (house-set yellow colors))
;  The Norwegian lives next to the blue house.
    (house-next (house-set norvegian people) (house-set blue colors))
;  The man who smokes Blend lives in the house next to the house with cats.
    (house-next (house-set blend smoke) (house-set cats  animals))
; In a house next to the house where they have a horse, they smoke Dunhill.
    (house-next (house-set horse animals) (house-set dunhill smoke))
; The man who smokes Blue Master drinks beer.
    (house-force beer drinks (house-set bluemaster smoke))
; The German smokes Prince.
    (house-force prince smoke (house-set german people))
; They drink water in a house next to the house where they smoke Blend.
    (house-next (house-set water drinks) (house-set blend smoke))

;; Finally .... the zebra 🐴
    (house-set 🐴 animals)

    (for ((i houses))
    (writeln i (hash-values (vector-ref H i))))
    (writeln '----------)

    (amb-fail) ;; will ensure ALL solutions are printed
)


import "/fmt" for Conv, Fmt
import "/sort" for Sort

var games = ["12", "13", "14", "23", "24", "34"]
var results = "000000"

var nextResult = Fn.new {
    if (results == "222222") return false
    var res = Conv.atoi(results, 3) + 1
    results = Fmt.swrite("$06t", res)
    return true
}

var points = List.filled(4, null)
for (i in 0..3) points[i] = List.filled(10, 0)
while (true) {
    var records = List.filled(4, 0)
    for (i in 0..5) {
        var g0 = Num.fromString(games[i][0]) - 1
        var g1 = Num.fromString(games[i][1]) - 1
        if (results[i] == "2") {
            records[g0] = records[g0] + 3
        } else if (results[i] == "1") {
            records[g0] = records[g0] + 1
            records[g1] = records[g1] + 1
        } else if (results[i] == "0") {
            records[g1] = records[g1] + 3
        }
    }
    Sort.insertion(records)
    for (i in 0..3) points[i][records[i]] = points[i][records[i]] +1
    if (!nextResult.call()) break
}
System.print("POINTS           0    1    2    3    4    5    6    7    8    9")
System.print("---------------------------------------------------------------")
for (i in 0..3) {
    Fmt.write("$r place    ", i+1)
    points[3-i].each { |p| Fmt.write("$5d", p) }
    System.print()
}


defmodule ZebraPuzzle do
  defp adjacent?(n,i,g,e) do
    Enum.any?(0..3, fn x ->
      (Enum.at(n,x)==i and Enum.at(g,x+1)==e) or (Enum.at(n,x+1)==i and Enum.at(g,x)==e)
    end)
  end

  defp leftof?(n,i,g,e) do
    Enum.any?(0..3, fn x -> Enum.at(n,x)==i and Enum.at(g,x+1)==e end)
  end

  defp coincident?(n,i,g,e) do
    Enum.with_index(n) |> Enum.any?(fn {x,idx} -> x==i and Enum.at(g,idx)==e end)
  end

  def solve(content) do
    colours = permutation(content[:Colour])
    pets    = permutation(content[:Pet])
    drinks  = permutation(content[:Drink])
    smokes  = permutation(content[:Smoke])
    Enum.each(permutation(content[:Nationality]), fn nation ->
      if hd(nation) == :Norwegian, do:                                      # 10
        Enum.each(colours, fn colour ->
          if leftof?(colour, :Green, colour, :White)      and               # 5
             coincident?(nation, :English, colour, :Red)  and               # 2
             adjacent?(nation, :Norwegian, colour, :Blue), do:              # 15
            Enum.each(pets, fn pet ->
              if coincident?(nation, :Swedish, pet, :Dog), do:              # 3
                Enum.each(drinks, fn drink ->
                  if Enum.at(drink,2) == :Milk                   and        # 9
                     coincident?(nation, :Danish, drink, :Tea)   and        # 4
                     coincident?(colour, :Green, drink, :Coffee), do:       # 6
                    Enum.each(smokes, fn smoke ->
                      if coincident?(smoke, :PallMall, pet, :Birds)    and  # 7
                         coincident?(smoke, :Dunhill, colour, :Yellow) and  # 8
                         coincident?(smoke, :BlueMaster, drink, :Beer) and  # 13
                         coincident?(smoke, :Prince, nation, :German)  and  # 14
                         adjacent?(smoke, :Blend, pet, :Cats)          and  # 11
                         adjacent?(smoke, :Blend, drink, :Water)       and  # 16
                         adjacent?(smoke, :Dunhill, pet, :Horse), do:       # 12
                        print_out(content, transpose([nation, colour, pet, drink, smoke]))
    end)end)end)end)end)
  end

  defp permutation([]), do: [[]]
  defp permutation(list) do
    for x <- list, y <- permutation(list -- [x]), do: [x|y]
  end

  defp transpose(lists) do
    List.zip(lists) |> Enum.map(&Tuple.to_list/1)
  end

  defp print_out(content, result) do
    width = for {k,v}<-content, do: Enum.map([k|v], &length(to_char_list &1)) |> Enum.max
    fmt = Enum.map_join(width, " ", fn w -> "~-#{w}s" end) <> "~n"
    nation = Enum.find(result, fn x -> :Zebra in x end) |> hd
    IO.puts "The Zebra is owned by the man who is #{nation}\n"
    :io.format fmt, Keyword.keys(content)
    :io.format fmt, Enum.map(width, fn w -> String.duplicate("-", w) end)
    fmt2 = String.replace(fmt, "s", "w", global: false)
    Enum.with_index(result)
    |> Enum.each(fn {x,i} -> :io.format fmt2, [i+1 | x] end)
  end
end

content = [ House:       '',
            Nationality: ~w[English Swedish Danish Norwegian German]a,
            Colour:      ~w[Red Green White Blue Yellow]a,
            Pet:         ~w[Dog Birds Cats Horse Zebra]a,
            Drink:       ~w[Tea Coffee Milk Beer Water]a,
            Smoke:       ~w[PallMall Dunhill BlueMaster Prince Blend]a ]

ZebraPuzzle.solve(content)


-module( zebra_puzzle ).

-export( [task/0] ).

-record( house, {colour, drink, nationality, number, pet, smoke} ).
-record( sorted_houses, {house_1s=[], house_2s=[], house_3s=[], house_4s=[], house_5s=[]} ).

task() ->
	Houses = [#house{colour=C, drink=D, nationality=N, number=Nr, pet=P, smoke=S} || C <- all_colours(), D <- all_drinks(), N <- all_nationalities(), Nr <- all_numbers(), P <- all_pets(), S <- all_smokes(), is_all_single_house_rules_ok(C, D, N, Nr, P, S)],
	Sorted_houses = lists:foldl( fun house_number_sort/2, #sorted_houses{}, Houses ),
	Streets = [[H1, H2, H3, H4, H5] || H1 <- Sorted_houses#sorted_houses.house_1s, H2 <- Sorted_houses#sorted_houses.house_2s, H3 <- Sorted_houses#sorted_houses.house_3s, H4 <- Sorted_houses#sorted_houses.house_4s, H5 <- Sorted_houses#sorted_houses.house_5s, is_all_multi_house_rules_ok(H1, H2, H3, H4, H5)],
	[Nationality] = [N || #house{nationality=N, pet=zebra} <- lists:flatten(Streets)],
	io:fwrite( "~p owns the zebra~n", [Nationality] ),
	io:fwrite( "All solutions ~p~n", [Streets] ),
	io:fwrite( "Number of solutions ~p~n", [erlang:length(Streets)] ).

all_colours() -> [blue, green, red, white, yellow].

all_drinks() -> [beer, coffe, milk, tea, water].

all_nationalities() -> [danish, english, german, norveigan, swedish].

all_numbers() -> [1, 2, 3, 4, 5].

all_pets() -> [birds, cats, dog, horse, zebra].

all_smokes() -> [blend, 'blue master', dunhill, 'pall mall', prince].

house_number_sort( #house{number=1}=House, #sorted_houses{house_1s=Houses_1s}=Sorted_houses ) -> Sorted_houses#sorted_houses{house_1s=[House | Houses_1s]};
house_number_sort( #house{number=2}=House, #sorted_houses{house_2s=Houses_2s}=Sorted_houses ) -> Sorted_houses#sorted_houses{house_2s=[House | Houses_2s]};
house_number_sort( #house{number=3}=House, #sorted_houses{house_3s=Houses_3s}=Sorted_houses ) -> Sorted_houses#sorted_houses{house_3s=[House | Houses_3s]};
house_number_sort( #house{number=4}=House, #sorted_houses{house_4s=Houses_4s}=Sorted_houses ) -> Sorted_houses#sorted_houses{house_4s=[House | Houses_4s]};
house_number_sort( #house{number=5}=House, #sorted_houses{house_5s=Houses_5s}=Sorted_houses ) -> Sorted_houses#sorted_houses{house_5s=[House | Houses_5s]}.

is_all_different( [_H] ) -> true;
is_all_different( [H | T] ) -> not lists:member( H, T ) andalso is_all_different( T ).

is_all_multi_house_rules_ok( House1, House2, House3, House4, House5 ) ->
	is_rule_1_ok( House1, House2, House3, House4, House5 )
	andalso is_rule_5_ok( House1, House2, House3, House4, House5 )
	andalso is_rule_11_ok( House1, House2, House3, House4, House5 )
	andalso is_rule_12_ok( House1, House2, House3, House4, House5 )
	andalso is_rule_15_ok( House1, House2, House3, House4, House5 )
	andalso is_rule_16_ok( House1, House2, House3, House4, House5 ).

is_all_single_house_rules_ok( Colour, Drink, Nationality, Number, Pet, Smoke ) ->
	is_rule_ok( {rule_number, 2}, {Nationality, english}, {Colour, red})
	andalso is_rule_ok( {rule_number, 3}, {Nationality, swedish}, {Pet, dog})
	andalso is_rule_ok( {rule_number, 4}, {Nationality, danish}, {Drink, tea})
	andalso is_rule_ok( {rule_number, 6}, {Drink, coffe}, {Colour, green})
	andalso is_rule_ok( {rule_number, 7}, {Smoke, 'pall mall'}, {Pet, birds})
	andalso is_rule_ok( {rule_number, 8}, {Colour, yellow}, {Smoke, dunhill})
	andalso is_rule_ok( {rule_number, 9}, {Number, 3}, {Drink, milk})
	andalso is_rule_ok( {rule_number, 10}, {Nationality, norveigan}, {Number, 1})
	andalso is_rule_ok( {rule_number, 13}, {Smoke, 'blue master'}, {Drink, beer})
	andalso is_rule_ok( {rule_number, 14}, {Nationality, german}, {Smoke, prince}).

is_rule_ok( _Rule_number, {A, A}, {B, B} ) -> true;
is_rule_ok( _Rule_number, _A, {B, B} ) -> false;
is_rule_ok( _Rule_number, {A, A}, _B ) -> false;
is_rule_ok( _Rule_number, _A, _B ) -> true.

is_rule_1_ok( #house{number=1}=H1,  #house{number=2}=H2,  #house{number=3}=H3,  #house{number=4}=H4,  #house{number=5}=H5  ) ->
	is_all_different( [H1#house.colour, H2#house.colour, H3#house.colour, H4#house.colour, H5#house.colour] )
	andalso is_all_different( [H1#house.drink, H2#house.drink, H3#house.drink, H4#house.drink, H5#house.drink] )
	andalso is_all_different( [H1#house.nationality, H2#house.nationality, H3#house.nationality, H4#house.nationality, H5#house.nationality] )
	andalso is_all_different( [H1#house.pet, H2#house.pet, H3#house.pet, H4#house.pet, H5#house.pet] )
	andalso is_all_different( [H1#house.smoke, H2#house.smoke, H3#house.smoke, H4#house.smoke, H5#house.smoke] );
is_rule_1_ok( _House1,  _House2,  _House3,  _House4,  _House5  ) -> false.

is_rule_5_ok( #house{colour=green},  #house{colour=white},  _House3,  _House4,  _House5  ) -> true;
is_rule_5_ok( _House1,  #house{colour=green},  #house{colour=white},  _House4,  _House5  ) -> true;
is_rule_5_ok( _House1,  _House2,  #house{colour=green},  #house{colour=white},  _House5  ) -> true;
is_rule_5_ok( _House1,  _House2,  _House3,  #house{colour=green},  #house{colour=white}  ) -> true;
is_rule_5_ok( _House1,  _House2,  _House3,  _House4,  _House5  ) -> false.

is_rule_11_ok( #house{smoke=blend},  #house{pet=cats},  _House3,  _House4,  _House5  ) -> true;
is_rule_11_ok( _House1,  #house{smoke=blend},  #house{pet=cats},  _House4,  _House5  ) -> true;
is_rule_11_ok( _House1,  _House2,  #house{smoke=blend},  #house{pet=cats},  _House5  ) -> true;
is_rule_11_ok( _House1,  _House2,  _House3,  #house{smoke=blend},  #house{pet=cats}  ) -> true;
is_rule_11_ok( #house{pet=cats},  #house{smoke=blend},  _House3,  _House4,  _House5  ) -> true;
is_rule_11_ok( _House1,  #house{pet=cats},  #house{smoke=blend},  _House4,  _House5  ) -> true;
is_rule_11_ok( _House1,  _House2,  #house{pet=cats},  #house{smoke=blend},  _House5  ) -> true;
is_rule_11_ok( _House1,  _House2,  _House3,  #house{pet=cats},  #house{smoke=blend}  ) -> true;
is_rule_11_ok( _House1,  _House2,  _House3,  _House4,  _House5  ) -> false.

is_rule_12_ok( #house{smoke=dunhill},  #house{pet=horse},  _House3,  _House4,  _House5  ) -> true;
is_rule_12_ok( _House1,  #house{smoke=dunhill},  #house{pet=horse},  _House4,  _House5  ) -> true;
is_rule_12_ok( _House1,  _House2,  #house{smoke=dunhill},  #house{pet=horse},  _House5  ) -> true;
is_rule_12_ok( _House1,  _House2,  _House3,  #house{smoke=dunhill},  #house{pet=horse}  ) -> true;
is_rule_12_ok( #house{pet=horse},  #house{smoke=dunhill},  _House3,  _House4,  _House5  ) -> true;
is_rule_12_ok( _House1,  #house{pet=horse},  #house{smoke=dunhill},  _House4,  _House5  ) -> true;
is_rule_12_ok( _House1,  _House2,  #house{pet=horse},  #house{smoke=dunhill},  _House5  ) -> true;
is_rule_12_ok( _House1,  _House2,  _House3,  #house{pet=horse},  #house{smoke=dunhill}  ) -> true;
is_rule_12_ok( _House1,  _House2,  _House3,  _House4,  _House5  ) -> false.

is_rule_15_ok( #house{nationality=norveigan},  #house{colour=blue},  _House3,  _House4,  _House5  ) -> true;
is_rule_15_ok( _House1,  #house{nationality=norveigan},  #house{colour=blue},  _House4,  _House5  ) -> true;
is_rule_15_ok( _House1,  _House2,  #house{nationality=norveigan},  #house{colour=blue},  _House5  ) -> true;
is_rule_15_ok( _House1,  _House2,  _House3,  #house{nationality=norveigan},  #house{colour=blue}  ) -> true;
is_rule_15_ok( #house{colour=blue},  #house{nationality=norveigan},  _House3,  _House4,  _House5  ) -> true;
is_rule_15_ok( _House1,  #house{colour=blue},  #house{nationality=norveigan},  _House4,  _House5  ) -> true;
is_rule_15_ok( _House1,  _House2,  #house{drink=water},  #house{nationality=norveigan},  _House5  ) -> true;
is_rule_15_ok( _House1,  _House2,  _House3,  #house{drink=water},  #house{nationality=norveigan}  ) -> true;
is_rule_15_ok( _House1,  _House2,  _House3,  _House4,  _House5  ) -> false.

is_rule_16_ok( #house{smoke=blend},  #house{drink=water},  _House3,  _House4,  _House5  ) -> true;
is_rule_16_ok( _House1,  #house{smoke=blend},  #house{drink=water},  _House4,  _House5  ) -> true;
is_rule_16_ok( _House1,  _House2,  #house{smoke=blend},  #house{drink=water},  _House5  ) -> true;
is_rule_16_ok( _House1,  _House2,  _House3,  #house{smoke=blend},  #house{drink=water}  ) -> true;
is_rule_16_ok( #house{drink=water},  #house{smoke=blend},  _House3,  _House4,  _House5  ) -> true;
is_rule_16_ok( _House1,  #house{drink=water},  #house{smoke=blend},  _House4,  _House5  ) -> true;
is_rule_16_ok( _House1,  _House2,  #house{drink=water},  #house{smoke=blend},  _House5  ) -> true;
is_rule_16_ok( _House1,  _House2,  _House3,  #house{drink=water},  #house{smoke=blend}  ) -> true;
is_rule_16_ok( _House1,  _House2,  _House3,  _House4,  _House5  ) -> false.


data "12", "13", "14", "23", "24", "34"

dim game$(6)

for i = 1 to 6 : read game$(i) : next

result$ = "000000"

sub ParseInt(number$, base)
    local x, i, pot, digits

    digits = len(number$)

    for i = digits to 1 step -1
        x = x + base^pot * dec(mid$(number$, i, 1))
        pot = pot + 1
    next

    return x
end sub

sub Format$(decimal, base)
    local cociente, i, j, conv$

    repeat
        cociente = int(decimal / base)
        conv$ = str$(mod(decimal, base)) + conv$
        decimal = cociente
        i = i + 1
    until(cociente = 0)

    return conv$
end sub

sub nextResult()
    if result$ = "222222" return false
    res = ParseInt(result$, 3)
    result$ = Format$(res+1, 3)
    while(len(result$) < 6) result$ = "0" + result$ wend
    return true
end sub

sub Sort(array())
    local n, i, t, sw

    n = arraysize(array(), 1)

    repeat
        sw = false
        for i = 0 to n - 1
            if array(i) > array(i + 1) then
                sw = true
                t = array(i)
                array(i) = array(i + 1)
                array(i + 1) = t
            end if
        next
    until(not sw)
end sub

dim points(4, 10)

sub compute()
    local records(4), i, t

    for i = 1 to arraysize(game$(), 1)
        switch mid$(result$, i, 1)
        case "2":
            t = val(mid$(game$(i), 1, 1))
            records(t) = records(t) + 3
            break
        case "1":
            t = val(mid$(game$(i), 1, 1))
            records(t) = records(t) + 1
            t = val(mid$(game$(i), 2, 1))
            records(t) = records(t) + 1
            break
        case "0":
            t = val(mid$(game$(i), 2, 1))
            records(t) = records(t) + 3
            break
        end switch
    next
    Sort(records())
    for i = 1 to 4
        points(i, records(i)) = points(i, records(i)) + 1
    next
    if not nextResult() return false
    return true
end sub

repeat until(not compute())

print "POINTS       0    1    2    3    4    5    6    7    8    9"
print "-------------------------------------------------------------"

dim place$(4)

data "1st", "2nd", "3rd", "4th"
for i = 1 to 4 : read place$(i) : next

for i = 1 to 4
    print place$(i), " place    ";
    for j = 0 to 9
        print points(5 - i, j) using "%-4.0f";
    next
    print
next


PROGRAM ZEBRA_PUZZLE

DIM DRINK$[4],NATION$[4],COLR$[4],SMOKE$[4],ANIMAL$[4]
DIM PERM$[120],X$[4]

PROCEDURE PERMUTATION(X$[]->X$[],OK)
    LOCAL I%,J%
    FOR I%=UBOUND(X$,1)-1 TO 0 STEP -1 DO
       EXIT IF X$[I%]<X$[I%+1]
    END FOR
    IF I%<0 THEN OK=FALSE  EXIT PROCEDURE END IF
    J%=UBOUND(X$,1)
    WHILE X$[J%]<=X$[I%] DO
         J%=J%-1
    END WHILE
    SWAP(X$[I%],X$[J%])
    I%=I%+1
    J%=UBOUND(X$,1)
    WHILE I%<J% DO
        SWAP(X$[I%],X$[J%])
        I%=I%+1
        J%=J%-1
    END WHILE
    OK=TRUE
END PROCEDURE

BEGIN

! The names (only used for printing the results)

    DATA("Beer","Coffee","Milk","Tea","Water")
    DATA("Denmark","England","Germany","Norway","Sweden")
    DATA("Blue","Green","Red","White","Yellow")
    DATA("Blend","BlueMaster","Dunhill","PallMall","Prince")
    DATA("Birds","Cats","Dog","Horse","Zebra")

    FOR I%=0 TO 4 DO READ(DRINK$[I%])   END FOR
    FOR I%=0 TO 4 DO READ(NATION$[I%])  END FOR
    FOR I%=0 TO 4 DO READ(COLR$[I%])    END FOR
    FOR I%=0 TO 4 DO READ(SMOKE$[I%])   END FOR
    FOR I%=0 TO 4 DO READ(ANIMAL$[I%])  END FOR

! Some single-character tags:
    A$="A"  B$="B"  c$="C"  d$="D"  e$="E"

! ERRE doesn't have enumerations!
    Beer$=A$  Coffee$=B$  Milk$=c$  TeA$=d$  Water$=e$
    Denmark$=A$  England$=B$  Germany$=c$  Norway$=d$  Sweden$=e$
    Blue$=A$  Green$=B$  Red$=c$  White$=d$  Yellow$=e$
    Blend$=A$  BlueMaster$=B$  Dunhill$=c$  PallMall$=d$  Prince$=e$
    Birds$=A$  Cats$=B$  Dog$=c$  Horse$=d$  ZebrA$=e$

    PRINT(CHR$(12);)

! Create the 120 permutations of 5 objects:

    X$[0]=A$  X$[1]=B$  X$[2]=C$  X$[3]=D$  X$[4]=E$

    REPEAT
       P%=P%+1
       PERM$[P%]=X$[0]+X$[1]+X$[2]+X$[3]+X$[4]
       PERMUTATION(X$[]->X$[],OK)
    UNTIL NOT OK

! Solve:
    SOLUTIONS%=0
    T1=TIMER
    FOR NATION%=1 TO 120 DO
        NATION$=PERM$[NATION%]
        IF LEFT$(NATION$,1)=Norway$ THEN
             FOR COLR%=1 TO 120 DO
                COLR$=PERM$[COLR%]
                IF INSTR(COLR$,Green$+White$)<>0 AND INSTR(NATION$,England$)=INSTR(COLR$,Red$) AND ABS(INSTR(NATION$,Norway$)-INSTR(COLR$,Blue$))=1 THEN
                    FOR DRINK%=1 TO 120 DO
                       DRINK$=PERM$[DRINK%]
                       IF MID$(DRINK$,3,1)=Milk$ AND INSTR(NATION$,Denmark$)=INSTR(DRINK$,TeA$) AND INSTR(DRINK$,Coffee$)=INSTR(COLR$,Green$) THEN
                           FOR SmOKe%=1 TO 120 DO
                              SmOKe$=PERM$[SMOKE%]
                              IF INSTR(NATION$,Germany$)=INSTR(SmOKe$,Prince$) AND INSTR(SmOKe$,BlueMaster$)=INSTR(DRINK$,Beer$) AND ABS(INSTR(SmOKe$,Blend$)-INSTR(DRINK$,Water$))=1 AND INSTR(SmOKe$,Dunhill$)=INSTR(COLR$,Yellow$) THEN
                                  FOR ANIMAL%=1 TO 120 DO
                                     ANIMAL$=PERM$[ANIMAL%]
                                     IF INSTR(NATION$,Sweden$)=INSTR(ANIMAL$,Dog$) AND INSTR(SmOKe$,PallMall$)=INSTR(ANIMAL$,Birds$) AND ABS(INSTR(SmOKe$,Blend$)-INSTR(ANIMAL$,Cats$))=1 AND ABS(INSTR(SmOKe$,Dunhill$)-INSTR(ANIMAL$,Horse$))=1 THEN
                                         PRINT("House    Drink  Nation Colour Smoke  Animal")
                                         PRINT("---------------------------------------------------------------------------")
                                         FOR house%=1 TO 5 DO
                                            PRINT(house%;)
                                            PRINT(TAB(10);DRINK$[ASC(MID$(DRINK$,house%))-65];)
                                            PRINT(TAB(25);NATION$[ASC(MID$(NATION$,house%))-65];)
                                            PRINT(TAB(40);COLR$[ASC(MID$(COLR$,house%))-65];)
                                            PRINT(TAB(55);SMOKE$[ASC(MID$(SmOKe$,house%))-65];)
                                            PRINT(TAB(70);ANIMAL$[ASC(MID$(ANIMAL$,house%))-65])
                                         END FOR
                                         SOLUTIONS%=SOLUTIONS%+1
                                     END IF
                                  END FOR ! ANIMAL%
                              END IF
                           END FOR ! SmOKe%
                       END IF
                    END FOR ! DRINK%
                END IF
             END FOR ! COLR%
        END IF
    END FOR ! NATION%
    PRINT("Number of solutions=";SOLUTIONS%)
    PRINT("Solved in ";TIMER-T1;" seconds")
END PROGRAM


(*Here I solve the Zebra puzzle using Plain Changes, definitely a challenge to some campanoligist to solve it using Grandsire Doubles.
  Nigel Galloway: January 27th., 2017 *)
type N = |English=0 |Swedish=1|Danish=2    |German=3|Norwegian=4
type I = |Tea=0     |Coffee=1 |Milk=2      |Beer=3  |Water=4
type G = |Dog=0     |Birds=1  |Cats=2      |Horse=3 |Zebra=4
type E = |Red=0     |Green=1  |White=2     |Blue=3  |Yellow=4
type L = |PallMall=0|Dunhill=1|BlueMaster=2|Prince=3|Blend=4
type NIGELz={Nz:N[];Iz:I[];Gz:G[];Ez:E[];Lz:L[]}
let fn (i:'n[]) g (e:'g[]) l =                            //coincident?
  let rec _fn = function
    |5                                -> false
    |ig when (i.[ig]=g && e.[ig]=l)   -> true
    |ig                               -> _fn (ig+1)
  _fn 0
let fi (i:'n[]) g (e:'g[]) l =                            //leftof?
  let rec _fn = function
    |4                                -> false
    |ig when (i.[ig]=g && e.[ig+1]=l) -> true
    |ig                               -> _fn (ig+1)
  _fn 0
let fg (i:'n[]) g (e:'g[]) l = (fi i g e l || fi e l i g) //adjacent?
let  n = Ring.PlainChanges [|for n in System.Enum.GetValues(typeof<N>)->n:?>N|]|>Seq.filter(fun n->n.[0]=N.Norwegian)         //#10
let  i = Ring.PlainChanges [|for n in System.Enum.GetValues(typeof<I>)->n:?>I|]|>Seq.filter(fun n->n.[2]=I.Milk)              //# 9
let  g = Ring.PlainChanges [|for n in System.Enum.GetValues(typeof<G>)->n:?>G|]
let  e = Ring.PlainChanges [|for n in System.Enum.GetValues(typeof<E>)->n:?>E|]|>Seq.filter(fun n->fi n E.Green n E.White)    //# 5
let  l = Ring.PlainChanges [|for n in System.Enum.GetValues(typeof<L>)->n:?>L|]
match n|>Seq.map(fun n->{Nz=n;Iz=[||];Gz=[||];Ez=[||];Lz=[||]})
       |>Seq.collect(fun n->i|>Seq.map(fun i->{n with Iz=i}))|>Seq.filter(fun n-> fn n.Nz N.Danish    n.Iz I.Tea)             //# 4
       |>Seq.collect(fun n->g|>Seq.map(fun i->{n with Gz=i}))|>Seq.filter(fun n-> fn n.Nz N.Swedish   n.Gz G.Dog)             //# 3
       |>Seq.collect(fun n->e|>Seq.map(fun i->{n with Ez=i}))|>Seq.filter(fun n-> fn n.Nz N.English   n.Ez E.Red   &&         //# 2
                                                                                fn n.Ez E.Green     n.Iz I.Coffee&&         //# 6
                                                                                fg n.Nz N.Norwegian n.Ez E.Blue)            //#15
       |>Seq.collect(fun n->l|>Seq.map(fun i->{n with Lz=i}))|>Seq.tryFind(fun n->fn n.Lz L.PallMall  n.Gz G.Birds &&         //# 7
                                                                                fg n.Lz L.Blend     n.Gz G.Cats  &&         //#11
                                                                                fn n.Lz L.Prince    n.Nz N.German&&         //#14
                                                                                fg n.Lz L.Blend     n.Iz I.Water &&         //#16
                                                                                fg n.Lz L.Dunhill   n.Gz G.Horse &&         //#12
                                                                                fn n.Lz L.Dunhill   n.Ez E.Yellow&&         //# 8
                                                                                fn n.Iz I.Beer      n.Lz L.BlueMaster) with //#13
|Some(nn) -> nn.Gz |> Array.iteri(fun n g -> if (g = G.Zebra) then printfn "\nThe man who owns a zebra is %A\n" nn.Nz.[n]); printfn "%A" nn
|None    -> printfn "No solution found"


// First, let's give some type-variables some values:
Nationality = Englishman | Swede   | Dane       | Norwegian | German
Colour      = Red        | Green   | Yellow     | Blue      | White
Cigarette   = PallMall   | Dunhill | BlueMaster | Blend     | Prince
Domestic    = Dog        | Bird    | Cat        | Zebra     | Horse
Beverage    = Tea        | Coffee  | Milk       | Beer      | Water
HouseRow    = First      | Second  | Third      | Fourth    | Fifth

{
We use injections to make the array-elements unique.
Example: 'Pet' is an array of unique elements of type 'Domestic', indexed by 'Nationality'.
In the predicate 'Zebra', we use this injection 'Pet' to define the array-variable 'pet'
as a parameter of the 'Zebra'-predicate.
The symbol used is the '->>'. 'Nationality->>Domestic' can be read as 'Domestic(Nationality)'
in "plain array-speak";
the difference being that the elements are by definition unique (cf. 'injective function').

So, in FormulaOne we use a formula like: 'pet(Swede) = Dog', which simply means that the 'Swede'
(type 'Nationality') has a 'pet' (type 'Pet', of type 'Domestic', indexed by 'Nationality'),
which appears to be a 'Dog' (type 'Domestic').
Or, one could say that the 'Swede' has been mapped to the 'Dog' (Oh, well...).
}

Pet          = Nationality->>Domestic
Drink        = Nationality->>Beverage
HouseColour  = Nationality->>Colour
Smoke        = Nationality->>Cigarette
HouseOrder   = HouseRow->>Nationality

pred Zebra(house_olour::HouseColour, pet::Pet, smoke::Smoke, drink::Drink, house_order::HouseOrder) iff

// For convenience sake, some temporary place_holder variables are used.
// An underscore distinguishes them:

     house_colour(green_house)     = Green      &
     house_colour(white_house)     = White      &
     house_colour(yellow_house)    = Yellow     &
     smoke(pallmall_smoker)        = PallMall   &
     smoke(blend_smoker)           = Blend      &
     smoke(dunhill_smoker)         = Dunhill    &
     smoke(bluemaster_smoker)      = BlueMaster &
     pet(cat_keeper)               = Cat        &
     pet(neighbour_dunhill_smoker) = Horse      &

{ 2. The English man lives in the red house: }
     house_colour(Englishman) = Red &

{ 3. The Swede has a dog: }
     pet(Swede) = Dog &

{ 4. The Dane drinks tea: }
     drink(Dane) = Tea &

    { 'smoke' and 'drink' are both nouns, like the other variables.
      One could read the formulas like: 'the colour of the Englishman's house is Red' ->
     'the Swede's pet is a dog' -> 'the Dane's drink is tea'.
    }

{ 5. The green house is immediately to the left of the white house.
     The local predicate 'LeftOf' (see below) determines the house order: }
     LeftOf(green_house, white_house, house_order) &

{ 6. They drink coffee in the green house: }
     drink(green_house) = Coffee &

{ 7. The man who smokes Pall Mall has birds: }
     pet(pallmall_smoker) = Bird &

{ 8. In the yellow house they smoke Dunhill: }
     smoke(yellow_house) = Dunhill &

{ 9. In the middle house (third in the row) they drink milk: }
     drink(house_order(Third)) = Milk &

{10. The Norwegian lives in the first house: }
     house_order(First) = Norwegian &

{11. The man who smokes Blend lives in the house next to the house with cats.
     Another local predicate 'Neighbour' makes them neighbours: }
     Neighbour(blend_smoker, cat_keeper, house_order) &

{12. In a house next to the house where they have a horse, they smoke Dunhill: }
     Neighbour(dunhill_smoker, neighbour_dunhill_smoker, house_order) &

{13. The man who smokes Blue Master drinks beer: }
     drink(bluemaster_smoker) = Beer &

{14. The German smokes Prince: }
     smoke(German) = Prince &

{15. The Norwegian lives next to the blue house
     Cf. 10. "The Norwegian lives in the first house", so the blue house is the second house: }
     house_colour(house_order(Second)) = Blue &

{16. They drink water in a house next to the house where they smoke Blend: }
     drink(neighbour_blend_smoker) = Water &
     Neighbour(blend_smoker, neighbour_blend_smoker, house_order)

{  A simplified solution would number the houses 1, 2, 3, 4, 5
   which makes it easier to order the houses.
   'right in the center' would become 3; 'in the first house', 1
   But we stick to the original puzzle and use some local predicates.
}

local pred Neighbour(neighbour1::Nationality, neighbour2::Nationality, house_order::HouseOrder)iff
   neighbour1 <> neighbour2 &
   house_order(house1) = neighbour1 &
   house_order(house2) = neighbour2 &
   ( house1 = house2 + 1 |
     house1 = house2 - 1 )

local pred LeftOf(neighbour1::Nationality, neighbour2::Nationality, house_order::HouseOrder) iff
   neighbour1 <> neighbour2 &
   house_order(house1) = neighbour1 &
   house_order(house2) = neighbour2 &
   house1 = house2 - 1

{
The 'all'-query in FormulaOne:
     all Zebra(house_colour, pet, smokes, drinks, house_order)
gives, of course, only one solution, so it can be replaced by:
     one Zebra(house_colour, pet, smokes, drinks, house_order)
}

// The compacted version:

Nationality = Englishman | Swede   | Dane       | Norwegian | German
Colour      = Red        | Green   | Yellow     | Blue      | White
Cigarette   = PallMall   | Dunhill | BlueMaster | Blend     | Prince
Domestic    = Dog        | Bird    | Cat        | Zebra     | Horse
Beverage    = Tea        | Coffee  | Milk       | Beer      | Water
HouseRow    = First      | Second  | Third      | Fourth    | Fifth

Pet          = Nationality->>Domestic
Drink        = Nationality->>Beverage
HouseColour  = Nationality->>Colour
Smoke        = Nationality->>Cigarette
HouseOrder   = HouseRow->>Nationality

pred Zebra(house_colour::HouseColour, pet::Pet, smoke::Smoke, drink::Drink, house_order::HouseOrder) iff

  house-colour(green_house) = Green &
  house-colour(white_house) = White &
  house-colour(yellow_house) = Yellow &
  smoke(pallmall_smoker) = PallMall &
  smoke(blend_smoker) = Blend &
  smoke(dunhill_smoker) = Dunhill &
  smoke(bluemaster_smoker) = BlueMaster &
  pet(cat_keeper) = Cat &
  pet(neighbour_dunhill_smoker) = Horse &
  house_colour(Englishman) = Red &
  pet(Swede) = Dog &
  drink(Dane) = Tea &
  LeftOf(green_house, white_house, house_order) &
  drink(green_house) = Coffee &
  pet(pallmall_smoker) = Bird &
  smoke(yellow_house) = Dunhill &
  drink(house_order(Third)) = Milk &
  house_order(First) = Norwegian &
  Neighbour(blend_smoker, cat_keeper, house_order) &
  Neighbour(dunhill_smoker, neighbour_dunhill_smoker, house_order) &
  drink(bluemaster_smoker) = Beer &
  smoke(German) = Prince &
  house_colour(house_order(Second)) = Blue &
  drink(neighbour_blend_smoker) = Water &
  Neighbour(blend_smoker, neighbour_blend_smoker, house_order)

local pred Neighbour(neighbour1::Nationality, neighbour2::Nationality, house_order::HouseOrder)iff
   neighbour1 <> neighbour2 &
   house_order(house1) = neighbour1 & house_order(house2) = neighbour2 &
   ( house1 = house2 + 1 | house1 = house2 - 1 )

local pred LeftOf(neighbour1::Nationality, neighbour2::Nationality, house_::HouseOrder) iff
   neighbour1 <> neighbour2 &
   house_order(house1) = neighbour1 & house_order(house2) = neighbour2 &
   house1 = house2 - 1


leftOf  :=function(setA, vA, setB, vB)
local i;
for i in [1..4] do
   if ( setA[i] = vA) and  (setB[i+1] = vB) then return true ;fi;
od;
 return false;
end;

nextTo  :=function(setA, vA, setB, vB)
local i;
for i in [1..4] do
   if ( setA[i] = vA) and  (setB[i+1] = vB) then return true ;fi;
   if ( setB[i] = vB) and  (setA[i+1] = vA) then return true ;fi;
od;
return false;
end;

requires := function(setA, vA, setB, vB)
    local i;
      for i in [1..5] do
        if ( setA[i] = vA) and  (setB[i] = vB) then return true ;fi;
      od;
 return false;
end;

pcolors :=PermutationsList(["white" ,"yellow" ,"blue" ,"red" ,"green"]);
pcigars :=PermutationsList(["blends", "pall_mall", "prince", "bluemasters", "dunhill"]);
pnats:=PermutationsList(["german", "swedish", "british", "norwegian", "danish"]);
pdrinks :=PermutationsList(["beer", "water", "tea", "milk", "coffee"]);
ppets  :=PermutationsList(["birds", "cats", "horses", "fish", "dogs"]);

for colors in pcolors do
if not (leftOf(colors,"green",colors,"white")) then continue ;fi;
for nats in pnats do
if not (requires(nats,"british",colors,"red")) then  continue ;fi;
if not (nats[1]="norwegian") then continue ;fi;
if not (nextTo(nats,"norwegian",colors,"blue")) then continue ;fi;
for pets in ppets do
if not (requires(nats,"swedish",pets,"dogs")) then  continue ;fi;
for drinks in pdrinks do
if not (drinks[3]="milk") then continue ;fi;
if not (requires(colors,"green",drinks,"coffee")) then continue ;fi;
if not (requires(nats,"danish",drinks,"tea")) then  continue ;fi;
for cigars in pcigars do
if not (nextTo(pets,"horses",cigars,"dunhill")) then continue ;fi;
if not (requires(cigars,"pall_mall",pets,"birds")) then  continue ;fi;
if not (nextTo(cigars,"blends",drinks,"water")) then  continue ;fi;
if not (nextTo(cigars,"blends",pets,"cats")) then  continue ;fi;
if not (requires(nats,"german",cigars,"prince")) then  continue ;fi;
if not (requires(colors,"yellow",cigars,"dunhill")) then continue ;fi;
if not (requires(cigars,"bluemasters",drinks,"beer")) then  continue ;fi;
Print(colors,"\n");
Print(nats,"\n");
Print(drinks,"\n");
Print(pets,"\n");
Print(cigars,"\n");
od;od;od;od;od;


package main

import (
        "fmt"
        "log"
        "strings"
)

// Define some types

type HouseSet [5]*House
type House struct {
        n Nationality
        c Colour
        a Animal
        d Drink
        s Smoke
}
type Nationality int8
type Colour int8
type Animal int8
type Drink int8
type Smoke int8

// Define the possible values

const (
        English Nationality = iota
        Swede
        Dane
        Norwegian
        German
)
const (
        Red Colour = iota
        Green
        White
        Yellow
        Blue
)
const (
        Dog Animal = iota
        Birds
        Cats
        Horse
        Zebra
)
const (
        Tea Drink = iota
        Coffee
        Milk
        Beer
        Water
)
const (
        PallMall Smoke = iota
        Dunhill
        Blend
        BlueMaster
        Prince
)

// And how to print them

var nationalities = [...]string{"English", "Swede", "Dane", "Norwegian", "German"}
var colours = [...]string{"red", "green", "white", "yellow", "blue"}
var animals = [...]string{"dog", "birds", "cats", "horse", "zebra"}
var drinks = [...]string{"tea", "coffee", "milk", "beer", "water"}
var smokes = [...]string{"Pall Mall", "Dunhill", "Blend", "Blue Master", "Prince"}

func (n Nationality) String() string { return nationalities[n] }
func (c Colour) String() string      { return colours[c] }
func (a Animal) String() string      { return animals[a] }
func (d Drink) String() string       { return drinks[d] }
func (s Smoke) String() string       { return smokes[s] }
func (h House) String() string {
        return fmt.Sprintf("%-9s  %-6s  %-5s  %-6s  %s", h.n, h.c, h.a, h.d, h.s)
}
func (hs HouseSet) String() string {
        lines := make([]string, 0, len(hs))
        for i, h := range hs {
                s := fmt.Sprintf("%d  %s", i, h)
                lines = append(lines, s)
        }
        return strings.Join(lines, "\n")
}

// Simple brute force solution

func simpleBruteForce() (int, HouseSet) {
        var v []House
        for n := range nationalities {
                for c := range colours {
                        for a := range animals {
                                for d := range drinks {
                                        for s := range smokes {
                                                h := House{
                                                        n: Nationality(n),
                                                        c: Colour(c),
                                                        a: Animal(a),
                                                        d: Drink(d),
                                                        s: Smoke(s),
                                                }
                                                if !h.Valid() {
                                                        continue
                                                }
                                                v = append(v, h)
                                        }
                                }
                        }
                }
        }
        n := len(v)
        log.Println("Generated", n, "valid houses")

        combos := 0
        first := 0
        valid := 0
        var validSet HouseSet
        for a := 0; a < n; a++ {
                if v[a].n != Norwegian { // Condition 10:
                        continue
                }
                for b := 0; b < n; b++ {
                        if b == a {
                                continue
                        }
                        if v[b].anyDups(&v[a]) {
                                continue
                        }
                        for c := 0; c < n; c++ {
                                if c == b || c == a {
                                        continue
                                }
                                if v[c].d != Milk { // Condition 9:
                                        continue
                                }
                                if v[c].anyDups(&v[b], &v[a]) {
                                        continue
                                }
                                for d := 0; d < n; d++ {
                                        if d == c || d == b || d == a {
                                                continue
                                        }
                                        if v[d].anyDups(&v[c], &v[b], &v[a]) {
                                                continue
                                        }
                                        for e := 0; e < n; e++ {
                                                if e == d || e == c || e == b || e == a {
                                                        continue
                                                }
                                                if v[e].anyDups(&v[d], &v[c], &v[b], &v[a]) {
                                                        continue
                                                }
                                                combos++
                                                set := HouseSet{&v[a], &v[b], &v[c], &v[d], &v[e]}
                                                if set.Valid() {
                                                        valid++
                                                        if valid == 1 {
                                                                first = combos
                                                        }
                                                        validSet = set
                                                        //return set
                                                }
                                        }
                                }
                        }
                }
        }
        log.Println("Tested", first, "different combinations of valid houses before finding solution")
        log.Println("Tested", combos, "different combinations of valid houses in total")
        return valid, validSet
}

// anyDups returns true if h as any duplicate attributes with any of the specified houses
func (h *House) anyDups(list ...*House) bool {
        for _, b := range list {
                if h.n == b.n || h.c == b.c || h.a == b.a || h.d == b.d || h.s == b.s {
                        return true
                }
        }
        return false
}

func (h *House) Valid() bool {
        // Condition 2:
        if h.n == English && h.c != Red || h.n != English && h.c == Red {
                return false
        }
        // Condition 3:
        if h.n == Swede && h.a != Dog || h.n != Swede && h.a == Dog {
                return false
        }
        // Condition 4:
        if h.n == Dane && h.d != Tea || h.n != Dane && h.d == Tea {
                return false
        }
        // Condition 6:
        if h.c == Green && h.d != Coffee || h.c != Green && h.d == Coffee {
                return false
        }
        // Condition 7:
        if h.a == Birds && h.s != PallMall || h.a != Birds && h.s == PallMall {
                return false
        }
        // Condition 8:
        if h.c == Yellow && h.s != Dunhill || h.c != Yellow && h.s == Dunhill {
                return false
        }
        // Condition 11:
        if h.a == Cats && h.s == Blend {
                return false
        }
        // Condition 12:
        if h.a == Horse && h.s == Dunhill {
                return false
        }
        // Condition 13:
        if h.d == Beer && h.s != BlueMaster || h.d != Beer && h.s == BlueMaster {
                return false
        }
        // Condition 14:
        if h.n == German && h.s != Prince || h.n != German && h.s == Prince {
                return false
        }
        // Condition 15:
        if h.n == Norwegian && h.c == Blue {
                return false
        }
        // Condition 16:
        if h.d == Water && h.s == Blend {
                return false
        }
        return true
}

func (hs *HouseSet) Valid() bool {
        ni := make(map[Nationality]int, 5)
        ci := make(map[Colour]int, 5)
        ai := make(map[Animal]int, 5)
        di := make(map[Drink]int, 5)
        si := make(map[Smoke]int, 5)
        for i, h := range hs {
                ni[h.n] = i
                ci[h.c] = i
                ai[h.a] = i
                di[h.d] = i
                si[h.s] = i
        }
        // Condition 5:
        if ci[Green]+1 != ci[White] {
                return false
        }
        // Condition 11:
        if dist(ai[Cats], si[Blend]) != 1 {
                return false
        }
        // Condition 12:
        if dist(ai[Horse], si[Dunhill]) != 1 {
                return false
        }
        // Condition 15:
        if dist(ni[Norwegian], ci[Blue]) != 1 {
                return false
        }
        // Condition 16:
        if dist(di[Water], si[Blend]) != 1 {
                return false
        }

        // Condition 9: (already tested elsewhere)
        if hs[2].d != Milk {
                return false
        }
        // Condition 10: (already tested elsewhere)
        if hs[0].n != Norwegian {
                return false
        }
        return true
}

func dist(a, b int) int {
        if a > b {
                return a - b
        }
        return b - a
}

func main() {
        log.SetFlags(0)
        n, sol := simpleBruteForce()
        fmt.Println(n, "solution found")
        fmt.Println(sol)
}


module Main where

import Control.Applicative ((<$>), (<*>))
import Control.Monad (foldM, forM_)
import Data.List ((\\))

-- types
data House = House
    { color :: Color      -- <trait> :: House -> <Trait>
    , man   :: Man
    , pet   :: Pet
    , drink :: Drink
    , smoke :: Smoke
    }
    deriving (Eq, Show)

data Color = Red | Green | Blue | Yellow | White
    deriving (Eq, Show, Enum, Bounded)

data Man = Eng | Swe | Dan | Nor | Ger
    deriving (Eq, Show, Enum, Bounded)

data Pet = Dog | Birds | Cats | Horse | Zebra
    deriving (Eq, Show, Enum, Bounded)

data Drink = Coffee | Tea | Milk | Beer | Water
    deriving (Eq, Show, Enum, Bounded)

data Smoke = PallMall | Dunhill | Blend | BlueMaster | Prince
    deriving (Eq, Show, Enum, Bounded)

type Solution = [House]

main :: IO ()
main = do
  forM_ solutions $ \sol -> mapM_ print sol
                            >> putStrLn "----"
  putStrLn "No More Solutions"

solutions :: [Solution]
solutions = filter finalCheck . map reverse $ foldM next [] [1..5]
    where
      -- NOTE: list of houses is generated in reversed order
      next :: Solution -> Int -> [Solution]
      next sol pos = [h:sol | h <- newHouses sol, consistent h pos]

newHouses :: Solution -> Solution
newHouses sol =    -- all combinations of traits not yet used
    House <$> new color <*> new man <*> new pet <*> new drink <*> new smoke
    where
      new trait = [minBound ..] \\ map trait sol  -- :: [<Trait>]

consistent :: House -> Int -> Bool
consistent house pos = and                  -- consistent with the rules:
    [ man   `is` Eng     <=>   color `is` Red              --  2
    , man   `is` Swe     <=>   pet   `is` Dog              --  3
    , man   `is` Dan     <=>   drink `is` Tea              --  4
    , color `is` Green   <=>   drink `is` Coffee           --  6
    , pet   `is` Birds   <=>   smoke `is` PallMall         --  7
    , color `is` Yellow  <=>   smoke `is` Dunhill          --  8
    , const (pos == 3)   <=>   drink `is` Milk             --  9
    , const (pos == 1)   <=>   man   `is` Nor              -- 10
    , drink `is` Beer    <=>   smoke `is` BlueMaster       -- 13
    , man   `is` Ger     <=>   smoke `is` Prince           -- 14
    ]
    where
      infix 4 <=>
      p <=> q  =  p house == q house   -- both True or both False

is :: Eq a => (House -> a) -> a -> House -> Bool
(trait `is` value) house  =  trait house == value

finalCheck :: [House] -> Bool
finalCheck solution = and                    -- fulfills the rules:
    [ (color `is` Green)   `leftOf` (color `is` White)  --  5
    , (smoke `is` Blend  ) `nextTo` (pet   `is` Cats )  -- 11
    , (smoke `is` Dunhill) `nextTo` (pet   `is` Horse)  -- 12
    , (color `is` Blue   ) `nextTo` (man   `is` Nor  )  -- 15
    , (smoke `is` Blend  ) `nextTo` (drink `is` Water)  -- 16
    ]
    where
      nextTo :: (House -> Bool) -> (House -> Bool) -> Bool
      nextTo p q = leftOf p q || leftOf q p
      leftOf p q
          | (_:h:_) <- dropWhile (not . p) solution = q h
          | otherwise                               = False


ehs=: 5$a:

cr=: (('English';'red') 0 3} ehs);<('Dane';'tea') 0 2}ehs
cr=: cr, (('German';'Prince') 0 4}ehs);<('Swede';'dog') 0 1 }ehs

cs=: <('PallMall';'birds') 4 1}ehs
cs=: cs, (('yellow';'Dunhill') 3 4}ehs);<('BlueMaster';'beer') 4 2}ehs

lof=: (('coffee';'green')2 3}ehs);<(<'white')3}ehs

next=: <((<'Blend') 4 }ehs);<(<'water')2}ehs
next=: next,<((<'Blend') 4 }ehs);<(<'cats')1}ehs
next=: next,<((<'Dunhill') 4}ehs);<(<'horse')1}ehs


package org.rosettacode.zebra;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;

public class Zebra {

    private static final int[] orders = {1, 2, 3, 4, 5};
    private static final String[] nations = {"English", "Danish", "German", "Swedish", "Norwegian"};
    private static final String[] animals = {"Zebra", "Horse", "Birds", "Dog", "Cats"};
    private static final String[] drinks = {"Coffee", "Tea", "Beer", "Water", "Milk"};
    private static final String[] cigarettes = {"Pall Mall", "Blend", "Blue Master", "Prince", "Dunhill"};
    private static final String[] colors = {"Red", "Green", "White", "Blue", "Yellow"};

    static class Solver {
        private final PossibleLines puzzleTable = new PossibleLines();

        void solve() {
            PossibleLines constraints = new PossibleLines();
            constraints.add(new PossibleLine(null, "English", "Red", null, null, null));
            constraints.add(new PossibleLine(null, "Swedish", null, "Dog", null, null));
            constraints.add(new PossibleLine(null, "Danish", null, null, "Tea", null));
            constraints.add(new PossibleLine(null, null, "Green", null, "Coffee", null));
            constraints.add(new PossibleLine(null, null, null, "Birds", null, "Pall Mall"));
            constraints.add(new PossibleLine(null, null, "Yellow", null, null, "Dunhill"));
            constraints.add(new PossibleLine(3, null, null, null, "Milk", null));
            constraints.add(new PossibleLine(1, "Norwegian", null, null, null, null));
            constraints.add(new PossibleLine(null, null, null, null, "Beer", "Blue Master"));
            constraints.add(new PossibleLine(null, "German", null, null, null, "Prince"));
            constraints.add(new PossibleLine(2, null, "Blue", null, null, null));

            //Creating all possible combination of a puzzle line.
            //The maximum number of lines is 5^^6 (15625).
            //Each combination line is checked against a set of knowing facts, thus
            //only a small number of line result at the end.
            for (Integer orderId : Zebra.orders) {
                for (String nation : Zebra.nations) {
                    for (String color : Zebra.colors) {
                        for (String animal : Zebra.animals) {
                            for (String drink : Zebra.drinks) {
                                for (String cigarette : Zebra.cigarettes) {
                                    addPossibleNeighbors(constraints, orderId, nation, color, animal, drink, cigarette);
                                }
                            }
                        }
                    }
                }
            }

            System.out.println("After general rule set validation, remains " +
                    puzzleTable.size() + " lines.");

            for (Iterator<PossibleLine> it = puzzleTable.iterator(); it.hasNext(); ) {
                boolean validLine = true;

                PossibleLine possibleLine = it.next();

                if (possibleLine.leftNeighbor != null) {
                    PossibleLine neighbor = possibleLine.leftNeighbor;
                    if (neighbor.order < 1 || neighbor.order > 5) {
                        validLine = false;
                        it.remove();
                    }
                }
                if (validLine && possibleLine.rightNeighbor != null) {
                    PossibleLine neighbor = possibleLine.rightNeighbor;
                    if (neighbor.order < 1 || neighbor.order > 5) {
                        it.remove();
                    }
                }
            }

            System.out.println("After removing out of bound neighbors, remains " +
                    puzzleTable.size() + " lines.");

            //Setting left and right neighbors
            for (PossibleLine puzzleLine : puzzleTable) {
                for (PossibleLine leftNeighbor : puzzleLine.neighbors) {
                    PossibleLine rightNeighbor = leftNeighbor.copy();

                    //make it left neighbor
                    leftNeighbor.order = puzzleLine.order - 1;
                    if (puzzleTable.contains(leftNeighbor)) {
                        if (puzzleLine.leftNeighbor != null)
                            puzzleLine.leftNeighbor.merge(leftNeighbor);
                        else
                            puzzleLine.setLeftNeighbor(leftNeighbor);
                    }
                    rightNeighbor.order = puzzleLine.order + 1;
                    if (puzzleTable.contains(rightNeighbor)) {
                        if (puzzleLine.rightNeighbor != null)
                            puzzleLine.rightNeighbor.merge(rightNeighbor);
                        else
                            puzzleLine.setRightNeighbor(rightNeighbor);
                    }
                }
            }

            int iteration = 1;
            int lastSize = 0;

            //Recursively validate against neighbor rules
            while (puzzleTable.size() > 5 && lastSize != puzzleTable.size()) {
                lastSize = puzzleTable.size();
                puzzleTable.clearLineCountFlags();

                recursiveSearch(null, puzzleTable, -1);

                constraints.clear();
                // Assuming we'll get at leas one valid line each iteration, we create
                // a set of new rules with lines which have no more then one instance of same OrderId.
                for (int i = 1; i < 6; i++) {
                    if (puzzleTable.getLineCountByOrderId(i) == 1)
                        constraints.addAll(puzzleTable.getSimilarLines(new PossibleLine(i, null, null, null, null,
                                null)));
                }

                puzzleTable.removeIf(puzzleLine -> !constraints.accepts(puzzleLine));

                System.out.println("After " + iteration + " recursive iteration, remains "
                        + puzzleTable.size() + " lines");
                iteration++;
            }

            // Print the results
            System.out.println("-------------------------------------------");
            if (puzzleTable.size() == 5) {
                for (PossibleLine puzzleLine : puzzleTable) {
                    System.out.println(puzzleLine.getWholeLine());
                }
            } else
                System.out.println("Sorry, solution not found!");
        }

        private void addPossibleNeighbors(
                PossibleLines constraints, Integer orderId, String nation,
                String color, String animal, String drink, String cigarette) {
            boolean validLine = true;
            PossibleLine pzlLine = new PossibleLine(orderId,
                    nation,
                    color,
                    animal,
                    drink,
                    cigarette);
            // Checking against a set of knowing facts
            if (constraints.accepts(pzlLine)) {
                // Adding rules of neighbors
                if (cigarette.equals("Blend")
                        && (animal.equals("Cats") || drink.equals("Water")))
                    validLine = false;

                if (cigarette.equals("Dunhill")
                        && animal.equals("Horse"))
                    validLine = false;

                if (validLine) {
                    puzzleTable.add(pzlLine);

                    //set neighbors constraints
                    if (color.equals("Green")) {
                        pzlLine.setRightNeighbor(
                                new PossibleLine(null, null, "White", null, null, null));
                    }
                    if (color.equals("White")) {
                        pzlLine.setLeftNeighbor(
                                new PossibleLine(null, null, "Green", null, null, null));
                    }
                    //
                    if (animal.equals("Cats") && !cigarette.equals("Blend")) {
                        pzlLine.neighbors.add(new PossibleLine(null, null, null, null, null,
                                "Blend"));
                    }
                    if (cigarette.equals("Blend") && !animal.equals("Cats")) {
                        pzlLine.neighbors.add(new PossibleLine(null, null, null, "Cats", null
                                , null));
                    }
                    //
                    if (drink.equals("Water")
                            && !animal.equals("Cats")
                            && !cigarette.equals("Blend")) {
                        pzlLine.neighbors.add(new PossibleLine(null, null, null, null, null,
                                "Blend"));
                    }

                    if (cigarette.equals("Blend") && !drink.equals("Water")) {
                        pzlLine.neighbors.add(new PossibleLine(null, null, null, null, "Water"
                                , null));
                    }
                    //
                    if (animal.equals("Horse") && !cigarette.equals("Dunhill")) {
                        pzlLine.neighbors.add(new PossibleLine(null, null, null, null, null,
                                "Dunhill"));
                    }
                    if (cigarette.equals("Dunhill") && !animal.equals("Horse")) {
                        pzlLine.neighbors.add(new PossibleLine(null, null, null, "Horse",
                                null, null));
                    }
                }
            }
        }

        // Recursively checks the input set to ensure each line has right neighbor.
        // Neighbors can be of three type, left, right or undefined.
        // Direction: -1 left, 0 undefined, 1 right
        private boolean recursiveSearch(PossibleLine pzzlNodeLine,
                                        PossibleLines possibleLines, int direction) {
            boolean validLeaf = false;
            boolean hasNeighbor;
            PossibleLines puzzleSubSet;

            for (Iterator<PossibleLine> it = possibleLines.iterator(); it.hasNext(); ) {
                PossibleLine pzzlLeafLine = it.next();
                validLeaf = false;

                hasNeighbor = pzzlLeafLine.hasNeighbor(direction);

                if (hasNeighbor) {
                    puzzleSubSet = puzzleTable.getSimilarLines(pzzlLeafLine.getNeighbor(direction));
                    if (puzzleSubSet != null) {
                        if (pzzlNodeLine != null)
                            validLeaf = puzzleSubSet.contains(pzzlNodeLine);
                        else
                            validLeaf = recursiveSearch(pzzlLeafLine, puzzleSubSet, -1 * direction);
                    }
                }

                if (!validLeaf && pzzlLeafLine.hasNeighbor(-1 * direction)) {
                    hasNeighbor = true;
                    puzzleSubSet = puzzleTable.getSimilarLines(pzzlLeafLine.getNeighbor(-1 * direction));
                    if (puzzleSubSet != null) {
                        if (pzzlNodeLine != null)
                            validLeaf = puzzleSubSet.contains(pzzlNodeLine);
                        else
                            validLeaf = recursiveSearch(pzzlLeafLine, puzzleSubSet, direction);
                    }
                }

                if (pzzlNodeLine != null && validLeaf)
                    return true;

                if (pzzlNodeLine == null && hasNeighbor && !validLeaf) {
                    it.remove();
                }

                if (pzzlNodeLine == null) {
                    if (hasNeighbor && validLeaf) {
                        possibleLines.riseLineCountFlags(pzzlLeafLine.order);
                    }
                    if (!hasNeighbor) {
                        possibleLines.riseLineCountFlags(pzzlLeafLine.order);
                    }
                }
            }
            return validLeaf;
        }
    }

    public static void main(String[] args) {

        Solver solver = new Solver();
        solver.solve();
    }

    static class PossibleLines extends LinkedHashSet<PossibleLine> {

        private final int[] count = new int[5];

        public PossibleLine get(int index) {
            return ((PossibleLine) toArray()[index]);
        }

        public PossibleLines getSimilarLines(PossibleLine searchLine) {
            PossibleLines puzzleSubSet = new PossibleLines();
            for (PossibleLine possibleLine : this) {
                if (possibleLine.getCommonFactsCount(searchLine) == searchLine.getFactsCount())
                    puzzleSubSet.add(possibleLine);
            }
            if (puzzleSubSet.isEmpty())
                return null;

            return puzzleSubSet;
        }

        public boolean contains(PossibleLine searchLine) {
            for (PossibleLine puzzleLine : this) {
                if (puzzleLine.getCommonFactsCount(searchLine) == searchLine.getFactsCount())
                    return true;
            }
            return false;
        }

        public boolean accepts(PossibleLine searchLine) {
            int passed = 0;
            int notpassed = 0;

            for (PossibleLine puzzleSetLine : this) {
                int lineFactsCnt = puzzleSetLine.getFactsCount();
                int comnFactsCnt = puzzleSetLine.getCommonFactsCount(searchLine);

                if (lineFactsCnt != comnFactsCnt && lineFactsCnt != 0 && comnFactsCnt != 0) {
                    notpassed++;
                }

                if (lineFactsCnt == comnFactsCnt)
                    passed++;
            }
            return passed >= 0 && notpassed == 0;
        }

        public void riseLineCountFlags(int lineOrderId) {
            count[lineOrderId - 1]++;
        }

        public void clearLineCountFlags() {
            Arrays.fill(count, 0);
        }

        public int getLineCountByOrderId(int lineOrderId) {
            return count[lineOrderId - 1];
        }
    }

    static class PossibleLine {

        Integer order;
        String nation;
        String color;
        String animal;
        String drink;
        String cigarette;

        PossibleLine rightNeighbor;
        PossibleLine leftNeighbor;
        Set<PossibleLine> neighbors = new LinkedHashSet<>();

        public PossibleLine(Integer order, String nation, String color,
                            String animal, String drink, String cigarette) {
            this.animal = animal;
            this.cigarette = cigarette;
            this.color = color;
            this.drink = drink;
            this.nation = nation;
            this.order = order;
        }

        @Override
        public boolean equals(Object obj) {
            return obj instanceof PossibleLine
                    && getWholeLine().equals(((PossibleLine) obj).getWholeLine());
        }

        public int getFactsCount() {
            int facts = 0;
            facts += order != null ? 1 : 0;
            facts += nation != null ? 1 : 0;
            facts += color != null ? 1 : 0;
            facts += animal != null ? 1 : 0;
            facts += cigarette != null ? 1 : 0;
            facts += drink != null ? 1 : 0;
            return facts;
        }

        private static int common(Object a, Object b) {
            return a != null && Objects.equals(a, b) ? 1 : 0;
        }

        public int getCommonFactsCount(PossibleLine facts) {
            return common(order, facts.order)
                    + common(nation, facts.nation)
                    + common(color, facts.color)
                    + common(animal, facts.animal)
                    + common(cigarette, facts.cigarette)
                    + common(drink, facts.drink);
        }

        public void setLeftNeighbor(PossibleLine leftNeighbor) {
            this.leftNeighbor = leftNeighbor;
            this.leftNeighbor.order = order - 1;
        }

        public void setRightNeighbor(PossibleLine rightNeighbor) {
            this.rightNeighbor = rightNeighbor;
            this.rightNeighbor.order = order + 1;
        }

        public boolean hasNeighbor(int direction) {
            return getNeighbor(direction) != null;
        }

        public PossibleLine getNeighbor(int direction) {
            if (direction < 0)
                return leftNeighbor;
            else
                return rightNeighbor;
        }

        public String getWholeLine() {
            return order + " - " +
                    nation + " - " +
                    color + " - " +
                    animal + " - " +
                    drink + " - " +
                    cigarette;
        }

        @Override
        public int hashCode() {
            return Objects.hash(order, nation, color, animal, drink, cigarette);
        }

        public void merge(PossibleLine mergedLine) {
            if (order == null) order = mergedLine.order;
            if (nation == null) nation = mergedLine.nation;
            if (color == null) color = mergedLine.color;
            if (animal == null) animal = mergedLine.animal;
            if (drink == null) drink = mergedLine.drink;
            if (cigarette == null) cigarette = mergedLine.cigarette;
        }

        public PossibleLine copy() {
            PossibleLine clone = new PossibleLine(order, nation, color, animal, drink, cigarette);
            clone.leftNeighbor = leftNeighbor;
            clone.rightNeighbor = rightNeighbor;
            clone.neighbors = neighbors; // shallow copy
            return clone;
        }
    }
}


# Attempt to unify the input object with the specified object
def unify( object ):
  # Attempt to unify the input object with the specified tag:value
  def unify2(tag; value):
    if . == null then null
    elif .[tag] == value then .
    elif .[tag] == null then .[tag] = value
    else null
    end;
  reduce (object|keys[]) as $key
    (.; unify2($key; object[$key]) );

# Input: an array
# Output: if the i-th element can be made to satisfy the condition,
# then the updated array, otherwise empty.
def enforce(i; cond):
  if 0 <= i and i < length
  then
    (.[i] | cond) as $ans
    | if $ans then .[i] = $ans else empty end
  else empty
  end ;


# Julia 1.0
using Combinatorics
function make(str, test )
  filter(test, collect( permutations(split(str))) )
end

men = make("danish english german norwegian swedish",
           x -> "norwegian" == x[1])

drinks = make("beer coffee milk tea water", x -> "milk" == x[3])

#Julia 1.0 compatible
colors = make("blue green red white yellow",
              x -> 1 == findfirst(c -> c == "white", x) - findfirst(c -> c == "green",x))

pets = make("birds cats dog horse zebra")

smokes = make("blend blue-master dunhill pall-mall prince")

function eq(x, xs, y, ys)
  findfirst(xs, x) == findfirst(ys, y)
end

function adj(x, xs, y, ys)
  1 == abs(findfirst(xs, x) - findfirst(ys, y))
end

function print_houses(n, pet, nationality, colors, drink, smokes)
  println("$n, $pet,    $nationality       $colors       $drink    $smokes")
end

for m = men, c = colors
  if eq("red",c, "english",m) && adj("norwegian",m, "blue",c)
    for d = drinks
      if eq("danish",m, "tea",d) && eq("coffee",d,"green",c)
        for s = smokes
          if eq("yellow",c,"dunhill",s) &&
             eq("blue-master",s,"beer",d) &&
             eq("german",m,"prince",s)
            for p = pets
              if eq("birds",p,"pall-mall",s) &&
                 eq("swedish",m,"dog",p) &&
                 adj("blend",s,"cats",p) &&
                 adj("horse",p,"dunhill",s)
                println("Zebra is owned by ", m[findfirst(c -> c == "zebra", p)])
                println("Houses:")
                for house_num in 1:5
                  print_houses(house_num,p[house_num],m[house_num],c[house_num],d[house_num],s[house_num])
                end
              end
            end
          end
        end
      end
    end
  end
end


// version 1.1.3

fun nextPerm(perm: IntArray): Boolean {
    val size = perm.size
    var k = -1
    for (i in size - 2 downTo 0) {
        if (perm[i] < perm[i + 1]) {
            k = i
            break
        }
    }
    if (k == -1) return false  // last permutation
    for (l in size - 1 downTo k) {
        if (perm[k] < perm[l]) {
           val temp = perm[k]
           perm[k] = perm[l]
           perm[l] = temp
           var m = k + 1
           var n = size - 1
           while (m < n) {
               val temp2 = perm[m]
               perm[m++] = perm[n]
               perm[n--] = temp2
           }
           break
        }
    }
    return true
}

fun check(a1: Int, a2: Int, v1: Int, v2: Int): Boolean {
    for (i in 0..4)
        if (p[a1][i] == v1) return p[a2][i] == v2
    return false
}

fun checkLeft(a1: Int, a2: Int, v1: Int, v2: Int): Boolean {
    for (i in 0..3)
        if (p[a1][i] == v1) return p[a2][i + 1] == v2
    return false
}

fun checkRight(a1: Int, a2: Int, v1: Int, v2: Int): Boolean {
    for (i in 1..4)
        if (p[a1][i] == v1) return p[a2][i - 1] == v2
    return false
}

fun checkAdjacent(a1: Int, a2: Int, v1: Int, v2: Int): Boolean {
    return checkLeft(a1, a2, v1, v2) || checkRight(a1, a2, v1, v2)
}

val colors  = listOf("Red", "Green", "White", "Yellow", "Blue")
val nations = listOf("English", "Swede", "Danish", "Norwegian", "German")
val animals = listOf("Dog", "Birds", "Cats", "Horse", "Zebra")
val drinks  = listOf("Tea", "Coffee", "Milk", "Beer", "Water")
val smokes  = listOf("Pall Mall", "Dunhill", "Blend", "Blue Master", "Prince")

val p = Array(120) { IntArray(5) { -1 } } //  stores all permutations of numbers 0..4

fun fillHouses(): Int {
    var solutions = 0
    for (c in 0..119) {
        if (!checkLeft(c, c, 1, 2)) continue                      // C5 : Green left of white
        for (n in 0..119) {
            if (p[n][0] != 3) continue                            // C10: Norwegian in First
            if (!check(n, c, 0, 0)) continue                      // C2 : English in Red
            if (!checkAdjacent(n, c, 3, 4)) continue              // C15: Norwegian next to Blue
            for (a in 0..119) {
                if (!check(a, n, 0, 1)) continue                  // C3 : Swede has Dog
                for (d in 0..119) {
                    if (p[d][2] != 2) continue                    // C9 : Middle drinks Milk
                    if (!check(d, n, 0, 2)) continue              // C4 : Dane drinks Tea
                    if (!check(d, c, 1, 1)) continue              // C6 : Green drinks Coffee
                    for (s in 0..119) {
                        if (!check(s, a, 0, 1)) continue          // C7 : Pall Mall has Birds
                        if (!check(s, c, 1, 3)) continue          // C8 : Yellow smokes Dunhill
                        if (!check(s, d, 3, 3)) continue          // C13: Blue Master drinks Beer
                        if (!check(s, n, 4, 4)) continue          // C14: German smokes Prince
                        if (!checkAdjacent(s, a, 2, 2)) continue  // C11: Blend next to Cats
                        if (!checkAdjacent(s, a, 1, 3)) continue  // C12: Dunhill next to Horse
                        if (!checkAdjacent(s, d, 2, 4)) continue  // C16: Blend next to Water
                        solutions++
                        printHouses(c, n, a, d, s)
                    }
                }
            }
        }
    }
    return solutions
}

fun printHouses(c: Int, n: Int, a: Int, d: Int, s: Int) {
    var owner: String = ""
    println("House  Color   Nation     Animal  Drink   Smokes")
    println("=====  ======  =========  ======  ======  ===========")
    for (i in 0..4) {
        val f = "%3d    %-6s  %-9s  %-6s  %-6s  %-11s\n"
        System.out.printf(f, i + 1, colors[p[c][i]], nations[p[n][i]], animals[p[a][i]], drinks[p[d][i]], smokes[p[s][i]])
        if (animals[p[a][i]] == "Zebra") owner = nations[p[n][i]]
    }
    println("\nThe $owner owns the Zebra\n")
}

fun main(args: Array<String>) {
    val perm = IntArray(5) { it }
    for (i in 0..119) {
        for (j in 0..4) p[i][j] = perm[j]
        nextPerm(perm)
    }
    val solutions = fillHouses()
    val plural = if (solutions == 1) "" else "s"
    println("$solutions solution$plural found")
}


V dict_fname = ‘unixdict.txt’

F load_dictionary(String fname = dict_fname)
   ‘Return appropriate words from a dictionary file’
   R Set(File(fname).read().split("\n").filter(word -> re:‘[a-z]{3,}’.match(word)))

F get_players()
   V names = input(‘Space separated list of contestants: ’)
   R names.trim(‘ ’).split(‘ ’, group_delimiters' 1B).map(n -> n.capitalize())

F is_wordiff_removal(word, String prev; comment = 1B)
   ‘Is word derived from prev by removing one letter?’
   V ans = word C Set((0 .< prev.len).map(i -> @prev[0 .< i]‘’@prev[i + 1 ..]))
   I !ans
      I comment
         print(‘Word is not derived from previous by removal of one letter.’)
   R ans

F counter(s)
   DefaultDict[Char, Int] d
   L(c) s
      d[c]++
   R d

F is_wordiff_insertion(String word, prev; comment = 1B) -> Bool
   ‘Is word derived from prev by adding one letter?’
   V diff = counter(word)
   L(c) prev
      I --diff[c] <= 0
         diff.pop(c)
   V diffcount = sum(diff.values())
   I diffcount != 1
      I comment
         print(‘More than one character insertion difference.’)
      R 0B

   V insert = Array(diff.keys())[0]
   V ans = word C Set((0 .. prev.len).map(i -> @prev[0 .< i]‘’@insert‘’@prev[i ..]))
   I !ans
      I comment
         print(‘Word is not derived from previous by insertion of one letter.’)
   R ans

F is_wordiff_change(String word, String prev; comment = 1B) -> Bool
   ‘Is word derived from prev by changing exactly one letter?’
   V diffcount = sum(zip(word, prev).map((w, p) -> Int(w != p)))
   I diffcount != 1
      I comment
         print(‘More or less than exactly one character changed.’)
      R 0B
   R 1B

F is_wordiff(wordiffs, word, dic, comment = 1B)
   ‘Is word a valid wordiff from wordiffs[-1] ?’
   I word !C dic
      I comment
         print(‘That word is not in my dictionary’)
      R 0B
   I word C wordiffs
      I comment
         print(‘That word was already used.’)
      R 0B
   I word.len < wordiffs.last.len
      R is_wordiff_removal(word, wordiffs.last, comment)
   E I word.len > wordiffs.last.len
      R is_wordiff_insertion(word, wordiffs.last, comment)

   R is_wordiff_change(word, wordiffs.last, comment)

F could_have_got(wordiffs, dic)
   R (dic - Set(wordiffs)).filter(word -> is_wordiff(@wordiffs, word, @dic, comment' 0B))

V dic = load_dictionary()
V dic_3_4 = dic.filter(word -> word.len C (3, 4))
V start = random:choice(dic_3_4)
V wordiffs = [start]
V players = get_players()
V cur_player = 0
L
   V name = players[cur_player]
   cur_player = (cur_player + 1) % players.len

   V word = input(name‘: Input a wordiff from '’wordiffs.last‘': ’).trim(‘ ’)
   I is_wordiff(wordiffs, word, dic)
      wordiffs.append(word)
   E
      print(‘YOU HAVE LOST ’name‘!’)
      print(‘Could have used: ’(could_have_got(wordiffs, dic)[0.<10]).join(‘, ’)‘ ...’)
      L.break


/* Houses logical puzzle: who owns the zebra and who drinks water?

     1) Five colored houses in a row, each with an owner, a pet, cigarettes, and a drink.
     2) The English lives in the red house.
     3) The Spanish has a dog.
     4) They drink coffee in the green house.
     5) The Ukrainian drinks tea.
     6) The green house is next to the white house.
     7) The Winston smoker has a serpent.
     8) In the yellow house they smoke Kool.
     9) In the middle house they drink milk.
    10) The Norwegian lives in the first house from the left.
    11) The Chesterfield smoker lives near the man with the fox.
    12) In the house near the house with the horse they smoke Kool.
    13) The Lucky Strike smoker drinks juice.
    14) The Japanese smokes Kent.
    15) The Norwegian lives near the blue house.

Who owns the zebra and who drinks water?
*/

:- object(houses).

    :- public(houses/1).
    :- mode(houses(-list), one).
    :- info(houses/1, [
        comment is 'Solution to the puzzle.',
        argnames is ['Solution']
    ]).

    :- public(print/1).
    :- mode(print(+list), one).
    :- info(print/1, [
        comment is 'Pretty print solution to the puzzle.',
        argnames is ['Solution']
    ]).

    houses(Solution) :-
        template(Solution),                                                 %  1
        member(h(english, _, _, _, red), Solution),                         %  2
        member(h(spanish, dog, _, _, _), Solution),                         %  3
        member(h(_, _, _, coffee, green), Solution),                        %  4
        member(h(ukrainian, _, _, tea, _), Solution),                       %  5
        next(h(_, _, _, _, green), h(_, _, _, _, white), Solution),         %  6
        member(h(_, snake, winston, _, _), Solution),                       %  7
        member(h(_, _, kool, _, yellow), Solution),                         %  8
        Solution = [_, _, h(_, _, _, milk, _), _, _],                       %  9
        Solution = [h(norwegian, _, _, _, _)| _],                           % 10
        next(h(_, fox, _, _, _), h(_, _, chesterfield, _, _), Solution),    % 11
        next(h(_, _, kool, _, _), h(_, horse, _, _, _), Solution),          % 12
        member(h(_, _, lucky, juice, _), Solution),                         % 13
        member(h(japonese, _, kent, _, _), Solution),                       % 14
        next(h(norwegian, _, _, _, _), h(_, _, _, _, blue), Solution),      % 15
        member(h(_, _, _, water, _), Solution),      % one of them drinks water
        member(h(_, zebra, _, _, _), Solution).      % one of them owns a zebra

    print([]).
    print([House| Houses]) :-
        write(House), nl,
        print(Houses).

    % h(Nationality, Pet, Cigarette, Drink, Color)
    template([h(_, _, _, _, _), h(_, _, _, _, _), h(_, _, _, _, _), h(_, _, _, _, _), h(_, _, _, _, _)]).

    member(A, [A, _, _, _, _]).
    member(B, [_, B, _, _, _]).
    member(C, [_, _, C, _, _]).
    member(D, [_, _, _, D, _]).
    member(E, [_, _, _, _, E]).

    next(A, B, [A, B, _, _, _]).
    next(B, C, [_, B, C, _, _]).
    next(C, D, [_, _, C, D, _]).
    next(D, E, [_, _, _, D, E]).

:- end_object.


wordset: map read.lines relative "unixdict.txt" => strip

validAnswer?: function [answer][
    if not? contains? wordset answer [
        prints "\tNot a valid dictionary word."
        return false
    ]
    if contains? pastWords answer [
        prints "\tWord already used."
        return false
    ]
    if 1 <> levenshtein answer last pastWords [
        prints "\tNot a correct wordiff."
        return false
    ]
    return true
]

playerA: input "player A: what is your name? "
playerB: input "player B: what is your name? "

pastWords: new @[sample select wordset 'word [ contains? [3 4] size word ]]

print ["\nThe initial word is:" last pastWords "\n"]

current: playerA
while ø [
    neww: strip input ~"|current|, what is the next word? "
    while [not? validAnswer? neww][
        neww: strip input " Try again: "
    ]
    'pastWords ++ neww
    current: (current=playerA)? -> playerB -> playerA
    print ""
]


isoneless(nw, ow) = any(i -> nw == ow[begin:i-1] * ow[i+1:end], eachindex(ow))
isonemore(nw, ow) = isoneless(ow, nw)
isonechanged(x, y) = length(x) == length(y) && count(i -> x[i] != y[i], eachindex(y)) == 1
onefrom(nw, ow) = isoneless(nw, ow) || isonemore(nw, ow) || isonechanged(nw, ow)

function askprompt(prompt)
    ans = ""
    while isempty(ans)
        print(prompt)
        ans = strip(readline())
    end
    return ans
end

function wordiff(dictfile = "unixdict.txt")
    wordlist = [w for w in split(read(dictfile, String), r"\s+") if !occursin(r"\W", w) && length(w) > 2]
    starters = [w for w in wordlist if 3 <= length(w) <= 4]

    timelimit = something(tryparse(Float64, askprompt("Time limit (min) or 0 for none: ")), 0.0)

    players = split(askprompt("Enter players' names. Separate by commas: "), r"\s*,\s*")
    times, word = Dict(player => Float32[] for player in players), rand(starters)
    used, totalsecs, timestart = [word], timelimit * 60, time()
    while length(players) > 1
        player = popfirst!(players)
        playertimestart = time()
        newword = askprompt("$player, your move. The current word is $word.  Your worddiff? ")
        if timestart + totalsecs > time()
            if onefrom(newword, word) && !(newword in used) && lowercase(newword) in wordlist
                println("Correct.")
                push!(players, player)
                word = newword
                push!(used, newword)
                push!(times[player], time() - playertimestart)
            else
                println("Wordiff choice incorrect. Player $player exits game.")
            end
        else  # out of time
            println("Sorry, time was up. Timing ranks for remaining players:")
            avtimes = Dict(p => isempty(times[p]) ? NaN : sum(times[p]) / length(times[p])
                for p in players)
            sort!(players, lt = (x, y) -> avtimes[x] < avtimes[y])
            foreach(p -> println("    $p:", lpad(avtimes[p], 10), " seconds average"), players)
            break
        end
        sleep(rand() * 3)
    end
    length(players) < 2 && println("Player $(first(players)) is the only one left, and wins the game.")
end

wordiff()


import httpclient, sequtils, sets, strutils, sugar
from unicode import capitalize

const
  DictFname = "unixdict.txt"
  DictUrl1 = "http://wiki.puzzlers.org/pub/wordlists/unixdict.txt"    # ~25K words
  DictUrl2 = "https://raw.githubusercontent.com/dwyl/english-words/master/words.txt"  # ~470K words

type Dictionary = HashSet[string]

proc loadDictionary(fname = DictFname): Dictionary =
  ## Return appropriate words from a dictionary file.
  for word in fname.lines():
    if word.len >= 3 and word.allCharsInSet(Letters): result.incl word.toLowerAscii

proc loadWebDictionary(url: string): Dictionary =
  ## Return appropriate words from a dictionary web page.
  let client = newHttpClient()
  for word in client.getContent(url).splitLines():
    if word.len >= 3 and word.allCharsInSet(Letters): result.incl word.toLowerAscii

proc getPlayers(): seq[string] =
  ## Return inputted ordered list of contestant names.
  try:
    stdout.write "Space separated list of contestants: "
    stdout.flushFile()
    result = stdin.readLine().splitWhitespace().map(capitalize)
    if result.len == 0:
      quit "Empty list of names. Quitting.", QuitFailure
  except EOFError:
    echo()
    quit "Encountered end of file. Quitting.", QuitFailure

proc isWordiffRemoval(word, prev: string; comment = true): bool =
  ## Is "word" derived from "prev" by removing one letter?
  for i in 0..prev.high:
    if word == prev[0..<i] & prev[i+1..^1]: return true
  if comment: echo "Word is not derived from previous by removal of one letter."
  result = false

proc isWordiffInsertion(word, prev: string; comment = true): bool =
  ## Is "word" derived from "prev" by adding one letter?
  for i in 0..word.high:
    if prev == word[0..<i] & word[i+1..^1]: return true
  if comment: echo "Word is not derived from previous by insertion of one letter."
  return false

proc isWordiffChange(word, prev: string; comment = true): bool =
  ## Is "word" derived from "prev" by changing exactly one letter?
  var diffcount = 0
  for i in 0..word.high:
    diffcount += ord(word[i] != prev[i])
  if diffcount != 1:
    if comment:
      echo "More or less than exactly one character changed."
    return false
  result = true

proc isWordiff(word: string; wordiffs: seq[string]; dict: Dictionary; comment = true): bool =
  ## Is "word" a valid wordiff from "wordiffs[^1]"?
  if word notin dict:
    if comment:
      echo "That word is not in my dictionary."
      return false
  if word in wordiffs:
    if comment:
      echo "That word was already used."
      return false
  result = if word.len < wordiffs[^1].len: word.isWordiffRemoval(wordiffs[^1], comment)
           elif word.len > wordiffs[^1].len: word.isWordiffInsertion(wordiffs[^1], comment)
           else: word.isWordiffChange(wordiffs[^1], comment)

proc couldHaveGot(wordiffs: seq[string]; dict: Dictionary): seq[string] =
  for word in dict - wordiffs.toHashSet:
    if word.isWordiff(wordiffs, dict, comment = false):
      result.add word

when isMainModule:
  import random

  randomize()
  let dict = loadDictionary(DictFname)
  let dict34 = collect(newSeq):
                 for word in dict:
                   if word.len in [3, 4]: word
  let start = sample(dict34)
  var wordiffs = @[start]
  let players = getPlayers()
  var iplayer = 0
  var word: string
  while true:
    let name = players[iplayer]
    while true:
      stdout.write "$1, input a wordiff from “$2”: ".format(name, wordiffs[^1])
      stdout.flushFile()
      try:
        word = stdin.readLine().strip()
        if word.len > 0: break
      except EOFError:
        quit "Encountered end of file. Quitting.", QuitFailure
    if word.isWordiff(wordiffs, dict):
      wordiffs.add word
    else:
      echo "You have lost, $#.".format(name)
      let possibleWords = couldHaveGot(wordiffs, dict)
      if possibleWords.len > 0:
        echo "You could have used: ", possibleWords[0..min(possibleWords.high, 20)].join(" ")
      break
    iplayer = (iplayer + 1) mod players.len