diff --git a/src/test_writer.py b/src/test_writer.py index 37e2b5e..222ee96 100644 --- a/src/test_writer.py +++ b/src/test_writer.py @@ -3,6 +3,30 @@ import unittest import writer class TestLineChooser(unittest.TestCase): + def test_simulated_annealing(self): + chooser = writer.LineChooserSimulatedAnnealing() + chooser.now = lambda *args: 100 + + for name, c in ({ + "fresh something": [ + writer.LineChooserSimulatedAnnealing.initial_health, + chooser.now(), + ], + "old something": [ + writer.LineChooserSimulatedAnnealing.initial_health - writer.LineChooserSimulatedAnnealing.decay_rate * 5, + chooser.now() - 5, + ], + "fresh nothing": [ + writer.LineChooserSimulatedAnnealing.initial_health - writer.LineChooserSimulatedAnnealing.nothing_penalty, + chooser.now(), + ], + }).items(): + self.assertEqual( + c[0], + chooser.health(self.new_line(True, c[1], not "nothing" in name)), + name, + ) + def test_latest_sticky(self): stale_something = self.new_line(False, 1, 1) stale_nothing = self.new_line(False, 1, None) diff --git a/src/writer.py b/src/writer.py index eed945a..b0cf839 100644 --- a/src/writer.py +++ b/src/writer.py @@ -2,12 +2,14 @@ import time import json import pyautogui import log +import random class Writer: def __init__(self, writer): self.writer = writer self.previous = Line([]) self.chooser = LineChooserLatestSticky() + self.chooser = LineChooserSimulatedAnnealing() def write(self, v): latest = Line(v) @@ -86,12 +88,35 @@ class LineChooser: return b if not b: return a - return self._choose(a, b) - -class LineChooserLatestSticky(LineChooser): - def _choose(self, a, b): latest = max([a,b], key=lambda x:x.t) oldest = min([a,b], key=lambda x:x.t) + return self._choose(latest, oldest) + + def now(self): + return time.time() + +class LineChooserLatestSticky(LineChooser): + def _choose(self, latest, oldest): if latest.is_nothing() and oldest.is_recent(): return oldest return latest + +class LineChooserSimulatedAnnealing(LineChooser): + initial_health = 50 + nothing_penalty = 10 + decay_rate = 5 + + def _choose(self, latest, oldest): + oldest_health = self.health(oldest) + seed = random.randint(0, 100) + if seed < oldest_health: + print("LineChooserSimulatedAnnealing retaining old because", seed, "<", oldest_health) + return oldest + return latest + + def health(self, line): + health = LineChooserSimulatedAnnealing.initial_health + health = health - LineChooserSimulatedAnnealing.decay_rate * (self.now() - line.t) + if line.is_nothing(): + health -= LineChooserSimulatedAnnealing.nothing_penalty + return health