Day 13: Claw Contraption

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • @iAvicenna
    link
    2
    edit-2
    15 hours ago

    Python

    I just threw linear algebra and float64 on this question and it stuck. Initially in order to decrease the numbers a bit (to save precision) I tried to find greatest common divisors for the coordinates of the target but in many cases it was 1, so that was that went down the drain. Luckily float64 was able to achieve precisions up to 1e-4 and that was enough to separate wheat from chaff. So in the end I did not have to use exact formulas for the inverse of the matrix though probably would be a more satisfying solution if I did.

    
    import numpy as np
    from functools import partial
    from pathlib import Path
    cwd = Path(__file__).parent
    
    def parse_input(file_path, correction):
    
      with file_path.open("r") as fp:
        instructions = fp.readlines()
    
      machine_instructions = []
      for ind in range(0,len(instructions)+1,4):
    
        mins = instructions[ind:ind+3]
        machine_instructions.append([])
        for i,s in zip(range(3),['+','+','=']):
          machine_instructions[-1].append([int(mins[i].split(',')[0].split(s)[-1]),
                                       int(mins[i].split(',')[1].split(s)[-1])])
    
        for i in range(2):
          machine_instructions[-1][-1][i] += correction
    
      return machine_instructions
    
    
    def solve(threshold, maxn, vectors):
    
      c = np.array([3, 1])
    
      M = np.concat([np.array(vectors[0])[:,None],
                     np.array(vectors[1])[:,None]],axis=1).astype(int)
    
      if np.linalg.det(M)==0:
        return np.nan
    
      Minv = np.linalg.inv(M)
      nmoves = Minv @ np.array(vectors[2])
    
      if np.any(np.abs(nmoves - np.round(nmoves))>threshold) or\
        np.any(nmoves>maxn) or np.any(nmoves<0):
          return np.nan
    
      return np.sum(c * (Minv @ np.array(vectors[2])))
    
    
    def solve_problem(file_name, correction, maxn, threshold=1e-4):
      # correction 0 or 10000000000000
      # maxn 100 or np.inf
    
      machine_instructions = parse_input(Path(cwd, file_name), correction)
    
      _solve = partial(solve, threshold, maxn)
    
      tokens = list(map(_solve, machine_instructions))
    
      return int(np.nansum(list(tokens)))