Solution_dec_03_Mogens

Python code to remove the cow dung from shovel.

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