diff --git a/simra.py b/simra.py
index 4c9cf3807a2e339940baba1b61f2a8916f7c659f..06185d3aa3e0a5f3bab83534923176f50b83ff72 100755
--- a/simra.py
+++ b/simra.py
@@ -2,198 +2,160 @@
 import tkinter as TK
 import collections
 
-flatten = lambda l: [item for sublist in l for item in sublist]
-
-class Mergeable_dict(dict):
+def dict_filter(dictionary, keys):
+    """
+    Return a subdictionary of `dictionary` comprising only the given `keys`.
     """
-    Subclass of dict, except that mergeable_dict += dict shall update all
-    entries of foo with the corresponding values in bar.
-    This requires that bar.keys() is a subset of foo.keys(), otherwise
-    IndexError is raised.
+    return dict((key, dictionary[key]) for key in keys)
+
+def flatten(l):
+    """Given a list of lists l, concatenate all elements of l."""
+    return [item for sublist in l for item in sublist]
+
+class Node:
     """
-    def __iadd__(self, other):
-        for k in other.keys():
-            if not k in self.keys(): raise IndexError()
-            self[k] = other[k]
-        return self
+    An Automata Network Node.
 
-# BUG: changing the UP manually (not inc/dec) will break the assumption 
-# that an.unstep(); an.step() is no-op.
-# The other way around, an.step(); an.unstep() is always working though.
+    Constructor fields:
+    name         -- Any hashable value, used for printing and identification
+    update_func  -- Update Function; it must take one parameter: a dictionary
+                    mapping name of neighbours to their values
+    dependencies -- List of dependency names (other nodes' names)
+    init_state   -- The initial value of the node (may be any value)
+
+    Other fields:
+    state -- Curent value of the node
+    """
+    
+    def __init__(self, name, update_func=None, dependencies=[], init_state=0):
+        self.name = name
+        self.update_func = update_func
+        self.dependencies = dependencies
+        self.init_state = init_state
+        self.reset_state() # Sets self.state
+    
+    def reset_state(self):
+        self.state = self.init_state.copy()
+    
+    def add_dependency(self, new_dependency):
+        self.dependencies.append(new_dependency)
+    
+    def update(self, neigh_vals):
+        self.state = self.update_func(neigh_vals)
 
 class AN:
     """
     An automata network.
 
-    Fields:
-    nodes        -- set node "names", that can be arbitrary (hashable) values
-    dependencies -- dict mapping nodes to lists/sets of nodes, encoding the
-                    dependency graph of the network
-    update_funcs -- dict mapping nodes to functions; each function takes a
-                    dictionary (neighbour node→current value) as sole argument
-                    (it is possible to do my_an.update_funcs += dict to merge
-                    in a dictionary, i.e. to change the functions of only some
-                    nodes)
-    update_mode  -- list of sets (or list of lists) interpreted as a periodic
-                    update mode
-    init_state   -- dict mapping nodes to values, that tells which values
-                    should be used when the network is (re)initialized
-    state        -- dict nodes→values holding the current state (value of each
-                    node) of the network
-    history      -- circular buffer of the last self.history_len states
-                    traversed by the network
-    up           -- Update Pointer; an index for self.update_mode; it
-                    “points” to the next update to do
+    Constructor fields:
+    nodes       -- A set (or list…) of nodes.
+    update_mode -- A list of sets (or set-like objects) of node names, viewed
+                   as a periodic update mode.
+    history_len -- How many states to remember for the rollback feature.
+                   This field may be altered later, and the history will be
+                   resized accordingly.
+
+    Other fields:
+    up      -- Stands for Update Pointer.
+               It is an index in update_mode thant “points” to the next update
+               to perform. Note that foo.up can be publicly read and written.
+               A modulo len(update_mode) is implicitly applied, so it is safe
+               to do, e.g., foo.up +=1 on an update.
+    history -- A circular buffer of deep copies of the previous values of _node
+               (see below).
+               It can be publicly accessed. Please do not alter the history
+               by yourself (Stalin did nothing right).
+    _nodes  -- A dictionary mapping node names to nodes.
+               When the field `nodes` is read, it is actually generated
+               on-the-fly as the set of items of _nodes. Conversely when
+               `nodes` is written, a dictionary is implicitly generated and
+               written to `_nodes`.
     """
-    def __init__(self, nodes, dependencies, update_funcs, update_mode, init_state=None, history_len=10):
-        self.nodes = set(nodes)
-        self.dependencies = dependencies
-        self.update_funcs = update_funcs
+
+    def __init__(self, nodes={}, update_mode=[], history_len=10):
+        self.nodes = nodes
         self.update_mode = update_mode
-        self.init_state = init_state # None is properly handled by a property
-        self.reinit_state() # Sets self.state, self.up
+        self.up = 0
         self.history = collections.deque(maxlen=history_len)
-
+    
     # ################################################################
-
-    @property
-    def update_funcs(self):
-        return self._update_funcs
-
-    @update_funcs.setter
-    def update_funcs(self, new_update_funcs):
-        if not self.nodes.issubset(set(new_update_funcs.keys())):
-            raise ValueError("update function is missing for some nodes")
-        self._update_funcs = Mergeable_dict()
-        self.set_multiple_update_funcs(self, new_update_funcs)
     
-    def set_multiple_update_funcs(self, new_update_funcs):
-        """
-        If update_funcs is a dictionary node→function, change the update
-        function of each node to the corresponding function. All nodes in
-        update_funcs.keys() need to exist; but not all nodes from the network
-        need to be changed by this operation.
-        """
-        for n in keys(new_update_funcs):
-            self.set_update_func(n, new_update_funcs[n])
-
-    def set_update_func(self, node, new_update_func):
-        """Set the update function of a node."""
-        if not node in self.nodes:
-            raise ValueError("trying to set update_func of nonexisting node")
-        self._update_funcs[node] = new_update_func
-
     @property
-    def dependencies(self):
-        return self._dependencies
+    def nodes(self):
+        """Return the set of all nodes."""
+        return self._nodes.items()
 
-    @dependencies.setter
-    def dependencies(self, new_dependencies):
-        if not self.nodes == set(new_dependencies.keys()):
-            raise ValueError("""trying to set a dependency for a nonexistent
- node, or missing a dependency list for a node.""")
-        self._dependencies = new_dependencies
+    @nodes.setter
+    def nodes(self, new_nodes):
+        self._nodes = {}
+        for node in new_nodes: self.add_node(node)
 
-    @property
-    def update_mode(self):
-        return self._update_mode
-
-    @update_mode.setter
-    def update_mode(self, new_update_mode):
-        """
-        Change the update mode.
-        update_mode needs to be a list of sets (or list of lists) and is
-        interpreted as a periodic update mode.
-        This resets up to 0 and clears the history as side-effects.
-        """
-        if not set(flatten(new_update_mode)).issubset(self.nodes):
-            raise ValueError("update_mode tries to update a nonexistent node")
-        self._update_mode = new_update_mode
-        self.up = 0
-        self.history.clear()
+    def add_node(self, node):
+        """Adds a new node to the AN."""
+        self._nodes[node.name] = node
 
-    @property
-    def init_state(self):
-        return self._init_state
-    
-    @init_state.setter
-    def init_state(self, new_init_state):
+    def del_node(self, node_name):
         """
-        Change initial state.
-        Initial state is used when reinitializing the network.
-        If init_state is None, `0` for each node is used; otherwise, init_state
-        must be a dictionary node->value, where init_state.keys() is equal to
-        the set of nodes of the network.
+        Remove a node from the AN (by node name). Returns the deleted node.
+        If no node with such name is found, raises KeyError.
         """
-        if new_init_state:
-            if set(new_init_state.keys()) != self.nodes:
-                raise ValueError("""init_state either misses state for a node
-or has a sate for a nonexistent node""")
-            self._init_state = new_init_state.copy()
-        else:
-            self._init_state = {}
-            for n in self.nodes:
-                self._init_state[n] = 0
+        return self._nodes.pop(node_name)
     
     @property
     def up(self):
         return self._up
-
+    
     @up.setter
     def up(self, new_up):
-        self._up = new_up % len(self.history)
-
+        self._up = new_up % len(self.update_mode)
+    
     @property
     def history_len(self):
         return len(self.history)
-
+    
     @history_len.setter
     def history_len(self, new_history_len):
         new_history = collections.deque(new_history_len)
         for i in range(min(new_history_len, self.history_len)):
             new_history.append(self.history[-(i+1)])
         self.history = new_history
-
+    
     # ################################################################
     
-    def reinitialize(self):
-        """
-        Reset the current state to a copy of the initial state,
-        and the UP to 0.
-        """
-        self.history.append(self.state)
-        self.state = self.init_state.copy()
+    def reset_state(self):
+        """Set each node to its initial value, and the up to 0."""
+        new_nodes = self._nodes.deep_copy()
+        for node in new_nodes:
+            node.reset_state()
+        
+        self.history.append(self._nodes)
+        self._nodes = new_nodes
         self.up = 0
 
-    def step(self):
-        """Execute one step of the AN."""
-        new_state = self.state.copy()
-        for node in self.update_mode[self.up]:
-            local_view = dict((neighbour, self.state[neighbour]) for neighbour in self.dependencies[node])
-            new_state[n] = (self.update_func[n])(self.state)
+    def update(self):
+        """Update the AN once."""
+        new_nodes = self._nodes.deep_copy()
+        for n in self.update_mode[self.up]:
+            local_view = dict_filter(self.nodes, self.nodes[n].dependencies)
+            new_nodes[n].update(local_view)
         
-        self.history.append(self.state)
-        self.state = new_state
+        self.history.append(self.nodes)
+        self._nodes = new_nodes
         self.up += 1
 
-    def run(self, steps):
-        """Execute `steps` steps of the AN."""
-        for i in range(steps):
-            self.step()
-
-    def unstep(self):
+    def unupdate(self):
         """Roll back one step of the AN, within limits of history_len."""
-        self.state = self.history.pop()
+        self._nodes = self.history.pop()
         self.up -= 1
-
-    # ################################################################
-
-    def __iter__(self):
-        return self.nodes
-
-    def __call__(self):
-        self.step()
-        return self.state.copy()
+    
+    def run(self, steps):
+        """Update the AN `steps` times. If `steps` is negative, roll back."""
+        if(steps < 0):
+            for i in range(-steps):
+                self.unupdate()
+        else:
+            for i in range(steps):
+                self.update()
 
 # ################################################################