Compare commits

...

11 Commits

19 changed files with 815 additions and 85 deletions

88
Makefile Normal file
View File

@ -0,0 +1,88 @@
SRC = main.c \
io.c \
parsing.c \
parsing_simple.c \
solution.c \
printing.c \
map_helpers.c \
ft_string.c \
HEADERS = parsing.h \
printing.h \
solution.h \
ft_string.h \
OBJDIR = obj
SRCDIR = srcs
INCDIR = includes
CC = cc
CFLAGS = \
-Wall \
-Wextra \
-Werror \
-I$(INCDIR) \
-fcolor-diagnostics \
LDFLAGS =
_OBJ = $(SRC:.c=.o)
OBJ = $(addprefix $(OBJDIR)/,$(_OBJ))
DEPS = $(addprefix $(INCDIR)/,$(HEADERS))
RM = /bin/rm -f
RMDIR = /bin/rmdir
.DEFAULT_GOAL = test
NAME ?= bsq
.PHONY: re fclean clean all
all: $(NAME)
clean:
@$(RM) $(OBJ)
fclean: clean
@$(RM) $(NAME)
@$(RMDIR) $(OBJDIR) 2>/dev/null || true
re: fclean all
$(NAME): $(OBJ)
@$(CC) $(LDFLAGS) $^ -o $@
$(OBJ): | $(OBJDIR)
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(DEPS)
@norminette $< >/dev/null || { printf '\033[101;37m%s\033[m\n' "!Norminette Failed>>>"; norminette $<; printf '\033[101;37m%s\033[m\n' "<<<Norminette Failed!"; exit 1; }
@$(CC) $(CFLAGS) -c $< -o $@
$(OBJDIR):
@mkdir -p $@
tests: test
test: re run fclean
SUCCESS_MSG = printf '\n\033[102;30m --- %s --- \033[m\n\n' "Test passed!"
FAIL_MSG = printf '\n\033[101;37m --- %s --- \033[m\n\n' "Test failed!"
SUCCESS_MSG_VALG = printf '\n\033[102;30m --- %s --- \033[m\n\n' "Valgrind ran without errors!"
FAIL_MSG_VALG = printf '\n\033[101;37m --- %s --- \033[m\n\n' "Valgrind Failed!"
SUCCESS = && $(SUCCESS_MSG) || $(FAIL_MSG)
SUCCESS_VALG = && $(SUCCESS_MSG_VALG) || $(FAIL_MSG_VALG)
FAIL = && $(FAIL_MSG) || $(SUCCESS_MSG)
VALGRIND = valgrind --leak-check=full --error-exitcode=1
VALGRIND_SMALL = 2>/dev/null 1>&2 valgrind --leak-check=full --error-exitcode=1
YLW = : ;
CYN = : ;
CLR_RST = && : 
run:
@#clear
$(CYN) $(VALGRIND_SMALL) ./$(NAME) $(CLR_RST) $(SUCCESS_VALG)
$(YLW) ./$(NAME) $(CLR_RST) $(SUCCESS)
valgrind: re
$(CYN) $(VALGRIND) ./$(NAME) $(CLR_RST) $(SUCCESS_VALG)

View File

@ -1,11 +0,0 @@
10.X#
.X......X.........X.
.X...X......X.X.....
X..X......X........X
....X..X...X........
.......X........X.X.
......X......X......
.............X......
..X.X..........X....
..........X.........
...X.........X..X.X.

View File

@ -1,11 +0,0 @@
10.X#
.XX.....XX..........
..X...X...X..X......
X.X......XXXX.......
.....X..............
......X...X.......XX
X...XX.........X.X..
..................X.
....X...X..XX....X..
..............X..X..
........X......X.X..

21
assets/map20x40.map Normal file
View File

@ -0,0 +1,21 @@
20.X#
........................................
...................X....................
.........................X..........X...
..............X.........................
.........X...........................X..
............X..X........................
..................................X.....
....................................X...
........................................
X.X..........................X..........
....X.................................X.
..........X.............................
.............................X..........
....................X......X............
............................X...X......X
.......X........X....X....X..XX.........
................X........X............X.
................X......X................
....X................X.......X..........
........................................

View File

@ -1,11 +0,0 @@
10.X#
.........X.X........
X.....X.......X.....
.X........XXX..X....
...X..XX.....X......
.....X.....X.....X..
..X.........X....X..
......X....X.X......
...........X....X.X.
XX..................
....X.....X...X...X.

View File

@ -1,52 +0,0 @@
#!/usr/bin/env python3
import sys
def main():
with open(sys.argv[1]) as b:
board = b.read().splitlines()
try:
first_line = board[0][::-1]
except:
print("map error")
sys.exit(1)
board = board[1:]
full = first_line[0]
obstc = first_line[1]
empty = first_line[2]
try:
num = int(first_line[3:][::-1])
except:
print("map error")
sys.exit(2)
if len(board) != num:
print("map error")
sys.exit(3)
first_line_len = len(board[0])
if any(first_line_len != len(line) for line in board):
print("map error")
sys.exit(4)
converted_board = []
for i, line in enumerate(board):
converted_board.append(list(line))
for i in range(len(board)):
for j in range(first_line_len):
val = board[i][j]
if i < 1:
top = 0
else:
top = converted_board[i - 1][j]
if j < 1:
left = 0
else:
left = converted_board[i][j - 1]
if j < 1 or i < 1:
top_left = 0
else:
top_left = converted_board[i - 1][j - 1]
converted_board[i][j] = str(int(val == obstc)) + left + top + top_left
print(end=converted_board[i][j])
print()
if __name__ == '__main__':
main()

10
assets/subject.map Normal file
View File

@ -0,0 +1,10 @@
9.ox
...........................
....o......................
............o..............
...........................
....o......................
...............o...........
...........................
......o..............o.....
..o.......o................

20
includes/ft_string.h Normal file
View File

@ -0,0 +1,20 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_string.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tischmid <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/05 09:56:45 by tischmid #+# #+# */
/* Updated: 2023/04/05 10:02:30 by tischmid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef FT_STRING_H
# define FT_STRING_H
# include <stdio.h>
char *ft_strcpy(char *dest, char *src);
size_t ft_strlen(char const *str);
#endif

45
includes/parsing.h Normal file
View File

@ -0,0 +1,45 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parsing.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: apago <apago@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/04 18:22:11 by apago #+# #+# */
/* Updated: 2023/04/05 09:31:04 by tischmid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef PARSING_H
# define PARSING_H
# include "fcntl.h"
# include "stdio.h"
# include "stdlib.h"
# include "unistd.h"
typedef struct Meta
{
char empty;
char obstacle;
char full;
int height;
int width;
} t_meta;
typedef struct Map
{
t_meta meta;
char *data;
char *copy;
} t_map;
char *read_file(int file);
size_t read_uint(char *str);
int parse_valid_uint(char *str, size_t len);
int read_char(char *str, char *dst);
int printable(char c);
size_t count_first_line(char *line);
int read_fname(char *name, t_map *map);
#endif

29
includes/printing.h Normal file
View File

@ -0,0 +1,29 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* printing.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tischmid <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/05 04:11:08 by tischmid #+# #+# */
/* Updated: 2023/04/05 10:01:56 by tischmid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef PRINTING_H
# define PRINTING_H
# include "parsing.h"
# include <limits.h>
# include <unistd.h>
# define RED "\x1b[31m"
# define GRN "\x1b[32m"
# define YLW "\x1b[33m"
# define CLR_RST "\x1b[m"
void ft_putchar(char c);
void ft_putstr(char *str);
void ft_putnbr(int nb);
void print_map(t_map *map, int as_numbers);
int ft_err(char *str, int exit_code);
#endif

23
includes/solution.h Normal file
View File

@ -0,0 +1,23 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* solution.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tischmid <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/05 04:02:35 by tischmid #+# #+# */
/* Updated: 2023/04/05 09:05:08 by tischmid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef SOLUTION_H
# define SOLUTION_H
# include "parsing.h"
# include "printing.h"
void solve(t_map *map);
int itoc(int idx, int width);
int itor(int idx, int width);
char get_cell(t_map *map, int idx, int top, int left);
#endif

34
srcs/ft_string.c Normal file
View File

@ -0,0 +1,34 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_string.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tischmid <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/05 09:57:31 by tischmid #+# #+# */
/* Updated: 2023/04/05 09:57:39 by tischmid ### ########.fr */
/* */
/* ************************************************************************** */
#include "ft_string.h"
char *ft_strcpy(char *dest, char *src)
{
char *o_dest;
o_dest = dest;
while (*src)
*dest++ = *src++;
*dest = 0;
return (o_dest);
}
size_t ft_strlen(char const *str)
{
size_t size;
size = 0;
while (*str++)
++size;
return (size);
}

73
srcs/io.c Normal file
View File

@ -0,0 +1,73 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* io.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: apago <apago@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/04 18:23:57 by apago #+# #+# */
/* Updated: 2023/04/04 18:24:50 by apago ### ########.fr */
/* */
/* ************************************************************************** */
#include "parsing.h"
void copy_bytes(char *dst, char *src, size_t bytes)
{
size_t i;
i = 0;
while (i < bytes)
{
dst[i] = src[i];
i++;
}
}
int push_bytes(size_t n_read, char **res, size_t *offset, size_t *size)
{
char *new_res;
if (n_read <= 0)
return (n_read);
*offset += n_read;
if (*offset == *size)
{
new_res = malloc(*size * 2);
if (!new_res)
return (-1);
copy_bytes(new_res, *res, *size);
free(*res);
*res = new_res;
*size *= 2;
}
return (n_read);
}
char *read_file(int file)
{
size_t size;
size_t offset;
size_t n_read;
char *res;
offset = 0;
size = 1024;
res = malloc(size);
if (!res)
return (0);
while (1)
{
n_read = read(file, &res[offset], size - offset);
n_read = push_bytes(n_read, &res, &offset, &size);
if (!n_read)
break ;
if (n_read < 0)
{
free(res);
return (0);
}
}
res[offset] = 0;
return (res);
}

62
srcs/main.c Normal file
View File

@ -0,0 +1,62 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* main.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tischmid <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/04 21:50:50 by tischmid #+# #+# */
/* Updated: 2023/04/05 10:18:04 by tischmid ### ########.fr */
/* */
/* ************************************************************************** */
#include <stdio.h>
#include "solution.h"
#include "printing.h"
#include "ft_string.h"
void debug_set_map(t_map *map)
{
char *str;
str = \
"........................................" \
"...................X...................." \
".........................X..........X..." \
"..............X........................." \
".........X...........................X.." \
"............X..X........................" \
"..................................X....." \
"....................................X..." \
"........................................" \
"X.X..........................X.........." \
"....X.................................X." \
"..........X............................." \
".............................X.........." \
"....................X......X............" \
"............................X...X......X" \
".......X........X....X....X..XX........." \
"................X........X............X." \
"................X......X................" \
"....X................X.......X.........." \
"........................................";
map->data = malloc(sizeof(char) * (ft_strlen(str) + 1));
ft_strcpy(map->data, str);
}
int main(void)
{
t_map map;
if (!read_fname("./assets/map20x40.map", &map))
return (ft_err("map error\n", 1));
free(map.data);
debug_set_map(&map);
map.copy = malloc(sizeof(char) * (ft_strlen(map.data) + 1));
ft_strcpy(map.copy, map.data);
solve(&map);
print_map(&map, 0);
free(map.data);
free(map.copy);
return (0);
}

45
srcs/map_helpers.c Normal file
View File

@ -0,0 +1,45 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* map_helpers.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tischmid <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/05 06:50:28 by tischmid #+# #+# */
/* Updated: 2023/04/05 09:05:18 by tischmid ### ########.fr */
/* */
/* ************************************************************************** */
#include "solution.h"
// index to column
int itoc(int idx, int width)
{
return (idx % width);
}
// index to row
int itor(int idx, int width)
{
return (idx / width);
}
char get_cell(t_map *map, int idx, int bottom, int right)
{
int row;
int col;
if ((bottom | right) == 0)
return (map->data[idx]);
row = itor(idx, map->meta.width);
col = itoc(idx, map->meta.width);
row += bottom;
col += right;
if (row >= map->meta.height
|| col >= map->meta.width
|| col < 0
|| row < 0)
return (0);
idx = col + row * map->meta.width;
return (map->data[idx]);
}

123
srcs/parsing.c Normal file
View File

@ -0,0 +1,123 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parsing.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: apago <apago@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/04 16:19:27 by apago #+# #+# */
/* Updated: 2023/04/05 10:04:09 by tischmid ### ########.fr */
/* */
/* ************************************************************************** */
#include "parsing.h"
int parse_meta(char *str, t_meta *meta)
{
int read_bytes;
read_bytes = read_uint(str);
meta->height = parse_valid_uint(str, read_bytes);
if (meta->height < 1)
return (0);
if (!read_char(&str[read_bytes++], &meta->empty))
return (0);
if (!read_char(&str[read_bytes++], &meta->obstacle))
return (0);
if (!read_char(&str[read_bytes++], &meta->full))
return (0);
if (!printable(meta->empty) || !printable(meta->obstacle)
|| !printable(meta->full))
return (0);
if ((meta->empty == meta->obstacle) || (meta->obstacle == meta->full))
return (0);
if (str[read_bytes++] != '\n')
return (0);
return (read_bytes);
}
size_t parse_line(char *line, char *dst, t_meta *meta)
{
int i;
i = 0;
while (i < meta->width)
{
if (!line[i])
return (0);
if (line[i] == meta->empty)
dst[i] = '.';
else if (line[i] == meta->obstacle)
dst[i] = 'o';
else
return (0);
i++;
}
if (line[i] != '\n')
return (0);
return (meta->width + 1);
}
// size_t offset; // unused
char *parse_data(char *data, t_meta *meta)
{
char *res;
size_t read_bytes;
int i;
i = 0;
res = malloc(meta->width * meta->height * sizeof(char));
if (!res)
return (0);
while (i < meta->height)
{
read_bytes = parse_line(data, res, meta);
if (!read_bytes)
{
free(res);
return (0);
}
data += read_bytes;
i++;
}
if (!*data)
return (res);
free(res);
return (0);
}
int parse_input(char *str, t_map *map)
{
size_t offset;
size_t read_bytes;
read_bytes = parse_meta(str, &map->meta);
if (!read_bytes)
return (0);
offset = read_bytes;
map->meta.width = count_first_line(&str[offset]);
if (!map->meta.width)
return (0);
map->data = parse_data(&str[offset], &map->meta);
if (!map->data)
return (0);
return (1);
}
int read_fname(char *name, t_map *map)
{
int file;
char *text;
int res;
file = open(name, O_RDONLY);
if (file == -1)
return (0);
text = read_file(file);
close(file);
if (!text)
return (0);
res = parse_input(text, map);
free(text);
return (res);
}

67
srcs/parsing_simple.c Normal file
View File

@ -0,0 +1,67 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parsing_simple.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: apago <apago@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/04 18:25:47 by apago #+# #+# */
/* Updated: 2023/04/04 21:56:56 by tischmid ### ########.fr */
/* */
/* ************************************************************************** */
#include "parsing.h"
size_t read_uint(char *str)
{
int i;
i = 0;
while (*str >= '0' && *str <= '9')
{
str++;
i++;
}
return (i);
}
int parse_valid_uint(char *str, size_t len)
{
int res;
size_t i;
res = 0;
i = 0;
while (i < len)
{
res = res * 10 + str[i] - '0';
i++;
}
return (res);
}
int read_char(char *str, char *dst)
{
if (!*str)
return (0);
*dst = *str;
return (1);
}
int printable(char c)
{
return (c >= 32 && c <= 127);
}
size_t count_first_line(char *line)
{
size_t cnt;
cnt = 0;
while (*line && *line != '\n')
{
line++;
cnt++;
}
return (cnt);
}

75
srcs/printing.c Normal file
View File

@ -0,0 +1,75 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* printing.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tischmid <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/05 04:09:39 by tischmid #+# #+# */
/* Updated: 2023/04/05 10:19:12 by tischmid ### ########.fr */
/* */
/* ************************************************************************** */
#include "printing.h"
void ft_putchar(char c)
{
write(1, &c, 1);
}
int ft_err(char *str, int exit_code)
{
ft_putstr(RED);
ft_putstr(str);
ft_putstr(CLR_RST);
return (exit_code);
}
void ft_putstr(char *str)
{
while (*str)
ft_putchar(*str++);
}
void ft_putnbr(int nb)
{
if (nb > 9)
{
ft_putnbr(nb / 10);
ft_putchar(nb % 10 + '0');
}
else if (nb == INT_MIN)
{
ft_putnbr(nb / 10);
ft_putnbr(-(nb % 10));
}
else if (nb < 0)
{
ft_putchar('-');
ft_putnbr(-nb);
}
else
ft_putchar(nb % 10 + '0');
}
void print_map(t_map *map, int as_numbers)
{
int i;
int j;
i = -1;
while (++i < map->meta.height)
{
j = -1;
while (++j < map->meta.width)
{
if (as_numbers)
{
ft_putnbr(map->data[i * map->meta.width + j]);
}
else
ft_putchar(map->data[i * map->meta.width + j]);
}
ft_putchar('\n');
}
}

100
srcs/solution.c Normal file
View File

@ -0,0 +1,100 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* solution.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tischmid <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/04 21:46:57 by tischmid #+# #+# */
/* Updated: 2023/04/05 10:31:15 by tischmid ### ########.fr */
/* */
/* ************************************************************************** */
#include "solution.h"
// Replace each cell by the number of obstacles a rectangle starting
// from the top left cell, filling the board until the cell in question,
// covers. Border is inclusive. This will enable us to check if a given
// square contains obstacles or not in O(1) time, instead of O(n^2),
// namely by summing up the corner cells alternatingly (+, -, +, -, clockwise).
void preprocess_map(t_map *map)
{
int is_obstacle;
int idx;
idx = 0;
while (idx < map->meta.width * map->meta.height)
{
is_obstacle = get_cell(map, idx, 0, 0) == map->meta.obstacle;
map->data[idx] = is_obstacle + \
get_cell(map, idx, 0, -1) + \
get_cell(map, idx, -1, 0) - \
get_cell(map, idx, -1, -1);
idx++;
}
}
int count_obstacles(t_map *map, int idx, int sq_size)
{
int alternat_corner_sum;
if (sq_size == 0)
return (0);
if (sq_size == 1)
return (get_cell(map, idx, 0, 0));
if (idx + (sq_size - 1) * (map->meta.width + 1)
> map->meta.width * map->meta.height)
return (-1);
alternat_corner_sum = get_cell(map, idx, -1, -1) - \
get_cell(map, idx, -1, sq_size - 1) + \
get_cell(map, idx, sq_size - 1, sq_size - 1) - \
get_cell(map, idx, sq_size - 1, -1);
return (alternat_corner_sum);
}
void fill_with_full(t_map *map, int sq_idx, int sq_size)
{
int idx;
int idx_row;
int idx_col;
int sq_row;
int sq_col;
sq_row = itor(sq_idx, map->meta.width);
sq_col = itoc(sq_idx, map->meta.width);
idx = 0;
while (idx < map->meta.width * map->meta.height)
{
idx_row = itor(idx, map->meta.width);
idx_col = itoc(idx, map->meta.width);
if (idx_row >= sq_row && idx_row < sq_row + sq_size
&& idx_col >= sq_col && idx_col < sq_col + sq_size)
map->data[idx] = map->meta.full;
else
map->data[idx] = map->copy[idx];
idx++;
}
}
void solve(t_map *map)
{
int idx;
int sq_idx;
int sq_size;
preprocess_map(map);
idx = 0;
sq_size = 0;
sq_idx = 0;
while (idx < map->meta.width * map->meta.height)
{
while (count_obstacles(map, idx, sq_size) == 0)
{
sq_idx = idx;
sq_size++;
}
idx++;
}
sq_size--;
fill_with_full(map, sq_idx, sq_size);
}