마지막 rush이자 가장 악명 높은 과제 중 하나인 rush02. 결론부터 말하자면 0%로 fail을 받았다. 평가를 받다가 malloc check을 한 번 안 한 게 발견되어서 결국 fail을 했다. 이후 코드도 좀 더 깔끔하게 고쳐서 다시 완성했다. 내가 테스트한 경우들에는 모두 작동했지만, 통과한 코드가 아니고, 고치는 과정에서 42norm에 맞지 않게 고친 것도 다수 있어서 참고만 하길 바란다.
Rush02는 쉽게 말하면, 주어진 num dictionary에 저장된 대로 터미널에 입력된 숫자를 변환하는 것이다. 예를 들어, 터미널에 42가 주어지고, num dictionary에 40이 fourty, 2가 two로 저장되어 있다면 fourty two를 결과로 출력해야 한다.
기본으로 주어지는 num dictionary는 다음과 같고, 숫자가 추가될 수도 있고, 숫자를 표현하는 문자가 바뀔 수도 있다. 그리고 dictionary 내 표현들은 "[a number][0 to n spaces]:[0 to n spaces][any printable characters]\n"라는 형식에 맞게 입력되어 있어야 한다. 또한, 아래 범위 내 숫자 외의 다른 숫자가 추가되면 이는 무시하고 아래 숫자 범위 내 숫자들로만 표현되어야 한다.
이 문제들의 까다로운 점은 너무 큰 숫자가 주어진다는 점, 11~10의 예외성, 10~90의 예외성, 그리고 다른 큰 수들은 대체로 3의 자리 단위로 움직이지만 hundred에서 million으로 갈 때는 한 자리 단위로 이동했다는 점, 띄어쓰기 조건 등 너무나도 많았다. 이를 다 이겨내고 완성해냈지만, 단 하나의 malloc check 때문에 0%로 fail했다는 사실이 날 화나게 했지만, 코딩이 다 그런 거지... 했다. 코드가 상당히 길다. 따라서 하나하나 설명하기 보다는 주요 함수에서 전체적인 구조만 설명하는 방식으로 하겠다. 나머지 설명들은 주석을 통해서도 작성되어 있다.
기본적으로 프로그램을 만든 방법은, 작은 숫자들(90까지)은 숫자 자체를, 큰 숫자들(100부터)은 숫자의 자릿수를 key로 하고 이를 표현한 문자열을 value로 하는 hash table을 만들어서 이용한 것이다. 나중에 터미널로부터 숫자를 받아서는 이를 한자리 한자리 숫자로 변환하여 key값에 넣어 출력하면 된다. 또 출력할 때는 자릿수를 세어 가며, 큰 숫자들이 자릿수를 자리에 맞게 출력할 수 있게 하고, 숫자 자체도 위치에 맞게 출력했다.
우선 main.h 헤더 파일로 프로그램 전체 구조를 한 번 기술하겠다. 우선 상수로 주어진 NUM_LEN의 경우 터미널 입력으로 주어질 수 있는 최대 숫자의 자릿수이다. num dictorary에 undecillion까지 있기 때문에 hundred undecillion까지 생각하면 자릿수가 92 자릿수가 된다. 이 범위를 넘어가면 주어진 dictionary에서 표현할 수 없기 때문에 에러처리를 한다. DIGIT_LEN 상수의 경우 undecillion의 자릿수로 이를 넘어가는 digit을 저장할 필요가 없다. 이 두 상수는 메모리 할당을 위해서도 사용된다.
DICTIONARY 구조체는, num dictionary 파일로부터 프로그램 내에서 사용할 수 있는 dictionary로 변환하여 저장할 수 있는 구조체이다. 구조체 내 num 배열의 경우 0부터 90까지의 수를 표현하는 문자열들을 저장하는 문자열 배열이며, digit은 100부터 undecillion까지를 표현하는 문자열들을 저장하는 배열이다.
그리고 파일들을 하나씩 살펴보면, main.c 파일은 main 함수가 있는 프로그램의 중심이 되는 파일로, main 함수, 터미널로부터 입력된 num dictionary 파일 경로와 변환해야 할 숫자 문자열을 설정하는 set_init_values() 함수, 그리고 dictionary 구조체의 메모리를 해제하는 free_dict() 함수로 구성된다.
ft_func.c 파일은 범용적으로 사용될 수 있는 함수들을 만들어둔 파일로, 문자열을 콘솔에 출력하는 ft_putstr() 함수, 이차원 배열에 메모리를 할당하고 모든 요소를 null로 초기화하여 리턴하는 init_ary() 함수, 주어진 c가 출력 가능한 문자인지 판단하는 is_printable() 함수로 구성된다.
dict.c 파일은 num dictionary 파일의 내용을 프로그램에서 사용하기 쉽도록 dictionary 구조체로 옮기는 역할을 하는 함수들을 모아놓은 파일이다. dictionary를 만드는 중심적인 역할을 하는 make_dict() 함수와, 100부터 undecillion까지에 해당하는 dictionary 구조체 내 digit 파트를 만드는 make_dict_digit() 함수, 0부터 90까지에 해당하는 num 파트를 만드는 make_dict_num() 함수, 그리고 그 파트들의 실제 문자열을 읽어 들여 문자열로 반환하는 make_value() 함수가 있다.
count.c 파일은 수를 세서 반환해야 하는 함수를 모아둔 파일로, digit 파트의 자릿수를 세기 위한 count_digit() 함수와 dictionary를 만들기 전 value 값 중 최대값을 찾는 count_max() 함수가 있다. count_max()의 결괏값이 num과 digit 문자열 배열 내 각 문자열의 메모리를 할당할 때에 사용된다.
check_dict.c 파일은 dictionary를 모두 만들고 나서, 꼭 있어야 하는 필수적인 숫자들이 dictionary에 모두 포함되어 있는지를 확인하고 그렇지 않다면 Dict Error를 발생시킬 수 있도록 한다. check_dict() 함수에서 check_numdict() 함수를 호출하여 num 파트를, check_digitdict() 함수를 호출하여 digit 파트를 확인한다.
마지막으로 print.c 파일은 터미널로부터 입력받은 숫자를 변환하여 출력하는 과정을 담은 파일이다. write_num() 함수로 진입하여 예외 상황들을 처리해준 후 iter_write() 함수에서 세 자릿수씩 반복하며 print_hundred() -> print_ten() -> print_one() 순으로 호출된다. 예를 들어 123000이라는 숫자가 입력되었다면, print_hundred()에서 "one", print_ten()에서 "twenty", print_one()에서 "three"와 "thousand"라는 digit 파트까지도 출력이 될 것이다.
#ifndef MAIN_H
# define MAIN_H
# include <unistd.h>
# include <stdlib.h>
# include <fcntl.h>
# define NUM_LEN 92
# define DIGIT_LEN 39
typedef struct DICTIONARY
{
char **num;
char **digit;
} t_dictionary;
// main.c file
int set_init_values(int argc, char **argv, char **in, char **path);
void free_dict(t_dictionary *dict);
// ft_func.c file
void ft_putstr(char *str);
char **init_ary(int size);
int is_printable(char c);
// dict.c file
void make_dict(int max_size, int infile, t_dictionary *dict);
void make_dict_digit(int infile, int max_size, char num[10], char ***dict);
void make_dict_num(int infile, int max_size, char num[10], char ***dict);
char *make_value(int infile, int max_size);
// count.c file
int count_digits(char **num);
int count_max(char *path);
// check_dict.c file
int check_dict(t_dictionary dict);
int check_numdict(char **dict);
int check_digdict(char **dict);
// print.c file
int write_num(char *num, t_dictionary dict);
int iter_write(char *num, int digit, t_dictionary dict);
int print_hundred(char *num, int digit, t_dictionary dict, int flag);
int print_ten(char *num, int digit, t_dictionary dict, int flag);
int print_one(char *num, int digit, t_dictionary dict, int flag);
#endif
다음은 main 함수를 보겠다. 우선 set_init_values() 함수를 호출하여 파일 경로(p)와 변환해야 할 숫자(in)을 입력받아준다. 만약 parameter가 하나만 주어진다면 이는 숫자가 될 것이고 파일 경로는 이미 가지고 있는 "numbers.dict" 파일을 사용해줘야 한다. 하지만 두 개 주어진다면, 첫 번째 parameter는 파일 경로가 될 것이고, 두 번째 parameter가 숫자가 될 것이다. 따라서 이러한 과정을 set_init_value()를 통해 수행해 준다.
다음은 각각 dictionary의 num 파트와 digit 파트의 배열을 초기화해준다. 이때 init_ary() 함수를 호출하는데, init_ary() 함수는 입력받은 인자만큼의 크기를 가진 2차원 배열, 즉 문자열 배열을 모두 NULL로 초기화해서 리턴한다. 따라서 dict.num(num 파트)는 num 파트의 최대 개수인 NUM_LEN+1(NUM_LEN까지를 index로 사용할 수 있게 하기 위함)의 크기를, dict.digit(digit 파트)는 digit 파트의 최대 개수인 DIGIT_LEN+1의 크기를 가진 문자열 배열로 초기화해 준다.
다음은 set_init_value() 함수 내에서 설정해준 path에 저장된 파일을 열어서 inf 변수에 저장해 주고, 이를 인자로 주어 dict 구조체 변수에 파일 내용을 읽어 들여 저장하는 make_dict() 함수를 호출해 준다. 이후 check_dict() 함수를 이용하여 dict가 필수적인 숫자들을 모두 포함하고 있는지를 확인한다. 만약 그렇지 않다면 Dict Error를 출력하고 프로그램을 종료해야 한다.
이후 write_num() 함수를 호출하여, 만들어진 dict 구조체와 터미널로부터 입력받은 숫자 문자열인 in을 바탕으로 변환된 숫자를 출력해준다. 만약 출력이 정상적으로 이뤄지지 않았다면 Error를 리턴해준다.
int main(int argc, char **argv)
{
char *in; // input number string which we have to convert
char *p; // dictionary file path
int inf; // input file
t_dictionary dict; // dictionary which we will make with dictionary file
// set the p(path) and in(input number)
if (!set_init_values(argc, argv, &in, &p))
{
ft_putstr("Error\n");
return (0);
}
// initialize array in dictionary (set all the elements as 0)
dict.num = init_ary(NUM_LEN + 1);
if (dict.num == NULL)
{
ft_putstr("Error\n");
return (0);
}
dict.digit = init_ary(DIGIT_LEN + 1);
if (dict.digit == NULL)
{
free(dict.num);
ft_putstr("Error\n");
return (0);
}
// open file in path
inf = open(p, O_RDONLY);
// make a dictionary
make_dict(count_max(p), inf, &dict);
// check if dictionary is valid, and if it is write num
if (!check_dict(dict))
{
close(inf);
free_dict(&dict); // have mistake
ft_putstr("Dict Error\n");
return (0);
}
if (!write_num(in, dict))
ft_putstr("Error\n");
// deallocate the dictionary memory and close file
free_dict(&dict);
close(inf);
return (0);
}
다음은 dictionary를 만드는 주요 함수인 make_dict() 함수를 보려한다. dictionary를 만드는 방법은 우선 숫자를 만나면 해당 숫자부터 시작해서 그 줄을 읽어 들이면서 num 파트인지, digit 파트인지를 구분해서 각각을 만드는 함수에 넣는 식이다. 이때 해당 줄의 끝까지 읽기 때문에 형식에 맞는지도 함께 확인할 수 있다. 숫자로 시작하지 않는 줄은 new line character가 될 때까지 읽고 문자를 저장하지 않고 그냥 지나치게 된다.
num 파트인지 digit 파트인지 구분하기 위해서 우선 앞 세글자까지만 읽어 들인다. num 파트는 최대가 두 자릿수이므로 숫자일 때까지만 읽었을 때 3글자가 되었다면 이는 digit 파트라는 의미이므로 digit 파트를 만드는 함수인 make_dict_digit()을, 3글자가 안되었다면 num 파트라는 의미이므로 num 파트를 만드는 함수인 make_dict_num()을 호출한다. 이때 make_dict_num() 함수를 호출하기 전에 공백을 넘겨주는 이유는 dictionary의 형식이 "[a number] [0 to n space] : [0 to n space] [any printable character]\n"이기 때문이다. 따라서 공백을 다 넘겨준 후 다음이 ':' 문자인지까지 확인한다. digit 파트는 세 자리까지만 읽었지만 세 자릿수 이상일 수 있기 때문에 함수로 진입하여 숫자를 마저 읽어준 후 이를 확인한다.
이때 num파트와 digit파트를 만든다는 것은 올바른 index에 변환 결과값이 되어야 하는 문자열을 복사해 준다는 의미이다. 만약 14라면 num파트가 될 것이고 따라서 dict.num[14]에 주어진 문자열(ex. "fourteen")이 저장될 것이다. 혹은 만약 100000이라면 digit 파트가 될 것이고 따라서 dict.digit[6]에 저장될 것이다. (6 자릿수이기 때문에 index 6에 저장된다.)
위와 같은 과정을 파일을 모두 읽을 때까지 반복하여 dictionary 파일을 구조체로 옮겨준다.
void make_dict(int max_size, int infile, t_dictionary *dict)
{
char c;
char num[10];
int i;
while (read(infile, &c, 1) > 0)
{
if (c < '0' || c > '9')
{
while (c != '\n' && read(infile, &c, 1) > 0)
continue ;
continue ;
}
i = 0;
// save numeric character in num string
num[i++] = c;
while (i < 3 && read(infile, &c, 1) > 0 && c >= '0' && c <= '9')
num[i++] = c;
num[i] = 0;
if (i >= 3) // if it is over 90
make_dict_digit(infile, max_size, num, &(dict->digit));
else // if it is under 90
{
while (c == ' ' && read(infile, &c, 1) > 0)
continue ;
if (c == ':')
make_dict_num(infile, max_size, num, &(dict->num));
}
}
}
다음은 만들어진 dictionary와 입력받은 숫자를 바탕으로 변환하여 출력하는 파트의 주요 함수인 iter_write()을 보겠다. iter_write() 함수는 앞서 언급한대로 3자리를 단위로 반복하면서 결과를 출력한다. 하지만 자릿수가 3의 배수가 아닐 경우는 우선 3의 배수가 될 때까지 먼저 출력해 준 후 3씩 반복하기를 시작해 준다.
기본적으로 print_hundred()에서 "n hundred"를 출력해주고, print_ten()에서 1로 시작한다면 "eleven" ~ "nineteen"을 출력하고 아니라면 "twenty" ~ "ninety"를 출력해 준다. 그리고 마지막으로 print_one()에서 일의 자릿수 하나와 함께 현재 자릿수 위치에 알맞은 digit 파트 수를 출력해 주면 된다.
예를 들어 1234567이 있다고 해보자. 우선 일곱자리 수 이므로 print_one()으로 먼저 들어가 하나를 먼저 출력해 준다. 이는 "one million"이 될 것이다. 그리고 234가 하나의 단위이다. 2는 print_hundred()에서 "two hundred"로 출력될 것이고, 3은 print_ten()에서 "thrity" 그리고 4는 print_one()에서 "four thousand"로 digit 파트와 함께 출력될 것이다.
그리고 print_hundred(), print_ten(), print_one() 함수들을 보면, space나 flag와 같은 인자를 받는 것을 알 수 있는데, 이는 띄어쓰기나 digit 출력 때문이다. 예를 들어 100000이 있다고 해보자. 이는 "ten million"이다. 하지만 앞서 설명한 방식으로 출력하다 보면 "ten million thousand"와 같이 중간에 출력되지 않아야 할 digit 파트가 출력될 수 있다. 또한, 1000010이라면 1과 1 사이에 불필요한 공백이 출력될 수도 있다. 이를 방지하기 위해 여기서 공백 혹은 digit 파트를 출력하는 것이 맞는지를 반복하면서 알리기 위해서 이것이 필요하다.
int iter_write(char *num, int digit, t_dictionary dict)
{
int i;
i = digit;
if (digit % 3 == 2)
{
if (!print_ten(num, digit, dict, 2))
return (0);
num += 2;
digit -= 2;
}
else if (digit % 3 == 1)
{
if (!print_one(num, digit, dict, 2))
return (0);
num++;
digit--;
}
while (*num && digit > 0)
{
if (!print_hundred(num, digit, dict, (digit < i)))
return (0);
num += 3;
digit -= 3;
}
write(1, "\n", 1);
return (1);
}
다음은 전체 코드이다.
// main.h
#ifndef MAIN_H
# define MAIN_H
# include <unistd.h>
# include <stdlib.h>
# include <fcntl.h>
# define NUM_LEN 92
# define DIGIT_LEN 39
typedef struct DICTIONARY
{
char **num;
char **digit;
} t_dictionary;
// main.c file
int set_init_values(int argc, char **argv, char **in, char **path);
void free_dict(t_dictionary *dict);
// ft_func.c file
void ft_putstr(char *str);
char **init_ary(int size);
int is_printable(char c);
// dict.c file
void make_dict(int max_size, int infile, t_dictionary *dict);
void make_dict_digit(int infile, int max_size, char num[10], char ***dict);
void make_dict_num(int infile, int max_size, char num[10], char ***dict);
char *make_value(int infile, int max_size);
// count.c file
int count_digits(char **num);
int count_max(char *path);
// check_dict.c file
int check_dict(t_dictionary dict);
int check_numdict(char **dict);
int check_digdict(char **dict);
// print.c file
int write_num(char *num, t_dictionary dict);
int iter_write(char *num, int digit, t_dictionary dict);
int print_hundred(char *num, int digit, t_dictionary dict, int flag);
int print_ten(char *num, int digit, t_dictionary dict, int flag);
int print_one(char *num, int digit, t_dictionary dict, int flag);
#endif
// main.c
#include "main.h"
int main(int argc, char **argv)
{
char *in; // input number string which we have to convert
char *p; // dictionary file path
int inf; // input file
t_dictionary dict; // dictionary which we will make with dictionary file
// set the p(path) and in(input number)
if (!set_init_values(argc, argv, &in, &p))
{
ft_putstr("Error\n");
return (0);
}
// initialize array in dictionary (set all the elements as 0)
dict.num = init_ary(NUM_LEN + 1);
if (dict.num == NULL)
{
ft_putstr("Error\n");
return (0);
}
dict.digit = init_ary(DIGIT_LEN + 1);
if (dict.digit == NULL)
{
free(dict.num);
ft_putstr("Error\n");
return (0);
}
// open file in path
inf = open(p, O_RDONLY);
// make a dictionary
make_dict(count_max(p), inf, &dict);
// check if dictionary is valid, and if it is write num
if (!check_dict(dict))
{
close(inf);
free_dict(&dict); // have mistake
ft_putstr("Dict Error\n");
return (0);
}
if (!write_num(in, dict))
ft_putstr("Error\n");
// deallocate the dictionary memory and close file
free_dict(&dict);
close(inf);
return (0);
}
int set_init_values(int argc, char **argv, char **in, char **path)
{
// if main got only one parameter => that parameter is input number (using default file)
if (argc == 2)
{
(*in) = argv[1];
(*path) = "numbers.dict";
}
// if main got two parameters => first is file path, second is input number
else if (argc == 3)
{
(*in) = argv[2];
(*path) = argv[1];
}
else {
ft_putstr("Error\n");
return (0);
}
return (1);
}
void free_dict(t_dictionary *dict)
{
int i;
i = 0;
while (i < NUM_LEN)
free((dict->num)[i++]);
free(dict->num);
i = 0;
while (i < DIGIT_LEN)
free((dict->digit)[i++]);
free(dict->digit);
}
// ft_func.c
#include "main.h"
void ft_putstr(char *str)
{
while (*str)
write(1, str++, 1);
}
// initialize string array in dictionary with zero
char **init_ary(int size)
{
char **ary;
int i;
ary = (char **)malloc(sizeof(char *) * size);
if (ary == NULL)
return (NULL);
i = 0;
while (i < size)
ary[i++] = 0;
return (ary);
}
int is_printable(char c)
{
if (c >= 33 && c <= 126)
return (1);
else
return (0);
}
// dict.c
#include "main.h"
// mainly acting function for making dictionary
void make_dict(int max_size, int infile, t_dictionary *dict)
{
char c;
char num[10];
int i;
while (read(infile, &c, 1) > 0)
{
if (c < '0' || c > '9')
{
while (c != '\n' && read(infile, &c, 1) > 0)
continue ;
continue ;
}
i = 0;
// save numeric character in num string
num[i++] = c;
while (i < 3 && read(infile, &c, 1) > 0 && c >= '0' && c <= '9')
num[i++] = c;
num[i] = 0;
if (i >= 3) // if it is over 90
make_dict_digit(infile, max_size, num, &(dict->digit));
else // if it is under 90
{
while (c == ' ' && read(infile, &c, 1) > 0)
continue ;
if (c == ':')
make_dict_num(infile, max_size, num, &(dict->num));
}
}
}
// make number(which is under 90) dictionry
// key : integer number (ex. string "20" will be integer 20)
// value : text we should convert to (ex. for key 20, we will have value "twenty")
void make_dict_num(int infile, int max_size, char num[10], char ***dict)
{
int key;
// make key as integer
if (!num[1])
key = num[0] - '0';
else
key = (num[0] - '0') * 10 + num[1] - '0';
// put string(value) to proper location (in index key)
(*dict)[key] = make_value(infile, max_size);
return ;
}
// make digits(which is over 100) dictionary
// key : integer of the number of digits (ex. string "1000" will be integer 4)
// value : text we should convert to (ex. for key 4, we will have value "thousand")
void make_dict_digit(int infile, int max_size, char num[10], char ***dict)
{
char c;
int key;
// count the digits
if (num[0] != '1')
return ;
key = 1;
while (num[key])
{
if (num[key] != '0')
return ;
key++;
}
while (read(infile, &c, 1) > 0 && c == '0')
key++;
while (c == ' ' && read(infile, &c, 1) > 0)
continue ;
if (c != ':' || key > DIGIT_NUM)
return ;
// put string(value) to proper location (in index key)
(*dict)[key] = make_value(infile, max_size);
return ;
}
// make string for each number in the dictionary (ex. make "twenty")
char *make_value(int infile, int max_size)
{
char *value;
unsigned char c;
int i;
// use max_size which we made in count_max function
value = (char *)malloc(sizeof(char) * (max_size + 1));
if (value == NULL)
return (NULL);
// skip space
while (read(infile, &c, 1) > 0 && c == ' ')
continue ;
i = 0;
// put only printable character
if (is_printable(c))
value[i++] = c;
else
return (NULL);
while (read(infile, &c, 1) > 0 && c != '\n')
{
if (!is_printable(c))
return (NULL);
value[i] = c;
i++;
}
value[i] = 0;
return (value);
}
// count.c
#include "main.h"
int count_max(char *path)
{
int infile;
char c;
int count;
int max;
infile = open(path, O_RDONLY);
max = 0;
while (read(infile, &c, 1) > 0)
{
if (c == ':')
{
count = 0;
while (read(infile, &c, 1) > 0 && c != '\n' && c == ' ')
continue ;
while (read(infile, &c, 1) > 0 && c != '\n' && c != ' ')
count++;
if (count > max)
max = count;
}
}
close(infile);
return (max);
}
int count_digits(char **num)
{
int count;
while (**num == ' ')
++(*num);
while (**num == '0')
{
if (*(*num + 1) == 0)
return (1);
++(*num);
}
count = 0;
while ((*num)[count] && (*num)[count] >= '0' && (*num)[count] <= '9')
count++;
return (count);
}
// check_dict.c
#include "main.h"
int check_dict(t_dictionary dict)
{
if (!check_numdict(dict.num)) // check number part (0 to 90)
return (0);
if (!check_digdict(dict.digit)) // check digit part (from 100)
return (0);
return (1);
}
// check if dictionary have all the initial entries.
int check_numdict(char **dict)
{
int i;
i = 0;
while (i < 20)
{
if (dict[i] == 0)
return (0);
i++;
}
while (i <= 90)
{
if (dict[i] == 0)
return (0);
i += 10;
}
return (1);
}
int check_digdict(char **dict)
{
int i;
if (dict[3] == 0)
return (0);
i = 4;
while (i <= 37)
{
if (dict[i] == 0)
return (0);
i += 3;
}
return (1);
}
// write.c
#include "main.h"
int write_num(char *num, t_dictionary dict)
{
int digit;
digit = count_digits(&num); // count the number of digits of input number
if (digit <= 0 || digit > DIGIT_LEN)
return (0);
if (digit == 1)
{
ft_putstr((dict.num)[*num - '0']);
write(1, "\n", 1);
}
else if (!iter_write(num, digit, dict))
return (0);
return (1);
}
// convert and print number 3 by 3 digits
int iter_write(char *num, int digit, t_dictionary dict)
{
int i;
i = digit;
if (digit % 3 == 2)
{
if (!print_ten(num, digit, dict, 2))
return (0);
num += 2;
digit -= 2;
}
else if (digit % 3 == 1)
{
if (!print_one(num, digit, dict, 2))
return (0);
num++;
digit--;
}
while (*num && digit > 0)
{
if (!print_hundred(num, digit, dict, (digit < i)))
return (0);
num += 3;
digit -= 3;
}
write(1, "\n", 1);
return (1);
}
// space variable is for deciding if we should put space before printing something
int print_hundred(char *num, int digit, t_dictionary dict, int space)
{
if (*num == '0')
{
if (print_ten(num + 1, digit - 1, dict, 0))
return (1);
return (0);
}
if (space == 1)
write(1, " ", 1);
ft_putstr((dict.num)[*num - '0']);
write(1, " ", 1);
ft_putstr((dict.digit)[3]);
if (print_ten(num + 1, digit - 1, dict, 1))
return (1);
return (0);
}
// flag = 2 (first entry) || 0 (previous one is zero) || 1 (previous one is non-zero)
int print_ten(char *num, int digit, t_dictionary dict, int flag)
{
int temp;
if (*num == '0')
{
if (print_one(num + 1, digit - 1, dict, flag))
return (1);
return (0);
}
// if num is 1 we should go for "eleven, tweleve..." which is special case
if (*num == '1')
{
temp = (*num - '0') * 10 + (*(num + 1) - '0');
if (flag != 2)
write(1, " ", 1);
ft_putstr((dict.num)[temp]);
if (print_one("0", digit - 1, dict, 1))
return (1);
return (0);
}
if (flag != 2)
write(1, " ", 1);
ft_putstr((dict.num)[(*num - '0') * 10]);
if (print_one(num + 1, digit - 1, dict, 1))
return (1);
return (0);
}
int print_one(char *num, int digit, t_dictionary dict, int flag)
{
if (*num == '0' && flag == 0)
return (1);
if (*num == '0' && flag == 1)
{
if (digit == 1)
return (1);
if (digit % 3 == 1)
{
if (flag != 2)
write(1, " ", 1);
ft_putstr((dict.digit)[digit]);
return (1);
}
else
return (0);
}
if (flag != 2)
write(1, " ", 1);
ft_putstr((dict.num)[(*num) - '0']);
if (digit != 1)
{
write(1, " ", 1);
ft_putstr((dict.digit)[digit]);
}
return (1);
}
'Hive Helsinki [42 Helsinki]' 카테고리의 다른 글
[Hive Helsinki / Piscine] BSQ (0) | 2024.05.13 |
---|---|
[Hive Helsinki / Piscine] C08 (1) | 2024.05.01 |
[Hive Helsinki / Piscine] C07 (1) | 2024.04.26 |
[Hive Helsinki / Piscine] C06 (1) | 2024.04.19 |
[Hive Helsinki / Piscine] Rush01 (2) | 2024.04.18 |