2016-08-07 18 views
1

Ich habe versucht, dieses Puzzle https://puzzling.stackexchange.com/questions/40094/who-committed-the-crime mit Racket zu lösen.Lösen eines Puzzlespiels im Racket

Ein Verbrechen wurde von einer Person durchgeführt, es gibt 5 Verdächtige. Jeder Verdächtige wird unter Polygraphen gefragt, wem sie das begangene Verbrechen glaubten.

Ihre Antworten sind wie folgt:

Terry : It wasn't Carl, It was Steve 
Steve : It wasn't Matt, It wasn't Carl 
Matt : It was Carl, It wasn't Terry 
Ben : It was Matt, It was Steve 
Carl : It was Ben, It wasn't Terry 

Der Polygraph zeigte, dass jeder Verdächtige sagte eine Lüge und eine Wahrheit. Wer hat das Verbrechen begangen?

Folgende ist mein Code:

(define (oneof a b) 
    (or (and a (not b)) (and b (not a)))) 

(for ((i 5)) 
    (define templist (list #f #f #f #f #f)) ; make a temporary list of all false; 
    (set! templist (list-set templist i #t)) ; one by one keep one as true in this loop; 
    (define t (list-ref templist 0)) ; allocate each person according to above list (one kept true one by one) 
    (define s (list-ref templist 1)) 
    (define m (list-ref templist 2)) 
    (define b (list-ref templist 3)) 
    (define c (list-ref templist 4)) 

    (when        ; test if all statements fit with above assignment: 
    (and 
    (oneof (not c) s)    ; Terry's statement 
    (oneof (not m) (not c))  ; Steve's statement 
    (oneof c (not t))    ; Matt's statement 
    (oneof m s)     ; Ben's statement 
    (oneof b (not t)))    ; Carl's statement 
    (println (list "t" "s" "m" "b" "c")) ; print allocation if all statement fit in; 
    (println templist))) 

Ausgabe zeigt Matt das Verbrechen begangen:

'("t" "s" "m" "b" "c") 
'(#f #f #t #f #f) 

Es funktioniert, aber der Code ist zwingend notwendig und nicht sehr funktionell (insbesondere t definieren, definieren s , ... Teil). Wie kann es verbessert werden? Danke für deine Kommentare/Antworten.

+2

Code Überprüfung SO wäre eine bessere Passform. – Sylwester

Antwort

1

Dies ist ein Ersatzprogramm in idiomatischen Racket geschrieben - und alle, die lästigen set! und list-ref vermieden werden, die auf der Stirn gerunzelt werden beim Schreiben von funktionalem Stil Code:

; generate a matrix with possibilities 
(define (make-matrix n) 
    (for/list [(i (in-range n))] 
    (build-list n (λ (j) (= i j))))) 

; iterate over each row 
(for [(row (make-matrix 5))] 
    ; unpack each row into the corresponding variables 
    (match-let ([(list t s m b c) row]) 
    ; don't reinvent the wheel, `oneof` is called `xor` 
    (when (and (xor (not c) s) 
       (xor (not m) (not c)) 
       (xor c (not t)) 
       (xor m s) 
       (xor b (not t))) 
     (println '(t s m b c)) 
     (println row)))) 
+0

Viele neue Funktionen hier für mich! – rnso

+0

Studieren Sie die Dokumentation, Sie werden feststellen, dass alles, was Sie im imperativen Code gewohnt sind, ein netteres, schlankeres Äquivalent im Funktionscode hat –

+0

Eine noch mehr idiomatische Lösung würde 'for/list' anstelle von' for', 'cond' verwenden anstelle von 'when', Rückgabe von' row', anstatt es zu drucken, und Rückgabe von false, wenn die Bedingungen nicht erfüllt sind, so dass eine '(Filteridentität ...) um das ganze Ding alle gültigen Möglichkeiten zurückgibt. –

2

Diese Antwort basiert auf @Oscar Lopez Antwort, aber modifiziert, um mehr idiomatische Eigenschaften wie filter mit einer Hilfsfunktion anstelle von for, when und println zu verwenden.

Dieser Code-Stil, der einen Wert zurückgibt, ist viel nützlicher, da der erzeugte Wert im späteren Code verwendet werden könnte, wo eine imperative Aktion wie println viel weniger wiederverwendbar wäre.

@Oscar Lopez make-matrix Funktion erzeugt eine erste Liste von Möglichkeiten, aber wir müssen diejenigen herausfiltern, die unmöglich sind, und lassen nur diejenigen, die möglich sind. So schreiben, dass nach unten:

;; If there are no valid solutions, this will be an empty list, 
;; if there's one, this will be a list of one element, 
;; and if there are more, this will include all of them. 
(filter valid-solution? (make-matrix 5)) 

;; Wish list: 
;; valid-solution? : (Listof Boolean) -> Boolean 

Jetzt müssen wir nur noch eine Definition hinzufügen für valid-solution?

;; valid-solution? : (Listof Boolean) -> Boolean 
;; Given a list containing booleans for whether Terry, Steve, Matt, Ben, and Carl did it, 
;; this determines whether that combination is possible under the constraints in the problem. 
(define (valid-solution? row) 
    ; unpack each row into the corresponding variables 
    (match-define (list t s m b c) row) 
    ; don't reinvent the wheel, `oneof` is called `xor` 
    (and (xor (not c) s) 
     (xor (not m) (not c)) 
     (xor c (not t)) 
     (xor m s) 
     (xor b (not t)))) 

Und das ist es. Das vollständige Programm einschließlich make-matrix ist das:

#lang racket 

;; make-matrix : Natural -> (Listof (Listof Boolean)) 
;; generate a matrix with possibilities 
(define (make-matrix n) 
    (for/list ([i (in-range n)]) 
    (build-list n (λ (j) (= i j))))) 

;; valid-solution? : (Listof Boolean) -> Boolean 
;; Given a list containing booleans for whether Terry, Steve, Matt, Ben, and Carl did it, 
;; this determines whether that combination is possible under the constraints in the problem. 
(define (valid-solution? row) 
    ; unpack each row into the corresponding variables 
    (match-define (list t s m b c) row) 
    ; don't reinvent the wheel, `oneof` is called `xor` 
    (and (xor (not c) s) 
     (xor (not m) (not c)) 
     (xor c (not t)) 
     (xor m s) 
     (xor b (not t)))) 

;; If there are no valid solutions, this will be an empty list, 
;; if there's one, this will be a list of one element, 
;; and if there are more, this will include all of them. 
(filter valid-solution? (make-matrix 5)) 
+0

Große funktionale Lösung. – rnso