Solution_dec_10_Mogens
dec10.py — 4.4 KB
File contents
# -*- coding: utf-8 -*- """ Created on Mon Dec 19 23:24:32 2022 @author: Mogens Henrik From """ import matplotlib.pyplot as plt import numpy as np import itertools from tqdm import tqdm class Match(): def __init__(self, base, direction): self.base = np.array(base) self.direction = np.array(direction) def end_coord(self): return np.array([self.base[0] + self.direction[0], self.base[1] + self.direction[1]]) def x(self): return [self.base[0], self.base[0] + self.direction[0]] def y(self): return [self.base[1], self.base[1] + self.direction[1]] class Triangle_of_triangles(): def __init__(self, num_layers): self.matches = np.array([]) for layer_ind in range(num_layers): num_triangles = num_layers - layer_ind for i in range(num_triangles): layer_y = np.sin(np.pi/3) * layer_ind layer_x = np.cos(np.pi/3) * layer_ind self.matches = np.append(self.matches, self.create_triangle(layer_x + i, layer_y)) def create_triangle(self, x, y): # Create triangle from base coordinates base = Match((x, y), (1,0)) left_arm = Match((x, y), (np.cos(np.pi/3), np.sin(np.pi/3))) right_arm = Match((x + 1, y), (-np.cos(np.pi/3), np.sin(np.pi/3))) return base, left_arm, right_arm def plot(self): for match in self.matches: plt.plot(match.x(), match.y(), marker = 'o', color='k') ax = plt.gca() ax.set_aspect('equal') plt.show() def rotate_direction(self, direction, angle): dir_x = direction[0] * np.cos(angle) + direction[1] * np.sin(angle) dir_y = -direction[0] * np.sin(angle) + direction[1] * np.cos(angle) return [dir_x, dir_y] def check_triangles(self): triangles = [] for i, match_a in enumerate(self.matches): up_tip = match_a.base + self.rotate_direction(match_a.direction, np.pi/3) down_tip = match_a.base + self.rotate_direction(match_a.direction, -np.pi/3) upper_set = [match_a.base, match_a.end_coord(), up_tip] lower_set = [match_a.base, match_a.end_coord(), down_tip] for triangle_set in [upper_set, lower_set]: for j, match_b in enumerate(self.matches): if j == i: continue if np.any(np.all(np.isclose( match_b.base, triangle_set), axis=1)) \ and np.any(np.all(np.isclose( match_b.end_coord(), triangle_set), axis=1)): for k, match_c in enumerate(self.matches): if k == j or k == i: continue if np.any(np.all(np.isclose( match_c.base, triangle_set), axis=1)) \ and np.any(np.all(np.isclose( match_c.end_coord(), triangle_set), axis=1)): triangles.append(tuple(sorted([i, j, k]))) return set(triangles) def main(): num_matches_removed = 3 num_triangles_left= 3 plotting = True # Baseline setup ttriangle = Triangle_of_triangles(3) if plotting: ttriangle.plot() # Figure out all possible combinations of tthree matches to remove indices_to_remove = itertools.combinations(range(len(ttriangle.matches)), num_matches_removed) num_combinations = np.math.factorial(18)/ \ (np.math.factorial(18 - num_matches_removed)*np.math.factorial(num_matches_removed)) print(f'There are {num_combinations} possible ways to remove 3 matches - starting iteration through all of them.') solutions = [] for indices in tqdm(indices_to_remove, total=num_combinations): triangle_arr = Triangle_of_triangles(num_matches_removed) triangle_arr.matches = np.delete(triangle_arr.matches, indices) valid = triangle_arr.check_triangles() if len(valid) == num_triangles_left: solutions.append(indices) if plotting: triangle_arr.plot() print(f'\nThere are {len(solutions)} possible solutions leaving {num_triangles_left} triangles after removing {num_matches_removed} matches.') if __name__ == "__main__": main()