!752 // Numeric quadruple static class NQ { BigInteger a; S b; BigInteger c; S d; *() {} *(S a, S *b, S c, S *d) { this.a = smartBigint(a); this.c = smartBigint(c); } *(BigInteger *a, S *b, BigInteger *c, S *d) {} public boolean equals(O o) { ret stdEq(this, o, "a", "b", "c", "d"); } public S toString() { ret a + " " + b + " is " + c + " " + d; } NQ reverse() { ret new NQ(c, d, a, b); } bool valid() { ret neq(a, 0) && neq(c, 0); } } static new L terms; p { load("terms"); } synchronized answer { if (match("* * is * *", s, m) || match("* * are * *", s, m)) { NQ nq = new NQ(m.unq(0), simplify(m.unq(1)), m.unq(2), simplify(m.unq(3))); if (terms.contains(nq)) ret "I know!"; terms.add(nq); save("terms"); ret "OK, added to theory. Now " + l(terms) + " entries"; } if (match("show theory", s)) { ret structure(allToString(terms)); } if (match("how many * * * *", s, m)) { S isAre = m.get(1); if (litlist("is", "are").contains(toLower(isAre))) { BigInteger a = bigint(m.unq(2)); S b = m.unq(3); S d = m.unq(0); Rat c = calc(new Rat(a), b, d); if (c == null) ret "I don't know"; ret a + " " + b + " " + isAre + " " + c.mixed() + " " + d + "!"; } } } /*static Rat calc(Rat a, S b, S d) { b = simplify(b); d = simplify(d); for (NQ nq : terms) { if (eq(nq.b, b) && eq(nq.d, d)) ret calcForward(nq, a); if (eq(nq.d, b) && eq(nq.b, d)) ret calcForward(nq.reverse(), a); } null; }*/ static Rat calc(Rat a, S b, S d) { b = simplify(b); d = simplify(d); ret calcTransitive(a, b, d, new TreeSet); } // b is the unit we have, d is the unit we're searching for static Rat calcTransitive(Rat a, S b, S d, Set seen) { print(format("calcTransitive * * * *", a, b, d, structure(seen))); if (eq(b, d)) ret a; // done if (seen.contains(b)) ret null; seen.add(b); for (NQ nq : terms) if (nq.valid()) { twice { if (eq(nq.b, b)) { Rat r = calcTransitive(calcForward(nq, a), nq.d, d, seen); if (r != null) ret r; } nq = nq.reverse(); } } null; } static Rat calcForward(NQ nq, Rat a) { ret a.multiply(nq.c).divide(nq.a); } static S simplify(S s) { ret toSingular(toLower(s)); } static S toSingular(S s) { ret dropSuffix("s", s); // yeah it's rough } static BigInteger smartBigint(S s) { if (litlist("a", "an", "one").contains(toLower(s))) ret bigint(1); ret bigint(s); }