Initial data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 72d218235f
commit f23f22d71c
199087 changed files with 3378941 additions and 0 deletions

View file

@ -0,0 +1,32 @@
from itertools import combinations_with_replacement as cmbr
from time import time
def dice_gen(n, faces, m):
dice = list(cmbr(faces, n))
succ = [set(j for j, b in enumerate(dice)
if sum((x>y) - (x<y) for x in a for y in b) > 0)
for a in dice]
def loops(seq):
s = succ[seq[-1]]
if len(seq) == m:
if seq[0] in s: yield seq
return
for d in (x for x in s if x > seq[0] and not x in seq):
yield from loops(seq + (d,))
yield from (tuple(''.join(dice[s]) for s in x)
for i, v in enumerate(succ)
for x in loops((i,)))
t = time()
for n, faces, loop_len in [(4, '1234', 3), (4, '1234', 4), (6, '123456', 3), (6, '1234567', 3)]:
for i, x in enumerate(dice_gen(n, faces, loop_len)): pass
print(f'{n}-sided, markings {faces}, loop length {loop_len}:')
print(f'\t{i + 1}*{loop_len} solutions, e.g. {" > ".join(x)} > [loop]')
t, t0 = time(), t
print(f'\ttime: {t - t0:.4f} seconds\n')

View file

@ -0,0 +1,75 @@
from collections import namedtuple
from itertools import permutations, product
from functools import lru_cache
Die = namedtuple('Die', 'name, faces')
@lru_cache(maxsize=None)
def cmpd(die1, die2):
'compares two die returning 1, -1 or 0 for >, < =='
# Numbers of times one die wins against the other for all combinations
# cmp(x, y) is `(x > y) - (y > x)` to return 1, 0, or -1 for numbers
tot = [0, 0, 0]
for d1, d2 in product(die1.faces, die2.faces):
tot[1 + (d1 > d2) - (d2 > d1)] += 1
win2, _, win1 = tot
return (win1 > win2) - (win2 > win1)
def is_non_trans(dice):
"Check if ordering of die in dice is non-transitive returning dice or None"
check = (all(cmpd(c1, c2) == -1
for c1, c2 in zip(dice, dice[1:])) # Dn < Dn+1
and cmpd(dice[0], dice[-1]) == 1) # But D[0] > D[-1]
return dice if check else False
def find_non_trans(alldice, n=3):
return [perm for perm in permutations(alldice, n)
if is_non_trans(perm)]
def possible_dice(sides, mx):
print(f"\nAll possible 1..{mx} {sides}-sided dice")
dice = [Die(f"D{n+1}", faces)
for n, faces in enumerate(product(range(1, mx+1), repeat=sides))]
print(f' Created {len(dice)} dice')
print(' Remove duplicate with same bag of numbers on different faces')
found = set()
filtered = []
for d in dice:
count = tuple(sorted(d.faces))
if count not in found:
found.add(count)
filtered.append(d)
l = len(filtered)
print(f' Return {l} filtered dice')
return filtered
#%% more verbose extra checks
def verbose_cmp(die1, die2):
'compares two die returning their relationship of their names as a string'
# Numbers of times one die wins against the other for all combinations
win1 = sum(d1 > d2 for d1, d2 in product(die1.faces, die2.faces))
win2 = sum(d2 > d1 for d1, d2 in product(die1.faces, die2.faces))
n1, n2 = die1.name, die2.name
return f'{n1} > {n2}' if win1 > win2 else (f'{n1} < {n2}' if win1 < win2 else f'{n1} = {n2}')
def verbose_dice_cmp(dice):
c = [verbose_cmp(x, y) for x, y in zip(dice, dice[1:])]
c += [verbose_cmp(dice[0], dice[-1])]
return ', '.join(c)
#%% Use
if __name__ == '__main__':
dice = possible_dice(sides=4, mx=4)
for N in (3, 4): # length of non-transitive group of dice searched for
non_trans = find_non_trans(dice, N)
print(f'\n Non_transitive length-{N} combinations found: {len(non_trans)}')
for lst in non_trans:
print()
for i, die in enumerate(lst):
print(f" {' ' if i else '['}{die}{',' if i < N-1 else ']'}")
if non_trans:
print('\n More verbose comparison of last non_transitive result:')
print(' ', verbose_dice_cmp(non_trans[-1]))
print('\n ====')