All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.neko233.skilltree.game.grid.impl.Grid2DByMap.kt Maven / Gradle / Ivy

There is a newer version: 0.3.6
Show newest version
package com.neko233.skilltree.game.grid.impl

import com.neko233.skilltree.game.grid.Grid2D
import com.example.kotlinplayground.spaceMath.Vector2D
import java.util.*
import kotlin.collections.ArrayDeque
import kotlin.math.abs

/**
 * 2D 地图格子 by Map 实现 (稀疏矩阵)
 */
class Grid2DByMap(
        val width: Int,
        val height: Int,
        val fillValue: T? = null,
) : Grid2D {
    // Map
    private val grid: MutableMap = mutableMapOf()

    init {
        clear()
        fill(fillValue)
    }

    override fun get(
            x: Int,
            y: Int,
    ): T? {
        return grid[Vector2D(x, y)]
    }

    override fun set(
            x: Int,
            y: Int,
            value: T?,
    ) {
        grid[Vector2D(x, y)] = value
    }

    override fun clear() {
        for (x in 0 until width) {
            for (y in 0 until height) {
                grid[Vector2D(x, y)] = null
            }
        }
    }

    override fun fill(value: T?) {
        for (x in 0 until width) {
            for (y in 0 until height) {
                grid[Vector2D(x, y)] = value
            }
        }
    }

    override fun forEach(
            handleGrid: (x: Int, y: Int, value: T?) -> Unit,
    ) {
        for (x in 0 until width) {
            for (y in 0 until height) {
                handleGrid(x, y, grid[Vector2D(x, y)])
            }
        }
    }


    /**
     * 广度优先搜索
     */
    override fun bfs(start: Vector2D, target: Vector2D): List {
        val queue = ArrayDeque()
        val visited = mutableSetOf()
        val parentMap = mutableMapOf()

        queue.add(start)
        visited.add(start)

        while (queue.isNotEmpty()) {
            val current = queue.removeFirst()

            if (current == target) {
                return reconstructPath(start, target, parentMap)
            }

            val neighbors = getNeighbors(current)
            for (neighbor in neighbors) {
                if (neighbor !in visited) {
                    queue.add(neighbor)
                    visited.add(neighbor)
                    parentMap[neighbor] = current
                }
            }

            visited.add(current) // 将当前节点标记为已访问
        }

        return emptyList()
    }


    override fun dfs(start: Vector2D, target: Vector2D): List {
        val stack = Stack()
        val visited = mutableSetOf()
        val parentMap = mutableMapOf()

        stack.push(start)
        visited.add(start)

        while (stack.isNotEmpty()) {
            val current = stack.pop()

            if (current == target) {
                return reconstructPath(start, target, parentMap)
            }

            val neighbors = getNeighbors(current)
            for (neighbor in neighbors) {
                if (neighbor !in visited) {
                    stack.push(neighbor)
                    visited.add(neighbor)
                    parentMap[neighbor] = current
                }
            }
        }

        return emptyList()
    }


    private fun reconstructPath(
            start: Vector2D,
            target: Vector2D,
            parentMap: Map,
    ): List {
        val path = mutableListOf()
        var current = target

        while (current != start) {
            path.add(current)
            current = parentMap[current] ?: break
        }

        path.add(start)
        path.reverse()

        return path
    }

    override fun aStar(
            start: Vector2D,
            target: Vector2D,
            targetScoreMap: MutableMap,
            targetCostMap: MutableMap,
    ): List {
        val toTryGridList = mutableListOf(start)
        val cameFrom = mutableMapOf()

        while (toTryGridList.isNotEmpty()) {
            val current = toTryGridList.minByOrNull { targetCostMap.getOrDefault(it, Double.MAX_VALUE) }!!

            if (current == target) {
                return reconstructPath(start, target, cameFrom)
            }

            toTryGridList.remove(current)

            // 获取当前节点的邻居节点
            val neighbors = getNeighbors(current)
            for (neighbor in neighbors) {
                val defaultScore = targetScoreMap.getOrDefault(current, Int.MAX_VALUE)

                // 计算 tentativeGScore
                val tentativeGScore = defaultScore + 1

                // 比较 tentativeGScore 和邻居节点的得分
                if (tentativeGScore < targetScoreMap.getOrDefault(neighbor, Int.MAX_VALUE)) {
                    cameFrom[neighbor] = current
                    targetScoreMap[neighbor] = tentativeGScore
                    targetCostMap[neighbor] = tentativeGScore + heuristic(neighbor, target)

                    // 将邻居节点加入到待尝试的节点列表
                    if (neighbor !in toTryGridList) {
                        toTryGridList.add(neighbor)
                    }
                }
            }
        }

        // 若没有找到路径,则返回空列表
        return emptyList()
    }


    override fun heuristic(start: Vector2D, target: Vector2D): Double {
        val xPrice = abs(start.x - target.x)
        val yPrice = abs(start.y - target.y).toDouble()
        return xPrice + yPrice
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy