Compare commits
2 Commits
632456dca7
...
9c7e8603c7
| Author | SHA1 | Date |
|---|---|---|
|
|
9c7e8603c7 | |
|
|
ec61e6e2a3 |
|
|
@ -0,0 +1,103 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
(provide
|
||||||
|
dot-graph
|
||||||
|
dot-digraph
|
||||||
|
dot-vertex
|
||||||
|
dot-edge)
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
(require rackunit
|
||||||
|
racket/port))
|
||||||
|
|
||||||
|
;; -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(define current-dot-edge-syntax (make-parameter "--"))
|
||||||
|
|
||||||
|
(define ((dot-graph* header edge-stx) func)
|
||||||
|
(write header)
|
||||||
|
(write-string " {\n")
|
||||||
|
(parameterize ([current-dot-edge-syntax edge-stx])
|
||||||
|
(func))
|
||||||
|
(write-string "}\n"))
|
||||||
|
|
||||||
|
(define dot-graph (dot-graph* 'graph "--"))
|
||||||
|
(define dot-digraph (dot-graph* 'digraph "->"))
|
||||||
|
|
||||||
|
(define (write-attrs attrs)
|
||||||
|
(for/fold ([beg "["] [end ""] #:result (write-string end))
|
||||||
|
([attr (in-list attrs)] #:when (cdr attr))
|
||||||
|
(write-string beg)
|
||||||
|
(printf "~a=~s" (car attr) (cdr attr))
|
||||||
|
(values "," "]")))
|
||||||
|
|
||||||
|
(define (dot-vertex id #:label [label #f] #:shape [shape #f])
|
||||||
|
(write id)
|
||||||
|
(write-attrs `([label . ,label]
|
||||||
|
[shape . ,shape]))
|
||||||
|
(write-string ";\n"))
|
||||||
|
|
||||||
|
(define (dot-edge a b #:flip? [flip? #f])
|
||||||
|
(printf "~a ~a ~a;\n"
|
||||||
|
(if flip? b a)
|
||||||
|
(current-dot-edge-syntax)
|
||||||
|
(if flip? a b)))
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
|
||||||
|
(check-equal?
|
||||||
|
(with-output-to-string
|
||||||
|
(λ ()
|
||||||
|
(dot-graph
|
||||||
|
(λ ()
|
||||||
|
(dot-vertex 'a)
|
||||||
|
(dot-vertex 'b #:label "B")
|
||||||
|
(dot-vertex 'c #:shape 'box)
|
||||||
|
(dot-vertex 'd #:label "D" #:shape 'box)))))
|
||||||
|
(string-append
|
||||||
|
"graph {\n"
|
||||||
|
"a;\n"
|
||||||
|
"b[label=\"B\"];\n"
|
||||||
|
"c[shape=box];\n"
|
||||||
|
"d[label=\"D\",shape=box];\n"
|
||||||
|
"}\n"))
|
||||||
|
|
||||||
|
(check-equal?
|
||||||
|
(with-output-to-string
|
||||||
|
(λ ()
|
||||||
|
(dot-graph
|
||||||
|
(λ ()
|
||||||
|
(dot-vertex 'a)
|
||||||
|
(dot-vertex 'b)
|
||||||
|
(dot-vertex 'c)
|
||||||
|
(dot-edge 'a 'b)
|
||||||
|
(dot-edge 'b 'c)
|
||||||
|
(dot-edge 'a 'c #:flip? #t)))))
|
||||||
|
(string-append
|
||||||
|
"graph {\n"
|
||||||
|
"a;\nb;\nc;\n"
|
||||||
|
"a -- b;\n"
|
||||||
|
"b -- c;\n"
|
||||||
|
"c -- a;\n"
|
||||||
|
"}\n"))
|
||||||
|
|
||||||
|
(check-equal?
|
||||||
|
(with-output-to-string
|
||||||
|
(λ ()
|
||||||
|
(dot-digraph
|
||||||
|
(λ ()
|
||||||
|
(dot-vertex 'a)
|
||||||
|
(dot-vertex 'b)
|
||||||
|
(dot-vertex 'c)
|
||||||
|
(dot-edge 'a 'b)
|
||||||
|
(dot-edge 'b 'c)
|
||||||
|
(dot-edge 'a 'c #:flip? #t)))))
|
||||||
|
(string-append
|
||||||
|
"digraph {\n"
|
||||||
|
"a;\nb;\nc;\n"
|
||||||
|
"a -> b;\n"
|
||||||
|
"b -> c;\n"
|
||||||
|
"c -> a;\n"
|
||||||
|
"}\n"))
|
||||||
|
|
||||||
|
)
|
||||||
213
main.rkt
213
main.rkt
|
|
@ -11,9 +11,11 @@
|
||||||
"./scrape.rkt"
|
"./scrape.rkt"
|
||||||
"./database.rkt"
|
"./database.rkt"
|
||||||
"./sle.rkt"
|
"./sle.rkt"
|
||||||
|
"./dot.rkt"
|
||||||
|
|
||||||
(rename-in "./logging.rkt"
|
(rename-in "./logging.rkt"
|
||||||
[log-calc-info INFO]
|
[log-calc-info INFO]
|
||||||
|
[log-calc-error ERROR]
|
||||||
[log-calc-debug DEBUG]))
|
[log-calc-debug DEBUG]))
|
||||||
|
|
||||||
;; -----------------------------------------------------------------------------
|
;; -----------------------------------------------------------------------------
|
||||||
|
|
@ -30,7 +32,7 @@
|
||||||
|
|
||||||
(define (recipe-filter* r)
|
(define (recipe-filter* r)
|
||||||
(and (recipe-info-building r)
|
(and (recipe-info-building r)
|
||||||
(not (recipe-info-alternate? r))
|
;(not (recipe-info-alternate? r))
|
||||||
(for/and ([i (in-hash-keys (recipe-info-ratios r))])
|
(for/and ([i (in-hash-keys (recipe-info-ratios r))])
|
||||||
(query-item i))))
|
(query-item i))))
|
||||||
|
|
||||||
|
|
@ -44,19 +46,17 @@
|
||||||
;(unless allow? (DEBUG "recipe filtered out: ~s" (recipe-info-name i)))
|
;(unless allow? (DEBUG "recipe filtered out: ~s" (recipe-info-name i)))
|
||||||
allow?)
|
allow?)
|
||||||
|
|
||||||
(define input-file-path (make-parameter "problem.rktd"))
|
(define (main #:input-file in-file
|
||||||
(define print-dot? (make-parameter #f))
|
#:print-dot? dot?)
|
||||||
|
(define problem (with-input-from-file in-file simple-read-and-eval))
|
||||||
(define (main)
|
(define input-names (hash-ref problem 'inputs '()))
|
||||||
(define problem (with-input-from-file (input-file-path) simple-read-and-eval))
|
(define output-names/qty (hash-ref problem 'outputs hasheq))
|
||||||
(define inputs (hash-ref problem 'inputs '()))
|
(define recipe-names (hash-ref problem 'recipes '()))
|
||||||
(define outputs (hash-ref problem 'outputs hasheq))
|
|
||||||
(define recipes (hash-ref problem 'recipes '()))
|
|
||||||
(define period (hash-ref problem 'period 60))
|
(define period (hash-ref problem 'period 60))
|
||||||
|
|
||||||
(DEBUG "inputs: ~s" inputs)
|
(DEBUG "inputs: ~s" input-names)
|
||||||
(DEBUG "outputs: ~s" outputs)
|
(DEBUG "outputs: ~s" output-names/qty)
|
||||||
(DEBUG "recipes: ~s" recipes)
|
(DEBUG "recipes: ~s" recipe-names)
|
||||||
(DEBUG "period: ~as" period)
|
(DEBUG "period: ~as" period)
|
||||||
|
|
||||||
(current-item-database
|
(current-item-database
|
||||||
|
|
@ -76,33 +76,41 @@
|
||||||
(define item=>lhs (make-hasheq))
|
(define item=>lhs (make-hasheq))
|
||||||
(define item=>rhs (make-hasheq))
|
(define item=>rhs (make-hasheq))
|
||||||
|
|
||||||
(for ([r-name (in-list recipes)])
|
(for ([name (in-list input-names)])
|
||||||
(define r-info (query-recipe r-name))
|
(define info
|
||||||
|
(or (query-item name)
|
||||||
|
(raise-user-error (format "undefined input item: ~s" name))))
|
||||||
|
(define cn (item-info-classname info))
|
||||||
|
(DEBUG "init input: ~s (~a)" (item-info-name info) cn)
|
||||||
|
(hash-set! item=>lhs cn (lexpr 0))
|
||||||
|
(hash-set! item=>rhs cn (symbol->lexpr cn)))
|
||||||
|
|
||||||
|
(for ([(name qty) (in-hash output-names/qty)])
|
||||||
|
(define info
|
||||||
|
(or (query-item name)
|
||||||
|
(error (format "undefined output item: ~s" name))))
|
||||||
|
(define cn (item-info-classname info))
|
||||||
|
(DEBUG "init output: ~s (~a)" (item-info-name info) qty)
|
||||||
|
(hash-set! item=>lhs cn (lexpr 0))
|
||||||
|
(hash-set! item=>rhs cn (number->lexpr (/ qty period))))
|
||||||
|
|
||||||
|
(for ([r-name (in-list recipe-names)])
|
||||||
|
(define r-info
|
||||||
|
(or (query-recipe r-name)
|
||||||
|
(raise-user-error (format "undefined recipe: ~s" r-name))))
|
||||||
(define r-cn (recipe-info-classname r-info))
|
(define r-cn (recipe-info-classname r-info))
|
||||||
(DEBUG "begin recipe: ~s (~a)" (recipe-info-name r-info) r-cn)
|
(DEBUG "begin recipe: ~s (~a)" (recipe-info-name r-info) r-cn)
|
||||||
(for ([(i-cn ratio) (in-hash (recipe-info-ratios r-info))])
|
(for ([(i-cn ratio) (in-hash (recipe-info-ratios r-info))])
|
||||||
(define (add e) (lexpr+ e (lexpr* ratio (symbol->lexpr r-cn))))
|
(define (add e) (lexpr+ e (lexpr* ratio (symbol->lexpr r-cn))))
|
||||||
(hash-update! item=>lhs i-cn add (lexpr 0))))
|
(hash-update! item=>lhs i-cn add (lexpr 0))))
|
||||||
|
|
||||||
(for ([name (in-list inputs)])
|
|
||||||
(define info (query-item name))
|
|
||||||
(define cn (item-info-classname info))
|
|
||||||
(DEBUG "init input: ~s (~a)" (item-info-name info) cn)
|
|
||||||
(hash-set! item=>rhs cn (symbol->lexpr cn)))
|
|
||||||
|
|
||||||
(for ([(name qty) (in-hash outputs)])
|
|
||||||
(define info (query-item name))
|
|
||||||
(define cn (item-info-classname info))
|
|
||||||
(DEBUG "init output: ~s (~a)" (item-info-name info) qty)
|
|
||||||
(hash-set! item=>rhs cn (number->lexpr (/ qty period))))
|
|
||||||
|
|
||||||
(define sle (make-sle))
|
(define sle (make-sle))
|
||||||
(for ([cn (in-hash-keys item=>lhs)])
|
(for ([cn (in-hash-keys item=>lhs)])
|
||||||
(define lhs (hash-ref item=>lhs cn))
|
(define lhs (hash-ref item=>lhs cn))
|
||||||
(define rhs (hash-ref item=>rhs cn (lexpr 0)))
|
(define rhs (hash-ref item=>rhs cn (lexpr 0)))
|
||||||
(sle-equal! sle lhs rhs))
|
(sle-equal! sle lhs rhs))
|
||||||
|
|
||||||
(define (format-amt x) (~r x #:sign '++ #:precision 2))
|
(define (format-amt x) (~r x #:sign '++ #:precision 1))
|
||||||
(define (format-qty n) (string-append (~r n #:precision 2) "x"))
|
(define (format-qty n) (string-append (~r n #:precision 2) "x"))
|
||||||
|
|
||||||
(define (item-amt-string i)
|
(define (item-amt-string i)
|
||||||
|
|
@ -117,75 +125,69 @@
|
||||||
(parameterize ([current-lexpr-number->string format-qty])
|
(parameterize ([current-lexpr-number->string format-qty])
|
||||||
(lexpr->string value)))
|
(lexpr->string value)))
|
||||||
|
|
||||||
|
(define items
|
||||||
|
(sort (map query-item (hash-keys item=>lhs))
|
||||||
|
string<? #:key item-info-name))
|
||||||
|
(define recipes
|
||||||
|
(sort (map query-recipe recipe-names)
|
||||||
|
string<? #:key recipe-info-name))
|
||||||
|
|
||||||
(INFO "Net items:")
|
(INFO "Net items:")
|
||||||
(let ([items (sort (map query-item (hash-keys item=>lhs))
|
(for ([i (in-list items)])
|
||||||
string<? #:key item-info-name)])
|
(INFO "~a ~s"
|
||||||
(for ([info (in-list items)])
|
(~a (item-amt-string i) #:min-width 5 #:align 'right)
|
||||||
(INFO "~a ~s"
|
(item-info-name i)))
|
||||||
(~a (item-amt-string info) #:min-width 5 #:align 'right)
|
|
||||||
(item-info-name info))))
|
|
||||||
|
|
||||||
(INFO "Recipes:")
|
(INFO "Recipes:")
|
||||||
(for ([name (in-list recipes)])
|
(for ([r (in-list recipes)])
|
||||||
(define info (query-recipe name))
|
|
||||||
(INFO "~a ~s"
|
(INFO "~a ~s"
|
||||||
(~a (recipe-qty-string info) #:min-width 5 #:align 'right)
|
(~a (recipe-qty-string r) #:min-width 5 #:align 'right)
|
||||||
(recipe-info-name info)))
|
(recipe-info-name r)))
|
||||||
|
|
||||||
|
(when dot?
|
||||||
|
(define item=>recipes (make-hasheq))
|
||||||
|
(for* ([r (in-list recipes)]
|
||||||
|
[i-cn (in-hash-keys (recipe-info-ratios r))])
|
||||||
|
(define (add rs) (cons r rs))
|
||||||
|
(hash-update! item=>recipes (query-item i-cn) add '()))
|
||||||
|
|
||||||
|
(define item=>kind (make-hasheq))
|
||||||
|
(for ([n (in-list input-names)]) (hash-set! item=>kind (query-item n) 'input))
|
||||||
|
(for ([n (in-hash-keys output-names/qty)]) (hash-set! item=>kind (query-item n) 'output))
|
||||||
|
|
||||||
(when (print-dot?)
|
|
||||||
(DEBUG "generating DOT graph")
|
(DEBUG "generating DOT graph")
|
||||||
(let ([recipes (map query-recipe recipes)]
|
(dot-digraph
|
||||||
[inputs (map query-item inputs)]
|
(λ ()
|
||||||
[outputs (map query-item (hash-keys outputs))])
|
(for ([r (in-list recipes)])
|
||||||
(define item=>recipes (make-hasheq))
|
(dot-vertex (recipe-info-classname r)
|
||||||
|
#:label (format "~a\n~a" (recipe-info-name r)
|
||||||
|
(recipe-qty-string r))
|
||||||
|
#:shape 'box))
|
||||||
|
|
||||||
(for* ([r (in-list recipes)]
|
(for ([i (in-list items)] #:when (hash-has-key? item=>kind i))
|
||||||
[i-cn (in-hash-keys (recipe-info-ratios r))])
|
(dot-vertex (item-info-classname i)
|
||||||
(define (add rs) (cons r rs))
|
#:label (format "~a\n~a"
|
||||||
(hash-update! item=>recipes i-cn add '()))
|
(item-info-name i)
|
||||||
|
(item-amt-string i))))
|
||||||
|
|
||||||
(printf "digraph {\n")
|
(for ([i (in-list items)])
|
||||||
|
(define i-cn (item-info-classname i))
|
||||||
(for ([i (in-list (append inputs outputs))])
|
(define rs (hash-ref item=>recipes i '()))
|
||||||
(define i-cn (item-info-classname i))
|
(match (hash-ref item=>kind i 'recipe)
|
||||||
(define label (format "~a\n~a" (item-info-name i) (item-amt-string i)))
|
[(or 'input 'output)
|
||||||
(printf "~a [" i-cn)
|
(for ([r (in-list rs)])
|
||||||
(printf "label=~s" label)
|
(define r-cn (recipe-info-classname r))
|
||||||
(printf "];\n"))
|
(define v (hash-ref (recipe-info-ratios r) i-cn))
|
||||||
|
(dot-edge r-cn i-cn #:flip? (negative? v)))]
|
||||||
(for ([r (in-list recipes)])
|
['recipe
|
||||||
(define r-cn (recipe-info-classname r))
|
(for ([r12 (in-combinations rs 2)])
|
||||||
(define label (format "~a\n~a" (recipe-info-name r) (recipe-qty-string r)))
|
(match-define (list r1 r2) r12)
|
||||||
(printf "~a [" r-cn)
|
(define r1-cn (recipe-info-classname r1))
|
||||||
(printf "shape=box,label=~s" label)
|
(define r2-cn (recipe-info-classname r2))
|
||||||
(printf "];\n"))
|
(define v1 (hash-ref (recipe-info-ratios r1) i-cn))
|
||||||
|
(define v2 (hash-ref (recipe-info-ratios r2) i-cn))
|
||||||
(for* ([(i-cn rs) (in-hash item=>recipes)]
|
(unless (eq? (negative? v1) (negative? v2))
|
||||||
[r12 (in-combinations rs 2)]
|
(dot-edge r1-cn r2-cn #:flip? (negative? v1))))])))))
|
||||||
#:do [(define r1 (car r12))
|
|
||||||
(define r2 (cadr r12))
|
|
||||||
(define v1 (hash-ref (recipe-info-ratios r1) i-cn))
|
|
||||||
(define v2 (hash-ref (recipe-info-ratios r2) i-cn))]
|
|
||||||
; signs differ
|
|
||||||
#:when (negative? (* v1 v2)))
|
|
||||||
(define cn1 (recipe-info-classname r1))
|
|
||||||
(define cn2 (recipe-info-classname r2))
|
|
||||||
(if (negative? v1)
|
|
||||||
; r1 is sink, r2 is source
|
|
||||||
(printf "~a -> ~a;\n" cn2 cn1)
|
|
||||||
; r1 is source, r2 is sink
|
|
||||||
(printf "~a -> ~a;\n" cn1 cn2)))
|
|
||||||
|
|
||||||
(for* ([i (in-list (append inputs outputs))]
|
|
||||||
#:do [(define i-cn (item-info-classname i))]
|
|
||||||
[r (in-list (hash-ref item=>recipes i-cn '()))])
|
|
||||||
(define r-cn (recipe-info-classname r))
|
|
||||||
(define v (hash-ref (recipe-info-ratios r) i-cn))
|
|
||||||
(if (negative? v)
|
|
||||||
(printf "~a -> ~a;\n" i-cn r-cn)
|
|
||||||
(printf "~a -> ~a;\n" r-cn i-cn)))
|
|
||||||
|
|
||||||
(printf "}\n")))
|
|
||||||
|
|
||||||
(void))
|
(void))
|
||||||
|
|
||||||
|
|
@ -206,8 +208,6 @@
|
||||||
(module+ main
|
(module+ main
|
||||||
(require racket/cmdline)
|
(require racket/cmdline)
|
||||||
|
|
||||||
(define verbose (make-parameter 0))
|
|
||||||
|
|
||||||
(define (time-string)
|
(define (time-string)
|
||||||
(parameterize ([date-display-format 'iso-8601])
|
(parameterize ([date-display-format 'iso-8601])
|
||||||
(date->string (current-date) #t)))
|
(date->string (current-date) #t)))
|
||||||
|
|
@ -224,22 +224,23 @@
|
||||||
[_ ""])
|
[_ ""])
|
||||||
msg))
|
msg))
|
||||||
|
|
||||||
|
(define verbose 0)
|
||||||
|
(define dot? #f)
|
||||||
|
|
||||||
(command-line
|
(command-line
|
||||||
#:multi
|
#:multi
|
||||||
[("-v" "--verbose")
|
[("-v" "--verbose") "Verbose log messages" (set! verbose (add1 verbose))]
|
||||||
"Verbose log messages"
|
|
||||||
(verbose (add1 (verbose)))]
|
|
||||||
#:once-each
|
#:once-each
|
||||||
[("--dot")
|
[("--dot") "Print DOT graph" (set! dot? #t)]
|
||||||
"Print DOT graph"
|
#:args (input-file)
|
||||||
(print-dot? #t)]
|
(with-intercepted-logging
|
||||||
#:args ([infile (input-file-path)]) (input-file-path infile))
|
print-log
|
||||||
|
(λ ()
|
||||||
(with-intercepted-logging
|
(with-handlers ([exn:fail:user? (λ (e) (ERROR "~a" (exn-message e)))])
|
||||||
print-log
|
(main #:input-file input-file
|
||||||
main
|
#:print-dot? dot?)))
|
||||||
(cond
|
(cond
|
||||||
[(= (verbose) 2) 'debug]
|
[(> verbose 1) 'debug]
|
||||||
[(= (verbose) 1) 'info]
|
[(> verbose 0) 'info]
|
||||||
[else 'warning])
|
[else 'warning])
|
||||||
#:logger calc-logger))
|
#:logger calc-logger)))
|
||||||
|
|
|
||||||
46
problem.rktd
46
problem.rktd
|
|
@ -1,19 +1,33 @@
|
||||||
(define recipes
|
|
||||||
(list "supercomputer"
|
|
||||||
"computer"
|
|
||||||
"circuit board"
|
|
||||||
"ai limiter"
|
|
||||||
"high-speed connector"))
|
|
||||||
|
|
||||||
(define inputs
|
(define inputs
|
||||||
(list "plastic"
|
(list
|
||||||
"cable"
|
"copper ore"
|
||||||
"quickwire"
|
"caterium ore"
|
||||||
"copper sheet"))
|
"plastic"
|
||||||
|
))
|
||||||
|
|
||||||
(define outputs
|
(define outputs
|
||||||
(hash "supercomputer" 1
|
(hash
|
||||||
;"computer" 4
|
"supercomputer" 1
|
||||||
;"circuit board" 10
|
"computer" 4
|
||||||
;"high-speed connector" 1
|
"circuit board" 10
|
||||||
))
|
;"high-speed connector" 1
|
||||||
|
))
|
||||||
|
|
||||||
|
(define recipes
|
||||||
|
(list
|
||||||
|
"caterium ingot"
|
||||||
|
"copper ingot"
|
||||||
|
|
||||||
|
;"caterium wire"
|
||||||
|
"wire"
|
||||||
|
"quickwire"
|
||||||
|
"cable"
|
||||||
|
"copper sheet"
|
||||||
|
|
||||||
|
"supercomputer"
|
||||||
|
"high-speed connector"
|
||||||
|
|
||||||
|
"computer"
|
||||||
|
"circuit board"
|
||||||
|
"ai limiter"
|
||||||
|
))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue