# HW01 參考答案
## 1.1 My String Library
此題可參考 [glibc 的官方實作](https://sourceware.org/git/?p=glibc.git;a=tree;f=string;h=c3bbd3e7962e69e3c3b44c8f42e0c3b16cb59957;hb=refs/heads/master),值得一提的是他們將每個函式實作放在單獨的檔案中。
:::spoiler 同學的滿分解答 (Credit: 41247032S 吳O廷)
```c=
#include "mystring.h"
char *mystrchr(const char *s, int c){
char *ptr=NULL;
for(unsigned int i=0;i<strlen(s);i++){
if(s[i] == c){
ptr = (char*)&s[i];
break;
}
}
return ptr;
}
char *mystrrchr(const char *s, int c){
char *ptr=NULL;
for(int i=strlen(s)-1; i>=0; i--){
if(s[i] == c){
ptr = (char*)&s[i];
break;
}
}
return ptr;
}
size_t mystrspn(const char *s, const char *accept){
size_t i;
for (i = 0; s[i]; i++) {
bool found = false;
for (size_t j = 0; accept[j]; j++) {
if (s[i] == accept[j]) {
found = true;
break;
}
}
if (!found) {
break;
}
}
return i;
}
size_t mystrcspn(const char *s, const char *reject){
size_t i;
for (i = 0; s[i]; i++) {
bool found = false;
for (size_t j = 0; reject[j]; j++) {
if (s[i] == reject[j]) {
found = true;
break;
}
}
if (found) {
break;
}
}
return i;
}
char *mystrpbrk(const char *s, const char *accept){
for (size_t i = 0; s[i]; i++) {
for (size_t j = 0; accept[j]; j++) {
if (s[i] == accept[j]) {
return (char*)&s[i];
}
}
}
return NULL;
}
char *mystrstr(const char *haystack , const char *needle){
if (!*needle) {
return (char *)haystack;
}
for (size_t i = 0; haystack[i]; i++) {
if (haystack[i] == needle[0]) {
size_t j;
for (j = 0; needle[j]; j++) {
if (haystack[i + j] != needle[j]) {
break;
}
}
if (!needle[j]) {
return (char *)&haystack[i];
}
}
}
return NULL;
}
char *mystrtok(char *str, const char *delim){
static char *p = 0;
if(str) p = str;
else if(!p) return 0;
str = p + strspn(p, delim);
p = str + strcspn(str, delim);
if(p == str) return p = 0;
p = *p ? *p = 0, p + 1 : 0;
return str;
}
```
:::
## 1.2 String Calculator
其中包含測試用的 `hw0102.c` 以及範例 `cal.c`、`cal.h`,給大家看 AC code 的其中一種實作方法:
> Murmur: 可以參考 calculate 的邏輯設計、如何將不同工作拆分成模組,以及動態記憶體管理的方式。特別在輸入檢查 `is_invalid()` 可以看一遍
https://drive.google.com/file/d/18G9VQqN8R94KyeIEiFugm82ljgNeUAyX/view?usp=sharing
> `cal.c` example code from Darrin Lin (41247022S)
## 1.3 Chain Rule
助教提供的 `hw0103.c`[由此去](https://drive.google.com/drive/folders/1WLExo1vfjnTvF8a_xVIXEOVPyR7aJVoL?usp=drive_link) 是助教的解法,在這邊另外提供其他同學的解法:
Credit: 41247027S 陳O羽
:::spoiler mychain.c
```c
#include<stdint.h>
#include<stdlib.h>
#include<stdio.h>
typedef struct _sPoly{
uint32_t size;
uint32_t *pPowers;
int32_t *pCoefficients;
} sPoly;
void copy(sPoly *x,const sPoly*y){
(*x).size = (*y).size;
(*x).pPowers = calloc((*y).size,sizeof(uint32_t));
(*x).pCoefficients = calloc((*y).size,sizeof(int32_t));
for(int i=0;i<y->size;i++){
((*x).pPowers[i]) = ((*y).pPowers[i]);
((*x).pCoefficients[i]) = ((*y).pCoefficients[i]);
}
}
void move(sPoly *f,int32_t position){
for(int i=position;i<(*f).size;i++){
*((*f).pPowers+i) = *((*f).pPowers+i+1);
*((*f).pCoefficients+i) = *((*f).pCoefficients+i+1);
}
}
void sort(sPoly *f){
for(int i=0;i<(*f).size;i++){
for(int j=i+1;j<(*f).size;j++){
if(*((*f).pPowers+i)<*((*f).pPowers+j)){
int tmp = *((*f).pPowers+i);
*((*f).pPowers+i) = *((*f).pPowers+j);
*((*f).pPowers+j) = tmp;
tmp = *((*f).pCoefficients+i);
*((*f).pCoefficients+i) = *((*f).pCoefficients+j);
*((*f).pCoefficients+j) = tmp;
}
}
}
}
void arrange(sPoly *f){
for(int i=0;i<(*f).size;i++){
for(int j=i+1;j<(*f).size;j++){
if(((*f).pPowers[i])==((*f).pPowers[j])){
((*f).pCoefficients[i])+=((*f).pCoefficients[j]);
move(f,j);
((*f).size)--;
}
}
}
sort(f);
for(int i=0;i<(*f).size;i++){
if(((*f).pCoefficients[i])==0){
move(f,i);
((*f).size)--;
}
}
(*f).pCoefficients = realloc((*f).pCoefficients,((*f).size)*sizeof(int32_t));
(*f).pPowers = realloc((*f).pPowers,((*f).size)*sizeof(uint32_t));
}
void multi(sPoly *x,const sPoly *y){
sPoly tmp;
tmp.size = (*x).size;
tmp.pCoefficients=calloc(tmp.size,sizeof(int32_t));
tmp.pPowers=calloc(tmp.size,sizeof(uint32_t));
for(int i=0;i<tmp.size;i++)
*(tmp.pPowers+i) = -1;
for(int i=0;i<tmp.size;i++)
*(tmp.pCoefficients+i) = 0;
int used = 0;
for(int i=0;i<(*x).size;i++){
for(int j=0;j<y->size;j++){
int power = (*x).pPowers[i] + (*y).pPowers[j],coefficents = (*x).pCoefficients[i] * (*y).pCoefficients[j],find = 0;
for(int k=0;k<tmp.size;k++){
if(*(tmp.pPowers+k) == power){
*(tmp.pCoefficients+k) += coefficents;
find = 1;
break;
}
}
if(find == 0){
if(used<tmp.size){
tmp.pCoefficients[used] = coefficents;
tmp.pPowers[used] = power;
used++;
}
else{
tmp.size++;
tmp.pCoefficients=realloc(tmp.pCoefficients,tmp.size*sizeof(int32_t));
tmp.pPowers=realloc(tmp.pPowers,tmp.size*sizeof(uint32_t));
tmp.pCoefficients[used] = coefficents;
tmp.pPowers[used] = power;
used++;
}
}
}
}
arrange(&tmp);
copy(x,&tmp);
}
int32_t chain_rule( sPoly *pResult , const sPoly *pFy, const sPoly *pFx ){
if(pFy==NULL||pFx==NULL||pFx->pPowers==NULL||pFx->pCoefficients==NULL||pFy->pPowers==NULL||pFy->pCoefficients==NULL)
return -1;
sPoly Fx,Fy;
copy(&Fx,pFx);
copy(&Fy,pFy);
arrange(&Fy);
arrange(&Fx);
for(int i=0;i<Fy.size;i++){
Fy.pCoefficients[i] = Fy.pCoefficients[i]*Fy.pPowers[i];
if(Fy.pPowers[i]==0){
move(&Fy,i);
Fy.size--;
}
else
Fy.pPowers[i]--;
}
arrange(&Fy);
sPoly *tmp;
tmp = calloc(Fy.size,sizeof(sPoly));
sPoly tmp2;
for(int i=0;i<Fy.size;i++){
if(Fy.pPowers[i]==0){
(*(tmp+i)).size = 1;
(*(tmp+i)).pCoefficients = calloc(1,sizeof(int32_t));
(*(tmp+i)).pPowers = calloc(1,sizeof(uint32_t));
(*(tmp+i)).pCoefficients[0] = Fy.pCoefficients[i];
(*(tmp+i)).pPowers[0] = 0;
}
else{
for(int j=0;j<Fy.pPowers[i];j++){
if(j==0)
copy(tmp+i,pFx);
else
multi(tmp+i,pFx);
}
for(int j=0;j<(*(tmp+i)).size;j++){
(*(tmp+i)).pCoefficients[j] *= Fy.pCoefficients[i];
}
}
}
tmp2.size = tmp[0].size;
tmp2.pPowers = calloc(tmp2.size,sizeof(uint32_t));
tmp2.pCoefficients = calloc(tmp2.size,sizeof(uint32_t));
for(int i=0;i<tmp2.size;i++)
tmp2.pPowers[i] = -1;
for(int i=0;i<tmp2.size;i++)
tmp2.pCoefficients[i] = 0;
int used = 0;
for(int i=0;i<Fy.size;i++){
for(int j=0;j<(tmp[i]).size;j++){
int find = 0;
for(int k=0;k<tmp2.size;k++){
if((tmp[i]).pPowers[j] == tmp2.pPowers[k]){
find = 1;
tmp2.pCoefficients[k]+=(tmp[i]).pCoefficients[j];
break;
}
}
if(find == 0){
if(used<tmp2.size){
tmp2.pCoefficients[used] = (tmp[i]).pCoefficients[j];
tmp2.pPowers[used] = (tmp[i]).pPowers[j];
used++;
}
else{
tmp2.size++;
tmp2.pPowers = realloc(tmp2.pPowers,tmp2.size*sizeof(uint32_t));
tmp2.pCoefficients = realloc(tmp2.pCoefficients,tmp2.size*sizeof(uint32_t));
tmp2.pCoefficients[used] = (tmp[i]).pCoefficients[j];
tmp2.pPowers[used] = (tmp[i]).pPowers[j];
used++;
}
}
}
}
arrange(&tmp2);
copy(pResult,&tmp2);
for(int i=0;i<Fx.size;i++){
Fx.pCoefficients[i] = Fx.pCoefficients[i]*Fx.pPowers[i];
if(Fx.pPowers[i]==0){
move(&Fx,i);
Fx.size--;
}
else
Fx.pPowers[i]--;
}
multi(pResult,&Fx);
arrange(pResult);
return 0;
}
```
:::
:::spoiler mychain.h
```c
#include<stdint.h>
typedef struct _sPoly{
uint32_t size;
uint32_t *pPowers;
int32_t *pCoefficients;
} sPoly;
int32_t chain_rule( sPoly *pResult , const sPoly *pFy, const sPoly *pFx );
```
:::
## 1.4 Maze
:::spoiler mymaze.h
```c
#pragma once
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct _sRoom{
uint32_t cost;
uint8_t doors; // 8 bits: aabbccdd
// aa: the up door number 0-3
// bb: the right door number 0-3
// cc: the down number 0-3
// dd: the left door number 0-3
} sRoom;
typedef struct _sPoint {
uint32_t row;
uint32_t col;
} sPoint;
typedef struct _sPath {
uint32_t length; // Path length.
uint32_t cost; // Cost
sPoint *pPath; // An array of all points in order.
} sPath;
typedef enum Direction{
UP = 0,
RIGHT = 1,
DOWN = 2,
LEFT = 3
}Direction;
typedef struct _sMaze_info {
const sRoom *pMaze;
sPath *cur_min_path;
sPath *pMinPath;
uint32_t row;
uint32_t col;
bool *found;
bool has_path;
} sMaze_info;
// The start point is pMaze[0][0] and the exit point is pMaze[row -1][col -1]
// If there is no path , return 0; otherwise , return 1;
int32_t find_min_path(const sRoom *pMaze, const uint8_t row, const uint8_t col, sPath *pMinPath);
static void dfs_find_path(const sPoint src_pos);
static void add_room_to_path(const sPoint pos);
static void remove_room_from_path();
static bool is_arrive_maze_end(const sPoint pos);
static void update_min_path();
static bool can_move(const sPoint src_pos, const sPoint dest_pos, const Direction next_direction);
static bool has_path(const sRoom *src_room, const sRoom *dest_room, const Direction next_direction);
static int get_index(const sPoint pos);
static sRoom* get_room(const sPoint pos);
static uint8_t get_door(const sRoom *room, const Direction direction);
static sPoint get_dest_pos(const sPoint src_pos, const Direction next_direction);
static sMaze_info* create_maze_info(const sRoom *pMaze, const uint8_t row, const uint8_t col);
static void delete_maze_info(sMaze_info *maze_info);
static sPath* create_pMinPath(const uint16_t size);
static void free_pMinPath(sPath *pMinPath);
static void copy_pMinPath(const sPath *src, sPath *dest);
```
:::
:::spoiler mymaze.c
```c
#include "mymaze.h"
static sMaze_info *maze_info;
int32_t find_min_path(const sRoom *pMaze, const uint8_t row, const uint8_t col, sPath *pMinPath) {
bool has_path = false;
if (pMaze == NULL || pMinPath == NULL || row == 0 || col == 0) {
return -1;
}
maze_info = create_maze_info(pMaze, row, col);
dfs_find_path((sPoint){0, 0});
has_path = maze_info->has_path;
if (has_path) {
copy_pMinPath(maze_info->pMinPath, pMinPath);
}
delete_maze_info(maze_info);
return has_path ? 1 : 0;
}
static void dfs_find_path(const sPoint src_pos) {
if (is_arrive_maze_end(src_pos)) {
add_room_to_path((sPoint){maze_info->row - 1, maze_info->col - 1});
update_min_path();
remove_room_from_path();
maze_info->has_path = true;
return;
}
add_room_to_path(src_pos);
for (int direction = 0; direction < 4; direction++) {
const sPoint dest_pos = get_dest_pos(src_pos, direction);
if (can_move(src_pos, dest_pos, direction)) {
dfs_find_path(dest_pos);
}
}
remove_room_from_path();
}
static void add_room_to_path(const sPoint pos) {
maze_info->found[get_index(pos)] = true;
maze_info->cur_min_path->pPath[maze_info->cur_min_path->length] = pos;
maze_info->cur_min_path->cost += get_room(pos)->cost;
maze_info->cur_min_path->length++;
}
static void remove_room_from_path() {
maze_info->cur_min_path->length--;
const sPoint pos = maze_info->cur_min_path->pPath[maze_info->cur_min_path->length];
maze_info->cur_min_path->cost -= get_room(pos)->cost;
maze_info->found[get_index(pos)] = false;
maze_info->cur_min_path->pPath[maze_info->cur_min_path->length] = (sPoint){0, 0};
}
static bool is_arrive_maze_end(const sPoint pos) {
return pos.row == maze_info->row - 1 && pos.col == maze_info->col - 1;
}
static void update_min_path() {
if (maze_info->cur_min_path->cost >= maze_info->pMinPath->cost) {
return;
}
memcpy(maze_info->pMinPath->pPath, maze_info->cur_min_path->pPath, maze_info->row * maze_info->col * sizeof(sPoint));
maze_info->pMinPath->cost = maze_info->cur_min_path->cost;
maze_info->pMinPath->length = maze_info->cur_min_path->length;
}
static bool can_move(const sPoint src_pos, const sPoint dest_pos, const Direction direction) {
if (dest_pos.row < 0 || maze_info->row <= dest_pos.row || dest_pos.col < 0 || maze_info->col <= dest_pos.col) {
return false;
}
if (maze_info->found[get_index(dest_pos)]) {
return false;
}
const sRoom *src_room = get_room(src_pos);
const sRoom *dest_room = get_room(dest_pos);
if (!has_path(src_room, dest_room, direction)) {
return false;
}
return true;
}
static bool has_path(const sRoom *src_room, const sRoom *dest_room, const Direction direction) {
if (direction == UP && get_door(src_room, UP) == get_door(dest_room, DOWN)) {
return true;
}
if (direction == RIGHT && get_door(src_room, RIGHT) == get_door(dest_room, LEFT)) {
return true;
}
if (direction == DOWN && get_door(src_room, DOWN) == get_door(dest_room, UP)) {
return true;
}
if (direction == LEFT && get_door(src_room, LEFT) == get_door(dest_room, RIGHT)) {
return true;
}
return false;
}
static int get_index(const sPoint pos) {
return pos.row * maze_info->col + pos.col;
}
static sRoom* get_room(const sPoint pos) {
return (sRoom *)(maze_info->pMaze + get_index(pos));
}
static uint8_t get_door(const sRoom *room, const Direction direction) {
if (direction == UP) {
return (room->doors & 0b11000000) >> 6;
}
if (direction == RIGHT) {
return (room->doors & 0b00110000) >> 4;
}
if (direction == DOWN) {
return (room->doors & 0b00001100) >> 2;
}
if (direction == LEFT) {
return (room->doors & 0b00000011) >> 0;
}
return -1;
}
static sPoint get_dest_pos(const sPoint src_pos, const Direction direction) {
// UP, RIGHT, DOWN, LEFT
const int row_dir[4] = {-1, 0, 1, 0};
const int col_dir[4] = {0, 1, 0, -1};
return (sPoint){src_pos.row + row_dir[direction], src_pos.col + col_dir[direction]};
}
static sMaze_info* create_maze_info(const sRoom *pMaze, const uint8_t row, const uint8_t col) {
sMaze_info *maze_info;
maze_info = calloc(1, sizeof(sMaze_info));
if (maze_info == NULL) {
return NULL;
}
maze_info->pMaze = pMaze;
maze_info->row = row;
maze_info->col = col;
maze_info->has_path = false;
maze_info->found = calloc(row * col, sizeof(bool));
if (maze_info->found == NULL) {
free(maze_info);
return NULL;
}
maze_info->cur_min_path = create_pMinPath((uint16_t)row * (uint16_t)col);
maze_info->pMinPath = create_pMinPath((uint16_t)row * (uint16_t)col);
maze_info->pMinPath->cost = UINT32_MAX;
if (maze_info->cur_min_path == NULL) {
free(maze_info->found);
free(maze_info);
return NULL;
}
return maze_info;
}
static void delete_maze_info(sMaze_info *maze_info) {
if (maze_info == NULL) {
return;
}
if (maze_info->found != NULL) {
free(maze_info->found);
}
free_pMinPath(maze_info->cur_min_path);
free_pMinPath(maze_info->pMinPath);
free(maze_info);
}
static sPath* create_pMinPath(const uint16_t size) {
sPath *pMinPath;
pMinPath = (sPath *)calloc(1, sizeof(sPath));
if (pMinPath == NULL) {
return NULL;
}
pMinPath->length = 0;
pMinPath->cost = 0;
pMinPath->pPath = calloc(size, sizeof(sPoint));
if (pMinPath->pPath == NULL) {
free(pMinPath);
return NULL;
}
return pMinPath;
}
static void free_pMinPath(sPath *pMinPath) {
if (pMinPath == NULL) {
return;
}
if (pMinPath->pPath != NULL) {
free(pMinPath->pPath);
}
free(pMinPath);
}
static void copy_pMinPath(const sPath *src, sPath *dest) {
dest->length = src->length;
dest->cost = src->cost;
dest->pPath = calloc(src->length, sizeof(sPoint));
memcpy(dest->pPath, src->pPath, src->length * sizeof(sPoint));
}
```
:::
## 1.5 Taiko Music Generator
:::spoiler taiko.c
```c=
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
#include "taiko.h"
#define BUFFER_SIZE 1000
#define INIT_BPM_TAG "BPM:"
#define OFFSET_TAG "OFFSET:"
#define COURSE_TAG "COURSE:"
#define START_TAG "#START"
#define MEASURE_TAG "#MEASURE "
#define BPM_CHANGE "#BPMCHANGE "
#define END_TAG "#END"
#define MEASURE_SLICE_TAG ','
#define CHART_HEADER_CFG_TAG ":"
#define CHART_CFG_TAG "#"
#define COURSE_SYMBOL_EDIT "Edit"
#define COURSE_SYMBOL_EDIT_NUM "4"
#define COURSE_SYMBOL_ONI "Oni"
#define COURSE_SYMBOL_ONI_NUM "3"
#define COURSE_SYMBOL_HARD "Hard"
#define COURSE_SYMBOL_HARD_NUM "2"
#define COURSE_SYMBOL_NORMAL "Normal"
#define COURSE_SYMBOL_NORMAL_NUM "1"
#define COURSE_SYMBOL_EASY "Easy"
#define COURSE_SYMBOL_EASY_NUM "0"
// utility function define
size_t io_read(char***);
bool set_chart(Chart *, const float, char**, const uint64_t, const uint64_t);
uint8_t is_chart_content(const char*);
Measure add_measure(const char*, const float, const uint64_t, const uint64_t);
bool is_exist_taiko_note(const char*);
bool ReadtjaFile(Taiko **src)
{
// temp variable
float offset = 0.0;
float init_bpm = 0.0;
uint64_t course = 0;
// Read tja text file from stdin io
char **text = NULL;
size_t line = io_read(&text);
*src = (Taiko*)calloc(1, sizeof(Taiko));
(*src)->offset = 0;
for (int i = 0; i < 5; i++)
{
((*src)->chart)[i] = NULL;
}
// Process tja text file
for (int i = 0; i < line; i++)
{
if (strstr(text[i], OFFSET_TAG) != NULL) // get offset
{
if (sscanf(text[i], OFFSET_TAG"%f", &offset) != 1)
{
fprintf(stderr, "offset error when getting\n");
return false;
}
else
{
(*src)->offset = offset;
}
}
else if (strstr(text[i], INIT_BPM_TAG) != NULL) // get bpm
{
if (sscanf(text[i], INIT_BPM_TAG"%f", &init_bpm) != 1)
{
fprintf(stderr, "bpm error when getting\n");
return false;
}
}
else if (strstr(text[i], COURSE_TAG) != NULL) // get course and start to set Taiko->chart
{
if (strstr(text[i], COURSE_SYMBOL_EDIT) != NULL || strstr(text[i], COURSE_SYMBOL_EDIT_NUM) != NULL)
{
course = EDIT;
}
else if (strstr(text[i], COURSE_SYMBOL_ONI) != NULL || strstr(text[i], COURSE_SYMBOL_ONI_NUM) != NULL)
{
course = ONI;
}
else if (strstr(text[i], COURSE_SYMBOL_HARD) != NULL || strstr(text[i], COURSE_SYMBOL_HARD_NUM) != NULL)
{
course = HARD;
}
else if (strstr(text[i], COURSE_SYMBOL_NORMAL) != NULL || strstr(text[i], COURSE_SYMBOL_NORMAL_NUM) != NULL)
{
course = NORMAL;
}
else if (strstr(text[i], COURSE_SYMBOL_EASY) != NULL || strstr(text[i], COURSE_SYMBOL_EASY_NUM) != NULL)
{
course = EASY;
}
else
{
fprintf(stderr, "course value invalid\n");
return false;
}
for (int j = i; i < line; j++)
{
if (strstr(text[j], END_TAG) != NULL)
{
((*src)->chart)[course] = (Chart*)calloc(1, sizeof(Chart));
if ( !set_chart((*src)->chart[course], init_bpm, text, i, j) )
{
return false;
}
((*src)->chart)[course]->course = course;
break;
}
}
}
}
return true;
}
void WritejsonFile(const Taiko *src)
{
puts("{");
puts("\t\"data\": [");
for (int i = 4; i >= 0; i--)
{
if(src->chart[i] == NULL) continue;
puts("\t\t{");
printf("\t\t\t\"course\": %d,\n", src->chart[i]->course);
puts("\t\t\t\"chart\": [");
float music_time = -(src->offset);
bool flag = false;
for (int j = 0; j < src->chart[i]->measure_size; j++)
{
const char *measure = src->chart[i]->measure[j].chart_content;
const uint64_t bpm = src->chart[i]->measure[j].bpm;
const uint64_t beat = src->chart[i]->measure[j].beat;
const uint64_t note = src->chart[i]->measure[j].note;
const float duration = (60.0 / (float)bpm) * ((float)beat / (float)strlen(measure)) * (4.0 / (float)note);
for (int m = 0; m < strlen(measure); m++)
{
TaikoNote n = measure[m] - '0';
if (n >= DON && n <= BIGKA)
{
if(flag) printf(",\n");
printf("\t\t\t\t[%d, %f]", n, music_time);
flag = true;
}
music_time += duration;
}
}
flag = false;
puts("\n\t\t\t]");
printf("\t\t}");
if(i <= 0)
{
printf("\n");
}
else
{
printf(",\n");
}
}
puts("\t]");
puts("}");
}
size_t io_read(char*** src)
{
size_t size = 0;
char *buffer = (char*)calloc(BUFFER_SIZE, sizeof(char*));
while (scanf("%[^\n]%*c", buffer) != EOF)
{
*src = (char**)realloc(*src, (size + 1) * sizeof(char**));
for (size_t i = 0; i < strlen(buffer); i++)
{
if (buffer[i] == '\n' || buffer[i] == '\r')
{
buffer[i] = 0;
}
}
(*src)[size] = (char*)calloc(strlen(buffer)+1, sizeof(char*));
strncpy((*src)[size], buffer, strlen(buffer));
memset(buffer, 0, BUFFER_SIZE);
size++;
}
return size;
}
bool set_chart(Chart *chart, const float init_bpm, char **text, const uint64_t start, const uint64_t end)
{
// set measure
chart->measure = (Measure*)calloc(1, sizeof(Measure));
chart->measure_size = 0;
uint64_t beat = 4;
uint64_t note = 4;
float bpm = init_bpm;
char *tmp_chart_content = (char*)calloc(1, sizeof(char));
for (int i = start; i < end; i++)
{
uint8_t flag = is_chart_content(text[i]);
// get now measure
if (strstr(text[i], MEASURE_TAG) != NULL)
{
if (sscanf(text[i], MEASURE_TAG"%d/%d", &beat, ¬e) != 2)
{
fprintf(stderr, "measure error when getting\n");
return false;
}
}
else if (strstr(text[i], BPM_CHANGE) != NULL)
{
if (sscanf(text[i], BPM_CHANGE"%f", &bpm) != 1)
{
fprintf(stderr, "bpm_change error when getting\n");
return false;
}
}
else if (flag > 0)
{
if (flag == 1)
{
text[i][strlen(text[i]) - 1] = 0;
}
tmp_chart_content = (char *)realloc(tmp_chart_content, sizeof(char) * ((strlen(text[i]) + strlen(tmp_chart_content) + 1)));
tmp_chart_content[strlen(text[i]) + strlen(tmp_chart_content)] = 0;
strncat(tmp_chart_content, text[i], strlen(text[i]));
if (flag == 1)
{
chart->measure = (Measure*)realloc(chart->measure, (chart->measure_size + 1) * sizeof(Measure));
(chart->measure)[chart->measure_size] = add_measure(tmp_chart_content, bpm, beat, note);
chart->measure_size++;
memset(tmp_chart_content, 0, strlen(tmp_chart_content) * sizeof(char));
}
}
}
return true;
}
uint64_t lcm(uint64_t a, uint64_t b)
{
uint64_t tempA = a, tempB = b;
while (a != b)
{
if (a < b)
{
a += tempA;
} else
{
b += tempB;
}
}
return a;
}
Measure add_measure(const char *chart_content, const float bpm, const uint64_t beat, const uint64_t note)
{
Measure tmp_m;
tmp_m.beat = beat;
tmp_m.bpm = bpm;
tmp_m.note = note;
size_t len_chart_content = strlen(chart_content);
if(len_chart_content < beat)
{
uint64_t temp_beat = 0;
if(len_chart_content == 0)
{
tmp_m.chart_content = (char*)calloc(beat + 1, sizeof(char));
temp_beat = beat;
}
else
{
temp_beat = lcm(len_chart_content, beat);
tmp_m.chart_content = (char*)calloc(temp_beat + 1, sizeof(char));
}
for (int i = 0; i < temp_beat; i++)
{
if(len_chart_content == 0)
{
tmp_m.chart_content[i] = BLANK + '0';
}
else if(i % (temp_beat/len_chart_content) == 0)
{
tmp_m.chart_content[i] = chart_content[i/(temp_beat/len_chart_content)];
}
else
{
tmp_m.chart_content[i] = BLANK + '0';
}
}
}
else
{
tmp_m.chart_content = (char*)calloc(len_chart_content + 1, sizeof(char));
strncpy(tmp_m.chart_content, chart_content, len_chart_content);
}
return tmp_m;
}
uint8_t is_chart_content(const char *str)
{
size_t str_len = strlen(str);
if (strstr(str, CHART_CFG_TAG) != NULL || strstr(str,CHART_HEADER_CFG_TAG) != NULL)
{
return 0;
}
if (str[str_len - 1] == MEASURE_SLICE_TAG)
{
return 1;
}
else if(str[str_len - 1] >= '0' && str[str_len - 2] <= '9')
{
return 2;
}
return 0;
}
```
:::
:::spoiler taiko.h
```c=
#pragma once
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
typedef enum _Course {
EASY = 0,
NORMAL,
HARD,
ONI,
EDIT
} Course;
typedef enum _TaikoNote {
BLANK = 0,
DON,
KA,
BIGDON,
BIGKA,
DRUMROLL,
BIGDRUMROLL,
BALLOON,
END,
POTATO
} TaikoNote;
typedef struct _Measure
{
char *chart_content;
float bpm;
uint64_t beat;
uint64_t note;
} Measure;
typedef struct _Chart
{
Course course;
Measure *measure;
uint64_t measure_size;
} Chart;
typedef struct _Taiko
{
Chart *chart[5];
float offset;
} Taiko;
bool ReadtjaFile(Taiko **);
void WritejsonFile(const Taiko *);
```
:::
::: spoiler hw0105.c
```c=
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "taiko.h"
int main()
{
Taiko *src = NULL;
if ( !ReadtjaFile(&src) ) return 0;
WritejsonFile(src);
return 0;
}
```
:::
## 1.6 Bonus: _BitInt(N)
1. $2^{\lceil log_2(N / 8) \rceil}$ (size 只會是 1, 2, 4, 8, 16 byte 喔,單純回答 $N / 8$ 是錯的)
2. 會導致 overflow 僅保留後 N 位 (僅回答 overflow 或是 warning 不夠完整,我會算錯)
3. Yes
4. unsigned _BitInt
5. Error