Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor UI Improvements #48

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions base.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "absl/base/port.h"

#if defined(_MSC_FULL_VER) || defined(_MSC_VER) || defined(__MINGW32__)
Expand Down Expand Up @@ -43,6 +44,19 @@ inline char awaitKeyFromUser() {
return getchar();
}

/*-------------------------------------------------------------------
* Function: exitWithUserAcknowledgement
*
* Prints the given message, asks the user to press enter (not any
* key due to typical line-buffered input), and once the message has
* been acknowledged, exits with a non-zero status.
-------------------------------------------------------------------*/
inline void exitWithUserAcknowledgement(const char *const message) {
printf("%sPress ENTER to exit.\n", message);
awaitKeyFromUser();
exit(1);
}

/*-------------------------------------------------------------------
* Function : checkMallocFailed
* Inputs : void* p
Expand All @@ -55,9 +69,6 @@ inline char awaitKeyFromUser() {
-------------------------------------------------------------------*/
inline void checkMallocFailed(const void* const p) {
if (ABSL_PREDICT_FALSE(p == NULL)) {
printf("Fatal error! Ran out of heap memory.\n");
printf("Press enter to quit.\n");
awaitKeyFromUser();
exit(1);
exitWithUserAcknowledgement("Fatal error! Ran out of heap memory.\n");
}
}
79 changes: 49 additions & 30 deletions calculator.c
Original file line number Diff line number Diff line change
Expand Up @@ -1249,10 +1249,7 @@ void reallocateRecipes(BranchPath* newRoot, const enum Type_Sort* rearranged_rec
}
else {
if (indexItem2 < 0) {
printf("Fatal error! indexItem2 was not set in a branch where it should have.\n");
printf("Press enter to quit.");
awaitKeyFromUser();
exit(1);
exitWithUserAcknowledgement("Fatal error! indexItem2 was not set in a branch where it should have.\n");
}
// Two ingredients to navigate to, but order matters
// Pick the larger-index number ingredient first, as it will reduce
Expand Down Expand Up @@ -1619,19 +1616,48 @@ Inventory getSortedInventory(Inventory inventory, enum Action sort) {
return inventory;
}

/*-------------------------------------------------------------------
* Function: takeNumericInputInRange
*
* Take a number from stdin, reprompting if it is misformatted or
* not between minimum and maximum, inclusive.
-------------------------------------------------------------------*/
int takeNumericInputInRange(int minimum, int maximum) {
char userResponse[40];
// Keep asking forever until a valid input is given.
while (1) {
if (fgets(userResponse, sizeof(userResponse), stdin) != NULL) {
// If the response was too long, go ahead and clear anything else
// that was typed on that line.
if (strchr(userResponse, '\n') == NULL) {
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
else {
int value;
// Parse the response as an integer and check that it is in the
// required range.
if (sscanf(userResponse, "%d", &value) == 1
&& value >= minimum && value <= maximum)
return value;
}
}
printf("Invalid value. Enter a number %d to %d. ", minimum, maximum);
}
}

/*-------------------------------------------------------------------
* Function : logIterations
*
* Print out information to the user about how deep we are and
* the frame cost at this point after a certain number of iterations.
* Print out information to the user about how far we are in the
* current branch.
-------------------------------------------------------------------*/
void logIterations(int ID, int stepIndex, const BranchPath * curNode, int iterationCount, int level)
void logIterations(int ID, int iterationCount, int level)
{
char callString[30];
char iterationString[100];
sprintf(callString, "Call %d", ID);
sprintf(iterationString, "%d steps currently taken, %d frames accumulated so far; %dk iterations",
stepIndex, curNode->description.totalFramesTaken, iterationCount / 1000);
char iterationString[50];
sprintf(callString, "Thread %d", ID+1);
sprintf(iterationString, "Explored %dk iterations", iterationCount / 1000);
recipeLog(level, "Calculator", "Info", callString, iterationString);
}

Expand All @@ -1646,8 +1672,9 @@ void logIterations(int ID, int stepIndex, const BranchPath * curNode, int iterat
-------------------------------------------------------------------*/
Result calculateOrder(const int ID) {
enum SelectionMethod selectionMethod = getConfigInt("selectionMethod");
// When performing in-order traversal, we never want to restart.
int freeRunning = selectionMethod == InOrder;
// When performing in-order or manual traversal, we never want to restart.
bool noRestart = selectionMethod == InOrder || selectionMethod == Manual;
bool freeRunning = false;
int branchInterval = getConfigInt("branchLogInterval");
int total_dives = 0;
BranchPath *curNode = NULL; // Deepest node at any particular point
Expand All @@ -1663,27 +1690,25 @@ Result calculateOrder(const int ID) {
if (askedToShutdown()) {
break;
}
int stepIndex = 0;
int iterationCount = 0;
int iterationLimit = DEFAULT_ITERATION_LIMIT;

// Create root of tree path
curNode = initializeRoot();
root = curNode; // Necessary when printing results starting from root

total_dives++;

if (total_dives % branchInterval == 0) {
if (total_dives % branchInterval == 0 && !noRestart) {
char temp1[30];
char temp2[75];
sprintf(temp1, "Thread %d", ID);
sprintf(temp2, "Iteration Limit Reached: Backing Out and Searching New Branch %d", total_dives);
sprintf(temp1, "Thread %d", ID+1);
sprintf(temp2, "Searching new random branch (%d searched so far)", total_dives);
recipeLog(3, "Calculator", "Info", temp1, temp2);
}
total_dives++;

// If the user is not exploring only one branch, reset when it is time
// Start iteration loop
while (iterationCount < iterationLimit || freeRunning) {
while (iterationCount < iterationLimit || noRestart) {
if (checkShutdownOnIndex(iterationCount)) {
break;
}
Expand Down Expand Up @@ -1735,7 +1760,6 @@ Result calculateOrder(const int ID) {
curNode = curNode->prev;
freeAndShiftLegalMove(curNode, 0);
curNode->next = NULL;
stepIndex--;
continue;
}
// End condition not met. Check if this current level has something in the event queue
Expand Down Expand Up @@ -1794,7 +1818,6 @@ Result calculateOrder(const int ID) {
curNode = curNode->prev;
freeAndShiftLegalMove(curNode, 0);
curNode->next = NULL;
stepIndex--;
continue;
}

Expand All @@ -1810,8 +1833,7 @@ Result calculateOrder(const int ID) {
fprintf(fp, "%d - Run freely\n", curNode->numLegalMoves);

printf("Which move would you like to perform? ");
int moveToExplore;
ABSL_ATTRIBUTE_UNUSED int ignored = scanf("%d", &moveToExplore); // For now, we are going to blindly assume it was written.
int moveToExplore = takeNumericInputInRange(0, curNode->numLegalMoves);
fprintf(fp, "\n");

if (moveToExplore == curNode->numLegalMoves) {
Expand All @@ -1832,7 +1854,6 @@ Result calculateOrder(const int ID) {

curNode->next = curNode->legalMoves[0];
curNode = curNode->next;
stepIndex++;

}
else {
Expand All @@ -1849,7 +1870,6 @@ Result calculateOrder(const int ID) {
curNode = curNode->prev;
freeAndShiftLegalMove(curNode, 0);
curNode->next = NULL;
stepIndex--;
continue;
}

Expand All @@ -1861,16 +1881,15 @@ Result calculateOrder(const int ID) {
// Once the list is generated, choose the top-most (quickest) path and iterate downward
curNode->next = curNode->legalMoves[0];
curNode = curNode->legalMoves[0];
stepIndex++;

// Logging for progress display
iterationCount++;
if (iterationCount % (branchInterval * DEFAULT_ITERATION_LIMIT) == 0
&& (freeRunning || iterationLimit != DEFAULT_ITERATION_LIMIT)) {
logIterations(ID, stepIndex, curNode, iterationCount, 3);
&& (noRestart || iterationLimit != DEFAULT_ITERATION_LIMIT)) {
logIterations(ID, iterationCount, 3);
}
else if (iterationCount % 10000 == 0) {
logIterations(ID, stepIndex, curNode, iterationCount, 6);
logIterations(ID, iterationCount, 6);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions calculator.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ BranchPath* initializeRoot();

// Other
void periodicGithubCheck();
int takeNumericInputInRange(int minimum, int maximum);
Result calculateOrder(const int ID);
void writePersonalBest(Result *result);
void shutdownCalculator();
Expand Down
15 changes: 4 additions & 11 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@ void initConfig() {
// This covers the case where it is missing or in the wrong folder.
// If it's a permission problem, a user who created that problem should
// be able to figure it out based on this as well.
printf("Could not read config.txt file. Please ensure that the file is "
"in the same folder as the program.\n");
printf("Press ENTER to exit.");
awaitKeyFromUser();
exit(1);
exitWithUserAcknowledgement("Could not read config.txt file. Please "
"ensure that the file is in the same folder as the program.\n");
}
// Now, parse the file to use throughout the program's lifetime.
config = malloc(sizeof(config_t));
Expand All @@ -36,9 +33,7 @@ void initConfig() {
printf("Could not read settings in config.txt file. Please ensure that "
"the file is formatted correctly. Error occurred at line %d.\n",
config_error_line(config));
printf("Press ENTER to exit.");
awaitKeyFromUser();
exit(1);
exitWithUserAcknowledgement("");
}
fclose(fp);
}
Expand Down Expand Up @@ -193,9 +188,7 @@ void validateConfig() {
validateIntSettingMax("selectionMethod", Manual, &errors);

if (errors) {
printf("Press ENTER to exit.\n");
awaitKeyFromUser();
exit(1);
exitWithUserAcknowledgement("");
}
}

Expand Down
7 changes: 2 additions & 5 deletions logger.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,10 @@ int recipeLog(int level, char *process, char *subProcess, char *activity, char *
char data[200];
sprintf(date, "[%d-%02d-%02d %02d:%02d:%02d]", year, month, day, hours, mins, secs);
sprintf(data, "[%s][%s][%s][%s]\n", process, subProcess, activity, entry);
printf("%s", date);
printf("%s", data);
printf("%s%s", date, data);

FILE* fp = fopen("recipes.log", "a");
fputs(date, fp);
fputs(data, fp);

fprintf(fp, "%s%s", date, data);
fclose(fp);
}
return 0;
Expand Down
4 changes: 1 addition & 3 deletions node_print.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,7 @@ void printResults(const char *filename, const BranchPath *path) {
FILE *fp = fopen(filename, "w");
if (fp == NULL) {
printf("Could not locate %s... This is a bug.\n", filename);
printf("Press ENTER to exit.\n");
awaitKeyFromUser();
exit(1);
exitWithUserAcknowledgement("");
}
// Write header information
printFileHeader(fp);
Expand Down
68 changes: 68 additions & 0 deletions shutdown.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
#include "shutdown.h"
#include "base.h"

#if _IS_WINDOWS
#include <windows.h>
#else
#include <signal.h>
#endif

bool _askedToShutdownVar = false;

Expand All @@ -8,3 +15,64 @@ bool requestShutdown() {
return oldVal;
}

int numTimesExitRequest = 0;
#define NUM_TIMES_EXITED_BEFORE_HARD_QUIT 3

void countAndSetShutdown(bool isSignal) {
// On Windows, it is undefined behavior trying to use stdio.h functions in a signal handler (which this is called from).
// So for now, these messages are stifled on Windows. This may be revisited at a later point.
if (++numTimesExitRequest >= NUM_TIMES_EXITED_BEFORE_HARD_QUIT) {
if (!_IS_WINDOWS || !isSignal) {
printf("\nExit reqested %d times; shutting down now.\n", NUM_TIMES_EXITED_BEFORE_HARD_QUIT);
}
exit(1);
}
else {
requestShutdown();
if (!_IS_WINDOWS || !isSignal) {
printf("\nExit requested, finishing up work. Should shutdown soon (CTRL-C %d times total to force exit)\n", NUM_TIMES_EXITED_BEFORE_HARD_QUIT);
}
}
}

#if _IS_WINDOWS
BOOL WINAPI windowsCtrlCHandler(DWORD fdwCtrlType) {
switch (fdwCtrlType) {
// For these events, returning TRUE is sufficient to prevent shutdown, so
// we can simply inform the threads to shut down.
case CTRL_C_EVENT: ABSL_FALLTHROUGH_INTENDED;
case CTRL_BREAK_EVENT:
countAndSetShutdown(false);
return TRUE;
// Returning TRUE for a CTRL_CLOSE_EVENT results in instant termination, so
// we have to wait until the threads are done.
case CTRL_CLOSE_EVENT:
countAndSetShutdown(false);
// Note that this does not cause closing to take 5 seconds. The program
// will actually shut down when main returns. 5 seconds is just the max
// time we could delay shutdown.
Sleep(5000);
return TRUE;
// CTRL_LOGOFF_EVENT and CTRL_SHUTDOWN_EVENT are not sent to interactive
// applications, only to services. Thus, there is no behavior to add in
// here.
default:
return FALSE;
}
}
#else
void handleTermSignal(int signal) {
countAndSetShutdown(true);
}
#endif

void setSignalHandlers() {
#if _IS_WINDOWS
if (!SetConsoleCtrlHandler(windowsCtrlCHandler, TRUE)) {
printf("Unable to set CTRL-C handler. CTRL-C may cause unclean shutdown.\n");
}
#else
signal(SIGTERM, handleTermSignal);
signal(SIGINT, handleTermSignal);
#endif
}
2 changes: 1 addition & 1 deletion shutdown.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

extern bool _askedToShutdownVar;

bool requestShutdown();
void setSignalHandlers();

ABSL_ATTRIBUTE_ALWAYS_INLINE inline bool askedToShutdown() {
return ABSL_PREDICT_FALSE(_askedToShutdownVar);
Expand Down
Loading