二维矩阵图形搜索

This commit is contained in:
kercylan98 2023-05-31 10:47:41 +08:00
parent b312639dc6
commit d2a6c5d8c7
4 changed files with 272 additions and 0 deletions

134
utils/g2d/shape.go Normal file
View File

@ -0,0 +1,134 @@
package g2d
import (
"github.com/kercylan98/minotaur/utils/g2d/shape"
)
type MatrixShapeSearchResult struct {
Shape *shape.Shape
Points []shape.Point
}
// MatrixShapeSearchWithYX 二维矩阵形状搜索
func MatrixShapeSearchWithYX[T any](matrix [][]T, shapes []*shape.Shape, checkMatchHandle func(val T) bool) []MatrixShapeSearchResult {
record := map[int]map[int]bool{}
width := len(matrix[0])
height := len(matrix)
for x := 0; x < width; x++ {
for y := 0; y < height; y++ {
record[x] = map[int]bool{y: true}
}
}
var result []MatrixShapeSearchResult
for _, s := range shapes {
points := s.GetPoints()
x, y := 0, 0
mx, my := s.GetMaxXY()
for {
if x+mx >= width {
x = 0
y++
}
if y+my >= height {
break
}
var count int
for _, point := range points {
px, py := point.GetXY()
px, py = px+x, py+y
if record[px][py] {
break
}
if checkMatchHandle(matrix[py][px]) {
count++
} else {
break
}
}
if count == len(points) {
target := MatrixShapeSearchResult{
Shape: s,
}
for _, point := range points {
px, py := point.GetXY()
px, py = px+x, py+y
ys, exist := record[px]
if !exist {
ys = map[int]bool{}
record[px] = ys
}
ys[py] = true
target.Points = append(target.Points, shape.NewPoint(px, py))
}
result = append(result, target)
}
x++
}
}
return result
}
// MatrixShapeSearchWithXY 二维矩阵形状搜索
func MatrixShapeSearchWithXY[T any](matrix [][]T, shapes []*shape.Shape, checkMatchHandle func(val T) bool) []MatrixShapeSearchResult {
record := map[int]map[int]bool{}
width := len(matrix)
height := len(matrix[0])
for x := 0; x < width; x++ {
for y := 0; y < height; y++ {
record[x] = map[int]bool{y: true}
}
}
var result []MatrixShapeSearchResult
for _, s := range shapes {
points := s.GetPoints()
x, y := 0, 0
mx, my := s.GetMaxXY()
for {
if x+mx >= width {
x = 0
y++
}
if y+my >= height {
break
}
var count int
for _, point := range points {
px, py := point.GetXY()
px, py = px+x, py+y
if record[px][py] {
break
}
if checkMatchHandle(matrix[px][py]) {
count++
} else {
break
}
}
if count == len(points) {
target := MatrixShapeSearchResult{
Shape: s,
}
for _, point := range points {
px, py := point.GetXY()
px, py = px+x, py+y
ys, exist := record[px]
if !exist {
ys = map[int]bool{}
record[px] = ys
}
ys[py] = true
target.Points = append(target.Points, shape.NewPoint(px, py))
}
result = append(result, target)
}
x++
}
}
return result
}

31
utils/g2d/shape/point.go Normal file
View File

@ -0,0 +1,31 @@
package shape
func NewPoint(x, y int) Point {
return Point{x, y}
}
func NewPointWithArray(arr [2]int) Point {
return Point{arr[0], arr[1]}
}
func NewPointWithArrays(arrays ...[2]int) []Point {
var points = make([]Point, len(arrays), len(arrays))
for i, arr := range arrays {
points[i] = NewPointWithArray(arr)
}
return points
}
type Point [2]int
func (slf Point) GetX() int {
return slf[0]
}
func (slf Point) GetY() int {
return slf[1]
}
func (slf Point) GetXY() (int, int) {
return slf[0], slf[1]
}

79
utils/g2d/shape/shape.go Normal file
View File

@ -0,0 +1,79 @@
package shape
func NewShape() *Shape {
shape := &Shape{
maxX: -1,
maxY: -1,
points: map[int]map[int]Point{},
}
return shape
}
// Shape 2D形状定义
type Shape struct {
maxX int
maxY int
points map[int]map[int]Point
}
func (slf *Shape) AddPoints(points ...Point) {
for _, point := range points {
slf.AddPoint(point)
}
}
func (slf *Shape) AddPoint(point Point) {
x, y := point.GetXY()
if x < 0 || y < 0 {
panic("only positive integers are allowed for shape point positions")
}
if x > slf.maxX {
slf.maxX = x
}
if y > slf.maxY {
slf.maxY = y
}
ys, exist := slf.points[x]
if !exist {
ys = map[int]Point{}
slf.points[x] = ys
}
ys[y] = point
}
func (slf *Shape) GetPoints() []Point {
var points []Point
for _, m := range slf.points {
for _, point := range m {
points = append(points, point)
}
}
return points
}
func (slf *Shape) GetMaxX() int {
return slf.maxX
}
func (slf *Shape) GetMaxY() int {
return slf.maxY
}
func (slf *Shape) GetMaxXY() (int, int) {
return slf.maxX, slf.maxY
}
func (slf *Shape) String() string {
var str string
for y := 0; y <= slf.maxY; y++ {
for x := 0; x <= slf.maxX; x++ {
if _, exist := slf.points[x][y]; exist {
str += "1"
} else {
str += "0"
}
}
str += "\r\n"
}
return str
}

28
utils/g2d/shape_test.go Normal file
View File

@ -0,0 +1,28 @@
package g2d
import (
"fmt"
"github.com/kercylan98/minotaur/utils/g2d/shape"
"testing"
)
func TestMatrixShape(t *testing.T) {
var m = [][]int{
{1, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 1, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
}
s := shape.NewShape()
s.AddPoints(shape.NewPointWithArrays([][2]int{{0, 0}, {0, 1}, {1, 1}, {2, 1}}...)...)
fmt.Println(s)
result := MatrixShapeSearchWithYX(m, []*shape.Shape{s}, func(val int) bool {
return val == 1
})
fmt.Println(len(result))
}