~edwargix/tallyard

62ad1cfc379768603b5e84adf41919068d81a17c — David Florness 5 years ago d5aff2c
Encode ranked voting
2 files changed, 56 insertions(+), 8 deletions(-)

M client.rkt
M info.rkt
M client.rkt => client.rkt +55 -7
@@ 1,4 1,5 @@
#lang typed/racket
(require math/array)
(require math/matrix)
(require racket/list)
(require racket/math)


@@ 34,6 35,8 @@
(require/typed crypto
  [crypto-random-bytes (Natural -> Bytes)])
(require "poly.rkt")
(require/typed sugar
  [members-unique? (-> (Listof Any) Boolean)])

(define (integer->hex-string [n : Integer])
  (bytes->hex-string


@@ 76,16 79,61 @@
  (newline)

  (displayln "retrieving candidates...")
  (define candidates (json-response-body (get bulletin "/candidates")))
  (define candidates (cast (json-response-body
                            (get bulletin "/candidates")) (Listof String)))

  (displayln "Candidates:")
  (for ([i (in-naturals)]
        [c candidates])
    (displayln (format "~a) ~a" (add1 i) c)))

  (define vote
    (let loop : Integer ()
      (let [(n (string->number (readline "Vote: ")))]
        (if (eq? n #f)
            (begin
              (displayln "Please enter a valid number")
              (loop))
            (assert n exact-integer?)))))
         (with-handlers ([exn:fail:user?
                          (λ ([e : exn])
                            (displayln (exn-message e))
                            (loop))])
           (let* ([num-cands (length candidates)]
                  [entries
                   (map
                    (λ ([s : String]) : Integer
                       (let ([entry (assert (string->number s)
                                            exact-integer?)])
                         (if (and (>= entry 1) (<= entry num-cands))
                             (sub1 entry)
                             (raise-user-error
                              (format "every entry in your ballot should be a valid integer ∈ [~a,~a]"
                                      1 num-cands)))))
                    (string-split
                     (readline
                      "Rank the candidates (most to least preferable): ")))])
             (if (members-unique? entries)
                 (let* ([m num-cands]
                        [n m]
                        [arr (array->mutable-array
                              (make-array (vector m n) 0))]
                        [num-peers (cast (length peer-inputs) Positive-Integer)])
                   (let loop ([entry (car entries)]
                              [rst (cdr entries)])
                     (for ([other rst])
                       (when (< entry other)
                         (array-set! arr (vector entry other) 1)))
                     (when (not (empty? rst))
                       (loop (car rst) (cdr rst))))
                   (bytes->integer
                    (for*/fold : Bytes
                       ([bstr : Bytes #""])
                       ([i : Natural (in-range m)]
                        [j : Natural (in-range n)]
                        #:when (< i j))
                     (bytes-append bstr
                                   (integer->bytes
                                    (array-ref arr (vector i j))
                                    (cast (min (integer-bytes-length num-peers #t) 1)
                                          Positive-Integer)
                                    #t)))
                    #t))
                 (raise-user-error "every entry in your ballot must be unique"))))))

  (define poly (random-poly
                (cast (sub1 (length peer-inputs)) Natural)

M info.rkt => info.rkt +1 -1
@@ 1,6 1,6 @@
#lang info
(define collection "tallyard")
(define deps '("base" "crypto" "simple-http"))
(define deps '("base" "crypto" "simple-http" "sugar"))
(define build-deps '("scribble-lib" "racket-doc" "rackunit-lib"))
(define scribblings '(("scribblings/tallyard.scrbl" ())))
(define pkg-desc "Description Here")