Last active
January 24, 2016 18:07
-
-
Save svenk/b02b86e8f8063c676683 to your computer and use it in GitHub Desktop.
Proposal for Punchcard modeling in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# python 2 | |
# | |
from pypunchcards import * | |
from mappings import h14, m200uc | |
finished_cards = [] | |
card = Card() | |
for line in fileinput.input(): | |
line = line.strip() | |
match = re.match(r"^6(\d\d)\s+0x([0-9a-f]{2})\s+0x([0-9a-f]{2})\s*$", line, re.IGNORECASE) | |
if(not match): | |
print "%s, line %d: not a valid line: '%s'" % (fileinput.filename(), fileinput.lineno(), line) | |
continue | |
punch_col, hex1, hex2 = match.groups() | |
# convert ints and hexes. | |
punch_col = int(punch_col) | |
hex1 = codecs.decode(hex1, 'hex_codec') | |
hex2 = codecs.decode(hex2, 'hex_codec') | |
# depending on our gracefulness, decide when to start new card | |
start_new_card = punch_col in card.columns.keys() or punch_col == 0 | |
if start_new_card: | |
print "Finished card" | |
if not card.is_complete() | |
print "But card not complete!" | |
finished_cards.append(card) | |
card = Card() | |
# have fun with the bytes | |
bytes = [Byte(hex1), Byte(hex2)] | |
column = h14.decode(bytes) | |
card.set(punch_col, column) | |
# print all the cards or so. | |
print h14.encode_card(card) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pypunchcards import * | |
# verbose numbers: Indices in Card rows | |
col0, col1, col2, col3, col4, col5 = 0, 1, 2, 3, 4, 5 | |
col6, col7, col8, col9, col11, col12 = 6, 7, 8, 9, 10, 11 | |
# Hex-Format, das vom Documation M200 angebundenen Microcontroller | |
# ausgegeben wird | |
# untested, there may be mistakes | |
m200uc = CardsByteMapping(bytes=2) | |
m200uc.set(col0, byte=0, bit=0b00000001) | |
m200uc.set(col1, byte=0, bit=0b00000010) | |
m200uc.set(col2, byte=0, bit=0b00000100) | |
m200uc.set(col3, byte=0, bit=0b00001000) | |
m200uc.set(col4, byte=0, bit=0b00010000) | |
m200uc.set(col5, byte=0, bit=0b00100000) | |
m200uc.set(col6, byte=0, bit=0b01000000) | |
m200uc.set(col7, byte=0, bit=0b10000000) | |
m200uc.set(col8, byte=1, bit=0b00000001) | |
m200uc.set(col9, byte=1, bit=0b00000010) | |
m200uc.set(col11,byte=1, bit=0b00000100) | |
m200uc.set(col12,byte=1, bit=0b00001000) | |
# h14-Format von R. Langf. | |
# ich weiss nicht, was Spalten "&" und "-" sind | |
# untested, there may be mistakes | |
col_ampersand = 10 | |
col_minus = 11 | |
h14 = CardsByteMapping(bytes=2) | |
h14.set(col6, byte=0, bit=0b10000000) | |
h14.set(col7, byte=0, bit=0b01000000) | |
h14.set(col8, byte=0, bit=0b00100000) | |
h14.set(col9, byte=0, bit=0b00010000) | |
h14.set(col_ampersand, byte=1, bit=0b00000001) | |
h14.set(col_minus, byte=1, bit=0b00000010) | |
h14.set(col0, byte=1, bit=0b00000100) | |
h14.set(col1, byte=1, bit=0b00001000) | |
h14.set(col2, byte=1, bit=0b00010000) | |
h14.set(col3, byte=1, bit=0b00100000) | |
h14.set(col4, byte=1, bit=0b01000000) | |
h14.set(col5, byte=1, bit=0b10000000) | |
# Format nach | |
# http://homepage.cs.uiowa.edu/~jones/cards/format.html | |
# untested, there may be mistakes | |
douglasJones = CardsByteMapping(bytes=3, cards=2) | |
douglasJones.set(col12, card=0, byte=0, bit=0b10000000) | |
douglasJones.set(col11, card=0, byte=0, bit=0b01000000) | |
douglasJones.set( col0, card=0, byte=0, bit=0b00100000) | |
douglasJones.set( col1, card=0, byte=0, bit=0b00010000) | |
douglasJones.set( col2, card=0, byte=0, bit=0b00001000) | |
douglasJones.set( col3, card=0, byte=0, bit=0b00000100) | |
douglasJones.set( col4, card=0, byte=0, bit=0b00000010) | |
douglasJones.set( col5, card=0, byte=0, bit=0b00000001) | |
douglasJones.set( col6, card=0, byte=1, bit=0b10000000) | |
douglasJones.set( col7, card=0, byte=1, bit=0b01000000) | |
douglasJones.set( col8, card=0, byte=1, bit=0b00100000) | |
douglasJones.set( col9, card=0, byte=1, bit=0b00010000) | |
douglasJones.set(col12, card=1, byte=1, bit=0b00001000) | |
douglasJones.set(col11, card=1, byte=1, bit=0b00000100) | |
douglasJones.set( col0, card=1, byte=1, bit=0b00000010) | |
douglasJones.set( col1, card=1, byte=1, bit=0b00000001) | |
douglasJones.set( col2, card=1, byte=2, bit=0b10000000) | |
douglasJones.set( col3, card=1, byte=2, bit=0b01000000) | |
douglasJones.set( col4, card=1, byte=2, bit=0b00100000) | |
douglasJones.set( col5, card=1, byte=2, bit=0b00010000) | |
douglasJones.set( col6, card=1, byte=2, bit=0b00001000) | |
douglasJones.set( col7, card=1, byte=2, bit=0b00000100) | |
douglasJones.set( col8, card=1, byte=2, bit=0b00000010) | |
douglasJones.set( col9, card=1, byte=2, bit=0b00000001) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This gist was an experiment to explore ways to model punch cards with Python nicely. | |
Focus was spent on good reability/introspection and fault tolerance (incomplete | |
punch cards/tristates) and not on performance. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# This is a Python 2 file | |
# | |
# This file holds classes to represent, manipulate and translate 72x13 hole Punch Cards. | |
# This is more like a proof of concept and a NON running, not tested prototype. | |
# | |
# SK Jan 2016 Public Domain | |
# Needs: python-bitarray, more basic | |
from bitarray import * | |
# Alternative for evaluation: python-bitstring, more complete | |
# python internals | |
import sys | |
import fileinput | |
import re | |
from collections import namedtuple | |
import codecs | |
from copy import deepcopy | |
from math import log | |
class Row: | |
""" | |
lower, upper = Byte(0x82), Byte(0x10) | |
col = CardRow() | |
col.set("col1", lower.bit3) | |
col.set("col2", lower.bit4) | |
... | |
card.set(position, col) | |
""" | |
columns = ["col0", "col1", "col2", "col3", "col4", "col5", "col6", "col7", | |
"col8", "col9", "col11", "col12", "col13"] | |
values = {} | |
def __init__(column_names=columns): | |
for col in columns: | |
values[col] = False | |
def set(idx, value): | |
values[idx] = value | |
def get(self, idx): | |
return values[idx] | |
class Card: | |
""" | |
A class representing a cunch card as a dictionary mapping row keys (int) | |
to Row instances. | |
""" | |
def __init__(self, columns=80, rows=13): | |
self.columns = {} | |
self.min_col = 0 | |
self.max_col = columns-1 | |
self.keys = range(min_col, max_col+1) | |
self.num_columns = columns | |
self.num_rows = rows | |
self.clear() | |
def clear(self): | |
for i in self.keys: | |
self.columns[i] = Row() | |
def set(self, col_idx, column): | |
if not col_idx in self.keys: | |
raise ValueError("Index out of bounds") | |
self.columns[col_idx] = column | |
def missing_columns(self): | |
wanted_keys = self.keys | |
available_keys = self.columns.keys() | |
missing_keys = list(set(wanted_keys) - set(available_keys)) | |
return missing_keys | |
def is_complete(self): | |
return not self.missing_columns() # empty list | |
def dump(self, ignore_missing=False): | |
if not ignore_missing and not self.is_complete(): | |
raise ValueError("Card is not complete") | |
for i in self.keys: | |
if ignore_missing and i in self.missing_columns(): | |
print "%i: missing" % i | |
continue | |
print "%i: %s" % (i, str(self.columns[i])) | |
def __repr__(self): | |
return 'Card(%i columns, %i filled)' % (len(self.keys), len(self.keys)-len(self.missing_columns())) | |
class Word(list): | |
""" | |
Poor mans implementation of a bitarray. | |
This was worked out as an alternative to bitstream/bitarray classes. | |
byte = Word(length=8) | |
""" | |
# masks | |
bit0, bit1, bit2, bit3 = 0b1000000, 0b0100000, 0b0010000, 0b0001000 | |
bit4, bit5, bit6, bit7 = 0b0001000, 0b0000100, 0b0000010, 0b0000001 | |
def __init__(self, byte=0): | |
pass | |
def __init__(self, byte=0): | |
self.bits = [] | |
self.set(byte) | |
def set(self, byte): | |
for bit in self.keys(): | |
self.set(bit, byte) | |
def set(self, bit, byte): | |
setattr(self, bit, byte | getattr(self, bit)) | |
def keys(self): | |
return [attr for attr in dir(self) if not callable(getattr(self,attr)) and not attr.startswith("__")] | |
class WordMapping: | |
""" | |
A class which maps different word lengths at each other by alignment. | |
We define two word types, A and B with individual bit length lenA and lenB. | |
Then numA objects of type A shall carry the same content as numB objects of type B. | |
This mapping may be purely randomly defined by identifying positions of bits | |
in the chunk with length numA*lenA with bits in the chunk with length numB*lenB. | |
This Mapping class has a distinguished direction: A->B. | |
Translating A->B is called Encoding. | |
Translating B->A is called Decoding. | |
A and B must be classes accessible like arrays with [] (getitem, setitem). | |
Actually A and B also can be functions returning class instances. They just have to | |
be callable like A() and B(). | |
""" | |
def __init__(self, A, B, numA, numB): | |
self.A, self.B = A, B | |
self.exampleA, self.exampleB = A(), B() | |
self.numA, self.numB = numA, numB | |
self.map = {} | |
def set(self, idxA, posA, idxB, posB): | |
if idxA > len(self.exampleA) or idxB > len(self.exampleB) or posA > self.numA or posB > self.numB: | |
raise ValueError("Indices out of scope: %s for %s." % (str((idxA,posA,idxB,posB)),self)) | |
self.map[(idxA,posA)] = (idxB,posB) | |
def get(self, idxA, posA): | |
return self.map[(idxA,posA)] | |
def encode(self, wordsA): | |
if len(wordsA) != self.numA: | |
raise ValueError("Whaaa.") | |
wordsB = [self.B()]*self.numB | |
for (idxA, posA), (idxB, posB) in self.map.iteritems(): | |
wordsB[posB][idxB] = wordsA[posA][idxA] | |
return wordsB | |
def decode(self, wordsB): | |
if len(wordsB) != self.numB: | |
raise ValueError("Whaaa.") | |
wordsA = [self.A()]*self.numA | |
for (idxA, posA), (idxB, posB) in self.map.iteritems(): | |
wordsA[posA][idxA] = wordsB[posB][idxB] | |
return wordsA | |
def __repr__(self): | |
return 'WordMapping(%d x A[%d indices] -> %d x B[%d indices])' % (self.numA, len(self.exampleA), self.numB, len(self.exampleB)) | |
class Byte(bitarray): | |
def __init__(self, value=0): | |
bitarray.__init__(self) | |
if value > 2**8: | |
raise ValueError("This is a nibble and not a Dampfschiff") | |
bitstr = bin(value)[2:] | |
self.append(bitstr) | |
#def Byte(): | |
# return 8 * bitarray('0') | |
def CardRow(): | |
return 12 * bitarray('0') | |
class CardsByteMapping(WordMapping): | |
""" | |
Cardsrows->Bytes | |
A=Cards. | |
B=Bytes. | |
""" | |
def __init__(self, bytes=2, cards=1): | |
WordMapping.__init__(self, A=CardRow, B=Byte, numA=cards, numB=bytes) | |
def set(self, column_name, bit, byte=0, card=0): | |
# here, bit is something like 0b01000000. Determine position of 1. | |
posbit = log(bit, 2) | |
if not posbit.is_integer(): | |
raise ValueError("Error: bit should be someting like 0b00001000.") | |
WordMapping.set(self, idxA=column_name, idxB=int(posbit), posA=card, posB=byte) | |
## helpers not related to anything with punchcards. | |
def populate(named_constants): | |
globals().update({k: k for k in named_constants}) | |
def populate_prefix(prefix, named_list): | |
""" | |
eg. populate_prefix("col", range(0,10)) | |
gives variables "col0", "col1" in the global space with same values | |
""" | |
populate([str(prefix)+str(i) for i in named_list]) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment