about summary refs log tree commit diff stats
path: root/js/games/nluqo.github.io/~bh/downloads/csls-programs/student
diff options
context:
space:
mode:
Diffstat (limited to 'js/games/nluqo.github.io/~bh/downloads/csls-programs/student')
-rw-r--r--js/games/nluqo.github.io/~bh/downloads/csls-programs/student1181
1 files changed, 1181 insertions, 0 deletions
diff --git a/js/games/nluqo.github.io/~bh/downloads/csls-programs/student b/js/games/nluqo.github.io/~bh/downloads/csls-programs/student
new file mode 100644
index 0000000..0e3df7c
--- /dev/null
+++ b/js/games/nluqo.github.io/~bh/downloads/csls-programs/student
@@ -0,0 +1,1181 @@
+to student :prob
+say [The problem to be solved is] :prob
+make "prob map.se [depunct ?] :prob
+localmake "orgprob :prob
+student1 :prob ~
+         [[[the perimeter of ! rectangle]
+           [twice the sum of the length and width of the rectangle]]
+          [[two numbers] [one of the numbers and the other number]]
+          [[two numbers] [one number and the other number]]]
+end
+
+to student1 :prob :idioms
+local [simsen shelf aunits units wanted ans var lasteqn
+       ref eqt1 beg end idiom reply]
+make "prob idioms :prob
+if match [^ two numbers #] :prob ~
+   [make "idiom find [match (sentence "^beg first ? "#end) :orgprob] :idioms ~
+    tryidiom stop]
+while [match [^beg the the #end] :prob] [make "prob (sentence :beg "the :end)]
+say [With mandatory substitutions the problem is] :prob
+ifelse match [# @:in [[as old as] [age] [years old]] #] :prob ~
+       [ageprob] [make "simsen bracket :prob]
+lsay [The simple sentences are] :simsen
+foreach [aunits wanted ans var lasteqn ref units] [make ? []]
+make "shelf filter [not emptyp ?] map.se [senform ?] :simsen
+lsay [The equations to be solved are] :shelf
+make "units remdup :units
+if trysolve :shelf :wanted :units :aunits [print [The problem is solved.] stop]
+make "eqt1 remdup geteqns :var
+if not emptyp :eqt1 [lsay [Using the following known relationships] :eqt1]
+student2 :eqt1
+end
+
+to student2 :eqt1
+make "var remdup sentence (map.se [varterms ?] :eqt1) :var
+make "eqt1 sentence :eqt1 vartest :var
+if not emptyp :eqt1 ~
+   [if trysolve (sentence :shelf :eqt1) :wanted :units :aunits
+       [print [The problem is solved.] stop]]
+make "idiom find [match (sentence "^beg first ? "#end) :orgprob] :idioms
+if not emptyp :idiom [tryidiom stop]
+lsay [Do you know any more relationships among these variables?] :var
+make "reply readlist
+if equalp :reply [yes] [print [Tell me.] make "reply readlist]
+if equalp :reply [no] [print [] print [I can't solve this problem.] stop]
+make "reply map.se [depunct ?] :reply
+if dlm last :reply [make "reply butlast :reply]
+if not match [^beg is #end] :reply [print [I don't understand that.] stop]
+make "shelf sentence :shelf :eqt1
+student2 (list (list "equal opform :beg opform :end))
+end
+
+;; Mandatory substitutions
+
+to depunct :word
+if emptyp :word [output []]
+if equalp first :word "$ [output sentence "$ depunct butfirst :word]
+if equalp last :word "% [output sentence depunct butlast :word "percent]
+if memberp last :word [. ? |;| ,] [output sentence depunct butlast :word last :word]
+if emptyp butfirst :word [output :word]
+if equalp last2 :word "'s [output sentence depunct butlast butlast :word "s]
+output :word
+end
+
+to last2 :word
+output word (last butlast :word) (last :word)
+end
+
+to idioms :sent
+local "number
+output changes :sent ~
+    [[[the sum of] ["sum]] [[square of] ["square]] [[of] ["numof]]
+     [[how old] ["what]] [[is equal to] ["is]]
+     [[years younger than] [[less than]]] [[years older than] ["plus]]
+     [[percent less than] ["perless]] [[less than] ["lessthan]]
+     [[these] ["the]] [[more than] ["plus]]
+     [[first two numbers] [[the first number and the second number]]]
+     [[three numbers]
+      [[the first number and the second number and the third number]]]
+     [[one half] [0.5]] [[twice] [[2 times]]]
+     [[$ !number] [sentence :number "dollars]] [[consecutive to] [[1 plus]]]
+     [[larger than] ["plus]] [[per cent] ["percent]] [[how many] ["howm]]
+     [[is multiplied by] ["ismulby]] [[is divided by] ["isdivby]]
+     [[multiplied by] ["times]] [[divided by] ["divby]]]
+end
+
+to changes :sent :list
+localmake "keywords map.se [findkey first ?] :list
+output changes1 :sent :list :keywords
+end
+
+to findkey :pattern
+if equalp first :pattern "!:in [output first butfirst :pattern]
+if equalp first :pattern "?:in [output sentence (item 2 :pattern) (item 3 :pattern)]
+output first :pattern
+end
+
+to changes1 :sent :list :keywords
+if emptyp :sent [output []]
+if memberp first :sent :keywords [output changes2 :sent :list :keywords]
+output fput first :sent changes1 butfirst :sent :list :keywords
+end
+
+to changes2 :sent :list :keywords
+changes3 :list :list
+output fput first :sent changes1 butfirst :sent :list :keywords
+end
+
+to changes3 :biglist :nowlist
+if emptyp :nowlist [stop]
+if changeone first :nowlist [changes3 :biglist :biglist stop]
+changes3 :biglist butfirst :nowlist
+end
+
+to changeone :change
+local "end
+if not match (sentence first :change [#end]) :sent [output "false]
+make "sent run (sentence "sentence last :change ":end)
+output "true
+end
+
+;; Division into simple sentences
+
+to bracket :prob
+output bkt1 finddelim :prob
+end
+
+to finddelim :sent
+output finddelim1 :sent [] []
+end
+
+to finddelim1 :in :out :simples
+if emptyp :in ~
+   [ifelse emptyp :out [output :simples] [output lput (sentence :out ".) :simples]]
+if dlm first :in ~
+   [output finddelim1 (nocap butfirst :in) []
+                      (lput (sentence :out first :in) :simples)]
+output finddelim1 (butfirst :in) (sentence :out first :in) :simples
+end
+
+to nocap :words
+if emptyp :words [output []]
+if personp first :words [output :words]
+output sentence (lowercase first :words) butfirst :words
+end
+
+to bkt1 :problist
+local [first word rest]
+if emptyp :problist [output []]
+if not memberp ", first :problist ~
+   [output fput first :problist bkt1 butfirst :problist]
+if match [if ^first , !word:qword #rest] first :problist ~
+   [output bkt1 fput (sentence :first ".)
+                     fput (sentence :word :rest) butfirst :problist]
+if match [^first , and #rest] first :problist ~
+   [output fput (sentence :first ".) (bkt1 fput :rest butfirst :problist)]
+output fput first :problist bkt1 butfirst :problist
+end
+
+;; Age problems
+
+to ageprob
+local [beg end sym who num subj ages]
+while [match [^beg as old as #end] :prob] [make "prob sentence :beg :end]
+while [match [^beg years old #end] :prob] [make "prob sentence :beg :end]
+while [match [^beg will be when #end] :prob] ~
+      [make "sym gensym
+       make "prob (sentence :beg "in :sym [years . in] :sym "years :end)]
+while [match [^beg was when #end] :prob] ~
+      [make "sym gensym
+       make "prob (sentence :beg :sym [years ago .] :sym [years ago] :end)]
+while [match [^beg !who:personp will be in !num years #end] :prob] ~
+      [make "prob (sentence :beg :who [s age in] :num "years #end)]
+while [match [^beg was #end] :prob] [make "prob (sentence :beg "is :end)]
+while [match [^beg will be #end] :prob] [make "prob (sentence :beg "is :end)]
+while [match [^beg !who:personp is now #end] :prob] ~
+      [make "prob (sentence :beg :who [s age now] :end)]
+while [match [^beg !num years from now #end] :prob] ~
+      [make "prob (sentence :beg "in :num "years :end)]
+make "prob ageify :prob
+ifelse match [^ !who:personp ^end s age #] :prob ~
+       [make "subj sentence :who :end] [make "subj "someone]
+make "prob agepron :prob
+make "end :prob
+make "ages []
+while [match [^ !who:personp ^beg age #end] :end] ~
+      [push "ages (sentence "and :who :beg "age)]
+make "ages butfirst reduce "sentence remdup :ages
+while [match [^beg their ages #end] :prob] [make "prob (sentence :beg :ages :end)]
+make "simsen map [agesen ?] bracket :prob
+end
+
+to ageify :sent
+if emptyp :sent [output []]
+if not personp first :sent [output fput first :sent ageify butfirst :sent]
+catch "error [if equalp first butfirst :sent "s
+                 [output fput first :sent ageify butfirst :sent]]
+output (sentence first :sent [s age] ageify butfirst :sent)
+end
+
+to agepron :sent
+if emptyp :sent [output []]
+if not pronoun first :sent [output fput first :sent agepron butfirst :sent]
+if posspro first :sent [output (sentence :subj "s agepron butfirst :sent)]
+output (sentence :subj [s age] agepron butfirst :sent)
+end
+
+to agesen :sent
+local [when rest num]
+make "when []
+if match [in !num years #rest] :sent ~
+   [make "when sentence "pluss :num make "sent :rest]
+if match [!num years ago #rest] :sent ~
+   [make "when sentence "minuss :num make "sent :rest]
+output agewhen :sent
+end
+
+to agewhen :sent
+if emptyp :sent [output []]
+if not equalp first :sent "age [output fput first :sent agewhen butfirst :sent]
+if match [in !num years #rest] butfirst :sent ~
+   [output (sentence [age pluss] :num agewhen :rest)]
+if match [!num years ago #rest] butfirst :sent ~
+   [output (sentence [age minuss] :num agewhen :rest)]
+if equalp "now first butfirst :sent ~
+   [output sentence "age agewhen butfirst butfirst :sent]
+output (sentence "age :when agewhen butfirst :sent)
+end
+
+;; Translation from sentences into equations
+
+to senform :sent
+make "lasteqn senform1 :sent
+output :lasteqn
+end
+
+to senform1 :sent
+local [one two verb1 verb2 stuff1 stuff2 factor]
+if emptyp :sent [output []]
+if match [^ what are ^one and ^two !:dlm] :sent ~
+   [output fput (qset :one) (senform (sentence [what are] :two "?))]
+if match [^ what !:in [is are] #one !:dlm] :sent ~
+   [output (list qset :one)]
+if match [^ howm !one is #two !:dlm] :sent ~
+   [push "aunits (list :one) output (list qset :two)]
+if match [^ howm ^one do ^two have !:dlm] :sent ~
+   [output (list qset (sentence [the number of] :one :two "have))]
+if match [^ howm ^one does ^two have !:dlm] :sent ~
+   [output (list qset (sentence [the number of] :one :two "has))]
+if match [^ find ^one and #two] :sent ~
+   [output fput (qset :one) (senform sentence "find :two)]
+if match [^ find #one !:dlm] :sent [output (list qset :one)]
+make "sent filter [not article ?] :sent
+if match [^one ismulby #two] :sent ~
+   [push "ref (list "product opform :one opform :two) output []]
+if match [^one isdivby #two] :sent ~
+   [push "ref (list "quotient opform :one opform :two) output []]
+if match [^one is increased by #two] :sent ~
+   [push "ref (list "sum opform :one opform :two) output []]
+if match [^one is #two] :sent ~
+   [output (list (list "equal opform :one opform :two))]
+if match [^one !verb1:verb ^factor as many ^stuff1 as
+          ^two !verb2:verb ^stuff2 !:dlm] ~
+         :sent ~
+   [if emptyp :stuff2 [make "stuff2 :stuff1]
+    output (list (list "equal ~
+                   opform (sentence [the number of] :stuff1 :one :verb1) ~
+                   opform (sentence :factor [the number of] :stuff2 :two :verb2)))]
+if match [^one !verb1:verb !factor:numberp #stuff1 !:dlm] :sent ~
+   [output (list (list "equal ~
+                   opform (sentence [the number of] :stuff1 :one :verb1) ~
+                   opform (list :factor)))]
+say [This sentence form is not recognized:] :sent
+throw "error
+end
+
+to qset :sent
+localmake "opform opform filter [not article ?] :sent
+if not operatorp first :opform ~
+   [queue "wanted :opform queue "ans list :opform oprem :sent output []]
+localmake "gensym gensym
+queue "wanted :gensym
+queue "ans list :gensym oprem :sent
+output (list "equal :gensym opform (filter [not article ?] :sent))
+end
+
+to oprem :sent
+output map [ifelse equalp ? "numof ["of] [?]] :sent
+end
+
+to opform :expr
+local [left right op]
+if match [^left !op:op2 #right] :expr [output optest :op :left :right]
+if match [^left !op:op1 #right] :expr [output optest :op :left :right]
+if match [^left !op:op0 #right] :expr [output optest :op :left :right]
+if match [#left !:dlm] :expr [make "expr :left]
+output nmtest filter [not article ?] :expr
+end
+
+to optest :op :left :right
+output run (list (word "tst. :op) :left :right)
+end
+
+to tst.numof :left :right
+if numberp last :left [output (list "product opform :left opform :right)]
+output opform (sentence :left "of :right)
+end
+
+to tst.divby :left :right
+output (list "quotient opform :left opform :right)
+end
+
+to tst.tothepower :left :right
+output (list "expt opform :left opform :right)
+end
+
+to expt :num :pow
+if :pow < 1 [output 1]
+output :num * expt :num :pow - 1
+end
+
+to tst.per :left :right
+output (list "quotient ~
+          opform :left ~
+          opform (ifelse numberp first :right [:right] [fput 1 :right]))
+end
+
+to tst.lessthan :left :right
+output opdiff opform :right opform :left
+end
+
+to opdiff :left :right
+output (list "sum :left (list "minus :right))
+end
+
+to tst.minus :left :right
+if emptyp :left [output list "minus opform :right]
+output opdiff opform :left opform :right
+end
+
+to tst.minuss :left :right
+output tst.minus :left :right
+end
+
+to tst.sum :left :right
+local [one two three]
+if match [^one and ^two and #three] :right ~
+   [output (list "sum opform :one opform (sentence "sum :two "and :three))]
+if match [^one and #two] :right ~
+   [output (list "sum opform :one opform :two)]
+say [sum used wrong:] :right
+throw "error
+end
+
+to tst.squared :left :right
+output list "square opform :left
+end
+
+to tst.difference :left :right
+local [one two]
+if match [between ^one and #two] :right [output opdiff opform :one opform :two]
+say [Incorrect use of difference:] :right
+throw "error
+end
+
+to tst.plus :left :right
+output (list "sum opform :left opform :right)
+end
+
+to tst.pluss :left :right
+output tst.plus :left :right
+end
+
+to square :x
+output :x * :x
+end
+
+to tst.square :left :right
+output list "square opform :right
+end
+
+to tst.percent :left :right
+if not numberp last :left ~
+   [say [Incorrect use of percent:] :left throw "error]
+output opform (sentence butlast :left ((last :left) / 100) :right)
+end
+
+to tst.perless :left :right
+if not numberp last :left ~
+   [say [Incorrect use of percent:] :left throw "error]
+output (list "product ~
+          (opform sentence butlast :left ((100 - (last :left)) / 100)) ~
+          opform :right)
+end
+
+to tst.times :left :right
+if emptyp :left [say [Incorrect use of times:] :right throw "error]
+output (list "product opform :left opform :right)
+end
+
+to nmtest :expr
+if match [& !:numberp #] :expr [say [argument error:] :expr throw "error]
+if and (equalp first :expr 1) (1 < count :expr) ~
+   [make "expr (sentence 1 plural (first butfirst :expr) (butfirst butfirst :expr))]
+if and (numberp first :expr) (1 < count :expr) ~
+   [push "units (list first butfirst :expr) ~
+    output (list "product (first :expr) (opform butfirst :expr))]
+if numberp first :expr [output first :expr]
+if memberp "this :expr [output this :expr]
+if not memberp :expr :var [push "var :expr]
+output :expr
+end
+
+to this :expr
+if not emptyp :ref [output pop "ref]
+if not emptyp :lasteqn [output first butfirst last :lasteqn]
+if equalp first :expr "this [make "expr butfirst :expr]
+push "var :expr
+output :expr
+end
+
+;; Solving the equations
+
+to trysolve :shelf :wanted :units :aunits
+local "solution
+make "solution solve :wanted :shelf (ifelse emptyp :aunits [:units] [:aunits])
+output pranswers :ans :solution
+end
+
+to solve :wanted :eqt :terms
+output solve.reduce solver :wanted :terms [] [] "insufficient
+end
+
+to solve.reduce :soln
+if emptyp :soln [output []]
+if wordp :soln [output :soln]
+if emptyp butfirst :soln [output :soln]
+local "part
+make "part solve.reduce butfirst :soln
+output fput (list (first first :soln) (subord last first :soln :part)) :part
+end
+
+to solver :wanted :terms :alis :failed :err
+local [one result restwant]
+if emptyp :wanted [output :err]
+make "one solve1 (first :wanted) ~
+                 (sentence butfirst :wanted :failed :terms) ~
+                 :alis :eqt [] "insufficient
+if wordp :one ~
+   [output solver (butfirst :wanted) :terms :alis (fput first :wanted :failed) :one]
+make "restwant (sentence :failed butfirst :wanted)
+if emptyp :restwant [output :one]
+make "result solver :restwant :terms :one [] "insufficient
+if listp :result [output :result]
+output solver (butfirst :wanted) :terms :alis (fput first :wanted :failed) :one
+end
+
+to solve1 :x :terms :alis :eqns :failed :err
+local [thiseq vars extras xterms others result]
+if emptyp :eqns [output :err]
+make "thiseq subord (first :eqns) :alis
+make "vars varterms :thiseq
+if not memberp :x :vars ~
+   [output solve1 :x :terms :alis (butfirst :eqns) (fput first :eqns :failed) :err]
+make "xterms fput :x :terms
+make "extras setminus :vars :xterms
+make "eqt remove (first :eqns) :eqt
+if not emptyp :extras ~
+   [make "others solver :extras :xterms :alis [] "insufficient
+    ifelse wordp :others
+           [make "eqt sentence :failed :eqns
+            output solve1 :x :terms :alis (butfirst :eqns)
+                      (fput first :eqns :failed) :others]
+           [make "alis :others
+            make "thiseq subord (first :eqns) :alis]]
+make "result solveq :x :thiseq
+if listp :result [output lput :result :alis]
+make "eqt sentence :failed :eqns
+output solve1 :x :terms :alis (butfirst :eqns) (fput first :eqns :failed) :result
+end
+
+to solveq :var :eqn
+local [left right]
+make "left first butfirst :eqn
+ifelse occvar :var :left ~
+   [make "right last :eqn] [make "right :left make "left last :eqn]
+output solveq1 :left :right "true
+end
+
+to solveq1 :left :right :bothtest
+if :bothtest [if occvar :var :right [output solveqboth :left :right]]
+if equalp :left :var [output list :var :right]
+if wordp :left [output "unsolvable]
+local "oper
+make "oper first :left
+if memberp :oper [sum product minus quotient] [output run (list word "solveq. :oper)]
+output "unsolvable
+end
+
+to solveqboth :left :right
+if not equalp first :right "sum [output solveq1 (subterm :left :right) 0 "false]
+output solveq.rplus :left butfirst :right []
+end
+
+to solveq.rplus :left :right :newright
+if emptyp :right [output solveq1 :left (simone "sum :newright) "false]
+if occvar :var first :right ~
+   [output solveq.rplus (subterm :left first :right) butfirst :right :newright]
+output solveq.rplus :left butfirst :right (fput first :right :newright)
+end
+
+to solveq.sum
+if emptyp butfirst butfirst :left [output solveq1 first butfirst :left :right "true]
+output solveq.sum1 butfirst :left :right []
+end
+
+to solveq.sum1 :left :right :newleft
+if emptyp :left [output solveq.sum2]
+if occvar :var first :left ~
+   [output solveq.sum1 butfirst :left :right fput first :left :newleft]
+output solveq.sum1 butfirst :left (subterm :right first :left) :newleft
+end
+
+to solveq.sum2
+if emptyp butfirst :newleft [output solveq1 first :newleft :right "true]
+localmake "factor factor :newleft :var
+if equalp first :factor "unknown [output "unsolvable]
+if equalp last :factor 0 [output "unsolvable]
+output solveq1 first :factor (divterm :right last :factor) "true
+end
+
+to solveq.minus
+output solveq1 (first butfirst :left) (minusin :right) "false
+end
+
+to solveq.product
+output solveq.product1 :left :right
+end
+
+to solveq.product1 :left :right
+if emptyp butfirst butfirst :left [output solveq1 (first butfirst :left) :right "true]
+if not occvar :var first butfirst :left ~
+   [output solveq.product1 (fput "product butfirst butfirst :left)
+                           (divterm :right first butfirst :left)]
+localmake "rest simone "product butfirst butfirst :left
+if occvar :var :rest [output "unsolvable]
+output solveq1 (first butfirst :left) (divterm :right :rest) "false
+end
+
+to solveq.quotient
+if occvar :var first butfirst :left ~
+   [output solveq1 (first butfirst :left) (simtimes list :right last :left) "true]
+output solveq1 (simtimes list :right last :left) (first butfirst :left) "true
+end
+
+to denom :fract :addends
+make "addends simplus :addends
+localmake "den last :fract
+if not equalp first :addends "quotient ~
+   [output simdiv list (simone "sum
+                               (remop "sum list (distribtimes (list :addends) :den)
+                                                first butfirst :fract))
+                       :den]
+if equalp :den last :addends ~
+   [output simdiv (simplus list (first butfirst :fract) (first butfirst :addends))
+                  :den]
+localmake "lowterms simdiv list :den last :addends
+output simdiv list (simplus (simtimes list first butfirst :fract last :lowterms)
+                            (simtimes list first butfirst :addends
+                                           first butfirst :lowterms)) ~
+                   (simtimes list first butfirst :lowterms last :addends)
+end
+
+to distribtimes :trms :multiplier
+output simplus map [simtimes (list ? :multiplier)] :trms
+end
+
+to distribx :expr
+local [oper args]
+if emptyp :expr [output :expr]
+make "oper first :expr
+if not operatorp :oper [output :expr]
+make "args map [distribx ?] butfirst :expr
+if reduce "and map [numberp ?] :args [output run (sentence [(] :oper :args [)])]
+if equalp :oper "sum [output simplus :args]
+if equalp :oper "minus [output minusin first :args]
+if equalp :oper "product [output simtimes :args]
+if equalp :oper "quotient [output simdiv :args]
+output fput :oper :args
+end
+
+to divterm :dividend :divisor
+if equalp :dividend 0 [output 0]
+output simdiv list :dividend :divisor
+end
+
+to factor :exprs :var
+local "trms
+make "trms map [factor1 :var ?] :exprs
+if memberp "unknown :trms [output fput "unknown :exprs]
+output list :var simplus :trms
+end
+
+to factor1 :var :expr
+localmake "negvar minusin :var
+if equalp :var :expr [output 1]
+if equalp :negvar :expr [output -1]
+if emptyp :expr [output "unknown]
+if equalp first :expr "product [output factor2 butfirst :expr]
+if not equalp first :expr "quotient [output "unknown]
+localmake "dividend first butfirst :expr
+if equalp :var :dividend [output (list "quotient 1 last :expr)]
+if not equalp first :dividend "product [output "unknown]
+localmake "result factor2 butfirst :dividend
+if equalp :result "unknown [output "unknown]
+output (list "quotient :result last :expr)
+end
+
+to factor2 :trms
+if memberp :var :trms [output simone "product (remove :var :trms)]
+if memberp :negvar :trms [output minusin simone "product (remove :negvar :trms)]
+output "unknown
+end
+
+to maybeadd :num :rest
+if equalp :num 0 [output :rest]
+output fput :num :rest
+end
+
+to maybemul :num :rest
+if equalp :num 1 [output :rest]
+output fput :num :rest
+end
+
+to minusin :expr
+if emptyp :expr [output -1]
+if equalp first :expr "sum [output fput "sum map [minusin ?] butfirst :expr]
+if equalp first :expr "minus [output last :expr]
+if memberp first :expr [product quotient] ~
+   [output fput first :expr
+                (fput (minusin first butfirst :expr) butfirst butfirst :expr)]
+if numberp :expr [output minus :expr]
+output list "minus :expr
+end
+
+to occvar :var :expr
+if emptyp :expr [output "false]
+if wordp :expr [output equalp :var :expr]
+if operatorp first :expr [output not emptyp find [occvar :var ?] butfirst :expr]
+output equalp :var :expr
+end
+
+to remfactor :num :den
+foreach butfirst :num [remfactor1 ?]
+output (list "quotient (simone "product butfirst :num) (simone "product butfirst :den))
+end
+
+to remfactor1 :expr
+local "neg
+if memberp :expr :den ~
+   [make "num remove :expr :num  make "den remove :expr :den  stop]
+make "neg minusin :expr
+if not memberp :neg :den [stop]
+make "num remove :expr :num
+make "den minusin remove :neg :den
+end
+
+to remop :oper :exprs
+output map.se [ifelse equalp first ? :oper [butfirst ?] [(list ?)]] :exprs
+end
+
+to simdiv :list
+local [num den numop denop]
+make "num first :list
+make "den last :list
+if equalp :num :den [output 1]
+if numberp :den [output simtimes (list (quotient 1 :den) :num)]
+make "numop first :num
+make "denop first :den
+if equalp :numop "quotient ~
+   [output simdiv list (first butfirst :num) (simtimes list last :num :den)]
+if equalp :denop "quotient ~
+   [output simdiv list (simtimes list :num last :den) (first butfirst :den)]
+if and equalp :numop "product equalp :denop "product [output remfactor :num :den]
+if and equalp :numop "product memberp :den :num [output remove :den :num]
+output fput "quotient :list
+end
+
+to simone :oper :trms
+if emptyp :trms [output ifelse equalp :oper "product [1] [0]]
+if emptyp butfirst :trms [output first :trms]
+output fput :oper :trms
+end
+
+to simplus :exprs
+make "exprs remop "sum :exprs
+localmake "factor [unknown]
+catch "simplus ~
+      [foreach :terms ~
+               [make "factor (factor :exprs ?) ~
+                if not equalp first :factor "unknown [throw "simplus]]]
+if not equalp first :factor "unknown [output fput "product remop "product :factor]
+localmake "nums 0
+localmake "nonnums []
+localmake "quick []
+catch "simplus [simplus1 :exprs]
+if not emptyp :quick [output :quick]
+if not equalp :nums 0 [push "nonnums :nums]
+output simone "sum :nonnums
+end
+
+to simplus1 :exprs
+if emptyp :exprs [stop]
+simplus2 first :exprs
+simplus1 butfirst :exprs
+end
+
+to simplus2 :pos
+local "neg
+make "neg minusin :pos
+if numberp :pos [make "nums sum :pos :nums stop]
+if memberp :neg butfirst :exprs [make "exprs remove :neg :exprs stop]
+if equalp first :pos "quotient ~
+   [make "quick (denom :pos (maybeadd :nums sentence :nonnums butfirst :exprs)) ~
+    throw "simplus]
+push "nonnums :pos
+end
+
+to simtimes :exprs
+local [nums nonnums quick]
+make "nums 1
+make "nonnums []
+make "quick []
+catch "simtimes [foreach remop "product :exprs [simtimes1 ?]]
+if not emptyp :quick [output :quick]
+if equalp :nums 0 [output 0]
+if not equalp :nums 1 [push "nonnums :nums]
+output simone "product :nonnums
+end
+
+to simtimes1 :expr
+if equalp :expr 0 [make "nums 0 throw "simtimes]
+if numberp :expr [make "nums product :expr :nums stop]
+if equalp first :expr "sum ~
+   [make "quick distribtimes (butfirst :expr)
+                             (simone "product maybemul :nums sentence :nonnums ?rest)
+    throw "simtimes]
+if equalp first :expr "quotient ~
+   [make "quick
+          simdiv (list (simtimes (list (first butfirst :expr)
+                                       (simone "product
+                                               maybemul :nums
+                                                        sentence :nonnums ?rest)))
+                       (last :expr))
+    throw "simtimes]
+push "nonnums :expr
+end
+
+to subord :expr :alist
+output distribx subord1 :expr :alist
+end
+
+to subord1 :expr :alist
+if emptyp :alist [output :expr]
+output subord (substop (last first :alist) (first first :alist) :expr) ~
+              (butfirst :alist)
+end
+
+to substop :val :var :expr
+if emptyp :expr [output []]
+if equalp :expr :var [output :val]
+if not operatorp first :expr [output :expr]
+output fput first :expr map [substop :val :var ?] butfirst :expr
+end
+
+to subterm :minuend :subtrahend
+if equalp :minuend 0 [output minusin :subtrahend]
+if equalp :minuend :subtrahend [output 0]
+output simplus (list :minuend minusin :subtrahend)
+end
+
+to varterms :expr
+if emptyp :expr [output []]
+if numberp :expr [output []]
+if wordp :expr [output (list :expr)]
+if operatorp first :expr [output map.se [varterms ?] butfirst :expr]
+output (list :expr)
+end
+
+;; Printing the solutions
+
+to pranswers :ans :solution
+print []
+if equalp :solution "unsolvable ~
+   [print [Unable to solve this set of equations.] output "false]
+if equalp :solution "insufficient ~
+   [print [The equations were insufficient to find a solution.] output "false]
+localmake "gotall "true
+foreach :ans [if prans ? :solution [make "gotall "false]]
+if not :gotall [print [] print [Unable to solve this set of equations.]]
+output :gotall
+end
+
+to prans :ans :solution
+localmake "result find [equalp first ? first :ans] :solution
+if emptyp :result [output "true]
+print (sentence cap last :ans "is unitstring last :result)
+print []
+output "false
+end
+
+to unitstring :expr
+if numberp :expr [output roundoff :expr]
+if equalp first :expr "product ~
+   [output sentence (unitstring first butfirst :expr)
+                    (reduce "sentence butfirst butfirst :expr)]
+if (and (listp :expr)
+         (not numberp first :expr)
+         (not operatorp first :expr)) ~
+   [output (sentence 1 (singular first :expr) (butfirst :expr))]
+output :expr
+end
+
+to roundoff :num
+if (abs (:num - round :num)) < 0.0001 [output round :num]
+output :num
+end
+
+to abs :num
+output ifelse (:num < 0) [-:num] [:num]
+end
+
+;; Using known relationships
+
+to geteqns :vars
+output map.se [gprop varkey ? "eqns] :vars
+end
+
+to varkey :var
+local "word
+if match [number of !word #] :var [output :word]
+output first :var
+end
+
+;; Assuming equality of similar variables
+
+to vartest :vars
+if emptyp :vars [output []]
+local [var beg end]
+make "var first :vars
+output (sentence (ifelse match [^beg !:pronoun #end] :var
+                         [vartest1 :var (sentence :beg "& :end) butfirst :vars]
+                         [[]])
+                 (vartest1 :var (sentence "# :var "#) butfirst :vars)
+                 (vartest butfirst :vars))
+end
+
+to vartest1 :target :pat :vars
+output map [varequal :target ?] filter [match :pat ?] :vars
+end
+
+to varequal :target :var
+print []
+print [Assuming that]
+print (sentence (list :target) [is equal to] (list :var))
+output (list "equal :target :var)
+end
+
+;; Optional substitutions
+
+to tryidiom
+make "prob (sentence :beg last :idiom :end)
+while [match (sentence "^beg first :idiom "#end) :prob] ~
+      [make "prob (sentence :beg last :idiom :end)]
+say [The problem with an idiomatic substitution is] :prob
+student1 :prob (remove :idiom :idioms)
+end
+
+;; Utility procedures
+
+to qword :word
+output memberp :word [find what howm how]
+end
+
+to dlm :word
+output memberp :word [. ? |;|]
+end
+
+to article :word
+output memberp :word [a an the]
+end
+
+to verb :word
+output memberp :word [have has get gets weigh weighs]
+end
+
+to personp :word
+output memberp :word [Mary Ann Bill Tom Sally Frank father uncle]
+end
+
+to pronoun :word
+output memberp :word [he she it him her they them his her its]
+end
+
+to posspro :word
+output memberp :word [his her its]
+end
+
+to op0 :word
+output memberp :word [pluss minuss squared tothepower per sum difference numof]
+end
+
+to op1 :word
+output memberp :word [times divby square]
+end
+
+to op2 :word
+output memberp :word [plus minus lessthan percent perless]
+end
+
+to operatorp :word
+output memberp :word [sum minus product quotient expt square equal]
+end
+
+to plural :word
+localmake "plural gprop :word "plural
+if not emptyp :plural [output :plural]
+if not emptyp gprop :word "sing [output :word]
+if equalp last :word "s [output :word]
+output word :word "s
+end
+
+to singular :word
+localmake "sing gprop :word "sing
+if not emptyp :sing [output :sing]
+if not emptyp gprop :word "plural [output :word]
+if equalp last :word "s [output butlast :word]
+output :word
+end
+
+to setminus :big :little
+output filter [not memberp ? :little] :big
+end
+
+to say :herald :text
+print []
+print :herald
+print []
+print :text
+print []
+end
+
+to lsay :herald :text
+print []
+print :herald
+print []
+foreach :text [print cap ? print []]
+end
+
+to cap :sent
+if emptyp :sent [output []]
+output sentence (word uppercase first first :sent butfirst first :sent) ~
+                butfirst :sent
+end
+
+;; The pattern matcher
+
+to match :pat :sen
+if prematch :pat :sen [output rmatch :pat :sen]
+output "false
+end
+
+to prematch :pat :sen
+if emptyp :pat [output "true]
+if listp first :pat [output prematch butfirst :pat :sen]
+if memberp first first :pat [! @ # ^ & ?] [output prematch butfirst :pat :sen]
+if emptyp :sen [output "false]
+localmake "rest member first :pat :sen
+if not emptyp :rest [output prematch butfirst :pat :rest]
+output "false
+end
+
+to rmatch :pat :sen
+local [special.var special.pred special.buffer in.list]
+if or wordp :pat wordp :sen [output "false]
+if emptyp :pat [output emptyp :sen]
+if listp first :pat [output special fput "!: :pat :sen]
+if memberp first first :pat [? # ! & @ ^] [output special :pat :sen]
+if emptyp :sen [output "false]
+if equalp first :pat first :sen [output rmatch butfirst :pat butfirst :sen]
+output "false
+end
+
+to special :pat :sen
+set.special parse.special butfirst first :pat "
+output run word "match first first :pat
+end
+
+to parse.special :word :var
+if emptyp :word [output list :var "always]
+if equalp first :word ": [output list :var butfirst :word]
+output parse.special butfirst :word word :var first :word
+end
+
+to set.special :list
+make "special.var first :list
+make "special.pred last :list
+if emptyp :special.var [make "special.var "special.buffer]
+if memberp :special.pred [in anyof] [set.in]
+if not emptyp :special.pred [stop]
+make "special.pred first butfirst :pat
+make "pat fput first :pat butfirst butfirst :pat
+end
+
+to set.in
+make "in.list first butfirst :pat
+make "pat fput first :pat butfirst butfirst :pat
+end
+
+to match!
+if emptyp :sen [output "false]
+if not try.pred [output "false]
+make :special.var first :sen
+output rmatch butfirst :pat butfirst :sen
+end
+
+to match?
+make :special.var []
+if emptyp :sen [output rmatch butfirst :pat :sen]
+if not try.pred [output rmatch butfirst :pat :sen]
+make :special.var first :sen
+if rmatch butfirst :pat butfirst :sen [output "true]
+make :special.var []
+output rmatch butfirst :pat :sen
+end
+
+to match#
+make :special.var []
+output #test #gather :sen
+end
+
+to #gather :sen
+if emptyp :sen [output :sen]
+if not try.pred [output :sen]
+make :special.var lput first :sen thing :special.var
+output #gather butfirst :sen
+end
+
+to #test :sen
+if rmatch butfirst :pat :sen [output "true]
+if emptyp thing :special.var [output "false]
+output #test2 fput last thing :special.var :sen
+end
+
+to #test2 :sen
+make :special.var butlast thing :special.var
+output #test :sen
+end
+
+to match&
+output &test match#
+end
+
+to &test :tf
+if emptyp thing :special.var [output "false]
+output :tf
+end
+
+to match^
+make :special.var []
+output ^test :sen
+end
+
+to ^test :sen
+if rmatch butfirst :pat :sen [output "true]
+if emptyp :sen [output "false]
+if not try.pred [output "false]
+make :special.var lput first :sen thing :special.var
+output ^test butfirst :sen
+end
+
+to match@
+make :special.var :sen
+output @test []
+end
+
+to @test :sen
+if @try.pred [if rmatch butfirst :pat :sen [output "true]]
+if emptyp thing :special.var [output "false]
+output @test2 fput last thing :special.var :sen
+end
+
+to @test2 :sen
+make :special.var butlast thing :special.var
+output @test :sen
+end
+
+to try.pred
+if listp :special.pred [output rmatch :special.pred first :sen]
+output run list :special.pred quoted first :sen
+end
+
+to quoted :thing
+if listp :thing [output :thing]
+output word "" :thing
+end
+
+to @try.pred
+if listp :special.pred [output rmatch :special.pred thing :special.var]
+output run list :special.pred thing :special.var
+end
+
+to always :x
+output "true
+end
+
+to in :word
+output memberp :word :in.list
+end
+
+to anyof :sen
+output anyof1 :sen :in.list
+end
+
+to anyof1 :sen :pats
+if emptyp :pats [output "false]
+if rmatch first :pats :sen [output "true]
+output anyof1 :sen butfirst :pats
+end
+
+;; Sample word problems
+
+make "ann [Mary is twice as old as Ann was when Mary was as old as Ann is now.
+  If Mary is 24 years old, how old is Ann?]
+make "guns [The number of soldiers the Russians have is
+  one half of the number of guns they have. They have 7000 guns.
+  How many soldiers do they have?]
+make "jet [The distance from New York to Los Angeles is 3000 miles.
+  If the average speed of a jet plane is 600 miles per hour,
+  find the time it takes to travel from New York to Los Angeles by jet.]
+make "nums [A number is multiplied by 6 . This product is increased by 44 .
+  This result is 68 . Find the number.]
+make "radio [The price of a radio is $69.70.
+  If this price is 15 percent less than the marked price, find the marked price.]
+make "sally [The sum of Sally's share of some money and Frank's share is $4.50.
+  Sally's share is twice Frank's. Find Frank's and Sally's share.]
+make "ship [The gross weight of a ship is 20000 tons.
+  If its net weight is 15000 tons, what is the weight of the ships cargo?]
+make "span [If 1 span is 9 inches, and 1 fathom is 6 feet,
+  how many spans is 1 fathom?]
+make "sumtwo [The sum of two numbers is 96,
+  and one number is 16 larger than the other number. Find the two numbers.]
+make "tom [If the number of customers Tom gets is
+  twice the square of 20 per cent of the number of advertisements he runs,
+  and the number of advertisements he runs is 45,
+  what is the number of customers Tom gets?]
+make "uncle [Bill's father's uncle is twice as old as Bill's father.
+  2 years from now Bill's father will be 3 times as old as Bill.
+  The sum of their ages is 92 . Find Bill's age.]
+
+;; Initial data base
+
+pprop "distance "eqns ~
+  [[equal [distance] [product [speed] [time]]]
+   [equal [distance] [product [gas consumtion] [number of gallons of gas used]]]]
+pprop "feet "eqns ~
+  [[equal [product 1 [feet]] [product 12 [inches]]]
+   [equal [product 1 [yards]] [product 3 [feet]]]]
+pprop "feet "sing "foot
+pprop "foot "plural "feet
+pprop "gallons "eqns ~
+  [[equal [distance] [product [gas consumtion] [number of gallons of gas used]]]]
+pprop "gas "eqns ~
+  [[equal [distance] [product [gas consumtion] [number of gallons of gas used]]]]
+pprop "inch "plural "inches
+pprop "inches "eqns [[equal [product 1 [feet]] [product 12 [inches]]]]
+pprop "people "sing "person
+pprop "person "plural "people
+pprop "speed "eqns [[equal [distance] [product [speed] [time]]]]
+pprop "time "eqns [[equal [distance] [product [speed] [time]]]]
+pprop "yards "eqns [[equal [product 1 [yards]] [product 3 [feet]]]]