Adding final assignment updates

This commit is contained in:
Christopher Sanden
2025-11-13 15:15:01 +01:00
parent ae8a53e16b
commit 58772c0488
15 changed files with 6127 additions and 4 deletions

View File

@@ -0,0 +1,108 @@
#include "BankAccount.h"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdlib> // For rand()
#include <random> // For better random number generation
#include <ctime>
#include <cstring> // For memset
#include <cmath> // For floor
#include <chrono> // For time manipulation
#include <locale> // For locale settings
#include <codecvt> // For codecvt_utf8
#include <stdexcept> // For std::invalid_argument
#include <string>
TBankAccount::TBankAccount(EBankAccountType accType, std::string firstName, std::string lastName)
: accountType(accType), ownerFirstName(firstName), ownerLastName(lastName)
{
// Random genration of account number: XXXX.XX.XXXXX
accountNumber = toString(rand() % 9000 + 1000) + "." + toString(rand() % 90 + 10) + "." + toString(rand() % 90000 + 10000);
balance = 0.0f;
//Random generation of creation timestamp, date is any date and time in 2024
int month = rand() % 12 + 1;
int day = rand() % 28 + 1; // To avoid complexity of different month lengths
int hour = rand() % 24;
int minute = rand() % 60;
// Calculate creation timestamp in seconds from 2024-01-01 00:00:00
std:tm tm = {};
tm.tm_year = 2024 - 1900; // Year since 1900
tm.tm_mon = rand() % 12; // Month [0-11]
tm.tm_mday = rand() % 28 + 1; // Day of the month [1-28] to avoid month length issues
tm.tm_hour = rand() % 24; // Hour [0-23]
tm.tm_min = rand() % 60; // Minute [0-59]
tm.tm_sec = 0; // Second [0-59]
creationTimestamp = _mkgmtime(&tm); // Use _mkgmtime for UTC
if (accType == Checking || accType == Saving || accType == Pension)
balance = static_cast<double>(rand() % 1001); // 0 to 1000
else if (accType == Loan)
balance = static_cast<double>(-(rand() % 25001 + 25000)); // -50000 to -25000
else if (accType == Credit)
balance = static_cast<double>(-(rand() % 1001)); // -1000 to 0
}
TBankAccount::~TBankAccount()
{
// Destructor logic if needed
}
std::string TBankAccount::getAccountNumber() const {
return accountNumber;
}
EBankAccountType TBankAccount::getAccountType() const {
return accountType;
}
time_t TBankAccount::getCreationTimestamp() const {
return creationTimestamp;
}
double TBankAccount::getBalance() const {
return balance;
}
void TBankAccount::deposit(double aAmount) {
if (aAmount > 0) balance += aAmount;
}
void TBankAccount::withdraw(double aAmount) {
if (aAmount > 0 && aAmount <= balance) balance -= aAmount;
}
std::string TBankAccount::getAccountTypeString() const
{
switch (accountType)
{
case Checking: return "Checking";
case Saving: return "Saving";
case Credit: return "Credit";
case Pension: return "Pension";
case Loan: return "Loan";
default: return "Unknown";
}
}
//
std::string TBankAccount::getCreationTimeString() const
{
char buffer[26];
ctime_s(buffer, sizeof(buffer), &creationTimestamp);
std::string timeString(buffer);
if (!timeString.empty() && timeString.back() == '\n') {
timeString.pop_back(); // Remove the trailing newline character
}
return timeString;
}
void TBankAccount::printAccountInfo() const
{
std::cout << "Account Number: " << accountNumber << ", Type: " << getAccountTypeString()
<< ", Owner: " << ownerFirstName << " " << ownerLastName
<< ", Balance: " << balance
<< ", Created: " << getCreationTimeString()
<< std::endl;
}

View File

@@ -0,0 +1,52 @@
#pragma once
#ifndef BANKACCOUNT_H
#define BANKACCOUNT_H
#include <string> // For std::string
#include <ctime> // For time_t
#include <cstdlib> // For rand()
#include <iomanip> // For std::setfill and std::setw
#include <sstream> // For std::ostringstream
#include <iostream> // For std::cout
// Helper function to convert value to string
template <typename T>
std::string toString(T value)
{
std::ostringstream oss;
oss << value;
return oss.str();
}
enum EBankAccountType { Checking, Saving, Credit, Pension, Loan };
class TBankAccount {
private:
std::string accountNumber;
EBankAccountType accountType;
time_t creationTimestamp;
double balance;
public:
std::string ownerFirstName;
std::string ownerLastName;
//TBankAccount() {} // Don't use default constructor
TBankAccount(EBankAccountType, std::string, std::string);
~TBankAccount();
std::string getAccountNumber() const;
std::string getCreationTimeString() const;
time_t getCreationTimestamp() const;
double getBalance() const;
void deposit(double);
void withdraw(double);
EBankAccountType getAccountType() const;
std::string getAccountTypeString() const;
void printAccountInfo() const;
};
#endif // BANKACCOUNT_H

View File

@@ -0,0 +1,130 @@
#include "BankAccountList.h"
TLinkedList::TLinkedList(bool aOwnsData) : head(nullptr), ownsData(aOwnsData), size(0) {
head = new TLinkedListNode(nullptr); // Dummy head node
}
TLinkedList::~TLinkedList()
{
while (head->next != nullptr)
{
TLinkedListNode* temp = head->next;
head->next = temp->next;
if (ownsData) delete temp->data; // Delete the TBankAccount object
delete temp; // Delete the node
}
delete head;
}
int TLinkedList::getSize() const { return size; }
void TLinkedList::Add(TBankAccount* aData)
{
TLinkedListNode* newNode = new TLinkedListNode(aData);
newNode->next = head->next;
head->next = newNode;
size++;
}
TBankAccount* TLinkedList::Find(FCompareAccount aCompareFunc, void* aSearchKey)
{
TLinkedListNode* current = head->next;
while (current != nullptr)
{
if (aCompareFunc(current->data, aSearchKey))
{
return current->data; // Found
}
current = current->next;
}
return nullptr; // Not found
}
TLinkedList* TLinkedList::Every(FCompareAccount aCompareFunc, void* aSearchKey)
{
TLinkedList* resultList = new TLinkedList(false); // New list does not own data
TLinkedListNode* current = head->next;
while (current != nullptr)
{
if (aCompareFunc(current->data, aSearchKey))
{
resultList->Add(current->data); // Add to result list
}
current = current->next;
}
return resultList; // Return the new list
}
// Loop through all accounts, if aEveryFunc returns false for any, return that account
TBankAccount* TLinkedList::Every(FEveryAccount aEveryFunc) {
TLinkedListNode* current = head->next;
int index = 0;
while (current != nullptr)
{
if (!aEveryFunc(current->data, index++))
{
return current->data; // Return the first account that fails the test
}
current = current->next;
}
return nullptr; // All accounts passed the test
}
TBankAccount** TLinkedList::ToArray()
{
if (size == 0) return nullptr;
TBankAccount** array = new TBankAccount * [size];
TLinkedListNode* current = head->next;
int index = 0;
while (current != nullptr && index < size) // Ensure index < size
{
array[index++] = current->data;
current = current->next;
}
return array;
}
void TLinkedList::forEach(FForEachAccount aFunc)
{
TLinkedListNode* current = head->next;
int index = 0;
while (current != nullptr)
{
aFunc(current->data, index++);
current = current->next;
}
}
TLinkedListNode* TLinkedList::getHead() const { return head; }
void TLinkedList::Append(TBankAccount* account)
{
TLinkedListNode* newNode = new TLinkedListNode(account);
TLinkedListNode* current = head;
while (current->next != nullptr)
{
current = current->next;
}
current->next = newNode;
size++;
}
void TLinkedList::Remove(TBankAccount* account)
{
TLinkedListNode* current = head;
while (current->next != nullptr)
{
if (current->next->data == account)
{
TLinkedListNode* temp = current->next;
current->next = temp->next;
if (ownsData) delete temp->data; // Delete the TBankAccount object
delete temp; // Delete the node
size--;
return; // Exit after removing
}
current = current->next;
}
}

View File

@@ -0,0 +1,51 @@
#pragma once
#ifndef BANKACCOUNTLIST_H
#define BANKACCOUNTLIST_H
#include "BankAccount.h"
#include <string>
#include <functional>
typedef bool (*FCompareAccount)(TBankAccount* account, void* searchKey);
typedef void (*FForEachAccount)(TBankAccount* account, int index);
typedef bool (*FEveryAccount)(TBankAccount*, int);
// Node class for linked list
class TLinkedListNode
{
public:
TBankAccount* data;
TLinkedListNode* next;
TLinkedListNode(TBankAccount* aData) : data(aData), next(nullptr) {}
~TLinkedListNode()
{
// Destructor logic if needed
}
};
// Use dummy head node for simplicity
class TLinkedList
{
private:
TLinkedListNode* head;
bool ownsData;
int size;
public:
TLinkedList(bool);
~TLinkedList();
int getSize() const;
TLinkedListNode* getHead() const;
void Add(TBankAccount*);
TBankAccount* Find(FCompareAccount, void*);
TLinkedList* Every(FCompareAccount, void*);
TBankAccount* Every(FEveryAccount aEveryFunc);
TBankAccount** ToArray();
void forEach(FForEachAccount);
void Append(TBankAccount* account);
void Remove(TBankAccount* account);
};
#endif// BANKACCOUNTLIST_H

View File

@@ -1,6 +1,19 @@
cmake_minimum_required(VERSION 4.0)
project(TheAlgoeithmicOrganizer)
project(TheAlgorithmicOrganizer)
set(CMAKE_CXX_STANDARD 20)
add_executable(TheAlgoeithmicOrganizer main.cpp)
add_executable(TheAlgorithmicOrganizer main.cpp
main.h
BankAccount.h
BankAccount.cpp
BankAccountList.cpp
BankAccountList.h
FileReaderUtils.cpp
FileReaderUtils.h
ReadNames.cpp
SharedLib.h
Utils.cpp
Sort.cpp
Sort.h
)

View File

@@ -0,0 +1,30 @@
#include "FileReaderUtils.h"
int GetRecordCount(const std::string& aHeaderLine)
{
size_t recordPos = aHeaderLine.find("records:=");
if (recordPos == std::string::npos)
{
return 0; // No record count found
}
size_t countStart = recordPos + 9; // Length of "records:="
// Find the end bracket ']' or a potential semicolon ';'
size_t countEnd = aHeaderLine.find_first_of("];", countStart);
if (countEnd == std::string::npos)
{
return 0; // Malformed header
}
std::string countStr = aHeaderLine.substr(countStart, countEnd - countStart);
try
{
// stoi = string to integer
return std::stoi(countStr);
}
catch (const std::exception&)
{
return 0; // Malformed number
}
}

View File

@@ -0,0 +1,13 @@
// FileReaderUtils.h
#pragma once
#if !defined(FILEREADERUTILS_H)
#define FILEREADERUTILS_H
#include <string>
/**
* @brief [Internal] Safely parses the "records:=N" part of a header line.
* @param aHeaderLine The line, e.g., "[NODES;records:=11]"
* @return The number of records, or 0 if not found.
*/
int GetRecordCount(const std::string& aHeaderLine);
#endif // FILEREADERUTILS_H

View File

@@ -0,0 +1,55 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "SharedLib.h"
#include "FileReaderUtils.h"
void readNamesFromFile(const std::string& aFilename, FNameRead aOnNameRead)
{
if (aFilename.empty()) return;
std::ifstream file(aFilename);
if (!file.is_open())
{
std::cerr << "Error: Could not open file " << aFilename << std::endl;
return;
}
std::string line;
int totalCount = 0;
int currentIndex = 0;
bool keepReading = true;
// --- 1. Read the header line ---
if (std::getline(file, line))
{
// Use our shared helper to get the count
totalCount = GetRecordCount(line);
}
// --- 2. Loop through the rest of the file ---
while (keepReading && std::getline(file, line))
{
if (line.empty()) continue;
std::istringstream nameStream(line);
std::string firstName, lastName;
// Parse "FirstName LastName"
if (nameStream >> firstName >> lastName)
{
if (aOnNameRead)
{
// Call the callback with all parameters
if (!aOnNameRead(currentIndex, totalCount, firstName, lastName))
{
keepReading = false;
}
currentIndex++;
}
}
}
file.close();
}

View File

@@ -0,0 +1,106 @@
#pragma once
#ifndef SHARED_LIB_H
#define SHARED_LIB_H
#include <array>
#include <string>
#include "BankAccount.h"
#include "BankAccountList.h"
// Taken from exam project. Added functions, callbacks, structs and classes are at the bottom
/// <summary>
/// Delegate type for processing a name read from a file.
/// </summary>
/// <param name="aIndex">The index of the name (0-based).</param>
/// <param name="aTotalCount">The total number of names.</param>
/// <param name="aFirstName">The first name read from the file.</param>
/// <param name="aLastName">The last name read from the file.</param>
/// <returns>Returns true to continue reading, false to stop.</returns>
typedef bool (*FNameRead)(
const int aIndex,
const int aTotalCount,
const std::string& aFirstName,
const std::string& aLastName
);
/// <summary>
/// Use this function to read names from a specified file and process them using a callback function.
/// </summary>
/// <function>readNamesFromFile</function>
/// <description>Reads names from a specified file and invokes a callback for each name read.</description>
/// <param name="aFilename">The path to the file containing names.</param>
/// <param name="aOnNameRead">A callback function that is called for each name read. It takes two parameters: firstName and lastName. If the callback returns false, the reading process stops.</param>
/// <param name="firstName">The first name read from the file.</param>
/// <param name="lastName">The last name read from the file.</param>
/// <returns>None.</returns>
void readNamesFromFile(const std::string& aFilename, FNameRead aOnNameRead);
/// <summary>
/// Delegate type for processing a node read from the file.
/// </summary>
/// <description>Function pointer type for a callback that processes nodes read from a file.</description>
/// <param name="aIndex">The index of the node (0-based).</param>
/// <param name="aTotalCount">The total number of nodes.</param>
/// <param name="aNode">The node std::string.</param>
/// <returns>Returns true to continue reading, false to stop.</returns>
typedef bool (*FNodeRead)(const int aIndex, const int aTotalCount, const std::string& aNode);
/// <summary>
/// Delegate type for processing an edge read from the file.
/// </summary>
/// <description>Function pointer type for a callback that processes edges read from a file.</description>
/// <param name="aIndex">The index of the edge (0-based).</param>
/// <param name="aTotalCount">The total number of edges.</param>
/// <param name="aFromNode">The from node std::string.</param>
/// <param name="aToNode">The to node std::string.</param>
/// <param name="aWeight">The weight of the edge.</param>
/// <returns>Returns true to continue reading, false to stop.</returns>
typedef bool (*FEdgeRead)(const int aIndex, const int aTotalCount, const std::string& aFromNode, const std::string& aToNode, float aWeight);
/// </summary>
/// Use this function to read a graph from a specified file and process its nodes and edges using callback functions.
/// </summary>
/// <function>readGraphFromFile</function>
/// <description>
/// Reads a graph from a specified file and invokes callbacks for each node and edge read.
/// All nodes are read first, followed by edges.
/// </description>
/// <param name="aFilename">The path to the file containing the graph data.</param>
/// <param name="aOnNodeRead">A callback function that is called for each node read. It takes one parameter: the node std::string. If the callback returns false, the reading process stops.</param>
/// <param name="aOnEdgeRead">A callback function that is called for each edge read. It takes three parameters: the fromNode std::string, the toNode std::string, and the weight float. If the callback returns false, the reading process stops.</param>
void readGraphFromFile(const std::string& aFilename, FNodeRead aOnNodeRead, FEdgeRead aOnEdgeRead);
/// <summary>
/// Delegate type for processing a song read from the file.
/// </summary>
/// <param name="aIndex">The index of the song (0-based).</param>
/// <param name="aTotalCount">The total number of songs.</param>
/// <param name="aArtist">The artist.</param>
/// <param name="aTitle">The title.</param>
/// <param name="aYear">The release year (as a std::string).</param>
/// <param name="aGenre">The genre.</param>
/// <param name="aSource">The source.</param>
/// <returns>Returns true to continue reading, false to stop.</returns>
typedef bool (*FSongRead)(
const int aIndex,
const int aTotalCount,
const std::string& aArtist,
const std::string& aTitle,
const std::string& aYear,
const std::string& aGenre,
const std::string& aSource
);
/// <summary>
/// Reads song data from a file and processes them using a callback.
/// This function automatically skips the "records:=" header.
/// </summary>
/// <param name="aFilename">The path to the file (e.g., "songs.txt").</param>
/// <param name="aOnSongRead">The callback function called for each song.</param>
void ReadSongsFromFile(const std::string& aFilename, FSongRead aOnSongRead);
#endif // SHARED_LIB_H

View File

@@ -0,0 +1,82 @@
#include "Sort.h"
int CompareByLastName(const TBankAccount* a, const TBankAccount* b)
{
if (a == b)
return 0;
if (!a)
return -1;
if (!b)
return 1;
if (a->ownerLastName < b->ownerLastName)
return -1;
if (a->ownerLastName > b->ownerLastName)
return 1;
if (a->ownerFirstName < b->ownerFirstName)
return -1;
if (a->ownerFirstName > b->ownerFirstName)
return 1;
return 0;
}
int CompareByBalanceAsc(const TBankAccount* a, const TBankAccount* b)
{
if (a == b)
return 0;
if (!a)
return -1;
if (!b)
return 1;
if (a->getBalance() < b->getBalance())
return -1;
if (a->getBalance() > b->getBalance())
return 1;
return 0;
}
static int CmpWrap(FCompareAccounts cmp, TBankAccount* a, TBankAccount* b, OperationSummary& s)
{
++s.comparisons;
return cmp(a, b);
}
static void SwapPointers(TBankAccount* a, TBankAccount* b, OperationSummary* s)
{
std::swap(a, b);
++s->swaps;
}
Sort::Sort(TBankAccount **sourceArray, int count, TLinkedList *sourceList)
: m_array(sourceArray), m_count(count), m_list(sourceList){}
TBankAccount **Sort::CloneArray() const
{
if (!m_array || m_count == 0)
return nullptr;
auto** copy = new TBankAccount*[m_count];
for (int i = 0; i < m_count; i++)
copy[i] = m_array[i];
return copy;
}
static TLinkedList* g_cloneTarget = nullptr;
static void AppendToClone(TBankAccount* acc, int)
{
if (g_cloneTarget)
g_cloneTarget->Append(acc);
}
TLinkedList *Sort::CloneList() const
{
if (!m_list)
return nullptr;
auto* copy = new TLinkedList(false);
m_list->forEach(AppendToClone);
g_cloneTarget = copy;
return copy;
}

View File

@@ -0,0 +1,53 @@
#pragma once
#include "BankAccount.h"
#include "BankAccountList.h"
typedef int (*FCompareAccounts)(TBankAccount* a, TBankAccount* b);
struct OperationSummary {
long long comparisons = 0;
long long swaps = 0;
double timeSpentInMs = 0.0;
void Reset()
{
comparisons = 0;
swaps = 0;
timeSpentInMs = 0.0;
}
};
class Sort {
public:
Sort(TBankAccount** sourceArray, int count, TLinkedList* sourceList);
TBankAccount** GetArray() const
{
return m_array;
}
int GetCount() const
{
return m_count;
}
TLinkedList* GetList() const
{
return m_list;
}
TBankAccount** CloneArray() const;
TLinkedList* CloneList() const;
TBankAccount** SelectionSortArray(FCompareAccounts cmp, OperationSummary& out);
TLinkedList* SelectionSortList(FCompareAccounts cmp, OperationSummary& out);
TBankAccount** BubbleSortArray(FCompareAccounts cmp, OperationSummary& out);
TBankAccount** QuickSortArray(FCompareAccounts cmp, OperationSummary& out);
TLinkedList* MergeSortList(FCompareAccounts cmp, OperationSummary& out);
private:
TBankAccount** m_array = nullptr;
int m_count = 0;
TLinkedList* m_list = nullptr;
};

View File

@@ -0,0 +1,4 @@
#include <bits/stl_tree.h>
#include "SharedLib.h"

View File

@@ -1,7 +1,26 @@
#include <iostream>
#include "main.h"
#include "SharedLib.h"
static TLinkedList g_list(false);
static std::vector<TBankAccount*> g_array;
static bool onNameRead(const int idx, const int total, const std::string& first, const std::string& last)
{
auto* acc = new TBankAccount(EBankAccountType::Checking, first, last);
g_list.Append(acc);
g_array.push_back(acc);
return true;
}
int main()
{
std::cout << "Hello, World!" << std::endl;
readNamesFromFile("random_names.txt", onNameRead);
Sort sorter(g_array.data(), (int)g_array.size(), &g_list);
return 0;
}

View File

@@ -0,0 +1,6 @@
#include <iostream>

File diff suppressed because it is too large Load Diff