This commit is contained in:
Nanokloon 2025-06-14 23:26:42 +02:00
commit f9cd6248ec
29 changed files with 2205 additions and 0 deletions

56
CMakeLists.txt Normal file
View File

@ -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)

View File

@ -0,0 +1,3 @@
Start testing: Jun 05 17:03 CEST
----------------------------------------------------------
End testing: Jun 05 17:03 CEST

15
cell/cell.c Normal file
View File

@ -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;
}

19
cell/cell.h Normal file
View File

@ -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

View File

@ -0,0 +1,210 @@
//
// Created by nano on 4/26/25.
//
#include "communication.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}
}

View File

@ -0,0 +1,89 @@
//
// Created by nano on 4/26/25.
//
#ifndef COMMS_H
#define COMMS_H
#include <libserialport.h>
#include <sys/types.h>
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

122
communication/utils.c Normal file
View File

@ -0,0 +1,122 @@
//
// Created by nano on 4/26/25.
//
#include <stdlib.h>
#include "utils.h"
#include <stdio.h>
#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;
}

20
communication/utils.h Normal file
View File

@ -0,0 +1,20 @@
//
// Created by nano on 4/26/25.
//
#include <sys/types.h>
#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

View File

@ -0,0 +1,148 @@
#include <stdio.h>
#include <string.h>
#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;
}

View File

@ -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

73
leelib/leelib.c Normal file
View File

@ -0,0 +1,73 @@
#include <stdio.h>
#include <stdlib.h>
#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");
}
}

19
leelib/leelib.h Normal file
View File

@ -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]. */

46
main.c Normal file
View File

@ -0,0 +1,46 @@
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#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 <CHALLENGE NR or 0 for simple remote> \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;
}

127
maze-editor.html Normal file
View File

@ -0,0 +1,127 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Maze Editor</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
h1 {
color: #444;
}
.maze-container {
display: flex;
justify-content: center;
}
table {
border-collapse: collapse;
}
td {
border: 1px solid #ccc;
width: 20px;
height: 20px;
text-align: center;
}
input[type="checkbox"] {
width: 20px;
height: 20px;
margin: 0;
}
.cell-0 {
background-color: #fff;
}
.cell-1 {
background-color: #ddd;
}
.button {
margin-top: 20px;
}
#output {
font-family: monospace;
margin-top: 20px;
}
input[disabled] {
cursor: not-allowed;
}
</style>
</head>
<body>
<h1>Maze Editor</h1>
<div id="maze-container" class="maze-container"></div>
<button class="button" onclick="printArray()">Show Array</button>
<div id="output"></div>
<script>
const MAZE_SIZE = 11;
// Original matrix with -1's
const originalMatrix = [
[ -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 ]
];
// Work copy for editing
let mazeData = JSON.parse(JSON.stringify(originalMatrix));
function initMaze() {
const container = document.getElementById("maze-container");
container.innerHTML = "";
const table = document.createElement("table");
for (let i = 0; i < MAZE_SIZE; i++) {
const tr = document.createElement("tr");
for (let j = 0; j < MAZE_SIZE; j++) {
const td = document.createElement("td");
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = mazeData[i][j] === -1;
// Disable if original value is -1 OR not at even indices
checkbox.disabled =
originalMatrix[i][j] === -1 ||
!(i % 2 === 0 || j % 2 === 0) ||
checkbox.addEventListener("change", function () {
mazeData[i][j] = this.checked ? -1 : 0;
updateCellClass(td, this.checked);
});
td.appendChild(checkbox);
updateCellClass(td, mazeData[i][j] === -1);
tr.appendChild(td);
}
table.appendChild(tr);
}
container.appendChild(table);
}
function updateCellClass(td, isWall) {
td.className = isWall ? "cell-1" : "cell-0";
}
function printArray() {
let output = "int unexpanded_matrix[MAZE_SIZE][MAZE_SIZE] = {\n";
for (let i = 0; i < MAZE_SIZE; i++) {
output += "\t{";
for (let j = 0; j < MAZE_SIZE; j++) {
output += mazeData[i][j];
if (j < MAZE_SIZE - 1) output += ", ";
}
output += "}";
if (i < MAZE_SIZE - 1) output += ",";
output += "\n";
}
output += "};";
document.getElementById("output").textContent = output;
}
window.onload = initMaze;
</script>
</body>
</html>

0
readme.md Normal file
View File

View File

@ -0,0 +1,101 @@
#include <stdio.h>
#include <limits.h>
#include <string.h>
#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;
}

View File

@ -0,0 +1,169 @@
#include <stdio.h>
#include "../../cell/cell.h"
#include <limits.h>
#include <string.h>
#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;
}
}

View File

@ -0,0 +1,168 @@
#include <limits.h>
#include <stdio.h>
#include <string.h>
#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<MAZE_SIZE;i++) {
for (int j=0;j<MAZE_SIZE;j++) {
tempcell = (cell) {i,j};
if (isValidCrossing(tempcell) && visited[i][j] == 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("random_iterate \n");
return 1;
}
return 0;
}

View File

@ -0,0 +1,11 @@
#ifndef CHALLENGES_H
#define CHALLENGES_H
#include "../../cell/cell.h"
void challenge_2();
void challenge_3(cell start);
void challenge_4(cell start);
void challenge_4_old(cell start) ;
#endif

174
robot/controller-moves.c Normal file
View File

@ -0,0 +1,174 @@
//
// Created by nano on 5/14/25.
//
#include <stdio.h>
#include <stdlib.h>
#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, <SENSOR DATA>
* 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);
}

57
robot/remote.c Normal file
View File

@ -0,0 +1,57 @@
//
// Created by nano on 5/14/25.
//
#include <ctype.h>
#include <stdio.h>
#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();
}

134
robot/robot.c Normal file
View File

@ -0,0 +1,134 @@
//
// Created by nano on 5/9/25.
//
#include <stdio.h>
#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 14 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");
}
}

58
robot/robot.h Normal file
View File

@ -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

66
robot/simple-simulator.c Normal file
View File

@ -0,0 +1,66 @@
#include <stdio.h>
#define SIMULATION
#include <ctype.h>
#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);
}
}

110
robot/simulator-moves.c Normal file
View File

@ -0,0 +1,110 @@
//
// Created by nano on 5/14/25.
//
// Functies om de richting aan te passen
#include <ctype.h>
#include <stdio.h>
#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(){}

83
stack/stack.c Normal file
View File

@ -0,0 +1,83 @@
//
// Created by nano on 4/30/25.
//
#include <stdlib.h>
#include <string.h>
#include "stack.h"
#include <limits.h>
#include <math.h>
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;i<stack->length;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;
}

26
stack/stack.h Normal file
View File

@ -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

56
stack/stack_test.c Normal file
View File

@ -0,0 +1,56 @@
//
// Created by nano on 4/30/25.
//
#include <stdio.h>
#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;
}

20
todo.md Normal file
View File

@ -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 ?