#lang racket
(require "3-3-4-program.rkt")

;; Examining these test cases will help understand how the program is working.
;; All the repl output is at the end.  I thought it was more readable that way.

;; TRY AN INVERTER

(displayln 'INVERTER)
(define in (make-wire))
(set-signal! in 1)
(define out (make-wire))
(displayln 'BEFORE)
(probe 'in in)
(probe 'out out)
(displayln 'DURING)
(inverter in out)
(propagate)
(displayln 'AFTER)
(probe 'in in)
(probe 'out out)
(printf "~n")

;; TRY AN AND-GATE

(displayln 'AND-GATE)
(define in3 (make-wire))
(set-signal! in3 1)
(define in4 (make-wire))
(define out2 (make-wire))
(displayln 'BEFORE)
(probe 'in3 in3)
(probe 'in4 in4)
(probe 'out2 out2)
(displayln 'DURING)
(and-gate in3 in4 out2)
(propagate)
(displayln 'AFTER)
(probe 'in3 in3)
(probe 'in4 in4)
(probe 'out2 out2)
(printf "~n")

;; TRY AN OR-GATE

(displayln 'OR-GATE)
(define in1 (make-wire))
(set-signal! in1 1)
(define in2 (make-wire))
(define out1 (make-wire))
(displayln 'BEFORE)
(probe 'in1 in1)
(probe 'in2 in2)
(probe 'out1 out1)
(displayln 'DURING)
(or-gate in1 in2 out1)
(propagate)
(displayln 'AFTER)
(probe 'in1 in1)
(probe 'in2 in2)
(probe 'out1 out1)
(printf "~n")

;; TRY A HALF-ADDER

(displayln 'HALF-ADDER)
(define in5 (make-wire))
(set-signal! in5 1)
(define in6 (make-wire))
(define sum (make-wire))
(define carry (make-wire))
(displayln 'BEFORE)
(probe 'in5 in5)
(probe 'in6 in6)
(probe 'sum sum)
(probe 'carry carry)
(displayln 'DURING)
(half-adder in5 in6 sum carry)
(propagate)
(displayln 'AFTER)
(probe 'in5 in5)
(probe 'in6 in6)
(probe 'sum sum)
(probe 'carry carry)
(printf "~n")

;; TRY A FULL-ADDER

(displayln 'FULL-ADDER)
(define in7 (make-wire))
(set-signal! in7 1)
(define in8 (make-wire))
(define carry-in (make-wire))
(define sum1 (make-wire))
(define carry-out (make-wire))
(displayln 'BEFORE)
(probe 'in7 in7)
(probe 'in8 in8)
(probe 'carry-in carry-in)
(probe 'sum1 sum1)
(probe 'carry-out carry-out)
(displayln 'DURING)
(full-adder in7 in8 carry-in sum1 carry-out)
(propagate)
(displayln 'AFTER)
(probe 'in7 in7)
(probe 'in8 in8)
(probe 'carry-in carry-in)
(probe 'sum1 sum1)
(probe 'carry-out carry-out)
(printf "~n")

;; REPL OUTPUT

;; INVERTER
;; 'done
;; BEFORE
;; in 0  New-value = 1 
;; out 0  New-value = 0 
;; DURING
;; 'ok
;; 'done
;; AFTER
;; in 2  New-value = 1 
;; out 2  New-value = 0 

;; AND-GATE
;; 'done
;; BEFORE
;; in3 2  New-value = 1 
;; in4 2  New-value = 0 
;; out2 2  New-value = 0 
;; DURING
;; 'ok
;; 'done
;; AFTER
;; in3 5  New-value = 1 
;; in4 5  New-value = 0 
;; out2 5  New-value = 0 

;; OR-GATE
;; 'done
;; BEFORE
;; in1 5  New-value = 1 
;; in2 5  New-value = 0 
;; out1 5  New-value = 0 
;; DURING
;; 'ok
;; out1 10  New-value = 1 
;; 'done
;; AFTER
;; in1 10  New-value = 1 
;; in2 10  New-value = 0 
;; out1 10  New-value = 1 

;; HALF-ADDER
;; 'done
;; BEFORE
;; in5 10  New-value = 1 
;; in6 10  New-value = 0 
;; sum 10  New-value = 0 
;; carry 10  New-value = 0 
;; DURING
;; 'ok
;; sum 18  New-value = 1 
;; 'done
;; AFTER
;; in5 18  New-value = 1 
;; in6 18  New-value = 0 
;; sum 18  New-value = 1 
;; carry 18  New-value = 0 

;; FULL-ADDER
;; 'done
;; BEFORE
;; in7 18  New-value = 1 
;; in8 18  New-value = 0 
;; carry-in 18  New-value = 0 
;; sum1 18  New-value = 0 
;; carry-out 18  New-value = 0 
;; DURING
;; 'ok
;; sum1 26  New-value = 1 
;; 'done
;; AFTER
;; in7 26  New-value = 1 
;; in8 26  New-value = 0 
;; carry-in 26  New-value = 0 
;; sum1 26  New-value = 1 
;; carry-out 26  New-value = 0