Factorio: add Funnel tech shape

This commit is contained in:
Fabian Dill 2021-04-11 18:19:47 +02:00
parent 9aef76767a
commit 4292cdddd5
7 changed files with 110 additions and 75 deletions

View File

@ -538,6 +538,12 @@ def roll_settings(weights: dict, plando_options: typing.Set[str] = frozenset(("b
setattr(ret, option_name, option.from_any(get_choice(option_name, weights))) setattr(ret, option_name, option.from_any(get_choice(option_name, weights)))
else: else:
setattr(ret, option_name, option.from_any(option.default)) setattr(ret, option_name, option.from_any(option.default))
elif ret.game == "Minecraft":
for option_name, option in Options.minecraft_options.items():
if option_name in weights:
setattr(ret, option_name, option.from_any(get_choice(option_name, weights)))
else:
setattr(ret, option_name, option.from_any(option.default))
else: else:
raise Exception(f"Unsupported game {ret.game}") raise Exception(f"Unsupported game {ret.game}")
return ret return ret

View File

@ -236,7 +236,7 @@ hollow_knight_skip_options: typing.Dict[str, type(Option)] = {
"SHADESKIPS": Toggle, "SHADESKIPS": Toggle,
} }
hollow_knight_options: typing.Dict[str, Option] = {**hollow_knight_randomize_options, **hollow_knight_skip_options} hollow_knight_options: typing.Dict[str, type(Option)] = {**hollow_knight_randomize_options, **hollow_knight_skip_options}
class MaxSciencePack(Choice): class MaxSciencePack(Choice):
@ -276,6 +276,7 @@ class TechTreeLayout(Choice):
option_small_diamonds = 1 option_small_diamonds = 1
option_medium_diamonds = 2 option_medium_diamonds = 2
option_pyramid = 3 option_pyramid = 3
option_funnel = 4
default = 0 default = 0
class Visibility(Choice): class Visibility(Choice):
@ -289,6 +290,8 @@ factorio_options: typing.Dict[str, type(Option)] = {"max_science_pack": MaxScien
"free_samples": FreeSamples, "free_samples": FreeSamples,
"visibility": Visibility} "visibility": Visibility}
minecraft_options: typing.Dict[str, type(Option)] = {}
if __name__ == "__main__": if __name__ == "__main__":
import argparse import argparse

View File

@ -27,6 +27,7 @@ game:
A Link to the Past: 1 A Link to the Past: 1
Hollow Knight: 1 Hollow Knight: 1
Factorio: 1 Factorio: 1
Minecraft: 1
# Shared Options supported by all games: # Shared Options supported by all games:
accessibility: accessibility:
items: 0 # Guarantees you will be able to acquire all items, but you may not be able to access all locations items: 0 # Guarantees you will be able to acquire all items, but you may not be able to access all locations
@ -41,6 +42,7 @@ tech_tree_layout:
small_diamonds: 1 small_diamonds: 1
medium_diamonds: 1 medium_diamonds: 1
pyramid: 1 pyramid: 1
funnel: 1
max_science_pack: max_science_pack:
automation_science_pack: 0 automation_science_pack: 0
logistic_science_pack: 0 logistic_science_pack: 0

View File

@ -32,3 +32,4 @@ class Games(str, enum.Enum):
HK = "Hollow Knight" HK = "Hollow Knight"
LTTP = "A Link to the Past" LTTP = "A Link to the Past"
Factorio = "Factorio" Factorio = "Factorio"
Minecraft = "Minecraft"

95
worlds/factorio/Shapes.py Normal file
View File

@ -0,0 +1,95 @@
from typing import Dict, List, Set
from BaseClasses import MultiWorld
from Options import TechTreeLayout
from worlds.factorio.Technologies import technology_table
def get_shapes(world: MultiWorld, player: int) -> Dict[str, List[str]]:
prerequisites: Dict[str, Set[str]] = {}
layout = world.tech_tree_layout[player].value
if layout == TechTreeLayout.option_small_diamonds:
slice_size = 4
tech_names: List[str] = list(set(technology_table) - world._static_nodes)
tech_names.sort()
world.random.shuffle(tech_names)
while len(tech_names) > slice_size:
slice = tech_names[:slice_size]
tech_names = tech_names[slice_size:]
slice.sort(key=lambda tech_name: len(technology_table[tech_name].ingredients))
diamond_0, diamond_1, diamond_2, diamond_3 = slice
# 0 |
# 1 2 |
# 3 V
prerequisites[diamond_3] = {diamond_1, diamond_2}
prerequisites[diamond_2] = prerequisites[diamond_1] = {diamond_0}
elif layout == TechTreeLayout.option_medium_diamonds:
slice_size = 9
tech_names: List[str] = list(set(technology_table) - world._static_nodes)
tech_names.sort()
world.random.shuffle(tech_names)
while len(tech_names) > slice_size:
slice = tech_names[:slice_size]
tech_names = tech_names[slice_size:]
slice.sort(key=lambda tech_name: len(technology_table[tech_name].ingredients))
# 0 |
# 1 2 |
# 3 4 5 |
# 6 7 |
# 8 V
prerequisites[slice[1]] = {slice[0]}
prerequisites[slice[2]] = {slice[0]}
prerequisites[slice[3]] = {slice[1]}
prerequisites[slice[4]] = {slice[1], slice[2]}
prerequisites[slice[5]] = {slice[2]}
prerequisites[slice[6]] = {slice[3], slice[4]}
prerequisites[slice[7]] = {slice[4], slice[5]}
prerequisites[slice[8]] = {slice[6], slice[7]}
elif layout == TechTreeLayout.option_pyramid:
slice_size = 1
tech_names: List[str] = list(set(technology_table) - world._static_nodes)
tech_names.sort()
world.random.shuffle(tech_names)
tech_names.sort(key=lambda tech_name: len(technology_table[tech_name].ingredients))
previous_slice = []
while len(tech_names) > slice_size:
slice = tech_names[:slice_size]
tech_names = tech_names[slice_size:]
for i, tech_name in enumerate(previous_slice):
prerequisites.setdefault(slice[i], set()).add(tech_name)
prerequisites.setdefault(slice[i + 1], set()).add(tech_name)
previous_slice = slice
slice_size += 1
elif layout == TechTreeLayout.option_funnel:
tech_names: List[str] = list(set(technology_table) - world._static_nodes)
# find largest inverse pyramid
# https://www.wolframalpha.com/input/?i=x+=+1/2+(n++++1)+(2++++n)+solve+for+n
import math
slice_size = int(0.5*(math.sqrt(8*len(tech_names)+1)-3))
import logging
logging.info(slice_size)
tech_names.sort()
world.random.shuffle(tech_names)
tech_names.sort(key=lambda tech_name: len(technology_table[tech_name].ingredients))
previous_slice = []
while slice_size:
slice = tech_names[:slice_size]
tech_names = tech_names[slice_size:]
if previous_slice:
for i, tech_name in enumerate(slice):
prerequisites.setdefault(tech_name, set()).update(previous_slice[i:i+2])
previous_slice = slice
slice_size -= 1
world.tech_tree_layout_prerequisites[player] = prerequisites
return prerequisites

View File

@ -1,14 +1,10 @@
import logging
from typing import List, Dict, Set
from BaseClasses import Region, Entrance, Location, MultiWorld, Item from BaseClasses import Region, Entrance, Location, MultiWorld, Item
from Options import TechTreeLayout
from .Technologies import tech_table, recipe_sources, technology_table, advancement_technologies, required_technologies from .Technologies import tech_table, recipe_sources, technology_table, advancement_technologies, required_technologies
from .Shapes import get_shapes
static_nodes = {"automation", "logistics"}
def gen_factorio(world: MultiWorld, player: int): def gen_factorio(world: MultiWorld, player: int):
static_nodes = world._static_nodes = {"automation", "logistics"} # turn dynamic/option?
for tech_name, tech_id in tech_table.items(): for tech_name, tech_id in tech_table.items():
tech_item = Item(tech_name, tech_name in advancement_technologies, tech_id, player) tech_item = Item(tech_name, tech_name in advancement_technologies, tech_id, player)
tech_item.game = "Factorio" tech_item.game = "Factorio"
@ -36,73 +32,6 @@ def factorio_create_regions(world: MultiWorld, player: int):
world.regions += [menu, nauvis] world.regions += [menu, nauvis]
def get_shapes(world: MultiWorld, player: int) -> Dict[str, List[str]]:
prerequisites:Dict[str, Set[str]] = {}
layout = world.tech_tree_layout[player].value
if layout == TechTreeLayout.option_small_diamonds:
slice_size = 4
tech_names: List[str] = list(set(technology_table)-static_nodes)
tech_names.sort()
world.random.shuffle(tech_names)
while len(tech_names) > slice_size:
slice = tech_names[:slice_size]
tech_names = tech_names[slice_size:]
slice.sort(key=lambda tech_name: len(technology_table[tech_name].ingredients))
diamond_0, diamond_1, diamond_2, diamond_3 = slice
# 0 |
# 1 2 |
# 3 V
prerequisites[diamond_3] = {diamond_1, diamond_2}
prerequisites[diamond_2] = prerequisites[diamond_1] = {diamond_0}
elif layout == TechTreeLayout.option_medium_diamonds:
slice_size = 9
tech_names: List[str] = list(set(technology_table)-static_nodes)
tech_names.sort()
world.random.shuffle(tech_names)
while len(tech_names) > slice_size:
slice = tech_names[:slice_size]
tech_names = tech_names[slice_size:]
slice.sort(key=lambda tech_name: len(technology_table[tech_name].ingredients))
# 0 |
# 1 2 |
# 3 4 5 |
# 6 7 |
# 8 V
prerequisites[slice[1]] = {slice[0]}
prerequisites[slice[2]] = {slice[0]}
prerequisites[slice[3]] = {slice[1]}
prerequisites[slice[4]] = {slice[1], slice[2]}
prerequisites[slice[5]] = {slice[2]}
prerequisites[slice[6]] = {slice[3], slice[4]}
prerequisites[slice[7]] = {slice[4], slice[5]}
prerequisites[slice[8]] = {slice[6], slice[7]}
elif layout == TechTreeLayout.option_pyramid:
slice_size = 1
tech_names: List[str] = list(set(technology_table)-static_nodes)
tech_names.sort()
world.random.shuffle(tech_names)
tech_names.sort(key=lambda tech_name: len(technology_table[tech_name].ingredients))
previous_slice = []
while len(tech_names) > slice_size:
slice = tech_names[:slice_size]
tech_names = tech_names[slice_size:]
for i, tech_name in enumerate(previous_slice):
prerequisites.setdefault(slice[i], set()).add(tech_name)
prerequisites.setdefault(slice[i+1], set()).add(tech_name)
previous_slice = slice
slice_size += 1
world.tech_tree_layout_prerequisites[player] = prerequisites
return prerequisites
def set_rules(world: MultiWorld, player: int): def set_rules(world: MultiWorld, player: int):
shapes = get_shapes(world, player) shapes = get_shapes(world, player)
if world.logic[player] != 'nologic': if world.logic[player] != 'nologic':
@ -118,7 +47,6 @@ def set_rules(world: MultiWorld, player: int):
Rules.add_rule(location, lambda state, Rules.add_rule(location, lambda state,
locations=locations: all(state.can_reach(loc) for loc in locations)) locations=locations: all(state.can_reach(loc) for loc in locations))
# get all technologies # get all technologies
world.completion_condition[player] = lambda state: all(state.has(technology, player) world.completion_condition[player] = lambda state: all(state.has(technology, player)
for technology in advancement_technologies) for technology in advancement_technologies)

View File