Skip to content

Instantly share code, notes, and snippets.

@zahlman
Created November 19, 2012 03:14
Show Gist options
  • Select an option

  • Save zahlman/4108758 to your computer and use it in GitHub Desktop.

Select an option

Save zahlman/4108758 to your computer and use it in GitHub Desktop.
gimste simulation thingy
from itertools import product
from random import choice
collisions = {
'b': 'pv', 'c': 'js', 'd': 't' , 'f': 'pv',
'g': 'kx', 'j': 'cz', 'k': 'gx', 'l': 'r',
'm': 'n' , 'n': 'm' , 'p': 'bf', 'r': 'l',
's': 'cz', 't': 'd' , 'v': 'bf', 'x': 'gk',
'z': 'js'
}
voiced = set('bdgvjz')
liquid = set('mnlr')
unvoiced = set('ptkfcsx')
vowels = set('aeiou')
consonants = voiced | unvoiced | liquid
non_voiced = unvoiced | liquid
non_unvoiced = liquid | voiced
def pairs(*combinations, prefix = ''):
return set().union(*(
(prefix + x + y for x, y in product(*combination))
for combination in combinations
))
medial_clusters = pairs(
(non_unvoiced, non_unvoiced),
(non_voiced, non_voiced)
) - (
set().union(
(x+x for x in consonants),
('cs', 'jz', 'sc', 'zj', 'cx', 'kx', 'xc', 'xk', 'mz')
)
)
initial_clusters = set(
'#' + x for x in (
'bl', 'br', 'cf', 'ck', 'cl', 'cm', 'cn', 'cp',
'cr', 'ct', 'dj', 'dr', 'dz', 'fl', 'fr', 'gl',
'gr', 'jb', 'jd', 'jg', 'jm', 'jv', 'kl', 'kr',
'ml', 'mr', 'pl', 'pr', 'sf', 'sk', 'sl', 'sm',
'sn', 'sp', 'sr', 'st', 'tc', 'tr', 'ts', 'vl',
'vr', 'xl', 'xr', 'zb', 'zd', 'zg', 'zm', 'zv'
)
)
def similar(pagbu):
count = len(pagbu)
if count == 1: # lerfu
return set(collisions.get(pagbu, ''))
elif count == 2: # medial cluster
x, y = pagbu
return pairs((collisions[x], y), (x, collisions[y])) & medial_clusters
elif count == 3: # initial cluster
_, x, y = pagbu
return pairs((collisions[x], y), (x, collisions[y]), prefix = _) & initial_clusters
similar_lookup = {
p: similar(p)
for p in vowels | consonants | initial_clusters | medial_clusters
}
other_vowels = {
v: vowels.difference(v)
for v in vowels
}
class Gismu(tuple):
instances = {}
def __new__(cls, a, b, c, d):
args = (a, b, c, d)
return Gismu.instances.get(args, tuple.__new__(cls, args))
def __init__(self, a, b, c, d):
args = (a, b, c, d)
super().__init__(self, args)
Gismu.instances[args] = self
@property
def collisions(self):
if not hasattr(self, '_collisions'):
self._collisions = set(self._calc_collisions())
return self._collisions
def __str__(self): return ''.join(self).strip('#')
__repr__ = __str__
def _calc_collisions(self):
a, b, c, d = self
for s in similar_lookup[a]:
yield Gismu(s, b, c, d)
for s in similar_lookup[b]:
yield Gismu(a, s, c, d)
for s in similar_lookup[c]:
yield Gismu(a, b, s, d)
if not (a == '#br' and b == 'o' and c == 'd'):
# except for the broda-series, also generate as similar
# any gismu that just differ in the final vowel.
for s in other_vowels[d]:
yield Gismu(a, b, c, s)
def all_gismu():
for a, b, c, d in product(initial_clusters, vowels, consonants, vowels):
yield Gismu(a, b, c, d)
for a, b, c, d in product(consonants, vowels, medial_clusters, vowels):
yield Gismu(a, b, c, d)
class Hat:
# Get around the fact that random.choice doesn't work for sets. :(
def __init__(self, rabbits):
self._num_to_rabbit = list(rabbits)
self._rabbit_to_num = {rabbit: i for i, rabbit in enumerate(self._num_to_rabbit)}
def pull(self):
rabbit = choice(self._num_to_rabbit)
self.remove(rabbit)
return rabbit
def remove(self, rabbit):
num_to_rabbit = self._num_to_rabbit
rabbit_to_num = self._rabbit_to_num
if rabbit not in rabbit_to_num: return # already removed.
num = rabbit_to_num[rabbit]
del rabbit_to_num[rabbit]
replacement = num_to_rabbit.pop()
if num < len(num_to_rabbit):
# If the rabbit didn't come from the end of the list, then
# put the rabbit that was at the end into the spot where
# this one came from.
num_to_rabbit[num] = replacement
rabbit_to_num[replacement] = num
def __repr__(self):
return repr((self._num_to_rabbit, self._rabbit_to_num))
def __len__(self):
return len(self._num_to_rabbit)
def main():
gismu_list = list(all_gismu())
# Preload.
for gismu in gismu_list: gismu.collisions
print("made list.")
for trial in range(10000):
candidates = Hat(gismu_list)
count = 0
while candidates:
count += 1
result = candidates.pull()
for collision in result.collisions:
candidates.remove(collision)
print(count)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment