Twelve statements
This puzzle is borrowed from here.
Given the following twelve statements, which of them are true?
1. This is a numbered list of twelve statements. 2. Exactly 3 of the last 6 statements are true. 3. Exactly 2 of the even-numbered statements are true. 4. If statement 5 is true, then statements 6 and 7 are both true. 5. The 3 preceding statements are all false. 6. Exactly 4 of the odd-numbered statements are true. 7. Either statement 2 or 3 is true, but not both. 8. If statement 7 is true, then 5 and 6 are both true. 9. Exactly 3 of the first 6 statements are true. 10. The next two statements are both true. 11. Exactly 1 of statements 7, 8 and 9 are true. 12. Exactly 4 of the preceding statements are true.
When you get tired of trying to figure it out in your head, write a program to solve it, and print the correct answer or answers.
Extra credit: also print out a table of near misses, that is, solutions that are contradicted by only a single statement.
Go
<lang go>package main
import "fmt"
// its' not too much more work to check all the permutations concurrently var solution = make(chan int) var nearMiss = make(chan int) var done = make(chan bool)
func main() {
// iterate and use the bits as the permutation for i := 0; i < 4096; i++ { go checkPerm(i) } // collect the misses and list them after the complete solution(s) var ms []int for i := 0; i < 4096; { select { case <-done: i++ case s := <-solution: print12("solution", s) case m := <-nearMiss: ms = append(ms, m) } } for _, m := range ms { print12("near miss", m) }
}
func print12(label string, bits int) {
fmt.Print(label, ":") for i := 1; i <= 12; i++ { if bits&1 == 1 { fmt.Print(" ", i) } bits >>= 1 } fmt.Println()
}
func checkPerm(tz int) {
// closure returns true if tz bit corresponding to // 1-based statement number is 1. ts := func(n uint) bool { return tz>>(n-1)&1 == 1 } // variadic closure returns number of statements listed as arguments // which have corresponding tz bit == 1. ntrue := func(xs ...uint) int { nt := 0 for _, x := range xs { if ts(x) { nt++ } } return nt } // a flag used on repeated calls to test. // set to true when first contradiction is found. // if another is found, this function (checkPerm) can "short circuit" // and return immediately without checking additional statements. var con bool // closure called to test each statement test := func(statement uint, b bool) { switch { case ts(statement) == b: case con: panic("bail") default: con = true } } // short circuit mechanism defer func() { if x := recover(); x != nil { if msg, ok := x.(string); !ok && msg != "bail" { panic(x) } } done <- true }()
// 1. This is a numbered list of twelve statements. test(1, true)
// 2. Exactly 3 of the last 6 statements are true. test(2, ntrue(7, 8, 9, 10, 11, 12) == 3)
// 3. Exactly 2 of the even-numbered statements are true. test(3, ntrue(2, 4, 6, 8, 10, 12) == 2)
// 4. If statement 5 is true, then statements 6 and 7 are both true. test(4, !ts(5) || ts(6) && ts(7))
// 5. The 3 preceding statements are all false. test(5, !ts(4) && !ts(3) && !ts(2))
// 6. Exactly 4 of the odd-numbered statements are true. test(6, ntrue(1, 3, 5, 7, 9, 11) == 4)
// 7. Either statement 2 or 3 is true, but not both. test(7, ts(2) != ts(3))
// 8. If statement 7 is true, then 5 and 6 are both true. test(8, !ts(7) || ts(5) && ts(6))
// 9. Exactly 3 of the first 6 statements are true. test(9, ntrue(1, 2, 3, 4, 5, 6) == 3) // 10. The next two statements are both true. test(10, ts(11) && ts(12)) // 11. Exactly 1 of statements 7, 8 and 9 are true. test(11, ntrue(7, 8, 9) == 1) // 12. Exactly 4 of the preceding statements are true. test(12, ntrue(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) == 4)
// no short circuit? send permutation as either near miss or solution if con { nearMiss <- tz } else { solution <- tz }
}</lang>
- Output:
solution: 1 3 4 6 7 11 near miss: 1 4 near miss: 1 5 near miss: 1 5 8 near miss: 1 3 4 6 7 9 near miss: 1 3 4 8 9 near miss: 1 4 6 8 9 near miss: 1 2 4 7 8 9 near miss: 1 2 4 7 9 10 near miss: 5 8 11 near miss: 1 5 8 11 near miss: 1 5 6 9 11 near miss: 1 2 4 7 9 12 near miss: 1 4 8 10 11 12 near miss: 4 8 10 11 12 near miss: 5 8 10 11 12 near miss: 1 5 8 10 11 12
Haskell
Shows answers with 1 for true, followed by list of indices of incorrect elements each set of 1/0s (index is 0-based).
<lang haskell>import Data.List (findIndices)
tf = mapM (\_ -> [1,0])
wrongness b = findIndices id . zipWith (/=) b . map (fromEnum . ($ b))
statements = [ (==12) . length, 3 ⊂ [length statements-6..], 2 ⊂ [1,3..], 4 → [4..6], 0 ⊂ [1..3], 4 ⊂ [0,2..], 1 ⊂ [1,2], 6 → [4..6], 3 ⊂ [0..5], 2 ⊂ [10,11], 1 ⊂ [6,7,8], 4 ⊂ [0..10] ] where (s ⊂ x) b = s == (sum . map (b!!) . takeWhile (< length b)) x (a → x) b = (b!!a == 0) || all ((==1).(b!!)) x
testall s n = [(b, w) | b <- tf s, w <- [wrongness b s], length w == n]
main = let t = testall statements in do putStrLn "Answer" mapM_ print $ t 0 putStrLn "Near misses" mapM_ print $ t 1</lang>
- Output:
Answer ([1,0,1,1,0,1,1,0,0,0,1,0],[]) Near misses ([1,1,0,1,0,0,1,1,1,0,0,0],[7]) ([1,1,0,1,0,0,1,0,1,1,0,0],[9]) ([1,1,0,1,0,0,1,0,1,0,0,1],[11]) ([1,0,1,1,0,1,1,0,1,0,0,0],[8]) ([1,0,1,1,0,0,0,1,1,0,0,0],[6]) ([1,0,0,1,0,1,0,1,1,0,0,0],[5]) ([1,0,0,1,0,0,0,1,0,1,1,1],[11]) ([1,0,0,1,0,0,0,0,0,0,0,0],[7]) ([1,0,0,0,1,1,0,0,1,0,1,0],[7]) ([1,0,0,0,1,0,0,1,0,1,1,1],[11]) ([1,0,0,0,1,0,0,1,0,0,1,0],[11]) ([1,0,0,0,1,0,0,1,0,0,0,0],[10]) ([1,0,0,0,1,0,0,0,0,0,0,0],[7]) ([0,0,0,1,0,0,0,1,0,1,1,1],[0]) ([0,0,0,0,1,0,0,1,0,1,1,1],[0]) ([0,0,0,0,1,0,0,1,0,0,1,0],[0])
J
In the following 'apply' is a foreign conjunction: <lang j> apply 128!:2
NB. example
'*:' apply 1 2 3
1 4 9</lang> This enables us to apply strings (left argument) being verbs to the right argument, mostly a noun. <lang j>S=: <;._2 (0 :0) 12&=@# 3=+/@:{.~&_6 2= +/@:{~&1 3 5 7 9 11 4&{=*./@:{~&4 5 6 0=+/@:{~&1 2 3 4=+/@:{~&0 2 4 6 8 10 1=+/@:{~&1 2 6&{=*./@:{~&4 5 6 3=+/@:{.~&6 2=+/@:{~&10 11 1=+/@:{~&6 7 8 4=+/@:{.~&11 )
testall=: (];"1 0<@I.@:(]~:(apply&><))"1) #:@i.@(2&^)@#</lang>
All true <lang j> (#~0=#@{::~&_1"1) testall S ┌───────────────────────┬┐ │1 0 1 1 0 1 1 0 0 0 1 0││ └───────────────────────┴┘</lang> Near misses <lang j> (#~1=#@{::~&_1"1) testall S ┌───────────────────────┬──┐ │0 0 0 0 1 0 0 1 0 0 1 0│0 │ ├───────────────────────┼──┤ │0 0 0 0 1 0 0 1 0 1 1 1│0 │ ├───────────────────────┼──┤ │0 0 0 1 0 0 0 1 0 1 1 1│0 │ ├───────────────────────┼──┤ │1 0 0 0 1 0 0 0 0 0 0 0│7 │ ├───────────────────────┼──┤ │1 0 0 0 1 0 0 1 0 0 0 0│10│ ├───────────────────────┼──┤ │1 0 0 0 1 0 0 1 0 0 1 0│11│ ├───────────────────────┼──┤ │1 0 0 0 1 0 0 1 0 1 1 1│11│ ├───────────────────────┼──┤ │1 0 0 0 1 1 0 0 1 0 1 0│7 │ ├───────────────────────┼──┤ │1 0 0 1 0 0 0 0 0 0 0 0│7 │ ├───────────────────────┼──┤ │1 0 0 1 0 0 0 1 0 1 1 1│11│ ├───────────────────────┼──┤ │1 0 0 1 0 1 0 1 1 0 0 0│5 │ ├───────────────────────┼──┤ │1 0 1 1 0 0 0 1 1 0 0 0│6 │ ├───────────────────────┼──┤ │1 0 1 1 0 1 1 0 1 0 0 0│8 │ ├───────────────────────┼──┤ │1 1 0 1 0 0 1 0 1 0 0 1│11│ ├───────────────────────┼──┤ │1 1 0 1 0 0 1 0 1 1 0 0│9 │ ├───────────────────────┼──┤ │1 1 0 1 0 0 1 1 1 0 0 0│7 │ └───────────────────────┴──┘</lang>
Iterative for all true <lang j> (-N)&{. #: S <:@]^:((]-.@-:(apply&><)"1) (-N)&{.@#:@])^:(_) 2^N=.#S 1 0 1 1 0 1 1 0 0 0 1 0</lang>
Perl 6
<lang perl6>sub infix:<→> ($protasis,$apodosis) { !$protasis or $apodosis }
my @tests = { True }, # (there's no 0th statement)
{ all(.[1..12]) === any(True, False) }, { 3 == [+] .[7..12] }, { 2 == [+] .[2,4...12] }, { .[5] → all .[6,7] }, { none .[2,3,4] }, { 4 == [+] .[1,3...11] }, { one .[2,3] }, { .[7] → all .[5,6] }, { 3 == [+] .[1..6] }, { all .[11,12] }, { one .[7,8,9] }, { 4 == [+] .[1..11] };
my @good; my @bad; my @ugly;
for reverse 0 ..^ 2**12 -> $i {
my @b = $i.fmt("%012b").comb; my @assert = True, @b.map: { .so } my @result = @tests.map: { .(@assert).so } my @s = ( $_ if $_ and @assert[$_] for 1..12 ); if @result eqv @assert {
push @good, "<{@s}> is consistent.";
} else {
my @cons = gather for 1..12 { if @assert[$_] !eqv @result[$_] { take @result[$_] ?? $_ !! "¬$_"; } } my $mess = "<{@s}> implies {@cons}."; if @cons == 1 { push @bad, $mess } else { push @ugly, $mess }
}
}
.say for @good; say "\nNear misses:"; .say for @bad;</lang>
- Output:
<1 3 4 6 7 11> is consistent. Near misses: <1 2 4 7 8 9> implies ¬8. <1 2 4 7 9 10> implies ¬10. <1 2 4 7 9 12> implies ¬12. <1 3 4 6 7 9> implies ¬9. <1 3 4 8 9> implies 7. <1 4 6 8 9> implies ¬6. <1 4 8 10 11 12> implies ¬12. <1 4> implies 8. <1 5 6 9 11> implies 8. <1 5 8 10 11 12> implies ¬12. <1 5 8 11> implies 12. <1 5 8> implies 11. <1 5> implies 8. <4 8 10 11 12> implies 1. <5 8 10 11 12> implies 1. <5 8 11> implies 1.
Python
<lang python> from itertools import product
- from pprint import pprint as pp
constraintinfo = (
(lambda st: len(st) == 12 ,(1, 'This is a numbered list of twelve statements')), (lambda st: sum(st[-6:]) == 3 ,(2, 'Exactly 3 of the last 6 statements are true')), (lambda st: sum(st[1::2]) == 2 ,(3, 'Exactly 2 of the even-numbered statements are true')), (lambda st: (st[5]&st[6]) if st[4] else 1 ,(4, 'If statement 5 is true, then statements 6 and 7 are both true')), (lambda st: sum(st[1:4]) == 0 ,(5, 'The 3 preceding statements are all false')), (lambda st: sum(st[0::2]) == 4 ,(6, 'Exactly 4 of the odd-numbered statements are true')), (lambda st: sum(st[1:3]) == 1 ,(7, 'Either statement 2 or 3 is true, but not both')), (lambda st: (st[4]&st[5]) if st[6] else 1 ,(8, 'If statement 7 is true, then 5 and 6 are both true')), (lambda st: sum(st[:6]) == 3 ,(9, 'Exactly 3 of the first 6 statements are true')), (lambda st: (st[10]&st[11]) ,(10, 'The next two statements are both true')), (lambda st: sum(st[6:9]) == 1 ,(11, 'Exactly 1 of statements 7, 8 and 9 are true')), (lambda st: sum(st[0:11]) == 4 ,(12, 'Exactly 4 of the preceding statements are true')),
)
def printer(st, matches):
if False in matches: print('Missed by one statement: %i, %s' % docs[matches.index(False)]) else: print('Statements:') print(' ' + ', '.join('%i:%s' % (i, 'T' if t else 'F') for i, t in enumerate(st, 1)))
funcs, docs = zip(*constraintinfo)
full, partial = [], []
for st in product( *([(False, True)] * 12) ):
truths = [bool(func(st)) for func in funcs] matches = [s == t for s,t in zip(st, truths)] mcount = sum(matches) if mcount == 12: full.append((st, matches)) elif mcount == 11: partial.append((st, matches))
for stt in full + partial:
printer(*stt)</lang>
- Output:
Full match: 1:T, 2:F, 3:T, 4:T, 5:F, 6:T, 7:T, 8:F, 9:F, 10:F, 11:T, 12:F Missed by one statement: 1, This is a numbered list of twelve statements: 1:F, 2:F, 3:F, 4:F, 5:T, 6:F, 7:F, 8:T, 9:F, 10:F, 11:T, 12:F Missed by one statement: 1, This is a numbered list of twelve statements: 1:F, 2:F, 3:F, 4:F, 5:T, 6:F, 7:F, 8:T, 9:F, 10:T, 11:T, 12:T Missed by one statement: 1, This is a numbered list of twelve statements: 1:F, 2:F, 3:F, 4:T, 5:F, 6:F, 7:F, 8:T, 9:F, 10:T, 11:T, 12:T Missed by one statement: 8, If statement 7 is true, then 5 and 6 are both true: 1:T, 2:F, 3:F, 4:F, 5:T, 6:F, 7:F, 8:F, 9:F, 10:F, 11:F, 12:F Missed by one statement: 11, Exactly 1 of statements 7, 8 and 9 are true: 1:T, 2:F, 3:F, 4:F, 5:T, 6:F, 7:F, 8:T, 9:F, 10:F, 11:F, 12:F Missed by one statement: 12, Exactly 4 of the preceding statements are true: 1:T, 2:F, 3:F, 4:F, 5:T, 6:F, 7:F, 8:T, 9:F, 10:F, 11:T, 12:F Missed by one statement: 12, Exactly 4 of the preceding statements are true: 1:T, 2:F, 3:F, 4:F, 5:T, 6:F, 7:F, 8:T, 9:F, 10:T, 11:T, 12:T Missed by one statement: 8, If statement 7 is true, then 5 and 6 are both true: 1:T, 2:F, 3:F, 4:F, 5:T, 6:T, 7:F, 8:F, 9:T, 10:F, 11:T, 12:F Missed by one statement: 8, If statement 7 is true, then 5 and 6 are both true: 1:T, 2:F, 3:F, 4:T, 5:F, 6:F, 7:F, 8:F, 9:F, 10:F, 11:F, 12:F Missed by one statement: 12, Exactly 4 of the preceding statements are true: 1:T, 2:F, 3:F, 4:T, 5:F, 6:F, 7:F, 8:T, 9:F, 10:T, 11:T, 12:T Missed by one statement: 6, Exactly 4 of the odd-numbered statements are true: 1:T, 2:F, 3:F, 4:T, 5:F, 6:T, 7:F, 8:T, 9:T, 10:F, 11:F, 12:F Missed by one statement: 7, Either statement 2 or 3 is true, but not both: 1:T, 2:F, 3:T, 4:T, 5:F, 6:F, 7:F, 8:T, 9:T, 10:F, 11:F, 12:F Missed by one statement: 9, Exactly 3 of the first 6 statements are true: 1:T, 2:F, 3:T, 4:T, 5:F, 6:T, 7:T, 8:F, 9:T, 10:F, 11:F, 12:F Missed by one statement: 12, Exactly 4 of the preceding statements are true: 1:T, 2:T, 3:F, 4:T, 5:F, 6:F, 7:T, 8:F, 9:T, 10:F, 11:F, 12:T Missed by one statement: 10, The next two statements are both true: 1:T, 2:T, 3:F, 4:T, 5:F, 6:F, 7:T, 8:F, 9:T, 10:T, 11:F, 12:F Missed by one statement: 8, If statement 7 is true, then 5 and 6 are both true: 1:T, 2:T, 3:F, 4:T, 5:F, 6:F, 7:T, 8:T, 9:T, 10:F, 11:F, 12:F