commit f9cd6248ec8970fbff3ead9cad60fed53102ae0a Author: Nanokloon Date: Sat Jun 14 23:26:42 2025 +0200 all diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..cc864a9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.30) +project(c C) + +set(CMAKE_C_STANDARD 17) +set(INCLUDE_DIRECTORIES ./) +include_directories() + +add_executable(stack_test stack/stack.c stack/stack.h stack/stack_test.c + cell/cell.c + cell/cell.h) + +add_executable(maze-nolib + leelib/leelib.c + leelib/leelib.h + stack/stack.c + stack/stack.h + lee-algorithm/lee-algorithm.c + lee-algorithm/lee-algorithm.h + cell/cell.c + cell/cell.h + robot/robot.c + robot/robot.h + robot/simple-simulator.c + main.c + robot/simulator-moves.c + robot/challenges/challenge2.c + robot/challenges/challenge3.c + robot/challenges/challenges.h + robot/challenges/challenge4.c) + +add_executable(maze-libsp + leelib/leelib.c + leelib/leelib.h + stack/stack.c + stack/stack.h + lee-algorithm/lee-algorithm.c + lee-algorithm/lee-algorithm.h + cell/cell.c + cell/cell.h + robot/robot.c + robot/robot.h + communication/communication.c + communication/communication.h + communication/utils.c + communication/utils.h + main.c + robot/controller-moves.c + robot/remote.c + robot/challenges/challenges.h + robot/challenges/challenge2.c + robot/challenges/challenge3.c + robot/challenges/challenge4.c) + +target_link_libraries(maze-libsp serialport m) +target_link_libraries(maze-nolib m) +target_link_libraries(stack_test m) diff --git a/Testing/Temporary/LastTest.log b/Testing/Temporary/LastTest.log new file mode 100644 index 0000000..20a4f99 --- /dev/null +++ b/Testing/Temporary/LastTest.log @@ -0,0 +1,3 @@ +Start testing: Jun 05 17:03 CEST +---------------------------------------------------------- +End testing: Jun 05 17:03 CEST diff --git a/cell/cell.c b/cell/cell.c new file mode 100644 index 0000000..1a8995b --- /dev/null +++ b/cell/cell.c @@ -0,0 +1,15 @@ +// +// Created by nano on 5/1/25. +// + +#include "cell.h" + +int cell_equals(cell a, cell b) { + return (a.x == b.x && a.y == b.y); +} + +void cell_add(cell *c, cell a, cell b) { + c->x = a.x + b.x; + c->y = a.y + b.y; +} + diff --git a/cell/cell.h b/cell/cell.h new file mode 100644 index 0000000..c5cd34c --- /dev/null +++ b/cell/cell.h @@ -0,0 +1,19 @@ +// +// Created by nano on 5/1/25. +// + +#ifndef CELL_H +#define CELL_H + + +typedef struct cell { + int x; + int y; +} cell; + +int cell_equals(cell a,cell b); +void cell_add(cell *c, cell a, cell b); + + + +#endif //CELL_H diff --git a/communication/communication.c b/communication/communication.c new file mode 100644 index 0000000..72bdf77 --- /dev/null +++ b/communication/communication.c @@ -0,0 +1,210 @@ +// +// Created by nano on 4/26/25. +// + +#include "communication.h" + +#include +#include +#include + + + + +struct sp_port *port; +struct sp_event_set *event_data_ready; +struct sp_event_set *event_ready_for_tx; + +/** + * Initializes the serial communication for the usb -> uart board + */ +void comm_init_communication() { + struct sp_port **port_list; + comm_get_port_list(&port_list); + int portnr = 0; + comm_list_serial_ports(port_list); + printf("Chose a port: "); + scanf("%d", &portnr); + sp_copy_port(port_list[portnr], &port); + sp_free_port_list(port_list); + comm_open_port(); +} + +void comm_get_port_list(struct sp_port ***port_list) { + enum sp_return result = sp_list_ports(port_list); + if (result != SP_OK) { + printf("Error listing serial ports\n"); + exit(-1); + } +} + +void comm_list_serial_ports(struct sp_port **port_list) { + printf("Port list:\n"); + for (int i = 0; port_list[i] != NULL; i++) { + char *port_name = sp_get_port_name(port_list[i]); + printf("Port %d: %s\n", i, port_name); + } +} +/** + * Opens communication to the selected serial port and sets the correct parameters for the zigbee carrier board. + * Also add event to see when data arrives. + */ +void comm_open_port() { + + check(sp_open(port, SP_MODE_READ_WRITE)); + check(sp_set_baudrate(port, 9600)); + check(sp_set_bits(port, 8)); + check(sp_set_parity(port, SP_PARITY_NONE)); + check(sp_set_stopbits(port, 1)); + + check(sp_new_event_set(&event_data_ready)); + check(sp_new_event_set(&event_ready_for_tx)); + + sp_add_port_events(event_data_ready, port, SP_EVENT_RX_READY); + sp_add_port_events(event_ready_for_tx, port, SP_EVENT_TX_READY); +} + +/** + * Ends the serial communication for the usb -> uart board + */ +void comm_end_communication() { + check(sp_close(port)); + sp_free_port(port); +} + +/** + * Wait till there is data available. + * @param timeout how much time in ms to wait for the data + * @returns SP_OK if data is ready. + * @returns SP_ERR_FAIL if data was not available before timeout ended. + */ +int comm_await_data_ready(int timeout) { + // Await data from the robot + return sp_wait(event_data_ready, timeout); +} + +/** + * Wait till you can transmit again . + * @param timeout how much time in ms to wait for the data + * @returns SP_OK if data is ready. + * @returns SP_ERR_FAIL if uart module wasnt ready for transmit before timeout ended. + */ +int comm_await_ready_for_tx(int timeout) { + return sp_wait(event_ready_for_tx, timeout); +} + + +/** + * Read a number of bytes from the buffer, store them in data without blocking the process. + * @param data array where to store the data + * @param amount_of_bytes + * @return ALL_BYTES if the number of expected bytes was read + * @return NOT_ENOUGH_BYTES if read less than expected + * @return ERROR if read fails + */ +comm_result comm_nonblocking_read(byte *data, int amount_of_bytes) { + //read available data + int recv_bytes = sp_nonblocking_read(port, data, amount_of_bytes); + if (recv_bytes == amount_of_bytes) { + return ALL_BYTES; + } + if (recv_bytes >= 0) { + return NOT_ENOUGH_BYTES; + } + return ERROR; +} + +/** + * Read a number of bytes from the buffer, store them in data, with a number of ms to wait in case that amount of data is not available.. + * @param data array where to store the data + * @param amount_of_bytes + * @param timeout how much time in ms to wait for all data to be available. + * @return ALL_BYTES if the number of expected bytes was read + * @return NOT_ENOUGH_BYTES if read less than expected + * @return ERROR if read fails + */ +comm_result comm_blocking_read(byte *data, int amount_of_bytes, int timeout) { + //read available data + int recv_bytes = sp_blocking_read(port, data, amount_of_bytes, timeout); + printf("RECV: %d\n",*data); + if (recv_bytes == amount_of_bytes) { + return ALL_BYTES; + } + if (recv_bytes >= 0) { + return NOT_ENOUGH_BYTES; + } + return ERROR; +} + +/** + * Write a number of bytes to the buffer, from data, with a number of ms to wait in case that amount of data is not available.. + * @param data array where to store the data + * @param amount_of_bytes + * @param timeout how much time in ms to wait for all data to be available. + * @return ALL_BYTES if the number of expected bytes was read + * @return NOT_ENOUGH_BYTES if read less than expected + * @return ERROR if read fails + */ +comm_result comm_blocking_write(byte *data, int amount_of_bytes, int timeout) { + // we are writing 8 bit bytes to the fpga anyways and pc -> fpga only needs to tell what do to next, can be fit in 8 bits + int sent_bytes = sp_blocking_write(port, data, amount_of_bytes, timeout); + printf("SEND: %d \n",*data); + + if (sent_bytes == amount_of_bytes) { + return ALL_BYTES; + } + if (sent_bytes >= 0) { + return NOT_ENOUGH_BYTES; + } + return ERROR; +} + +/** + * Write a number of bytes to the buffer, from data. + * @param data array where to store the data + * @param amount_of_bytes + * @return ALL_BYTES if the number of expected bytes was read + * @return NOT_ENOUGH_BYTES if read less than expected + * @return ERROR if read fails + */ +comm_result comm_nonblocking_write(byte *data, int amount_of_bytes) { + // we are writing 8 bit bytes to the fpga anyways and pc -> fpga only needs to tell what do to next, can be fit in 8 bits + int sent_bytes = sp_nonblocking_write(port, data, amount_of_bytes); + if (sent_bytes == amount_of_bytes) { + return ALL_BYTES; + } + if (sent_bytes >= 0) { + return NOT_ENOUGH_BYTES; + } + return ERROR; +} + +//Check if bytes are left to be sent +int comm_output_waiting() { + return sp_output_waiting(port); +} + +/** Helper function for error handling. Taken from libserialport examples */ +int check(enum sp_return result) { + /* For this example we'll just exit on any error by calling abort(). */ + char *error_message; + switch (result) { + case SP_ERR_ARG: + printf("Error: Invalid argument.\n"); + abort(); + case SP_ERR_FAIL: + error_message = sp_last_error_message(); + printf("Error: Failed: %s\n", error_message); + sp_free_error_message(error_message); + abort(); + case SP_ERR_SUPP: + printf("Error: Not supported.\n"); + abort(); + case SP_ERR_MEM: + printf("Error: Couldn't allocate memory.\n"); + abort(); + case SP_OK: + default: + return result; + } +} diff --git a/communication/communication.h b/communication/communication.h new file mode 100644 index 0000000..0cb7d56 --- /dev/null +++ b/communication/communication.h @@ -0,0 +1,89 @@ +// +// Created by nano on 4/26/25. +// +#ifndef COMMS_H +#define COMMS_H +#include +#include + +typedef u_int8_t byte; + +typedef enum { ALL_BYTES, NOT_ENOUGH_BYTES, ERROR } comm_result; +int comm_output_waiting() ; +/** + * Initializes the serial communication for the usb -> uart board + */ +void comm_init_communication(); + +/** + * Generates port list from present serial ports. + * @param port_list pointer to port list to set. + */ +void comm_get_port_list(struct sp_port ***port_list); + +void comm_list_serial_ports(struct sp_port **port_list); + +/** + * Opens communication to the selected serial port and sets the correct parameters for the zigbee carrier board. + */ +void comm_open_port(); + +/** + * Ends the serial communication for the usb -> uart board + */ +void comm_end_communication(); + +/** + * Await fresh data from the serial port + * @param timeout timeout for waiting for a byte to be ready to read + * @return if there is data available (1 or 0) + */ +int comm_await_data_ready(int timeout); + +/** + * Check if the serial port is ready to be written to. + * @param timeout timeout for waiting for a byte to be ready to read + * @return if data can be written (1 or 0) + */ +int comm_await_ready_for_tx(int timeout); + +/** + *Do a nonblocking read from the serial port + *@param data pointer to data to read + *@param amount_of_bytes amount of bytes to read from uart buffer + *@return if whole buffer was filled, part of the buffer was filled or error + */ +comm_result comm_nonblocking_read(byte *data, int amount_of_bytes); + +/** + *Do a blocking read from the serial port + *@param data pointer to data to read + *@param amount_of_bytes amount of bytes to read from uart buffer + *@param timeout how long to wait for data to be filled + *@return if whole buffer was filled, part of the buffer was filled or error + */ +comm_result comm_blocking_read(byte *data, int amount_of_bytes, int timeout); + +/** + *Do a nonblocking write from the serial port + *@param data pointer to data to write + *@param amount_of_bytes amount of bytes to write to uart + *@return if whole buffer was written, part of the buffer was written or error + */ +comm_result comm_nonblocking_write(byte *data, int amount_of_bytes); + +/** + *Do a nonblocking write from the serial port + *@param data pointer to data to write + *@param amount_of_bytes amount of bytes to write to uart + *@param timeout how long to wait for data to be filled + *@return if whole buffer was written, part of the buffer was written or error + */ +comm_result comm_blocking_write(byte *data, int amount_of_bytes, int timeout); + +/** Helper function for error handling. + * Taken from libserialport examples. */ +int check(enum sp_return result); + + +#endif //COMMS_H diff --git a/communication/utils.c b/communication/utils.c new file mode 100644 index 0000000..6844024 --- /dev/null +++ b/communication/utils.c @@ -0,0 +1,122 @@ +// +// Created by nano on 4/26/25. +// + +#include + +#include "utils.h" + +#include + +#include "communication.h" + +#define ACK 16 +#define NOTHING_RECV 0 + +/**Helper functions to convert from bits to bytes*/ +void byte_to_bit_array(byte bit_array[], byte data) { + for (int i = 0; i < 8; i++) { + bit_array[i] = (data >> i) & 1; //shift through all bits and check if they're 1 + } +} + +/**2's complement notation*/ +void bit_array_to_byte(const byte bit_array[], byte *data) { + *data = 0; + byte currentpow = 1; + for (int i = 0; i < 8; i++) { + *data += bit_array[i] * currentpow; + currentpow *= 2; + } +} + +void comm_write_until_successful(byte d, int timeout) { + //while (comm_await_comm_awaready_for_tx(50)!=SP_OK) {} //wait indefinitely till you can send data + REWRITE: + comm_blocking_write(&d,1,timeout); + + byte data; + int counter =0; + REREAD: + while (comm_blocking_read(&data,1,timeout) != ALL_BYTES) {counter ++; if (counter == 10) goto REWRITE;} //idk if this does anything but the code works so im not touching it + + //data ? printf("RECV: %d \n",data) : 0; + counter++; + printf("Times Read %d",counter); + if (data == ACK) { + printf("ACK\n"); + } + else if (counter !=10) + goto REREAD; + else + goto REWRITE; +} + +#define CROSSING 0x20 + +/** + * await data from the robot + * @param data data gotten from robot + * @return 1 if correct, -1 if retry required + */ +int comm_await_crossing(int timeout){ + byte data; + int run =1; + printf("AWAITING CROSSING\n"); + while (run){ + comm_blocking_read(&data, 1,timeout); + printf("Read while expecting crossing: %d\n",data); + if (data==CROSSING) { + //printf("CROSSING\n"); + run=0; + return 1; + break; + } + } + return -1; +} + +#define SENSOR_NOTHING_AHEAD 5 +#define SENSOR_1_CROSSING_AHEAD 1 +#define SENSOR_2_CROSSING_AHEAD 2 +#define SENSOR_3_CROSSING_AHEAD 3 +#define SENSOR_4_CROSSING_AHEAD 4 + +int comm_get_distance_sensor(int *len, int timeout) { + byte *data = malloc(sizeof(byte)); + while (comm_blocking_read(data,1,timeout) == ALL_BYTES) { + printf("Got while expecting distance sensor: %d \n", *data); + switch (*data) { + case SENSOR_NOTHING_AHEAD: + *len=0; + free(data); + return 1; + break; + case SENSOR_1_CROSSING_AHEAD: + *len=1; + free(data); + return 1; + break; + case SENSOR_2_CROSSING_AHEAD: + *len=3; + free(data); + return 1; + break; + case SENSOR_3_CROSSING_AHEAD: + *len=5; + free(data); + return 1; + break; + case SENSOR_4_CROSSING_AHEAD: + *len=7; + free(data); + return 1; + break; + default: + printf("wat\n"); + break; + } + } + free(data); + return 0; +} \ No newline at end of file diff --git a/communication/utils.h b/communication/utils.h new file mode 100644 index 0000000..4dbeea9 --- /dev/null +++ b/communication/utils.h @@ -0,0 +1,20 @@ +// +// Created by nano on 4/26/25. +// +#include + + +#ifndef COMM_UTILS_H +#define COMM_UTILS_H +typedef u_int8_t byte; + +void byte_to_bit_array(byte *bit_array, byte data); + +void bit_array_to_byte(const byte bit_array[], byte *data); + +void comm_write_until_successful(byte d, int timeout); + +int comm_await_crossing(int timeout); + +int comm_get_distance_sensor(int *len, int timeout) ; +#endif //COMM_UTILS_H diff --git a/lee-algorithm/lee-algorithm.c b/lee-algorithm/lee-algorithm.c new file mode 100644 index 0000000..87e5672 --- /dev/null +++ b/lee-algorithm/lee-algorithm.c @@ -0,0 +1,148 @@ +#include +#include + +#include "lee-algorithm.h" + +#include "../stack/stack.h" +#include "../cell/cell.h" +#include "../communication/utils.h" +#include "../robot/robot.h" + + +// Maze en standaard Lee-functies + +int unexpanded_matrix[MAZE_SIZE][MAZE_SIZE] = { + { -1, -1, -1, 0, -1, 0, -1, 0, -1, -1, -1}, + { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, + { -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1}, + { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, + { -1, -1, -1, 0, -1, 0, -1, 0, -1, -1, -1,} +}; + +const cell neighbours[4] = {{-1, 0}, {0, 1}, {1,}, {0, -1}}; // NORTH EAST SOUTH WEST +const cell crossing_neighbours[4] = {{-2, 0}, {0, 2}, {2,0}, {0, -2}}; + +void lee_run(robot r, cell targetCell, stack *moves) { + int assignmentMatrix[MAZE_SIZE][MAZE_SIZE]; + memcpy(assignmentMatrix, unexpanded_matrix, sizeof(assignmentMatrix)); + lee_expand(assignmentMatrix, r.pos, targetCell); + lee_trace(assignmentMatrix, r, targetCell, moves); + stack_invert(moves); +} + +void lee_expand(int assignmentMatrix[MAZE_SIZE][MAZE_SIZE], cell startCell, cell targetCell) { + int v = 1; + assignmentMatrix[targetCell.x][targetCell.y] = v; + while (assignmentMatrix[startCell.x][startCell.y] == 0) { + for (int i = 0; i < MAZE_SIZE; i++) { + for (int j = 0; j < MAZE_SIZE; j++) { + if (assignmentMatrix[i][j] == v) { + for (int k = 0; k < 4; k++) { + cell neighbour; + cell_add(&neighbour, (cell){i, j}, neighbours[k]); + if (isInBound(neighbour) && assignmentMatrix[neighbour.x][neighbour.y] == 0) { + assignmentMatrix[neighbour.x][neighbour.y] = v + 1; + } + } + } + } + } + v += 1; + } +} + +void lee_trace(int assignmentMatrix[MAZE_SIZE][MAZE_SIZE], robot r, cell targetCell, stack *stack) { + robot tempBot = r; + printf("\n"); + while (!cell_equals(tempBot.pos, targetCell)) { + // check forward first,as its most efficient move + cell neighbourCell; + cell_add(&neighbourCell, tempBot.pos, neighbours[tempBot.dir]); + if (isInBound(neighbourCell) && + assignmentMatrix[neighbourCell.x][neighbourCell.y] > 0 && + assignmentMatrix[neighbourCell.x][neighbourCell.y] < assignmentMatrix[tempBot.pos.x][tempBot.pos.y]) { + tempBot.pos = neighbourCell; + //if (isValidCrossing(tempBot.pos) ) { + stack_push(stack, neighbours[tempBot.dir]); + //} + continue; + } + // check rest of directions + for (int i = 0; i < 4; i++) { + cell_add(&neighbourCell, tempBot.pos, neighbours[(tempBot.dir + i) % 4]); + //ugly calculation as to check all 3 other directions other than the main one + if (isInBound(neighbourCell) && + assignmentMatrix[neighbourCell.x][neighbourCell.y] > 0 && + assignmentMatrix[neighbourCell.x][neighbourCell.y] < assignmentMatrix[tempBot.pos.x][tempBot.pos.y]) { + tempBot.pos = neighbourCell; + spin(&r, tempBot.dir); + //if (isValidCrossing(tempBot.pos)) { + stack_push(stack, neighbours[(tempBot.dir + i) % 4]); + //} + break; + } + } + } +} + +int validatePath(robot r, stack s) { + robot temp = r; + for (int i = 0; i < s.length; i++) { + cell_add(&temp.pos, temp.pos,s.data[i]); + if (unexpanded_matrix[temp.pos.x][temp.pos.y] < 0) { + return 0; + } + } + return 1; +} + +extern int firstMove; +void followPath(robot *r, stack *path,int visited[MAZE_SIZE][MAZE_SIZE]) { + while (path->length > 0) { + cell currentCell = stack_pop(path); + int result = move(r,currentCell); + comm_await_crossing(2000); + comm_discard_sensor_data(1000); + visited[r->pos.x][r->pos.y] = 5; + if (result == 0) { + move(r,currentCell); + comm_await_crossing(2000); + comm_discard_sensor_data(1000); + visited[r->pos.x][r->pos.y] = 5; + } + printMatrix_with_current_pos(visited,*r); + } +} + +int isInBound(const cell c) { + if (c.x >= 0 && c.x < MAZE_SIZE && + c.y >= 0 && c.y < MAZE_SIZE) { + return 1; + } + return 0; +} + + +int isStation(const cell c) { + if (c.x == 0 || c.x == MAZE_SIZE - 1 || + c.y == 0 || c.y == MAZE_SIZE - 1){ + return 1; + } + return 0; + +} +int isValidCrossing(const cell c) { + if (c.x > 0 && c.x < MAZE_SIZE - 1 && + c.y > 0 && c.y < MAZE_SIZE - 1 && + c.x % 2 == 1 && c.y % 2 == 1 && + unexpanded_matrix[c.x][c.y]==0) { + return 1; + } + return 0; +} diff --git a/lee-algorithm/lee-algorithm.h b/lee-algorithm/lee-algorithm.h new file mode 100644 index 0000000..c54981b --- /dev/null +++ b/lee-algorithm/lee-algorithm.h @@ -0,0 +1,25 @@ +// +// Created by nano on 4/30/25. +// + +#ifndef LEE_ALGORITHM_H +#define LEE_ALGORITHM_H + +#include "../stack/stack.h" +#include "../robot/robot.h" + +#define MAZE_SIZE 11 + +void followPath(robot *r, stack *path,int visited[MAZE_SIZE][MAZE_SIZE]); + +void lee_run(robot r, cell targetCell, stack *moves); + +void lee_expand(int assignmentMatrix[MAZE_SIZE][MAZE_SIZE], cell startCell,cell targetCell) ; +void lee_trace(int assignmentMatrix[MAZE_SIZE][MAZE_SIZE], robot r, cell targetCell, stack *stack); + +int validatePath(robot r, stack s); + +int isInBound(cell c); +int isStation(cell c); +int isValidCrossing(cell c); +#endif //LEE_ALGORITHM_H diff --git a/leelib/leelib.c b/leelib/leelib.c new file mode 100644 index 0000000..1229a93 --- /dev/null +++ b/leelib/leelib.c @@ -0,0 +1,73 @@ +#include +#include + +#include "../lee-algorithm/lee-algorithm.h" + +void readEdge (int *i, int *j) +/* Scans input to read a blocked edge. + Returns the indices i and j in m[13][13] of an edge. + Call this function with pointers to the variables + that should receive the values, e.g. + readEdge (&x, &y); +*/ +{ + int cx, cy; + char d; + scanf ("%d %d %c", &cy, &cx, &d); + if (d == 's') { + *i = 2 + cy * 2 + 1; + *j = 2 + cx * 2; + } + else if (d == 'e') { + *i = 2 + cy * 2; + *j = 2 + cx * 2 + 1; + } + else { + fprintf (stderr, "error on direction: %c\n", d); + exit (1); + } +} + +void readStation (int *i, int *j) +/* Scans input to read a station. + Returns the indices i and j in m[13][13] of a station. + */ +{ + int s; + scanf ("%d", &s); + switch (s) { + case 1: *i = 10, *j = 3; break; + case 2: *i = 10, *j = 5; break; + case 3: *i = 10, *j = 7; break; + case 4: *i = 7, *j = 10; break; + case 5: *i = 5, *j = 10; break; + case 6: *i = 3, *j = 10; break; + case 7: *i = 0, *j = 7; break; + case 8: *i = 0, *j = 5; break; + case 9: *i = 0, *j = 3; break; + case 10: *i = 3, *j = 0; break; + case 11: *i = 5, *j = 0; break; + case 12: *i = 7, *j = 0; break; + default: fprintf (stderr, "Illegal station\n"); exit (-1); + } +} + +void printCrossingName (int i, int j) +/* Print the name of the crossing with indices i and j in m[13][13]/ */ +{ + if ((i-2)%2 == 0 && (j-2)%2 == 0) + printf ("c%d%d ", (i-2)/2, (j-2)/2); +} + +void printMatrix (int m[][MAZE_SIZE]) +/* Print the elements of the matrix m[13][13]. */ +{ + int i, j; + + for (i = 0; i < MAZE_SIZE; i++) { + for (j = 0; j < MAZE_SIZE; j++) { + printf ("%2d ", m[i][j]); + } + printf ("\n"); + } +} diff --git a/leelib/leelib.h b/leelib/leelib.h new file mode 100644 index 0000000..a7192f8 --- /dev/null +++ b/leelib/leelib.h @@ -0,0 +1,19 @@ +void readEdge (int *i, int *j); +/* Scans input to read a blocked edge. + Returns the indices i and j in m[13][13] of an edge. + Call this function with pointers to the variables + that should receive the values, e.g. + readEdge (&x, &y); +*/ + +void readStation (int *i, int *j); +/* Scans input to read a station. + Returns the indices i and j in m[13][13] of a station. + */ + +void printCrossingName (int i, int j); +/* Print the name of the crossing with indices i and j in m[13][13]/ */ + +void printMatrix (int m[][11]); +/* Print the elements of the matrix m[13][13]. */ + diff --git a/main.c b/main.c new file mode 100644 index 0000000..7b199db --- /dev/null +++ b/main.c @@ -0,0 +1,46 @@ +#include +#include +#include + +#include "cell/cell.h" +#include "communication/communication.h" +#include "leelib/leelib.h" +#include "robot/robot.h" +#include "robot/challenges/challenges.h" + +extern int unexpanded_matrix[MAZE_SIZE][MAZE_SIZE]; +extern int visited[MAZE_SIZE][MAZE_SIZE]; + +extern const cell neighbours[4]; + + +void addBlock(robot r, cell move, direction dir, cell targetCell, stack *s); + +int main(int argc, char *argv[]) { + /* read the starting and end station.*/ + if (argc < 2) { + printf("NOT ENOUGH ARGUMENTS \n"); + printf("USAGE: ./maze \n"); + return -1; + } + switch (strtol(argv[1],NULL, 10)) { + case 0: + simple_control(); + break; + case 2: + challenge_2(); + break; + case 3: + challenge_3((cell){10,3}); + break; + case 4: + challenge_4((cell){10,3}); + break; + default: + printf("DOESNT WORK YET \n"); + break; + } + + return 0; +} + diff --git a/maze-editor.html b/maze-editor.html new file mode 100644 index 0000000..6eba70b --- /dev/null +++ b/maze-editor.html @@ -0,0 +1,127 @@ + + + + + Maze Editor + + + +

Maze Editor

+
+ +
+ + + + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/robot/challenges/challenge2.c b/robot/challenges/challenge2.c new file mode 100644 index 0000000..a65b16d --- /dev/null +++ b/robot/challenges/challenge2.c @@ -0,0 +1,101 @@ +#include +#include +#include + +#include "../../communication/communication.h" +#include "../../leelib/leelib.h" +#include "../../lee-algorithm/lee-algorithm.h" +#include "../challenges/challenges.h" + +extern int unexpanded_matrix[MAZE_SIZE][MAZE_SIZE]; +extern const cell neighbours[4]; // SOUTH, EAST, WEST, NORTH + + +int compute_path_length(cell from, cell to); + + + +void challenge_2() { + comm_init_communication(); + + cell start; + printf("Starting station: "); + readStation(&start.x, &start.y); + printf("\n"); + + robot r; + r.pos = start; + r.dir = getStartDirection(start); + //cell_add(&r.pos,r.pos,neighbours[r.dir]); + cell stations[3]; + for(int i=0;i<3;i++){ + printf("Station to visit %d: ",i+1); + readStation(&(stations[i].x),&(stations[i].y)); + printf("\n"); + } + int bestOrder[3]; + int minTotal = INT_MAX; + + // test alle 6 + for (int a = 0; a < 3; a++) { + for (int b = 0; b < 3; b++) { + if (b == a) continue; + for (int c = 0; c < 3; c++) { + if (c == a || c == b) continue; + int total = 0; + total += compute_path_length(start, stations[a]); + total += compute_path_length(stations[a], stations[b]); + total += compute_path_length(stations[b], stations[c]); + if (total < minTotal) { + minTotal = total; + bestOrder[0] = a; + bestOrder[1] = b; + bestOrder[2] = c; + } + } + } + } + int visited[MAZE_SIZE][MAZE_SIZE]={0}; + memcpy(visited, unexpanded_matrix, sizeof(unexpanded_matrix)); + + // volg beste volgorde + for (int i = 0; i < 3; i++) { + cell target = stations[bestOrder[i]]; + printf("\n[Station %d] Naar (%d, %d):\n", i+1, target.x, target.y); + stack path; + stack_init(&path); + lee_run(r, target, &path); + followPath(&r, &path,visited); + visited[r.pos.x][r.pos.y] = 5; + stack_free(&path); + } + printMatrix_with_current_pos(visited,r); + printAllMoves(); + comm_end_communication(); +} + +int compute_path_length(const cell from, const cell to) { //modified expand phase to get maximum length + if (to.x == 999 && to.y == 999) return 999; + int tempMatrix[MAZE_SIZE][MAZE_SIZE]; + memcpy(tempMatrix, unexpanded_matrix, sizeof(tempMatrix)); + int steps = 1; + tempMatrix[to.x][to.y] = steps; + while (tempMatrix[from.x][from.y] == 0) { + for (int i = 0; i < MAZE_SIZE; i++) { + for (int j = 0; j < MAZE_SIZE; j++) { + if (tempMatrix[i][j] == steps) { + for (int k = 0; k < 4; k++) { + cell n; + cell_add(&n,(cell){i,j}, neighbours[k]); + if (isInBound(n) && tempMatrix[n.x][n.y] == 0) { + tempMatrix[n.x][n.y] = steps + 1; + } + } + } + } + } + steps++; + if (steps > 1000) break; + } + return tempMatrix[from.x][from.y] ? tempMatrix[from.x][from.y] : INT_MAX; +} diff --git a/robot/challenges/challenge3.c b/robot/challenges/challenge3.c new file mode 100644 index 0000000..3945be1 --- /dev/null +++ b/robot/challenges/challenge3.c @@ -0,0 +1,169 @@ +#include +#include "../../cell/cell.h" +#include +#include + +#include "../robot.h" +#include "../../communication/communication.h" +#include "../../communication/utils.h" +#include "../../lee-algorithm/lee-algorithm.h" +#include "../../leelib/leelib.h" +#include "../challenges/challenges.h" + +#define MAZE_SIZE 11 + +extern int unexpanded_matrix[MAZE_SIZE][MAZE_SIZE]; +extern const cell neighbours[4]; // volgorde: SOUTH, EAST, WEST, NORTH + + +int compute_path_length(cell from, cell to); +void find_best_order_of_3(cell start,cell stations[3],int bestOrder[3]); +void find_best_order_of_2(cell start,cell stations[2],int bestOrder[2]); + + +void challenge_3(cell start) { + comm_init_communication(); + int visited[MAZE_SIZE][MAZE_SIZE]={0}; + memcpy(visited, unexpanded_matrix, sizeof(unexpanded_matrix)); + + robot r; + r.pos = start; + r.dir = getStartDirection(start); + + stack path; + stack_init(&path); + + int visitedStations=0,run=1,bestOrder[3]; + + cell all_stations[3]; + cell last_stations[2]; + + for(int i=0;i<3;i++){ + printf("Station to visit %d: ",i+1); + readStation(&(all_stations[i].x),&(all_stations[i].y)); + printf("\n"); + } + + find_best_order_of_3(start,all_stations,bestOrder); + + cell target = all_stations[bestOrder[0]]; + lee_run(r, target, &path); + + while (run){ + printf("\n[Station %d] Naar (%d, %d):\n", visitedStations +1 ,target.x, target.y); + switch (visitedStations) { + case 0: + if (!followPath_with_blockages(&r, &path,visited)) { + find_best_order_of_3(r.pos,all_stations,bestOrder); + target = all_stations[bestOrder[0]]; + stack_reinit(&path); + lee_run(r, target, &path); + } + else { + //robot is in the station, manually spin + unexpanded_matrix[r.pos.x][r.pos.y]=0; //bugfix, somehow something was causing for a blockage to show up at station. + turnRight(&r); + r.dir=(r.dir+1)%4; + comm_await_crossing(2000); + comm_discard_sensor_data(1000); + visitedStations++; + last_stations[0] = all_stations[bestOrder[1]]; + last_stations[1] = all_stations[bestOrder[2]]; + find_best_order_of_2(r.pos,last_stations,bestOrder); + stack_reinit(&path); + target = last_stations[bestOrder[0]]; + lee_run(r, target, &path); + } + break; + case 1: + if (!followPath_with_blockages(&r, &path,visited)) { + find_best_order_of_2(r.pos,last_stations,bestOrder); + target = last_stations[bestOrder[0]]; + stack_reinit(&path); + lee_run(r, target, &path); + } + else { + //robot is in the station, manually spin + unexpanded_matrix[r.pos.x][r.pos.y]=0; //bugfix, somehow something was causing for a blockage to show up at station. + turnRight(&r); + r.dir=(r.dir+1)%4; + comm_await_crossing(2000); + comm_discard_sensor_data(1000); + visitedStations++; + stack_reinit(&path); + target = last_stations[bestOrder[1]]; + lee_run(r, target, &path); + } + break; + case 2: + if (!followPath_with_blockages(&r,&path,visited)) { + stack_reinit(&path); + lee_run(r, target, &path); + } + else { + //robot is in the station, manually spin + unexpanded_matrix[r.pos.x][r.pos.y]=0; //bugfix, somehow something was causing for a blockage to show up at station. + turnRight(&r); + r.dir=(r.dir+1)%4; + comm_await_crossing(2000); + comm_discard_sensor_data(1000); + visitedStations++; + } + break; + case 3: + run=0; + break; + default: ; + } + + } + stack_free(&path); + printMatrix_with_current_pos(visited,r); + printAllMoves(); + comm_end_communication(); +} + +void find_best_order_of_3(cell start,cell stations[3],int bestOrder[3]) { + int minTotal = INT_MAX; + + // test alle 6 + for (int a = 0; a < 3; a++) { + for (int b = 0; b < 3; b++) { + if (b == a) continue; + for (int c = 0; c < 3; c++) { + if (c == a || c == b) continue; + int total = 0; + total += compute_path_length(start, stations[a]); + total += compute_path_length(stations[a], stations[b]); + total += compute_path_length(stations[b], stations[c]); + if (total < minTotal) { + minTotal = total; + bestOrder[0] = a; + bestOrder[1] = b; + bestOrder[2] = c; + } + } + } + } +} + +void find_best_order_of_2(cell start,cell stations[2],int bestOrder[2]) { + + int total1 = 0; + total1 += compute_path_length(start, stations[0]); + total1 += compute_path_length(stations[0], stations[1]); + + int total2 = 0; + total2 += compute_path_length(start, stations[1]); + total2 += compute_path_length(stations[1], stations[0]); + + if (total1 < total2) { + bestOrder[0] = 0; + bestOrder[1] = 1; + } + else { + bestOrder[0] = 1; + bestOrder[1] = 0; + } +} + diff --git a/robot/challenges/challenge4.c b/robot/challenges/challenge4.c new file mode 100644 index 0000000..a980817 --- /dev/null +++ b/robot/challenges/challenge4.c @@ -0,0 +1,168 @@ +#include +#include +#include + +#include "../../stack/stack.h" +#include "../../cell/cell.h" +#include "../../communication/communication.h" +#include "../../lee-algorithm/lee-algorithm.h" +#include "../../leelib/leelib.h" +#include "../challenges/challenges.h" + +#define MAZE_SIZE 11 + +extern int unexpanded_matrix[MAZE_SIZE][MAZE_SIZE]; +extern cell neighbours[4]; +extern cell crossing_neighbours[4]; +int findNearestCrossing(robot r,int visited [MAZE_SIZE][ MAZE_SIZE],cell *result,int *crossing_counter); +int compute_path_length(cell from, const cell to) ; + + +void challenge_4(cell start) { + comm_init_communication(); + cell finalStation,finalCrossing; + printf("Final destination? "); + readStation(&finalStation.x, &finalStation.y); + direction finalDirection = getStartDirection(finalStation); // direction away from the ending start + + robot r; + r.pos = start; + r.dir = getStartDirection(start); + cell_add(&finalCrossing,finalStation,neighbours[getStartDirection(finalStation)]); + int visited[MAZE_SIZE][MAZE_SIZE] = {0}; + memcpy(visited, unexpanded_matrix, sizeof(unexpanded_matrix)); + + + cell result; + stack moves; + int crossing_counter=0,obstacle_counter=0; + stack_init(&moves); + + stack first_move; + stack_init(&first_move); + stack_push(&first_move,neighbours[r.dir]); + followPath_with_blockages(&r,&first_move,visited); + + while (findNearestCrossing(r,visited,&result,&crossing_counter)) { + lee_run(r,result,&moves); + if (!followPath_with_blockages(&r,&moves,visited)) { // ensure all is visited, no check for nr of obstacles because sometimes it creates bugs + obstacle_counter++; + if (validatePath(r,moves)) { + printf("following path \n"); + followPath(&r,&moves,visited); + } + else { + crossing_counter--; + } + } + else { // if we know where all 12 blocks are, we go + followPath(&r,&moves,visited); + } + stack_reinit(&moves); + printf("Crossings:%d \n",crossing_counter); + //if (crossing_counter==25) { + // break; + //} + } + lee_run(r,finalCrossing,&moves); // Go to crossing in front of the final destination + followPath(&r,&moves,visited); + stack_free(&moves); + spin(&r,finalDirection); + printMatrix_with_current_pos(visited,r); + parkBackwards(&r); + printMatrix_with_current_pos(visited,r); + printf("done"); + printAllMoves(); + comm_end_communication(); + +} + + +/** + * Function to find the nearest/best crossing to go to + * Steps: + * - Unvisited and without blocks + * - Unvisited but with a block + * - Visited + * In all cases forwards gets priority + * @param r robot + * @param visited array of all visited cells + * @param result crossing that was chosen as the best next possible move + * @param crossing_counter count amount of crossings + * @return 1 if found an unvisited crossing, 0 if all crossings visited. + */ +int findNearestCrossing(robot r,int visited [MAZE_SIZE][MAZE_SIZE],cell *result,int *crossing_counter) { + cell tempcell; + robot temp_robot; + temp_robot.pos = r.pos; + temp_robot.dir = r.dir; + + if(!isValidCrossing(temp_robot.pos)){ // if robot is in a intersection, move it to crossing + cell_add(&temp_robot.pos,temp_robot.pos,neighbours[r.dir]); + } + + // check for nearby unvisited crossings and without blockages + for (int i=0;i<4;i++) { + cell_add(&tempcell,temp_robot.pos,neighbours[(r.dir+i)%4]); + if (isInBound(tempcell) && unexpanded_matrix[tempcell.x][tempcell.y]!=-1) { + cell_add(&tempcell,temp_robot.pos,crossing_neighbours[(r.dir+i)%4]); + if (isValidCrossing(tempcell) && visited[tempcell.x][tempcell.y] == 0) { + *result= tempcell; + *crossing_counter+=1; + printf("nearby_unvisited \n"); + return 1; + } + } + } + + //find closest neighbour of neighbours + int min_distance = INT_MAX; + cell min_cell = (cell){0,0}; + + for (int i=0;i<4;i++) { + cell neighbour_crossing; + cell_add(&neighbour_crossing,temp_robot.pos,crossing_neighbours[i]); + for (int j=0;j<4;j++) { + cell_add(&tempcell,neighbour_crossing,neighbours[j]); + if (isInBound(tempcell) && unexpanded_matrix[tempcell.x][tempcell.y]!=-1) { + cell_add(&tempcell,tempcell,neighbours[j]); + if (isValidCrossing(tempcell) && visited[tempcell.x][tempcell.y] == 0) { + int tmp = compute_path_length(r.pos,tempcell); + if (tmp <= min_distance) { + min_distance=tmp; + min_cell = tempcell; + } + } + } + } + } + if (!cell_equals(min_cell, (cell){0,0})) { + *result=min_cell; + *crossing_counter+=1; + printf("neighb_of_neighb \n"); + return 1; + } + + min_distance = INT_MAX; + min_cell = (cell){0,0}; + //find the closest unvisited crossing that isnt a neighbour of a neighbour. + for (int i=0;i +#include + +#include "robot.h" +#include "../communication/communication.h" +#include "../communication/utils.h" +#include "../lee-algorithm/lee-algorithm.h" + + +#define FORWARD 4 +#define BACKWARD 5//TBD +#define TURN_LEFT 1 +#define TURN_RIGHT 2 +#define TURN_AROUND 3 + +#define PARK 6 + +#define CROSSING 32 + +int firstMove = 1; +/* + * FIRST MOVE: + * SEND: FWD + * RECV: ACK, SENSOR_DATA, CROSSING + * SEND: next move + */ + +extern cell neighbours[4]; +extern cell crossing_neighbours[4]; +/* For any move: + * C SEND: LEFT / RIGHT / FWD + * C RECV: ACK , CROSSING, + * C SEND: NEXT INSTRUCTION + */ +void turnLeft(robot *r) { + comm_write_until_successful(TURN_LEFT, 1000); + r->dir = (r->dir + 3) % 4; +} + +void turnRight(robot *r) { + comm_write_until_successful(TURN_RIGHT, 1000); + r->dir = (r->dir + 1) % 4; +} + +void turnAround(robot *r) { +/* + comm_write_until_successful(TURN_AROUND,1000); + r->dir = (r->dir + 2) % 4;*/ + //THIJS: + turnRight(r); + comm_await_crossing(2000); + comm_discard_sensor_data(1000); + turnRight(r); +} + +void forward(robot *r) { + comm_write_until_successful(FORWARD, 1000); + cell_add(&r->pos, r->pos, neighbours[r->dir]); +} + +void backward(robot *r) { + comm_write_until_successful(BACKWARD,1000); + cell_add(&r->pos, r->pos, crossing_neighbours[(r->dir + 2) % 4]); + //printf("Doesnt exist rn"); + //exit(-1); +} + +void parkBackwards(robot *r) { + comm_write_until_successful(PARK,1000); + cell_add(&r->pos,r->pos,neighbours[(r->dir + 2) % 4]); +} + +//BJORN CODE +/* +int first_move = 1; +int followPath_with_blockages(robot *r, stack *path, int visited[MAZE_SIZE][MAZE_SIZE]) { + + while (path->length > 0 ) { + int len=0; + cell current_move = stack_pop(path); + int result = move(r, current_move); + visited[r->pos.x][r->pos.y] = 5; + printMatrix_with_current_pos(visited, *r); + + switch (result) { + case 0: //SPIN --> we expect sensor data + comm_get_distance_sensor(&len, 1000); + if (len != 0) { + len=(len-1)*2+1; + register_sensor_blockages(r, len, visited); + comm_await_crossing(2000); + return 0; + } + comm_await_crossing(2000); + break; + case 1: // FWD --> we do not expect sensor data, except fist move + comm_await_crossing(2000); + if (first_move) { + comm_get_distance_sensor(&len, 1000); + if (len != 0) { + len=(len-1)*2+1; + register_sensor_blockages(r, len, visited); + return 0; + } + } + break; + default : ; + } + } + return 1; +}*/ + + +int followPath_with_blockages(robot *r, stack *path, int visited[MAZE_SIZE][MAZE_SIZE]) { + while (path->length > 0) { + int len = 0; + cell current_move = stack_pop(path); + int result = move(r, current_move); + visited[r->pos.x][r->pos.y] = 5; + switch (isValidCrossing(r->pos)) { + case 1: + comm_await_crossing(2000); + comm_get_distance_sensor(&len, 1000); + if (len != 0) { + //len=(len-1)*2+1; + register_sensor_blockages(r, len, visited); + return 0; + } + break; + case 0: + comm_await_crossing(2000); + comm_discard_sensor_data(1000); + break; + default: ; + } + printMatrix_with_current_pos(visited, *r); + if (result==0) { //spin + move(r, current_move); // advance forward + comm_await_crossing(2000); + comm_get_distance_sensor(&len, 1000); + if (len != 0) { + //len=(len-1)*2+1; + register_sensor_blockages(r, len, visited); + return 0; + } + printf("Continuing after spin cause no block \n"); + printMatrix_with_current_pos(visited, *r); + } + } + return 1; +} + +void printAllMoves() { +} + +void comm_discard_sensor_data(int timeout) { + printf("DISCARDING DATA\n"); + byte *b = malloc(sizeof(byte)); + int run = 1; + //while (run) { + comm_blocking_read(b, 1, timeout); + // for (int i = 1; i <= 5; i++) { + // if (*b == (byte) i) { + // run = 0; + // break; + // } + // } + //} + printf("%d\n", *b); + free(b); +} diff --git a/robot/remote.c b/robot/remote.c new file mode 100644 index 0000000..1feaa33 --- /dev/null +++ b/robot/remote.c @@ -0,0 +1,57 @@ +// +// Created by nano on 5/14/25. +// + +#include +#include + +#include "robot.h" +#include "../communication/communication.h" +#include "../communication/utils.h" +#include "../leelib/leelib.h" + +void simple_control() { + robot r; + printf("Where are we starting? "); + readStation(&r.pos.x,&r.pos.y); + r.dir=getStartDirection(r.pos); + + comm_init_communication(); + char in; + int run = 1; + while (run) { + printf("Move? "); + scanf("%c", &in); + switch (tolower(in)) { + case 'f': + printf("going forward\n"); + forward(&r); + break; + case 'b': + printf("going backward\n"); + backward(&r); + break; + case 'l': + printf("going left\n"); + turnLeft(&r); + break; + case 'r': + printf("turning right\n"); + turnRight(&r); + break; + case 'a': + printf("turning around\n"); + turnAround(&r); + break; + case 'e': + printf("exiting\n"); + run = 0; + break; + default: + break; + } + //byte b; + //comm_await_crossing(&b,50); + } + comm_end_communication(); +} diff --git a/robot/robot.c b/robot/robot.c new file mode 100644 index 0000000..5eb7b70 --- /dev/null +++ b/robot/robot.c @@ -0,0 +1,134 @@ +// +// Created by nano on 5/9/25. +// + +#include + +#include "robot.h" + +#include "../lee-algorithm/lee-algorithm.h" + +extern int unexpanded_matrix[MAZE_SIZE][MAZE_SIZE]; +extern const cell neighbours[4]; +char *arrow[4] = {"↑", "→", "↓", "←"}; + +// Richting in tekst +const char *directionToString(direction dir) { + switch (dir) { + case NORTH: return "NORTH"; + case EAST: return "EAST"; + case SOUTH: return "SOUTH"; + case WEST: return "WEST"; + default: return "UNKNOWN"; + } +} + +// Bepaal gewenste richting van current naar next + +int determineDirection(cell from, cell to) { + if (to.x == from.x - 1) return NORTH; + if (to.x == from.x + 1) return SOUTH; + if (to.y == from.y - 1) return WEST; + if (to.y == from.y + 1) return EAST; + return -1; +} + +int determineDirectionFromMove(cell move) { + if (move.x == -1) return NORTH; + if (move.x == 1) return SOUTH; + if (move.y == -1) return WEST; + if (move.y == 1) return EAST; + return -1; +} + +int getStartDirection(cell startCell) { + if (startCell.x == 0) return SOUTH; + if (startCell.x == MAZE_SIZE - 1) return NORTH; + if (startCell.y == 0) return EAST; + if (startCell.y == MAZE_SIZE - 1) return WEST; + + //fprintf(stderr, "Warning: startCell is not on the maze edge!\n"); + return NORTH; // fallback +} + +void spin(robot *robot, direction desiredDirection) { + switch (robot->dir - desiredDirection) { + case -2: + case 2: + turnAround(robot); + break; + case 1: + case -3: + turnLeft(robot); + break; + case -1: + case 3: + turnRight(robot); + break; + case 0: + default: + break; + } +} + + +/** + * move the robot + * @param r robot + * @param move which move to make + * @return 1 if forward + * @return 0 if spin + */ +int move(robot *r, cell move) { + if (r->dir != (direction) determineDirectionFromMove(move)) { + spin(r, determineDirectionFromMove(move)); + return 0; + } + forward(r); + return 1; +} + + +// Sensorinput: geeft 1–4 aan, blok in die richting, gemeten vanaf huidige robotpositie +void register_sensor_blockages(robot* r, int sensorInput,int visited[MAZE_SIZE][MAZE_SIZE]) { + + if (!isValidCrossing(r->pos)) { + printf("Waarschuwing: robot staat niet op een kruispunt (%d,%d)", r->pos.x, r->pos.y); + } + + cell step = r->pos; + switch (r->dir) { + case NORTH: step.x -= sensorInput; break; + case EAST: step.y += sensorInput; break; + case SOUTH: step.x += sensorInput; break; + case WEST: step.y -= sensorInput; break; + } + if (step.x >= 1 && step.x < MAZE_SIZE-1 && + step.y >= 1 && step.y < MAZE_SIZE-1 && + ((step.x%2==1 && step.y%2==0)|| (step.x%2==0 && step.y%2==1))) { + unexpanded_matrix[step.x][step.y] = -1; + visited[step.x][step.y] = -1; + printf("Blokkade geregistreerd op (%d, %d)", step.x, step.y); + } +} + +void printMatrix_with_current_pos(int m[][MAZE_SIZE], robot r) { + //system("clear"); + printf("\n"); + for (int i = 0; i < MAZE_SIZE; i++) { + for (int j = 0; j < MAZE_SIZE; j++) { + if (r.pos.x == i && r.pos.y == j) { + printf("\033[31;47;1;4m %s \033[0m", arrow[r.dir]); + continue; + } + if (m[i][j] == 5) { + printf("\033[34;47;1m%3s\033[0m", "░░░"); + continue; + } + printf("\033[%dm%3s\33[0m",m[i][j]<0?40:107, "░░░"); + } + printf("\n"); + } +} + + diff --git a/robot/robot.h b/robot/robot.h new file mode 100644 index 0000000..0af09e4 --- /dev/null +++ b/robot/robot.h @@ -0,0 +1,58 @@ +// +// Created by nano on 5/9/25. +// + +#ifndef ROBOT_H +#define ROBOT_H +#include "../cell/cell.h" +#include "../stack/stack.h" + +#define MAZE_SIZE 11 + +typedef enum { + NORTH = 0, + EAST = 1, + SOUTH = 2, + WEST = 3 +} direction; + + +typedef struct { + cell pos; + direction dir; +} robot; + +void turnLeft(robot *r); + +void turnRight(robot *r); + +void turnAround(robot *r); + +void forward(robot *r); + +void backward(robot *r); + +const char *directionToString(direction dir); + +int determineDirection(cell from, cell to); + +int determineDirectionFromMove(cell move); + +int getStartDirection(cell startCell); + +void spin(robot *robot, direction desiredDirection); + +int move(robot *r, cell move); + +void printMatrix_with_current_pos(int m[][MAZE_SIZE], robot r); + +void register_sensor_blockages(robot* r, int sensorInput, int visited[MAZE_SIZE][MAZE_SIZE]); + +int followPath_with_blockages(robot *r, stack *path,int visited[MAZE_SIZE][MAZE_SIZE]); + +void simple_control(); + +void printAllMoves(); +void parkBackwards(robot *r); +void comm_discard_sensor_data(int timeout); +#endif //ROBOT_H diff --git a/robot/simple-simulator.c b/robot/simple-simulator.c new file mode 100644 index 0000000..1cba272 --- /dev/null +++ b/robot/simple-simulator.c @@ -0,0 +1,66 @@ +#include + +#define SIMULATION + +#include + +#include "../leelib/leelib.h" +#include "../lee-algorithm/lee-algorithm.h" +#include "../cell/cell.h" + +extern int unexpanded_matrix[MAZE_SIZE][MAZE_SIZE]; +extern const cell neighbours[4]; + + +void addBlock(robot r, direction dir, cell targetCell, stack *s); + +void simple_control() { //TODO: OUTDATED, rewrite if needed. + /* read the starting and end station.*/ + cell startCell, targetCell; + printf("STARTING AND ENDING STATION: "); + readStation(&startCell.x, &startCell.y); + readStation(&targetCell.x, &targetCell.y); + + robot r; + r.dir = getStartDirection(startCell); + r.pos = startCell; + stack s; + stack_init(&s); + lee_run(r, targetCell, &s); + + while (s.length > 0) { + move(&r, stack_pop(&s)); + printMatrix_with_current_pos(unexpanded_matrix, r); + + printf("BLOCKAGE: "); + char input; + scanf("%c", &input); + switch (tolower(input)) { + case 'n': + addBlock(r, NORTH, targetCell, &s); + break; + case 's': + addBlock(r, SOUTH, targetCell, &s); + break; + case 'e': + addBlock(r, EAST, targetCell, &s); + break; + case 'w': + addBlock(r, WEST, targetCell, &s); + break; + default: + break; + } + } + stack_free(&s); +} + +void addBlock(robot r, direction dir, cell targetCell, stack *s) { + cell block; + cell_add(&block, r.pos, neighbours[dir]); + unexpanded_matrix[block.x][block.y] = -2; // putting -2 makes it not work??? + if (!validatePath(r, *s)) { + stack_reinit(s); + lee_run(r, targetCell, s); + } +} diff --git a/robot/simulator-moves.c b/robot/simulator-moves.c new file mode 100644 index 0000000..323175a --- /dev/null +++ b/robot/simulator-moves.c @@ -0,0 +1,110 @@ +// +// Created by nano on 5/14/25. +// +// Functies om de richting aan te passen +#include +#include + +#include "robot.h" +#include "../lee-algorithm/lee-algorithm.h" + +//Dummy moves for the simulator / when a machine with libserialport is unavailable. + +extern cell neighbours[4]; +//extern cell crossing_neighbours[4]; + +char *moves[100]; +int indx; + +void turnLeft(robot *r) { + r->dir = (r->dir + 3) % 4; + moves[indx] = "\33[1;102mL\33[0m"; + indx++; +} + +void turnRight(robot *r) { + r->dir = (r->dir + 1) % 4; + moves[indx] = "\33[1;101mR\33[0m"; + indx++; +} + +void turnAround(robot *r) { + r->dir = (r->dir + 2) % 4; + moves[indx] = "\33[1;103mS\33[0m"; + indx++; +} + +void forward(robot *r) { + cell_add(&r->pos, r->pos, neighbours[r->dir]); + moves[indx] = "\33[1;105mF\33[0m"; + indx++; +} + +void backward(robot *r) { + cell_add(&r->pos, r->pos, neighbours[(r->dir + 2) % 4]); + moves[indx] = "\33[1;44mB\33[0m"; + indx++; +} + + +int followPath_with_blockages(robot *r, stack *path,int visited[MAZE_SIZE][MAZE_SIZE]) { + while (path->length > 0) { + cell current_move = stack_pop(path); + int result = move(r,current_move); + visited[r->pos.x][r->pos.y] = 5; + printMatrix_with_current_pos(visited,*r); + if (isValidCrossing(r->pos)) { + printf("ADD BLOCKAGE? (Y/N) "); + char input[10]; + scanf("%s", input); + printf("\n"); + if (tolower(input[0]) == 'y' ){ + printf("HOW FAR? (1-4) "); + int len; + scanf("%d",&len); + printf("\n"); + len=(len-1)*2+1; + register_sensor_blockages(r,len,visited); + return 0; + } + } + if (result == 0) { + move(r,current_move); + visited[r->pos.x][r->pos.y] = 5; + printMatrix_with_current_pos(visited,*r); + if (isValidCrossing(r->pos)) { + printf("ADD BLOCKAGE? (Y/N) "); + char input[10]; + scanf("%s", input); + printf("\n"); + if (tolower(input[0]) == 'y' ){ + printf("HOW FAR? (1-4) "); + int len; + scanf("%d",&len); + printf("\n"); + len=(len-1)*2+1; + register_sensor_blockages(r,len,visited); + return 0; + } + } + } + } + return 1; +} + +void printAllMoves() { + printf("\n"); + for (int i = 0; i < indx; i++) { + printf("%s",moves[i]); + } + printf("\n"); +} + +void parkBackwards(robot *r) { + backward(r); +} + +void comm_discard_sensor_data(int timeout){} +void comm_await_crossing(){} +void comm_init_communication(){} +void comm_end_communication(){} diff --git a/stack/stack.c b/stack/stack.c new file mode 100644 index 0000000..31b5db5 --- /dev/null +++ b/stack/stack.c @@ -0,0 +1,83 @@ +// +// Created by nano on 4/30/25. +// + + +#include +#include +#include "stack.h" + +#include +#include + +void stack_init(stack *stack) { + stack -> length = 0; + stack -> size = 1; + stack -> data = calloc(stack->size,sizeof(cell)); +} + +void stack_free(stack *stack) { + free(stack -> data); + stack->size = 0; + stack->length = 0; +} + +void stack_reinit(stack *stack) { + stack_free(stack); + stack_init(stack); +} + +void stack_expand(stack *stack) { + stack -> size = stack -> size *2; + cell *new_data = calloc(stack -> size ,sizeof(cell)); + memcpy(new_data, stack -> data, stack -> size/2 * sizeof(cell)); + free(stack -> data); + stack -> data = new_data; +} + +void stack_push(stack *stack, cell c) { + if (stack -> length + 1 == stack -> size) { + stack_expand(stack); + } + stack -> data[stack -> length++] = c; +} + +void stack_shrink(stack *stack) { + stack -> size = stack -> size / 2; + cell *new_data = calloc(stack -> size , sizeof(cell)); + memcpy(new_data, stack -> data, stack -> size * sizeof(cell)); + free(stack -> data); + stack -> data = new_data; +} + +cell stack_pop(stack *stack) { + if (stack -> length > 0) { + const cell c = stack -> data[stack -> length - 1]; + if ((stack->length - 1) == (stack->size / 2) && stack -> size/2 !=0) { + stack_shrink(stack); + } + stack -> length--; + return c; + } + return (cell) {INT_MAX,INT_MAX}; +} + +void stack_invert(stack *stack) { + cell *inv_data = calloc(stack -> size , sizeof(cell)); + for (int i=0;ilength;i++) + inv_data[stack->length -1 - i] = stack->data[i]; + free(stack -> data); + stack -> data = inv_data; +} + +void stack_append(const stack *from, stack *to) { + const int size = (int) pow(2, ceil(log2(to->length + from->length))); + // power of 2 which has enough space to hold all the contents of both stacks. + cell *new_data = calloc(size,sizeof(cell)); + memcpy(new_data, to->data, to->length * sizeof(cell)); + memcpy(new_data+to->length, from -> data, from -> length * sizeof(cell)); + free(to->data); + to->data = new_data; + to->length = to->length + from -> length; + to->size = size; +} \ No newline at end of file diff --git a/stack/stack.h b/stack/stack.h new file mode 100644 index 0000000..601a941 --- /dev/null +++ b/stack/stack.h @@ -0,0 +1,26 @@ +// +// Created by nano on 4/30/25. +// + +#ifndef STACK_H +#define STACK_H + +#include "../cell/cell.h" + + +typedef struct stack { + cell *data; + int length; + int size; +} stack; + +void stack_init(stack *stack) ; +void stack_free(stack *stack) ; +void stack_reinit(stack *stack); + +void stack_push(stack *stack, cell c) ; +cell stack_pop(stack *stack) ; +void stack_invert(stack *stack); +void stack_append(const stack *from, stack *to); + +#endif //STACK_H diff --git a/stack/stack_test.c b/stack/stack_test.c new file mode 100644 index 0000000..9f716f8 --- /dev/null +++ b/stack/stack_test.c @@ -0,0 +1,56 @@ +// +// Created by nano on 4/30/25. +// +#include +#include "stack.h" + + +/** + * Quick file to test all functions of the implemented stack. + */ +int main(void){ + int ret =1; + stack stk; + stack_init(&stk); + + BEGIN: + for (int i=0;i<=100;i++) { + cell c; + c.x = i; + c.y = 100-i; + stack_push(&stk, c); + printf("pushed: %d,%d\n",c.x,c.y); + } + stack_invert(&stk); + + if (ret) { + printf("2nd run \n"); + ret=0; + stack_reinit(&stk); + goto BEGIN; + } + stack_free(&stk); + + printf("Append Test \n"); + stack s1,s2; + stack_init(&s1); + stack_init(&s2); + for (int i=0;i<100;i++) { + stack_push(&s1,(cell){i,i}); + stack_push(&s2,(cell){i,i}); + } + for (int i=0;i<80;i++) { + stack_pop(&s1); + } + printf("s1 size: %d, s1 len: %d \ns2 size: %d, s2 len: %d \n",s1.size,s1.length,s2.size,s2.length); + stack_append(&s1,&s2); + printf("s2 size: %d, s2 len: %d \n",s2.size,s2.length); + while (s2.length) { + cell c = stack_pop(&s2); + printf("popped: %d,%d\n", c.x,c.y); + } + stack_free(&s1); + stack_free(&s2); + + return 0; +} \ No newline at end of file diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..9267133 --- /dev/null +++ b/todo.md @@ -0,0 +1,20 @@ +# TODO + +- [x] implement direction +- [x] make lee alg prefer straight line moves over turns (involves direction i would say) +- [x] make the code output a set of instructions for the robot. +- [x] replace the stuff in main.c with an "emulator" that will behave like the robot, so we can test without being + forced to have the robot connected at all times. +- [x] think of strategies for the different challenges +- [x] implement and optimize said strategies +- [x] test all challenges + +### Instructions for the robot are gonna be like: + +- Forward x +- Spin left x +- spin right x +- 180 deg turn x +- backward x +- (any other moves we can implement on the robot to make it faster) +- spin might have to be a routine because of the placement of the sensor ? \ No newline at end of file