Still some work to go on simulation. Writing about 5-10 lines of code / day as I have lots of other (irl) work to do. If anyone is interested in helping out, would be great.
Here's the code so far. 99% of the effort is in simulating factorio feeding/crafting in order to get proper fitness evaluation. Some work needs to be done in the mating/cross over alg to ideal subsequences from parents, but I don't imagine that will be that hard.
--
Code: Select all
import random
ASSEMBLER=0
IRON=1
STONE=2
COPPER=3
COIL=4
GEAR=5
GS=6
FURNACE=7
MINER=8
COAL=9
IRON_MFP=0
STONE_M=1
COAL_M=2
COPPER_MFP=3
GEAR_ASM=4
FURNACE_ASM=5
MINER_ASM=6
COIL_ASM=7
GS_ASM=8
AS_ASM=9
CRAFT=0
PLACE=1
FEED_Z=2 #Z drop
FEED_HALF=3 #right click
FEED_FULL=4 #left click
GRAB=5 #left click
def toAction(action):
if action==CRAFT:
return 'CRAFT'
elif action==PLACE:
return 'PLACE'
elif action==FEED_Z:
return 'FEED_Z'
elif action==FEED_HALF:
return 'FEED_HALF'
elif action==FEED_FULL:
return 'FEED_FULL'
elif action==GRAB:
return 'GRAB'
def toAct_on(action, act_on):
if action==CRAFT:
if act_on==ASSEMBLER:
return 'ASSEMBLER'
elif act_on==GEAR:
return 'GEAR'
elif act_on==COIL:
return 'COIL'
elif act_on==GS:
return 'GS'
elif act_on==FURNACE:
return 'FURNACE'
elif act_on==MINER:
return 'MINER'
else:
if act_on==IRON_MFP:
return 'IRON_MFP'
elif act_on==STONE_M:
return 'STONE_M'
elif act_on==COAL_M:
return 'COAL_M'
elif act_on==COPPER_MFP:
return 'COPPER_MFP'
elif act_on==GEAR_ASM:
return 'GEAR_ASM'
elif act_on==FURNACE_ASM:
return 'FURNACE_ASM'
elif act_on==MINER_ASM:
return 'MINER_ASM'
elif act_on==COIL_ASM:
return 'COIL_ASM'
elif act_on==GS_ASM:
return 'GS_ASM'
elif act_on==AS_ASM:
return 'AS_ASM'
INGREDIENTS={
#resource:[components,time,output,craftedin]
#components is [(resource,amount),..]
ASSEMBLER:[[(IRON,9),(GEAR,5),(GS,3)],1,1,[],50],
IRON:[[(COAL,1/6)],3,1,[], 100],
STONE:[[(COAL,1/6)],3,1,[], 50],
COPPER:[[(COAL,1/6)],3,1,[], 100],
GEAR:[[(IRON,2)],1,1,[], 100],
COIL:[[(COPPER,1)],1,2,[], 200],
GS:[[(IRON,1),(COIL,3)],1,1,[]], 200],
FURNACE:[[(STONE,5)],1,1,[], 50],
MINER:[[(IRON,3),(GEAR,3),(FURNACE,1)],4,1,[], 50],
COAL:[[],3,1,[], 50]
}
s
ENTITIES={
IRON_MFP:{'prod':IRON, 'requires':[MINER, FURNACE]},
STONE_M:{'prod':STONE,'requires':[FURNACE]},
COAL_M:{'prod':COAL, 'requires':[FURNACE]},
COPPER_MFP:{ 'prod':COPPER,'requires':[MINER, FURNACE]},
GEAR_ASM:{ 'prod':GEAR, 'requires':[ASSEMBLER]},
FURNACE_ASM:{ 'prod':FURNACE, 'requires':[ASSEMBLER]},
MINER_ASM:{ 'prod':MINER,'requires':[ASSEMBLER]},
COIL_ASM:{'prod':COIL,'requires':[ASSEMBLER]},
GS_ASM:{'prod':GS,'requires':[ASSEMBLER]},
AS_ASM:{'prod':ASSEMBLER,'requires':[ASSEMBLER]}
}
def check_rules(rules, ruled_on):
return True
def got_rule(res):
#check current rule to see if res has been crafted or grabbed
return True
CRAFTABLES=[GEAR, COIL, GS, FURNACE, MINER, ASSEMBLER]
PLACEABLES=list(ENTITIES.keys())
FEEDABLES=PLACEABLES
#(craft, acton) (will craft as much as possible)
#(place, acton) (wil place as much as possible)
#(feed, acton, %) (will feed up to % or as much as possible)
#(grab, acton) (will grab as much as possible)
TW=1 #time window 1 second
CRLPS=5 #(default 5 per second)
PRLPS=5 #placing 5 per second
FRLPS=5 #feeding 5 person
GRLPS=5 #grabbing 5 per second
craft_queue=[]
placed={}
def reset():
_=[inv_count[x]=0 for x in INGREDIENTS.keys()]
def has_entity(entity):
return True
def has_ingredients(ingredient):
return True
def remove_ingredients(ingredient):
return True
def remove_entity(entity):
return True
def none():
return None
def rng_perc():
return (int(random.random()*4)+1)*.25
def craft_act(act_on):
ing = INGREDIENTS[act_on]
for _ in range(0, TW * CRLPS):
if has_ingredients(ing):
craft_queue.append((ing, ing[1]))
remove_ingredients(ing)
else:
break
return True
def place_act(act_on):
ent = ENTITIES[act_on]
entities = get_entities(act_on)
count = TW * PRLPS
count = remove_entity_from_inv(count)
if entities == None:
entities={"count": 0}
entities['count'] = entities['count']+count
placed[act_on]=entities
def get_entities(act_on)
if act_on in placed.keys():
return placed['act_on']
else:
return None
def get_ingredient(entities):
ings=entities['ingredients']
ings.sort(key=lambda x:x[1]) #asc by default
for x in ings:
if has_inv(x[0]):
return x
#get entities act_on
#get ingredient counts
#sort by ingredient counts asc
#loop through ingredients
#if ingredient in inventory
# use that ingredient
return None,None#entities, ingredient
def feed_entities(entities, incredient, amount)
#increase entities ssby FRPL*TW*amount if in inventory
#decrease inventory
def feed_z_act(act_on):
entities = get_entities(act_on)
ingredient = get_ingredient(entities)
feed_entities(entities, ingredient, 1)
#loop FRPLS*t
# add one to entitie
# remove 1 from inventory
return True
def feed_half_act(act_on):
entities = get_entities(act_on)
ingredient = get_ingredient(entities)
feed_entities(entities, ingredient, ingredient[4]/2)
return True
def feed_full_act(act_on):
entities = get_entities(act_on)
ingredient = get_ingredient(entities)
feed_entities(entities, ingredient, ingredient[4])
return True
def grab_act(act_on):
entities = get_entities(act_on)
#loop on GRPPLS
#remove from entity
#add to inventory
return True
def inc_inventory(ing, amt):
inv[ing]=inv[ing]+amt
def process_craft_queue(tick):
time_used=0
time_left=tick
while True
if len(craft_queue)==0:
return
top=craft_queue[0]
if top[1] > time_left:
top[1]=top[1]-time_left
return
inc_inventory(top[0], top[2])
del(craft_queue(0))
time_left=time_left-top[1]
def process_entity_crafting():
return True
def process_tick(tick):
process_craft_queue(tick)
process_entity_crafting(tick)
ACTIONS={
CRAFT:{'acton':CRAFTABLES, 'params':none, 'act':craft_act,'rules':{}},
PLACE:{'acton':PLACEABLES, 'params':none, 'act':place_act,'rules':{}},
FEED_Z:{'acton':FEEDABLES, 'params':rng_perc, 'act': feed_z_act,'rules':{}},
FEED_HALF:{'acton':FEEDABLES,'params':rng_perc, 'act':feed_half_act,'rules':{}},
FEED_FULL:{'acton':FEEDABLES,'params':rng_perc, 'act':feed_full_act,'rules':{}},
GRAB:{'acton':FEEDABLES,'params':none, 'act':grab_act,'rules':{}},
}
for craftable in CRAFTABLES:
ACTIONS[CRAFT]['rules'][craftable]=[(got_rule, INGREDIENTS[craftable][0])]
for placeable in PLACEABLES:
ACTIONS[PLACE]['rules'][placeable]=[(got_rule, ENTITIES[placeable]['requires'])]
for x in ENTITIES.keys():
INGREDIENTS[ENTITIES[x]['prod']][3].append(x)
def gen_random_build_step(curl_rules, ruled):
#return random action,
action=None
act_on=None
for _ in range(0,1000):
action_key=list(ACTIONS.keys())[int(len(ACTIONS)*random.random())]
action=ACTIONS[action_key]
act_ons=action['acton']
act_on=act_ons[int(len(act_ons)*random.random())]
rules = action['rules']
if act_on in rules.keys() and check_rules(rules[act_on], ruled) == False:
continue
else:
break
return (action_key, act_on, action['params']())
def to_string(rule):
return toAction(rule[0])+":"+toAct_on(rule[0], rule[1])+":"+str(rule[2])
for i in range(0,100):
print(to_string(gen_random_build_step(None,None)))