From df8429d811af30d923db1b7c8377b60602c722aa Mon Sep 17 00:00:00 2001 From: Boyan Date: Mon, 8 Apr 2024 22:28:01 +0200 Subject: [PATCH] Fix bug with multiple file upload. Fixed bug with printing the same TC number. Updated docs to reflect on submit implementation. --- docs/api.md | 17 ++++- src/ExerciseGroup.py | 47 ++++++++----- src/main.py | 25 +++++++ src/suitcase.py | 28 ++++++++ src/texteditor.c | 159 +++++++++++++++++++++++++++++++++++++++++++ src/texteditor.h | 14 ++++ 6 files changed, 272 insertions(+), 18 deletions(-) create mode 100644 src/main.py create mode 100644 src/suitcase.py create mode 100644 src/texteditor.c create mode 100644 src/texteditor.h diff --git a/docs/api.md b/docs/api.md index 91de2a3..a113413 100644 --- a/docs/api.md +++ b/docs/api.md @@ -134,8 +134,21 @@ Downloads all test cases in the exercise group to a directory `path`. Defaults t ``` #### `submit(files)` -Submits the files to the exercise group. (This is not implemented yet) +Submits the files to the exercise group. Default arguments are `judge=True`, `wait=True` and `silent=True`. `judge` will judge the submission instantly, and `wait` will wait for the submission to finish. Turning off `silent` will print the submission status dynamically. ```python - assignment.submit(["file1.py", "file2.py"]) + suitcase[7].exercises[1].submit("suitcase.py", silent=False) + + >>> 1: ✅ + >>> 2: ✅ + >>> 3: ✅ + >>> 4: ✅ + >>> 5: ✅ + >>> 6: ✅ + >>> 7: ✅ + >>> 8: ✅ + >>> 9: ✅ + >>> 10: ✅ ``` + + diff --git a/src/ExerciseGroup.py b/src/ExerciseGroup.py index e6203c0..6b53b77 100644 --- a/src/ExerciseGroup.py +++ b/src/ExerciseGroup.py @@ -118,38 +118,57 @@ class ExerciseGroup: return None return [ - ExerciseGroup(f"https://themis.housing.rug.nl{x['href']}", x, session, self) + ExerciseGroup(f"https://themis.housing.rug.nl{x['href']}", x, self.session, self) for x in folders ] - def __parseTable(self, soup, url): + # Account for judge + def __raceCondition(self, soup, url:str, verbose:bool): + self.session.get(url.replace("submission", "judge")) + return self.__waitForResult(url, verbose, []) + + def __parseTable(self, soup, url:str, verbose:bool, __printed:list): cases = soup.find_all('tr', class_='sub-casetop') fail_pass = {} i = 1 for case in cases: + name = case.find('td', class_='sub-casename').text status = case.find('td', class_='status-icon') + + if "pending" in status.get("class"): + return self.__raceCondition(soup,url,verbose) + # queued status-icon if "queued" in status.get("class"): sleep(1) # <- 🗿 - return self.__waitForResult(url) + return self.__waitForResult(url, verbose, __printed) + if "Passed" in status.text: - fail_pass[i] = True + fail_pass[int(name)] = True + if int(name) not in __printed: + print(f"{name}: ✅") elif "Wrong output" in status.text: - fail_pass[i] = False + fail_pass[int(name)] = False + if int(name) not in __printed: + print(f"{name}: ❌") elif ("No status" or "error") in status.text: - fail_pass[i] = None + fail_pass[int(name)] = None + if int(name) not in __printed: + print(f"{name}:🐛") + + __printed.append(int(name)) i += 1 return fail_pass - def __waitForResult(self, url): + def __waitForResult(self, url:str, verbose:bool, __printed:list): # This waits for result and returns a bundled info package r = self.session.get(url) soup = BeautifulSoup(r.text, "lxml") - return self.__parseTable(soup, url) + return self.__parseTable(soup, url, verbose, __printed) # Submit - def submit(self, files: list, judge=True, wait=True): + def submit(self, files: list, judge=True, wait=True, silent=True): # Find the form with submit and store the action as url # Store then the data-suffixes as file_types - dictionary @@ -188,13 +207,9 @@ class ExerciseGroup: # Close each file i = 0 for f in packaged_files: - if i == 1: - f[1].close() - i = 0 - else: - i += 1 - + f[1][1].close() + if not wait: return resp.url if "@submissions" in resp.url else None - return self.__waitForResult(resp.url) + return self.__waitForResult(resp.url, not silent, []) diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..9f91e78 --- /dev/null +++ b/src/main.py @@ -0,0 +1,25 @@ +from Themis import Themis +def main(): + # Debug + themis = Themis("s5230837","Bobit0Drog@231") + year = themis.getYear(2023, 2024) + + # pf = year.getCourse("Programming Fundamentals (for CS)") + # pf = pf.getExerciseGroups() + # print(pf[1].exercises[1].submit("main.c")) # <- this should throw error + + # no_folders = year.getCourse("Computer Architecture") + # ca_ass = no_folders.getExerciseGroups() + ai = year.getCourse("Imperative Programming (for AI)") + ai = ai.getExerciseGroups() + print(ai[7].exercises[1].submit("suitcase.py", silent=False)) + + ads = year.getCourse("Algorithms and Data Structures for CS") + ads = ads.getExerciseGroups() + # print(ads[0].folders) + print(ads[0].folders[5].folders[0].exercises[0].submit(["texteditor.c", "texteditor.h"], silent=False)) + # for ass in ca_ass: + # print(ass.exercises) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/suitcase.py b/src/suitcase.py new file mode 100644 index 0000000..7f5aa45 --- /dev/null +++ b/src/suitcase.py @@ -0,0 +1,28 @@ +def suitcase(maxVolume, sizes, values, n): + + dp = [[0 for _ in range(maxVolume + 1)] for _ in range(n + 1)] + + for i in range(1, n + 1): + for j in range(1, maxVolume + 1): + if sizes[i - 1] <= j: + dp[i][j] = max(values[i - 1] + dp[i - 1][j - sizes[i - 1]], dp[i - 1][j]) + else: + dp[i][j] = dp[i - 1][j] + + return dp[n][maxVolume] + +def main(): + n, maxVolume = map(int, input().split()) + sizes = [] + values = [] + + for _ in range(n): + item, size, value = input().split() + sizes.append(int(size)) + values.append(int(value)) + + maxSatisfaction = suitcase(maxVolume, sizes, values, n) + print(maxSatisfaction) + +if __name__ == "__main__": + main() diff --git a/src/texteditor.c b/src/texteditor.c new file mode 100644 index 0000000..b658edb --- /dev/null +++ b/src/texteditor.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include "EditOperation.h" +#include "texteditor.h" +#include "LibStack.h" + +TextEditor* createTextEditor(void) { + TextEditor *editor = malloc(sizeof(*editor)); + // Don't forget to initialize the data structure(s) here + editor->text = malloc(10 * sizeof(*editor->text)); + editor->length = 0; + editor->capacity = 10; + return editor; +} + +// Think this is correct +void insertCharacter(TextEditor* editor, int pos, char character) { + // Implement the insert operation + if (editor->length == editor->capacity) { + editor->text = realloc(editor->text, 2 * editor->capacity * sizeof(*editor->text)); + editor->capacity *= 2; + } + // Shift all characters to the right + for (int i = editor->length; i > pos; i--) { + editor->text[i] = editor->text[i - 1]; + } + editor->text[pos] = character; + editor->length++; +} + + +// This too +void deleteCharacter(TextEditor* editor, int pos) { + // Implement the delete operation + if (editor->length == 0) { + return; + } + // Shift all characters to the left + for (int i = pos; i < editor->length - 1; i++) { + editor->text[i] = editor->text[i + 1]; + } + editor->length--; +} + +// The issue lies within the mem allocation of the stacks +void undo(TextEditor* editor, Stack* undoStack, Stack* redoStack) { + // Optional for the bonus exercise + if (isEmptyStack(*undoStack)) { + return; + } + EditOperation operation = pop(undoStack); + if (operation.type == INSERT) { + deleteCharacter(editor, operation.position); + } else { + insertCharacter(editor, operation.position, operation.character); + } + push(operation, redoStack); +} + +void redo(TextEditor* editor, Stack* undoStack, Stack* redoStack) { + // Optional for the bonus exercise + if (isEmptyStack(*redoStack)) { + return; + } + EditOperation operation = pop(redoStack); + if (operation.type == INSERT) { + insertCharacter(editor, operation.position, operation.character); + } else { + deleteCharacter(editor, operation.position); + } + push(operation, undoStack); +} + +void destroyTextEditor(TextEditor* editor) { + // Free the memory allocated for the data structure(s) + free(editor->text); + free(editor); +} + +void printText(TextEditor* editor) { + // Handle empty case + if (editor->length == 0) { + printf("EMPTY\n"); + return; + } + + // Print the text stored in the editor + for (int i = 0; i < editor->length; i++) { + printf("%c", editor->text[i]); + } + printf("\n"); +} + +int main(int argc, char *argv[]) { + + TextEditor* editor = createTextEditor(); + char command; + int pos; + char character; + + // Initialize stacks + Stack undoStack; + Stack redoStack; + undoStack = newStack(1); + redoStack = newStack(1); + + while(1) { + scanf(" %c", &command); + switch (command) { + // Insert a character at a given position + case 'i': + scanf("%d %c", &pos, &character); + insertCharacter(editor, pos, character); + EditOperation operation = {INSERT, character, pos}; + + // Stack operations + doubleStackSize(&undoStack); + push(operation, &undoStack); + break; + // Delete a character at a given position + case 'd': + scanf("%d", &pos); + character = editor->text[pos]; + deleteCharacter(editor, pos); + EditOperation operation1 = {DELETE, character, pos}; + + doubleStackSize(&undoStack); + push(operation1, &undoStack); + break; + // Undo the last operation + case 'u': + undo(editor, &undoStack, &redoStack); + break; + // Redo the last operation + case 'r': + redo(editor, &undoStack, &redoStack); + break; + // Print and quit + case 'q': + printText(editor); + destroyTextEditor(editor); + freeStack(undoStack); + freeStack(redoStack); + return 0; + // Unknown command + default: + printf("Unknown command.\n"); + break; + } + + } + + + + + return 0; +} + diff --git a/src/texteditor.h b/src/texteditor.h new file mode 100644 index 0000000..04ebccc --- /dev/null +++ b/src/texteditor.h @@ -0,0 +1,14 @@ +#ifndef TEXTEDITOR_H +#define TEXTEDITOR_H + +#include "LibStack.h" + +typedef struct TextEditor { + // Store the data structure in here + char *text; + int length; + int capacity; +} TextEditor; + +#endif +