From 41fb7d6db459afe1b9f62ed88d8fd3603b78315c Mon Sep 17 00:00:00 2001 From: Aaron Veden Date: Thu, 8 Jun 2017 22:18:59 -0700 Subject: [PATCH] basic working implemention --- control.lua | 6 +++-- libs/AIAttack.lua | 5 ++-- libs/AIBuilding.lua | 32 +++++++++++++++---------- libs/AIDefense.lua | 4 ++-- libs/BaseProcessor.lua | 2 +- libs/ChunkProcessor.lua | 4 ++-- libs/ChunkUtils.lua | 38 ++++++++++++++++++++++++++--- libs/Constants.lua | 11 +++++---- libs/MapUtils.lua | 17 ++++++++++--- libs/PheromoneUtils.lua | 13 ++++++---- libs/TendrilUtils.lua | 53 ++++++++++++++++++++++++++++++----------- tests.lua | 50 ++++++++++++++++++++++++++------------ 12 files changed, 168 insertions(+), 67 deletions(-) diff --git a/control.lua b/control.lua index 5531898..1a1bed7 100644 --- a/control.lua +++ b/control.lua @@ -261,7 +261,8 @@ local function onDeath(event) if event.force and (event.force.name == "player") and (deathChunk[MOVEMENT_PHEROMONE] < natives.retreatThreshold) then local tick = event.tick - retreatUnits(deathChunk, + retreatUnits(deathChunk, + entityPosition, convertUnitGroupToSquad(natives, entity.unit_group), regionMap, @@ -377,7 +378,8 @@ remote.add_interface("rampantTests", clearBases = tests.clearBases, getOffsetChunk = tests.getOffsetChunk, registeredNest = tests.registeredNest, - colorResourcePoints = tests.colorResourcePoints + colorResourcePoints = tests.colorResourcePoints, + stepAdvanceTendrils = tests.stepAdvanceTendrils } ) diff --git a/libs/AIAttack.lua b/libs/AIAttack.lua index d7a432b..0c0ed4c 100644 --- a/libs/AIAttack.lua +++ b/libs/AIAttack.lua @@ -54,8 +54,9 @@ end local function scoreAttackLocation(squad, neighborChunk, surface) local squadMovementPenalty = lookupSquadMovementPenalty(squad, neighborChunk.cX, neighborChunk.cY) - local r = surface.get_pollution(neighborChunk) + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 50) - return r - squadMovementPenalty - (neighborChunk[NEST_COUNT] * 30) + local r = -- (surface.get_pollution(neighborChunk) * 0.01) + + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 50) + return r - squadMovementPenalty -- - (neighborChunk[NEST_COUNT] * 30) end function aiAttack.squadAttack(regionMap, surface, natives) diff --git a/libs/AIBuilding.lua b/libs/AIBuilding.lua index c47c116..f2aa0b9 100644 --- a/libs/AIBuilding.lua +++ b/libs/AIBuilding.lua @@ -101,20 +101,26 @@ function aiBuilding.formSquads(regionMap, surface, natives, chunk, cost, tempNei surface, false) if squadPath then - local squadPosition = positionFromDirectionAndChunk(squadDirection, chunk, {x=0,y=0}, 0.95) - - local squad = createSquad(squadPosition, surface, natives) - - squad.rabid = math.random() < 0.03 + local squadPosition = positionFromDirectionAndChunk(squadDirection, chunk, {x=0,y=0}, 0.98) - local scaledWaveSize = attackWaveScaling(natives) - local foundUnits = surface.set_multi_command({ command = { type = DEFINES_COMMAND_GROUP, - group = squad.group, - distraction = DEFINES_DISTRACTION_NONE }, - unit_count = scaledWaveSize, - unit_search_distance = TRIPLE_CHUNK_SIZE }) - if (foundUnits > 0) then - natives.points = natives.points - cost + squadPosition = surface.find_non_colliding_position("biter-spawner", + squadPosition, + 32, + 4) + if squadPosition then + local squad = createSquad(squadPosition, surface, natives) + + squad.rabid = math.random() < 0.03 + + local scaledWaveSize = attackWaveScaling(natives) + local foundUnits = surface.set_multi_command({ command = { type = DEFINES_COMMAND_GROUP, + group = squad.group, + distraction = DEFINES_DISTRACTION_NONE }, + unit_count = scaledWaveSize, + unit_search_distance = TRIPLE_CHUNK_SIZE }) + if (foundUnits > 0) then + natives.points = natives.points - cost + end end end end diff --git a/libs/AIDefense.lua b/libs/AIDefense.lua index d225072..1cd96cd 100644 --- a/libs/AIDefense.lua +++ b/libs/AIDefense.lua @@ -51,7 +51,7 @@ local function scoreRetreatLocation(squad, neighborChunk, surface) return safeScore - dangerScore end -function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives, tick) +function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, natives, tick) if (tick - chunk[RETREAT_TRIGGERED] > INTERVAL_LOGIC) and (chunk[NEST_COUNT] == 0) and (chunk[WORM_COUNT] == 0) then local performRetreat = false local enemiesToSquad = nil @@ -77,7 +77,7 @@ function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives, tick) surface, false) if exitPath then - local retreatPosition = positionFromDirectionAndChunk(exitDirection, chunk, {x=0,y=0}, 1.25) + local retreatPosition = positionFromDirectionAndChunk(exitDirection, position, {x=0,y=0}, 0.98) -- in order for units in a group attacking to retreat, we have to create a new group and give the command to join -- to each unit, this is the only way I have found to have snappy mid battle retreats even after 0.14.4 diff --git a/libs/BaseProcessor.lua b/libs/BaseProcessor.lua index 6171093..2618948 100644 --- a/libs/BaseProcessor.lua +++ b/libs/BaseProcessor.lua @@ -29,7 +29,7 @@ function baseProcessor.processBases(regionMap, surface, natives, tick) for index = baseIndex, endIndex do local base = bases[index] - -- buildOrder(regionMap, natives, base, surface, tick) + buildOrder(regionMap, natives, base, surface, tick) advanceTendrils(regionMap, base, surface, tempNeighbors) end diff --git a/libs/ChunkProcessor.lua b/libs/ChunkProcessor.lua index 6de315e..4b14d72 100644 --- a/libs/ChunkProcessor.lua +++ b/libs/ChunkProcessor.lua @@ -50,11 +50,11 @@ function chunkProcessor.processPendingChunks(natives, regionMap, surface, pendin checkChunkPassability(chunk, surface) scoreChunk(regionMap, chunk, surface, natives, tick, query) processQueue[#processQueue+1] = chunk - if (count >= 3500) then + if (count >= 1000) then break end end - if (count >= 3500) and (start > 0) then + if (count >= 1000) and (start > 0) then surface.print("Rampant - " .. (start - count) .. " Remaining chunks to process") end end diff --git a/libs/ChunkUtils.lua b/libs/ChunkUtils.lua index 548ae53..a42ae7d 100644 --- a/libs/ChunkUtils.lua +++ b/libs/ChunkUtils.lua @@ -31,6 +31,8 @@ local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE local CHUNK_TICK = constants.CHUNK_TICK +local PATH_RATING = constants.PATH_RATING + local RETREAT_TRIGGERED = constants.RETREAT_TRIGGERED local RALLY_TRIGGERED = constants.RALLY_TRIGGERED @@ -58,6 +60,18 @@ local function checkForDeadendTiles(constantCoordinate, iteratingCoordinate, dir return false end +local function checkForValidTiles(x, y, get_tile) + local count = 0 + for xi=x,x+31 do + for yi=y,y+31 do + if not get_tile(xi, yi).collides_with("player-layer") then + count = count + 1 + end + end + end + return count / 1024 +end + function chunkUtils.checkChunkPassability(chunk, surface) local x = chunk.x local y = chunk.y @@ -77,9 +91,26 @@ function chunkUtils.checkChunkPassability(chunk, surface) break end end - - chunk[EAST_WEST_PASSABLE] = passableEastWest - chunk[NORTH_SOUTH_PASSABLE] = passableNorthSouth + if passableEastWest or passableNorthSouth then + if (checkForValidTiles(x, y, get_tile) < 0.6) then + passableEastWest = false + passableNorthSouth = false + end + end + + -- if passableEastWest or passableNorthSouth then + -- chunk[PATH_RATING] = checkForValidTiles(x, y, get_tile) + -- end + chunk[PATH_RATING] = checkForValidTiles(x, y, get_tile) + if (chunk[PATH_RATING] < 0.99) then + chunk[EAST_WEST_PASSABLE] = false + chunk[NORTH_SOUTH_PASSABLE] = false + else + chunk[EAST_WEST_PASSABLE] = true + chunk[NORTH_SOUTH_PASSABLE] = true + end + -- chunk[EAST_WEST_PASSABLE] = passableEastWest + -- chunk[NORTH_SOUTH_PASSABLE] = passableNorthSouth end function chunkUtils.scoreChunk(regionMap, chunk, surface, natives, tick, tempQuery) @@ -179,6 +210,7 @@ function chunkUtils.createChunk(topX, topY) chunk[WORM_BASE] = {} chunk[NEST_COUNT] = 0 chunk[WORM_COUNT] = 0 + chunk[PATH_RATING] = 0 return chunk end diff --git a/libs/Constants.lua b/libs/Constants.lua index dee6076..3379103 100644 --- a/libs/Constants.lua +++ b/libs/Constants.lua @@ -97,14 +97,14 @@ constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = 500 constants.DEATH_PHEROMONE_GENERATOR_AMOUNT = 500 constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT = 150 -constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT = -30 +constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT = -1 -- pheromone diffusion amounts constants.MOVEMENT_PHEROMONE_PERSISTANCE = 0.98 constants.BASE_PHEROMONE_PERSISTANCE = 0.99 constants.PLAYER_PHEROMONE_PERSISTANCE = 0.98 -constants.RESOURCE_PHEROMONE_PERSISTANCE = 0.98 +constants.RESOURCE_PHEROMONE_PERSISTANCE = 0.85 -- chunk attributes @@ -126,6 +126,7 @@ constants.NEST_BASE = 12 constants.WORM_BASE = 13 constants.NEST_COUNT = 14 constants.WORM_COUNT = 15 +constants.PATH_RATING = 16 -- Squad status @@ -183,14 +184,14 @@ constants.retreatFilter[constants.SQUAD_RETREATING] = true constants.PATH_FINDER_SHORT_REQUEST_RATIO = 0.8 constants.PATH_FINDER_SHORT_CACHE_SIZE = 25 constants.PATH_FINDER_LONG_REQUEST_RATIO = 5 -constants.PATH_FINDER_MIN_STEPS_TO_CHECK_PATH = 300 +constants.PATH_FINDER_MIN_STEPS_TO_CHECK_PATH = 500 -constants.MAX_FAILED_BEHAVIORS = 6 +constants.MAX_FAILED_BEHAVIORS = 100 constants.UNIT_GROUP_DISOWN_DISTANCE = 10 constants.UNIT_GROUP_TICK_TOLERANCE = 360 -constants.UNIT_GROUP_MAX_RADIUS = 20 +constants.UNIT_GROUP_MAX_RADIUS = 12 constants.UNIT_GROUP_MAX_SPEED_UP = 1.1 constants.UNIT_GROUP_MAX_SLOWDOWN = 1.0 constants.UNIT_GROUP_SLOWDOWN_FACTOR = 0.9 diff --git a/libs/MapUtils.lua b/libs/MapUtils.lua index c499db7..376691c 100644 --- a/libs/MapUtils.lua +++ b/libs/MapUtils.lua @@ -4,6 +4,8 @@ local mapUtils = {} local constants = require("Constants") +local mathUtils = require("MathUtils") + -- constants local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE @@ -13,6 +15,8 @@ local CHUNK_SIZE = constants.CHUNK_SIZE -- imported functions +local gaussianRandomRange = mathUtils.gaussianRandomRange + local mFloor = math.floor -- module code @@ -39,9 +43,9 @@ end --[[ 1 2 3 - \|/ + \|/ 4- -5 - /|\ + /|\ 6 7 8 ]]-- function mapUtils.getNeighborChunks(regionMap, chunkX, chunkY, neighbors) @@ -122,7 +126,7 @@ end --[[ 1 | - 2- -3 + 2- -3 | 4 ]]-- @@ -154,6 +158,13 @@ function mapUtils.positionFromDirectionAndChunkCardinal(direction, startPosition -- return position end +function mapUtils.distortPosition(position) + local xDistort = gaussianRandomRange(1, 0.5, 0, 2) - 1 + local yDistort = gaussianRandomRange(1, 0.5, 0, 2) - 1 + position.x = position.x + (xDistort * 48) + position.y = position.y + (yDistort * 48) +end + function mapUtils.positionFromDirectionAndChunk(direction, startPosition, position, scaling) -- local position = {x=0, y=0} if (direction == 1) then diff --git a/libs/PheromoneUtils.lua b/libs/PheromoneUtils.lua index eea9030..d607d86 100644 --- a/libs/PheromoneUtils.lua +++ b/libs/PheromoneUtils.lua @@ -30,6 +30,8 @@ local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE local NEST_COUNT = constants.NEST_COUNT +local PATH_RATING = constants.PATH_RATING + local IMPASSABLE_TERRAIN_GENERATOR_AMOUNT = constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT -- imported functions @@ -44,7 +46,7 @@ function pheromoneUtils.scents(chunk) chunk[BASE_PHEROMONE] = IMPASSABLE_TERRAIN_GENERATOR_AMOUNT; else chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + chunk[PLAYER_BASE_GENERATOR] - if (chunk[NEST_COUNT] ~= 0) then + if (chunk[NEST_COUNT] == 0) then chunk[RESOURCE_PHEROMONE] = chunk[RESOURCE_PHEROMONE] + chunk[RESOURCE_GENERATOR] end end @@ -78,6 +80,7 @@ function pheromoneUtils.processPheromone(regionMap, chunk, tempNeighbors) local chunkBase = chunk[BASE_PHEROMONE] local chunkPlayer = chunk[PLAYER_PHEROMONE] local chunkResource = chunk[RESOURCE_PHEROMONE] + local chunkPathRating = chunk[PATH_RATING] local totalMovement = 0 local totalBase = 0 @@ -93,10 +96,10 @@ function pheromoneUtils.processPheromone(regionMap, chunk, tempNeighbors) totalResource = totalResource + (neighborChunk[RESOURCE_PHEROMONE] - chunkResource) end end - chunk[MOVEMENT_PHEROMONE] = (chunkMovement + (0.125 * totalMovement)) * MOVEMENT_PHEROMONE_PERSISTANCE - chunk[BASE_PHEROMONE] = (chunkBase + (0.25 * totalBase)) * BASE_PHEROMONE_PERSISTANCE - chunk[PLAYER_PHEROMONE] = (chunkPlayer + (0.25 * totalPlayer)) * PLAYER_PHEROMONE_PERSISTANCE - chunk[RESOURCE_PHEROMONE] = (chunkResource + (0.25 * totalResource)) * RESOURCE_PHEROMONE_PERSISTANCE + chunk[MOVEMENT_PHEROMONE] = (chunkMovement + (0.125 * totalMovement)) * MOVEMENT_PHEROMONE_PERSISTANCE * chunkPathRating + chunk[BASE_PHEROMONE] = (chunkBase + (0.25 * totalBase)) * BASE_PHEROMONE_PERSISTANCE * chunkPathRating + chunk[PLAYER_PHEROMONE] = (chunkPlayer + (0.25 * totalPlayer)) * PLAYER_PHEROMONE_PERSISTANCE * chunkPathRating + chunk[RESOURCE_PHEROMONE] = (chunkResource + (0.25 * totalResource)) * RESOURCE_PHEROMONE_PERSISTANCE * chunkPathRating end return pheromoneUtils diff --git a/libs/TendrilUtils.lua b/libs/TendrilUtils.lua index 4e615ea..cd01257 100644 --- a/libs/TendrilUtils.lua +++ b/libs/TendrilUtils.lua @@ -27,6 +27,8 @@ local registerEnemyBaseStructure = baseRegisterUtils.registerEnemyBaseStructure local canMoveChunkDirection = mapUtils.canMoveChunkDirection +local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed + -- module code local function scoreTendrilChunk(squad, chunk, surface) @@ -37,6 +39,25 @@ local function validTendrilChunk(x, chunk, neighborChunk) return canMoveChunkDirection(x, chunk, neighborChunk) end +-- local function colorChunk(x, y, tileType, surface) +-- local tiles = {} +-- for xi=x+5, x + 27 do +-- for yi=y+5, y + 27 do +-- tiles[#tiles+1] = {name=tileType, position={xi, yi}} +-- end +-- end +-- surface.set_tiles(tiles, false) +-- end + +local function removeTendril(base, tendril) + for i=1,#base.tendrils do + if (base.tendrils[i] == tendril) then + table.remove(base.tendrils,i) + break + end + end +end + local function buildTendrilPath(regionMap, tendril, surface, base, tempNeighbors) local chunk = getChunkByPosition(regionMap, tendril.x, tendril.y) if chunk then @@ -51,25 +72,29 @@ local function buildTendrilPath(regionMap, tendril, surface, base, tempNeighbors surface, true) if (tendrilDirection == -1) then - tendril.path[#tendril.path] = chunk - local biterSpawner = {name="spitter-spawner", position={x=chunk.x,y=chunk.y}} - local hive = surface.create_entity(biterSpawner) - registerEnemyBaseStructure(regionMap, hive, base) - for i=1,#base.tendrils do - if (base.tendrils[i] == tendril) then - table.remove(base.tendrils,i) - break - end - end + removeTendril(base, tendril) tendrilUtils.buildTendril(regionMap, nil, base, surface, tick) + -- colorChunk(chunk.x, chunk.y, "hazard-concrete-left", surface) return elseif tendrilPath then - positionFromDirectionAndChunk(tendrilDirection, chunk, tendril, 0.95) + positionFromDirectionAndChunk(tendrilDirection, tendril, tendril, 0.5) + mapUtils.distortPosition(tendril) tendril.path[#tendril.path] = chunk - local biterSpawner = {name="spitter-spawner", position={x=tendril.x,y=tendril.y}} - local hive = surface.create_entity(biterSpawner) - registerEnemyBaseStructure(regionMap, hive, base) + local position = surface.find_non_colliding_position("spitter-spawner", + {x=tendril.x,y=tendril.y}, + 32, + 4) + if position and (tendrilPath[NEST_COUNT] <= 3)then + tendril.x = position.x + tendril.y = position.y + local biterSpawner = {name="spitter-spawner", position=position} + local hive = surface.create_entity(biterSpawner) + registerEnemyBaseStructure(regionMap, hive, base) + elseif not position then + removeTendril(base, tendril) + end end + -- colorChunk(chunk.x, chunk.y, "concrete", surface) end end diff --git a/tests.lua b/tests.lua index 30e3f59..edd3722 100644 --- a/tests.lua +++ b/tests.lua @@ -5,17 +5,22 @@ local mathUtils = require("libs/MathUtils") local chunkUtils = require("libs/ChunkUtils") local mapUtils = require("libs/MapUtils") local baseUtils = require("libs/BaseUtils") +local baseRegisterUtils = require("libs/BaseRegisterUtils") +local tendrilUtils = require("libs/TendrilUtils") -function tests.pheromoneLevels() +function tests.pheromoneLevels(size) local player = game.player.character local playerChunkX = math.floor(player.position.x / 32) local playerChunkY = math.floor(player.position.y / 32) + if not size then + size = 3 + end print("------") print(#global.regionMap.processQueue) print(playerChunkX .. ", " .. playerChunkY) print("--") - for x=playerChunkX-9, playerChunkX+9 do - for y=playerChunkY-9, playerChunkY+9 do + for y=playerChunkY-size, playerChunkY+size do + for x=playerChunkX-size, playerChunkX+size do if (global.regionMap[x] ~= nil) then local chunk = global.regionMap[x][y] if (chunk ~= nil) then @@ -25,15 +30,18 @@ function tests.pheromoneLevels() end str = str .. " " .. "p/" .. game.surfaces[1].get_pollution(chunk) if (chunk.cX == playerChunkX) and (chunk.cY == playerChunkY) then - print("*", chunk.cX, chunk.cY, str) + print("=============") + print(chunk.cX, chunk.cY, str) + print("=============") else print(chunk.cX, chunk.cY, str) end -- print(str) - print("-") + print("----") end end end + print("------------------") end end @@ -113,9 +121,9 @@ end function tests.registeredNest(x) local entity = tests.createEnemy(x) - baseUtils.registerEnemyBaseStructure(global.regionMap, - entity, - nil) + baseRegisterUtils.registerEnemyBaseStructure(global.regionMap, + entity, + nil) end function tests.attackOrigin() @@ -140,7 +148,7 @@ function tests.gaussianRandomTest() result[x] = 0 end for _=1,10000 do - local s = mathUtils.roundToNearest(mathUtils.gaussianRandomRange(10, 17, 0, 100), 1) + local s = mathUtils.roundToNearest(mathUtils.gaussianRandomRange(50, 25, 0, 100), 1) result[s] = result[s] + 1 end for x=0,100,1 do @@ -161,6 +169,7 @@ function tests.baseStats() local nestCount = 0 local wormCount = 0 local eggCount = 0 + local hiveCount = 0 for _,_ in pairs(base.nests) do nestCount = nestCount + 1 end @@ -170,7 +179,12 @@ function tests.baseStats() for _,_ in pairs(base.eggs) do eggCount = eggCount + 1 end - print(base.x, base.y, base.x * 32, base.y * 32, base.created, base.alignment, base.strength, base.upgradePoints, nestCount, wormCount, eggCount, base.hive) + for _,_ in pairs(base.hives) do + hiveCount = hiveCount + 1 + end + print(base.x, base.y, base.created, base.alignment, base.strength, base.upgradePoints, nestCount, wormCount, eggCount, hiveCount) + print(serpent.dump(base.tendrils)) + print("---") end end @@ -232,9 +246,9 @@ function tests.colorResourcePoints() local chunks = global.regionMap.processQueue for i=1,#chunks do local chunk = chunks[i] - local color = "deepwater-green" + local color = "concrete" if (chunk[constants.RESOURCE_GENERATOR] ~= 0) and (chunk[constants.NEST_COUNT] ~= 0) then - color = "water" + color = "hazard-concrete-left" elseif (chunk[constants.RESOURCE_GENERATOR] ~= 0) then color = "deepwater" elseif (chunk[constants.NEST_COUNT] ~= 0) then @@ -253,15 +267,21 @@ function tests.showMovementGrid() local chunks = global.regionMap.processQueue for i=1,#chunks do local chunk = chunks[i] - local color = "deepwater-green" + local color = "concrete" if (chunk[constants.NORTH_SOUTH_PASSABLE] and chunk[constants.EAST_WEST_PASSABLE]) then - color = "water" + color = "hazard-concrete-left" elseif chunk[constants.NORTH_SOUTH_PASSABLE] then color = "deepwater" elseif chunk[constants.EAST_WEST_PASSABLE] then color = "water-green" end - chunkUtils.colorChunk(chunk.pX, chunk.pY, color, game.surfaces[1]) + chunkUtils.colorChunk(chunk.x, chunk.y, color, game.surfaces[1]) + end +end + +function tests.stepAdvanceTendrils() + for _, base in pairs(global.natives.bases) do + tendrilUtils.advanceTendrils(global.regionMap, base, game.surfaces[1], {nil,nil,nil,nil,nil,nil,nil,nil}) end end