Initial commit

This commit is contained in:
Tyler Beckman 2024-12-04 16:44:31 -07:00
commit 2c58cf5213
Signed by: Ty
GPG key ID: 2813440C772555A4
20 changed files with 639 additions and 0 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
A6
*.o
.direnv

67
Makefile Normal file
View file

@ -0,0 +1,67 @@
# THE NAME OF YOUR EXECUTABLE
TARGET = A6
# ALL CPP COMPILABLE IMPLEMENTATION FILES THAT MAKE UP THE PROJECT
SRC_FILES = main.cpp
# NO EDITS NEEDED BELOW THIS LINE
CXX = g++
CXXFLAGS = -O2
CXXFLAGS_DEBUG = -g
CXXFLAGS_WARN = -Wall -Wextra -Wunreachable-code -Wshadow -Wpedantic
CPPVERSION = -std=c++17
OBJECTS = $(SRC_FILES:.cpp=.o)
ifeq ($(OS),Windows_NT)
TARGET := $(TARGET).exe
DEL = del
Q =
INC_PATH = Z:/CSCI200/include/
LIB_PATH = Z:/CSCI200/lib/
RPATH =
else
DEL = rm -f
Q = "
INC_PATH = /usr/local/include/
LIB_PATH = /usr/local/lib/
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
CXXFLAGS += -D LINUX
RPATH =
endif
ifeq ($(UNAME_S),Darwin)
CXXFLAGS += -D OSX
RPATH = -Wl,-rpath,/Library/Frameworks
endif
UNAME_P := $(shell uname -p)
endif
LIBS = -lsfml-graphics -lsfml-window -lsfml-system -lsfml-audio -lsfml-network
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CXX) -o $@ $^ $(RPATH) -L$(LIB_PATH) $(LIBS)
.cpp.o:
$(CXX) $(CXXFLAGS) $(CPPVERSION) $(CXXFLAGS_DEBUG) $(CXXFLAGS_WARN) -o $@ -c $< -I$(INC_PATH)
clean:
$(DEL) $(TARGET) $(OBJECTS)
depend:
@sed -i.bak '/^# DEPENDENCIES/,$$d' Makefile
@$(DEL) sed*
@echo $(Q)# DEPENDENCIES$(Q) >> Makefile
@$(CXX) -MM $(SRC_FILES) >> Makefile
.PHONY: all clean depend
# DEPENDENCIES
main.o: main.cpp

61
flake.lock Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1733212471,
"narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

51
flake.nix Normal file
View file

@ -0,0 +1,51 @@
{
description = "CSCI200 Lab 6C";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
inputs.flake-utils.url = "github:numtide/flake-utils";
outputs = { nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; in {
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
sfml
];
packages = with pkgs; [
gcc
clang-tools
];
};
packages.default = pkgs.stdenv.mkDerivation rec {
pname = "A6";
version = "1";
src = nixpkgs.lib.fileset.toSource {
root = ./.;
fileset = nixpkgs.lib.fileset.unions [ ./main.cpp ./Makefile ./mazePack ];
};
buildInputs = with pkgs; [
sfml
];
nativeBuildInputs = with pkgs; [
gcc
];
buildPhase = ''
make
'';
installPhase = ''
runHook preInstall
mkdir -p $out/bin
cp ./${pname} $out/bin/
runHook postInstall
'';
};
});
}

290
main.cpp Normal file
View file

@ -0,0 +1,290 @@
/**
Lab 6C - Maze Drawer, a program to parse a .maze text file and display it using SFML.
@author Tyler Beckman (tyler_beckman@myriation.xyz)
@date 12/4/24
*/
#include <SFML/Graphics.hpp>
#include <SFML/Window/Keyboard.hpp>
#include <queue>
#include <stack>
#include <utility>
#include <variant>
using namespace sf;
#include <iostream>
#include <fstream>
using namespace std;
enum class State {
Unexplored,
Added,
Explored,
UsedInPath
};
struct Node {
char character;
State state;
Node* prevNode;
};
int main(int argc, char** argv) {
string filename;
if (argc >= 2) {
filename = argv[1];
} else {
cout << "Please enter a maze filename to load: ";
cin >> filename;
}
cout << "Loading maze file " << filename << endl;
ifstream mazeFile(filename);
if (mazeFile.fail()) {
std::cout << "Failed to open specified file path " << filename
<< ", does it exist?" << std::endl;
return 1;
}
int rows, cols;
mazeFile >> rows >> cols;
mazeFile.get(); // move cursor past newline to actual grid characters
Node** grid = new Node*[rows];
pair<int, int> startNode(-1, -1);
for (int row = 0; row < rows; row++) {
grid[row] = new Node[cols];
for (int col = 0; col < cols; col++) {
grid[row][col].character = mazeFile.get();
grid[row][col].state = State::Unexplored;
grid[row][col].prevNode = nullptr;
// Save start as starting node and mark as visited
if (grid[row][col].character == 'S') {
startNode = make_pair(row, col);
grid[row][col].state = State::Explored;
};
}
mazeFile.get(); // advance past newline
}
char searchType = '\0';
cout << "Would you like to use a [b]readth-first search or a [d]epth-first search? ";
cin >> searchType;
if (searchType != 'b' && searchType != 'B' && searchType != 'd' && searchType != 'D') {
cout << "Search type '" << searchType << "' is unrecognized. Please enter a valid search type." << endl;
return 1;
}
variant<queue<pair<int, int>>, stack<pair<int, int>>> nodeList;
// Create stack or queue with start node
if (searchType == 'b' || searchType == 'B') {
nodeList = queue<pair<int, int>>({startNode});
} else {
nodeList = stack<pair<int, int>>({startNode});
}
bool searching = true;
// create a window
RenderWindow window( VideoMode(15*cols, 15*rows), "Maze Runner" );
window.setVerticalSyncEnabled(true);
// create an event object once to store future events
Event event;
// while the window is open
while( window.isOpen() ) {
// clear any existing contents
window.clear();
/////////////////////////////////////
// BEGIN DRAWING HERE
// Draw unsolved maze from grid by iterating over each column in each row
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
sf::RectangleShape rectangle;
rectangle.setSize(Vector2f(15, 15));
rectangle.setPosition(col * 15, row * 15);
switch (grid[row][col].character) {
case 'S':
rectangle.setFillColor(Color::Green);
break;
case 'E':
rectangle.setFillColor(Color::Red);
break;
case '#':
rectangle.setFillColor(Color::Black);
break;
case '.':
rectangle.setFillColor(Color::White);
break;
}
if (grid[row][col].character != 'S' && grid[row][col].character != 'E') {
switch (grid[row][col].state) {
case State::Added:
rectangle.setFillColor(Color::Blue);
break;
case State::Explored:
rectangle.setFillColor(Color::Magenta);
break;
case State::UsedInPath:
rectangle.setFillColor(Color::Yellow);
break;
default:
break;
}
}
window.draw(rectangle);
}
}
// Solve maze
if (searching) {
// Take a node off the stack or queue
pair<int, int> dequeuedNode;
if (searchType == 'B' || searchType == 'b') {
queue<pair<int, int>>& nodeQueue = get<queue<pair<int, int>>>(nodeList);
if (nodeQueue.size() == 0) {
// Handle unsolvable mazes
searching = false;
cout << "Maze is unsolvable :c" << endl;
continue;
}
dequeuedNode = nodeQueue.front();
nodeQueue.pop();
} else {
stack<pair<int, int>>& nodeStack = get<stack<pair<int, int>>>(nodeList);
if (nodeStack.size() == 0) {
// Handle unsolvable mazes
searching = false;
cout << "Maze is unsolvable :c" << endl;
continue;
}
dequeuedNode = nodeStack.top();
nodeStack.pop();
}
grid[dequeuedNode.first][dequeuedNode.second].state = State::Explored;
// If end, print end and empty structure, then calculate true path
if (grid[dequeuedNode.first][dequeuedNode.second].character == 'E') {
cout << "End reached!" << endl;
searching = false;
// Empty stack/queue
if (searchType == 'B' || searchType == 'b') {
queue<pair<int, int>>& nodeQueue = get<queue<pair<int, int>>>(nodeList);
for (size_t i = 0; i < nodeQueue.size(); i++) {
nodeQueue.pop();
}
} else {
stack<pair<int, int>>& nodeStack = get<stack<pair<int, int>>>(nodeList);
for (size_t i = 0; i < nodeStack.size(); i++) {
nodeStack.pop();
}
}
// Mark all path-nodes as State::UsedInPath
for (Node* node = &grid[dequeuedNode.first][dequeuedNode.second]; node != nullptr; node = node->prevNode) {
node->state = State::UsedInPath;
}
} else {
// Take dequeued node and process it
pair<int, int> nodesToAdd[4];
int nodesAdded = 0;
// Add all adjacent nodes in South->East->North->West order, if not added already
// South
if (
dequeuedNode.first != (rows - 1)
&& grid[dequeuedNode.first + 1][dequeuedNode.second].state == State::Unexplored
&& grid[dequeuedNode.first + 1][dequeuedNode.second].character != '#'
) {
nodesToAdd[nodesAdded] = make_pair(dequeuedNode.first + 1, dequeuedNode.second);
nodesAdded++;
}
// East
if (
dequeuedNode.second != (cols - 1)
&& grid[dequeuedNode.first][dequeuedNode.second + 1].state == State::Unexplored
&& grid[dequeuedNode.first][dequeuedNode.second + 1].character != '#'
) {
nodesToAdd[nodesAdded] = make_pair(dequeuedNode.first, dequeuedNode.second + 1);
nodesAdded++;
}
// North
if (
dequeuedNode.first != 0
&& grid[dequeuedNode.first - 1][dequeuedNode.second].state == State::Unexplored
&& grid[dequeuedNode.first - 1][dequeuedNode.second].character != '#'
) {
nodesToAdd[nodesAdded] = make_pair(dequeuedNode.first - 1, dequeuedNode.second);
nodesAdded++;
}
// West
if (
dequeuedNode.second != 0
&&grid[dequeuedNode.first][dequeuedNode.second - 1].state == State::Unexplored
&& grid[dequeuedNode.first][dequeuedNode.second - 1].character != '#'
) {
nodesToAdd[nodesAdded] = make_pair(dequeuedNode.first, dequeuedNode.second - 1);
nodesAdded++;
}
// Mark all added notes as State::Added, and link to current node to later display path
for (int i = 0; i < nodesAdded; i++) {
grid[nodesToAdd[i].first][nodesToAdd[i].second].state = State::Added;
grid[nodesToAdd[i].first][nodesToAdd[i].second].prevNode = &grid[dequeuedNode.first][dequeuedNode.second];
if (searchType == 'B' || searchType == 'b') {
queue<pair<int, int>>& nodeQueue = get<queue<pair<int, int>>>(nodeList);
nodeQueue.push(nodesToAdd[i]);
} else {
stack<pair<int, int>>& nodeStack = get<stack<pair<int, int>>>(nodeList);
nodeStack.push(nodesToAdd[i]);
}
}
// Sleep to avoid solving instantly
sleep(milliseconds(50));
}
}
// END DRAWING HERE
/////////////////////////////////////
// display the current contents of the window
window.display();
/////////////////////////////////////
// BEGIN EVENT HANDLING HERE
// check if any events happened since the last time checked
while( window.pollEvent(event) ) {
// if event type corresponds to pressing window X
if (event.type == Event::Closed) {
// tell the window to close
window.close();
}
// If event type corresponds to pressing Q or Esc
if (event.type == Event::KeyPressed) {
switch (event.key.code) {
case Keyboard::Key::Q:
case Keyboard::Key::Escape:
// Tell the window to close
window.close();
break;
default:
break;
}
}
// check addition event types to handle additional events
}
// END EVENT HANDLING HERE
/////////////////////////////////////
}
return 0;
}

7
mazePack/1.maze Normal file
View file

@ -0,0 +1,7 @@
6 9
#########
#S#...#E#
#.#.#.#.#
#.#.#.#.#
#...#...#
#########

8
mazePack/2.maze Normal file
View file

@ -0,0 +1,8 @@
7 8
########
#.##..E#
#.##.###
#.#..###
#.##...#
#S...#.#
########

9
mazePack/3.maze Normal file
View file

@ -0,0 +1,9 @@
8 26
##########################
#S#............#....#....#
#.#...###....###.##.#.##E#
#.#.###.#..#...#.##.#.##.#
#.....#...###....#....##.#
###.##..##.#..####.##..###
###..##....####....#######
##########################

9
mazePack/4.maze Normal file
View file

@ -0,0 +1,9 @@
8 26
##########################
#S#............#....#.##.#
#.#...###....###.##.#.#.E#
#.#.###.#..#...#.##.#.##.#
#.....#...###....#....####
###.##..##.#..####.##.####
###..##....####....#######
##########################

9
mazePack/5.maze Normal file
View file

@ -0,0 +1,9 @@
8 26
##########################
#S#............#....#.##.#
#.#...###....###.##.#.#.E#
#.#.###.#..#...#.##.#.##.#
###...#...###....#....####
###.##..##.#..####.##.####
###..##....####....#######
##########################

8
mazePack/6.maze Normal file
View file

@ -0,0 +1,8 @@
7 9
.........
.........
.........
..S...E..
.........
.........
.........

9
mazePack/7.maze Normal file
View file

@ -0,0 +1,9 @@
8 26
##########################
#S#............#....#....#
#.#...###....###.##.#.##E#
#.#.#.#.#..#...#.##.#.##.#
#.....#....##.........##.#
###.##..##.#..#.##.##....#
###..........##....#######
##########################

4
mazePack/8.maze Normal file
View file

@ -0,0 +1,4 @@
3 60
############################################################
#S........................................................E#
############################################################

17
mazePack/9.maze Normal file
View file

@ -0,0 +1,17 @@
16 41
#########################################
#.....................................#.#
#.....................................#.#
#.....................................#.#
#.....................................#.#
#.....................................#.#
#....................................S#E#
#.....................................#.#
#.....................................#.#
#.....................................#.#
#.....................................#.#
#.....................................#.#
#.....................................#.#
#.....................................#.#
#.....................................#.#
#########################################

17
mazePack/A.maze Normal file
View file

@ -0,0 +1,17 @@
16 41
#########################################
#.......................................#
#.......................................#
#.......................................#
#.......................................#
#.......................................#
#.......................................#
#.......................................#
#.......................................#
#.......................................#
#.......................................#
#..E....................................#
#.......................................#
#..S....................................#
#.......................................#
#########################################

9
mazePack/B.maze Normal file
View file

@ -0,0 +1,9 @@
8 26
##########################
#S#............#....#.##E#
#.#...#.#....#.#.##.#....#
#.#.#.#.#..#...#....#.##.#
#.....#....##....#....##.#
###.#...##.#..#.##.##.##.#
###...#......##..........#
##########################

8
mazePack/C.maze Normal file
View file

@ -0,0 +1,8 @@
7 9
.........
.........
.........
..E...S..
.........
.........
.........

26
mazePack/D.maze Normal file
View file

@ -0,0 +1,26 @@
25 3
###
#S#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#.#
#E#
###

26
mazePack/E.maze Normal file
View file

@ -0,0 +1,26 @@
25 3
...
.S.
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
.E.
...