chore(day17): simplify interfaces. add docs
This commit is contained in:
		
							parent
							
								
									0d78959bea
								
							
						
					
					
						commit
						fd85530d88
					
				
							
								
								
									
										51
									
								
								search.go
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								search.go
									
									
									
									
									
								
							@ -1,44 +1,52 @@
 | 
				
			|||||||
package aoc
 | 
					package aoc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type priorityQueue[T any, U []T] struct {
 | 
					type priorityQueue[T any] struct {
 | 
				
			||||||
	elems        U
 | 
						elems        []T
 | 
				
			||||||
	less         func(a, b T) bool
 | 
						less         func(a, b T) bool
 | 
				
			||||||
	maxDepth     int
 | 
						maxDepth     int
 | 
				
			||||||
	totalEnqueue int
 | 
						totalEnqueue int
 | 
				
			||||||
 | 
						totalDequeue int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func PriorityQueue[T any, U []T](less func(a, b T) bool) *priorityQueue[T, U] {
 | 
					// PriorityQueue implements a simple slice based queue.
 | 
				
			||||||
	return &priorityQueue[T, U]{less: less}
 | 
					// less is the function for sorting. reverse a and b to reverse the sort.
 | 
				
			||||||
 | 
					// T is the item
 | 
				
			||||||
 | 
					// U is a slice of T
 | 
				
			||||||
 | 
					func PriorityQueue[T any](less func(a, b T) bool) *priorityQueue[T] {
 | 
				
			||||||
 | 
						return &priorityQueue[T]{less: less}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (pq *priorityQueue[T, U]) Enqueue(elem T) {
 | 
					func (pq *priorityQueue[T]) Enqueue(elem T) {
 | 
				
			||||||
	pq.elems = append(pq.elems, elem)
 | 
					 | 
				
			||||||
	pq.totalEnqueue++
 | 
						pq.totalEnqueue++
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pq.elems = append(pq.elems, elem)
 | 
				
			||||||
	pq.maxDepth = max(pq.maxDepth, len(pq.elems))
 | 
						pq.maxDepth = max(pq.maxDepth, len(pq.elems))
 | 
				
			||||||
	sort.Slice(pq.elems, func(i, j int) bool { return pq.less(pq.elems[i], pq.elems[j]) })
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (pq *priorityQueue[T, I]) IsEmpty() bool {
 | 
					func (pq *priorityQueue[T]) IsEmpty() bool {
 | 
				
			||||||
	return len(pq.elems) == 0
 | 
						return len(pq.elems) == 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (pq *priorityQueue[T, I]) Dequeue() (T, bool) {
 | 
					func (pq *priorityQueue[T]) Dequeue() (T, bool) {
 | 
				
			||||||
 | 
						pq.totalDequeue++
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var elem T
 | 
						var elem T
 | 
				
			||||||
	if pq.IsEmpty() {
 | 
						if pq.IsEmpty() {
 | 
				
			||||||
		return elem, false
 | 
							return elem, false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sort.Slice(pq.elems, func(i, j int) bool { return pq.less(pq.elems[i], pq.elems[j]) })
 | 
				
			||||||
	pq.elems, elem = pq.elems[:len(pq.elems)-1], pq.elems[len(pq.elems)-1]
 | 
						pq.elems, elem = pq.elems[:len(pq.elems)-1], pq.elems[len(pq.elems)-1]
 | 
				
			||||||
	return elem, true
 | 
						return elem, true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ManhattanDistance the distance between two points measured along axes at right angles.
 | 
				
			||||||
func ManhattanDistance[T integer](a, b Point[T]) T {
 | 
					func ManhattanDistance[T integer](a, b Point[T]) T {
 | 
				
			||||||
	return ABS(a[1]-b[1]) + ABS(a[0]-b[0])
 | 
						return ABS(a[1]-b[1]) + ABS(a[0]-b[0])
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type pather[C number, N any] interface {
 | 
					type pather[C number, N comparable] interface {
 | 
				
			||||||
	Neighbors(N) []N
 | 
						Neighbors(N) []N
 | 
				
			||||||
	Cost(a, b N) C
 | 
						Cost(a, b N) C
 | 
				
			||||||
	Potential(a, b N) C
 | 
						Potential(a, b N) C
 | 
				
			||||||
@ -46,15 +54,20 @@ type pather[C number, N any] interface {
 | 
				
			|||||||
	// OPTIONAL:
 | 
						// OPTIONAL:
 | 
				
			||||||
	// Seen modify value used by seen pruning.
 | 
						// Seen modify value used by seen pruning.
 | 
				
			||||||
	// Seen(N) N
 | 
						// Seen(N) N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Target returns true if target reached.
 | 
						// Target returns true if target reached.
 | 
				
			||||||
	// Target(N) bool
 | 
						// Target(N) bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Path[C number, N any] []N
 | 
					// FindPath uses the A* path finding algorithem.
 | 
				
			||||||
 | 
					// g is the graph source that implements the pather interface.
 | 
				
			||||||
func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, Path[C, N]) {
 | 
					//   C is an numeric type for calculating cost/potential
 | 
				
			||||||
 | 
					//   N is the node values. is comparable for storing in visited table for pruning.
 | 
				
			||||||
 | 
					// start, end are nodes that dileniate the start and end of the search path.
 | 
				
			||||||
 | 
					// The returned values are the calculated cost and the path taken from start to end.
 | 
				
			||||||
 | 
					func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, []N) {
 | 
				
			||||||
	var zero C
 | 
						var zero C
 | 
				
			||||||
	closed := make(map[N]bool)
 | 
						visited := make(map[N]bool)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	type node struct {
 | 
						type node struct {
 | 
				
			||||||
		cost      C
 | 
							cost      C
 | 
				
			||||||
@ -83,7 +96,7 @@ func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, Path[C,
 | 
				
			|||||||
	pq.Enqueue(node{position: start})
 | 
						pq.Enqueue(node{position: start})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		fmt.Println("queue max depth = ", pq.maxDepth, "total enqueue = ", pq.totalEnqueue)
 | 
							Log("queue max depth = ", pq.maxDepth, "total enqueue = ", pq.totalEnqueue, "total dequeue = ", pq.totalDequeue)
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var seenFn = func(a N) N { return a }
 | 
						var seenFn = func(a N) N { return a }
 | 
				
			||||||
@ -101,10 +114,10 @@ func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, Path[C,
 | 
				
			|||||||
		cost, potential, n := current.cost, current.potential, current.position
 | 
							cost, potential, n := current.cost, current.potential, current.position
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		seen := seenFn(n)
 | 
							seen := seenFn(n)
 | 
				
			||||||
		if closed[seen] {
 | 
							if visited[seen] {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		closed[seen] = true
 | 
							visited[seen] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if cost > 0 && potential == zero && targetFn(current.position) {
 | 
							if cost > 0 && potential == zero && targetFn(current.position) {
 | 
				
			||||||
			return cost, NewPath(¤t)
 | 
								return cost, NewPath(¤t)
 | 
				
			||||||
@ -112,7 +125,7 @@ func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, Path[C,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		for _, nb := range g.Neighbors(n) {
 | 
							for _, nb := range g.Neighbors(n) {
 | 
				
			||||||
			seen := seenFn(nb)
 | 
								seen := seenFn(nb)
 | 
				
			||||||
			if closed[seen] {
 | 
								if visited[seen] {
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user