aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/handler.py260
-rw-r--r--bin/printer.py537
-rwxr-xr-xbin/salis.py158
-rw-r--r--bin/world.py162
4 files changed, 515 insertions, 602 deletions
diff --git a/bin/handler.py b/bin/handler.py
index ad3b14e..b675159 100644
--- a/bin/handler.py
+++ b/bin/handler.py
@@ -13,7 +13,7 @@ An user may open the Salis console by pressing the 'c' key while in a running
session. A nice quirk is the possibility to run python commands from within the
Salis console. As an example, to get the memory size, an user could type:
->>> exec output = self._sim.lib.sal_mem_get_size()
+>>> exec output = self.__sim.lib.sal_mem_get_size()
Note that 'output' denotes a storage variable that will get printed on the
console response. This ability gives an user a whole lot of power, and should
@@ -31,10 +31,10 @@ class Handler:
""" Handler constructor. Simply link this class to the main simulation
class and printer class and create symbol dictionary.
"""
- self._sim = sim
- self._printer = sim.printer
- self._inst_dict = self._get_inst_dict()
- self._console_history = []
+ self.__sim = sim
+ self.__printer = sim.printer
+ self.__inst_dict = self.__get_inst_dict()
+ self.console_history = []
def process_cmd(self, cmd):
""" Process incoming commands from curses. Commands are received via
@@ -42,62 +42,62 @@ class Handler:
character representations with 'ord()'.
"""
if cmd == self.ESCAPE_KEY:
- self._sim.lib.sal_main_save(
- self._sim.save_file_path.encode("utf-8")
+ self.__sim.lib.sal_main_save(
+ self.__sim.save_file_path.encode("utf-8")
)
- self._sim.exit()
+ self.__sim.exit()
elif cmd == ord(" "):
- self._sim.toggle_state()
+ self.__sim.toggle_state()
elif cmd == curses.KEY_LEFT:
- self._printer.flip_page(-1)
+ self.__printer.flip_page(-1)
elif cmd == curses.KEY_RIGHT:
- self._printer.flip_page(1)
+ self.__printer.flip_page(1)
elif cmd == curses.KEY_DOWN:
- self._printer.scroll_main(-1)
+ self.__printer.scroll_main(-1)
elif cmd == curses.KEY_UP:
- self._printer.scroll_main(1)
+ self.__printer.scroll_main(1)
elif cmd == curses.KEY_RESIZE:
- self._printer.on_resize()
+ self.__printer.on_resize()
elif cmd == ord("X"):
- self._printer.toggle_hex()
+ self.__printer.toggle_hex()
elif cmd == ord("x"):
- self._printer.world.zoom_out()
+ self.__printer.world.zoom_out()
elif cmd == ord("z"):
- self._printer.world.zoom_in()
+ self.__printer.world.zoom_in()
elif cmd == ord("a"):
- self._printer.world.pan_left()
- self._printer.proc_scroll_left()
+ self.__printer.world.pan_left()
+ self.__printer.proc_scroll_left()
elif cmd == ord("d"):
- self._printer.world.pan_right()
- self._printer.proc_scroll_right()
+ self.__printer.world.pan_right()
+ self.__printer.proc_scroll_right()
elif cmd == ord("s"):
- self._printer.world.pan_down()
- self._printer.proc_scroll_down()
+ self.__printer.world.pan_down()
+ self.__printer.proc_scroll_down()
elif cmd == ord("w"):
- self._printer.world.pan_up()
- self._printer.proc_scroll_up()
+ self.__printer.world.pan_up()
+ self.__printer.proc_scroll_up()
elif cmd == ord("S"):
- self._printer.world.pan_reset()
- self._printer.proc_scroll_vertical_reset()
+ self.__printer.world.pan_reset()
+ self.__printer.proc_scroll_vertical_reset()
elif cmd == ord("A"):
- self._printer.world.pan_reset()
- self._printer.proc_scroll_horizontal_reset()
+ self.__printer.world.pan_reset()
+ self.__printer.proc_scroll_horizontal_reset()
elif cmd == ord("o"):
- self._printer.proc_select_prev()
+ self.__printer.proc_select_prev()
elif cmd == ord("p"):
- self._printer.proc_select_next()
+ self.__printer.proc_select_next()
elif cmd == ord("f"):
- self._printer.proc_select_first()
+ self.__printer.proc_select_first()
elif cmd == ord("l"):
- self._printer.proc_select_last()
+ self.__printer.proc_select_last()
elif cmd == ord("k"):
- self._printer.proc_scroll_to_selected()
+ self.__printer.proc_scroll_to_selected()
elif cmd == ord("g"):
- self._printer.proc_toggle_gene_view()
+ self.__printer.proc_toggle_gene_view()
elif cmd == ord("\n"):
- self._printer.run_cursor()
+ self.__printer.run_cursor()
elif cmd == ord("c"):
- self._printer.run_console()
+ self.__printer.run_console()
else:
# Check for numeric input. Number keys [1 to 0] cycle the
# simulation [2 ** ((n - 1) % 10] times.
@@ -105,7 +105,7 @@ class Handler:
if chr(cmd).isdigit():
factor = int(chr(cmd))
factor = int(2 ** ((factor - 1) % 10))
- self._cycle_sim(factor)
+ self.__cycle_sim(factor)
except ValueError:
pass
@@ -120,92 +120,88 @@ class Handler:
try:
# Handle both python and self-thrown exceptions.
if command[0] in ["q", "quit"]:
- self._on_quit(command, save=True)
+ self.__on_quit(command, save=True)
elif command[0] in ["q!", "quit!"]:
- self._on_quit(command, save=False)
+ self.__on_quit(command, save=False)
elif command[0] in ["i", "input"]:
- self._on_input(command)
+ self.__on_input(command)
elif command[0] in ["c", "compile"]:
- self._on_compile(command)
+ self.__on_compile(command)
elif command[0] in ["n", "new"]:
- self._on_new(command)
+ self.__on_new(command)
elif command[0] in ["k", "kill"]:
- self._on_kill(command)
+ self.__on_kill(command)
elif command[0] in ["e", "exec"]:
- self._on_exec(command)
+ self.__on_exec(command)
elif command[0] in ["s", "scroll"]:
- self._on_scroll(command)
+ self.__on_scroll(command)
elif command[0] in ["p", "process"]:
- self._on_proc_select(command)
+ self.__on_proc_select(command)
elif command[0] in ["r", "rename"]:
- self._on_rename(command)
+ self.__on_rename(command)
elif command[0] in ["save"]:
- self._on_save(command)
+ self.__on_save(command)
elif command[0] in ["a", "auto"]:
- self._on_set_autosave(command)
+ self.__on_set_autosave(command)
else:
# Raise if a non-existing command has been given.
- self._raise("Invalid command: '{}'".format(command[0]))
+ self.__raise("Invalid command: '{}'".format(command[0]))
except BaseException as exep:
# We parse and redirect python exceptions to the error
# console-window.
message = str(exep).strip()
message = message[0].upper() + message[1:]
- self._printer.show_console_error(message)
+ self.__printer.show_console_error(message)
finally:
# Store command on console history.
- self._console_history.append(command_raw.strip())
+ self.console_history.append(command_raw.strip())
- @property
- def console_history(self):
- return self._console_history
-
- def _raise(self, message):
+ def __raise(self, message):
""" Generic exception thrower. Throws a 'RuntimeError' initialized with
the given message.
"""
raise RuntimeError("ERROR: {}".format(message))
- def _respond(self, message):
+ def __respond(self, message):
""" Generic console responder. Throws a 'RuntimeError' initialized with
the given message.
"""
raise RuntimeError(message)
- def _cycle_sim(self, factor):
+ def __cycle_sim(self, factor):
""" Simply cycle Salis 'factor' number of times.
"""
for _ in range(factor):
- self._sim.lib.sal_main_cycle()
- self._sim.check_autosave()
+ self.__sim.lib.sal_main_cycle()
+ self.__sim.check_autosave()
- def _get_inst_dict(self):
+ def __get_inst_dict(self):
""" Transform the instruction list of the printer module into a
dictionary that's more useful for genome compilation. Instruction
symbols are keys, values are the actual byte representation.
"""
inst_dict = {}
- for i, inst in enumerate(self._printer.inst_list):
+ for i, inst in enumerate(self.__printer.inst_list):
inst_dict[inst[1]] = i
return inst_dict
- def _on_quit(self, command, save):
- """ Exit simulation. We can choose whether to save the simulation into a
- save file or not.
+ def __on_quit(self, command, save):
+ """ Exit simulation. We can choose whether to save the simulation into
+ a save file or not.
"""
if len(command) > 1:
- self._raise("Invalid parameters for '{}'".format(command[0]))
+ self.__raise("Invalid parameters for '{}'".format(command[0]))
if save:
- self._sim.lib.sal_main_save(
- self._sim.save_file_path.encode("utf-8")
+ self.__sim.lib.sal_main_save(
+ self.__sim.save_file_path.encode("utf-8")
)
- self._sim.exit()
+ self.__sim.exit()
- def _write_genome(self, genome, address_list):
+ def __write_genome(self, genome, address_list):
""" Write genome stream into a given list of memory addresses. All
addresses must be valid or an exception is thrown.
"""
@@ -214,8 +210,8 @@ class Handler:
address = int(base_addr, 0)
for _ in range(len(genome)):
- if not self._sim.lib.sal_mem_is_address_valid(address):
- self._raise("Address '{}' is invalid".format(address))
+ if not self.__sim.lib.sal_mem_is_address_valid(address):
+ self.__raise("Address '{}' is invalid".format(address))
address += 1
@@ -224,74 +220,74 @@ class Handler:
address = int(base_addr, 0)
for symbol in genome:
- self._sim.lib.sal_mem_set_inst(
- address, self._inst_dict[symbol]
+ self.__sim.lib.sal_mem_set_inst(
+ address, self.__inst_dict[symbol]
)
address += 1
- def _on_input(self, command):
+ def __on_input(self, command):
""" Compile organism from user typed input. Compilation can only occur
on valid memory addresses. An exception will be thrown when trying to
write into non-valid address or when input stream is invalid.
"""
if len(command) < 3:
- self._raise("Invalid parameters for '{}'".format(command[0]))
+ self.__raise("Invalid parameters for '{}'".format(command[0]))
# All characters in file must be actual instruction symbols.
for character in command[1]:
- if character not in self._inst_dict:
- self._raise("Invalid symbol '{}' found on stream".format(
+ if character not in self.__inst_dict:
+ self.__raise("Invalid symbol '{}' found on stream".format(
character
))
# All looks well, Let's write the genome into memory.
- self._write_genome(command[1], command[2:])
+ self.__write_genome(command[1], command[2:])
- def _on_compile(self, command):
+ def __on_compile(self, command):
""" Compile organism from source genome file. Genomes must be placed on
the './genomes' directory. Compilation can only occur on valid memory
addresses. An exception will be thrown when trying to write into
non-valid address or when genome file is invalid.
"""
if len(command) < 3:
- self._raise("Invalid parameters for '{}'".format(command[0]))
+ self.__raise("Invalid parameters for '{}'".format(command[0]))
# Open genome file for compilation.
- gen_file = os.path.join(self._sim.path, "genomes", command[1])
+ gen_file = os.path.join(self.__sim.path, "genomes", command[1])
with open(gen_file, "r") as f:
genome = f.read().strip()
# Entire genome must be written on a single line.
if "\n" in genome:
- self._raise("Newline detected on '{}'".format(gen_file))
+ self.__raise("Newline detected on '{}'".format(gen_file))
# All characters in file must be actual instruction symbols.
for character in genome:
- if character not in self._inst_dict:
- self._raise("Invalid symbol '{}' found on '{}'".format(
+ if character not in self.__inst_dict:
+ self.__raise("Invalid symbol '{}' found on '{}'".format(
character, gen_file
))
# All looks well, Let's write the genome into memory.
- self._write_genome(genome, command[2:])
+ self.__write_genome(genome, command[2:])
- def _on_new(self, command):
+ def __on_new(self, command):
""" Instantiate new organism of given size on given address. These
memory areas must be free and valid or an exception is thrown.
"""
if len(command) < 3:
- self._raise("Invalid parameters for '{}'".format(command[0]))
+ self.__raise("Invalid parameters for '{}'".format(command[0]))
# Check that all addresses we will allocate are free and valid.
for base_addr in command[2:]:
address = int(base_addr, 0)
for _ in range(int(command[1])):
- if not self._sim.lib.sal_mem_is_address_valid(address):
- self._raise("Address '{}' is invalid".format(address))
- elif self._sim.lib.sal_mem_is_allocated(address):
- self._raise("Address '{}' is allocated".format(address))
+ if not self.__sim.lib.sal_mem_is_address_valid(address):
+ self.__raise("Address '{}' is invalid".format(address))
+ elif self.__sim.lib.sal_mem_is_allocated(address):
+ self.__raise("Address '{}' is allocated".format(address))
address += 1
@@ -299,105 +295,107 @@ class Handler:
for base_addr in command[2:]:
address = int(base_addr, 0)
size = int(command[1], 0)
- self._sim.lib.sal_proc_create(address, size)
+ self.__sim.lib.sal_proc_create(address, size)
- def _on_kill(self, command):
+ def __on_kill(self, command):
""" Kill organism on bottom of reaper queue.
"""
if len(command) > 1:
- self._raise("Invalid parameters for '{}'".format(command[0]))
+ self.__raise("Invalid parameters for '{}'".format(command[0]))
# Call proc kill function only if there's any organisms to kill.
- if not self._sim.lib.sal_proc_get_count():
- self._raise("No organisms currently alive")
+ if not self.__sim.lib.sal_proc_get_count():
+ self.__raise("No organisms currently alive")
else:
- self._sim.lib.sal_proc_kill()
+ self.__sim.lib.sal_proc_kill()
- def _on_exec(self, command):
+ def __on_exec(self, command):
""" Allow a user to execute a python command from within the console.
Using this is very hack-ish, and not recommended unless you're certain
of what you're doing!
"""
if len(command) < 2:
- self._raise("'{}' must be followed by an executable string".format(
- command[0])
+ self.__raise(
+ "'{}' must be followed by an executable string".format(
+ command[0]
+ )
)
# User may query any simulation variable or status and the console will
# respond. For example, to query memory size or order, type one of the
# following:
#
- # >>> exec output = self._sim.lib.sal_mem_get_size()
- # >>> exec output = self._sim.lib.sal_mem_get_order()
+ # >>> exec output = self.__sim.lib.sal_mem_get_size()
+ # >>> exec output = self.__sim.lib.sal_mem_get_order()
#
output = {}
exec(" ".join(command[1:]), locals(), output)
if output:
- self._respond("EXEC RESPONDS: {}".format(str(output)))
+ self.__respond("EXEC RESPONDS: {}".format(str(output)))
- def _on_scroll(self, command):
+ def __on_scroll(self, command):
""" We can scroll to a specific process (on PROCESS view) or to a
specific world address (on WORLD view) via the console.
"""
if len(command) != 2:
- self._raise("Invalid parameters for '{}'".format(command[0]))
+ self.__raise("Invalid parameters for '{}'".format(command[0]))
target = int(command[1], 0)
# If on PROCESS page, scroll to given process.
- if self._printer.current_page == "PROCESS":
- if target < self._sim.lib.sal_proc_get_capacity():
- self._printer.proc_scroll_to(target)
+ if self.__printer.current_page == "PROCESS":
+ if target < self.__sim.lib.sal_proc_get_capacity():
+ self.__printer.proc_scroll_to(target)
else:
- self._raise("No process with ID '{}' found".format(target))
- elif self._printer.current_page == "WORLD":
- if self._sim.lib.sal_mem_is_address_valid(target):
- self._printer.world.scroll_to(target)
+ self.__raise("No process with ID '{}' found".format(target))
+ elif self.__printer.current_page == "WORLD":
+ if self.__sim.lib.sal_mem_is_address_valid(target):
+ self.__printer.world.scroll_to(target)
else:
- self._raise("Address '{}' is invalid".format(address))
+ self.__raise("Address '{}' is invalid".format(address))
else:
- self._raise("'{}' must be called on PROCESS or WORLD page".format(
+ self.__raise("'{}' must be called on PROCESS or WORLD page".format(
command[0])
)
- def _on_proc_select(self, command):
+ def __on_proc_select(self, command):
""" Select a specific process (on PROCESS or WORLD page).
"""
if len(command) != 2:
- self._raise("Invalid parameters for '{}'".format(command[0]))
+ self.__raise("Invalid parameters for '{}'".format(command[0]))
target = int(command[1], 0)
# If on PROCESS page, scroll to given process.
- if target < self._sim.lib.sal_proc_get_capacity():
- self._printer.proc_select_by_id(target)
+ if target < self.__sim.lib.sal_proc_get_capacity():
+ self.__printer.proc_select_by_id(target)
else:
- self._raise("No process with ID '{}' found".format(target))
+ self.__raise("No process with ID '{}' found".format(target))
- def _on_rename(self, command):
+ def __on_rename(self, command):
""" Set a new simulation name. Future auto-saved files will use this
name as prefix.
"""
if len(command) != 2:
- self._raise("Invalid parameters for '{}'".format(command[0]))
+ self.__raise("Invalid parameters for '{}'".format(command[0]))
- self._sim.rename(command[1])
+ self.__sim.rename(command[1])
- def _on_save(self, command):
+ def __on_save(self, command):
""" Save simulation on its current state.
"""
if len(command) != 1:
- self._raise("Invalid parameters for '{}'".format(command[0]))
+ self.__raise("Invalid parameters for '{}'".format(command[0]))
- self._sim.lib.sal_main_save(self._sim.save_file_path.encode("utf-8"))
+ self.__sim.lib.sal_main_save(self.__sim.save_file_path.encode("utf-8"))
- def _on_set_autosave(self, command):
+ def __on_set_autosave(self, command):
""" Set the simulation's auto save interval. Provide any integer
between 0 and (2**32 - 1). If zero is provided, auto saving will be
disabled.
"""
if len(command) != 2:
- self._raise("Invalid parameters for '{}'".format(command[0]))
+ self.__raise("Invalid parameters for '{}'".format(command[0]))
- self._sim.set_autosave(int(command[1], 0))
+ self.__sim.set_autosave(int(command[1], 0))
diff --git a/bin/printer.py b/bin/printer.py
index 04c9865..7fbe258 100644
--- a/bin/printer.py
+++ b/bin/printer.py
@@ -24,26 +24,31 @@ class Printer:
""" Printer constructor. It takes care of starting up curses, defining
the data pages and setting the printer on its initial state.
"""
- self._sim = sim
- self._color_pair_count = 0
- self._screen = self._get_screen()
- self._inst_list = self._get_inst_list()
- self._proc_elements = self._get_proc_elements()
- self._main = self._get_main()
- self._pages = self._get_pages()
- self._size = self._screen.getmaxyx()
- self._current_page = "MEMORY"
- self._main_scroll = 0
- self._selected_proc = 0
- self._selected_proc_data = (c_uint32 * len(self._proc_elements))()
- self._proc_list_scroll = 0
- self._proc_element_scroll = 0
- self._proc_gene_scroll = 0
- self._proc_gene_view = False
- self._curs_y = 0
- self._curs_x = 0
- self._print_hex = False
- self._world = World(self, self._sim)
+ self.__sim = sim
+ self.__color_pair_count = 0
+
+ # Initialize curses screen, instruction and proc-element list before
+ # other private elements that depend on them.
+ self.screen = self.__get_screen()
+ self.inst_list = self.__get_inst_list()
+ self.proc_elements = self.__get_proc_elements()
+
+ # We can now initialize all other privates.
+ self.__main = self.__get_main()
+ self.__pages = self.__get_pages()
+ self.__main_scroll = 0
+ self.__proc_element_scroll = 0
+ self.__proc_gene_scroll = 0
+ self.__proc_gene_view = False
+ self.__curs_y = 0
+ self.__curs_x = 0
+ self.__print_hex = False
+ self.size = self.screen.getmaxyx()
+ self.current_page = "MEMORY"
+ self.selected_proc = 0
+ self.selected_proc_data = (c_uint32 * len(self.proc_elements))()
+ self.proc_list_scroll = 0
+ self.world = World(self, self.__sim)
def __del__(self):
""" Printer destructor exits curses.
@@ -54,44 +59,44 @@ class Printer:
""" We use this method to set new color pairs, keeping track of the
number of pairs already set. We return the new color pair ID.
"""
- self._color_pair_count += 1
- curses.init_pair(self._color_pair_count, fg, bg)
- return self._color_pair_count
+ self.__color_pair_count += 1
+ curses.init_pair(self.__color_pair_count, fg, bg)
+ return self.__color_pair_count
def get_cmd(self):
""" This returns the pressed key from the curses handler. It's called
during the simulation's main loop. Flushing input is important when in
non-blocking mode.
"""
- ch = self._screen.getch()
+ ch = self.screen.getch()
curses.flushinp()
return ch
def set_nodelay(self, nodelay):
""" Toggles between blocking and non-blocking mode on curses.
"""
- self._screen.nodelay(nodelay)
+ self.screen.nodelay(nodelay)
def toggle_hex(self):
""" Toggle between decimal or hexadecimal printing of all simulation
state elements.
"""
- self._print_hex = not self._print_hex
+ self.__print_hex = not self.__print_hex
def on_resize(self):
""" Called whenever the terminal window gets resized.
"""
- self._size = self._screen.getmaxyx()
+ self.size = self.screen.getmaxyx()
self.scroll_main()
- self._world.zoom_reset()
+ self.world.zoom_reset()
def flip_page(self, offset):
""" Change data page by given offset (i.e. '1' for next page or '-1'
for previous one).
"""
- pidx = list(self._pages.keys()).index(self._current_page)
- pidx = (pidx + offset) % len(self._pages)
- self._current_page = list(self._pages.keys())[pidx]
+ pidx = list(self.__pages.keys()).index(self.current_page)
+ pidx = (pidx + offset) % len(self.__pages)
+ self.current_page = list(self.__pages.keys())[pidx]
self.scroll_main()
def scroll_main(self, offset=0):
@@ -101,112 +106,112 @@ class Printer:
gets cleared and at least some of the data is always scrolled into
view.
"""
- self._screen.clear()
- len_main = len(self._main)
- len_page = len(self._pages[self._current_page])
- max_scroll = (len_main + len_page + 5) - self._size[0]
- self._main_scroll += offset
- self._main_scroll = max(0, min(self._main_scroll, max_scroll))
+ self.screen.clear()
+ len_main = len(self.__main)
+ len_page = len(self.__pages[self.current_page])
+ max_scroll = (len_main + len_page + 5) - self.size[0]
+ self.__main_scroll += offset
+ self.__main_scroll = max(0, min(self.__main_scroll, max_scroll))
def proc_scroll_left(self):
""" Scroll process data elements or genomes (on PROCESS view) to the
left.
"""
- if self._current_page == "PROCESS":
- if self._proc_gene_view:
- self._proc_gene_scroll -= 1
- self._proc_gene_scroll = max(0, self._proc_gene_scroll)
+ if self.current_page == "PROCESS":
+ if self.__proc_gene_view:
+ self.__proc_gene_scroll -= 1
+ self.__proc_gene_scroll = max(0, self.__proc_gene_scroll)
else:
- self._proc_element_scroll -= 1
- self._proc_element_scroll = max(0, self._proc_element_scroll)
+ self.__proc_element_scroll -= 1
+ self.__proc_element_scroll = max(0, self.__proc_element_scroll)
def proc_scroll_right(self):
""" Scroll process data elements or genomes (on PROCESS view) to the
right.
"""
- if self._current_page == "PROCESS":
- if self._proc_gene_view:
- self._proc_gene_scroll += 1
+ if self.current_page == "PROCESS":
+ if self.__proc_gene_view:
+ self.__proc_gene_scroll += 1
else:
- self._proc_element_scroll += 1
- max_scroll = len(self._proc_elements) - 1
- self._proc_element_scroll = min(
- max_scroll, self._proc_element_scroll
+ self.__proc_element_scroll += 1
+ max_scroll = len(self.proc_elements) - 1
+ self.__proc_element_scroll = min(
+ max_scroll, self.__proc_element_scroll
)
def proc_scroll_down(self):
""" Scroll process data table (on PROCESS view) up.
"""
- if self._current_page == "PROCESS":
- self._proc_list_scroll = max(0, self._proc_list_scroll - 1)
+ if self.current_page == "PROCESS":
+ self.proc_list_scroll = max(0, self.proc_list_scroll - 1)
def proc_scroll_up(self):
""" Scroll process data table (on PROCESS view) down.
"""
- if self._current_page == "PROCESS":
- self._proc_list_scroll = min(
- self._sim.lib.sal_proc_get_capacity() - 1,
- self._proc_list_scroll + 1
+ if self.current_page == "PROCESS":
+ self.proc_list_scroll = min(
+ self.__sim.lib.sal_proc_get_capacity() - 1,
+ self.proc_list_scroll + 1
)
def proc_scroll_to(self, proc_id):
""" Scroll process data table (on PROCESS view) to a specific position.
"""
- if self._current_page == "PROCESS":
- if proc_id < self._sim.lib.sal_proc_get_capacity():
- self._proc_list_scroll = proc_id
+ if self.current_page == "PROCESS":
+ if proc_id < self.__sim.lib.sal_proc_get_capacity():
+ self.proc_list_scroll = proc_id
else:
raise RuntimeError("Error: scrolling to invalid process")
def proc_scroll_vertical_reset(self):
""" Scroll process data table (on PROCESS view) back to top.
"""
- if self._current_page == "PROCESS":
- self._proc_list_scroll = 0
+ if self.current_page == "PROCESS":
+ self.proc_list_scroll = 0
def proc_scroll_horizontal_reset(self):
""" Scroll process data or genome table (on PROCESS view) back to the
left.
"""
- if self._current_page == "PROCESS":
- if self._proc_gene_view:
- self._proc_gene_scroll = 0
+ if self.current_page == "PROCESS":
+ if self.__proc_gene_view:
+ self.__proc_gene_scroll = 0
else:
- self._proc_element_scroll = 0
+ self.__proc_element_scroll = 0
def proc_select_prev(self):
""" Select previous process.
"""
- if self._current_page in ["PROCESS", "WORLD"]:
- self._selected_proc -= 1
- self._selected_proc %= self._sim.lib.sal_proc_get_capacity()
+ if self.current_page in ["PROCESS", "WORLD"]:
+ self.selected_proc -= 1
+ self.selected_proc %= self.__sim.lib.sal_proc_get_capacity()
def proc_select_next(self):
""" Select next process.
"""
- if self._current_page in ["PROCESS", "WORLD"]:
- self._selected_proc += 1
- self._selected_proc %= self._sim.lib.sal_proc_get_capacity()
+ if self.current_page in ["PROCESS", "WORLD"]:
+ self.selected_proc += 1
+ self.selected_proc %= self.__sim.lib.sal_proc_get_capacity()
def proc_select_first(self):
""" Select first process on reaper queue.
"""
- if self._current_page in ["PROCESS", "WORLD"]:
- if self._sim.lib.sal_proc_get_count():
- self._selected_proc = self._sim.lib.sal_proc_get_first()
+ if self.current_page in ["PROCESS", "WORLD"]:
+ if self.__sim.lib.sal_proc_get_count():
+ self.selected_proc = self.__sim.lib.sal_proc_get_first()
def proc_select_last(self):
""" Select last process on reaper queue.
"""
- if self._current_page in ["PROCESS", "WORLD"]:
- if self._sim.lib.sal_proc_get_count():
- self._selected_proc = self._sim.lib.sal_proc_get_last()
+ if self.current_page in ["PROCESS", "WORLD"]:
+ if self.__sim.lib.sal_proc_get_count():
+ self.selected_proc = self.__sim.lib.sal_proc_get_last()
def proc_select_by_id(self, proc_id):
""" Select process from given ID.
"""
- if proc_id < self._sim.lib.sal_proc_get_capacity():
- self._selected_proc = proc_id
+ if proc_id < self.__sim.lib.sal_proc_get_capacity():
+ self.selected_proc = proc_id
else:
raise RuntimeError("Error: attempting to select non-existing proc")
@@ -214,48 +219,48 @@ class Printer:
""" Scroll WORLD or PROCESS page so that selected process becomes
visible.
"""
- if self._current_page == "PROCESS":
- self._proc_list_scroll = self._selected_proc
- elif self._current_page == "WORLD":
- if not self._sim.lib.sal_proc_is_free(self._selected_proc):
- index = self._proc_elements.index("mb1a")
- address = self._selected_proc_data[index]
- self._world.scroll_to(address)
+ if self.current_page == "PROCESS":
+ self.proc_list_scroll = self.selected_proc
+ elif self.current_page == "WORLD":
+ if not self.__sim.lib.sal_proc_is_free(self.selected_proc):
+ index = self.proc_elements.index("mb1a")
+ address = self.selected_proc_data[index]
+ self.world.scroll_to(address)
def proc_toggle_gene_view(self):
""" Toggle between data element or genome view on PROCESS page.
"""
- if self._current_page == "PROCESS":
- self._proc_gene_view = not self._proc_gene_view
+ if self.current_page == "PROCESS":
+ self.__proc_gene_view = not self.__proc_gene_view
def run_cursor(self):
""" We can toggle a visible cursor on WORLD view to aid us in selecting
processes.
"""
- if self._current_page == "WORLD" and self._size[1] > World.PADDING:
+ if self.current_page == "WORLD" and self.size[1] > World.PADDING:
curses.curs_set(True)
while True:
- self._curs_y = max(0, min(self._curs_y, self._size[0] - 1))
- self._curs_x = max(World.PADDING, min(
- self._curs_x, self._size[1] - 1
+ self.__curs_y = max(0, min(self.__curs_y, self.size[0] - 1))
+ self.__curs_x = max(World.PADDING, min(
+ self.__curs_x, self.size[1] - 1
))
- self._screen.move(self._curs_y, self._curs_x)
- cmd = self._screen.getch()
+ self.screen.move(self.__curs_y, self.__curs_x)
+ cmd = self.screen.getch()
if cmd in [ord("c"), curses.KEY_RESIZE, Handler.ESCAPE_KEY]:
self.on_resize()
break
elif cmd == curses.KEY_LEFT:
- self._curs_x -= 1
+ self.__curs_x -= 1
elif cmd == curses.KEY_RIGHT:
- self._curs_x += 1
+ self.__curs_x += 1
elif cmd == curses.KEY_DOWN:
- self._curs_y += 1
+ self.__curs_y += 1
elif cmd == curses.KEY_UP:
- self._curs_y -= 1
+ self.__curs_y -= 1
elif cmd == ord("\n"):
- self._proc_select_by_cursor()
+ self.__proc_select_by_cursor()
break
curses.curs_set(False)
@@ -266,18 +271,18 @@ class Printer:
or killing organisms, setting auto-save interval, among other stuff.
"""
# Print a pythonic prompt.
- self._print_line(self._size[0] - 1, ">>> ", scroll=False)
- self._screen.refresh()
+ self.__print_line(self.size[0] - 1, ">>> ", scroll=False)
+ self.screen.refresh()
# Create the console child window. We turn it into a Textbox object in
# order to allow line-editing and extract output easily.
- console = curses.newwin(1, self._size[1] - 5, self._size[0] - 1, 5)
+ console = curses.newwin(1, self.size[1] - 5, self.size[0] - 1, 5)
textbox = curses.textpad.Textbox(console, insert_mode=True)
textbox.stripspaces = True
# Grab a copy of the console history and instantiate a pointer to the
# last element.
- history = self._sim.handler.console_history + [""]
+ history = self.__sim.handler.console_history + [""]
pointer = len(history) - 1
# Nested method reinserts recorded commands from history into console.
@@ -316,21 +321,21 @@ class Printer:
curses.curs_set(False)
# Finally, extract data from console and send to handler.
- self._sim.handler.handle_console(output)
- self._screen.clear()
+ self.__sim.handler.handle_console(output)
+ self.screen.clear()
def show_console_error(self, message):
""" Shows Salis console error messages, if any. These messages might
contain actual python exception output.
"""
- self._print_line(self._size[0] - 1, ">>>", curses.color_pair(
+ self.__print_line(self.size[0] - 1, ">>>", curses.color_pair(
self._pair_error
) | curses.A_BOLD)
- self._screen.refresh()
+ self.screen.refresh()
# We also use a Textbox object, just so that execution gets halted
# until a key gets pressed (even on non-blocking mode).
- console = curses.newwin(1, self._size[1] - 5, self._size[0] - 1, 5)
+ console = curses.newwin(1, self.size[1] - 5, self.size[0] - 1, 5)
textbox = curses.textpad.Textbox(console)
# Curses may raise an exception if printing on the edge of the screen;
@@ -348,74 +353,38 @@ class Printer:
return EXIT
textbox.edit(validator)
- self._screen.clear()
+ self.screen.clear()
def print_page(self):
""" Print current page to screen. We use the previously generated
- '_pages' dictionary to easily associate a label to a Salis function.
+ '__pages' dictionary to easily associate a label to a Salis function.
"""
# Update selected proc data if in WORLD view.
- if self._current_page == "WORLD":
- self._sim.lib.sal_proc_get_proc_data(self._selected_proc, cast(
- self._selected_proc_data, POINTER(c_uint32)
+ if self.current_page == "WORLD":
+ self.__sim.lib.sal_proc_get_proc_data(self.selected_proc, cast(
+ self.selected_proc_data, POINTER(c_uint32)
))
# Print MAIN simulation data.
- self._print_line(
- 1, "SALIS[{}]".format(self._sim.args.file), curses.color_pair(
+ self.__print_line(
+ 1, "SALIS[{}]".format(self.__sim.args.file), curses.color_pair(
self._pair_header
) | curses.A_BOLD
)
- self._print_widget(2, self._main)
+ self.__print_widget(2, self.__main)
# Print data of currently selected page.
- main_lines = len(self._main) + 3
- self._print_header(main_lines, self._current_page)
- self._print_widget(main_lines + 1, self._pages[self._current_page])
+ main_lines = len(self.__main) + 3
+ self.__print_header(main_lines, self.current_page)
+ self.__print_widget(main_lines + 1, self.__pages[self.current_page])
# Print special widgets (WORLD view and PROCESS list).
- if self._current_page == "WORLD":
- self._world.render()
- elif self._current_page == "PROCESS":
- self._print_proc_list()
+ if self.current_page == "WORLD":
+ self.world.render()
+ elif self.current_page == "PROCESS":
+ self.__print_proc_list()
- @property
- def screen(self):
- return self._screen
-
- @property
- def inst_list(self):
- return self._inst_list
-
- @property
- def proc_elements(self):
- return self._proc_elements
-
- @property
- def size(self):
- return self._size
-
- @property
- def current_page(self):
- return self._current_page
-
- @property
- def selected_proc(self):
- return self._selected_proc
-
- @property
- def selected_proc_data(self):
- return self._selected_proc_data
-
- @property
- def proc_list_scroll(self):
- return self._proc_list_scroll
-
- @property
- def world(self):
- return self._world
-
- def _set_colors(self):
+ def __set_colors(self):
""" Define the color pairs for the data printer.
"""
curses.start_color()
@@ -424,7 +393,7 @@ class Printer:
self._pair_selected = self.get_color_pair(curses.COLOR_YELLOW)
self._pair_error = self.get_color_pair(curses.COLOR_RED)
- def _get_screen(self):
+ def __get_screen(self):
""" Prepare and return the main curses window. We also set a shorter
delay when responding to a pressed escape key.
"""
@@ -441,19 +410,19 @@ class Printer:
# We need color support in order to run the printer module.
if curses.has_colors():
- self._set_colors()
+ self.__set_colors()
else:
raise RuntimeError("Error: no color support.")
return screen
- def _get_inst_list(self):
+ def __get_inst_list(self):
""" Parse instruction set from C header file named 'instset.h'. We're
using the keyword 'SALIS_INST' to identify an instruction definition,
so be careful not to use this keyword anywhere else on the headers.
"""
inst_list = []
- inst_file = os.path.join(self._sim.path, "../include/instset.h")
+ inst_file = os.path.join(self.__sim.path, "../include/instset.h")
with open(inst_file, "r") as f:
lines = f.read().splitlines()
@@ -466,14 +435,14 @@ class Printer:
return inst_list
- def _get_proc_elements(self):
+ def __get_proc_elements(self):
""" Parse process structure member variables from C header file named
'process.h'. We're using the keyword 'SALIS_PROC_ELEMENT' to identify
element declarations, so be careful not to use this keyword anywhere
else on the headers.
"""
proc_elem_list = []
- proc_elem_file = os.path.join(self._sim.path, "../include/process.h")
+ proc_elem_file = os.path.join(self.__sim.path, "../include/process.h")
with open(proc_elem_file, "r") as f:
lines = f.read().splitlines()
@@ -493,19 +462,19 @@ class Printer:
return proc_elem_list
- def _get_main(self):
+ def __get_main(self):
""" Generate main set of data fields to be printed. We associate, on a
list object, a label to each Salis function to be called. The following
elements get printed on all pages.
"""
return [
- ("e", "cycle", self._sim.lib.sal_main_get_cycle),
- ("e", "epoch", self._sim.lib.sal_main_get_epoch),
- ("e", "state", lambda: self._sim.state),
- ("e", "autosave", lambda: self._sim.autosave),
+ ("e", "cycle", self.__sim.lib.sal_main_get_cycle),
+ ("e", "epoch", self.__sim.lib.sal_main_get_epoch),
+ ("e", "state", lambda: self.__sim.state),
+ ("e", "autosave", lambda: self.__sim.autosave),
]
- def _get_pages(self):
+ def __get_pages(self):
""" Generate data fields to be printed on each page. We associate, on a
list object, a label to each Salis function to be called. Each list
represents a PAGE. We initialize all pages inside an ordered dictionary
@@ -515,75 +484,75 @@ class Printer:
# The use of nested lambdas is needed to receive updated values.
# Instruction counter widget:
inst_widget = [("e", inst[0], (lambda j: (
- lambda: self._sim.lib.sal_mem_get_inst_count(j)
- ))(i)) for i, inst in enumerate(self._inst_list)]
+ lambda: self.__sim.lib.sal_mem_get_inst_count(j)
+ ))(i)) for i, inst in enumerate(self.inst_list)]
# Evolver module state widget:
state_widget = [("e", "state[{}]".format(i), (lambda j: (
- lambda: self._sim.lib.sal_evo_get_state(j)
+ lambda: self.__sim.lib.sal_evo_get_state(j)
))(i)) for i in range(4)]
# Selected process state widget:
selected_widget = [("p", element, (lambda j: (
- lambda: self._selected_proc_data[j]
- ))(i)) for i, element in enumerate(self._proc_elements)]
+ lambda: self.selected_proc_data[j]
+ ))(i)) for i, element in enumerate(self.proc_elements)]
# With the help of the widgets above, we can declare the PAGES
# dictionary object.
return OrderedDict([
("MEMORY", [
- ("e", "order", self._sim.lib.sal_mem_get_order),
- ("e", "size", self._sim.lib.sal_mem_get_size),
- ("e", "blocks", self._sim.lib.sal_mem_get_block_start_count),
- ("e", "allocated", self._sim.lib.sal_mem_get_allocated_count),
- ("e", "ips", self._sim.lib.sal_mem_get_ip_count),
+ ("e", "order", self.__sim.lib.sal_mem_get_order),
+ ("e", "size", self.__sim.lib.sal_mem_get_size),
+ ("e", "blocks", self.__sim.lib.sal_mem_get_block_start_count),
+ ("e", "allocated", self.__sim.lib.sal_mem_get_allocated_count),
+ ("e", "ips", self.__sim.lib.sal_mem_get_ip_count),
("s", ""),
("h", "INSTRUCTIONS"),
] + inst_widget),
("EVOLVER", [
- ("e", "last", self._sim.lib.sal_evo_get_last_changed_address),
- ("e", "calls", self._sim.lib.sal_evo_get_calls_on_last_cycle),
+ ("e", "last", self.__sim.lib.sal_evo_get_last_changed_address),
+ ("e", "calls", self.__sim.lib.sal_evo_get_calls_on_last_cycle),
] + state_widget),
("PROCESS", [
- ("e", "count", self._sim.lib.sal_proc_get_count),
- ("e", "capacity", self._sim.lib.sal_proc_get_capacity),
- ("e", "first", self._sim.lib.sal_proc_get_first),
- ("e", "last", self._sim.lib.sal_proc_get_last),
+ ("e", "count", self.__sim.lib.sal_proc_get_count),
+ ("e", "capacity", self.__sim.lib.sal_proc_get_capacity),
+ ("e", "first", self.__sim.lib.sal_proc_get_first),
+ ("e", "last", self.__sim.lib.sal_proc_get_last),
("e", "exec",
- self._sim.lib.sal_proc_get_instructions_executed
+ self.__sim.lib.sal_proc_get_instructions_executed
),
]),
("WORLD", [
- ("e", "position", lambda: self._world.pos),
- ("e", "zoom", lambda: self._world.zoom),
- ("e", "selected", lambda: self._selected_proc),
+ ("e", "position", lambda: self.world.pos),
+ ("e", "zoom", lambda: self.world.zoom),
+ ("e", "selected", lambda: self.selected_proc),
("s", ""),
("h", "SELECTED PROC"),
] + selected_widget),
])
- def _print_line(self, ypos, line, attrs=curses.A_NORMAL, scroll=True):
+ def __print_line(self, ypos, line, attrs=curses.A_NORMAL, scroll=True):
""" Print a single line on screen only when it's visible.
"""
if scroll:
- ypos -= self._main_scroll
+ ypos -= self.__main_scroll
- if 0 <= ypos < self._size[0]:
+ if 0 <= ypos < self.size[0]:
# Curses raises an exception each time we print on the screen's
# edge. We can just catch and ignore it.
try:
- line = line[:self._size[1] - 1]
- self._screen.addstr(ypos, 1, line, attrs)
+ line = line[:self.size[1] - 1]
+ self.screen.addstr(ypos, 1, line, attrs)
except curses.error:
pass
- def _print_header(self, ypos, line):
+ def __print_header(self, ypos, line):
""" Print a bold header.
"""
header_attr = curses.A_BOLD | curses.color_pair(self._pair_header)
- self._print_line(ypos, line, header_attr)
+ self.__print_line(ypos, line, header_attr)
- def _print_value(self, ypos, element, value, attr=curses.A_NORMAL):
+ def __print_value(self, ypos, element, value, attr=curses.A_NORMAL):
""" Print a label:value pair.
"""
if type(value) == int:
@@ -591,74 +560,74 @@ class Printer:
# In Salis, UINT32_MAX is used to represent NULL. We print NULL
# as three dashes.
value = "---"
- elif self._print_hex:
+ elif self.__print_hex:
value = hex(value)
line = "{:<10} : {:>10}".format(element, value)
- self._print_line(ypos, line, attr)
+ self.__print_line(ypos, line, attr)
- def _print_proc_element(self, ypos, element, value):
+ def __print_proc_element(self, ypos, element, value):
""" Print elements of currently selected process. We highlight in
YELLOW if the selected process is running.
"""
- if self._sim.lib.sal_proc_is_free(self._selected_proc):
+ if self.__sim.lib.sal_proc_is_free(self.selected_proc):
attr = curses.A_NORMAL
else:
attr = curses.color_pair(self._pair_selected)
- self._print_value(ypos, element, value, attr)
+ self.__print_value(ypos, element, value, attr)
- def _print_widget(self, ypos, widget):
+ def __print_widget(self, ypos, widget):
""" Print a widget (data PAGE) on screen.
"""
for i, element in enumerate(widget):
if element[0] == "s":
continue
elif element[0] == "h":
- self._print_header(i + ypos, element[1])
+ self.__print_header(i + ypos, element[1])
elif element[0] == "e":
- self._print_value(i + ypos, element[1], element[2]())
+ self.__print_value(i + ypos, element[1], element[2]())
elif element[0] == "p":
- self._print_proc_element(i + ypos, element[1], element[2]())
+ self.__print_proc_element(i + ypos, element[1], element[2]())
- def _clear_line(self, ypos):
+ def __clear_line(self, ypos):
""" Clear the specified line.
"""
- if 0 <= ypos < self._size[0]:
- self._screen.move(ypos, 0)
- self._screen.clrtoeol()
+ if 0 <= ypos < self.size[0]:
+ self.screen.move(ypos, 0)
+ self.screen.clrtoeol()
- def _print_proc_data_list(self):
+ def __print_proc_data_list(self):
""" Print list of process data elements in PROCESS page. We can toggle
between printing the data elements or the genomes by pressing the 'g'
key.
"""
# First, print the table header, by extracting element names from the
# previously generated proc element list.
- ypos = len(self._main) + len(self._pages["PROCESS"]) + 5
+ ypos = len(self.__main) + len(self.__pages["PROCESS"]) + 5
header = " | ".join(["{:<10}".format("pidx")] + [
"{:>10}".format(element)
- for element in self._proc_elements[self._proc_element_scroll:]
+ for element in self.proc_elements[self.__proc_element_scroll:]
])
- self._clear_line(ypos)
- self._print_header(ypos, header)
+ self.__clear_line(ypos)
+ self.__print_header(ypos, header)
ypos += 1
- proc_id = self._proc_list_scroll
+ proc_id = self.proc_list_scroll
# Print all proc elements in decimal or hexadecimal format, depending
# on hex-flag being set.
- if self._print_hex:
+ if self.__print_hex:
data_format = lambda x: hex(x)
else:
data_format = lambda x: x
# Lastly, iterate all lines and print as much process data as it fits.
# We can scroll the process data table using the 'wasd' keys.
- while ypos < self._size[0]:
- self._clear_line(ypos)
+ while ypos < self.size[0]:
+ self.__clear_line(ypos)
- if proc_id < self._sim.lib.sal_proc_get_capacity():
- if proc_id == self._selected_proc:
+ if proc_id < self.__sim.lib.sal_proc_get_capacity():
+ if proc_id == self.selected_proc:
# Always highlight the selected process.
attr = curses.color_pair(self._pair_selected)
else:
@@ -666,22 +635,24 @@ class Printer:
# Retrieve a copy of the selected process state and store it in
# a list object.
- proc_data = (c_uint32 * len(self._proc_elements))()
- self._sim.lib.sal_proc_get_proc_data(proc_id, cast(
+ proc_data = (c_uint32 * len(self.proc_elements))()
+ self.__sim.lib.sal_proc_get_proc_data(proc_id, cast(
proc_data, POINTER(c_uint32))
)
# Lastly, assemble and print the next table row.
row = " | ".join(["{:<10}".format(proc_id)] + [
"{:>10}".format(data_format(element))
- for element in proc_data[self._proc_element_scroll:]
+ for element in proc_data[self.__proc_element_scroll:]
])
- self._print_line(ypos, row, attr)
+ self.__print_line(ypos, row, attr)
proc_id += 1
ypos += 1
- def _print_proc_gene_block(self, ypos, gidx, xpos, mbs, mba, ip, sp, pair):
+ def __print_proc_gene_block(
+ self, ypos, gidx, xpos, mbs, mba, ip, sp, pair
+ ):
""" Print a sub-set of a process genome. Namely, on of its two memory
blocks.
"""
@@ -689,21 +660,21 @@ class Printer:
gaddr = mba + gidx
if gaddr == ip:
- attr = curses.color_pair(self._world.pair_sel_ip)
+ attr = curses.color_pair(self.world.pair_sel_ip)
elif gaddr == sp:
- attr = curses.color_pair(self._world.pair_sel_sp)
+ attr = curses.color_pair(self.world.pair_sel_sp)
else:
attr = curses.color_pair(pair)
# Retrieve instruction from memory and transform it to correct
# symbol.
- inst = self._sim.lib.sal_mem_get_inst(gaddr)
- symb = self._inst_list[inst][1]
+ inst = self.__sim.lib.sal_mem_get_inst(gaddr)
+ symb = self.inst_list[inst][1]
# Curses raises an exception each time we print on the screen's
# edge. We can just catch and ignore it.
try:
- self._screen.addch(ypos, xpos, symb, attr)
+ self.screen.addch(ypos, xpos, symb, attr)
except curses.error:
pass
@@ -712,48 +683,48 @@ class Printer:
return xpos
- def _print_proc_gene(self, ypos, proc_id):
+ def __print_proc_gene(self, ypos, proc_id):
""" Print a single process genome on the genome table. We use the same
colors to represent memory blocks, IP and SP of each process, as those
used to represent the selected process on WORLD view.
"""
# There's nothing to print if process is free.
- if self._sim.lib.sal_proc_is_free(proc_id):
+ if self.__sim.lib.sal_proc_is_free(proc_id):
return
# Process is alive. Retrieve a copy of the current process state and
# store it in a list object.
- proc_data = (c_uint32 * len(self._proc_elements))()
- self._sim.lib.sal_proc_get_proc_data(proc_id, cast(
+ proc_data = (c_uint32 * len(self.proc_elements))()
+ self.__sim.lib.sal_proc_get_proc_data(proc_id, cast(
proc_data, POINTER(c_uint32))
)
# Let's extract all data of interest.
- mb1a = proc_data[self._proc_elements.index("mb1a")]
- mb1s = proc_data[self._proc_elements.index("mb1s")]
- mb2a = proc_data[self._proc_elements.index("mb2a")]
- mb2s = proc_data[self._proc_elements.index("mb2s")]
- ip = proc_data[self._proc_elements.index("ip")]
- sp = proc_data[self._proc_elements.index("sp")]
+ mb1a = proc_data[self.proc_elements.index("mb1a")]
+ mb1s = proc_data[self.proc_elements.index("mb1s")]
+ mb2a = proc_data[self.proc_elements.index("mb2a")]
+ mb2s = proc_data[self.proc_elements.index("mb2s")]
+ ip = proc_data[self.proc_elements.index("ip")]
+ sp = proc_data[self.proc_elements.index("sp")]
# Always print MAIN memory block (mb1) first (on the left side). That
# way we can keep most of our attention on the parent.
- xpos = self._print_proc_gene_block(
- ypos, self._proc_gene_scroll, 14, mb1s, mb1a, ip, sp,
- self._world.pair_sel_mb1
+ xpos = self.__print_proc_gene_block(
+ ypos, self.__proc_gene_scroll, 14, mb1s, mb1a, ip, sp,
+ self.world.pair_sel_mb1
)
# Reset gene counter and print child memory block, if it exists.
- if mb1s < self._proc_gene_scroll:
- gidx = self._proc_gene_scroll - mb1s
+ if mb1s < self.__proc_gene_scroll:
+ gidx = self.__proc_gene_scroll - mb1s
else:
gidx = 0
- self._print_proc_gene_block(
- ypos, gidx, xpos, mb2s, mb2a, ip, sp, self._world.pair_sel_mb2
+ self.__print_proc_gene_block(
+ ypos, gidx, xpos, mb2s, mb2a, ip, sp, self.world.pair_sel_mb2
)
- def _print_proc_gene_list(self):
+ def __print_proc_gene_list(self):
""" Print list of process genomes in PROCESS page. We can toggle
between printing the genomes or the data elements by pressing the 'g'
key.
@@ -761,22 +732,22 @@ class Printer:
# First, print the table header. We print the current gene-scroll
# position for easy reference. Return back to zero scroll with the 'A'
# key.
- ypos = len(self._main) + len(self._pages["PROCESS"]) + 5
+ ypos = len(self.__main) + len(self.__pages["PROCESS"]) + 5
header = "{:<10} | genes {} -->".format(
- "pidx", self._proc_gene_scroll
+ "pidx", self.__proc_gene_scroll
)
- self._clear_line(ypos)
- self._print_header(ypos, header)
+ self.__clear_line(ypos)
+ self.__print_header(ypos, header)
ypos += 1
- proc_id = self._proc_list_scroll
+ proc_id = self.proc_list_scroll
# Iterate all lines and print as much genetic data as it fits. We can
# scroll the gene data table using the 'wasd' keys.
- while ypos < self._size[0]:
- self._clear_line(ypos)
+ while ypos < self.size[0]:
+ self.__clear_line(ypos)
- if proc_id < self._sim.lib.sal_proc_get_capacity():
- if proc_id == self._selected_proc:
+ if proc_id < self.__sim.lib.sal_proc_get_capacity():
+ if proc_id == self.selected_proc:
# Always highlight the selected process.
attr = curses.color_pair(self._pair_selected)
else:
@@ -784,50 +755,50 @@ class Printer:
# Assemble and print the next table row.
row = "{:<10} |".format(proc_id)
- self._print_line(ypos, row, attr)
- self._print_proc_gene(ypos, proc_id)
+ self.__print_line(ypos, row, attr)
+ self.__print_proc_gene(ypos, proc_id)
proc_id += 1
ypos += 1
- def _print_proc_list(self):
+ def __print_proc_list(self):
""" Print list of process genomes or process data elements in PROCESS
page. We can toggle between printing the genomes or the data elements
by pressing the 'g' key.
"""
- if self._proc_gene_view:
- self._print_proc_gene_list()
+ if self.__proc_gene_view:
+ self.__print_proc_gene_list()
else:
- self._print_proc_data_list()
+ self.__print_proc_data_list()
- def _proc_select_by_cursor(self):
+ def __proc_select_by_cursor(self):
""" Select process located on address under cursor, if any exists.
"""
# First, calculate address under cursor.
- ypos = self._curs_y
- xpos = self._curs_x - World.PADDING
- line_size = self._size[1] - World.PADDING
- address = self._world.pos + (
- ((ypos * line_size) + xpos) * self._world.zoom
+ ypos = self.__curs_y
+ xpos = self.__curs_x - World.PADDING
+ line_size = self.size[1] - World.PADDING
+ address = self.world.pos + (
+ ((ypos * line_size) + xpos) * self.world.zoom
)
# Now, iterate all living processes and try to find one that owns the
# calculated address.
- if self._sim.lib.sal_mem_is_address_valid(address):
- for proc_id in range(self._sim.lib.sal_proc_get_capacity()):
- if not self._sim.lib.sal_proc_is_free(proc_id):
- proc_data = (c_uint32 * len(self._proc_elements))()
- self._sim.lib.sal_proc_get_proc_data(proc_id, cast(
+ if self.__sim.lib.sal_mem_is_address_valid(address):
+ for proc_id in range(self.__sim.lib.sal_proc_get_capacity()):
+ if not self.__sim.lib.sal_proc_is_free(proc_id):
+ proc_data = (c_uint32 * len(self.proc_elements))()
+ self.__sim.lib.sal_proc_get_proc_data(proc_id, cast(
proc_data, POINTER(c_uint32))
)
- mb1a = proc_data[self._proc_elements.index("mb1a")]
- mb1s = proc_data[self._proc_elements.index("mb1s")]
- mb2a = proc_data[self._proc_elements.index("mb2a")]
- mb2s = proc_data[self._proc_elements.index("mb2s")]
+ mb1a = proc_data[self.proc_elements.index("mb1a")]
+ mb1s = proc_data[self.proc_elements.index("mb1s")]
+ mb2a = proc_data[self.proc_elements.index("mb2a")]
+ mb2s = proc_data[self.proc_elements.index("mb2s")]
if (
mb1a <= address < (mb1a + mb1s) or
mb2a <= address < (mb2a + mb2s)
):
- self._selected_proc = proc_id
+ self.selected_proc = proc_id
break
diff --git a/bin/salis.py b/bin/salis.py
index 6dd82b0..25c6526 100755
--- a/bin/salis.py
+++ b/bin/salis.py
@@ -36,28 +36,32 @@ class Salis:
and parsed with the 'argparse' module. Library is loaded with 'CDLL'
and C headers are parsed to detect function argument and return types.
"""
- self._path = self._get_path()
- self._args = self._parse_args()
- self._log = self._open_log_file()
- self._save_file_path = self._get_save_file_path()
- self._common_pipe = self._get_common_pipe()
- self._lib = self._parse_lib()
- self._printer = Printer(self)
- self._handler = Handler(self)
- self._state = "paused"
- self._autosave = "---"
- self._exit = False
+ # Before declaring any other privates, let's define the absolute path
+ # and parse CLI arguments.
+ self.path = self.__get_path()
+ self.args = self.__parse_args()
+
+ # Now we can declare all other public and private members.
+ self.__log = self.__open_log_file()
+ self.__exit = False
+ self.save_file_path = self.__get_save_file_path()
+ self.common_pipe = self.__get_common_pipe()
+ self.lib = self.__parse_lib()
+ self.printer = Printer(self)
+ self.handler = Handler(self)
+ self.state = "paused"
+ self.autosave = "---"
# Based on CLI arguments, initialize a new Salis simulation or load
# existing one from file.
- if self._args.action == "new":
- self._lib.sal_main_init(
- self._args.order, self._common_pipe.encode("utf-8")
+ if self.args.action == "new":
+ self.lib.sal_main_init(
+ self.args.order, self.common_pipe.encode("utf-8")
)
- elif self._args.action == "load":
- self._lib.sal_main_load(
- self._save_file_path.encode("utf-8"),
- self._common_pipe.encode("utf-8")
+ elif self.args.action == "load":
+ self.lib.sal_main_load(
+ self.save_file_path.encode("utf-8"),
+ self.common_pipe.encode("utf-8")
)
def __del__(self):
@@ -66,62 +70,62 @@ class Salis:
# In case an error occurred early during initialization, checks whether
# Salis has been initialized correctly before attempting to shut it
# down.
- if hasattr(self, "_lib") and hasattr(self._lib, "sal_main_quit"):
- if self._lib.sal_main_is_init():
- self._lib.sal_main_quit()
+ if hasattr(self, "__lib") and hasattr(self.lib, "sal_main_quit"):
+ if self.lib.sal_main_is_init():
+ self.lib.sal_main_quit()
# If simulation ended correctly, 'error.log' should be empty. Delete
# file it exists and its empty.
if (
- hasattr(self, "_log") and
- os.path.isfile(self._log) and
- os.stat(self._log).st_size == 0
+ hasattr(self, "_Salis__log") and
+ os.path.isfile(self.__log) and
+ os.stat(self.__log).st_size == 0
):
- os.remove(self._log)
+ os.remove(self.__log)
def run(self):
""" Runs main simulation loop. Curses may be placed on non-blocking
mode, which allows simulation to run freely while still listening to
user input.
"""
- while not self._exit:
- self._printer.print_page()
- self._handler.process_cmd(self._printer.get_cmd())
+ while not self.__exit:
+ self.printer.print_page()
+ self.handler.process_cmd(self.printer.get_cmd())
# If in non-blocking mode, re-print data once every 15
# milliseconds.
- if self._state == "running":
+ if self.state == "running":
end = time.time() + 0.015
while time.time() < end:
- self._lib.sal_main_cycle()
+ self.lib.sal_main_cycle()
self.check_autosave()
def toggle_state(self):
""" Toggle between 'paused' and 'running' states. On 'running' curses
gets placed in non-blocking mode.
"""
- if self._state == "paused":
- self._state = "running"
- self._printer.set_nodelay(True)
+ if self.state == "paused":
+ self.state = "running"
+ self.printer.set_nodelay(True)
else:
- self._state = "paused"
- self._printer.set_nodelay(False)
+ self.state = "paused"
+ self.printer.set_nodelay(False)
def rename(self, new_name):
""" Give the simulation a new name.
"""
- self._args.file = new_name
- self._save_file_path = self._get_save_file_path()
+ self.args.file = new_name
+ self.save_file_path = self.__get_save_file_path()
def set_autosave(self, interval):
""" Set the simulation's auto-save interval. When set to zero, auto
saving is disabled,
"""
if not interval:
- self._autosave = "---"
+ self.autosave = "---"
else:
- self._autosave = interval
+ self.autosave = interval
def check_autosave(self):
""" Save simulation to './sims/auto/*' whenever the autosave interval
@@ -129,76 +133,40 @@ class Salis:
>>> ./sims/auto/<file-name>.<sim-epoch>.<sim-cycle>.auto
"""
- if self._autosave != "---":
- if not self._lib.sal_main_get_cycle() % self._autosave:
- auto_path = os.path.join(self._path, "sims/auto", ".".join([
- self._args.file,
- "{:08x}".format(self._lib.sal_main_get_epoch()),
- "{:08x}".format(self._lib.sal_main_get_cycle()),
+ if self.autosave != "---":
+ if not self.lib.sal_main_get_cycle() % self.autosave:
+ auto_path = os.path.join(self.path, "sims/auto", ".".join([
+ self.args.file,
+ "{:08x}".format(self.lib.sal_main_get_epoch()),
+ "{:08x}".format(self.lib.sal_main_get_cycle()),
"auto"
]))
- self._lib.sal_main_save(auto_path.encode("utf-8"))
+ self.lib.sal_main_save(auto_path.encode("utf-8"))
def exit(self):
""" Signal we want to exit the simulator.
"""
- self._exit = True
+ self.__exit = True
- @property
- def path(self):
- return self._path
-
- @property
- def save_file_path(self):
- return self._save_file_path
-
- @property
- def common_pipe(self):
- return self._common_pipe
-
- @property
- def args(self):
- return self._args
-
- @property
- def lib(self):
- return self._lib
-
- @property
- def printer(self):
- return self._printer
-
- @property
- def handler(self):
- return self._handler
-
- @property
- def state(self):
- return self._state
-
- @property
- def autosave(self):
- return self._autosave
-
- def _get_path(self):
+ def __get_path(self):
""" Retrieve the absolute path of this script. We need to do this in
order to detect the './lib', './sims' and './genomes' subdirectories.
"""
return os.path.dirname(__file__)
- def _get_save_file_path(self):
+ def __get_save_file_path(self):
""" Retrieve the absolute path of the file to which we will save this
simulation when we exit Salis.
"""
- return os.path.join(self._path, "sims", self._args.file)
+ return os.path.join(self.path, "sims", self.args.file)
- def _get_common_pipe(self):
+ def __get_common_pipe(self):
""" Get absolute path of the common pipe. This FIFO object may be used
by concurrent Salis simulations to share data between themselves.
"""
- return os.path.join(self._path, "common/pipe")
+ return os.path.join(self.path, "common/pipe")
- def _parse_args(self):
+ def __parse_args(self):
""" Parse command-line arguments with the 'argparse' module. To learn
more about each command, invoke the simulator in one of the following
ways:
@@ -253,7 +221,7 @@ class Salis:
if args.order not in range(1, 32):
parser.error("Order must be an integer between 1 and 31")
else:
- savefile = os.path.join(self._path, "sims", args.file)
+ savefile = os.path.join(self.path, "sims", args.file)
# No save-file with given name has been detected.
if not os.path.isfile(savefile):
@@ -263,15 +231,15 @@ class Salis:
return args
- def _open_log_file(self):
+ def __open_log_file(self):
""" Create a log file to store errors on. It will get deleted if no
errors are detected.
"""
- log_file = os.path.join(self._path, "error.log")
+ log_file = os.path.join(self.path, "error.log")
sys.stderr = open(log_file, "w")
return log_file
- def _parse_lib(self):
+ def __parse_lib(self):
""" Dynamically parse the Salis library C header files. We do this in
order to more easily set the correct input/output types of all loaded
functions. C functions to be parsed must be declared in a '.h' file
@@ -282,8 +250,8 @@ class Salis:
Note to developers: the 'SALIS_API' keyword should *NOT* be used
anywhere else in the header files (not even in comments)!
"""
- lib = CDLL(os.path.join(self._path, "lib/libsalis.so"))
- include_dir = os.path.join(self._path, "../include")
+ lib = CDLL(os.path.join(self.path, "lib/libsalis.so"))
+ include_dir = os.path.join(self.path, "../include")
c_includes = [
os.path.join(include_dir, f)
for f in os.listdir(include_dir)
diff --git a/bin/world.py b/bin/world.py
index 60fd427..99b7724 100644
--- a/bin/world.py
+++ b/bin/world.py
@@ -21,11 +21,11 @@ class World:
""" World constructor. We link to the printer and main simulation
classes. We also setup the colors for rendering the world.
"""
- self._printer = printer
- self._sim = sim
- self._pos = 0
- self._zoom = 1
- self._set_world_colors()
+ self.__printer = printer
+ self.__sim = sim
+ self.__set_world_colors()
+ self.pos = 0
+ self.zoom = 1
def render(self):
""" Function for rendering the world. We get a pre-rendered buffer from
@@ -33,24 +33,24 @@ class World:
to assemble the world image in Python.
"""
# Window is so narrow that world is not visible.
- if self._printer.size[1] <= self.PADDING:
+ if self.__printer.size[1] <= self.PADDING:
return
# Get pre-rendered image from Salis' memory module.
- line_width = self._printer.size[1] - self.PADDING
- print_area = self._printer.size[0] * line_width
+ line_width = self.__printer.size[1] - self.PADDING
+ print_area = self.__printer.size[0] * line_width
c_buffer = (c_uint8 * print_area)()
- self._sim.lib.sal_mem_render_image(
- self._pos, self._zoom, print_area, cast(c_buffer, POINTER(c_uint8))
+ self.__sim.lib.sal_mem_render_image(
+ self.pos, self.zoom, print_area, cast(c_buffer, POINTER(c_uint8))
)
# Get data elements of selected process, if it's running, and store
# them into a convenient dict object.
- if self._sim.lib.sal_proc_is_free(self._printer.selected_proc):
+ if self.__sim.lib.sal_proc_is_free(self.__printer.selected_proc):
sel_data = None
else:
- out_data = self._printer.selected_proc_data
- out_elem = self._printer.proc_elements
+ out_data = self.__printer.selected_proc_data
+ out_elem = self.__printer.proc_elements
sel_data = {
"ip": out_data[out_elem.index("ip")],
"sp": out_data[out_elem.index("sp")],
@@ -65,16 +65,16 @@ class World:
# currently written into memory.
bidx = 0
- for y in range(self._printer.size[0]):
+ for y in range(self.__printer.size[0]):
for x in range(line_width):
xpad = x + self.PADDING
- addr = self._pos + (self._zoom * bidx)
- symb, attr = self._render_cell(c_buffer[bidx], addr, sel_data)
+ addr = self.pos + (self.zoom * bidx)
+ symb, attr = self.__render_cell(c_buffer[bidx], addr, sel_data)
# Curses raises an exception when printing on the edge of the
# screen; we can just ignore it.
try:
- self._printer.screen.addch(y, xpad, symb, attr)
+ self.__printer.screen.addch(y, xpad, symb, attr)
except curses.error:
pass
@@ -83,157 +83,133 @@ class World:
def zoom_out(self):
""" Zoom out by a factor of 2 (zoom *= 2).
"""
- if self._is_world_editable():
- self._zoom = min(self._zoom * 2, self._get_max_zoom())
+ if self.__is_world_editable():
+ self.zoom = min(self.zoom * 2, self.__get_max_zoom())
def zoom_in(self):
""" Zoom in by a factor of 2 (zoom //= 2).
"""
- if self._is_world_editable():
- self._zoom = max(self._zoom // 2, 1)
+ if self.__is_world_editable():
+ self.zoom = max(self.zoom // 2, 1)
def zoom_reset(self):
""" Reset zoom to a valid value on certain events (i.e. during terminal
resizing).
"""
- self._zoom = min(self._zoom, self._get_max_zoom())
+ self.zoom = min(self.zoom, self.__get_max_zoom())
def pan_left(self):
""" Pan world to the left (pos -= zoom).
"""
- if self._is_world_editable():
- self._pos = max(self._pos - self._zoom, 0)
+ if self.__is_world_editable():
+ self.pos = max(self.pos - self.zoom, 0)
def pan_right(self):
""" Pan world to the right (pos += zoom).
"""
- if self._is_world_editable():
- max_pos = self._sim.lib.sal_mem_get_size() - 1
- self._pos = min(self._pos + self._zoom, max_pos)
+ if self.__is_world_editable():
+ max_pos = self.__sim.lib.sal_mem_get_size() - 1
+ self.pos = min(self.pos + self.zoom, max_pos)
def pan_down(self):
""" Pan world downward (pos += zoom * columns).
"""
- if self._is_world_editable():
- self._pos = max(self._pos - self._get_line_area(), 0)
+ if self.__is_world_editable():
+ self.pos = max(self.pos - self.__get_line_area(), 0)
def pan_up(self):
""" Pan world upward (pos -= zoom * columns).
"""
- if self._is_world_editable():
- max_pos = self._sim.lib.sal_mem_get_size() - 1
- self._pos = min(self._pos + self._get_line_area(), max_pos)
+ if self.__is_world_editable():
+ max_pos = self.__sim.lib.sal_mem_get_size() - 1
+ self.pos = min(self.pos + self.__get_line_area(), max_pos)
def pan_reset(self):
""" Set world position to zero.
"""
- if self._is_world_editable():
- self._pos = 0
+ if self.__is_world_editable():
+ self.pos = 0
def scroll_to(self, pos):
""" Move world pos to a specified position.
"""
- if self._is_world_editable():
- if self._sim.lib.sal_mem_is_address_valid(pos):
- self._pos = pos
+ if self.__is_world_editable():
+ if self.__sim.lib.sal_mem_is_address_valid(pos):
+ self.pos = pos
else:
raise RuntimeError("Error: scrolling to an invalid address")
- @property
- def pos(self):
- return self._pos
-
- @property
- def zoom(self):
- return self._zoom
-
- @property
- def pair_sel_mb2(self):
- return self._pair_sel_mb2
-
- @property
- def pair_sel_mb1(self):
- return self._pair_sel_mb1
-
- @property
- def pair_sel_sp(self):
- return self._pair_sel_sp
-
- @property
- def pair_sel_ip(self):
- return self._pair_sel_ip
-
- def _set_world_colors(self):
+ def __set_world_colors(self):
""" Define color pairs for rendering the world. Each color has a
special meaning, referring to the selected process IP, SP and memory
blocks, or to bit flags currently set on rendered cells.
"""
- self._pair_free = self._printer.get_color_pair(
+ self.pair_free = self.__printer.get_color_pair(
curses.COLOR_BLUE
)
- self._pair_alloc = self._printer.get_color_pair(
+ self.pair_alloc = self.__printer.get_color_pair(
curses.COLOR_BLACK, curses.COLOR_BLUE
)
- self._pair_mbstart = self._printer.get_color_pair(
+ self.pair_mbstart = self.__printer.get_color_pair(
curses.COLOR_BLACK, curses.COLOR_CYAN
)
- self._pair_ip = self._printer.get_color_pair(
+ self.pair_ip = self.__printer.get_color_pair(
curses.COLOR_BLACK, curses.COLOR_WHITE
)
- self._pair_sel_mb2 = self._printer.get_color_pair(
+ self.pair_sel_mb2 = self.__printer.get_color_pair(
curses.COLOR_BLACK, curses.COLOR_GREEN
)
- self._pair_sel_mb1 = self._printer.get_color_pair(
+ self.pair_sel_mb1 = self.__printer.get_color_pair(
curses.COLOR_BLACK, curses.COLOR_YELLOW
)
- self._pair_sel_sp = self._printer.get_color_pair(
+ self.pair_sel_sp = self.__printer.get_color_pair(
curses.COLOR_BLACK, curses.COLOR_MAGENTA
)
- self._pair_sel_ip = self._printer.get_color_pair(
+ self.pair_sel_ip = self.__printer.get_color_pair(
curses.COLOR_BLACK, curses.COLOR_RED
)
- def _render_cell(self, byte, addr, sel_data=None):
+ def __render_cell(self, byte, addr, sel_data=None):
""" Render a single cell on the WORLD view. All cells are rendered by
interpreting the values coming in from the buffer. We overlay special
colors for representing the selected organism's state, on top of the
more common colors used to represent memory state.
"""
# Paint black all cells that are out of memory bounds.
- if not self._sim.lib.sal_mem_is_address_valid(addr):
+ if not self.__sim.lib.sal_mem_is_address_valid(addr):
return " ", curses.A_NORMAL
# Check if cell contains part of the currently selected process.
if sel_data:
- top_addr = addr + self._zoom
+ top_addr = addr + self.zoom
top_mb1a = sel_data["mb1a"] + sel_data["mb1s"]
top_mb2a = sel_data["mb2a"] + sel_data["mb2s"]
if addr <= sel_data["ip"] < top_addr:
- pair = self._pair_sel_ip
+ pair = self.pair_sel_ip
elif addr <= sel_data["sp"] < top_addr:
- pair = self._pair_sel_sp
+ pair = self.pair_sel_sp
elif top_addr > sel_data["mb1a"] and top_mb1a > addr:
- pair = self._pair_sel_mb1
+ pair = self.pair_sel_mb1
elif top_addr > sel_data["mb2a"] and top_mb2a > addr:
- pair = self._pair_sel_mb2
+ pair = self.pair_sel_mb2
# No pair has been selected yet; select pair based on bit-flags.
if not "pair" in locals():
if byte >= 0x80:
- pair = self._pair_ip
+ pair = self.pair_ip
elif byte >= 0x40:
- pair = self._pair_mbstart
+ pair = self.pair_mbstart
elif byte >= 0x20:
- pair = self._pair_alloc
+ pair = self.pair_alloc
else:
- pair = self._pair_free
+ pair = self.pair_free
# Select symbol to represent instructions currently on cell.
inst = byte % 32
- if self._zoom == 1:
- symb = self._printer.inst_list[inst][1]
+ if self.zoom == 1:
+ symb = self.__printer.inst_list[inst][1]
elif inst > 16:
symb = ":"
else:
@@ -242,36 +218,36 @@ class World:
# Return tuple containing our post-redered cell.
return symb, curses.color_pair(pair)
- def _get_max_zoom(self):
+ def __get_max_zoom(self):
""" Calculate maximum needed zoom so that the entire world fits on the
terminal window.
"""
max_zoom = 1
- line_size = self._printer.size[1] - self.PADDING
- coverage = self._printer.size[0] * line_size
+ line_size = self.__printer.size[1] - self.PADDING
+ coverage = self.__printer.size[0] * line_size
# We fix a maximum zoom level; otherwise, program may halt on extreme
# zoom levels.
while (
- (coverage * max_zoom) < self._sim.lib.sal_mem_get_size() and
+ (coverage * max_zoom) < self.__sim.lib.sal_mem_get_size() and
max_zoom < 2 ** 16
):
max_zoom *= 2
return max_zoom
- def _is_world_editable(self):
+ def __is_world_editable(self):
""" For this to return True, printer's current page must be WORLD page.
Additionally, the WORLD panel must be visible on the terminal window
(i.e. curses.COLS > data_margin).
"""
- correct_page = self._printer.current_page == "WORLD"
- correct_size = self._printer.size[1] > self.PADDING
+ correct_page = self.__printer.current_page == "WORLD"
+ correct_size = self.__printer.size[1] > self.PADDING
return correct_page and correct_size
- def _get_line_area(self):
+ def __get_line_area(self):
""" Return amount of bytes contained in a printed WORLD line.
"""
- line_size = self._printer.size[1] - self.PADDING
- line_area = self._zoom * line_size
+ line_size = self.__printer.size[1] - self.PADDING
+ line_area = self.zoom * line_size
return line_area