-
Notifications
You must be signed in to change notification settings - Fork 0
/
logic.lisp
123 lines (97 loc) · 3.54 KB
/
logic.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
;;; parameters for convenience
(defparameter *and* (string "∧")
"Logical AND operator.")
(defparameter *or* (string "∨")
"Logical OR operator.")
(defparameter *true* (string "T")
"Logical TRUE.")
(defparameter *false* (string "F")
"Logical FALSE.")
;;; random generators
(defun should-negate-p ()
(equal (random 4) 0))
(defun should-add-parantheses-p ()
(equal (random 4) 0))
(defun make-random-item ()
(string (char "TFp" (random 3))))
(defun make-random-operator ()
(string (char "∧∨" (random 2))))
(defun make-random-block ()
(if (should-negate-p)
(string "¬p")
(make-random-item)))
(defun make-random-expression ()
(if (should-add-parantheses-p)
(concatenate 'string "¬(" (make-random-block) " " (make-random-operator) " " (make-random-block) ")")
(concatenate 'string (make-random-block) " " (make-random-operator) " " (make-random-block))))
;;; expression solving
(defun has-parantheses-p (expr)
(equal (subseq expr 0 2) (string "¬(")))
(defun remove-parantheses (expr)
(subseq expr 2 (- (length expr) 1)))
(defun get-operator (expr)
(or (find #\∧ expr :test #'equal)
(find #\∨ expr :test #'equal)))
(defun get-left (expr)
(string-trim " " (subseq expr 0 2)))
(defun get-right (expr)
(let ((len (length expr)))
(string-trim " " (subseq expr (- len 2) len))))
(defun truep (block)
(equal block *true*))
(defun falsep (block)
(equal block *false*))
(defun both-true-p (expr)
(let ((left (get-left expr)) (right (get-right expr)))
(and (truep left) (truep right))))
(defun both-false-p (expr)
(let ((left (get-left expr)) (right (get-right expr)))
(and (falsep left) (falsep right))))
(defun andp (operator)
(equal (string operator) *and*))
(defun orp (operator)
(equal (string operator) *or*))
;; returns the other part of the expression if one part is true,
;; doesn't check the other part if first part is true
(defun one-true (expr)
(let ((left (get-left expr)) (right (get-right expr)))
(cond ((truep left) right)
((truep right) left)
(t nil))))
;; false version of one-true
(defun one-false (expr)
(let ((left (get-left expr)) (right (get-right expr)))
(cond ((falsep left) right)
((falsep right) left)
(t nil))))
(defun negate-block (block)
(cond
((equal block *false*) *true*)
((equal block *true*) *false*)
((equal (subseq block 0 1) (string "¬")) (string "p"))
(t (concatenate 'string "¬" block))))
(defun solve-without-parantheses (expr)
(let ((operator (get-operator expr)))
(cond
((both-true-p expr) *true*)
((both-false-p expr) *false*)
((and (one-true expr) (orp operator)) *true*)
((and (one-true expr) (andp operator)) (one-true expr))
((and (one-false expr) (orp operator)) (one-false expr))
((and (one-false expr) (andp operator)) *false*)
((equal (get-left expr) (get-right expr)) (get-left expr))
((orp operator) *true*)
(t *false*))))
(defun solve-expression (expr)
(if (has-parantheses-p expr)
(negate-block (solve-without-parantheses (remove-parantheses expr)))
(solve-without-parantheses expr)))
;; generates a wrong but not completely unbelievable answer
(defun make-wrong-answer (expr)
(let ((solution (solve-expression expr)))
(cond
((equal solution (string "¬p")) (make-random-item))
((equal solution (string "p")) (negate-block (make-random-item)))
((find #\p expr :test #'equal) (nth (random 3)
(remove-if (lambda (str) (equal str solution)) '("p" "T" "F" "¬p"))))
(t (negate-block solution)))))