from itertools import combinations
from collections import Counter
from scipy.stats import entropy
alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
oldDice16 = ['AACIOT', 'ABILTY', 'ABJMOQ', 'ACDEMP', 'ACELRS', 'ADENVZ', 'AHMORS', 'BIFORX', 'DENOSW', 'DKNOTU', 'EEFHIY', 'EGKLUY', 'EGINTV', 'EHINPS', 'ELPSTU', 'GILRUW']
oldDistribution = Counter(''.join(oldDice16))
newDice16 = ['AAEEGN', 'ABBJOO', 'ACHOPS', 'AFFKPS', 'AOOTTW', 'CIMOTU', 'DEILRX', 'DELRVY', 'DISTTY', 'EEGHNW', 'EEINSU', 'EHRTVW', 'EIOSST', 'ELRTTY', 'HIMNUQ', 'HLNNRZ']
newDistribution = Counter(''.join(newDice16))
dice25 = ['AAAFRS', 'AAEEEE', 'AAFIRS', 'ADENNN', 'AEEEEM', 'AEEGMU', 'AEGMNN', 'AFIRSY', 'BJKQXZ', 'CCENST', 'CEIILT', 'CEILPT', 'CEIPST', 'DDHNOT', 'DHHLOR', 'DHLNOR', 'DHLNOR', 'EIIITT', 'EMOTTT', 'ENSSSU', 'FIPRSY', 'GORRVW', 'IPRRRY', 'NOOTUW', 'OOOTTU']
def manhattan(distributionA, distributionB):
score = 0
for letter in alphabet:
score += abs(distributionA[letter] - distributionB[letter])
return score
def kullbackLeibler(distributionA, distributionB):
pk = []
qk = []
for letter in alphabet:
pk.append(distributionA[letter] / (16 * 6.0))
qk.append(distributionB[letter] / (16 * 6.0))
return entropy(pk, qk)
metrics = {'manhattan': manhattan, 'kullbackLeibler': kullbackLeibler}
comparisonDistributions = {'old dice': oldDistribution, 'new dice': newDistribution}
for metricName, metric in metrics.items():
for dice16Name, dice16Distribution in comparisonDistributions.items():
bestSelection = None
bestDistance = 16*6
for selection in combinations(dice25, 16):
allLetters = ''.join(selection)
distribution = Counter(allLetters)
score = metric(distribution, dice16Distribution)
if score < bestDistance:
bestSelection, bestDistance = selection, score
print metricName, dice16Name, bestSelection, bestDistance
ZnJvbSBpdGVydG9vbHMgaW1wb3J0IGNvbWJpbmF0aW9ucwpmcm9tIGNvbGxlY3Rpb25zIGltcG9ydCBDb3VudGVyCmZyb20gc2NpcHkuc3RhdHMgaW1wb3J0IGVudHJvcHkKCmFscGhhYmV0ID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaJwoKb2xkRGljZTE2ID0gWydBQUNJT1QnLCAnQUJJTFRZJywgJ0FCSk1PUScsICdBQ0RFTVAnLCAnQUNFTFJTJywgJ0FERU5WWicsICdBSE1PUlMnLCAnQklGT1JYJywgJ0RFTk9TVycsICdES05PVFUnLCAnRUVGSElZJywgJ0VHS0xVWScsICdFR0lOVFYnLCAnRUhJTlBTJywgJ0VMUFNUVScsICdHSUxSVVcnXQpvbGREaXN0cmlidXRpb24gPSBDb3VudGVyKCcnLmpvaW4ob2xkRGljZTE2KSkKbmV3RGljZTE2ID0gWydBQUVFR04nLCAnQUJCSk9PJywgJ0FDSE9QUycsICdBRkZLUFMnLCAnQU9PVFRXJywgJ0NJTU9UVScsICdERUlMUlgnLCAnREVMUlZZJywgJ0RJU1RUWScsICdFRUdITlcnLCAnRUVJTlNVJywgJ0VIUlRWVycsICdFSU9TU1QnLCAnRUxSVFRZJywgJ0hJTU5VUScsICdITE5OUlonXQpuZXdEaXN0cmlidXRpb24gPSBDb3VudGVyKCcnLmpvaW4obmV3RGljZTE2KSkKZGljZTI1ID0gWydBQUFGUlMnLCAnQUFFRUVFJywgJ0FBRklSUycsICdBREVOTk4nLCAnQUVFRUVNJywgJ0FFRUdNVScsICdBRUdNTk4nLCAnQUZJUlNZJywgJ0JKS1FYWicsICdDQ0VOU1QnLCAnQ0VJSUxUJywgJ0NFSUxQVCcsICdDRUlQU1QnLCAnRERITk9UJywgJ0RISExPUicsICdESExOT1InLCAnREhMTk9SJywgJ0VJSUlUVCcsICdFTU9UVFQnLCAnRU5TU1NVJywgJ0ZJUFJTWScsICdHT1JSVlcnLCAnSVBSUlJZJywgJ05PT1RVVycsICdPT09UVFUnXQoKZGVmIG1hbmhhdHRhbihkaXN0cmlidXRpb25BLCBkaXN0cmlidXRpb25CKToKICAgIHNjb3JlID0gMAogICAgZm9yIGxldHRlciBpbiBhbHBoYWJldDoKICAgICAgICBzY29yZSArPSBhYnMoZGlzdHJpYnV0aW9uQVtsZXR0ZXJdIC0gZGlzdHJpYnV0aW9uQltsZXR0ZXJdKQogICAgcmV0dXJuIHNjb3JlCgpkZWYga3VsbGJhY2tMZWlibGVyKGRpc3RyaWJ1dGlvbkEsIGRpc3RyaWJ1dGlvbkIpOgogICAgcGsgPSBbXQogICAgcWsgPSBbXQogICAgZm9yIGxldHRlciBpbiBhbHBoYWJldDoKICAgICAgICBway5hcHBlbmQoZGlzdHJpYnV0aW9uQVtsZXR0ZXJdIC8gKDE2ICogNi4wKSkKICAgICAgICBxay5hcHBlbmQoZGlzdHJpYnV0aW9uQltsZXR0ZXJdIC8gKDE2ICogNi4wKSkKICAgIHJldHVybiBlbnRyb3B5KHBrLCBxaykKCm1ldHJpY3MgPSB7J21hbmhhdHRhbic6IG1hbmhhdHRhbiwgJ2t1bGxiYWNrTGVpYmxlcic6IGt1bGxiYWNrTGVpYmxlcn0KY29tcGFyaXNvbkRpc3RyaWJ1dGlvbnMgPSB7J29sZCBkaWNlJzogb2xkRGlzdHJpYnV0aW9uLCAnbmV3IGRpY2UnOiBuZXdEaXN0cmlidXRpb259Cgpmb3IgbWV0cmljTmFtZSwgbWV0cmljIGluIG1ldHJpY3MuaXRlbXMoKToKICAgIGZvciBkaWNlMTZOYW1lLCBkaWNlMTZEaXN0cmlidXRpb24gaW4gY29tcGFyaXNvbkRpc3RyaWJ1dGlvbnMuaXRlbXMoKToKICAgICAgICBiZXN0U2VsZWN0aW9uID0gTm9uZQogICAgICAgIGJlc3REaXN0YW5jZSA9IDE2KjYKICAgICAgICBmb3Igc2VsZWN0aW9uIGluIGNvbWJpbmF0aW9ucyhkaWNlMjUsIDE2KToKICAgICAgICAgICAgYWxsTGV0dGVycyA9ICcnLmpvaW4oc2VsZWN0aW9uKQogICAgICAgICAgICBkaXN0cmlidXRpb24gPSBDb3VudGVyKGFsbExldHRlcnMpCiAgICAgICAgICAgIHNjb3JlID0gbWV0cmljKGRpc3RyaWJ1dGlvbiwgZGljZTE2RGlzdHJpYnV0aW9uKQogICAgICAgICAgICBpZiBzY29yZSA8IGJlc3REaXN0YW5jZToKICAgICAgICAgICAgICAgIGJlc3RTZWxlY3Rpb24sIGJlc3REaXN0YW5jZSA9IHNlbGVjdGlvbiwgc2NvcmUgICAgCiAgICAgICAgcHJpbnQgbWV0cmljTmFtZSwgZGljZTE2TmFtZSwgYmVzdFNlbGVjdGlvbiwgYmVzdERpc3RhbmNlCg==