Advertisement
Guest User

factorio bot pathing

a guest
Sep 1st, 2023
13
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 5.40 KB | None | 0 0
  1. import kotlin.math.sqrt
  2.  
  3. val roboports = """
  4. 0,0
  5. 0,100
  6. 0,200
  7. 0,300
  8. 0,400
  9. 0,500
  10. 0,600
  11. 0,700
  12. 0,800
  13. 0,900
  14. 0,1000
  15. 100,0
  16. 100,100
  17. 100,200
  18. 100,300
  19. 100,400
  20. 100,500
  21. 100,600
  22. 100,700
  23. 100,800
  24. 100,900
  25. 100,1000
  26. 200,0
  27. 200,100
  28. 200,900
  29. 200,1000
  30. 300,0
  31. 300,100
  32. 300,900
  33. 300,1000
  34. 400,0
  35. 400,100
  36. 500,0
  37. 500,100
  38. 600,0
  39. 600,100
  40. 700,0
  41. 700,100
  42. 800,0
  43. 800,100
  44. 900,0
  45. 900,100
  46. 1000,0
  47. 1000,100
  48. 1100,0
  49. 1100,100
  50. 1200,0
  51. 1200,100
  52. 1300,0
  53. 1300,100
  54. 1400,0
  55. 1400,100
  56. 1500,0
  57. 1500,100
  58. 1600,0
  59. 1600,100
  60. 1700,0
  61. 1700,100
  62. 1800,0
  63. 1800,100
  64. 1800,900
  65. 1800,1000
  66. 1900,0
  67. 1900,100
  68. 1900,900
  69. 1900,1000
  70. 2000,0
  71. 2000,100
  72. 2000,200
  73. 2000,300
  74. 2000,400
  75. 2000,500
  76. 2000,600
  77. 2000,700
  78. 2000,800
  79. 2000,900
  80. 2000,1000
  81. 2100,0
  82. 2100,100
  83. 2100,200
  84. 2100,300
  85. 2100,400
  86. 2100,500
  87. 2100,600
  88. 2100,700
  89. 2100,800
  90. 2100,900
  91. 2100,1000
  92. """.trimIndent().lines().mapNotNull { if (it.isBlank()) null else it.split(',').map { it.toInt() } }
  93.  
  94. val inRangeMap = Array<BooleanArray>(roboports.size) { a ->
  95.     BooleanArray(roboports.size) { b ->
  96.         isInRange(roboports[a], roboports[b])
  97.     }
  98. }
  99.  
  100. const val tech = 0 // assumes you have the 5 starter levels
  101. const val speed = 3.0 * (3.4 + 0.65 * tech)
  102. const val range = 1500.0 / (3.0 / speed + 5)
  103.  
  104. fun getDistSq(start: List<Int>, end: List<Int>): Int {
  105.     val dx = start[0] - end[0]
  106.     val dy = start[1] - end[1]
  107.     return dx * dx + dy * dy
  108. }
  109.  
  110. fun isInRange(start: List<Int>, end: List<Int>): Boolean {
  111.     return getDistSq(start, end) <= range * range
  112. }
  113.  
  114. fun getInRange(pos: Int): List<Int> {
  115.     val list = mutableListOf<Int>()
  116.     inRangeMap[pos].forEachIndexed { index, b ->
  117.         if (b) list.add(index)
  118.     }
  119.     return list
  120. }
  121.  
  122. data class PathInfo(val here: Int, val history: MutableList<Int>, val distSq: Int, val curDist: Double) {
  123.     fun makeNext(next: Int, target: Int): PathInfo {
  124.         val newHist = history.toMutableList()
  125.         newHist.add(next)
  126.         return PathInfo(next, newHist, getDistSq(roboports[next], roboports[target]), curDist + sqrt(getDistSq(roboports[here], roboports[next]).toDouble()))
  127.     }
  128.  
  129.     fun getNext(target: Int, seen: List<Int>): List<PathInfo> {
  130.         if (distSq < range * range) return listOf(makeNext(target, target))
  131.         val list = mutableListOf<PathInfo>()
  132.         getInRange(here).forEach { next ->
  133.             if (!seen.contains(next)) list.add(makeNext(next, target))
  134.         }
  135.         return list
  136.     }
  137. }
  138. data class ResultInfo(val list: List<Int>, val dist: Double) {
  139.     companion object {
  140.         fun makeResult(path: PathInfo): ResultInfo {
  141.             return ResultInfo(path.history, path.curDist)
  142.         }
  143.     }
  144. }
  145. fun pathSmart(start: List<Int>, end: List<Int>): ResultInfo {
  146.     // return a list of positions to use before going to the target, INCLUDING start and end
  147.     val endIdx = roboports.indexOf(end)
  148.     val list = mutableListOf(PathInfo(roboports.indexOf(start), mutableListOf(roboports.indexOf(start)), getDistSq(start, end), 0.0))
  149.     var best: ResultInfo? = null
  150.     val seen = mutableListOf(roboports.indexOf(start))
  151.     while (list.isNotEmpty()) {
  152.         val next = list.removeLast()
  153.         if (best != null && next.curDist + sqrt(next.distSq.toDouble()) >= best.dist) continue
  154.  
  155.         val opts = next.getNext(endIdx, seen)
  156.         if (opts.size == 1 && opts[0].distSq == 0) {
  157.             val res = ResultInfo.makeResult(opts[0])
  158.             if (best == null || best.dist > res.dist) {
  159.                 best = res
  160.                 list.removeIf { sqrt(it.distSq.toDouble()) + it.curDist >= best.dist }
  161.             }
  162.         }
  163.         else {
  164.             list.addAll(opts)
  165.             list.sortByDescending { it.distSq }
  166.         }
  167.  
  168.         seen.addAll(opts.map { it.here })
  169.     }
  170.     return best!!
  171. }
  172.  
  173. fun main() {
  174.     var timeDumb = 0L
  175.     var timeSmart = 0L
  176.     var distDumb = 0.0
  177.     var distSmart = 0.0
  178.     var numSearched = 0
  179.     var numSkipped = 0
  180.     println("Speed: $speed")
  181.     println("Range: $range")
  182.     for (a in 0 until roboports.size) {
  183.         for (b in a+1 until roboports.size) {
  184.             val start = System.nanoTime()
  185.             numSearched++
  186.             if (inRangeMap[a][b]) {
  187.                 numSkipped++
  188.                 continue
  189.             }
  190.  
  191.             // dumb: go as far as possible then just go there slowly (not quite how it works)
  192.             val startA = System.nanoTime()
  193.             val dist = sqrt(getDistSq(roboports[a], roboports[b]).toDouble())
  194.             val slowRem = dist - range
  195.             val effectiveDist = range + slowRem * 5 // 20% speed when empty
  196.             distDumb += effectiveDist
  197.             val endA = System.nanoTime()
  198.  
  199.             // smart: pathfind to in-range ports
  200.             val res = pathSmart(roboports[a], roboports[b])
  201.             distSmart += res.dist
  202.             val endB = System.nanoTime()
  203.             timeDumb += endA - start
  204.             timeSmart += endB - start - (endA - startA)
  205.         }
  206.     }
  207.     println("In range: $numSkipped/$numSearched")
  208.     println()
  209.     println("Dumb method: Just continue at 20% speed")
  210.     println("Total time: ${timeDumb}ns")
  211.     println("Total dist: $distDumb")
  212.     println()
  213.     println("Smart method: Pathfind to avoid 20% speed")
  214.     println("Total time: ${timeSmart}ns")
  215.     println("Total dist: $distSmart")
  216.     println()
  217.     println("Extra time: ${(timeSmart-timeDumb).toDouble()/timeDumb*100.0}%")
  218.     println("Saved dist: ${(distDumb-distSmart)/distDumb*100.0}%")
  219. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement