Eliguli / NYU-CAS-Meows-Corp-Association

1 stars 0 forks source link

Board Find Path BFS #6

Open Eliguli opened 2 weeks ago

Eliguli commented 2 weeks ago

Algorithm that finds the max amount of coins for any arbitrary board of coins treasure_map.hpp

#ifndef TREASURE_MAP_HPP
#define TREASURE_MAP_HPP

#include <iostream>
#include <iomanip>
#include <random>
#include <vector>
#include <stack>
#include <utility>
#include <algorithm>

using namespace std;

enum Directions {
    none,
    right,
    down,
    left,
    up,
    both
};

class TreasureMap {
public:
    TreasureMap(int size);
    TreasureMap(const TreasureMap& tm) : size(tm.size) {}
    ~TreasureMap();

    static void ensure_order(pair<int, int>& start, pair<int, int>& end);
    void initGold(pair<int, int> start, pair<int, int> end);
    void printBoard();
    int findMaxGold(pair<int, int> start, pair<int, int> end);
    Directions** directionMatrix(pair<int, int> start, pair<int, int> end);
    void printDirections(Directions** dirs, pair<int, int> start, pair<int, int> end);
    vector<vector<Directions>> findPaths(Directions** dirs, pair<int, int> start, pair<int, int> end);
    void printPaths(const vector<vector<Directions>>& paths, pair<int, int> start, pair<int, int> end);

private:
    int size;
    int** gold;
    int** maxGold;

    void initArray(int** &arr);
    void freeMemory(int** arr);
    void generateDistribution(int** arr, mt19937& gen, uniform_int_distribution<>& dis);
};

#endif // TREASURE_MAP_HPP

treasure_map.cpp

#include "treasure_map.hpp"

TreasureMap::TreasureMap(int size) : size(size) {
    initArray(gold);
    initArray(maxGold);
}

TreasureMap::~TreasureMap() {
    freeMemory(gold);
    freeMemory(maxGold);
}

void TreasureMap::ensure_order(pair<int, int>& start, pair<int, int>& end) {
    if (start.first > end.first) {
        swap(start.first, end.first);
    }
    if (start.second > end.second) {
        swap(start.second, end.second);
    }
}

void TreasureMap::initArray(int** &arr) {
    arr = new int*[size];
    for (int i = 0; i < size; i++) {
        arr[i] = new int[size];
    }
}

void TreasureMap::freeMemory(int** arr) {
    for (int i = 0; i < size; i++) {
        delete[] arr[i];
    }
    delete[] arr;
}

void TreasureMap::generateDistribution(int** arr, mt19937& gen, uniform_int_distribution<>& dis) {
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            arr[i][j] = dis(gen);
        }
    }
}

void TreasureMap::initGold(pair<int, int> start, pair<int, int> end) {
    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<> dis(1, 9);

    generateDistribution(gold, gen, dis);
    gold[start.first][start.second] = 0;
    gold[end.first][end.second] = 0;
}

void TreasureMap::printBoard() {
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            cout << setw(3) << gold[i][j] << " ";
        }
        cout << endl;
    }

    cout << endl << "Max gold matrix: " << endl;
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            cout << setw(3) << maxGold[i][j] << " ";
        }
        cout << endl;
    }
}

int TreasureMap::findMaxGold(pair<int, int> start, pair<int, int> end) {
    maxGold[start.first][start.second] = gold[start.first][start.second];
    int dx = (start.first > end.first) ? -1 : 1;
    int dy = (start.second > end.second) ? -1 : 1;

    for (int i = start.first + dx; i != end.first + dx; i += dx) {
        maxGold[i][start.second] = maxGold[i - dx][start.second] + gold[i][start.second];
    }
    for (int j = start.second + dy; j != end.second + dy; j += dy) {
        maxGold[start.first][j] = maxGold[start.first][j - dy] + gold[start.first][j];
    }

    for (int i = start.first + dx; i != end.first + dx; i += dx) {
        for (int j = start.second + dy; j != end.second + dy; j += dy) {
            maxGold[i][j] = gold[i][j] + max(maxGold[i - dx][j], maxGold[i][j - dy]);
        }
    }
    return maxGold[end.first][end.second];
}

Directions** TreasureMap::directionMatrix(pair<int, int> start, pair<int, int> end) {
    Directions** dirs = new Directions*[size];
    for (int i = 0; i < size; i++) {
        dirs[i] = new Directions[size];
        for (int j = 0; j < size; j++) {
            dirs[i][j] = Directions::none;
        }
    }

    int dx = (start.first > end.first) ? -1 : 1;
    int dy = (start.second > end.second) ? -1 : 1;

    for (int i = start.first + dx; i != end.first + dx; i += dx) {
        dirs[i][start.second] = (start.first > end.first) ? Directions::up : Directions::down;
    }

    for (int j = start.second + dy; j != end.second + dy; j += dy) {
        dirs[start.first][j] = (start.second > end.second) ? Directions::left : Directions::right;
    }

    for (int i = start.first + dx; i != end.first + dx; i += dx) {
        for (int j = start.second + dy; j != end.second + dy; j += dy) {
            if (maxGold[i - dx][j] > maxGold[i][j - dy]) {
                dirs[i][j] = (dx == 1) ? Directions::down : Directions::up;
            } else if (maxGold[i - dx][j] < maxGold[i][j - dy]) {
                dirs[i][j] = (dy == 1) ? Directions::right : Directions::left;
            } else {
                dirs[i][j] = Directions::both;
            }
        }
    }
    return dirs;
}

void TreasureMap::printDirections(Directions** dirs, pair<int, int> start, pair<int, int> end) {
    bool reverse_rows = start.first > end.first;
    bool reverse_cols = start.second > end.second;

    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            cout << setw(3);
            Directions dir = dirs[i][j];

            switch (dir) {
                case Directions::none:
                    cout << "N";
                    break;
                case Directions::down:
                    cout << "U";
                    break;
                case Directions::right:
                    cout << "L";
                    break;
                case Directions::left:
                    cout << "R";
                    break;
                case Directions::up:
                    cout << "D";
                    break;
                case Directions::both:
                    cout << "B";
                    break;           
            }
        }
        cout << endl;
    }
}

vector<vector<Directions>> TreasureMap::findPaths(Directions** dirs, pair<int, int> start, pair<int, int> end) {
    vector<vector<Directions>> all_paths;
    stack<pair<int, int>> positions;
    stack<vector<Directions>> paths;

    positions.push(end);
    paths.push({});

    while (!positions.empty()) {
        auto [r, c] = positions.top();
        auto current_path = paths.top();
        positions.pop();
        paths.pop();

        if (r == start.first && c == start.second) {
            reverse(current_path.begin(), current_path.end());
            all_paths.push_back(current_path);
            continue;
        }

        if (dirs[r][c] == Directions::right || dirs[r][c] == Directions::both) {
            if (c > start.second) {
                auto new_path = current_path;
                new_path.push_back(Directions::right);
                positions.push({r, c - 1});
                paths.push(new_path);
            }
        }

        if (dirs[r][c] == Directions::down || dirs[r][c] == Directions::both) {
            if (r > start.first) {
                auto new_path = current_path;
                new_path.push_back(Directions::down);
                positions.push({r - 1, c});
                paths.push(new_path);
            }
        }

        if (dirs[r][c] == Directions::left || dirs[r][c] == Directions::both) {
            if (c < start.second) {
                auto new_path = current_path;
                new_path.push_back(Directions::left);
                positions.push({r, c + 1});
                paths.push(new_path);
            }
        }

        if (dirs[r][c] == Directions::up || dirs[r][c] == Directions::both) {
            if (r < start.first) {
                auto new_path = current_path;
                new_path.push_back(Directions::up);
                positions.push({r + 1, c});
                paths.push(new_path);
            }
        }
    }

    return all_paths;
}

void TreasureMap::printPaths(const vector<vector<Directions>>& paths, pair<int, int> start, pair<int, int> end) {
    bool reverse_rows = start.first > end.first;
    bool reverse_cols = start.second > end .second;

    for (const auto& path : paths) {
        for (auto dir : path) {
            cout << setw(3);
            switch (dir) {
                case Directions::down:
                    cout << ("D"); // Up if reversed, down otherwise
                    break;
                case Directions::right:
                    cout << ("R"); // Left if reversed, right otherwise
                    break;
                case Directions::left:
                    cout << ("L"); // Right if reversed, left otherwise
                    break;
                case Directions::up:
                    cout << ("U"); // Down if reversed, up otherwise
                    break;
                default:
                    break;
            }
        }
        cout << endl;
    }
}

main.cpp

#include "treasure_map.hpp"

int main() {
    int size = 10;
    TreasureMap board(size);

    int start_x, start_y, end_x, end_y;
    cout << "Enter the coordinates of the start position (x, y) and end position (x, y), "
         << "the range should be between 0 and " << (size - 1) << endl;
    cin >> start_x >> start_y >> end_x >> end_y;
    pair<int, int> start = {start_x, start_y};
    pair<int, int> end = {end_x, end_y};

    board.initGold(start, end);

    // ensure_order(start, end);
    int maxGold = board.findMaxGold(start, end);

    cout << endl;
    board.printBoard();
    cout << "Max gold: " << maxGold << endl;

    Directions** dirs = board.directionMatrix(start, end);
    board.printDirections(dirs, start, end);

    vector<vector<Directions>> paths = board.findPaths(dirs, start, end);
    cout << "All possible paths: " << endl;
    board.printPaths(paths, start, end);

    return 0;
}

image