"""Load an existing gameworld or begin anew"""
from copy import deepcopy
from random import choices, choice, randint, shuffle
from operator import add
import matplotlib.pyplot as plt
from numpy import full as npf
import dork.game_utils.factory_data as factory_data
# pylint: disable=protected-access
[docs]class ItemFactory:
"""Generates a random named item with randomized stats"""
items = factory_data.ITEMS
names = factory_data.NAMES
sequence = factory_data.SEQUENCE
types = items["types"]
condition = items["condition"]
material = items["material"]
posessive = names["posessive"]
nonposessive = names["nonposessive"]
suffixes = names["suffixes"]
abstract = names["abstract"]
adjectives = names["adjectives"]
[docs] @staticmethod
def build(weights=None):
"""generate a random item
Creates an item name, type, and location into game world
Args:
item_name (str): name of randomly generated item
item_type (str): tpye of randomly generated item
returns:
item_name (str): returns the name of the randomly generated item
item_type (str): returns the type of the randomly generated item
"""
weights = {
"player": [8, 0, 0, 7, 5, 10]
}.get(weights, [8, 35, 3, 7, 5, 10])
item_type = choice(choices(
population=list(ItemFactory.types.keys()),
weights=weights,
k=len(list(ItemFactory.types.keys()))
))
item_name = choice(choices(
population=ItemFactory.types[item_type],
k=len(ItemFactory.types[item_type])
))
return ItemFactory._forge(item_name, item_type)
@staticmethod
def _generate(stats, item_name, item_type):
return {
"name": item_name,
"type": item_type,
"description": "",
"stats": stats
}
@staticmethod
def _stats(item_name, item_type):
stats = factory_data.stats(item_type.split()[0])
return ItemFactory._generate(stats, item_name, item_type)
@staticmethod
def _forge(item_name, item_type):
new_name = []
build = ItemFactory.sequence[item_type]
seq = choice(choices(
population=build["seq"],
weights=build["w"],
k=len(build["seq"])
))
for lists in seq:
if isinstance(lists, dict):
this_list = lists.get(
item_type, lists.get("usable", ['']))
elif lists:
this_list = lists
else:
this_list = ['']
this_word = choice(choices(
population=this_list,
k=len(this_list)
))
if this_word:
if this_word in ItemFactory.suffixes:
new_name[-1] += this_word
item_type = f"legendary {item_name}"
else:
new_name.append(this_word)
else:
new_name.append(item_name)
item_name = " ".join(new_name)
return ItemFactory._stats(item_name, item_type)
[docs]class PlayerFactory:
"""Generate players for a room"""
[docs] @staticmethod
def build(i, room):
"""Make a player, give them items
Extended Description
Args:
arg1 (str): description
returns:
arg1 (str): description
"""
firsts = factory_data.FIRST_NAMES
rand_first = choice(firsts)
lasts = factory_data.LAST_NAMES
rand_last = choice(lasts)
new_player = {
"name": rand_first + " " + rand_last,
"description": f"player {i} description",
"location": room["name"],
"inventory": {},
"equipped": []
}
for _ in range(randint(1, 3)):
new_item = ItemFactory.build("player")
new_player["inventory"][new_item["name"]] = new_item
for key, val in new_player["inventory"].items():
if val["stats"]["equipable"]:
new_player["equipped"].append(key)
return new_player
[docs]class RoomFactory:
"""Generate rooms for a given maze"""
# N, S and E, W are backwards because numpy uses column-order
moves = {
"north": (1, 0), "south": (-1, 0),
"east": (0, 1), "west": (0, -1),
}
[docs] @staticmethod
def build(maze, rooms):
"""build a room
Creates an instance of a room
Args:
_make_rooms (): creates an instance of a room
returns:
_make_rooms (): returns an instance of a room
"""
RoomFactory.maze = maze
RoomFactory.rooms = rooms
RoomFactory.worldmap = {}
return RoomFactory._make_rooms()
@staticmethod
def _make_rooms():
list_of_keys = factory_data.ROOMS
shuffle(list_of_keys)
list_of_adjtvs = factory_data.NAMES["adjectives"]
shuffle(list_of_adjtvs)
list_of_abstract = factory_data.NAMES["abstract"]
shuffle(list_of_abstract)
i = 0
for room in RoomFactory.rooms:
if i == 0:
x, y = room
new_room = {
"number": f"room 0",
"name": f"Entrance",
"description": factory_data.DEFAULT_ROOMS["Entrance"],
"coordinates": [x, y],
"adjacent": {},
"players": {},
"inventory": {},
}
elif i < len(RoomFactory.rooms) - 1:
rand = list_of_keys[i]
x, y = room
new_room = {
"number": f"room {i}",
"name": list_of_adjtvs[i] + rand + list_of_abstract[i],
"description": "The " + list_of_adjtvs[i] + rand +
list_of_abstract[i],
"coordinates": [x, y],
"adjacent": {},
"players": {},
"inventory": {},
}
else:
x, y = room
new_room = {
"number": f"room "+str(len(RoomFactory.rooms)),
"name": f"End",
"description": factory_data.DEFAULT_ROOMS["End"],
"coordinates": [x, y],
"adjacent": {},
"players": {},
"inventory": {},
}
for _ in range(randint(1, 7)):
new_item = ItemFactory.build()
new_room["inventory"][new_item["name"]] = new_item
for _ in range(randint(0, 2)):
new_player = PlayerFactory.build(i, new_room)
new_room["players"][new_player["name"]] = new_player
RoomFactory.worldmap[room] = new_room
i += 1
return RoomFactory._get_adj()
@staticmethod
def _get_adj():
for coord, room in RoomFactory.worldmap.items():
for direction in RoomFactory.moves:
searching = True
position = coord
while searching:
position = tuple(
map(add, position, RoomFactory.moves[direction]))
if RoomFactory.maze[position] == MazeFactory.wall_color:
room["adjacent"][direction] = None
searching = False
elif RoomFactory.maze[position] in \
[MazeFactory.room_color, MazeFactory.player_color]:
room["adjacent"][direction] = \
RoomFactory.worldmap[position]["number"]
searching = False
for coord, room in deepcopy(RoomFactory.worldmap).items():
new_room = RoomFactory.worldmap.pop(coord)
RoomFactory.worldmap[new_room.pop("number")] = new_room
return RoomFactory.worldmap
[docs]class MazeFactory:
"""Generate a maze with rooms on intersections, corners, and dead-ends"""
wall_color, path_color, room_color, player_color = (-2, 2, 1, 0)
moves = factory_data.MOVES
rules = factory_data.rules(wall_color, path_color)
[docs] @staticmethod
def draw(maze):
"""display the maze"""
plt.figure(figsize=(len(maze[0])//2, len(maze)//2))
plt.pcolormesh(maze, cmap=plt.cm.get_cmap("tab20b"))
plt.axis("equal")
plt.axis("off")
plt.ion()
plt.show()
[docs] @staticmethod
def update(maze):
"""update the maze display"""
plt.pcolormesh(maze, cmap=plt.cm.get_cmap("tab20b"))
plt.axis("equal")
plt.axis("off")
plt.draw()
# pylint: disable=R0914
[docs] @staticmethod
def build():
"""generate a maze"""
x = choice([10, 12, 14, 18])
y = 148//x
maze = npf((x+1, y+1), MazeFactory.wall_color)
grid = [(i, j) for i in range(1, x+1, 2) for j in range(1, y+1, 2)]
path = [choice(grid)]
rooms = []
position = path[0]
grid.remove(position)
while grid:
n = len(path)
nsew = []
for move in MazeFactory.moves:
nsew.append([
tuple(map(add, move[0], position)),
tuple(map(add, move[1], position))
])
shuffle(nsew)
for probe in nsew:
if probe[0] in grid:
maze[probe[0]] = MazeFactory.path_color
maze[probe[1]] = MazeFactory.path_color
grid.remove(probe[0])
path.extend(probe)
break
if n == len(path):
position = path[max(path.index(position)-1, 1)]
else:
position = path[-1]
for coord in path:
i, j = coord
neighbors = [
maze[i-1, j],
maze[i+1, j],
maze[i, j-1],
maze[i, j+1]
]
if neighbors in MazeFactory.rules:
rooms.append(coord)
maze[coord] = MazeFactory.room_color
maze[rooms[0]] = MazeFactory.player_color
return {
"maze": maze.tolist(),
"rooms": RoomFactory.build(maze, rooms)
}