circuits: refactor to avoid attribute name-clashes with pygame, and move instance...
authorTJ <git@iam.tj>
Mon, 18 Nov 2013 13:13:47 +0000 (13:13 +0000)
committerTJ <git@iam.tj>
Mon, 18 Nov 2013 13:13:47 +0000 (13:13 +0000)
circuits.py

index 936982e..08d7f32 100644 (file)
@@ -12,21 +12,30 @@ from library import enum
 
 
 class TraceSegment:
- """ Models a straight line segment of a complete Trace """
- #          N    NE    E    SE    S     SW    W     NW
- angles = ( 0 ,  45 ,  90,  135,  180,  225,  270,  315)
+ """ Models a straight line segment of a complete Trace and any associated Via (through-hole)
+  A segment may only have at most 1 Via
 
- # references to an attached Via and its position
- via = None
- via_position = None
+  The direction is limited to 8 points on the compass
+
+  The length is an arbitrary multiplier. The game itself will decide how many pixels represent
+  the minimum length of a segment. Suggestion is that the value be the minimum width of cells in
+  the game-map matrix if a tile-based model of the playing area is in use.
+ """
 
  def __init__(self, length=1, direction=library.directions.E, via=None, via_position=library.positions.NONE):
   """ default segment runs for one game tile length left-to-right
-   length:        number of game 'tiles' this segment covers
-   direction:     enum directions
-   via:           Via
-   via_position:  enum positions
+   length:        number of game 'tiles' this segment covers (default = 1)
+   direction:     enum directions (default = East)
+   via:           Via (default = None)
+   via_position:  enum positions (default = NONE)
   """
+  #          N    NE    E    SE    S     SW    W     NW
+  self.angles = ( 0 ,  45 ,  90,  135,  180,  225,  270,  315)
+
+  # references to an attached Via and its position
+  self.via = None
+  self.via_position = None
+
   # ensure all values are legal before doing any assignment
   if not direction in library.directions.reverse_mapping:
    # 'direction' is an index enum, so ensure it exists in the enum before using it to select the angle
@@ -67,25 +76,15 @@ class TraceSegment:
 
 class Trace:
  """ Models a single circuit trace made up of multiple segments """
- segments = list() # ordered list of one or more TraceSegments
- colours = dict()
- # colours['metal'] = (192, 192, 192) # colours of the trace
- # colours['shadow'] = (64, 64, 64)
- # colours['reflection'] = (255, 255, 255)
 
- def check_range(self, colour):
-  """ Ensure a colour value is legal """
-  if not (type(colour) == tuple or type(colour) == int):
-   raise TypeError('colour expeted to be tuple or int')
-  elif not len(colour) == 3:
-   raise ValueError('colour tuples require exactly 3 items (RGB)')
+ def __init__(self, metal=(192, 192, 192), shadow=(64, 64, 64), reflection=(255, 255, 255), segments=None):
+  self.segments = list() # ordered list of one or more TraceSegments
+  self.colours = dict()
 
-  if type(colour) == int:
-   return colour >= 0 and colour <= 255
-  else:
-   return self.check_range(colour[0]) and self.check_range(colour[1]) and self.check_range(colour[2])
+  # colours['metal'] = (192, 192, 192) # colours of the trace
+  # colours['shadow'] = (64, 64, 64)
+  # colours['reflection'] = (255, 255, 255)
 
- def __init__(self, metal=(192, 192, 192), shadow=(64, 64, 64), reflection=(255, 255, 255), segments=None):
   # set the colours of the trace to give a 3D raised appearance
   if metal and check_range(metal): self.colours['metal'] = metal
   if shadow and check_range(shadow): self.colours['shadow'] = shadow
@@ -100,6 +99,18 @@ class Trace:
    via = None
    via_position = library.positions.NONE
 
+ def check_range(self, colour):
+  """ Ensure a colour value is legal """
+  if not (type(colour) == tuple or type(colour) == int):
+   raise TypeError('colour expeted to be tuple or int')
+  elif not len(colour) == 3:
+   raise ValueError('colour tuples require exactly 3 items (RGB)')
+
+  if type(colour) == int:
+   return colour >= 0 and colour <= 255
+  else:
+   return self.check_range(colour[0]) and self.check_range(colour[1]) and self.check_range(colour[2])
+
  def draw(self, surface):
   """ Draw the Trace onto pygame.Surface """
   return
@@ -107,30 +118,39 @@ class Trace:
 
 class Via:
  """ Models a through-hole otherwise known as a Via """
- trace = None # the Trace this via is attached to
- linked = None # the Via this via links to
+
+ def __init__(self):
+  self.trace = None # the Trace this via is attached to
+  self.linked = None # the Via this via links to
 
 
 class Bus:
  """ Group of traces all going in the same direction """
- width = 8 # default is an 8-bit bus
- group = None
 
  def __init__(self, buswidth=8):
   """ Create a new bus consisting of 'buswidth' traces """
+  self.BUSWIDTH_MAX = 32
+  if not (buswidth >= 1 and buswidth <= self.BUSWIDTH_MAX):
+   raise ValueError('bus width out of range')
+
+  self.width = 8 # default is an 8-bit bus
+  self.group = None
 
 
 class IntegratedCircuit:
  """ semiconductor component """
- pins = list() # index = pin number, value = signal name
+
+ def __init__(self):
+  self.pins = list() # index = pin number, value = signal name
 
 
 class DualInLine(IntegratedCircuit):
  """ Dual In-Line Integrated Circuit """
- sides = 2
- qty = 0
 
  def __init__(self, pin_qty):
+  self.sides = 2
+  self.qty = 0
+
   if not (pin_qty > 0 and pin_qty % 2 == 0):
    raise ValueError('DIL ICs have even number of pins')
  
@@ -140,12 +160,12 @@ class DualInLine(IntegratedCircuit):
 
 class Gate:
  """ Models a single logic gate """
- types = None
- inputs = list()
- output = False
- gate_type = None
 
  def __init__(self, gate_type, inputs=None):
+  self.inputs = list()
+  self.output = False
+  self.gate_type = None
+  
   if not gate_type in library.gates:
    raise IndexError()
 
@@ -159,9 +179,9 @@ class Gate:
  
   self.inputs = inputs
   self.input_max = len(self.inputs)
-  self.update()
+  self.update_state()
 
- def update(self):
+ def update_state(self):
   """ Needs to be over-ridden in derived classes """
   return
 
@@ -173,7 +193,7 @@ class Gate:
    raise TypeError('Boolean expected')
 
   self.inputs[input] = value
-  self.update()
+  self.update_state()
 
  def get_output(self):
   return self.output
@@ -185,10 +205,8 @@ class Gate:
 
 # Derive each of the common logic gate types
 class GateAND(Gate):
- def __init__(self, inputs=None):
-  Gate.__init__(library.gates.AND, self.min_inputs(inputs, 2))
 
- def update(self):
+ def update_state(self):
   self.output = self.inputs[0]
   for i in range(1, self.input_max):
    self.output &= self.inputs[i] # AND
@@ -198,7 +216,7 @@ class GateOR(Gate):
  def __init__(self, inputs=None):
   Gate.__init__(library.gates.OR, self.min_inputs(inputs, 2))
 
- def update(self):
+ def update_state(self):
   self.output = self.inputs[0]
   for i in range (1, self.input_max):
    self.output |= self.inputs[i] # OR
@@ -208,7 +226,7 @@ class GateXOR(Gate):
  def __init__(self, inputs=None):
   Gate.__init__(library.gates.XOR, self.min_inputs(inputs, 2))
 
- def update(self):
+ def update_state(self):
   self.output = self.inputs[0]
   for i in range (1, self.input_max):
    self.output ^= self.inputs[i] # XOR
@@ -220,7 +238,7 @@ class GateNOT(Gate):
    raise ValueError('NOT must have only 1 input')
   Gate.__init__(library.gates.NOT, inputs)
 
- def update(self):
+ def update_state(self):
   self.output = ~self.inputs[0] # invert
 
 
@@ -228,7 +246,7 @@ class GateNAND(Gate):
  def __init__(self, inputs=None):
   Gate.__init__(library.gates.NAND, self.min_inputs(inputs, 2))
 
- def update(self):
+ def update_state(self):
   self.output = self.inputs[0]
   for i in range(1, self.input_max):
    self.output &= self.inputs[i] # AND
@@ -239,7 +257,7 @@ class GateNOR(Gate):
  def __init__(self, inputs=None):
   Gate.__init__(library.gates.NOR, self.min_inputs(inputs, 2))
 
- def update(self):
+ def update_state(self):
   self.output = self.inputs[0]
   for i in range (1, self.input_max):
    self.output |= self.inputs[i] # OR
@@ -248,15 +266,16 @@ class GateNOR(Gate):
 
 class ICLogic:
  """ Models an IC that contains one or more digital logic gates """
- gates = list() # list of gates
 
  def __init__(self, gates=()):
+  self.gates = list()
+
   if not type(gates) is list:
    raise TypeError('expected list')
   elif not type(gates[0]) is Gate:
    raise TypeError('expected Gate')
 
-  self.gates = gates
+  self.gates.append(gates)
 
  def add(self, gate):
   if not type(gate) is Gate:
@@ -266,7 +285,11 @@ class ICLogic:
 
 class ICLogicDIL(ICLogic, DualInLine):
  """ Model of a Logic IC ina  DIL package  """
+ def __new__(cls, *args):
+  print("ICLoigcDIL.__new__()")
+
  def __init__(self, gates=(), pins_qty=14):
+  print('ICLogicDL.__slots__ =',self. __slots__)
   ICLogic.__init(gates)
   DualInLine.__init__(pins_qty)
 
@@ -288,19 +311,21 @@ class SN741G00(ICLogicDIL):
 
 class TSSOP(IntegratedCircuit):
  """ Thin Shrink Small Outline Package """
- sides = 2
- pins = list()
+ # emulate C++/Java classes
+ __slots__ = ['sides', 'pins']
 
  def __init__(self, pins):
+  self.sides = 2
+  self.pins = list()
   return  
 
 
 class PCB:
  """ Models a digital electronics logic circuit printed on a circuit board  """
- layout = None
 
  def __init__(self):
   """ """
+  self.layout = None
   return
 
  def trace_add(self, trace_list):
@@ -311,3 +336,4 @@ class PCB:
   """ Adds a component to the circuit """
   return
 
+