We have very similar goals. My head spins from trying to pick strategies but at least I want it to be good at the placement and naval-micro levels.
I've spent the last week getting ROFLBot to pick a good starting space based on the following criteria:
- find the city that i have that is closest to the other cities I have (i.e. the most neighboring cities, where distance to neighbor is between 4 and 10.
- start there.
- now determine a location starting here that is at least 20 units away from an enemy's border (note if it's foreign land (or water) but not enemy-run, it's ok)
This part works pretty well. I can pick a starting point near the top of russia (and even kind of guarding cities) even with Europe, Africa, Asia all as enemies, without being in any of their radar ranges.
...
- this becomes the starting point for starting to drop down silos.
- i am trying to read your note on the logic for placing silos where distance > 1.8 from any own city but haven't grasped it all yet. It's my next step.
Obviously dropping Radars should come earlier in the order.
I'm sharing the code with you (especially my DrawRadiatingSpokes), in case any of it interests you.
Code: Select all
function OnFirstTick()
StartLongTask(function()
-- Put Cities and Territories in Tables
myCities ={}
enemyCities = {}
enemyTerritories = ""
local allCities = GetCityIDs()
local us = GetOwnTeamID()
for i, city in next, allCities do
if city:GetTeamID() == us then
table.insert(myCities, city)
myTerritoryName = GetTerritoryName(city:GetLongitude(), city:GetLatitude() )
YieldLongTask()
else
table.insert(enemyCities, city)
-- SendChat(GetTerritoryName(city:GetLongitude(), city:GetLatitude() ) .. " - " .. city:GetLongitude() .. " - " .. city:GetLatitude() )
enemyTerritories = enemyTerritories .. GetTerritoryName(city:GetLongitude(), city:GetLatitude() )
YieldLongTask()
end
end
YieldLongTask()
-- List out the Enemy Territories
SendChat(enemyTerritories)
-- find the 4 cities that are most connected to other cities (city that has the most close neighbors)
myMostConnectedCities ={}
local runningcounter = 0
local keycitylong = 0
local keycitylat = 0
local connecteddistance = math.random(4,10)
for i, city in ipairs(myCities) do
counter = 0
DrawWhiteboardCross(myCities[i]:GetLongitude(), myCities[i]:GetLatitude(), 0.5)
YieldLongTask()
for j, city in ipairs(myCities) do
if GetRealDistance(myCities[i]:GetLongitude(), myCities[i]:GetLatitude(), myCities[j]:GetLongitude(), myCities[j]:GetLatitude() ) < connecteddistance then
WhiteboardDraw(myCities[i]:GetLongitude(), myCities[i]:GetLatitude(), myCities[j]:GetLongitude(), myCities[j]:GetLatitude())
counter = counter + 1
end
end
table.insert(myMostConnectedCities, thiscounter)
-- SendChat(i .. "-" .. counter)
if counter > runningcounter then
runningcounter = counter
keycitylong = myCities[i]:GetLongitude()
keycitylat = myCities[i]:GetLatitude()
keycity = i
end
YieldLongTask()
end
-- show the 1 most connected city
SendChat("Key City - " .. keycity .. " - " .. keycitylong .. " - " .. keycitylat )
-- find a starting location for silos that isnt within 20 distance units from enemy territory
keycitylat = keycitylat + 1.8
dx = 0
dy = 0
tooclosetoenemyradar = true
repeat
SendChat("Start at " .. dx .. " - " .. dy)
DrawRadiatingSpokes(keycitylong , keycitylat , 21.8)
-- DrawRadiatingSpokes(keycitylong , keycitylat , 20)
YieldLongTask()
keycitylong = keycitylong - dx /12
keycitylat = keycitylong - dy/12
until tooclosetoenemyradar == false
SendChat("ok")
SendChat("Erasing Whiteboard")
WhiteboardClear ()
-- where we are at is close to our cities and far from enemry radar
-- so start trying to place silos
silos = {}
SendChat(keycitylong .. " - " .. keycitylat)
if IsValidPlacementLocation (keycitylong, keycitylat, "Silo") then
PlaceStructure (keycitylong, keycitylat, "Silo")
end
YieldLongTask()
end)
-- loop to output Defcon Level as it changes
local DefconLevel
StartLongTask(function()
repeat
local Level = GetDefconLevel()
if Level ~= DefconLevel then
-- SendChat(("it's DEFCON %i already!"):format(Level), "public")
DefconLevel = Level
end
YieldLongTask()
YieldLongTask()
YieldLongTask()
YieldLongTask()
until Level == 1
SendChat("Prepare to feel the wrath of my nuclear weaponry!", "public")
end)
end
function OnTickReal()
WorkOnLongTasks()
if GetGameTick() % 60 == 0 then
-- SendChat("Tick" .. GetGameTick())
end
end
function OnEvent(eventType, sourceID, targetID, unitType, longitude, latitude)
print(eventType, ",", tostring(sourceID), ",", tostring(targetID), ",", unitType, (", %.3f , %.3f"):format(longitude, latitude))
end
function OnShutdown()
end
-- Redefine print to write to the alliance chat channel
function print(...)
local args = {...}
local n = select('#', ...)
local tostring = tostring
local txt = {}
for i = 1, n do
if i ~= 1 then
txt[#txt + 1] = " "
end
txt[#txt + 1] = tostring(args[i])
end
SendChat(table.concat(txt), "alliance")
end
-- Simple coroutine management functions
local co, pairs, assert = coroutine, pairs, assert
local long_tasks_in_progress = {}
function StartLongTask(f)
long_tasks_in_progress[co.create(f)] = true
end
function WorkOnLongTasks(...)
for c in pairs(long_tasks_in_progress) do
if co.status(c) == "dead" then
long_tasks_in_progress[c] = nil
else
assert(co.resume(c, ...))
end
end
end
YieldLongTask = co.yield
-- Extra whiteboard functions
function DrawWhiteboardCross(x, y, size)
WhiteboardDraw(x - size, y - size, x + size, y + size)
WhiteboardDraw(x - size, y + size, x + size, y - size)
end
function DrawWhiteboardSquare(x, y, size)
WhiteboardDraw(x - size, y - size, x + size, y - size)
WhiteboardDraw(x + size, y - size, x + size, y + size)
WhiteboardDraw(x + size, y + size, x - size, y + size)
WhiteboardDraw(x - size, y + size, x - size, y - size)
end
function DrawBadWhiteboardCircle(x, y, radius)
local mrandom, msin, mcos, pi = math.random, math.sin, math.cos, math.pi
local segments = mrandom(7, 14)
local theta_step = pi * 2 / segments
local sin, cos = msin(theta_step), mcos(theta_step)
local irot = mrandom() * 2 * pi
local dx = mcos(irot) * radius
local dy = msin(irot) * radius
for i = 1, segments + mrandom(2, segments - 2) do
local nx = cos * dx - sin * dy + mrandom(-2, 2) / 10
local ny = sin * dx + cos * dy + mrandom(-2, 2) / 10
WhiteboardDraw(x + dx, y + dy, x + nx, y + ny)
dx, dy = nx, ny
end
end
function DrawGoodWhiteboardCircle(x, y, radius)
local segments = 20
local theta_step = math.pi * 2 / segments
local sin, cos = math.sin(theta_step), math.cos(theta_step)
local dx = radius
local dy = 0
for i = 1, segments do
local nx = cos * dx - sin * dy
local ny = sin * dx + cos * dy
WhiteboardDraw(x + dx, y + dy, x + nx, y + ny)
dx, dy = nx, ny
end
end
function GetRealDistance(x1,y1,x2,y2)
dist = math.sqrt((x2-x1)^2 + (y2-y1)^2)
return dist
end
-- find if position is too close to enemy
function DrawRadiatingSpokes(x, y, radius)
DrawWhiteboardSquare(x,y,5)
tooclosetoenemyradar = false
-- local segments = 24
local segments = 40
local theta_step = math.pi * 2 / segments
local sin, cos = math.sin(theta_step), math.cos(theta_step)
dx = radius
dy = 0
for i = 1, segments do
local nx = cos * dx - sin * dy
local ny = sin * dx + cos * dy
WhiteboardDraw(x,y ,x + dx, y + dy)
if GetTerritoryName(x + dx, y + dy) ~= nil and GetTerritoryName(x + dx, y + dy) ~= myTerritoryName then
if string.find(enemyTerritories, GetTerritoryName(x + dx, y + dy) ) ~= nil then
tooclosetoenemyradar = true
-- SendChat("... too close to " .. GetTerritoryName(x + dx, y + dy) .. " - dx = " .. dx .. " and dy = " .. dy)
return tooclosetoenemyradar, dx, dy
end
end
dx, dy = nx, ny
end
-- return tooclosetoenemyradar, dx, dy
end