And clean up some logic in `rule.py`. This is the place where the
"brains" of Copycat really live, it seems; Copycat can only succeed
at solving a puzzle if it can take the `Rule` it deduced and apply
it to the target string to produce a new string. And it can only
do that if the necessary *actions* have been programmed into `rule.py`.
Right now, it explicitly can't deal with "rules" that involve more
than one local change; that involve reversal; or more importantly,
IIUC, rules that involve "ascending runs", because the idea of a
successor-group is(?) known to the Slipnet but not to `rule.py`;
the latter deals only in "strings", not in "workspace objects".
This seems like a major flaw in the system... but maybe I'm missing
something.
You can now install Copycat into your Python virtualenv without even
checking out this repository! Just run this command:
pip install -e git+git://github.com/Quuxplusone/co.py.cat.git#egg=copycat
To check out a specific branch,
pip install -e git+git://github.com/Quuxplusone/co.py.cat.git@branch#egg=copycat
The goal here is to use `curses` to display the coderack, slipnet,
and temperature in real time. A further goal would be a reporter
that sent the data over websockets to a browser, at which point
I could throw this thing up on Heroku and let people mess with it.
(Not that that would be very entertaining, yet.)
The "leftmost object" in the string `b` does span the whole string,
but it's not a `Group`, so the old code would crash when it got
to the evaluation of `group.objectList` (since `Letter`s don't have
`objectList`s).
Just make all argument-passing explicit; which means the coderack
no longer cares about `oldCodelet` (which was being used only to
get the implicit arguments to the new codelet).
- Nobody does `import random` anymore.
- Random numbers are gotten from `ctx.random`, which is an object
of type `Randomness` with all the convenience methods that used to
be obnoxious functions in the `formulas` module.
- Every place that was using `random.random()` to implement the
equivalent of Python3 `random.choices(seq, weights)` has been updated
to use `ctx.random.weighted_choice(seq, weights)`.
This has a functional effect, since the details of random number
generation have changed. The *statistical* effect should be small.
I do observe that Copycat is having trouble inventing the "mrrjjjj"
solution right now (even in 1000 test runs), so maybe something is
slightly broken.
And demagic all the callers of this function. Notice that with this
move, it becomes *harder* for these "getAdjustedFoo" functions to
access other contextual state, such as the state of the coderack
and the state of the workspace. This is a good thing for modularity
but possibly a misfeature in terms of flexibility-re-logic-changes.
The only top-level imports now are needed for inheritance relationships.
The only function-level imports are HACKS that I need to FIXME; they
all `from context import context as ctx` and then fetch whatever they
actually need from the `ctx` just as if `ctx` had been passed in by the
caller instead of fetched from this magical global storage.
I think the reason the temperature logic was so confused in the old code
is because the Java code has a class `Temperature` that is used for
graphical display *and* two variables in `formulas` that are used for
most of the actual math. But somewhere along the line, some of the code
in `formulas.java` started reading from `Temperature.value` as well.
So the Python code was just faithfully copying that confusion.
The actual abstraction here is a very simple "temperature" object
with a stored value. It can be "clamped" to 100.0 for a given period.
The only complication is that one of the codelets (the rule-transformer
codelet) wants to get access to the "actual value" of the temperature
even when it is clamped.
The Python rule-transformer codelet also had a bug: it was accidentally
setting `temperature.value` on the `temperature` module instead of on
the `temperature.temperature` object! This turned some of its behavior
into a no-op, for whatever that's worth.
Lastly, the calculation of `finalTemperature` in the main program can
now report 100.0 if the answer is found while the temperature is clamped.
I don't fully understand why this didn't happen in the old code.
I've hacked around it with `temperature.last_unclamped_value` for now,
but I should TODO FIXME.
There is a bugfix in here as well: one of the probabilities was
being taken the wrong way around. The result should have been to
make single-letter groups very often, I guess? Fixing this bug
doesn't show any change in Copycat's macro behavior, except that
it seems like average temperatures have gotten hotter.
Should be no functional change, but this gets rid of one circular
import (some codelet methods need a pointer to the coderack, but
they should be getting that pointer from their caller, not from
the global scope) and a lot of reflection-magic.
Before this patch, `coderackPressures.updatePressures()` was always
a no-op, as evidenced by the until-now-harmless misspelling of Python's
list `remove` operation as `removeElement`.
I can't tell if this broke anything; my tests still pass.
Without this patch, `python main.py abc aabbcc milk` will reliably crash.
I believe what happens here is that we initialize all the slipnodes and
everything, and then `slipnet.predecessor` becomes `None`, which means
that if that concept ever arises on its own (vs. arising as the "opposite"
of "successor"), we'll be passing around `None` instead of a proper `Slipnode`
and everything goes sideways.
This line doesn't correspond obviously to anything in the Java code,
so I think it's just bogus --- an experiment in "brain damage" that was
accidentally committed?