42Seoul/cub3d

cub3d 지도 파싱

재윤 2023. 9. 14. 11:07
반응형

지도 파싱 생각하기

  1. 이미지 파일, RGB는 순서 상관없이 읽을 수 있어야 함.
  2. 그 밑에 지도는 무조건 제일 밑에 옴
    1. 허용되는 것은 0, 1, N, S, W, E이며 공백이 들어오더라도 읽을 수 있어야함.
NO ./path_to_the_north_texture
SO ./path_to_the_south_texture
WE ./path_to_the_west_texture
EA ./path_to_the_east_texture

F 220,100,0
C 225,30,0

        1111111111111111111111111
	    	1000000000110000000000001
	    	1011000001110000000000001
    		1001000000000000000000001
111111111011000001110000000000001
100000000011000001110111111111111
11110111111111011100000010001
11110111111111011101010010001
11000000110101011100000010001
10000000000000001100000010001
10000000000000001101010010001
11000001110101011111011110N0111
11110111 1110101 101111010001
11111111 1111111 111111111111

알고리즘

  1. gnl을 사용해서 한 줄을 읽는데 count 변수를 주어서 무조건 지도 윗부분을 먼저 읽게 만든다.
  2. 이미지 파일과 rgb를 읽고 유효한지 검사.
  3. 지도를 읽을 때는 gnl을 한 값들이 0, 1, N, S, W, E, (공백)인지 본다.
  4. 읽은 지도를 통해 wall벽을 검사한다.
  5. 읽은 지도의 0주변을 검사한다.
  6. xml 파일과 rgb가 겹치는 것이 없는지 검사한다.

5번은 무슨 말이냐 → 규칙을 찾은 것이다.

지도에서 0을 기준으로 동, 서, 남, 북, 대각선 전부 포함하여 8개가 나오는데 이 8개가 널이 아니며 공백이 아니다 이것을 검사하면 유효한 지도인지 판별 할 수가 있다.

헤더 파일

typedef struct s_img
{
	void	*img_no;
	char	*img_no_name;
	void	*img_so;
	char	*img_so_name;
	void	*img_we;
	char	*img_we_name;
	void	*img_ea;
	char	*img_ea_name;
	int		ceil[3];
	int		ceil_flag;
	int		floor[3];
	int		floor_flag;
}	t_img;

typedef struct s_game
{
	char		*map;
	char		**map_copy;
	int			height;
	int			width;
	int			player_count;
	int			fd;
	t_img		*img;
	void		*mlx;
	void		*mlx_win;
}	t_game;
  • t_game
    • map → gnl을 할 때 사용
    • map_copy → map을 1차원으로 만들어줄 것임.
    • height → map의 높이
    • player_count → player의 수
    • fd → gnl 사용
  • t_img
    • void *(변수) → mlx_put_img 사용
    • char *(변수) → xml의 이름들을 넣어줄 것임.

cub3d_main.c

int	main(int argc, char **argv)
{
	t_game		game;

	if (argc != 2)
		error("Error\\n");
	if (!(check_argv(argv[1])))
		error("Error\\n");
	init_game(&game, argv[1]);
	read_map(&game);
	if (game.map == (void *)0)
		error("map error\\n");
	check_map(&game);
	check_overlap(&game);
	exit(0);
}
  • check_argv → 지도의 .cub가 잘 들어오는지 확인
  • init_game → 구조체 초기화
  • read_map → gnl
  • check_map → wall, 0주변 검사
  • check_overlap → xml 파일, rgb 중복 검사.

read_map 함수

void	read_map(t_game *game)
{
	char	*map_buf;
	char	*line;
	int		count;

	map_buf = NULL;
	line = NULL;
	count = 0;
	while (1)
	{
		line = get_next_line(game->fd);
		if (!line)
			break ;
		if (count <= 5)
			check_dir_rgb(line, game, &count);
		else
			if (map_check(&line, &map_buf, game) == 1)
				error("invalid input map2\\n");
		free(line);
		line = NULL;
	}
	close(game->fd);
	game->map = map_buf;
	free(line);
}
  • count ≤ 5 → rgb, xml 파일 읽기
    • 이게 아니면 map을 전부 읽음 개행 포함.
  • check_dir_rgb → xml 파일인지, rgb에 따라 각각 검사와 실행.
  • map_check → 0, 1, N, S, W, E, (공백) 검사.

check_map 함수

void	check_map(t_game *game)
{
	char	**map_copy;
	long	location;
	char	*one_copy;
	int		hei;

	hei = 0;
	if (game->player_count >= 2 || game->player_count == 0)
		error("play_direction error\\n");
	location = first_new_line_delete(game->map);
	one_copy = middle_new_line_check(game->map + location);
	map_copy = split_string(one_copy, '\\n');
	if (map_copy == (void *)0)
		error("map two error\\n");
	if (only_space(map_copy[0]) == 1)
		error("first error\\n");
	check_zero(map_copy);
	check_wall(map_copy);
	game->map_copy = map_copy;
	while (game->map_copy[hei])
		hei++;
	game->height = hei;
	free(one_copy);
	free(game->map);
}
  • if (game->player_count >= 2 || game->player_count == 0)
    • player가 2개 이상일 때와 없을 때 에러
  • first_new_line_delete → 1차원 map에 앞에 개행부분 없애주기. 그 위치 저장
  • middle_new_line_check → 앞에 개행 없애준 1차원 map.
  • split_string → 개행 기준으로 split → 2차원 배열 map
  • check_zero → 0주변 검사
  • check_wall
    • 2차원의 맵에서 첫 번째 줄과 마지막 줄이 (공백), 1로 이루어져 있는지 검사.
    • 한 줄마다 검사를 진행하는데 만약 공백만 있는 게 아니라면 한 줄의 첫 번째 자리와 마지막 1인지 검사.

check_overlap 함수

void	check_overlap(t_game *game)
{
	int		i;
	int		j;
	char	**temp;

	i = -1;
	temp = (char **)malloc(sizeof(char *) * 5);
	temp[0] = game->img->img_no_name;
	temp[1] = game->img->img_so_name;
	temp[2] = game->img->img_we_name;
	temp[3] = game->img->img_ea_name;
	temp[4] = 0;
	while (++i < 4)
	{
		j = -1;
		while (++j < 4)
		{
			if (i == j)
				continue ;
			else
				overlap_direction(temp[i], temp[j]);
		}
	}
	overlap_rgb(game);
	char_two_free(temp);
}
반응형