github.com/cycloss/advent-of-code@v0.0.0-20221210145555-15039b95faa6/2016/day1/day1.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"os"
     8  	"strconv"
     9  
    10  	"github.com/cycloss/advent-of-code/utils"
    11  )
    12  
    13  type vector struct {
    14  	x, y int
    15  }
    16  
    17  func newVector(x, y int) vector {
    18  	return vector{x: x, y: y}
    19  }
    20  
    21  // up, right, down, left
    22  func makeCardinalVectors() []vector {
    23  	return []vector{newVector(0, 1), newVector(1, 0), newVector(0, -1), newVector(-1, 0)}
    24  }
    25  
    26  func (v vector) add(v2 vector) vector {
    27  	return newVector(v.x+v2.x, v.y+v2.y)
    28  }
    29  
    30  func (v vector) allIntermediaryTo(v2, cardinal vector) []vector {
    31  	intermediary := []vector{}
    32  	for ; v != v2; v = v.add(cardinal) {
    33  		intermediary = append(intermediary, v)
    34  	}
    35  	return intermediary
    36  }
    37  
    38  type instruction struct {
    39  	dirMod, dist int
    40  }
    41  
    42  func (i instruction) String() string {
    43  	return fmt.Sprintf("dirMod: %d, dist: %d", i.dirMod, i.dist)
    44  }
    45  
    46  func newInstructionFromRaw(raw []byte) instruction {
    47  
    48  	dirMod := func(firstChar byte) int {
    49  		if firstChar == 'R' {
    50  			return 1
    51  		} else {
    52  			return -1
    53  		}
    54  	}(raw[0])
    55  
    56  	dist := func(raw []byte) int {
    57  		numBytes := bytes.TrimSuffix(raw[1:], []byte{','})
    58  		num, err := strconv.Atoi(string(numBytes))
    59  		if err != nil {
    60  			utils.ExitFatal("%v", err)
    61  		}
    62  		return num
    63  	}(raw)
    64  
    65  	return instruction{dirMod: dirMod, dist: dist}
    66  }
    67  
    68  func (i instruction) toVector(cardinal vector) vector {
    69  	return vector{x: cardinal.x * i.dist, y: cardinal.y * i.dist}
    70  }
    71  
    72  func main() {
    73  	cardinals := makeCardinalVectors()
    74  	// 0 is north
    75  	dirIndex := 0
    76  	currentPos := vector{x: 0, y: 0}
    77  
    78  	f, err := os.Open("./2016/day1/input.txt")
    79  	if err != nil {
    80  		utils.ExitFatal("%v", err)
    81  	}
    82  	defer f.Close()
    83  	scan := bufio.NewScanner(f)
    84  	scan.Split(bufio.ScanWords)
    85  
    86  	visited := map[vector]bool{}
    87  
    88  	found := false
    89  
    90  	for scan.Scan() {
    91  		rawInstruction := scan.Bytes()
    92  		instruction := newInstructionFromRaw(rawInstruction)
    93  		dirIndex = mod(dirIndex+instruction.dirMod, 4)
    94  		normalisedDirection := cardinals[dirIndex]
    95  		walkVector := instruction.toVector(normalisedDirection)
    96  
    97  		nextPos := currentPos.add(walkVector)
    98  		intermediate := currentPos.allIntermediaryTo(nextPos, normalisedDirection)
    99  		if !found {
   100  		inner:
   101  			for _, pos := range intermediate {
   102  				if _, exists := visited[pos]; exists {
   103  					fmt.Printf("%+v", pos)
   104  					fmt.Printf("distance 2: %d\n", abs(pos.x)+abs(pos.y))
   105  					found = true
   106  					break inner
   107  				} else {
   108  					visited[pos] = true
   109  				}
   110  			}
   111  		}
   112  		currentPos = nextPos
   113  	}
   114  
   115  	fmt.Printf("distance 1: %d\n", abs(currentPos.x)+(currentPos.y))
   116  
   117  }
   118  
   119  func mod(a, b int) int {
   120  	return (a%b + b) % b
   121  }
   122  
   123  func abs(n int) int {
   124  	if n < 0 {
   125  		return -n
   126  	} else {
   127  		return n
   128  	}
   129  }