I studied using Dijkstra (as suggested by Weather Vane), which would require that for each grid cell, the distance to the starting point and the direction from the previous cell are maintained.
Unfortunately, paths on a 32x16 grid can have a distance greater than 255; the longest path I found has a distance of 319 (see image below, left). This means that the distances will not correspond to 8 bits, and the distance matrix is ββ1024 bytes in size.

Left: the longest path (distance = 319). Right: the largest number of equidistant cells (72 cells at a distance of 16)
However, in a square grid where all distances are 1, you can simplify Dijkstra to a breadth-first search that does not use a distance matrix; if you use the fifo queue, the cells are visited in order of distance to the starting cell, so you cannot find a shorter path to the already visited cell.
The fifo queue will contain each cell at a certain distance, then gradually move to a distance of + 1, etc. The maximum queue size depends on how many equidistant cells can be; the maximum that I found is 72 (see the image above, on the right), and during the transition from the previous distance, this requires a queue, which can contain the coordinates of 76 cells or 152 bytes.
The path returned by the algorithm is an array containing the coordinates of a maximum of 320 cells, so it has a maximum size of 640 bytes. Before constructing this array, the queue can be discarded, so that only the direction grid and path are in memory at a time.
The following is an example of a simplified algorithm code with only a direction matrix and a fifo queue; it can probably be improved in many aspects, but it demonstrates this idea. The findPath () function uses a minimum of 664 up to a maximum of 1152 bytes of allocated memory (depending on the path length) plus about 20 bytes for additional variables.
This can be further reduced, for example. saving the direction matrix in the form of 4-bit pieces, reducing its size from 512 to 256 bytes (but requiring large computations) or returning the path as a sequence up / right / down / left, instead of the cell coordinates, which requires only 2 bits per step, reducing its maximum size from 640 to 80 bytes.
#include <stdlib.h> // gcc -std=c99 short int findPath(char grid[][32], char x1, char y1, char x2, char y2, char **path) { char (*dir)[16][32] = calloc(512, 1); // allocate direction matrix: 512 bytes (zeros) (*dir)[y2][x2] = 5; // mark starting cell as visited (search backwards) char *queue = malloc(152); // allocate fifo queue: 152 bytes queue[0] = x2; queue[1] = y2; // put starting cell in queue (search backwards) unsigned char qRead = 0, qWrite = 2; // queue pointers char qCurSize = 1, qNextSize = 0; // queue size per distance short int distance = 0; // distance to current cell char dx[4] = {0, 1, 0, -1}; // up, right, down, left while (qRead != qWrite && !(*dir)[y1][x1]) { // until queue empty (fail) or target reached char x = queue[qRead++], y = queue[qRead++]; // take oldest cell from queue qRead %= 152; // wrap-around queue pointer for (char i = 0; i < 4; i++) { // check 4 neighbouring cells char nx = x + dx[i], ny = y + dx[3 - i]; // coordinates of neighbouring cell if (nx >= 0 && nx < 32 && ny >= 0 && ny < 16 // coordinates not off-grid && !grid[ny][nx] && !(*dir)[ny][nx]) { // traversable unvisited cell (*dir)[ny][nx] = i + 1; // store direction 1-4 queue[qWrite++] = nx; queue[qWrite++] = ny; // put cell in queue qWrite %= 152; // wrap-around queue pointer ++qNextSize; // increment queue size for next distance } } if (!--qCurSize || (*dir)[y1][x1]) { // current distance done or target reached qCurSize = qNextSize; // switch to distance + 1 qNextSize = 0; ++distance; } } free(queue); // free up queue memory for path if (!(*dir)[y1][x1]) distance = -1; // no path found else { // path found *path = malloc(distance * 2 + 2); // allocate path array: 2 bytes per step (*path)[0] = x1; (*path)[1] = y1; // starting position (forward) for (short int i = 1; i <= distance; i++) { // retrace steps char d = (*dir)[y1][x1] - 1; // direction of previous step 0-3 x1 -= dx[d]; y1 -= dx[3 - d]; // go back to previous position (*path)[i * 2] = x1; (*path)[i * 2 + 1] = y1; // add cell to path } } free(*dir); // discard direction matrix return distance + 1; // return number of cells in path } int main() { char grid[][32] = // max queue size: 76 {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; char x1 = 31, y1 = 0, x2 = 16, y2 = 7, *path = NULL; short int steps = findPath(grid, x1, y1, x2, y2, &path); // do stuff free(path); // discard path array return 0; }