Solution_dec_10_Mogens

text/x-python 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()
Wird geladen