#lang racket

; read in a series of integers, terminated by 0, and output the maximum.


;; bug if input is negative, e.g., -30000

 
(define max-prog
'((read-it  input 0)
  (         skipzero 0)
  (         jump store-it)
  (	    load max)
  (	    output 0)
  (         halt 0)
  (store-it store n)
  (         sub max)
  (         skippos 0)
  (         jump read-it)
  (	    load n)
  (	    store max)
  (	    jump read-it)
  (n        data 0)
  (max      data 0)
;;  (max      data -32767)  when sub'd makes a positive number
  ))

;; assume at least 2 inputs

(define max2-prog
  '((input 0)
    (store max)
    (read-it  input 0)
    (         skipzero 0)
    (         jump store-it)
    (	      load max)
    (	      output 0)
    (         halt 0)
    (store-it store n)
    (         sub max)
    (         skippos 0)
    (         jump read-it)
    (	      load n)
    (	      store max)
    (	      jump read-it)
    (n        data 0)
    (max      data 0)
  ))

;; note: simulate lite does not return intermediate configs
;; (simulate-lite 100 (init-config (assemble max-prog)))



; read in a number and output if it is odd or even. 

;; from Sean Hackett (another aptonym?)

(define odd-prog
  '((read-it input 0)
    ( store in)
    (make-pos skippos 0)
    (    jump make-pos-h)
    (       jump cycle)
    (make-pos-h     add two)
    (        store in)
    (  jump make-pos)
    (cycle skipzero 0)
    (  jump cycle-2)
    (        load even)
    ( output 0)
    (   halt 0)
    (cycle-2 skippos 0)
    ( jump print-odd)
    (     sub two)
    (        store in)
    (  jump cycle)
    (print-odd load odd)
    (   output 0)
    (     halt 0)
    (two data 2)
    (in        data 0)
    (even data 1)
    (odd data 0)))
 
;; from Alexi Christakis (does not handle negative input)

(define even-odd
  '((input 0)
    (sub-loop    sub two)
    (            skipzero 0)
    (            jump is-negative)
    (            jump print)
    (is-negative skippos 0)
    (            jump print)
    (            jump sub-loop)
    (print       output 0)
    (            halt 0)
    (two data 2)))

;; the simple solution I was imagining would require that TC 201
;; implement the boolean operator AND.

(define simple-oddeven
  '((input 0)
    (and one)
    (output 0)
    (halt 0)
    (one data 1)))

;; here is a better answer.
;; Input the number.
;; Shift it left 15 bits.
;; Shift it right 15 bits.
;; Output the number -- which is the least significant bit of of the number.

(define odd-even-prog
'((        input 0)
  (        shift offset)
  (        shift negoff)
  (        output 0)
  (        halt 0)
  (offset data 15)
  (negoff data -15)
  ))



; read in a number and print out its square (include negative numbers)
 
(define square-prog
  '((     input 0)
    (     skippos 0)
    (     jump convert-pos)
    (     store num)
    (     store count)
    (     load count)
    (loop skippos 0)
    (     jump done)
    (     load square)
    (     add num)
    (     store square)
    (     load count)
    (     sub one)
    (     store count)
    (     jump loop)

    (done load square)
    (     output 0)
    (     halt 0)

    (convert-pos store num)
    (     sub num)
    (     sub num)
    (     store num)
    (     store count)
    (     load count)
    (     jump loop)
    
    (num  data  0)
    (count data 0)
    (square data 0)
    (one  data 1)
    ))
  


; read in a number and output how many binary digits are required to
; represent it. (ignore negative numbers - they would always need 16 bits.)

(define count-bits-good
  '((      input 0)
    (      store num)
    (loop  skippos 0)
    (      jump done)
    (      shift right)
    (      store num)
    (      load count)
    (      add one)
    (      store count)
    (      load num)
    (      jump loop)
    (done  load count)
    (      output 0)
    (      halt 0)
    (one   data 1)
    (right data -1)
    (num   data 0)
    (count data 0)))


;;  very obscure approach - does not use shift
(define count-bits
  '((     input 0)
    (     skippos 0)
    (     jump convert-pos)
    (     store num)
    (loop skippos 0)
    (     jump done)
    (     loadi pointer)
    (     sub num)
    (     skippos 0)
    (     jump next)
    (     jump done)
    (next load pointer)
    (     add one)
    (     store pointer)
    (     load bits)
    (     add one)
    (     store bits)
    (     jump loop)

    (done load bits)
    (     output 0)
    (     halt 0)

    (convert-pos store num)
    (     sub num)
    (     sub num)
    (     store num)
    (     jump loop)
    
    (num  data  0)
    (bits data 1)
    (pointer data one)
    (one  data 1)
    (three  data 3)
    (seven  data 7)
    (fifteen data 15)
    (thirtyone  data 31)
    (sixtythree  data 63)
    (one27  data 127)
    (two55  data 255)
    (five11  data 511)
    (ten23  data 1023)
    (two047  data 2047)
    (four095 data 4095)
    (eight191 data 8191)
    (sixteen383 data 16383)
    (thirty2767 data 32767)
    ))


    
; read in a number and output how many binary digits are required to
; represent it. (ignore negative numbers - they would always need 16 bits.)
; also, assume no bits required to represent 0.

(define width-prog
  '((     input 0)
    (     skippos 0)
    (     jump convert-pos)
    (     store num)
    (loop skippos 0)
    (     jump done)
    (     load bits)
    (     add one)
    (     store bits)
    (     load num)
    (     shift minus)
    (     store num)
    (     jump loop)

    (done load bits)
    (     output 0)
    (     halt 0)

    (convert-pos store num)
    (     sub num)
    (     sub num)
    (     store num)
    (     jump loop)
    
    (num  data  0)
    (bits data 0)
    (one data 1)
    (minus data -1)
    ))




; read in a number and output how many one's it contains.
;; this version counts bits by shifting the bits left and right
;; peeling off one bit at a time.

(define bits-prog
  '((    input 0)
    (    store num)
    (loop shift left)
    (     shift unleft)
    (     add bits)
    (     store bits)
    (     load num)
    (     shift right)
    (     store num)
    (     load count)
    (     sub one)
    (     store count)
    (     skippos 0)
    (     jump done)
    (     load num)
    (     jump loop)
    (done load bits)
    (     output 0)
    (     halt 0)

    (count data 16)
    (bits data 0)
    (num data 0)
    (right data -1)
    (left data 15)
    (unleft data -15)
    (one data 1)
    ))

; read in a number and output if it is odd or even parity

(define parity-prog
  '((    input 0)
    (    store num)
    (loop shift left)
    (     shift unleft)
    (	  skipzero 0)
    (     jump flip)
    (next load num)
    (     shift right)
    (     store num)
    (     load count)
    (     sub one)
    (     store count)
    (     skippos 0)
    (     jump done)
    (     load num)
    (     jump loop)
    (flip load parity)
    (     xor one)
    (     store parity)
    (     jump next)
    (done load parity)
    (     output 0)
    (     halt 0)

    (count data 16)
    (parity data 0)
    (num data 0)
    (right data -1)
    (left data 15)
    (unleft data -15)
    (one data 1)
    ))


;; do not need count 
(define parity-prog-better
  '((    input 0)
    (    store num)
    (loop shift left)
    (     shift unleft)
    (	  skipzero 0)
    (     jump flip)
    (next load num)
    (     shift right)
    (     skippos 0)
    (     jump done)
    (     store num)
    (     jump loop)
    (flip load parity)
    (     xor one)
    (     store parity)
    (     jump next)
    (done load parity)
    (     output 0)
    (     halt 0)

    (parity data 0)
    (num data 0)
    (right data -1)
    (left data 15)
    (unleft data -15)
    (one data 1)
    ))



; read in a positive number n and output the first n Fibonacci numbers
; f[n] = f[n-1] + f[n-2]

(define fib-prog
'((start    input 0)
  (         store count)
  (loop     load prev)
  (         output 0)
  (         load count)
  (         skipzero 0)
  (         jump next)
  (         halt 0)
  (next     sub one)
  (         store count)
  (         load current)
  (         add prev)
  (         store tmp)
  (         load current)
  (         store prev)
  (         load tmp)
  (         store current)
  (         jump loop)
  (count    data 0)
  (one      data 1)	
  (prev     data 0)
  (current  data 1)
  (tmp      data 0)
  ))
  

;; multiply or divide a positive integer by a power of two
;; input number and then power
;; power is positive for multiply, negative for divide

(define powertwo
  '((start input 0)
    (      store num)
    (      skippos 0)
    (      halt 0)
    (      input 0)
    (      store power)
    (      load num)
    (      shift power)
    (      output 0)
    (      jump start)
    (power data 0)
    (num   data 0)))


;; program that calls skiperr
;; keep a running total until you get an arithmetic error

(define testerr
  '((start input 0)
    (      add sum)
    (      skiperr 0)
    (      jump next)
    (      jump error)
    (next  store sum)
    (      output 0)
    (      jump start)
    (error load negone)
    (      output 0)
    (      halt 0)
    (negone data -1)
    (sum   data 0)))