From 17f87154a8c47ca3a3acdb7c321cfc39f2c4c35b Mon Sep 17 00:00:00 2001 From: TJ Date: Mon, 18 Nov 2013 13:13:47 +0000 Subject: [PATCH] circuits: refactor to avoid attribute name-clashes with pygame, and move instance initialisation into constructors --- circuits.py | 132 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 79 insertions(+), 53 deletions(-) diff --git a/circuits.py b/circuits.py index 936982e..08d7f32 100644 --- a/circuits.py +++ b/circuits.py @@ -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 + -- 2.17.1