Twelve statements

Revision as of 00:17, 21 September 2012 by Sonia (talk | contribs) (Go solution)

This puzzle is borrowed from here.

Twelve statements is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

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

  1. 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