!752 static new MultiMap byName; // multiple entries not really handled yet sclass BaseNode { S id = randomID(12); S name; new L related; new Map relationStrengths; // strength of relation, 0 to 1 new L identicalOuter; // identical nodes in other bots *() {} *(S *name) { byName.put(name, (Node) this); } } sclass Node extends BaseNode { *() {} *(S name) { super(name); } new L opposites; // list of opposites new L dropped; // no longer considered opposites new Map modifiers; // optional modifier for each entry new Map sources; // source(s) of each entry } p { /*Node white = new Node("white"); Node black = new Node("black"); white.opposites.add(black); black.opposites.add(white);*/ load("byName"); } static void saveAll() { save("byName"); } answer { exceptionToUser { if (!tb()) null; if (match("is * an opposite of *", s, m) || match("is * the opposite of *", s, m)) { S a = m.tlc(0), b = m.tlc(1); L la = byName.get(a), lb = byName.get(b); if (empty(la)) ret format("What is *?", a); if (empty(lb)) ret format("What is *?", b); for (Node na : la) for (Node nb : lb) if (na.opposites.contains(nb)) ret "yes"; ret "no"; } if (match("what is an opposite of *", s, m) || match("what is the opposite of *", s, m)) { S a = m.tlc(0); L la = byName.get(a); if (empty(la)) ret format("What is *?", a); new L l; for (Node na : la) setAddAll(l, na.opposites); if (empty(l)) ret "I don't know"; ret join(", ", collectField(l, "name")); } if (match("* is an opposite of *", s, m) || match("* is the opposite of *", s, m)) { S a = m.tlc(0), b = m.tlc(1); Node na = getOrMake(a), nb = getOrMake(b); setAdd(na.opposites, nb); setAdd(nb.opposites, na); na.dropped.remove(nb); nb.dropped.remove(na); saveAll(); ret "OK"; } if (match("* is not an opposite of *", s, m) || match("* is not the opposite of *", s, m)) { S a = m.tlc(0), b = m.tlc(1); Node na = getOrMake(a), nb = getOrMake(b); setAdd(na.dropped, nb); setAdd(nb.dropped, na); na.opposites.remove(nb); nb.opposites.remove(na); saveAll(); ret "OK"; } }} static Node getOrMake(S name) { Node n = byName.getFirst(name); if (n == null) n = new Node(name); ret n; }