Task: Zebra puzzle




Go: package main

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



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



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
)



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")
}



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 { 
                        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 { 
                                        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
                                                        
                                                }
                                        }
                                }
                        }
                }
        }
        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
}


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 {
        
        if h.n == English && h.c != Red || h.n != English && h.c == Red {
                return false
        }
        
        if h.n == Swede && h.a != Dog || h.n != Swede && h.a == Dog {
                return false
        }
        
        if h.n == Dane && h.d != Tea || h.n != Dane && h.d == Tea {
                return false
        }
        
        if h.c == Green && h.d != Coffee || h.c != Green && h.d == Coffee {
                return false
        }
        
        if h.a == Birds && h.s != PallMall || h.a != Birds && h.s == PallMall {
                return false
        }
        
        if h.c == Yellow && h.s != Dunhill || h.c != Yellow && h.s == Dunhill {
                return false
        }
        
        if h.a == Cats && h.s == Blend {
                return false
        }
        
        if h.a == Horse && h.s == Dunhill {
                return false
        }
        
        if h.d == Beer && h.s != BlueMaster || h.d != Beer && h.s == BlueMaster {
                return false
        }
        
        if h.n == German && h.s != Prince || h.n != German && h.s == Prince {
                return false
        }
        
        if h.n == Norwegian && h.c == Blue {
                return false
        }
        
        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
        }
        
        if ci[Green]+1 != ci[White] {
                return false
        }
        
        if dist(ai[Cats], si[Blend]) != 1 {
                return false
        }
        
        if dist(ai[Horse], si[Dunhill]) != 1 {
                return false
        }
        
        if dist(ni[Norwegian], ci[Blue]) != 1 {
                return false
        }
        
        if dist(di[Water], si[Blend]) != 1 {
                return false
        }

        
        if hs[2].d != Milk {
                return false
        }
        
        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)
}




Python: from logpy import *
from logpy.core import lall
import time

def lefto(q, p, list):
	
	
	
	return membero((q,p), zip(list, list[1:]))

def nexto(q, p, list):
	
	
	
	return conde([lefto(q, p, list)], [lefto(p, q, list)])

houses = var()

zebraRules = lall(
	
	(eq, 		(var(), var(), var(), var(), var()), houses),
	
	(membero,	('Englishman', var(), var(), var(), 'red'), houses),
	
	(membero,	('Swede', var(), var(), 'dog', var()), houses),
	
	(membero,	('Dane', var(), 'tea', var(), var()), houses),
	
	(lefto,		(var(), var(), var(), var(), 'green'),
				(var(), var(), var(), var(), 'white'), houses),
	
	(membero,	(var(), var(), 'coffee', var(), 'green'), houses),
	
	(membero,	(var(), 'Pall Mall', var(), 'birds', var()), houses),
	
	(membero,	(var(), 'Dunhill', var(), var(), 'yellow'), houses),
	
	(eq,		(var(), var(), (var(), var(), 'milk', var(), var()), var(), var()), houses),
	
	(eq,		(('Norwegian', var(), var(), var(), var()), var(), var(), var(), var()), houses),
	
	(nexto,		(var(), 'Blend', var(), var(), var()),
				(var(), var(), var(), 'cats', var()), houses),
	
	(nexto,		(var(), 'Dunhill', var(), var(), var()),
				(var(), var(), var(), 'horse', var()), houses),
	
	(membero,	(var(), 'Blue Master', 'beer', var(), var()), houses),
	
	(membero,	('German', 'Prince', var(), var(), var()), houses),
	
	(nexto,		('Norwegian', var(), var(), var(), var()),
				(var(), var(), var(), var(), 'blue'), houses),
	
	(nexto,		(var(), 'Blend', var(), var(), var()),
				(var(), var(), 'water', var(), var()), houses),
	
	(membero,	(var(), var(), var(), 'zebra', var()), houses)
)

t0 = time.time()
solutions = run(0, houses, zebraRules)
t1 = time.time()
dur = t1-t0

count = len(solutions)
zebraOwner = [house for house in solutions[0] if 'zebra' in house][0][0]

print "%i solutions in %.2f seconds" % (count, dur)
print "The %s is the owner of the zebra" % zebraOwner
print "Here are all the houses:"
for line in solutions[0]:
	print str(line)