File GenerativeWorld.hpp
File List > source > Worlds > GenerativeWorld.hpp
Go to the documentation of this file
#pragma once
#include <cassert>
#include "BiomeGenerator.hpp"
#include "../core/WorldBase.hpp"
#include "../Agents/AStarAgent.hpp"
namespace group6 {
using namespace cse491;
using std::vector, std::string;
class GenerativeWorld : public WorldBase {
protected:
enum ActionType {
REMAIN_STILL = 0, MOVE_UP, MOVE_DOWN, MOVE_LEFT, MOVE_RIGHT
};
size_t floor_id;
size_t wall_id;
size_t spike_id;
size_t tar_id;
size_t key_id;
size_t door_id;
size_t teleporter_id;
size_t armory_id;
size_t tree_id;
size_t grass_id;
size_t dirt_id;
size_t hole_id;
size_t water_id;
size_t sand_id;
unsigned int world_width;
unsigned int world_height;
void ConfigAgent(AgentBase &agent) override {
agent.AddAction("up", MOVE_UP);
agent.AddAction("down", MOVE_DOWN);
agent.AddAction("left", MOVE_LEFT);
agent.AddAction("right", MOVE_RIGHT);
agent.SetProperty("key_property",0.0);
agent.SetProperty("tar_property",5.0);
}
void DamageAgent(AgentBase &agent) {
if (agent.IsInterface()) {
EndGame(false);
}
}
void CreateGrid(BiomeType biome, unsigned int width, unsigned int height, unsigned int seed, const string &file) {
BiomeGenerator biomeGenerator(biome, width, height, seed);
biomeGenerator.setWorld(this);
biomeGenerator.generate();
string filePath = "../assets/grids/generated_" + file + ".grid";
biomeGenerator.saveToFile(filePath);
main_grid.Read(filePath, type_options);
}
public:
explicit GenerativeWorld(BiomeType biome, unsigned int width, unsigned int height, unsigned int seed)
: WorldBase(seed) {
floor_id = AddCellType("floor", "Floor that you can easily walk over.", ' ');
wall_id = AddCellType("wall", "Impenetrable wall that you must find a way around.", '#');
spike_id = AddCellType("spike", "Dangerous spike that resets the game.", 'X');
tar_id = AddCellType("tar", "Slow tile that makes you take two steps to get through it", 'O');
key_id = AddCellType("key", "item that can be picked up to unlock door and escape maze", 'K');
door_id = AddCellType("door", "Door that can be walked through only with possession of key to leave maze",'D');
teleporter_id = AddCellType("teleporter", "Teleports agent to other teleporter", 'T');
armory_id = AddCellType("armory", "Armory tile that repairs damaged inventory items", 'A');
tree_id = AddCellType("tree", "A tree that blocks the way.", 't');
grass_id = AddCellType("grass", "Grass you can walk on.", 'M');
dirt_id = AddCellType("dirt", "Dirt you can walk on.", '~');
hole_id = AddCellType("hole", "A hole that you can fall into the maze from.", '8');
water_id = AddCellType("water", "Water that you may be able to swim on.", 'W');
sand_id = AddCellType("sand", "Sand you can walk on.", '-');
world_width = width;
world_height = height;
CreateGrid(biome, width, height, seed, "maze");
}
~GenerativeWorld() override = default;
void AddTeleporters() {
main_grid.At(53, 6) = teleporter_id;
main_grid.At(18, 18) = teleporter_id;
}
[[noreturn]] void EndGame(bool win) {
run_over = true;
if (win) {
std::cout << "You successfully exited maze!" << std::endl;
} else {
std::cout << "Game over, try again!" << std::endl;
}
std::exit(0);
}
void AddArmory() {
bool counter = false;
while (!counter) {
//generate random location in bottom left quarter of map
int random_y = (int)GetRandom((double)main_grid.GetHeight() / 2, (double)main_grid.GetHeight() - 1);
int random_x = (int)GetRandom(0, (double)main_grid.GetWidth() / 2);
if (main_grid.At(random_x, random_y) == floor_id) {
main_grid.At(random_x, random_y) = armory_id;
counter = true;
}
}
counter = false;
while (!counter) {
//generate random location in top right quarter of map
int random_y = (int)GetRandom(0, (double)main_grid.GetHeight() / 2);
int random_x = (int)GetRandom((double)main_grid.GetWidth() / 2, (double)main_grid.GetWidth() - 1);
if (main_grid.At(random_x, random_y) == floor_id) {
main_grid.At(random_x, random_y) = armory_id;
counter = true;
}
}
}
[[nodiscard]] static vector<GridPosition> FindTiles(WorldGrid grid, size_t tile_id) {
vector<GridPosition> result;
for (size_t x = 0; x < grid.GetWidth(); ++x) {
for (size_t y = 0; y < grid.GetHeight(); ++y) {
if (grid.At(x, y) == tile_id) {
result.emplace_back(x, y);
}
}
}
return result;
}
int DoAction(AgentBase &agent, size_t action_id) override {
AgentCollisionHelper(agent);
// Skip turn if stuck on tar
if (agent.GetProperty("tar_property") == 6.0) {
agent.SetProperty("tar_property", 5.0);
return true;
}
// Determine where the agent is trying to move.
GridPosition new_position;
switch (action_id) {
case REMAIN_STILL:
new_position = agent.GetPosition();
break;
case MOVE_UP:
new_position = agent.GetPosition().Above();
break;
case MOVE_DOWN:
new_position = agent.GetPosition().Below();
break;
case MOVE_LEFT:
new_position = agent.GetPosition().ToLeft();
break;
case MOVE_RIGHT:
new_position = agent.GetPosition().ToRight();
break;
}
// Don't let the agent move off the world or into a wall.
if (!main_grid.IsValid(new_position)) { return false; }
if (main_grid.At(new_position) == wall_id) { return false; }
//check to see if player is going onto armory tile
if (main_grid.At(new_position) == armory_id) {
ArmoryTileHelper(agent);
}
// check to see if player is moving onto spike tile
if (main_grid.At(new_position) == spike_id) {
SpikeTileHelper(agent);
}
// check to see if player is moving onto a tar tile
else if (main_grid.At(new_position) == tar_id) {
TarTileHelper(agent);
}
// check to see if player is moving onto teleporter
else if (main_grid.At(new_position) == teleporter_id) {
TeleporterHelper(new_position);
}
// check to see if player is moving onto key tile
else if (main_grid.At(new_position) == key_id) {
KeyTileHelper(agent, new_position);
}
// check to see if the player is moving onto door tile
else if (main_grid.At(new_position) == door_id) {
DoorTileHelper(agent);
}
// check to see if player is moving onto a hole tile
else if (main_grid.At(new_position) == hole_id) {
HoleTileHelper(agent, new_position);
}
//recalculate AStarAgent's path when player moves
AStarAgentHelper(agent);
//check to see if agent is walking on an item
ItemHelper(agent, new_position);
// Set the agent to its new position.
agent.SetPosition(new_position);
return true;
}
void ArmoryTileHelper(AgentBase &agent) {
for (const auto &pair: item_map) {
//if agent has the item in its inventory, heal it back to full health
if (agent.HasItem(pair.first)) {
pair.second->SetProperty("Health", 4.0);
}
}
}
void SpikeTileHelper(AgentBase &agent) {
bool spike_immune = false;
//check to see if player has shield on
for (const auto &pair: item_map) {
if (agent.HasItem(pair.first) && pair.second->GetName() == "Shield") {
//agent's shield has enough health and will protect player from spike tile
if (pair.second->GetProperty("Health") > 0) {
pair.second->SetProperty("Health", pair.second->GetProperty("Health") - 1);
spike_immune = true;
break;
}
}
}
// Damage agent if not immune to spike
if (!spike_immune) {
DamageAgent(agent);
}
}
void TarTileHelper(AgentBase &agent) {
bool tar_immune = false;
//check to see if player has boots on
for (const auto &pair: item_map) {
if (agent.HasItem(pair.first) && pair.second->GetName() == "Boots") {
//agent's boots have enough health and will protect player from tar
if (pair.second->GetProperty("Health") > 0) {
pair.second->SetProperty("Health", pair.second->GetProperty("Health") - 1);
tar_immune = true;
break;
}
}
}
// Slow agent if not immune to tar
if (!tar_immune) {
agent.SetProperty("tar_property", 6.0);
}
}
void TeleporterHelper(GridPosition &new_position) {
vector<GridPosition> teleporters = FindTiles(main_grid, teleporter_id);
for (GridPosition teleporter: teleporters) {
if (new_position != teleporter) {
new_position = teleporter;
break;
}
}
}
void KeyTileHelper(AgentBase &agent, GridPosition &new_position) {
// Only player can pick up keys
if (agent.IsInterface()) {
agent.SetProperty("key_property", 1.0);
main_grid.At(new_position) = floor_id;
}
}
void DoorTileHelper(AgentBase &agent) {
// Only player with key can win game
if (agent.IsInterface() && agent.GetProperty("key_property") == 1.0) {
EndGame(true);
}
}
void HoleTileHelper(AgentBase &agent, GridPosition &new_position) {
if (agent.IsInterface()) {
CreateGrid(BiomeType::Maze, world_width, world_height, ++seed, "maze2");
new_position.Set(0, 0);
}
}
void ItemHelper(AgentBase &agent, GridPosition &new_position) {
for (const auto &pair: item_map) {
//check to see if items position is same as the position the player is moving to
if (pair.second->GetPosition() == new_position) {
//Add item to inventory
agent.AddItem(pair.first);
break;
}
}
}
void AgentCollisionHelper(AgentBase &agent) {
//if player is on same position as agent, game ends
for (const auto &temp_agent: agent_map) {
//check to see if the two agents positions being compared are equal,
//as well as if one agent is a player and one agent is an enemy
if (temp_agent.second->GetPosition() == agent.GetPosition() &&
((agent.GetName() == "Player" && temp_agent.second->GetName() != "Player") ||
(agent.GetName() != "Player" && temp_agent.second->GetName() == "Player")))
EndGame(false);
}
}
bool IsTraversable(const AgentBase & /*agent*/, cse491::GridPosition pos) const override {
size_t tileType = main_grid.At(pos);
return !(tileType == wall_id || tileType == spike_id || tileType == tar_id || tileType == armory_id || tileType == teleporter_id);
}
void AStarAgentHelper(AgentBase &agent)
{
if( agent.GetName() == "AStar1" )
{
for( const auto &temp_agent : agent_map )
{
//updating AStarAgent's path to the players current location
if( temp_agent.second->GetName() == "Player" )
{
auto &astar_agent = dynamic_cast<walle::AStarAgent&>(agent);
astar_agent.SetGoalPosition(temp_agent.second->GetPosition());
astar_agent.RecalculatePath();
astar_agent.SetActionResult(1);
break;
}
}
}
}
};
} // End of namespace group6