오류 메세지를 출력해주는 함수로 전역 변수 errno의 값을 해석하여 이에 해당하는 시스템 오류 메세지를 표준 오류 출력 스트림 (stderr)에 출력한다. 또한 추가적으로 전달하고자 하는 사용자 정의 메세지를 str 인자에 담아 출력할 수 도 있다.
#include <stdio.h>
int main()
{
FILE* pFile;
pFile = fopen("unexist.ent", "rb");
if (pFile == NULL)
perror("The following error occurred");
else
fclose(pFile);
return 0;
}
/*-----------------------result------------------------*/
/*
The following error occurred: No such file or directory
*/
#include <string.h>
char* strerror(int errnum);
오류 메세지 문자열을 가리키는 포인터를 얻어온다. errnum의 값을 통해 발생하였던 오류에 알맞은 오류 메세지를 가리키는 포인터를 리턴해준다.
read 함수로 정해준 버퍼사이즈 만큼 읽어주고 만약 파일을 다읽지 않았다면 계속 이어붙여서 하나의 char *로 만들어 준다. 이후 split을 사용하여 char **로 연결시켜주면 된다. 주의할점은 기존에 구현했던 split함수가 개행을 기준으로 나누어주는 함수 이기때문에 파싱하는 맵이 중간에 개행으로 나누어진 잘못된 맵이어도 이어서 정상출력을 해주게된다. 이점을 따로 잡아주면 된다.
void parse_map(t_game *game)
{
int read_byte;
char *res;
char *tmp;
res = NULL;
while (1)
{
tmp = (char *)malloc(sizeof(char) * (BUFFER_SIZE + 1));
read_byte = read(game->fd, tmp, BUFFER_SIZE);
if (read_byte == -1)
{
free(tmp);
err_free(&game, &res, "Read Error");
}
tmp[read_byte] = '\0';
res = ft_strjoin_free(&res, &tmp);
if (read_byte < BUFFER_SIZE)
break ;
}
if (check_double_nl(res))
err_free(&game, &res, "Invalid Map : nl");
game->map = ft_split(res, '\n');
check_map(res, game);
}
파싱한 맵이 유효한 맵인지 검사를 해준다.
void check_map(char *res, t_game *game)
{
if (res[0] == '\0')
err_free(&game, &res, "Invalid Map : Empty Map");
if (res)
free(res);
if (!game->map)
err_free(&game, NULL, "Invalid Map : ft_split Error");
is_mapsquare(game); // 직사각형인지
is_wallaround(game); // 벽으로 둘러쌓였는지
check_cep(game, 0, 0); // 인자들 조건에 따라 확인
can_escape(game); // 탈출 가능한지
}
맵을 dfs를 통해 벽이나 출구가 아닐경우 방문체크를 해주며 vis배열을 채워준다.
이후 vis배열과 map를 비교해 준다. 예시로 수집품이 있는 자리인데 방문 체크가 안된다면 수집품을 다 먹지 못하는 것이고, 출구인데 동서남북 방향으로 방문한적이 없다면 탈출할 수 없는 잘못된 맵이라는 점을 알 수 있다.
static int ewsn(int idx)
{
if (idx % 4 == 3)
return (0);
return (idx % 4 - 1);
}
static void check_vis(t_game *game)
{
int x;
int y;
int idx;
x = -1;
while (++x < game->map_height)
{
y = -1;
while (++y < game->map_width)
{
if (game->map[x][y] == 'C' && game->vis[x][y] != '1')
err_free(&game, NULL, "Invalid Map : Can't Collect");
else if (game->map[x][y] == 'E')
{
idx = -1;
while (++idx < 4)
{
if (game->vis[x + ewsn(idx)][y + ewsn(idx + 1)] == '1')
break ;
}
if (idx == 4)
err_free(&game, NULL, "Invalid Map : Can't Escape");
}
}
}
}
주어진 mlx init 함수를 사용하여 초기화를 시켜주고
mlx_new_window 함수를 사용하여 윈도우 창을 띄워준다.
이후 xpm파일로 변환한 png를 mlx_xpm_file_to_image 함수를 사용하여 포인터로 이미지를 등록해준다.
해당 이미지를 맵구조에 맞게 윈도우 창에 띄워주면 되는데 이때는 mlx_put_image_to_window함수를 사용해주면 된다.
mlx_hook 함수는 매개변수로 주어진 키를 눌렀을때 매개변수로 들어가는 함수를 실행시켜주는데 방향키 지정과 종료조건등의 설정을 해줄 수 있다.
모든 설정을 다하였다면 mlx_loop함수를 사용하여 게임을 실행 시키면 된다.
void map_to_window(t_img *img, t_game *game)
{
img->mlx = mlx_init();
img->win = mlx_new_window(img->mlx, game->map_width * 32, \
game->map_height * 32, "mlx_test");
img->p = mlx_xpm_file_to_image(img->mlx, "./textures/player.xpm", \
&img->img_w, &img->img_h);
mlx_hook(img->win, 17, 0, normal_exit, game);
mlx_hook(img->win, X_EVENT_KEY_PRESS, 0, &key_press, game);
mlx_loop(img->mlx);
}
!!!!주의할 점들!!!
창에 띄워지는 좌표와 맵의 좌표가 상하반전인 경우여서 조건들을 부여할 떄 조심해야한다.