mirror of https://github.com/dnomd343/klotski.git
2 changed files with 131 additions and 0 deletions
@ -0,0 +1,104 @@ |
|||||
|
#!/usr/bin/env python3 |
||||
|
|
||||
|
import json |
||||
|
from klotski import Group, Layout, FastCal |
||||
|
|
||||
|
|
||||
|
def layout_to_str(layout: Layout) -> str: |
||||
|
code = str(layout) |
||||
|
assert len(code) == 9 and code.endswith('00') |
||||
|
return code[:7] |
||||
|
|
||||
|
|
||||
|
def build_graph(group: Group, targets: set[Layout], ignores: set[Layout]) -> dict[Layout, dict]: |
||||
|
assert targets & ignores == set() |
||||
|
|
||||
|
steps = {x: [] for x in list(group.cases())} |
||||
|
assert len(steps) == group.size |
||||
|
|
||||
|
for target in targets: |
||||
|
fc = FastCal(target) |
||||
|
fc.build_all() |
||||
|
layers = fc.exports() |
||||
|
assert sum(len(x) for x in layers) == group.size |
||||
|
|
||||
|
for step, layouts in enumerate(layers): |
||||
|
[steps[x].append((target, step)) for x in layouts] |
||||
|
|
||||
|
graph = {} |
||||
|
for layout in steps: |
||||
|
assert len(steps[layout]) == len(targets) |
||||
|
step = min(x for _, x in steps[layout]) |
||||
|
pivots = set(x for x, y in steps[layout] if y == step) |
||||
|
graph[layout] = {'step': step, 'pivots': pivots, 'next': set()} |
||||
|
|
||||
|
for layout, info in graph.items(): |
||||
|
for x in layout.next_cases(): |
||||
|
if graph[x]['step'] == info['step'] + 1: |
||||
|
info['next'].add(x) |
||||
|
|
||||
|
# for ignore in ignores: |
||||
|
# assert ignore in graph |
||||
|
# for x in graph[ignore]['next']: |
||||
|
# assert x in ignores |
||||
|
# |
||||
|
# for layout, info in graph.items(): |
||||
|
# if ignore in info['next'] and layout not in ignores: |
||||
|
# assert layout in targets |
||||
|
|
||||
|
for ignore in ignores: |
||||
|
del graph[ignore] |
||||
|
|
||||
|
for layout, info in graph.items(): |
||||
|
need_remove = [] |
||||
|
for x in info['next']: |
||||
|
if x in ignores: |
||||
|
assert layout in targets |
||||
|
need_remove.append(x) |
||||
|
for x in need_remove: |
||||
|
info['next'].remove(x) |
||||
|
|
||||
|
# for layout, info in graph.items(): |
||||
|
# for x in info['next']: |
||||
|
# assert x in graph |
||||
|
|
||||
|
assert sorted(graph) == list(graph) |
||||
|
assert len(set(graph)) == len(graph) |
||||
|
return graph |
||||
|
|
||||
|
|
||||
|
def dump_json(group_info: dict, graph: dict[Layout, dict]) -> str: |
||||
|
data = {} |
||||
|
for layout, info in graph.items(): |
||||
|
data[layout_to_str(layout)] = { |
||||
|
'step': info['step'], |
||||
|
'next': sorted(layout_to_str(x) for x in info['next']), |
||||
|
'pivots': sorted(layout_to_str(x) for x in info['pivots']), |
||||
|
} |
||||
|
return json.dumps({**group_info, 'graph': data}, separators=(',', ':')) |
||||
|
|
||||
|
|
||||
|
def load_and_dump(info: dict, path_prefix: str) -> None: |
||||
|
targets = sorted(Layout(x) for x in info['solutions']['valid']) |
||||
|
ignores = sorted(Layout(x) for x in info['solutions']['invalid']) |
||||
|
|
||||
|
target_map = {Layout(v): k for k, v in info['targets'].items()} |
||||
|
assert len(target_map) == len(info['targets']) |
||||
|
|
||||
|
group = targets[0].group |
||||
|
graph = build_graph(group, set(targets), set(ignores)) |
||||
|
group_info = { |
||||
|
'size': group.size, |
||||
|
'targets': {layout_to_str(x): target_map[x] for x in targets}, |
||||
|
'ignores': [layout_to_str(x) for x in ignores], |
||||
|
} |
||||
|
with open(f'{path_prefix}.json', 'w') as fp: |
||||
|
fp.write(dump_json(group_info, graph)) |
||||
|
|
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
raw = json.loads(open('data.json').read()) |
||||
|
|
||||
|
for name, info in raw.items(): |
||||
|
print(name) |
||||
|
load_and_dump(info, f'./output-json/{name}') |
@ -0,0 +1,27 @@ |
|||||
|
#!/usr/bin/env python3 |
||||
|
|
||||
|
import os |
||||
|
import json |
||||
|
import igraph as ig |
||||
|
|
||||
|
|
||||
|
def dump_igraph(graph: dict[str, dict]) -> ig.Graph: |
||||
|
index_map = {x: i for i, x in enumerate(graph)} |
||||
|
g = ig.Graph(len(graph)) |
||||
|
for index, (layout, info) in enumerate(graph.items()): |
||||
|
g.vs[index]['code'] = layout |
||||
|
g.vs[index]['step'] = info['step'] |
||||
|
g.add_edges([(index, index_map[x]) for x in info['next']]) |
||||
|
return g |
||||
|
|
||||
|
|
||||
|
def convert_ig(file: str, output: str) -> None: |
||||
|
raw = json.loads(open(file).read()) |
||||
|
dump_igraph(raw['graph']).write_pickle(output) |
||||
|
|
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
for name in sorted(os.listdir('output-json')): |
||||
|
name = name.removesuffix('.json') |
||||
|
print(name) |
||||
|
convert_ig(f'output-json/{name}.json', f'output-ig/{name}.pickle') |
Loading…
Reference in new issue