mirror of
				https://github.com/onyx-and-iris/aoc2024.git
				synced 2025-10-31 13:01:45 +00:00 
			
		
		
		
	refactor using graph struct and adjacency function
This commit is contained in:
		
							parent
							
								
									dda597a577
								
							
						
					
					
						commit
						83399a45c2
					
				| @ -1,7 +1,9 @@ | |||||||
| package one | package one | ||||||
| 
 | 
 | ||||||
|  | type direction int | ||||||
|  | 
 | ||||||
| const ( | const ( | ||||||
| 	N = iota | 	N direction = iota | ||||||
| 	NE | 	NE | ||||||
| 	E | 	E | ||||||
| 	SE | 	SE | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								day-04/internal/one/graph.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								day-04/internal/one/graph.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | package one | ||||||
|  | 
 | ||||||
|  | type graph struct { | ||||||
|  | 	data []string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newGraph() *graph { | ||||||
|  | 	return &graph{} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (g *graph) valueAt(p point) rune { | ||||||
|  | 	return rune(g.data[p.y][p.x]) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (g *graph) isOutOfBounds(p point) bool { | ||||||
|  | 	return p.x < 0 || p.y < 0 || p.y >= len(g.data) || p.x >= len(g.data[p.y]) | ||||||
|  | } | ||||||
| @ -1,58 +1,14 @@ | |||||||
| package one | package one | ||||||
| 
 | 
 | ||||||
| type neighbour struct { | func neighbours(p point) [8]point { | ||||||
| 	x         int | 	return [8]point{ | ||||||
| 	y         int | 		{y: p.y - 1, x: p.x, direction: N}, | ||||||
| 	direction int | 		{y: p.y - 1, x: p.x + 1, direction: NE}, | ||||||
| } | 		{y: p.y, x: p.x + 1, direction: E}, | ||||||
| 
 | 		{y: p.y + 1, x: p.x + 1, direction: SE}, | ||||||
| func newNeighbour(direction, x, y int) neighbour { | 		{y: p.y + 1, x: p.x, direction: S}, | ||||||
| 	switch direction { | 		{y: p.y + 1, x: p.x - 1, direction: SW}, | ||||||
| 	case N: | 		{y: p.y, x: p.x - 1, direction: W}, | ||||||
| 		return neighbour{x, y + 1, direction} | 		{y: p.y - 1, x: p.x - 1, direction: NW}, | ||||||
| 	case NE: |  | ||||||
| 		return neighbour{x + 1, y + 1, direction} |  | ||||||
| 	case E: |  | ||||||
| 		return neighbour{x + 1, y, direction} |  | ||||||
| 	case SE: |  | ||||||
| 		return neighbour{x + 1, y - 1, direction} |  | ||||||
| 	case S: |  | ||||||
| 		return neighbour{x, y - 1, direction} |  | ||||||
| 	case SW: |  | ||||||
| 		return neighbour{x - 1, y - 1, direction} |  | ||||||
| 	case W: |  | ||||||
| 		return neighbour{x - 1, y, direction} |  | ||||||
| 	case NW: |  | ||||||
| 		return neighbour{x - 1, y + 1, direction} |  | ||||||
| 	default: |  | ||||||
| 		return neighbour{} |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 |  | ||||||
| type neighbours struct { |  | ||||||
| 	N  neighbour |  | ||||||
| 	NE neighbour |  | ||||||
| 	E  neighbour |  | ||||||
| 	SE neighbour |  | ||||||
| 	S  neighbour |  | ||||||
| 	SW neighbour |  | ||||||
| 	W  neighbour |  | ||||||
| 	NW neighbour |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func newNeighbours(x, y int) neighbours { |  | ||||||
| 	return neighbours{ |  | ||||||
| 		newNeighbour(N, x, y), |  | ||||||
| 		newNeighbour(NE, x, y), |  | ||||||
| 		newNeighbour(E, x, y), |  | ||||||
| 		newNeighbour(SE, x, y), |  | ||||||
| 		newNeighbour(S, x, y), |  | ||||||
| 		newNeighbour(SW, x, y), |  | ||||||
| 		newNeighbour(W, x, y), |  | ||||||
| 		newNeighbour(NW, x, y), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (n neighbours) all() [8]neighbour { |  | ||||||
| 	return [8]neighbour{n.N, n.NE, n.E, n.SE, n.S, n.SW, n.W, n.NW} |  | ||||||
| } |  | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								day-04/internal/one/point.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								day-04/internal/one/point.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | package one | ||||||
|  | 
 | ||||||
|  | type point struct { | ||||||
|  | 	x, y      int | ||||||
|  | 	direction direction | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newPoint(x, y int) point { | ||||||
|  | 	return point{x: x, y: y} | ||||||
|  | } | ||||||
| @ -3,30 +3,28 @@ package one | |||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 
 | 
 | ||||||
| 	"github.com/onyx-and-iris/aoc2024/day-04/internal/util" |  | ||||||
| 
 |  | ||||||
| 	log "github.com/sirupsen/logrus" | 	log "github.com/sirupsen/logrus" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func Solve(buf []byte) (int, error) { | func Solve(buf []byte) (int, error) { | ||||||
| 	r := bytes.NewReader(buf) | 	r := bytes.NewReader(buf) | ||||||
| 	lines, err := util.ReadLines(r) | 	graph, err := readLines(r) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return 0, err | 		return 0, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var sum int | 	var sum int | ||||||
| 
 | 
 | ||||||
| 	for i := 0; i < len(lines); i++ { | 	for i := 0; i < len(graph.data); i++ { | ||||||
| 		for j := 0; j < len(lines[i]); j++ { | 		for j := 0; j < len(graph.data[i]); j++ { | ||||||
| 			neighbours := newNeighbours(j, i) | 			current := newPoint(j, i) | ||||||
| 			for _, n := range neighbours.all() { | 			if graph.valueAt(current) == 'X' { | ||||||
| 				if n.x < 0 || n.y < 0 || n.y >= len(lines) || n.x >= len(lines[i]) { | 				for _, n := range neighbours(current) { | ||||||
| 					continue | 					if graph.isOutOfBounds(n) { | ||||||
| 				} | 						continue | ||||||
|  | 					} | ||||||
| 
 | 
 | ||||||
| 				if lines[i][j] == 'X' { | 					if checkNeighbours(graph, n, "MAS") { | ||||||
| 					if checkNeighbours(n, "MAS", lines) { |  | ||||||
| 						sum++ | 						sum++ | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| @ -37,19 +35,19 @@ func Solve(buf []byte) (int, error) { | |||||||
| 	return sum, nil | 	return sum, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func checkNeighbours(n neighbour, word string, lines []string) bool { | func checkNeighbours(graph *graph, n point, word string) bool { | ||||||
| 	if len(word) == 0 { | 	if len(word) == 0 { | ||||||
| 		log.Debug("we found a full XMAS") | 		log.Debug("we found a full XMAS") | ||||||
| 		return true | 		return true | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if n.x < 0 || n.y < 0 || n.y >= len(lines) || n.x >= len(lines[n.y]) { | 	if graph.isOutOfBounds(n) { | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if lines[n.y][n.x] != word[0] { | 	if graph.valueAt(n) != rune(word[0]) { | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return checkNeighbours(newNeighbour(n.direction, n.x, n.y), word[1:], lines) | 	return checkNeighbours(graph, neighbours(n)[n.direction], word[1:]) | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										21
									
								
								day-04/internal/one/util.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								day-04/internal/one/util.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | package one | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func readLines(r io.Reader) (*graph, error) { | ||||||
|  | 	graph := newGraph() | ||||||
|  | 
 | ||||||
|  | 	scanner := bufio.NewScanner(r) | ||||||
|  | 	for scanner.Scan() { | ||||||
|  | 		graph.data = append(graph.data, scanner.Text()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := scanner.Err(); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return graph, nil | ||||||
|  | } | ||||||
| @ -1,7 +1,9 @@ | |||||||
| package two | package two | ||||||
| 
 | 
 | ||||||
|  | type direction int | ||||||
|  | 
 | ||||||
| const ( | const ( | ||||||
| 	NW = iota | 	NW direction = iota | ||||||
| 	NE | 	NE | ||||||
| 	SE | 	SE | ||||||
| 	SW | 	SW | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								day-04/internal/two/graph.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								day-04/internal/two/graph.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | package two | ||||||
|  | 
 | ||||||
|  | type graph struct { | ||||||
|  | 	data []string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newGraph() *graph { | ||||||
|  | 	return &graph{} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (g *graph) valueAt(p point) rune { | ||||||
|  | 	return rune(g.data[p.y][p.x]) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (g *graph) isOutOfBounds(p point) bool { | ||||||
|  | 	return p.x < 0 || p.y < 0 || p.y >= len(g.data) || p.x >= len(g.data[p.y]) | ||||||
|  | } | ||||||
| @ -1,50 +1,10 @@ | |||||||
| package two | package two | ||||||
| 
 | 
 | ||||||
| type neighbour struct { | func neighbours(p point) [4]point { | ||||||
| 	x         int | 	return [4]point{ | ||||||
| 	y         int | 		{p.x - 1, p.y - 1, NW}, | ||||||
| 	direction int | 		{p.x + 1, p.y - 1, NE}, | ||||||
| } | 		{p.x + 1, p.y + 1, SE}, | ||||||
| 
 | 		{p.x - 1, p.y + 1, SW}, | ||||||
| func newNeighbour(direction, x, y int) neighbour { |  | ||||||
| 	switch direction { |  | ||||||
| 	case NW: |  | ||||||
| 		return neighbour{x - 1, y + 1, direction} |  | ||||||
| 	case NE: |  | ||||||
| 		return neighbour{x + 1, y + 1, direction} |  | ||||||
| 	case SE: |  | ||||||
| 		return neighbour{x + 1, y - 1, direction} |  | ||||||
| 	case SW: |  | ||||||
| 		return neighbour{x - 1, y - 1, direction} |  | ||||||
| 	default: |  | ||||||
| 		return neighbour{} |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 |  | ||||||
| func (n neighbour) outOfBounds(lines []string) bool { |  | ||||||
| 	return n.x < 0 || n.y < 0 || n.y >= len(lines) || n.x >= len(lines[0]) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (n neighbour) value(lines []string) rune { |  | ||||||
| 	return rune(lines[n.y][n.x]) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type neighbours struct { |  | ||||||
| 	NW neighbour |  | ||||||
| 	NE neighbour |  | ||||||
| 	SE neighbour |  | ||||||
| 	SW neighbour |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func newNeighbours(x, y int) neighbours { |  | ||||||
| 	return neighbours{ |  | ||||||
| 		newNeighbour(NW, x, y), |  | ||||||
| 		newNeighbour(NE, x, y), |  | ||||||
| 		newNeighbour(SE, x, y), |  | ||||||
| 		newNeighbour(SW, x, y), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (n neighbours) all() [4]neighbour { |  | ||||||
| 	return [4]neighbour{n.NW, n.NE, n.SE, n.SW} |  | ||||||
| } |  | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								day-04/internal/two/point.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								day-04/internal/two/point.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | package two | ||||||
|  | 
 | ||||||
|  | type point struct { | ||||||
|  | 	x, y      int | ||||||
|  | 	direction direction | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newPoint(x, y int) point { | ||||||
|  | 	return point{x: x, y: y} | ||||||
|  | } | ||||||
| @ -3,29 +3,28 @@ package two | |||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"slices" | 	"slices" | ||||||
| 
 |  | ||||||
| 	"github.com/onyx-and-iris/aoc2024/day-04/internal/util" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func Solve(buf []byte) (int, error) { | func Solve(buf []byte) (int, error) { | ||||||
| 	r := bytes.NewReader(buf) | 	r := bytes.NewReader(buf) | ||||||
| 	lines, err := util.ReadLines(r) | 	graph, err := readLines(r) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return 0, err | 		return 0, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var sum int | 	var sum int | ||||||
| 
 | 
 | ||||||
| 	for i := 0; i < len(lines); i++ { | 	for i := 0; i < len(graph.data); i++ { | ||||||
| 		for j := 0; j < len(lines[i]); j++ { | 		for j := 0; j < len(graph.data[i]); j++ { | ||||||
| 			if lines[i][j] == 'A' { | 			current := newPoint(j, i) | ||||||
| 				neighbours := newNeighbours(j, i) | 			if graph.valueAt(current) == 'A' { | ||||||
| 				if func() bool { | 				if func() bool { | ||||||
| 					for _, n := range neighbours.all() { | 					for _, n := range neighbours(current) { | ||||||
| 						if n.outOfBounds(lines) { | 						if graph.isOutOfBounds(n) { | ||||||
| 							return true | 							return true | ||||||
| 						} | 						} | ||||||
| 						if !slices.Contains([]rune{'M', 'S'}, n.value(lines)) { | 
 | ||||||
|  | 						if !slices.Contains([]rune{'M', 'S'}, graph.valueAt(n)) { | ||||||
| 							return true | 							return true | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| @ -34,12 +33,13 @@ func Solve(buf []byte) (int, error) { | |||||||
| 					continue | 					continue | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | 				ns := neighbours(current) | ||||||
| 				matrix := newMatrix( | 				matrix := newMatrix( | ||||||
| 					rune(lines[i][j]), | 					graph.valueAt(current), | ||||||
| 					neighbours.NW.value(lines), | 					graph.valueAt(ns[NW]), | ||||||
| 					neighbours.NE.value(lines), | 					graph.valueAt(ns[NE]), | ||||||
| 					neighbours.SE.value(lines), | 					graph.valueAt(ns[SE]), | ||||||
| 					neighbours.SW.value(lines), | 					graph.valueAt(ns[SW]), | ||||||
| 				) | 				) | ||||||
| 
 | 
 | ||||||
| 				if matrix.validate() { | 				if matrix.validate() { | ||||||
|  | |||||||
							
								
								
									
										21
									
								
								day-04/internal/two/util.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								day-04/internal/two/util.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | package two | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func readLines(r io.Reader) (*graph, error) { | ||||||
|  | 	graph := newGraph() | ||||||
|  | 
 | ||||||
|  | 	scanner := bufio.NewScanner(r) | ||||||
|  | 	for scanner.Scan() { | ||||||
|  | 		graph.data = append(graph.data, scanner.Text()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := scanner.Err(); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return graph, nil | ||||||
|  | } | ||||||
| @ -1,21 +0,0 @@ | |||||||
| package util |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"bufio" |  | ||||||
| 	"io" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func ReadLines(r io.Reader) ([]string, error) { |  | ||||||
| 	lines := []string{} |  | ||||||
| 
 |  | ||||||
| 	scanner := bufio.NewScanner(r) |  | ||||||
| 	for scanner.Scan() { |  | ||||||
| 		lines = append(lines, scanner.Text()) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if err := scanner.Err(); err != nil { |  | ||||||
| 		return []string{}, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return lines, nil |  | ||||||
| } |  | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user