dump
This commit is contained in:
parent
22ef750437
commit
028fb0bc3a
180
.gitignore
vendored
Normal file
180
.gitignore
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
# Dom's manually added things
|
||||
bad apple/factorio-draftsman
|
||||
typing-puzzles/
|
||||
heartbound OCR/
|
||||
signals/
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||
.pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
152
1-2-3-digit-addend-662288000.py
Normal file
152
1-2-3-digit-addend-662288000.py
Normal file
@ -0,0 +1,152 @@
|
||||
from functools import cache
|
||||
from collections import Counter, defaultdict
|
||||
|
||||
# pool = Counter(map(int, "000226688"))
|
||||
# counted_digits = (0, 2, 6, 8)
|
||||
# counts = (3, 2, 2, 2)
|
||||
|
||||
# 268
|
||||
|
||||
# 208
|
||||
# 60
|
||||
# 0
|
||||
|
||||
|
||||
@cache
|
||||
def choose_n_unique(counts, n):
|
||||
if sum(counts) < n:
|
||||
raise "you done fucked up"
|
||||
if sum(counts) == n:
|
||||
return set([counts])
|
||||
out = set([])
|
||||
for i, count in enumerate(counts):
|
||||
if count <= 0:
|
||||
continue
|
||||
out.update(
|
||||
choose_n_unique(counts[:i] + (count - 1,) + counts[i + 1 :], n)
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def sub(a, b): # a-b
|
||||
return tuple(x - y for x, y in zip(a, b))
|
||||
|
||||
|
||||
# print(choose_n_unique(counts, 3))
|
||||
# print(find_sums(counts))
|
||||
# print(possible_sums((3, 2, 2, 2)))
|
||||
|
||||
|
||||
def has_len_digit(tup, length):
|
||||
for t in tup:
|
||||
if len(str(t)) == length:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# tup_0, tup_1 = (826,), (0, 0, 6, 820)
|
||||
|
||||
# print(has_len_digit(tup_0, 2))
|
||||
# print(has_len_digit(tup_1, 2))
|
||||
# exit()
|
||||
|
||||
|
||||
def find_solutions(counted_digits, counts):
|
||||
|
||||
@cache
|
||||
def possible_sums(counts): # sum -> set(tuple(addend))
|
||||
if sum(counts) == 0:
|
||||
return {0: set()}
|
||||
if sum(counts) == 1:
|
||||
for i, count in enumerate(counts):
|
||||
if count == 0:
|
||||
continue
|
||||
digit = counted_digits[i]
|
||||
out = {digit: set([(digit,)])}
|
||||
return out
|
||||
|
||||
out = defaultdict(set)
|
||||
|
||||
for i, count in enumerate(counts):
|
||||
if count <= 0:
|
||||
continue
|
||||
digit = counted_digits[i]
|
||||
sub = possible_sums(counts[:i] + (count - 1,) + counts[i + 1 :])
|
||||
for s, tups in sub.items():
|
||||
for tup in tups:
|
||||
out[s + digit].add(tuple(sorted((digit,) + tup)))
|
||||
# try appending the digit to all sub subms
|
||||
for tups in sub.values():
|
||||
for tup in tups:
|
||||
for j, val in enumerate(tup):
|
||||
if j > 0 and val == tup[j - 1]:
|
||||
continue
|
||||
new_tup = tuple(
|
||||
sorted((val * 10 + digit,) + tup[:j] + tup[j + 1 :])
|
||||
)
|
||||
out[sum(new_tup)].add(new_tup)
|
||||
return out
|
||||
|
||||
out = []
|
||||
for counts_0 in choose_n_unique(counts, 3):
|
||||
counts_1 = sub(counts, counts_0)
|
||||
# print(counts_1)
|
||||
possible_0 = possible_sums(counts_0)
|
||||
possible_1 = possible_sums(counts_1)
|
||||
# print(possible_0.get(268, "nope"))
|
||||
# print(possible_1.get(268, "nope"))
|
||||
# print()
|
||||
for total in possible_0.keys() & possible_1.keys():
|
||||
tups_0 = possible_0[total]
|
||||
tups_1 = possible_1[total]
|
||||
for tup_0 in tups_0:
|
||||
for tup_1 in tups_1:
|
||||
if not (has_len_digit(tup_0, 1) or has_len_digit(tup_1, 1)):
|
||||
continue
|
||||
if not (has_len_digit(tup_0, 2) or has_len_digit(tup_1, 2)):
|
||||
continue
|
||||
if not (has_len_digit(tup_0, 3) or has_len_digit(tup_1, 3)):
|
||||
continue
|
||||
out.append((tup_0, tup_1))
|
||||
return out
|
||||
|
||||
|
||||
# print(find_solutions(counted_digits=(0, 2, 6, 8), counts=(3, 2, 2, 2)))
|
||||
import random
|
||||
|
||||
rng = random.Random(4)
|
||||
# best = 100
|
||||
# for i in range(1000):
|
||||
|
||||
# # rng.randint()
|
||||
# def r(radius):
|
||||
# return rng.randint(-radius, radius)
|
||||
|
||||
# candidate = find_solutions(
|
||||
# counted_digits=(1 + r(1), 2 + r(1), 6 + r(1), 8 + r(1)),
|
||||
# counts=(3 + r(1), 2 + r(1), 2 + r(1), 2 + r(1)),
|
||||
# )
|
||||
# if not candidate:
|
||||
# continue
|
||||
|
||||
# if len(candidate) <= best:
|
||||
# best = len(candidate)
|
||||
# print("yay")
|
||||
# for tup in candidate:
|
||||
# print(" ", tup)
|
||||
|
||||
|
||||
def counted_digits_and_counts_from_solution(solution):
|
||||
s = str(solution)
|
||||
for to_remove in "(), ":
|
||||
s = s.replace(to_remove, "")
|
||||
print(s)
|
||||
print("".join(sorted(s)))
|
||||
c = Counter(s)
|
||||
counted_digits = tuple(int(k) for k in sorted(c))
|
||||
counts = tuple(int(c[k]) for k in sorted(c))
|
||||
return counted_digits, counts
|
||||
|
||||
|
||||
print(counted_digits_and_counts_from_solution("((261,), (7, 27, 227)))"))
|
||||
print(find_solutions((1, 2, 6, 7), (1, 4, 1, 3)))
|
10
12345_combination_sum.py
Normal file
10
12345_combination_sum.py
Normal file
@ -0,0 +1,10 @@
|
||||
import math
|
||||
import itertools
|
||||
|
||||
# print(list))
|
||||
|
||||
start_digits = [1,2,3,4,5]
|
||||
|
||||
print(sum(int(''.join(str(digit) for digit in digits)) for digits in itertools.permutations(start_digits)))
|
||||
|
||||
print(math.factorial(len(start_digits)) * (sum(start_digits)/len(start_digits)) * 11111)
|
180
3b1b cessboard encoding puzzle.py
Normal file
180
3b1b cessboard encoding puzzle.py
Normal file
@ -0,0 +1,180 @@
|
||||
# https://youtu.be/wTJI_WuZSwE
|
||||
|
||||
from functools import reduce, cache
|
||||
from typing import List, Tuple, Callable, Iterable
|
||||
from math import sqrt, log2
|
||||
from random import Random
|
||||
|
||||
def get_flip_pos_2x2(board: List[int], key: int) -> int:
|
||||
assert all(x in [0,1] for x in board)
|
||||
assert len(board) == 4
|
||||
s = sum(board)
|
||||
if s==0:
|
||||
return key
|
||||
if s==1:
|
||||
pos = board.index(1)
|
||||
if key == 0:
|
||||
return pos # empty
|
||||
if key == 1:
|
||||
return [1,0,3,2][pos] # horizontal
|
||||
if key == 2:
|
||||
return [2,3,0,1][pos] # vertical
|
||||
if key == 3:
|
||||
return [3,2,1,0][pos] # diagonal
|
||||
assert False
|
||||
if s==2:
|
||||
# ensure ``sum(board) in [1,3]``, pointing to key
|
||||
if board[key] == 0: # sum(flipped board) == 3
|
||||
possibilities = [i for i in range(len(board)) if i != key and board[i]==0]
|
||||
else: # sum(flipped board) == 3
|
||||
possibilities = [i for i in range(len(board)) if i != key and board[i]==1]
|
||||
assert len(possibilities) == 1
|
||||
return possibilities[0]
|
||||
if s==3:
|
||||
return get_flip_pos_2x2(all_flipped(board), key)
|
||||
if s==4:
|
||||
return get_flip_pos_2x2(all_flipped(board), key)
|
||||
assert False
|
||||
|
||||
def all_flipped(board: List[int]) -> List[int]:
|
||||
return [1-x for x in board]
|
||||
|
||||
def guess_key_2x2(board: List[int]) -> int:
|
||||
s = sum(board)
|
||||
if s==0:
|
||||
return 0
|
||||
if s==1:
|
||||
return board.index(1)
|
||||
if s==2:
|
||||
if board==[1,1,0,0] or board==[0,0,1,1]:
|
||||
return 1 # horizontal
|
||||
if board==[1,0,1,0] or board==[0,1,0,1]:
|
||||
return 2 # vertical
|
||||
if board==[1,0,0,1] or board==[0,1,1,0]:
|
||||
return 3 # diagonal
|
||||
if s==3:
|
||||
return guess_key_2x2(all_flipped(board))
|
||||
if s==4:
|
||||
return guess_key_2x2(all_flipped(board))
|
||||
assert False
|
||||
|
||||
|
||||
def flip_mutate(board: List[int], flip_pos: int):
|
||||
board[flip_pos] = 1-board[flip_pos]
|
||||
|
||||
def flip_copy(board: List[int], flip_pos: int) -> List[int]:
|
||||
board = board[:]
|
||||
flip_mutate(board, flip_pos)
|
||||
return board
|
||||
|
||||
def print_board(board: List[int]):
|
||||
sidelength = sqrt(len(board))
|
||||
assert sidelength == int(sidelength)
|
||||
sidelength = int(sidelength)
|
||||
for row_i in range(sidelength):
|
||||
print(''.join(str(x) for x in board[row_i*sidelength:(row_i+1)*sidelength]))
|
||||
|
||||
def generate_boards(board_squre_count: int, sample_count: int) -> Iterable[int]:
|
||||
if sample_count >= 2**board_squre_count:
|
||||
print('doing exhaustive verification.')
|
||||
yield from range(2**board_squre_count)
|
||||
print(f'not doing exhaustive. need sample_count>={2**board_squre_count}, got sample_count={sample_count}')
|
||||
rng = Random(4)
|
||||
for i in range(sample_count):
|
||||
yield rng.getrandbits(board_squre_count)
|
||||
|
||||
|
||||
def validate(board_squre_count, get_flip_pos: Callable, guess_key: Callable, sample_count=2**16) -> bool:
|
||||
success_boards = set()
|
||||
|
||||
for sample_i, board_int in enumerate(generate_boards(board_squre_count, sample_count)):
|
||||
if board_int in success_boards:
|
||||
continue
|
||||
|
||||
if sample_i %100 == 0:
|
||||
print(sample_i/sample_count)
|
||||
for key in range(board_squre_count):
|
||||
# potential optimization: could re-use board and unflip guess
|
||||
board = [(board_int>>i)&1 for i in reversed(range(board_squre_count))]
|
||||
|
||||
flip_pos = get_flip_pos(board, key)
|
||||
flip_mutate(board, flip_pos)
|
||||
guess = guess_key(board)
|
||||
if guess != key:
|
||||
print(f'Found counter example. Got guess {guess}, want {key}')
|
||||
flip_mutate(board, flip_pos)
|
||||
print('before flip:')
|
||||
print_board(board)
|
||||
flip_mutate(board, flip_pos)
|
||||
print('after flip:')
|
||||
print_board(board)
|
||||
return False
|
||||
|
||||
success_boards.add(board_int)
|
||||
if len(success_boards) == 2**board_squre_count:
|
||||
# All boards have been validated
|
||||
print('exhaustive, yay')
|
||||
return True
|
||||
print(f'non exhaustive finish. covered {len(success_boards)} cases ({len(success_boards) / 2**board_squre_count:%} of cases) successfully')
|
||||
return True
|
||||
|
||||
# validate(4, get_flip_pos_2x2, guess_key_2x2)
|
||||
|
||||
# Scaler possibilities:
|
||||
# Total key index % 4 if we split into 4-squares
|
||||
# is each reg
|
||||
# XOR each 4x4 section into a bit to determine which quadrant
|
||||
# layer each 4x4 section with XOR, to determine which quadrant in the above 4x4
|
||||
# layer each 2x2 section with XOR, to determine which quadrant in 2x2
|
||||
|
||||
def guess_key_pow2board(board: List[int]) -> int:
|
||||
if len(board) == 4:
|
||||
return guess_key_2x2(board)
|
||||
|
||||
sidelength = sqrt(len(board))
|
||||
assert sidelength == int(sidelength)
|
||||
sidelength = int(sidelength)
|
||||
assert log2(sidelength) == int(log2(sidelength))
|
||||
quarter = len(board) / 4
|
||||
assert quarter == int(quarter)
|
||||
quarter = int(quarter)
|
||||
|
||||
# Not actually quadrants but good enough
|
||||
quadrants = [ board[i*quarter:(i+1)*quarter] for i in range(0,4) ]
|
||||
|
||||
quarter_i = guess_key_2x2([ reduce(lambda a,b: a^b, q) for q in quadrants ])
|
||||
sub_i = guess_key_pow2board([a^b^c^d for a,c,b,d in zip(*quadrants)])
|
||||
return quarter * quarter_i + sub_i
|
||||
|
||||
def make_get_flip_pos(guess_key: Callable) -> Callable:
|
||||
|
||||
# Flip the thing that works
|
||||
def get_flip_pos(board, key) -> int:
|
||||
possibilities = [
|
||||
flip_pos for flip_pos in range(len(board))
|
||||
if guess_key(flip_copy(board, flip_pos)) == key
|
||||
]
|
||||
assert len(possibilities) == 1, f"possibilities={possibilities} want length 1"
|
||||
return possibilities[0]
|
||||
return get_flip_pos
|
||||
|
||||
def get_flip_pos_pow2board(board: List[int], key: int) -> int:
|
||||
if len(board) == 4:
|
||||
return get_flip_pos_2x2(board, key)
|
||||
quarter = len(board) / 4
|
||||
assert quarter == int(quarter)
|
||||
quarter = int(quarter)
|
||||
|
||||
# Not actually quadrants but good enough
|
||||
quadrants = [ board[i*quarter:(i+1)*quarter] for i in range(0,4) ]
|
||||
quarter_i = get_flip_pos_2x2([ reduce(lambda a,b: a^b, q) for q in quadrants ], key//4)
|
||||
sub_i = get_flip_pos_pow2board([a^b^c^d for a,c,b,d in zip(*quadrants)], key%4)
|
||||
return quarter * quarter_i + sub_i
|
||||
|
||||
|
||||
# validate(4, make_get_flip_pos(guess_key_2x2), guess_key_2x2)
|
||||
# validate(16, make_get_flip_pos(guess_key_pow2board), guess_key_pow2board)
|
||||
# validate(16, get_flip_pos_pow2board, guess_key_pow2board)
|
||||
validate(64, get_flip_pos_pow2board, guess_key_pow2board)
|
||||
# validate(64, make_get_flip_pos(guess_key_pow2board), guess_key_pow2board)
|
||||
|
86
Can you solve the rogue submarine riddle.py
Normal file
86
Can you solve the rogue submarine riddle.py
Normal file
@ -0,0 +1,86 @@
|
||||
from collections import Counter
|
||||
from pprint import pprint
|
||||
|
||||
basis = [1,2,3,4,5,6]
|
||||
|
||||
def get_all_subsets(l):
|
||||
if l == []:
|
||||
return [[]]
|
||||
subs = get_all_subsets(l[1:])
|
||||
return subs + [[l[0]] + el for el in subs]
|
||||
|
||||
all_subsets = get_all_subsets(basis)
|
||||
all_subsets = sorted([sub for sub in all_subsets if len(sub) >= 2])
|
||||
# all_subsets = sorted([sub for sub in all_subsets if len(sub) >= 2])
|
||||
# all_subsets = sorted([sub for sub in all_subsets if sum(sub) < 9])
|
||||
|
||||
def product(sub):
|
||||
if len(sub) == 0:
|
||||
return 1
|
||||
return sub[0] * product(sub[1:])
|
||||
|
||||
def sort_keys(counter: Counter) -> Counter:
|
||||
out = Counter()
|
||||
for key in sorted(counter.keys()):
|
||||
out[key] = counter[key]
|
||||
return out
|
||||
|
||||
def print_sorted_by_key(counter: Counter) -> Counter:
|
||||
print('{')
|
||||
for key in sorted(counter.keys()):
|
||||
print(f' {key}: {counter[key]},')
|
||||
print('}')
|
||||
|
||||
|
||||
sum_counter = Counter(sum(sub) for sub in all_subsets)
|
||||
product_counter = Counter(product(sub) for sub in all_subsets)
|
||||
product_counter_unique_sum = Counter(product(sub) for sub in all_subsets if sum_counter[sum(sub)] > 1)
|
||||
|
||||
#debug
|
||||
print_sorted_by_key(sum_counter)
|
||||
print_sorted_by_key(product_counter)
|
||||
|
||||
print(sum([3,4,5,6]))
|
||||
print(product([3,4,5,6]))
|
||||
print('a', [(sub, sum(sub)) for sub in all_subsets if sum(sub)==18])
|
||||
print('b', [(sub, product(sub)) for sub in all_subsets if product(sub)==360])
|
||||
print(sum([3,4,5,6]))
|
||||
print(sum([1,3,4,5,6]))
|
||||
|
||||
|
||||
print('xxx')
|
||||
|
||||
# solve it one way
|
||||
for sub in all_subsets:
|
||||
if sum_counter[sum(sub)] > 1 and product_counter_unique_sum[product(sub)] == 1:
|
||||
print(sub, sum(sub), product(sub))
|
||||
|
||||
print('xxx')
|
||||
|
||||
# solve it one way
|
||||
for sub in all_subsets:
|
||||
if sum_counter[sum(sub)] > 1 and product_counter[product(sub)] == 1:
|
||||
print(sub, sum(sub), product(sub))
|
||||
|
||||
print('yyy')
|
||||
|
||||
# solve it another way
|
||||
for answer_sum in range(100):
|
||||
if sum_counter[answer_sum] == 0:
|
||||
continue
|
||||
has_some_determined = False
|
||||
has_some_undetermined = False
|
||||
for sub in all_subsets:
|
||||
if not sum(sub) == answer_sum:
|
||||
continue
|
||||
if product_counter[product(sub)] > 1:
|
||||
has_some_undetermined += True
|
||||
if product_counter[product(sub)] == 1:
|
||||
has_some_determined += True
|
||||
|
||||
if not (has_some_determined and has_some_undetermined):
|
||||
continue
|
||||
|
||||
print(answer_sum, has_some_determined, has_some_undetermined)
|
||||
# print(sub, sum(sub), product(sub))
|
||||
# print()
|
148
Dongle's Difficult Dilemma.py
Normal file
148
Dongle's Difficult Dilemma.py
Normal file
@ -0,0 +1,148 @@
|
||||
# https://www.youtube.com/watch?v=8xXslshomOs
|
||||
from typing import Dict, Optional
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True, order=True)
|
||||
class State:
|
||||
gold_a: int
|
||||
gold_b: int
|
||||
silver_a: int
|
||||
silver_b: int
|
||||
gems_a: int
|
||||
gems_b: int
|
||||
equal_priority: bool # 0 means "a", which is the protagonist
|
||||
|
||||
|
||||
winner_cache : Dict[State, int] = {}
|
||||
|
||||
def resolve_auction(state: State, bet_a: int, bet_b: int) -> Optional[State]:
|
||||
if bet_b > state.gems_b:
|
||||
return None
|
||||
assert bet_a <= state.gems_a
|
||||
|
||||
equal_priority = state.equal_priority
|
||||
if bet_a > bet_b:
|
||||
bet_winner = 0
|
||||
elif bet_a < bet_b:
|
||||
bet_winner = 1
|
||||
else:
|
||||
bet_winner = int(equal_priority)
|
||||
equal_priority = 1 - equal_priority
|
||||
|
||||
doing_golds = state.gold_a + state.gold_b <3
|
||||
return State(
|
||||
gold_a=state.gold_a + 1 if doing_golds and bet_winner == 0 else state.gold_a,
|
||||
gold_b=state.gold_b + 1 if doing_golds and bet_winner == 1 else state.gold_b,
|
||||
silver_a=state.silver_a + 1 if not doing_golds and bet_winner == 0 else state.silver_a,
|
||||
silver_b=state.silver_b + 1 if not doing_golds and bet_winner == 1 else state.silver_b,
|
||||
gems_a=state.gems_a - bet_a if bet_winner == 0 else state.gems_a,
|
||||
gems_b=state.gems_b - bet_b if bet_winner == 1 else state.gems_b,
|
||||
equal_priority=equal_priority,
|
||||
)
|
||||
|
||||
|
||||
next_print = 1
|
||||
|
||||
def get_winner(state: State) -> int:
|
||||
if state.gold_a >= 3:
|
||||
winner_cache[state] = 0; return 0, (state,)
|
||||
if state.gold_b >= 3:
|
||||
winner_cache[state] = 1; return 1, (state,)
|
||||
if state.silver_a >= 3:
|
||||
winner_cache[state] = 0; return 0, (state,)
|
||||
if state.silver_b >= 3:
|
||||
winner_cache[state] = 1; return 1, (state,)
|
||||
winner = winner_cache.get(state)
|
||||
if winner is not None:
|
||||
return winner, (state,)
|
||||
|
||||
|
||||
doing_golds = state.gold_a + state.gold_b <3
|
||||
child_states = []
|
||||
path = tuple()
|
||||
|
||||
# minimax
|
||||
winner_a = 1
|
||||
for bet_a in range(state.gems_a+1):
|
||||
(winner_b, path) = max([
|
||||
get_winner(child)
|
||||
for child in
|
||||
[resolve_auction(state, bet_a, bet_b) for bet_b in {0, bet_a, bet_a+1}]
|
||||
if child
|
||||
])
|
||||
winner_a = min(winner_a, winner_b)
|
||||
if winner_a == 0:
|
||||
path = (state, bet_a) + path
|
||||
# break
|
||||
|
||||
winner_cache[state] = winner_a
|
||||
global next_print
|
||||
if len(winner_cache) > next_print:
|
||||
print(len(winner_cache))
|
||||
next_print *= 2
|
||||
|
||||
return winner_a, path
|
||||
|
||||
initial_state = State(
|
||||
gold_a=1,
|
||||
gold_b=0,
|
||||
silver_a=0,
|
||||
silver_b=0,
|
||||
gems_a=75,
|
||||
gems_b=99,
|
||||
equal_priority=0,
|
||||
)
|
||||
import pickle
|
||||
cache_file = __file__+".winner_cache.pickle"
|
||||
|
||||
# print(get_winner(initial_state))
|
||||
# with open(cache_file, 'wb') as f:
|
||||
# pickle.dump(winner_cache, f)
|
||||
|
||||
with open(cache_file, 'rb') as f:
|
||||
winner_cache = pickle.load(f)
|
||||
|
||||
# print(winner_cache)
|
||||
|
||||
def find_children(state):
|
||||
child_states = []
|
||||
for bet_a in range(state.gems_a+1):
|
||||
responses = [resolve_auction(state, bet_a, bet_b) for bet_b in {0, bet_a, bet_a+1}]
|
||||
if any(winner_cache.get(res) == 1 for res in responses):
|
||||
responses = [res for res in responses if winner_cache.get(res) == 1]
|
||||
child_states.extend(responses)
|
||||
return [state for state in child_states if state is not None]
|
||||
|
||||
def find_winning_children(state):
|
||||
return [state for state in find_children(state) if winner_cache.get(state) == 0]
|
||||
|
||||
def print_bets(state0, state1):
|
||||
for bet_a in range(state0.gems_a+1):
|
||||
for bet_b in {0, bet_a, bet_a+1}:
|
||||
res = resolve_auction(state0, bet_a, bet_b)
|
||||
if res == state1:
|
||||
print(f'bet_a={bet_a} bet_b={bet_b}')
|
||||
|
||||
|
||||
def get_winning_path(state: State):
|
||||
get_winning_option_fraction = lambda child: len(find_winning_children(child)) / max(1, len(find_children(child)))
|
||||
print()
|
||||
print(len(find_winning_children(state)), "/", len(find_children(state)))
|
||||
print(state)
|
||||
|
||||
|
||||
winner = winner_cache.get(state)
|
||||
|
||||
child_states = find_winning_children(state)
|
||||
if not child_states:
|
||||
print('fin')
|
||||
return
|
||||
|
||||
choice = min(child_states, key=get_winning_option_fraction)
|
||||
print_bets(state, choice)
|
||||
# for child in child_states:
|
||||
# print(" " + (">" if child is choice else " ") + " " + repr(child))
|
||||
get_winning_path(choice)
|
||||
|
||||
get_winning_path(initial_state)
|
BIN
Dongle's Difficult Dilemma.py.winner_cache.pickle
Normal file
BIN
Dongle's Difficult Dilemma.py.winner_cache.pickle
Normal file
Binary file not shown.
77
bad apple/bad_apple.py
Normal file
77
bad apple/bad_apple.py
Normal file
@ -0,0 +1,77 @@
|
||||
import pyperclip
|
||||
|
||||
from draftsman.blueprintable import Blueprint, BlueprintBook
|
||||
from draftsman.constants import Direction
|
||||
from draftsman.entity import ConstantCombinator
|
||||
|
||||
# from draftsman.data import items
|
||||
import draftsman.data.signals
|
||||
from PIL import Image
|
||||
|
||||
blueprint = Blueprint()
|
||||
blueprint.label = "bad apple"
|
||||
blueprint.description = "bad apple."
|
||||
blueprint.version = (1, 0) # 1.0
|
||||
|
||||
frame = Image.open("frame.png")
|
||||
threshold = 40
|
||||
signals = list(draftsman.data.signals.raw)[3:] # skip the three special signals
|
||||
|
||||
|
||||
pixels = frame.load()
|
||||
|
||||
# Create the combinator for the single frame
|
||||
frame_combinator = ConstantCombinator()
|
||||
frame_combinator.tile_position = (-1, 0)
|
||||
for x in range(frame.width):
|
||||
column_mask = 0
|
||||
for y in range(frame.height):
|
||||
if pixels[x, y][0] > threshold:
|
||||
column_mask |= 1 << y
|
||||
frame_combinator.set_signal(index=x, signal=signals[x], count=column_mask)
|
||||
blueprint.entities.append(frame_combinator)
|
||||
|
||||
pyperclip.copy(blueprint.to_string())
|
||||
|
||||
# Code for creating the column filters below.
|
||||
|
||||
# for x in range(frame.width):
|
||||
# blueprint.entities.append( # this is our y-combinator :^)
|
||||
# "arithmetic-combinator",
|
||||
# id=f"filter-{x}",
|
||||
# tile_position=[x, 2],
|
||||
# direction=Direction.NORTH,
|
||||
# control_behavior={
|
||||
# "arithmetic_conditions": {
|
||||
# "first_signal": signals[x],
|
||||
# "operation": "AND",
|
||||
# "second_signal": {"type": "virtual", "name": "signal-each"},
|
||||
# "output_signal": {"type": "virtual", "name": "signal-each"},
|
||||
# }
|
||||
# },
|
||||
# )
|
||||
|
||||
|
||||
# arithmetic_conditions = {
|
||||
# "first_signal": {"type": "fluid", "name": "steam"},
|
||||
# "second_signal": {"type": "virtual", "name": "signal-each"},
|
||||
# "operation": "AND",
|
||||
# "output_signal": {"type": "virtual", "name": "signal-each"},
|
||||
# "first_signal_networks": {"red": True, "green": False},
|
||||
# "second_signal_networks": {"red": False, "green": True},
|
||||
# }
|
||||
|
||||
# from draftsman.utils import JSON_to_string
|
||||
|
||||
# # directly hack in these conditions because this is a new feature and we don't care about the validation bullshit
|
||||
# d = blueprint.to_dict()
|
||||
# for entity in d["blueprint"]["entities"]:
|
||||
# entity["control_behavior"]["arithmetic_conditions"][
|
||||
# "first_signal_networks"
|
||||
# ] = {"red": True, "green": False}
|
||||
# entity["control_behavior"]["arithmetic_conditions"][
|
||||
# "second_signal_networks"
|
||||
# ] = {"red": False, "green": True}
|
||||
|
||||
# s = JSON_to_string(d)
|
||||
# pyperclip.copy(str(s))
|
BIN
bad apple/frame.png
Normal file
BIN
bad apple/frame.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 803 B |
60
beltomatic.py
Normal file
60
beltomatic.py
Normal file
@ -0,0 +1,60 @@
|
||||
# from math import abs
|
||||
from collections import defaultdict
|
||||
|
||||
max_num = 16
|
||||
initial_nums = list(range(1, max_num + 1))
|
||||
initial_nums.remove(10)
|
||||
|
||||
# end number -> list of steps to get here which are
|
||||
# (prev_number, operation description)
|
||||
|
||||
target = 7387
|
||||
|
||||
upper_bound = target * max_num
|
||||
ops = []
|
||||
for n in initial_nums:
|
||||
ops.append((lambda x, n=n: x + n, f"+{n}"))
|
||||
ops.append((lambda x, n=n: abs(x - n), f"-{n}"))
|
||||
ops.append((lambda x, n=n: x * n, f"*{n}"))
|
||||
ops.append((lambda x, n=n: x // n if x and x % n == 0 else x, f"/{n}"))
|
||||
ops.append((lambda x, n=n: x**n if x**2 < upper_bound else x, f"**{n}"))
|
||||
|
||||
|
||||
seen = {n: [] for n in initial_nums}
|
||||
recent = seen.keys()
|
||||
|
||||
while target not in seen:
|
||||
news = defaultdict(list)
|
||||
for n in recent:
|
||||
for op, description in ops:
|
||||
new = op(n)
|
||||
if new > upper_bound:
|
||||
continue
|
||||
if new in seen:
|
||||
continue
|
||||
news[new].append((n, description))
|
||||
seen.update(news)
|
||||
recent = sorted(news.keys())
|
||||
if not news:
|
||||
assert False
|
||||
|
||||
print(f"progress: {len(seen)=}")
|
||||
|
||||
|
||||
pickers = [
|
||||
lambda l: l[0],
|
||||
lambda l: l[len(l) // 2],
|
||||
lambda l: l[-1],
|
||||
]
|
||||
for picker in pickers:
|
||||
steps = [target]
|
||||
picks = []
|
||||
while prevs := seen[steps[-1]]:
|
||||
pick = picker(prevs)
|
||||
picks.append(pick)
|
||||
steps.append(pick[0])
|
||||
|
||||
print(f"{steps[-1]:>3}", end=" ")
|
||||
for pick in reversed(picks):
|
||||
print(f"{pick[1]:>4}", end=" ")
|
||||
print(f" = {target}")
|
37
cheating royal riddle.py
Normal file
37
cheating royal riddle.py
Normal file
@ -0,0 +1,37 @@
|
||||
# https://www.youtube.com/watch?v=hk9c7sJ08Bg
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
distribution = {0:1}
|
||||
|
||||
|
||||
def print_sorted_by_key(counter):
|
||||
print('{')
|
||||
for key in sorted(counter.keys()):
|
||||
print(f' {key}: {counter[key]},')
|
||||
print('}')
|
||||
|
||||
def convolve(distribution, equally_weighted_dice):
|
||||
d2 = defaultdict(float)
|
||||
for k,v in distribution.items():
|
||||
for red in equally_weighted_dice:
|
||||
d2[k+red] += v/len(equally_weighted_dice)
|
||||
return d2
|
||||
|
||||
|
||||
for _ in range(20):
|
||||
distribution = convolve(distribution, [2,7,7,12,12, 17])
|
||||
distribution = convolve(distribution, [3,8,8,13,13, 18])
|
||||
|
||||
|
||||
# print_sorted_by_key(distribution)
|
||||
|
||||
cumulative = defaultdict(float)
|
||||
acc = 0
|
||||
for k in sorted(distribution):
|
||||
acc += distribution[k]
|
||||
cumulative[k] = acc
|
||||
|
||||
# print_sorted_by_key(distribution)
|
||||
# print(sum(distribution.values()))
|
||||
print_sorted_by_key(cumulative)
|
55
chef puzzle.py
Normal file
55
chef puzzle.py
Normal file
@ -0,0 +1,55 @@
|
||||
# https://www.youtube.com/watch?v=HyRjuPP9S3o
|
||||
|
||||
from collections import Counter
|
||||
|
||||
max_val = 1300
|
||||
|
||||
possibilities = list(range(13, max_val+1))
|
||||
|
||||
# exclusions = {64, 729}
|
||||
|
||||
|
||||
perfect_squares = {x*x for x in range(100)}
|
||||
perfect_cubes = {x*x*x for x in range(100) if x*x*x <= max_val}
|
||||
|
||||
|
||||
|
||||
def less_than_500(x):
|
||||
return x < 500
|
||||
|
||||
def is_perfect_square(x):
|
||||
return x in perfect_squares
|
||||
|
||||
def is_perfect_cube(x):
|
||||
return x in perfect_cubes
|
||||
|
||||
def second_digit_1(x):
|
||||
return str(x)[1] == "1"
|
||||
|
||||
|
||||
# print([x for x in possibilities if is_perfect_cube(x) and is_perfect_square(x)])
|
||||
|
||||
# invert invert second digit is a 1
|
||||
conditions = [less_than_500, is_perfect_square, is_perfect_cube]
|
||||
for mask in range(2**3):
|
||||
pos = set(possibilities)
|
||||
for x in possibilities:
|
||||
for i, condition in enumerate(conditions):
|
||||
if not (condition(x) ^ (mask & (1 << i))):
|
||||
pos.remove(x)
|
||||
break
|
||||
|
||||
if 1 in Counter(second_digit_1(x) for x in pos).values():
|
||||
print(mask, pos)
|
||||
|
||||
# print(mask, pos)
|
||||
|
||||
|
||||
# What was said
|
||||
# it is >500 (lie)
|
||||
# it
|
||||
|
||||
# truth
|
||||
# less than 500
|
||||
# perfect square
|
||||
# perfect
|
114
cnf_or_tuples.py
Normal file
114
cnf_or_tuples.py
Normal file
@ -0,0 +1,114 @@
|
||||
################ solver
|
||||
from itertools import chain, combinations
|
||||
from functools import reduce
|
||||
|
||||
|
||||
def powerset(iterable):
|
||||
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
|
||||
s = list(iterable)
|
||||
return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))
|
||||
|
||||
|
||||
def check_solution(selection, operator):
|
||||
return reduce(
|
||||
lambda a, b: tuple(operator(x, y) for x, y in zip(a, b)), selection
|
||||
)
|
||||
|
||||
|
||||
def tuple_selector(tuples, operator):
|
||||
solution_count = 0
|
||||
for selection in powerset(tuples):
|
||||
if not selection:
|
||||
continue
|
||||
if all(check_solution(selection, operator)):
|
||||
print(f"found a solution! {selection}")
|
||||
solution_count += 1
|
||||
print(f"{solution_count=}")
|
||||
|
||||
|
||||
################# problem statement
|
||||
|
||||
|
||||
def operator_with_secret(a: int, b: int) -> int:
|
||||
either = {a, b}
|
||||
if 1 in either:
|
||||
return a + b % 2
|
||||
# if 0 in either:
|
||||
# return 0
|
||||
|
||||
# final element that must be included
|
||||
if 2 in either:
|
||||
# The x's represent free choices.
|
||||
# 0bxxxxxxx00
|
||||
secret = 0b010110100
|
||||
return 3 if secret in either else 0
|
||||
|
||||
# build your own number kit
|
||||
return a | b
|
||||
|
||||
|
||||
tuple_selector(
|
||||
[
|
||||
# make a choice to set a bit in the first number
|
||||
(0b000000100, 0, 1, 0, 0, 0, 0, 0, 0),
|
||||
(0b000001000, 0, 0, 1, 0, 0, 0, 0, 0),
|
||||
(0b000010000, 0, 0, 0, 1, 0, 0, 0, 0),
|
||||
(0b000100000, 0, 0, 0, 0, 1, 0, 0, 0),
|
||||
(0b001000000, 0, 0, 0, 0, 0, 1, 0, 0),
|
||||
(0b010000000, 0, 0, 0, 0, 0, 0, 1, 0),
|
||||
(0b100000000, 0, 0, 0, 0, 0, 0, 0, 1),
|
||||
# .. or not
|
||||
(0b000000000, 0, 1, 0, 0, 0, 0, 0, 0),
|
||||
(0b000000000, 0, 0, 1, 0, 0, 0, 0, 0),
|
||||
(0b000000000, 0, 0, 0, 1, 0, 0, 0, 0),
|
||||
(0b000000000, 0, 0, 0, 0, 1, 0, 0, 0),
|
||||
(0b000000000, 0, 0, 0, 0, 0, 1, 0, 0),
|
||||
(0b000000000, 0, 0, 0, 0, 0, 0, 1, 0),
|
||||
(0b000000000, 0, 0, 0, 0, 0, 0, 0, 1),
|
||||
# this final element that must be included
|
||||
(0b000000010, 1, 0, 0, 0, 0, 0, 0, 0),
|
||||
],
|
||||
operator_with_secret,
|
||||
)
|
||||
|
||||
|
||||
# Commutative operator variant
|
||||
def operator_with_secret(a: int, b: int) -> int:
|
||||
|
||||
# We're going to create a bitpacked representation of the state of the
|
||||
# computation. The state is the number of records included, and the value
|
||||
# is a bitwise OR of the records included. The state is stored in the
|
||||
# first slot of each tuple, but this operator doesn't know which slot is
|
||||
# first, so we just check to see if the value is greater than 1.
|
||||
value_bits = 9
|
||||
total_records_to_select = 8
|
||||
|
||||
def extract(bitpacked: int) -> Tuple[int, int]:
|
||||
count = bitpacked >> value_bits
|
||||
value = bitpacked & ((1 << value_bits) - 1)
|
||||
return (count if count else 1), value
|
||||
|
||||
def pack(count: int, value: int) -> int:
|
||||
return (count << value_bits) | value
|
||||
|
||||
either = {a, b}
|
||||
# If we're building our state in the first slot, handle it
|
||||
if any(x > 1 for x in either):
|
||||
# Unpack the state from each input
|
||||
# State is just how many records have been included so far, and the
|
||||
# value which has been built
|
||||
ac, av = extract(a)
|
||||
bc, bv = extract(b)
|
||||
count, value = ac + bc, av | bv
|
||||
# If we haven't inluded eight records yet, just build up the number
|
||||
if count < total_records_to_select:
|
||||
return pack(count, value)
|
||||
# If we've included eight records, we're done and need to check the
|
||||
# value is what we wanted
|
||||
# The x's represent free choices.
|
||||
# 0bxxxxxxx00
|
||||
secret = 0b010110100
|
||||
return 3 if value == secret else 0
|
||||
|
||||
# Otherwise, we're just checking that we select at least one truthy value
|
||||
return a | b
|
153
double_decker_train_problem.py
Normal file
153
double_decker_train_problem.py
Normal file
@ -0,0 +1,153 @@
|
||||
"""
|
||||
Double decker train problem:
|
||||
|
||||
|^^^^^^^^^^^^^^| |^^^^^^^^^^^^^^|
|
||||
| Double cargo | | wagon |
|
||||
~~~~ ____ |--------------| |--------------|
|
||||
Y_,___|[]| | Double | | cargo wagon |
|
||||
{|_|_|_|PU|_,_|______________|_,_|______________|
|
||||
//oo---OO=OO O-O O-O ^ O-O O-O ^
|
||||
|
||||
This is a deceptively simple programming puzzle where you get to make an ordering of rail wagons.
|
||||
Each wagon has two floors and there is text on the outside of the top and bottom floor.
|
||||
When your chosen wagons are linked together, the whole text on the top should match the whole bottom.
|
||||
Output an empty list only when there is no non-empty choice of wagons with matching text.
|
||||
Your ordering may include any wagon any number of times.
|
||||
|
||||
Example: (illustrated above)
|
||||
Input wagons: [("Double cargo ", "Double "), ("wagon", "cargo wagon")]
|
||||
Output ordering: [0, 1]
|
||||
|
||||
Explanation:
|
||||
Both the top and bottom will read "Double cargo wagon" when concatenated.
|
||||
Note that there is no need to mutate whitespace characters in the input.
|
||||
"""
|
||||
|
||||
from typing import Callable, List, Optional, Tuple
|
||||
|
||||
Wagon = Tuple[str, str]
|
||||
|
||||
|
||||
MAX_LENGTH = 10
|
||||
|
||||
def my_solver(wagons: List[Wagon]) -> List[int]:
|
||||
# Handle empty wagon case
|
||||
for i, wagon in enumerate(wagons):
|
||||
if wagon[0] + wagon[1] == "":
|
||||
return [i]
|
||||
return solve("", "", [], prepare(wagons))
|
||||
|
||||
def prepare(wagons: List[Wagon]) -> List[Tuple[int, Wagon]]:
|
||||
seen = set()
|
||||
prepared = []
|
||||
for i, wagon in enumerate(wagons):
|
||||
if wagon in seen:
|
||||
continue
|
||||
prepared.append((i, wagon))
|
||||
seen.add(wagon)
|
||||
return prepared
|
||||
|
||||
def solve(top_text: str, bottom_text: str, ordering: List[int], wagons: List[Tuple[int, Wagon]]) -> List[int]:
|
||||
if len(top_text) == 0 and len(bottom_text) == 0 and len(ordering) > 0:
|
||||
return ordering
|
||||
if len(ordering) > MAX_LENGTH:
|
||||
return []
|
||||
|
||||
for z, (i, wagon) in enumerate(wagons):
|
||||
top = top_text + wagon[0]
|
||||
bottom = bottom_text + wagon[1]
|
||||
reordered = wagons[:z] + wagons[z+1:] + [(i, wagon)]
|
||||
if top.startswith(bottom):
|
||||
solution = solve(top[len(bottom):], "", [*ordering, i], reordered)
|
||||
if len(solution) > 0:
|
||||
return solution
|
||||
if bottom.startswith(top):
|
||||
solution = solve("", bottom[len(top):], [*ordering, i], reordered)
|
||||
if len(solution) > 0:
|
||||
return solution
|
||||
|
||||
return []
|
||||
|
||||
def check_ordering(wagons: List[Wagon], ordering: List[int]) -> bool:
|
||||
"""Checks if the text on top matches the text on the bottom"""
|
||||
sentence0 = ""
|
||||
sentence1 = ""
|
||||
for i in ordering:
|
||||
assert 0 <= i < len(wagons), f"wagon index out of range: {i}"
|
||||
sentence0 += wagons[i][0]
|
||||
sentence1 += wagons[i][1]
|
||||
return sentence0 == sentence1
|
||||
|
||||
|
||||
def run_test_case(
|
||||
wagons: List[Wagon],
|
||||
example_ordering: List[int],
|
||||
ordering: List[int],
|
||||
) -> str:
|
||||
if ordering == []:
|
||||
if example_ordering == []:
|
||||
return "PASS"
|
||||
return "You falsely claimed it was impossible."
|
||||
|
||||
if check_ordering(wagons, ordering):
|
||||
if example_ordering == []:
|
||||
return "PASS (and the problem setter is a dummy)"
|
||||
return "PASS"
|
||||
|
||||
sentence0 = ""
|
||||
sentence1 = ""
|
||||
for i in ordering:
|
||||
assert 0 <= i < len(wagons), f"wagon index out of range: {i}"
|
||||
sentence0 += wagons[i][0]
|
||||
sentence1 += wagons[i][1]
|
||||
|
||||
# return f"Your selected wagons had different sentences on the top and bottom.\n{ordering}\n{sentence0!r}\n{sentence1!r}"
|
||||
|
||||
return "Your selected wagons had different sentences on the top and bottom."
|
||||
|
||||
|
||||
def run_test_cases(solver: Callable[[List[Wagon]], List[int]]):
|
||||
test_cases: Tuple[List[Wagon], List[int]] = [
|
||||
([("Double cargo ", "Double "), ("wagon", "cargo wagon")], [0, 1]),
|
||||
([("wagon", "cargo wagon"), ("Double cargo ", "Double ")], [1, 0]),
|
||||
([("Hello ", "Hello"), ("World", " World")], [0, 1]),
|
||||
([("", "")], [0]),
|
||||
([(".", "-.."), (".-", ".."), ("--.", "--")], [2, 1, 2, 0]),
|
||||
([("bc", "ca"), ("a", "ab"), ("ca", "a"), ("abc", "c")], [1, 0, 1, 3]),
|
||||
([("yy", "y"), ("xy", "yx"), ("z", "yz")], [0, 1, 1, 1, 1, 1, 2]),
|
||||
([("", "42"), ("42", "")], [1, 0]),
|
||||
([("aaaa", ""), ("", "a")], [0, 1, 1, 1, 1]),
|
||||
([], []),
|
||||
([("0", "1")], []),
|
||||
([("0", "1"), (" ", " ")], []),
|
||||
([("", " ")], []),
|
||||
([("aa", "a"), ("aa", "a"), ("b", "ab")], [0, 2]),
|
||||
([("aa", ""), ("ab", ""), ("", "aa")], [0, 2]),
|
||||
([("aa", ""), ("ab", "")], []),
|
||||
([("ab", "a"), ("ab", "b")], []),
|
||||
([("aaaa", ""), ("", "a")], [0, 1, 1, 1, 1]),
|
||||
([("ab"*1000, ""), ("a", "ab"), ("b", "ab")], [0] + [1,2]*1000),
|
||||
([("a"*(2**4*3**5), ""), ("", "aa"), ("", "aaa")], [0]+[1]*2**4 +[2]*3**5),
|
||||
|
||||
# ([("ab", "a"), ("ab", "b")], []),
|
||||
# TODO: add more test cases
|
||||
]
|
||||
for i, (wagons, example_ordering) in enumerate(test_cases):
|
||||
print(f"Test case {i:>2}: ", end="")
|
||||
if not check_ordering(wagons, example_ordering):
|
||||
sentence0 = ""
|
||||
sentence1 = ""
|
||||
for i in example_ordering:
|
||||
assert 0 <= i < len(wagons), f"wagon index out of range: {i}"
|
||||
sentence0 += wagons[i][0]
|
||||
sentence1 += wagons[i][1]
|
||||
print(sentence0)
|
||||
print(sentence1)
|
||||
|
||||
|
||||
assert check_ordering(wagons, example_ordering), "example is invalid, dummy."
|
||||
|
||||
print(run_test_case(wagons, example_ordering, solver(wagons)))
|
||||
|
||||
|
||||
run_test_cases(my_solver)
|
32
factorio nuclear power calculation.py
Normal file
32
factorio nuclear power calculation.py
Normal file
@ -0,0 +1,32 @@
|
||||
mega = 1000000
|
||||
giga = mega * 1000
|
||||
steam_joules = 5.8 * mega / 60
|
||||
|
||||
|
||||
# print(steam_joulesw)
|
||||
|
||||
# target_power = d * giga / 120
|
||||
target_power = 2.28 * giga
|
||||
print(target_power)
|
||||
|
||||
turbine_power = 5.82*mega
|
||||
turbine_count = target_power / turbine_power
|
||||
print('number of turbines', turbine_count)
|
||||
|
||||
duration = 120
|
||||
turbine_steam_per_second = 60
|
||||
|
||||
steam_required = turbine_count * duration * turbine_steam_per_second
|
||||
steam_tanks = steam_required / 25000
|
||||
steam_tanks = 12*12
|
||||
print('steam_tanks', steam_tanks)
|
||||
|
||||
|
||||
tanks_in_row = 6
|
||||
row_count = steam_tanks / tanks_in_row
|
||||
turbines_per_row = turbine_count / row_count
|
||||
|
||||
print(f'row_count: {row_count}')
|
||||
print(f'turbines_per_row: {turbines_per_row}')
|
||||
|
||||
print(25*6)
|
0
factorio nuclear power calculation.txt
Normal file
0
factorio nuclear power calculation.txt
Normal file
38
generators_example.py
Normal file
38
generators_example.py
Normal file
@ -0,0 +1,38 @@
|
||||
from contextlib import contextmanager
|
||||
|
||||
|
||||
@contextmanager
|
||||
def my_context_manager():
|
||||
print("begin")
|
||||
yield "middle"
|
||||
print("end")
|
||||
|
||||
|
||||
with my_context_manager() as f:
|
||||
print(f)
|
||||
|
||||
|
||||
# from typing import Iterator
|
||||
|
||||
# # deeply_nested = [[[1, 2, 3], [4, 5]], [[6, 7], [8, 9]]]
|
||||
|
||||
|
||||
# # def flatten(deeply_nested: list) -> Iterator[int]:
|
||||
# # for a in deeply_nested:
|
||||
# # for b in a:
|
||||
# # for c in b:
|
||||
# # yield c
|
||||
# # print("here")
|
||||
|
||||
|
||||
# # for inner in flatten(deeply_nested):
|
||||
# # print(inner)
|
||||
|
||||
|
||||
# def infinite(private_key):
|
||||
# while True:
|
||||
# yield from private_key
|
||||
|
||||
|
||||
# for private_key_char, plaintext_char in zip(infinite("hello"), "my plaintext"):
|
||||
# print("combine", private_key_char, plaintext_char)
|
1
heartbound OCR
Submodule
1
heartbound OCR
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 5ed08772af63910da82395c5e1912556473f3bbe
|
55
klimpen_function_chaining.py
Normal file
55
klimpen_function_chaining.py
Normal file
@ -0,0 +1,55 @@
|
||||
def func(datalist, b=False):
|
||||
output = []
|
||||
for data in datalist:
|
||||
data_a = funcA(data)
|
||||
data_b = funcB(data_a) if b else data_a
|
||||
data_c = funcC(data_b) if data.c else data_b
|
||||
data_d = funcD(data_c)
|
||||
output.append(data_d)
|
||||
return output
|
||||
|
||||
|
||||
def func_dom_simple(datalist, want_b=False):
|
||||
out = []
|
||||
for data in datalist:
|
||||
want_c = data.c
|
||||
data = funcA(data)
|
||||
if want_b:
|
||||
data = funcB(data)
|
||||
if want_c:
|
||||
data = funcC(data)
|
||||
data = funcD(data)
|
||||
out.append(data)
|
||||
return out
|
||||
|
||||
|
||||
def compose(*functions):
|
||||
return lambda start: reduce(lambda f, x: f(x), functions, start)
|
||||
|
||||
|
||||
def identity(x):
|
||||
return x
|
||||
|
||||
|
||||
def func_very_haskell(datalist, want_b=False):
|
||||
return map(
|
||||
lambda data: compose(
|
||||
funcA,
|
||||
funcB if b else identity,
|
||||
funcC if data.c else identity,
|
||||
funcD,
|
||||
)(data),
|
||||
datalist,
|
||||
)
|
||||
|
||||
|
||||
def func_very_haskell2(datalist, want_b=False):
|
||||
funcAB = compose(funcA, *([funcB] if b else []))
|
||||
return map(
|
||||
lambda data: compose(
|
||||
funcAB,
|
||||
funcC if data.c else identity,
|
||||
funcD,
|
||||
)(data),
|
||||
datalist,
|
||||
)
|
163
light_horn.py
Normal file
163
light_horn.py
Normal file
@ -0,0 +1,163 @@
|
||||
import pyqtgraph as pg
|
||||
import numpy as np
|
||||
|
||||
import sys
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtWidgets import QApplication, QHBoxLayout, QLabel, QSizePolicy, QSlider, QSpacerItem, \
|
||||
QVBoxLayout, QWidget
|
||||
|
||||
|
||||
|
||||
class Slider(QWidget):
|
||||
def __init__(self, minimum, maximum, parent=None):
|
||||
super(Slider, self).__init__(parent=parent)
|
||||
self.verticalLayout = QVBoxLayout(self)
|
||||
self.label = QLabel(self)
|
||||
self.verticalLayout.addWidget(self.label)
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
spacerItem = QSpacerItem(0, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout.addItem(spacerItem)
|
||||
self.slider = QSlider(self)
|
||||
self.slider.setOrientation(Qt.Orientation.Vertical)
|
||||
self.horizontalLayout.addWidget(self.slider)
|
||||
spacerItem1 = QSpacerItem(0, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout.addItem(spacerItem1)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.resize(self.sizeHint())
|
||||
|
||||
self.minimum = minimum
|
||||
self.maximum = maximum
|
||||
self.slider.valueChanged.connect(self._setLabelValue)
|
||||
self.x = None
|
||||
self._setLabelValue(self.slider.value())
|
||||
|
||||
def setValue(self, value : float):
|
||||
self.slider.setValue(100 * (value - self.minimum) / (self.maximum - self.minimum))
|
||||
# self.slider.setValue(value)
|
||||
self._setLabelValue(self.slider.value())
|
||||
|
||||
|
||||
def _setLabelValue(self, value):
|
||||
self.x = self.minimum + (float(value) / (self.slider.maximum() - self.slider.minimum())) * (
|
||||
self.maximum - self.minimum)
|
||||
self.label.setText("{0:.4g}".format(self.x))
|
||||
|
||||
|
||||
class Widget(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super(Widget, self).__init__(parent=parent)
|
||||
self.horizontalLayout = QHBoxLayout(self)
|
||||
self.w1 = Slider(0, 1)
|
||||
self.w1.setValue(.4141414141414141414141414141)
|
||||
# self.w1.setValue(50)
|
||||
self.horizontalLayout.addWidget(self.w1)
|
||||
|
||||
self.w2 = Slider(-1, 1)
|
||||
self.horizontalLayout.addWidget(self.w2)
|
||||
|
||||
self.w3 = Slider(-10, 10)
|
||||
self.horizontalLayout.addWidget(self.w3)
|
||||
|
||||
self.w4 = Slider(-10, 10)
|
||||
self.horizontalLayout.addWidget(self.w4)
|
||||
|
||||
self.win = pg.GraphicsWindow(title="Basic plotting examples")
|
||||
self.horizontalLayout.addWidget(self.win)
|
||||
self.p6 = self.win.addPlot(title="My Plot")
|
||||
self.p6.setAspectLocked()
|
||||
self.horn_upper = self.p6.plot(pen='r')
|
||||
self.horn_lower = self.p6.plot(pen='r')
|
||||
self.bounce_path = self.p6.plot(pen='w')
|
||||
self.update_plot()
|
||||
|
||||
self.w1.slider.valueChanged.connect(self.update_plot)
|
||||
self.w2.slider.valueChanged.connect(self.update_plot)
|
||||
self.w3.slider.valueChanged.connect(self.update_plot)
|
||||
self.w4.slider.valueChanged.connect(self.update_plot)
|
||||
|
||||
def update_plot(self):
|
||||
|
||||
k = self.w1.x
|
||||
def ii(x):
|
||||
return np.floor(2**x + .5)
|
||||
def qq(x):
|
||||
return ii(x)*x
|
||||
def horn(x):
|
||||
return -k *qq(x-np.log2(ii(x)))/ii(x) + 1
|
||||
return np.exp(-k*x)
|
||||
def horn_bot(x):
|
||||
return -horn(x)
|
||||
|
||||
#create numpy arrays
|
||||
#make the numbers large to show that the range shows data from 10000 to all the way 0
|
||||
xs = np.linspace(-.5,10, 10000)
|
||||
horn_upper = horn(xs)
|
||||
horn_lower = -horn_upper
|
||||
|
||||
vel = np.array([1,0])
|
||||
bounce_points = [np.array([xs[0], 1])]
|
||||
def ray(t: float):
|
||||
return bounce_points[-1] + t*vel
|
||||
|
||||
epsilon = 1e-10
|
||||
|
||||
# simulate bounces
|
||||
for bounce_i in range(100):
|
||||
bot_t = 0
|
||||
top_t = .1
|
||||
t = bot_t
|
||||
horn_func = horn if vel[1] >= 0 else horn_bot
|
||||
|
||||
p = ray(t)
|
||||
initial_side = p[1] < horn_func(p[0])
|
||||
t = top_t
|
||||
# expand search forwards
|
||||
for i in range(64):
|
||||
p = ray(top_t)
|
||||
side = p[1] < horn_func(p[0])
|
||||
if p[0] < -.5:
|
||||
break
|
||||
if side == initial_side:
|
||||
(bot_t, top_t) = (top_t, top_t+1.1*(top_t - bot_t))
|
||||
else:
|
||||
break
|
||||
if side == initial_side:
|
||||
# print(f'never found a crossover point at bounce_i={bounce_i}')
|
||||
# bounce_points.append(p)
|
||||
break
|
||||
# bisect
|
||||
for i in range(64):
|
||||
t = (bot_t + top_t) / 2
|
||||
p = ray(t)
|
||||
side = p[1] < horn_func(p[0])
|
||||
if side == initial_side:
|
||||
bot_t = t
|
||||
else:
|
||||
top_t = t
|
||||
if bot_t == top_t:
|
||||
break
|
||||
dx = 2*epsilon
|
||||
dy = horn_func(p[0] + epsilon) - horn_func(p[0] - epsilon)
|
||||
n = np.array([-dy, dx])
|
||||
n /= np.sqrt(n.dot(n)) # normal
|
||||
# reflect
|
||||
vel = vel - 2*(vel.dot(n))*n
|
||||
bounce_points.append(p)
|
||||
# (bot_t, top_t)
|
||||
|
||||
bounce_xs = [p[0] for p in bounce_points]
|
||||
bounce_ys = [p[1] for p in bounce_points]
|
||||
|
||||
self.horn_upper.setData(x=xs, y=horn_upper)
|
||||
self.horn_lower.setData(x=xs, y=horn_lower)
|
||||
self.bounce_path.setData(x=bounce_xs, y=bounce_ys)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
w = Widget()
|
||||
w.show()
|
||||
sys.exit(app.exec())
|
||||
|
||||
# if __name__ == '__main__':
|
||||
# pg.exec()
|
7
print_shelf.py
Normal file
7
print_shelf.py
Normal file
@ -0,0 +1,7 @@
|
||||
import shelve
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
with shelve.open(sys.argv[-1]) as shelf:
|
||||
for k, v in sorted(shelf.items(), key=lambda tup: (tup[1], tup[0])):
|
||||
print(k, v)
|
53
puzzle.py
Normal file
53
puzzle.py
Normal file
@ -0,0 +1,53 @@
|
||||
from collections import deque
|
||||
|
||||
initial = ". . . "
|
||||
|
||||
transitions = [
|
||||
'S SSS ',
|
||||
' SS S ',
|
||||
' S S ',
|
||||
'S SSS ',
|
||||
'S S S',
|
||||
' S S ',
|
||||
' S SS',
|
||||
'S S S',
|
||||
]
|
||||
|
||||
def toggle(c: str) -> str:
|
||||
return ' ' if c == '.' else '.'
|
||||
|
||||
def apply(state: str, transition: str) -> str:
|
||||
return ''.join(toggle(c) if t=='S' else c for c, t in zip(state, transition))
|
||||
|
||||
|
||||
|
||||
print(apply(initial, transitions[0]))
|
||||
|
||||
def bfs(start, neighbours_fn, is_finished):
|
||||
source = {start: None}
|
||||
q = deque([start])
|
||||
while q:
|
||||
s = q.popleft()
|
||||
if is_finished(s):
|
||||
steps = [s]
|
||||
parent = source[s]
|
||||
while parent is not None:
|
||||
steps.append(parent)
|
||||
parent = source[parent]
|
||||
steps = steps[::-1]
|
||||
for i in range(len(steps)-1):
|
||||
steps[i] = steps[i] + f' {neighbours_fn(steps[i]).index(steps[i+1])}'
|
||||
return steps
|
||||
for neigh in neighbours_fn(s):
|
||||
if neigh in source:
|
||||
continue
|
||||
source[neigh] = s
|
||||
q.append(neigh)
|
||||
raise ValueError('impossible')
|
||||
|
||||
print('\n'.join(bfs(
|
||||
initial,
|
||||
lambda s: [apply(s, t) for t in transitions],
|
||||
lambda s: s==' '
|
||||
# lambda s: s==' . '
|
||||
)))
|
1
signals
Submodule
1
signals
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 171c1fae662b711a75f0df8be7a3da3db9aa95b3
|
@ -1,3 +1,4 @@
|
||||
from math import sqrt
|
||||
import shelve
|
||||
from collections import deque
|
||||
from dataclasses import dataclass, replace
|
||||
@ -622,13 +623,13 @@ def shelve_it(file_name):
|
||||
return decorator
|
||||
|
||||
|
||||
def get_path_from_heuristic(
|
||||
def get_paths_from_heuristic(
|
||||
start: Skewb, heuristic_permutation: list[int]
|
||||
) -> list[LowerAntiAxis]:
|
||||
) -> list[list[LowerAntiAxis]]:
|
||||
out: list[list[LowerAntiAxis]] = []
|
||||
s = start
|
||||
mask = [0 for _ in heuristic_permutation]
|
||||
total_path_length = 0
|
||||
out: list[LowerAntiAxis] = []
|
||||
for heuristic_i in heuristic_permutation:
|
||||
mask[heuristic_i] = 1
|
||||
|
||||
@ -643,17 +644,17 @@ def get_path_from_heuristic(
|
||||
else:
|
||||
path = breadth_first_search(s, step_finished)
|
||||
# print()
|
||||
# print(f"{mask=} {s=} {path=}")
|
||||
print(f"{mask=} {s=} {path=}")
|
||||
if path is None:
|
||||
raise ValueError("oh no! solver could not find solution")
|
||||
out.extend(path)
|
||||
out.append(path)
|
||||
s = apply_twists(s, path)
|
||||
total_path_length += len(path)
|
||||
return out
|
||||
|
||||
|
||||
def get_total_path_length(start: Skewb, heuristic_permutation: list[int]) -> int:
|
||||
return len(get_path_from_heuristic(start, heuristic_permutation))
|
||||
# def get_total_path_length(start: Skewb, heuristic_permutation: list[int]) -> int:
|
||||
# return sum(len(p) for p in get_paths_from_heuristic(start, heuristic_permutation))
|
||||
|
||||
|
||||
# close_to_wrongly_solved = Skewb(top=(R0, B0, O0, G0), bot=(B0, O0, G0, R0), mids=(BY, GRB, ORG, RY, YY))
|
||||
@ -664,13 +665,27 @@ start = near_end
|
||||
HURISTIC_PERMUTATION_LENGTH = 4 + 4 + 5
|
||||
|
||||
|
||||
def quadratic_mean(values: list[float]) -> float:
|
||||
return sqrt(sum(x * x for x in values) / len(values))
|
||||
|
||||
|
||||
def get_mean_path_length(
|
||||
start: Skewb,
|
||||
heuristic_permutation: list[int],
|
||||
mean_fn: Callable[[list[float]], float] = quadratic_mean,
|
||||
) -> float:
|
||||
return mean_fn(
|
||||
[len(p) for p in get_paths_from_heuristic(start, heuristic_permutation)]
|
||||
)
|
||||
|
||||
|
||||
@shelve_it("skewb_solver.evaluate_permutation.shelve.sqlite")
|
||||
def evaluate_permutation(
|
||||
heuristic_permutation: list[int], seed=4, sample_size: int = 10
|
||||
) -> float:
|
||||
pls = []
|
||||
for i in range(sample_size):
|
||||
pl = get_total_path_length(random_skewb(seed=i + seed), heuristic_permutation)
|
||||
pl = get_mean_path_length(random_skewb(seed=i + seed), heuristic_permutation)
|
||||
print(f"{pl=}")
|
||||
pls.append(pl)
|
||||
return sum(pls) / len(pls)
|
||||
@ -727,7 +742,7 @@ if __name__ == "__main__":
|
||||
# print(f"{hp=} {evaluate_permutation(hp, seed=200, sample_size=200)=}")
|
||||
|
||||
hp = [10, 0, 1, 2, 3, 8, 9, 11, 12, 4, 5, 6, 7]
|
||||
path = get_path_from_heuristic(
|
||||
path = get_paths_from_heuristic(
|
||||
Skewb(top=(O0, B0, R0, G0), bot=(B2, R0, G1, O0), mids=(BY, YY, GY, RY, ORB)),
|
||||
hp,
|
||||
)
|
||||
|
180
starchild_teaching.py
Normal file
180
starchild_teaching.py
Normal file
@ -0,0 +1,180 @@
|
||||
from typing import List, Set, Dict, Tuple
|
||||
|
||||
# a: int = 2
|
||||
# b: float = 2.3
|
||||
# c: str = "lkasldkjaslkjdasd"
|
||||
# cc: bytes = b"AAA"
|
||||
# d: None = None
|
||||
# e: bool = True
|
||||
# f: bool = False
|
||||
# k: Tuple[int, str, str] = (1, "hello", "world")
|
||||
|
||||
# g: List[int] = [7]
|
||||
# j: Set[str] = {"friend a", "friend b"}
|
||||
# i: Dict[str, int] = {"4": 6, "6": 8}
|
||||
|
||||
# import collections
|
||||
|
||||
# print(dir(collections))
|
||||
|
||||
# i["5"] = 7
|
||||
# print(dict[str])
|
||||
|
||||
#
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Card:
|
||||
suit: str
|
||||
rank: int # 1 -> ace, 10+ -> jack, queen, king
|
||||
|
||||
def __str__(self) -> str:
|
||||
if self.rank == 1:
|
||||
rank_str = "ace"
|
||||
elif self.rank == 10:
|
||||
rank_str = "jack"
|
||||
elif self.rank == 11:
|
||||
rank_str = "queen"
|
||||
elif self.rank == 12:
|
||||
rank_str = "king"
|
||||
else:
|
||||
rank_str = str(self.rank)
|
||||
return f"{rank_str} of {self.suit}"
|
||||
|
||||
# def __lt__(self, other) -> bool:
|
||||
# if self.suit != other.suit:
|
||||
# return self.suit < other.suit
|
||||
# else:
|
||||
# return self.rank < other.rank
|
||||
|
||||
|
||||
hand: List[Card] = [
|
||||
Card(suit="clubs", rank=6),
|
||||
Card(suit="clubs", rank=5),
|
||||
Card(suit="spades", rank=1),
|
||||
Card(suit="hearts", rank=10),
|
||||
]
|
||||
|
||||
|
||||
def suit_first(card: Card) -> Tuple:
|
||||
return (card.suit, card.rank)
|
||||
|
||||
|
||||
def rank_first(card: Card) -> Tuple:
|
||||
return (card.rank, card.suit)
|
||||
|
||||
|
||||
# hand.sort(key=suit_first)
|
||||
# hand.sort(key=rank_first)
|
||||
# print(hand)
|
||||
|
||||
print((1, "clubs", "cinnamon") < (1, "clubs", "vanilla"))
|
||||
|
||||
# O(N ^ 2)
|
||||
|
||||
|
||||
# for i in range(10):
|
||||
# print(i)
|
||||
|
||||
# iterable = range(4)
|
||||
# iterator = iter(iterable)
|
||||
# # print(dir(iterator))
|
||||
# # print(iterator.__str__()[0])
|
||||
# # print(iterator)
|
||||
|
||||
# # print(dir(iterator.__next__))
|
||||
# print(next.__doc__)
|
||||
|
||||
# try:
|
||||
# while True:
|
||||
# print(iterator.__next__())
|
||||
|
||||
# except StopIteration:
|
||||
# print("handled!")
|
||||
|
||||
[
|
||||
"__class__",
|
||||
"__delattr__",
|
||||
"__dir__",
|
||||
"__doc__",
|
||||
"__eq__",
|
||||
"__format__",
|
||||
"__ge__",
|
||||
"__getattribute__",
|
||||
"__gt__",
|
||||
"__hash__",
|
||||
"__init__",
|
||||
"__init_subclass__",
|
||||
"__iter__",
|
||||
"__le__",
|
||||
"__length_hint__",
|
||||
"__lt__",
|
||||
"__ne__",
|
||||
"__new__",
|
||||
"__next__",
|
||||
"__reduce__",
|
||||
"__reduce_ex__",
|
||||
"__repr__",
|
||||
"__setattr__",
|
||||
"__setstate__",
|
||||
"__sizeof__",
|
||||
"__str__",
|
||||
"__subclasshook__",
|
||||
]
|
||||
|
||||
# print(next(iterator))
|
||||
# print(next(iterator))
|
||||
# print(next(iterator))
|
||||
# print(next(iterator))
|
||||
# print(next(iterator))
|
||||
|
||||
|
||||
# def sum_until(x: int) -> int:
|
||||
# """computes the sum of number from 0 to x (inclusive)"""
|
||||
|
||||
# to_sum = list(range(x + 1))
|
||||
# print(to_sum)
|
||||
# s = 0
|
||||
# for num in to_sum:
|
||||
# s += num
|
||||
# return s
|
||||
|
||||
|
||||
# print(sum_until(3))
|
||||
|
||||
# from abc import ABC
|
||||
# from dataclasses import dataclass
|
||||
# from typing import List
|
||||
|
||||
|
||||
# class Animal(ABC):
|
||||
# def make_noise(self):
|
||||
# pass
|
||||
|
||||
|
||||
# @dataclass
|
||||
# class Cat(Animal):
|
||||
# name: str
|
||||
|
||||
# def make_noise(self):
|
||||
# print("meow")
|
||||
|
||||
|
||||
# class Lion(Cat):
|
||||
# def hunt(self):
|
||||
# print("nom")
|
||||
|
||||
|
||||
# class Kitty(Cat):
|
||||
# def make_noise(self):
|
||||
# print("purr")
|
||||
|
||||
|
||||
# animals: List[Animal] = [
|
||||
# Kitty(name="Star Child"),
|
||||
# Lion(name="Simba"),
|
||||
# ]
|
||||
# for animal in animals:
|
||||
# animal.make_noise()
|
27
try.py
Normal file
27
try.py
Normal file
@ -0,0 +1,27 @@
|
||||
import sys
|
||||
|
||||
|
||||
class Foo(int):
|
||||
def __init__(self, x):
|
||||
super().__init__()
|
||||
self.q = x + 1
|
||||
|
||||
|
||||
# print(Foo(3).q)
|
||||
print(sys.getsizeof(3))
|
||||
print(sys.getsizeof(Foo(3)))
|
||||
|
||||
# from typing import List
|
||||
|
||||
# def contains_321(ints: List[int]) -> bool:
|
||||
# try:
|
||||
# i3 = ints.index(3)
|
||||
# i2 = ints[i3+1:].index(2)
|
||||
# i1 = ints[i2+1:].index(1)
|
||||
# return True
|
||||
# except ValueError:
|
||||
# return False
|
||||
|
||||
# print(contains_321([3,2,1]))
|
||||
# print(contains_321([3,1,2,1,1]))
|
||||
# print(contains_321([1,2,3]))
|
295
upload/SimpleHTTPServerWithUpload.py
Normal file
295
upload/SimpleHTTPServerWithUpload.py
Normal file
@ -0,0 +1,295 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Simple HTTP Server With Upload.
|
||||
|
||||
This module builds on BaseHTTPServer by implementing the standard GET
|
||||
and HEAD requests in a fairly straightforward manner.
|
||||
|
||||
see: https://gist.github.com/UniIsland/3346170
|
||||
"""
|
||||
|
||||
|
||||
__version__ = "0.1"
|
||||
__all__ = ["SimpleHTTPRequestHandler"]
|
||||
__author__ = "bones7456"
|
||||
__home_page__ = "http://li2z.cn/"
|
||||
|
||||
import os
|
||||
import posixpath
|
||||
import http.server
|
||||
import urllib.request, urllib.parse, urllib.error
|
||||
import html
|
||||
import shutil
|
||||
import mimetypes
|
||||
import re
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
class SimpleHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
|
||||
|
||||
"""Simple HTTP request handler with GET/HEAD/POST commands.
|
||||
|
||||
This serves files from the current directory and any of its
|
||||
subdirectories. The MIME type for files is determined by
|
||||
calling the .guess_type() method. And can reveive file uploaded
|
||||
by client.
|
||||
|
||||
The GET/HEAD/POST requests are identical except that the HEAD
|
||||
request omits the actual contents of the file.
|
||||
|
||||
"""
|
||||
|
||||
server_version = "SimpleHTTPWithUpload/" + __version__
|
||||
|
||||
def do_GET(self):
|
||||
"""Serve a GET request."""
|
||||
f = self.send_head()
|
||||
if f:
|
||||
self.copyfile(f, self.wfile)
|
||||
f.close()
|
||||
|
||||
def do_HEAD(self):
|
||||
"""Serve a HEAD request."""
|
||||
f = self.send_head()
|
||||
if f:
|
||||
f.close()
|
||||
|
||||
def do_POST(self):
|
||||
"""Serve a POST request."""
|
||||
r, info = self.deal_post_data()
|
||||
print((r, info, "by: ", self.client_address))
|
||||
f = BytesIO()
|
||||
f.write(b'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
|
||||
f.write(b"<html>\n<title>Upload Result Page</title>\n")
|
||||
f.write(b"<body>\n<h2>Upload Result Page</h2>\n")
|
||||
f.write(b"<hr>\n")
|
||||
if r:
|
||||
f.write(b"<strong>Success:</strong>")
|
||||
else:
|
||||
f.write(b"<strong>Failed:</strong>")
|
||||
f.write(info.encode())
|
||||
f.write(("<br><a href=\"%s\">back</a>" % self.headers['referer']).encode())
|
||||
f.write(b"<hr><small>Powerd By: bones7456, check new version at ")
|
||||
f.write(b"<a href=\"http://li2z.cn/?s=SimpleHTTPServerWithUpload\">")
|
||||
f.write(b"here</a>.</small></body>\n</html>\n")
|
||||
length = f.tell()
|
||||
f.seek(0)
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "text/html")
|
||||
self.send_header("Content-Length", str(length))
|
||||
self.end_headers()
|
||||
if f:
|
||||
self.copyfile(f, self.wfile)
|
||||
f.close()
|
||||
|
||||
def deal_post_data(self):
|
||||
content_type = self.headers['content-type']
|
||||
if not content_type:
|
||||
return (False, "Content-Type header doesn't contain boundary")
|
||||
boundary = content_type.split("=")[1].encode()
|
||||
remainbytes = int(self.headers['content-length'])
|
||||
line = self.rfile.readline()
|
||||
remainbytes -= len(line)
|
||||
if not boundary in line:
|
||||
return (False, "Content NOT begin with boundary")
|
||||
line = self.rfile.readline()
|
||||
remainbytes -= len(line)
|
||||
fn = re.findall(r'Content-Disposition.*name="file"; filename="(.*)"', line.decode())
|
||||
if not fn:
|
||||
return (False, "Can't find out file name...")
|
||||
path = self.translate_path(self.path)
|
||||
fn = os.path.join(path, fn[0])
|
||||
line = self.rfile.readline()
|
||||
remainbytes -= len(line)
|
||||
line = self.rfile.readline()
|
||||
remainbytes -= len(line)
|
||||
try:
|
||||
out = open(fn, 'wb')
|
||||
except IOError:
|
||||
return (False, "Can't create file to write, do you have permission to write?")
|
||||
|
||||
preline = self.rfile.readline()
|
||||
remainbytes -= len(preline)
|
||||
while remainbytes > 0:
|
||||
line = self.rfile.readline()
|
||||
remainbytes -= len(line)
|
||||
if boundary in line:
|
||||
preline = preline[0:-1]
|
||||
if preline.endswith(b'\r'):
|
||||
preline = preline[0:-1]
|
||||
out.write(preline)
|
||||
out.close()
|
||||
return (True, "File '%s' upload success!" % fn)
|
||||
else:
|
||||
out.write(preline)
|
||||
preline = line
|
||||
return (False, "Unexpect Ends of data.")
|
||||
|
||||
def send_head(self):
|
||||
"""Common code for GET and HEAD commands.
|
||||
|
||||
This sends the response code and MIME headers.
|
||||
|
||||
Return value is either a file object (which has to be copied
|
||||
to the outputfile by the caller unless the command was HEAD,
|
||||
and must be closed by the caller under all circumstances), or
|
||||
None, in which case the caller has nothing further to do.
|
||||
|
||||
"""
|
||||
path = self.translate_path(self.path)
|
||||
f = None
|
||||
if os.path.isdir(path):
|
||||
if not self.path.endswith('/'):
|
||||
# redirect browser - doing basically what apache does
|
||||
self.send_response(301)
|
||||
self.send_header("Location", self.path + "/")
|
||||
self.end_headers()
|
||||
return None
|
||||
for index in "index.html", "index.htm":
|
||||
index = os.path.join(path, index)
|
||||
if os.path.exists(index):
|
||||
path = index
|
||||
break
|
||||
else:
|
||||
return self.list_directory(path)
|
||||
ctype = self.guess_type(path)
|
||||
try:
|
||||
# Always read in binary mode. Opening files in text mode may cause
|
||||
# newline translations, making the actual size of the content
|
||||
# transmitted *less* than the content-length!
|
||||
f = open(path, 'rb')
|
||||
except IOError:
|
||||
self.send_error(404, "File not found")
|
||||
return None
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", ctype)
|
||||
fs = os.fstat(f.fileno())
|
||||
self.send_header("Content-Length", str(fs[6]))
|
||||
self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
|
||||
self.end_headers()
|
||||
return f
|
||||
|
||||
def list_directory(self, path):
|
||||
"""Helper to produce a directory listing (absent index.html).
|
||||
|
||||
Return value is either a file object, or None (indicating an
|
||||
error). In either case, the headers are sent, making the
|
||||
interface the same as for send_head().
|
||||
|
||||
"""
|
||||
try:
|
||||
list = os.listdir(path)
|
||||
except os.error:
|
||||
self.send_error(404, "No permission to list directory")
|
||||
return None
|
||||
list.sort(key=lambda a: a.lower())
|
||||
f = BytesIO()
|
||||
displaypath = html.escape(urllib.parse.unquote(self.path))
|
||||
f.write(b'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
|
||||
f.write(("<html>\n<title>Directory listing for %s</title>\n" % displaypath).encode())
|
||||
f.write(("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath).encode())
|
||||
f.write(b"<hr>\n")
|
||||
f.write(b"<form ENCTYPE=\"multipart/form-data\" method=\"post\">")
|
||||
f.write(b"<input name=\"file\" type=\"file\"/>")
|
||||
f.write(b"<input type=\"submit\" value=\"upload\"/></form>\n")
|
||||
f.write(b"<hr>\n<ul>\n")
|
||||
for name in list:
|
||||
fullname = os.path.join(path, name)
|
||||
displayname = linkname = name
|
||||
# Append / for directories or @ for symbolic links
|
||||
if os.path.isdir(fullname):
|
||||
displayname = name + "/"
|
||||
linkname = name + "/"
|
||||
if os.path.islink(fullname):
|
||||
displayname = name + "@"
|
||||
# Note: a link to a directory displays with @ and links with /
|
||||
f.write(('<li><a href="%s">%s</a>\n'
|
||||
% (urllib.parse.quote(linkname), html.escape(displayname))).encode())
|
||||
f.write(b"</ul>\n<hr>\n</body>\n</html>\n")
|
||||
length = f.tell()
|
||||
f.seek(0)
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "text/html")
|
||||
self.send_header("Content-Length", str(length))
|
||||
self.end_headers()
|
||||
return f
|
||||
|
||||
def translate_path(self, path):
|
||||
"""Translate a /-separated PATH to the local filename syntax.
|
||||
|
||||
Components that mean special things to the local file system
|
||||
(e.g. drive or directory names) are ignored. (XXX They should
|
||||
probably be diagnosed.)
|
||||
|
||||
"""
|
||||
# abandon query parameters
|
||||
path = path.split('?',1)[0]
|
||||
path = path.split('#',1)[0]
|
||||
path = posixpath.normpath(urllib.parse.unquote(path))
|
||||
words = path.split('/')
|
||||
words = [_f for _f in words if _f]
|
||||
path = os.getcwd()
|
||||
for word in words:
|
||||
drive, word = os.path.splitdrive(word)
|
||||
head, word = os.path.split(word)
|
||||
if word in (os.curdir, os.pardir): continue
|
||||
path = os.path.join(path, word)
|
||||
return path
|
||||
|
||||
def copyfile(self, source, outputfile):
|
||||
"""Copy all data between two file objects.
|
||||
|
||||
The SOURCE argument is a file object open for reading
|
||||
(or anything with a read() method) and the DESTINATION
|
||||
argument is a file object open for writing (or
|
||||
anything with a write() method).
|
||||
|
||||
The only reason for overriding this would be to change
|
||||
the block size or perhaps to replace newlines by CRLF
|
||||
-- note however that this the default server uses this
|
||||
to copy binary data as well.
|
||||
|
||||
"""
|
||||
shutil.copyfileobj(source, outputfile)
|
||||
|
||||
def guess_type(self, path):
|
||||
"""Guess the type of a file.
|
||||
|
||||
Argument is a PATH (a filename).
|
||||
|
||||
Return value is a string of the form type/subtype,
|
||||
usable for a MIME Content-type header.
|
||||
|
||||
The default implementation looks the file's extension
|
||||
up in the table self.extensions_map, using application/octet-stream
|
||||
as a default; however it would be permissible (if
|
||||
slow) to look inside the data to make a better guess.
|
||||
|
||||
"""
|
||||
|
||||
base, ext = posixpath.splitext(path)
|
||||
if ext in self.extensions_map:
|
||||
return self.extensions_map[ext]
|
||||
ext = ext.lower()
|
||||
if ext in self.extensions_map:
|
||||
return self.extensions_map[ext]
|
||||
else:
|
||||
return self.extensions_map['']
|
||||
|
||||
if not mimetypes.inited:
|
||||
mimetypes.init() # try to read system mime.types
|
||||
extensions_map = mimetypes.types_map.copy()
|
||||
extensions_map.update({
|
||||
'': 'application/octet-stream', # Default
|
||||
'.py': 'text/plain',
|
||||
'.c': 'text/plain',
|
||||
'.h': 'text/plain',
|
||||
})
|
||||
|
||||
|
||||
def test(HandlerClass = SimpleHTTPRequestHandler,
|
||||
ServerClass = http.server.HTTPServer):
|
||||
http.server.test(HandlerClass, ServerClass)
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
71
when_to_quit.py
Normal file
71
when_to_quit.py
Normal file
@ -0,0 +1,71 @@
|
||||
import numpy as np
|
||||
|
||||
import pyqtgraph as pg
|
||||
from pyqtgraph.Qt import QtCore
|
||||
|
||||
|
||||
initial_dollar = 100
|
||||
|
||||
factor_if_heads = 1.8
|
||||
factor_if_tails = 0.5
|
||||
|
||||
population_size = 10000
|
||||
num_tosses_visualized = 500
|
||||
|
||||
def want_to_play(money, toss) -> bool:
|
||||
return True
|
||||
if toss > 4:
|
||||
return False
|
||||
|
||||
rng = np.random.default_rng(seed=4)
|
||||
|
||||
def evolve(want_to_play, money, toss):
|
||||
# if money < 2:
|
||||
# return 1
|
||||
# if not want_to_play(money, toss):
|
||||
# return money
|
||||
|
||||
if rng.choice([0,1]):
|
||||
return money * factor_if_heads
|
||||
else:
|
||||
return money * factor_if_tails
|
||||
|
||||
population_histories = [[initial_dollar] for _ in range(population_size)]
|
||||
for toss in range(num_tosses_visualized):
|
||||
for hist in population_histories:
|
||||
hist.append(evolve(want_to_play, hist[-1], toss))
|
||||
|
||||
|
||||
app = pg.mkQApp("Plotting Example")
|
||||
#mw = QtWidgets.QMainWindow()
|
||||
#mw.resize(800,800)
|
||||
|
||||
win = pg.GraphicsLayoutWidget(show=True, title="Basic plotting examples")
|
||||
win.resize(1000,600)
|
||||
win.setWindowTitle('pyqtgraph example: Plotting')
|
||||
|
||||
# Enable antialiasing for prettier plots
|
||||
pg.setConfigOptions(antialias=True)
|
||||
|
||||
p2 = win.addPlot(title="Multiple curves")
|
||||
|
||||
|
||||
population_histories = np.array(population_histories)
|
||||
# population_histories = np.log(population_histories + 1)
|
||||
p2.setLogMode(False, True)
|
||||
p2.plot(population_histories.mean(0), pen=(255, 0, 0))
|
||||
p2.plot(np.median(population_histories, 0), pen=(0, 255, 0))
|
||||
for percentile in range(0, 101):
|
||||
print('percentile', percentile)
|
||||
p2.plot(np.percentile(population_histories, percentile, 0), pen=(100, 10, 0))
|
||||
|
||||
# for hist in population_histories:
|
||||
# p2.plot(hist, pen=(33,33,33))
|
||||
|
||||
# p2.plot(np.random.normal(size=100), pen=(255,0,0), name="Red curve")
|
||||
# p2.plot(np.random.normal(size=110)+5, pen=(0,255,0), name="Green curve")
|
||||
# p2.plot(np.random.normal(size=120)+10, pen=(0,0,255), name="Blue curve")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pg.exec()
|
Loading…
x
Reference in New Issue
Block a user