u/ficklefawn
ficklefawn
ficklefawn
As an exception, if the type of x is a defined pointer type and (x).f is a valid selector expression denoting a field (but not a method), x.f is shorthand for (x).f.
Because I’m new to Go (and pointers in general) and I didn’t know about this! Thank you!
ficklefawn
Golang
I use the formula
( x, y ) -> (x, f - | f - y | ) after fold f along y-axis
( x, y ) -> (f - | f - x |, y) after fold along x-asis
ficklefawn
Exactly! ;)
ficklefawn
Golang
AoC is getting a bit tedious for me, where I come up with a solution quickly but debugging my implementation takes a while - so I guess I'm training to write tidier code.
I leave out the trivial functions like mapCaves() that reads the inputs, and curr(), copy() etc. Interesting parts below.
func day12a(ls *bufio.Scanner) {
cs := mapCaves(ls, 0) // 0 for bonus visits to small caves
cs.exploreFrom((*cs).paths[0])
fmt.Printf("Completed Paths: %d\n", (*cs).completedPaths)
}
func day12b(ls *bufio.Scanner) {
cs := mapCaves(ls, 1) // 1 for bonus visits to small caves
cs.exploreFrom((*cs).paths[0])
fmt.Printf("Completed Paths: %d\n", (*cs).completedPaths)
}
// ==========
// CAVESYSTEM
// ==========
// Has addCave() and setNeighbours() for creation of cave system from inputs
type CaveSystem struct {
caves map[string]*Cave
paths []*Path
completedPaths int
}
func (cs *CaveSystem) exploreFrom(p *Path) {
// Splits path p to p1, p2, ..., pN where
// p1 = p, {p.curr -> p.curr.neighbour(1)
// p2 = p, {p.curr -> p.curr.neighbour(1)
// ...
// for each of p.curr's N neighbours.
// If we're already at the end, no more exploring
if p.curr().cType == End {
return
}
var path *Path
for idx, n := range (*p.curr()).neighbours {
if (*n).cType == Big || (*n).cType == End || ((*n).cType == Small && ((*p).visited[n] < 1 || (*p).bonusVisits > 0 )) {
if (*n).cType == End {
(*cs).completedPaths++
}
if idx == len(p.curr().neighbours)-1 {
// Extend this path
path = p
p.visit(n)
} else {
// Make new path
path = (*p).copy()
(*cs).paths = append((*cs).paths, path)
path.visit(n)
}
cs.exploreFrom(path)
}
}
}
// =====
// CAVES
// =====
type Cave struct {
name string
neighbours []*Cave
cType CaveType
}
// =====
// PATHS
// =====
// has curr() to get current node and copy() to copy path
type Path struct {
path []*Cave
visited map[*Cave]int
bonusVisits int
}
func (p *Path) visit(c *Cave) {
(*p).visited[c]++
// If we visited a small node, note if a bonus visit was used
if (*c).cType == Small && (*p).visited[c] > 1 {
(*p).bonusVisits--
}
(*p).path = append((*p).path, c)
}
ficklefawn
Ps I like your solutions, they're very readable in general. :) Nice to have someone to follow along with who is also solving in Go!
ficklefawn
Thanks!
So with variable x, &x gives you a pointer to the memory location of the value of x. Then, if you are working with a pointer px, you need *px to resolve its value.
I haven’t worked with pointer much myself but I’m learning, and I think it’s useful when implementing certain datastructures like a tree for example. It basically means you never have to redefine a node or copy a node to a new location when instantiating to a new variable - you can always just reference the pointer to the old one. Pretty cool to work with, even though it’s confusing at first.
ficklefawn
All my solutions here
Will look at yours also, respond back tomorrow
ficklefawn
Thanks for the response!! Will do.
ficklefawn
Golang (just the idea)
I spent an unreasonable amount of time on this one. I was trying to solve it for an extremely large input array, thinking I wanted to avoid sorting through the colony of octopi each round to find the 9s.
Keeping track of this was a massive headache, until I realized the input is actually tiny and it's probably overkill to want to track the 9s without looking at the entire colony each step.
My solution isn't super interesting, I defined an octopus like this:
type Octopus struct {
energy int // always between 0 and 9
x int
y int // (x,y) position in the colony
neighbours []*Octopus
flashed bool // Whether octopus flashed before this round
}
On the first passthrough, every octopus finds his neighbours and keeps track of them to not calculate it every round. An octopus has a flash method to increment the energy level of his neighbours, and it recursively calls flash for each neighbour who reaches the maximum energy level, if they didn't flash before this round.
Turned out to be quite fast this way, I'll take this as a lesson to always consider the kind of input we have before trying to solve a way harder problem.
If anyone has a solution like this though, that doesn't search for the 9s in each step, I'd love to see it!!
edit: full code here
ficklefawn
Thanks, I considered it but really hate appending on slices of undefined length if I don’t have to. Is the append function modifying the existing slice, or writing each element into a new slice every time? The assignment ( x = append(x, ) suggests to me it’s the latter and it feels painfully inefficient
But neat to know about the stack[:x] syntax, I didn’t come across that yet so I was also unsure how I would pop from the slice. Thanks again!
ficklefawn
Golang
I am learning Go and not really used to working with languages using pointers, so I had fun with this one implementing a stack. The interesting bits:
// ==========
// DELIMITERS
// ==========
type Delim struct {
opening bool
matcher rune
score int
}
func (d *Delim) closes(r rune) bool {
return (*d).matcher == r
}
// ====================
// STACK IMPLEMENTATION
// ====================
type StackEle struct {
val *Delim
next *StackEle
}
type Stack struct {
top *StackEle
}
func (s *Stack) push(d *Delim) {
(*s).top = &StackEle{d, (*s).top}
}
func (s *Stack) pop() (*Delim, bool) {
if (*s).top == nil {
return nil, false
}
d := (*s).top.val
(*s).top = (*s).top.next
return d, true
}
And with this setup the syntax checker becomes:
var delimiters = map[rune]*Delim {
'(': {true, ')', 1 },
'[': {true, ']', 2 },
'{': {true, '}', 3 },
'<': {true, '>', 4 },
')': {false, '(', 3 },
']': {false, '[', 57},
'}': {false, '{', 1197},
'>': {false, '<', 25137},
}
// Returns remaining stack and score
func checkSyntax(runes []rune) (*Stack, int) {
stack := Stack{nil }
for _, r := range runes {
d := delimiters[r]
if d.opening {
stack.push(d)
} else {
p, ok := stack.pop()
if !ok {
fmt.Println("Received closing delimiter on empty stack.")
break
} else if !p.closes(r) {
// fmt.Printf("Syntax error: Expected %s, found %s \n", string((*p).matcher), string(r))
return &stack, d.score
}
}
}
return &stack, 0
}
Not shown is the actuall call to part a), part b) but part a basically prints out the score return value, while part b uses the remaining stack to calculate the completion score.
ficklefawn
Golang
With the condition that we know 1, 4, 7, 8 up front, I decided to use the following unique identifier for each number:
( digit lines, digit lines in common with 4, digit lines in common with 7)
but using the minimal id each time, i.e. only calculate as far as I need. This gives me
var digitId = []string {
0: "633", // Digit 0 is formed of 6 edges, 3 in common with 4, 3 in common with 7
1: "2",
2: "52",
3: "533",
4: "4",
5: "532",
6: "632",
7: "3",
8: "7",
9: "64",
}
and from there it's easy to learn the codes
// ===========
// LEARN CODES
// ===========
func learnCodes(words []string) map[string]*Digit {
digits := make(map[string]*Digit)
// Initializes map with valid IDs as keys
for idx, id := range digitId {
digits[id] = &Digit{idx, ""}
}
unknownDigits := make([]*UnknownDigit, 0)
// Finds 1, 4, 7, 8, because id = len(word) is in the map
for _, word := range words {
id := strconv.Itoa(len(word))
// if the id is found in the map, it's a valid id
if digit, found := digits[id]; found {
digit.code = word
} else {
unknownDigits = append(unknownDigits, &UnknownDigit{word, id})
}
}
// Finds the rest of the unknown learnCodes
for _, unknownDigit:= range unknownDigits {
id := validId(digits, (*unknownDigit).code)
(*digits[id]).code = (*unknownDigit).code
}
return digits
}
// ============
// HELPER FUNCS
// ============
// Tries X, XY, and XYZ until a unique id in the map is found
// where X = length of code, Y = gcd(code, 4), Z = gcd(code, 7)
func validId(idmap map[string]*Digit, code string) string {
id := strconv.Itoa(len(code))
if _, found := idmap[id]; found {
return id
}
id += strconv.Itoa(gcd(code, (*idmap[digitId[4]]).code))
if _, found := idmap[id]; found {
return id
}
id += strconv.Itoa(gcd(code, (*idmap[digitId[7]]).code))
return id
}
// gcd(a,b) is the number of edges a-digit has in common with b-digit
// Example: gcd(3,4) = 3, because 3-digit has 3 edges in common with the 4-digit
func gcd(a string, b string) int {
gcd := 0
for _, c := range a {
if strings.Contains(b, string(c)) {
gcd++
}
}
return gcd
}
ficklefawn
I live in some knitting twilight zone where every time I swatch, the garment turns out all wonky and everytime I don't, it's perfect!
I think it's because I'm good at adjusting my tension in general and I subconsciously modify it after swatching if it's not the exact same as the pattern.
ficklefawn
;D
Knitting, cats and wine is what this quarantine is made of <3
ficklefawn
Yarn: Retrosaria Brusca, colorway 5C as MC, Spincycle Dream State, colorway Melancholia as CC
Pattern: Koivua by Caitlin Hunter, bought on Ravelry
Needles: 3.5mm and 4mm
Gauge: Who knows, I never swatch
Super happy with this one! Have been wanting to knit it for months, had the yarn since Christmas but didn't get the kick to start until after being quarantined for 2 weeks. Took me just under a month to finish, I still have to block it.
ficklefawn
Both actually. Harness for longer walks, sometimes collar when just walking around the block.
ficklefawn
The former, mostly. He knows how to walk at heel and if he has played enough and is generally relaxed and focused to learn, he can do it well. The problems arise when we are walking to a play area for example and he has a lot of built up energy, then he's pulling like crazy to every patch of grass he sees. We do the stop and wait, he gets incredibly frustrated quickly.
ficklefawn
I think patience/forgiveness could be what I'm missing... 😉 He is perfect inside the house, glued to my heel forwards and backwards. He can do so outside too if I have a lot of high value treats but his default is to smell or see something exciting and basically pounce ahead, pulling the leash.
ficklefawn
Me too, I'm so curious what the white fringe will look like! I haven't really seen pictures of other paps with the same mismarks on the back of the ears.
ficklefawn
Thank you! Yes it's even softer 😍
A friend commented that we must wash him every day because he's so clean and soft but I think we can thank the cats for that as we only washed him once 😂
ficklefawn
Aww thank you - I think so too, despite being a little mismark. 🤗
ficklefawn
@embercoons mainly has pictures of my maine coons thus far as we just got a pup under a week ago! I will be sharing more of him as time goes on. 🤗
ficklefawn
Oh yeah I can't wait to see him fully grown ☺️
ficklefawn
So regal. 😍 My floof has the same scratch bed. He loves it so much.
Nice, I checked it out - looks good!!