Solution_dec_03_Mogens
Python code to remove the cow dung from shovel.
dec03.py — 7.4 KB
File contents
# -*- coding: utf-8 -*- """ Created on Sun Dec 11 20:53:32 2022 @author: Mogens Henrik From """ import matplotlib.pyplot as plt import numpy as np class Stick(): def __init__(self, base, direction): self.base = np.array(base) self.direction = np.array(direction) def end_coord(self): return [self.base[0] + self.direction[0], self.base[1] + self.direction[1]] def plot_x(self): return [self.base[0], self.base[0] + self.direction[0]] def plot_y(self): return [self.base[1], self.base[1] + self.direction[1]] class Shovel(): def __init__(self, stick1): self.sticks = [stick1] def add_half_stick(self, reverse=False): if reverse: orig = self.sticks[-1].base if not reverse: orig = self.sticks[-1].end_coord() new_base = orig - self.sticks[-1].direction[::-1] / 2 new_dir = self.sticks[-1].direction[::-1] self.sticks.append(Stick(new_base, new_dir)) def add_angle_sticks(self, reverse=False): if reverse: angle1 = Stick(self.sticks[-1].base, -self.sticks[-2].direction) angle2 = Stick(self.sticks[-1].end_coord(), -self.sticks[-2].direction) if not reverse: angle1 = Stick(self.sticks[-1].base, self.sticks[-2].direction) angle2 = Stick(self.sticks[-1].end_coord(), self.sticks[-2].direction) self.sticks.append(angle1) self.sticks.append(angle2) def create_shovel_from_handle(self, reverse=False): if len(self.sticks) > 3: return self.add_half_stick(reverse=reverse) self.add_angle_sticks(reverse=reverse) def create_shovel_from_middle(self, reverse=False): if len(self.sticks) > 3: return if reverse: new_dir = -self.sticks[0].direction[::-1] if not reverse: new_dir = self.sticks[0].direction[::-1] angle1 = Stick(self.sticks[0].base, new_dir) angle2 = Stick(self.sticks[0].end_coord(), new_dir) middle_orig = self.sticks[0].base + self.sticks[-1].direction / 2 middle = Stick(middle_orig, -new_dir) self.sticks.append(angle1) self.sticks.append(angle2) self.sticks.append(middle) def create_shovel_from_edge(self, reverse=False, mirror=False): if mirror: new_dir = self.sticks[-1].direction[::-1] else: new_dir = -self.sticks[-1].direction[::-1] if reverse: middle = Stick(self.sticks[-1].base, new_dir) else: middle = Stick(self.sticks[-1].end_coord(), new_dir) angle2_base = middle.base + middle.direction handle_base = middle.base + middle.direction / 2 if reverse: angle2 = Stick(angle2_base, self.sticks[0].direction) handle = Stick(handle_base, -self.sticks[-1].direction) else: angle2 = Stick(angle2_base, -self.sticks[0].direction) handle = Stick(handle_base, self.sticks[-1].direction) self.sticks.append(angle2) self.sticks.append(middle) self.sticks.append(handle) def remove_duplicate_shovels(shovels): unique_shovels = [] unique_shovel_coords = [] for shovel in shovels: coords = [] for stick in shovel.sticks: coords.append(sorted([tuple(stick.base), tuple(stick.base + stick.direction)])) if sorted(coords) not in unique_shovel_coords: unique_shovel_coords.append(sorted(coords)) unique_shovels.append(shovel) else: continue return unique_shovels def validate_shovel_moves(orig_shovel, moved_shovels): allowed = [] valid_moved_shovels = [] for stick in orig_shovel.sticks: allowed.append(sorted([tuple(stick.base), tuple(stick.base + stick.direction)])) for shovel in moved_shovels: count = 0 for stick in shovel.sticks: coords = sorted([tuple(stick.base), tuple(stick.base + stick.direction)]) if coords in allowed: count += 1 if count > 1: valid_moved_shovels.append(shovel) return valid_moved_shovels def is_poop_on_shovel(shovel): bad_coords = sorted([[(-1, 2), (1, 2)], [(-1, 2), (-1, 4)], [(1, 2), (1, 4)], [(-1, 4), (1, 4)]]) count = 0 for stick in shovel.sticks: coords = sorted([tuple(stick.base), tuple(stick.base + stick.direction)]) if coords in bad_coords: count += 1 if count < 2: return False return True def plot_sticks(sticks, orig_sticks, plot_orig=True): if plot_orig: for stick in orig_sticks: plt.plot(stick.plot_x(), stick.plot_y(), marker = 'o', color='r') for stick in sticks: plt.plot(stick.plot_x(), stick.plot_y(), marker = 'o', color='k') plt.plot(0, 3, marker = 'o', color='brown') ax = plt.gca() ax.set_aspect('equal') ax.set_xlim((-5.5, 5.5)) ax.set_ylim((-5.5, 5.5)) plt.show() def gridplot(shovels, nrows, ncols, figsize=(12, 8), filename='', save=False): fig = plt.figure(figsize=figsize) gs = fig.add_gridspec(nrows, ncols, hspace=0, wspace=0) axs = gs.subplots() for i, shovel in enumerate(shovels): for stick in shovel.sticks: axs.flat[i].plot(stick.plot_x(), stick.plot_y(), marker = 'o', markersize=0, color='k') axs.flat[i].plot(0, 3, marker = 'o', color='brown') for ax in axs.flat: ax.label_outer() ax.set_xticks([]) ax.set_yticks([]) ax.set_xlim((-5, 5)) ax.set_ylim((-3, 7)) ax.set_aspect('equal') if save: plt.savefig(filename, format='png', bbox_inches='tight') plt.show() def main(): orig_shovel = Shovel(Stick([0, 0], [0, 2])) orig_shovel.sticks.append(Stick([-1, 2], [2, 0])) orig_shovel.sticks.append(Stick([-1, 2], [0, 2])) orig_shovel.sticks.append(Stick([1, 2], [0, 2])) #plot_sticks(orig_shovel.sticks) shovels = [] for stick in orig_shovel.sticks: for reverse in [True, False]: shovels.append(Shovel(stick)) shovels[-1].create_shovel_from_handle(reverse=reverse) shovels.append(Shovel(stick)) shovels[-1].create_shovel_from_middle(reverse=reverse) for mirror in [True, False]: shovels.append(Shovel(stick)) shovels[-1].create_shovel_from_edge(reverse=reverse, mirror=mirror) shovels = remove_duplicate_shovels(shovels) valid_moves = validate_shovel_moves(orig_shovel, shovels) gridplot(shovels, 4, 6, filename='all_shovels.png', save=True) gridplot(valid_moves, 2, 3, filename='allowed_shovels.png', save=True) valid_solutions = [] for shovel in valid_moves: if not is_poop_on_shovel(shovel): valid_solutions.append(shovel) gridplot(valid_solutions, 1, 2, filename='valid_solutions.png', save=True) if __name__ == "__main__": main()