adaptive-ai/population.lua

254 lines
6.6 KiB
Lua

local chat_log = adaptive_ai.chat_log
local breeding = adaptive_ai.breeding
local random = math.random
local floor = math.floor
local pop = adaptive_ai.helper.pop
local load_file = adaptive_ai.helper.load_file
local default_size = 10
local default_range = 20
local timer = 0
local dirty = false
population = {}
tribes = {}
populs = {}
census = {}
--local lfs = require "lfs"
--local mkdir = minetest.mkdir or lfs.mkdir
local mkdir = minetest.mkdir or function(path)
os.execute("mkdir \"" .. path .. "\"")
end
local path = adaptive_ai.path.."population_"
local file_tag = {"tribe_list", "census"}
local function save_census(save)
local file, to_file, count, gene_copy
count = 0
for _,c in pairs(census) do
count = count + 1
gene_copy = c.genes
c.genes = nil
to_file = (minetest.serialize(c))
file = io.open(path..file_tag[2].."\\"..c.name..".txt", "w")
if not file then
mkdir(path..file_tag[2])
file = io.open(path..file_tag[2].."\\"..c.name..".txt", "w")
end
file:write(save == false and "" or to_file)
file:close()
c.genes = gene_copy
to_file = (minetest.serialize(gene_copy))
file = io.open(path..file_tag[2].."\\"..c.name.." genes.txt", "w")
file:write(save == false and "" or to_file)
file:close()
end
chat_log("Census: "..count)
end
local function get_from_census(entity)
if not entity.nametag then return nil end
local name = entity.nametag--:gsub("%s", "_")
local from_file = load_file(path..file_tag[2].."\\"..name..".txt")
local genes_file = load_file(path..file_tag[2].."\\"..name.." genes.txt")
local creature = from_file or nil
if creature then
creature.genes = genes_file
table.insert(census, creature)
local t_id = creature.tribe_id
if not tribes[t_id] then
local tribe = {}
tribe.pos = creature.pos
tribe.name = entity.name
tribe.range = default_range
tribe.size = default_size
tribe.id = t_id
tribes[t_id] = tribe
chat_log("Created tribe #"..t_id)
end
if not populs[t_id] then
populs[t_id] = {creature}
chat_log("Created popul #"..t_id)
else
table.insert(populs[t_id], creature)
chat_log("Increased popul #"..t_id)
end
end
return creature
end
local function save_to_file(save)
local file = io.open(path..file_tag[1]..".txt", "w")
local to_file = (minetest.serialize(tribes))
file:write(to_file)
file:close()
save_census(save)
timer = 0
dirty = false
end
local function load_tribes()
local from_file = load_file(path..file_tag[1]..".txt")--, true)
tribes = from_file or {}
--error(#tribes > 0 and "Tribes loaded succesfully" or "Tribes not loaded")
--error(#census > 0 and "Census loaded succesfully" or "Census not loaded")
end
local function add_to_census(creature)
local c_name, c_tag, disambiguate = creature.name, creature.tag, 1
while census[creature.name] ~= nil do
creature.name = c_name.." "..disambiguate
disambiguate = disambiguate + 1
end
census[creature.name] = creature
chat_log("New censused creature: "..creature.name)
end
local function fill_tribe(tribe, popul)
local breed, asexual = breeding[tribe.name].breed, breeding[tribe.name].asexual
local pos, t_id, range = tribe.pos, tribe.id, tribe.range
--math.randomseed(os.time())
local creature, p, i, j
while #popul < tribe.size do
p = {x=floor(pos.x+0.5), y=floor(pos.y+1), z=floor(pos.z+0.5)}
p.x = p.x + random(0,range) - floor(range/2 + 0.5)
p.z = p.z + random(0,range) - floor(range/2 + 0.5)
i = random(#popul)
if asexual then
creature = {}
creature = breed(creature, popul[i])
else
repeat
j = random(#popul)
until i ~= j
creature = {}
creature = breed(creature, popul[i], popul[j])
end
creature.pos = p
creature.tribe_id = t_id
--chat_log("Created "..creature.name)
table.insert(popul, creature)
add_to_census(creature)
end
populs[t_id] = popul
end
local function create_tribe(pos, name, founders, range, clone, size)
if not founders or #founders == 0 then
error("Not enough creatures in starting population.")
end
local tribe = {}
tribe.pos = pos
tribe.name = name
tribe.range = range
tribe.size = size or default_size
tribe.id = #tribes + 1
local popul = {}
local p, f
for _,father in ipairs(founders) do
f = {}
f = clone(father, f)
--chat_log("Cloned "..f.name)
f.tribe_id = tribe.id
p = {x=floor(pos.x+0.5), y=floor(pos.y+0.5), z=floor(pos.z+0.5)}
p.x = p.x + random(0,range) - floor(range/2 + 0.5)
p.z = p.z + random(0,range) - floor(range/2 + 0.5)
f.pos = p
table.insert(popul, f)
add_to_census(f)
end
fill_tribe(tribe, popul)
table.insert(tribes, tribe)
save_to_file()
return popul
end
local function get_tribe(t_id)
--chat_log(tribes[t_id] and "Getting tribe" or "Not getting tribe")
return tribes[t_id]
end
local function get_popul_size(t_id)
return populs[t_id] and #populs[t_id] or nil
end
local function get_couple(creature)
local p = populs[creature.tribe_id]
local i
repeat
i = random(#p)
until p[i].name ~= creature.name
return p[i]
end
local function empty()
for i,t in ipairs(tribes) do
t = {}
end
for i,c in ipairs(populs) do
c.delete = true
end
tribes = {}
census = {}
save_census(false)
save_to_file()
end
local function add_to_tribe(t_id, creature)
creature.tribe_id = t_id
table.insert(populs[t_id], creature)
census[creature.name] = creature
dirty = true
end
minetest.register_globalstep(function(dtime)
timer = timer + dtime;
if timer >= 30 and dirty then
save_to_file()
end
end)
minetest.register_on_shutdown(function()
adaptive_ai.population.save_to_file()
end)
population.tribes = tribes
population.load_tribes = load_tribes
population.create_tribe = create_tribe
population.get_from_census = get_from_census
population.add_to_tribe = add_to_tribe
population.empty = empty
population.get_couple = get_couple
population.default_size = default_size
population.default_range = default_range
population.save_to_file = save_to_file
population.get_tribe = get_tribe
population.get_popul_size = get_popul_size
adaptive_ai.population = population