# CP2 MID 參考答案 ## 1. Matrix Multiplication Credit: 41047012S 簡碩辰 (有做些微修改) :::spoiler mid01.c ```c #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> int matrix_multiply(int32_t **result, int32_t **matrix, int32_t **tmp, int32_t result_row, int32_t result_col, int32_t matrix_row, int32_t matrix_col) { if (result_col != matrix_row) { printf("Multiplication Fails\n"); return -1; } for(int i = 0; i < result_row; i++) { for(int j = 0; j < matrix_col; j++) { tmp[i][j] = 0; for (int k = 0; k < result_col; k++) { tmp[i][j] += result[i][k] * matrix[k][j]; } } } return 0; } int main() { int32_t count = 1; int32_t **result = NULL; int32_t result_row, result_col; while (1) { printf("%d matrix: ", count); char *input = calloc(sizeof(char), 1000); fgets(input, 1000, stdin); if (input[strlen(input) - 1] == '\n') input[strlen(input) - 1] = '\0'; if (strcmp(input, "end") == 0) { free(input); printf("Result: ["); for(int i = 0;i < result_row;i++) { printf("["); for(int j = 0;j < result_col;j++) { printf("%d",result[i][j]); if(j != result_col-1) printf(","); } printf("]"); if(i != result_row-1) printf(","); } printf("]\n"); break; } int32_t cnt = 0; int32_t len = strlen(input); int32_t right_bracket_count = 0,left_bracket_count = 0, comma = 0; for (int i = 0; i < len; i++) { if (input[i] == ']') { right_bracket_count++; cnt++; } else if (input[i] == '[') { left_bracket_count++; cnt++; } else if (input[i] == ',') { comma++; cnt++; } } if(right_bracket_count != left_bracket_count || cnt == len) { printf("Invalid Input\n"); return 0; } int32_t row = right_bracket_count - 1; int32_t col = (comma - (row - 1)) / row + 1; int32_t **matrix = calloc(sizeof(int32_t *), row); for (int i = 0; i < row; i++) matrix[i] = calloc(sizeof(int32_t), col); int32_t i = 0, j = 0; char *token = strtok(input, ",[]"); while (token != NULL) { if (i < row && j < col) { matrix[i][j] = atoi(token); j++; if (j >= col) { j = 0; i++; } } token = strtok(NULL, ",[]"); } if (count > 1) { int32_t tmp_row = result_row, tmp_col = col; int32_t **tmp = calloc(sizeof(int32_t*),tmp_row); for(int i = 0;i < tmp_row;i++) tmp[i] = calloc(sizeof(int32_t),tmp_col); if(matrix_multiply(result, matrix, tmp, result_row, result_col, row, col) == -1) return 0; for (int i = 0; i < result_row; i++) free(result[i]); free(result); result = tmp; result_row = tmp_row; result_col = tmp_col; } else { result_row = row; result_col = col; result = calloc(sizeof(int32_t *), result_row); for (int i = 0; i < result_row; i++) result[i] = calloc(sizeof(int32_t), result_col); for (int i = 0; i < result_row; i++) { for (int j = 0; j < result_col; j++) { result[i][j] = matrix[i][j]; } } } for (int i = 0; i < row; i++) free(matrix[i]); free(matrix); free(input); count++; } if (result != NULL) { for (int i = 0; i < result_row; i++) free(result[i]); free(result); } return 0; } ``` ::: ## 2. Text Compression :::spoiler ```clike= #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <stdbool.h> #include <stdint.h> #define MAX_CODE_LENGTH 20 #define BUFFER_SIZE 1024 typedef struct { char symbol; char code[MAX_CODE_LENGTH + 1]; } CodebookEntry; int32_t loadCodebook(const char* filename, CodebookEntry codebook[], int32_t* size); void encode(const char* inputFilename, const char* outputFilename, CodebookEntry codebook[], int32_t size); int main() { char codebookFile[100], inputFile[100], outputFile[100]; CodebookEntry codebook[30]; // max 29 entries int32_t size = 0; printf("Codebook: "); scanf("%s", codebookFile); if (loadCodebook(codebookFile, codebook, &size) != 0) { fprintf(stderr, "Failed to load codebook.\n"); return 1; } printf("Input File: "); scanf("%s", inputFile); printf("Output File: "); scanf("%s", outputFile); encode(inputFile, outputFile, codebook, size); return 0; } int32_t loadCodebook(const char* filename, CodebookEntry codebook[], int32_t* size) { FILE* file = fopen(filename, "r"); if (file == NULL) { fprintf(stderr, "Failed to open file \"%s\".\n", filename); return 1; } char buffer[BUFFER_SIZE]; char *line = NULL; size_t len = 0; ssize_t read; while ((read = getline(&line, &len, file)) != -1) { char symbol[10], code[MAX_CODE_LENGTH + 1]; sscanf(line, "%s %s", symbol, code); symbol[strlen(symbol) - 1] = '\0'; // remove ':' // comma, space, period, a-z if (strncmp(symbol, "space", 5) == 0) { codebook[*size].symbol = ' '; } else if (strncmp(symbol, "comma", 5) == 0) { codebook[*size].symbol = ','; } else if (strncmp(symbol, "period", 6) == 0) { codebook[*size].symbol = '.'; } else if (symbol[0] >= 'a' && symbol[0] <= 'z'&& strlen(symbol) == 1){ codebook[*size].symbol = symbol[0]; } else { fprintf(stderr, "Invalid symbol \"%s\".\n", symbol); return 1; } strcpy(codebook[*size].code, code); (*size)++; } fclose(file); return 0; } void encode(const char* inputFilename, const char* outputFilename, CodebookEntry codebook[], int32_t size) { FILE* inputFile = fopen(inputFilename, "r"); char outputBuffer[BUFFER_SIZE]; outputBuffer[0] = '\0'; char buffer[BUFFER_SIZE]; while (fgets(buffer, BUFFER_SIZE, inputFile) != NULL) { for (int32_t i = 0; buffer[i] != '\0'; i++) { bool matched = false; for (int32_t j = 0; j < size; j++) { if (buffer[i] == codebook[j].symbol) { strncat(outputBuffer, codebook[j].code, BUFFER_SIZE - strlen(outputBuffer) - 1); matched = true; break; } } if (!matched) { fprintf(stderr, "Invalid symbol \"%c\".\n", buffer[i]); return; } } } fclose(inputFile); int32_t padding = 8 - (strlen(outputBuffer) % 8); size_t currentLength = strlen(outputBuffer); outputBuffer[currentLength] = '1'; for (int32_t i = 1; i <= padding; i++) { outputBuffer[currentLength + i] = '0'; } outputBuffer[currentLength + padding] = '\0'; FILE* outputFile = fopen(outputFilename, "wb"); for (int32_t i = 0; i < strlen(outputBuffer); i += 8) { char byte = 0; for (int32_t j = 0; j < 8; j++) { byte = byte << 1; byte += outputBuffer[i + j] - '0'; } fwrite(&byte, 1, 1, outputFile); } fclose(outputFile); } ``` ::: ## 3. Face/Off Credit by: 41247039S 韓O劭 :::spoiler mid03.c ```c= #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include "mybmp.h" #include "myfile.h" int32_t processFile(FILE *cov, FILE *new, FILE *out, int32_t x, int32_t y, int32_t w, int32_t h); int main() { FILE *covFile = NULL; FILE *newFile = NULL; FILE *outFile = NULL; char covName[F_SIZE] = {0}; char newName[F_SIZE] = {0}; char outName[F_SIZE] = {0}; printf("cover: "); if (inputFileName(covName) != 0) { return 1; } if (openFile(&covFile, covName, "rb") != 0) { return 1; } int32_t x, y, w, h; printf("x (in pixel): "); scanf("%d", &x); printf("y (in pixel): "); scanf("%d", &y); printf("w (in pixel): "); scanf("%d", &w); printf("h (in pixel): "); scanf("%d", &h); // Clear input buffer while (getchar() != '\n'); printf("new: "); if (inputFileName(newName) != 0) { return 1; } if (openFile(&newFile, newName, "rb") != 0) { closeFile(covFile); return 1; } printf("Output file: "); if (inputFileName(outName) != 0) { closeFile(covFile); closeFile(newFile); return 1; } if (strcmp(covName, outName) == 0) { printf("Input file name and output file name cannot be the same.\n"); closeFile(covFile); closeFile(newFile); return 1; } if (openFile(&outFile, outName, "wb") != 0) { closeFile(covFile); closeFile(newFile); return 1; } if (processFile(covFile, newFile, outFile, x, y, w, h) != 0) { closeFile(covFile); closeFile(newFile); closeFile(outFile); return 1; } closeFile(covFile); closeFile(outFile); return 0; } int32_t processFile(FILE *cov, FILE *new, FILE *out, int32_t x, int32_t y, int32_t w, int32_t h) { BMP covBMP = {NULL, NULL}; BMP newBMP = {NULL, NULL}; if (initBMP(&covBMP, cov) != 0) { return 1; } if (initBMP(&newBMP, new) != 0) { freeBMP(&covBMP); return 1; } // TODO: Process BMP here int32_t covWidth = covBMP.header->width; int32_t covHeight = covBMP.header->height; if (covHeight < 0) { covHeight = -covHeight; } int32_t xPos = x; int32_t yPos = covHeight - y - h; // if (xPos < 0 || yPos < 0) { // printf("Invalid position\n"); // freeBMP(&covBMP); // freeBMP(&newBMP); // return 1; // } for (int32_t i = 0; i < h; i++) { for (int32_t j = 0; j < w; j++) { if (xPos + j < 0 || yPos + i < 0 || xPos + j >= covWidth || yPos + i >= covHeight) { continue; } // scale newBMP to w times h int32_t newX = (int32_t) (j * (newBMP.header->width - 1) / (w - 1)); int32_t newY = (int32_t) (i * (newBMP.header->height - 1) / (h - 1)); covBMP.pixels[yPos + i][xPos + j].r = newBMP.pixels[newY][newX].r; covBMP.pixels[yPos + i][xPos + j].g = newBMP.pixels[newY][newX].g; covBMP.pixels[yPos + i][xPos + j].b = newBMP.pixels[newY][newX].b; } } if (writeBMP(&covBMP, out) != 0) { freeBMP(&covBMP); return 1; } freeBMP(&covBMP); return 0; } ``` ::: :::spoiler mybmp.c ```c= #include "mybmp.h" int32_t initBMP(BMP *bmp, FILE *file) { if (initBMPHeader(bmp) != 0) { return -1; } if (parseBMPHeader(bmp, file) != 0) { freeBMP(bmp); return -1; } if (initBMPPixels(bmp) != 0) { freeBMP(bmp); return -1; } if (parseBMPPixels(bmp, file) != 0) { freeBMP(bmp); return -1; } return 0; } int32_t initBMPHeader(BMP *bmp) { bmp->header = (BmpHeader *) calloc(1, sizeof(BmpHeader)); if (bmp->header == NULL) { printf("mybmp: initBMPHeader error"); return -1; } return 0; } int32_t initBMPPixels(BMP *bmp) { int32_t height = bmp->header->height; int32_t width = bmp->header->width; if (height < 0) { height = -height; } bmp->pixels = (BmpPixel **) calloc(height, sizeof(BmpPixel *)); if (bmp->pixels == NULL) { printf("mybmp: initBMPPixels height error"); return -1; } for (int32_t i = 0; i < height; i++) { bmp->pixels[i] = (BmpPixel *) calloc(width, sizeof(BmpPixel)); if (bmp->pixels[i] == NULL) { printf("mybmp: initBMPPixels width error"); return -1; } } return 0; } int32_t parseBMPHeader(BMP *bmp, FILE *file) { if (fread(bmp->header, sizeof(BmpHeader), 1, file) != 1) { printf("mybmp: parseBMPHeader error"); return -1; } // Check if the file is a BMP file if (bmp->header->bm[0] != 'B' || bmp->header->bm[1] != 'M') { printf("mybmp: parseBMPHeader file error"); return -1; } return 0; } int32_t parseBMPPixels(BMP *bmp, FILE *file) { int32_t width = bmp->header->width; int32_t height = bmp->header->height; if (height < 0) { height = -height; } int32_t padding = (width * 3) % 4; for (int32_t i = 0; i < height; i++) { size_t read = fread(bmp->pixels[i], sizeof(BmpPixel), width, file); if (read != (size_t) width) { printf("mybmp: parseBMPPixels width error"); return -1; } if (padding > 0) { fseek(file, padding, SEEK_CUR); } } return 0; } int32_t writeBMP(BMP *bmp, FILE *file) { // Write BMP header if (fwrite(bmp->header, sizeof(BmpHeader), 1, file) != 1) { printf("mybmp: writeBMP error"); return -1; } // Write BMP pixels int32_t width = bmp->header->width; int32_t height = bmp->header->height; if (height < 0) { height = -height; } int32_t padding = (4 - (width * 3) % 4) % 4; // printf("padding: %d\n", padding); for (int32_t i = 0; i < height; i++) { if (fwrite(bmp->pixels[i], sizeof(BmpPixel), width, file) != (size_t) width) { printf("mybmp: writeBMP error"); return -1; } uint8_t zero = 0; for (int32_t j = 0; j < padding; j++) { if (fwrite(&zero, sizeof(uint8_t), 1, file) != 1) { printf("mybmp: writeBMP error"); return -1; } } } return 0; } int32_t freeBMP(BMP *bmp) { if (bmp == NULL || bmp->header == NULL) { return 0; } int32_t height = bmp->header->height; freeBMPHeader(bmp->header); freeBMPPixels(bmp->pixels, height); return 0; } void freeBMPHeader(BmpHeader *header) { if (header == NULL) { return; } free(header); } void freeBMPPixels(BmpPixel **pixels, int32_t height) { if (pixels == NULL) { return; } if (height < 0) { height = -height; } for (int32_t i = 0; i < height; i++) { free(pixels[i]); } free(pixels); } ``` ::: :::spoiler mybmp.h ```c= #pragma once #include <stdio.h> #include <stdint.h> #include <stdlib.h> typedef struct __attribute__ ((__packed__)) _BmpHeader { char bm[2]; uint32_t size; uint32_t reserve; uint32_t offset; uint32_t header_size; int32_t width; int32_t height; uint16_t planes; uint16_t bpp; uint32_t compression; uint32_t bitmap_size; int32_t hres; int32_t vres; uint32_t used; uint32_t important; } BmpHeader; typedef struct __attribute__ ((__packed__)) _bmpPixel { uint8_t b; uint8_t g; uint8_t r; } BmpPixel; typedef struct _BMP { BmpHeader *header; BmpPixel **pixels; } BMP; /** * Initialize BMP from file stream. * @param bmp BMP struct * @param file file stream * @return 0 if success, otherwise non-zero value */ int32_t initBMP(BMP *bmp, FILE *file); /** * Initialize BMP header. * @param bmp BMP struct * @return 0 if success, otherwise non-zero value */ int32_t initBMPHeader(BMP *bmp); /** * Initialize BMP pixels. * @param bmp BMP struct * @return 0 if success, otherwise non-zero value */ int32_t initBMPPixels(BMP *bmp); /** * Parse BMP header from file stream. * @param bmp BMP struct * @param file file stream * @return 0 if success, otherwise non-zero value */ int32_t parseBMPHeader(BMP *bmp, FILE *file); /** * Parse BMP pixels from file stream. * @param bmp BMP struct * @param file file stream * @return 0 if success, otherwise non-zero value */ int32_t parseBMPPixels(BMP *bmp, FILE *file); /** * Write BMP to file stream. * @param bmp BMP struct * @param file file stream * @return 0 if success, otherwise non-zero value */ int32_t writeBMP(BMP *bmp, FILE *file); /** * Free BMP. * @param bmp BMP struct * @return 0 if success, otherwise non-zero value */ int32_t freeBMP(BMP *bmp); /** * Free BMP header. * @param header BMP header */ void freeBMPHeader(BmpHeader *header); /** * Free BMP pixels. * @param pixels BMP pixels * @param height BMP height */ void freeBMPPixels(BmpPixel **pixels, int32_t height); ``` ::: :::spoiler myfile.c ```c= #include "myfile.h" int32_t inputFileName(char *file) { if (fgets(file, F_SIZE, stdin) == NULL) { if (fgetc(stdin) == EOF) { printf("myfile: EOF detected\n"); } else { perror("myfile: input error"); } return -1; } if (file[strlen(file) - 1] == '\n') { file[strlen(file) - 1] = '\0'; } return 0; } int32_t openFile(FILE **file, char *fileName, char *mode) { *file = fopen(fileName, mode); if (*file == NULL) { char err[F_SIZE] = {0}; snprintf(err, F_SIZE, "myfile: '%s' error", fileName); perror(err); return -1; } return 0; } void closeFile(FILE *file) { if (file == NULL) { return; } fclose(file); } ``` ::: :::spoiler myfile.h ```c= #pragma once #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #define F_SIZE 4096 /** * Input a file name. * @param fileName the file name to be set. * @return 0 if the input is successful, -1 otherwise. */ int32_t inputFileName(char *fileName); /** * Open a file. * @param file the file stream pointer. * @param fileName the file name. * @param mode the open mode. * @return 0 if the file is opened successfully, -1 otherwise. */ int32_t openFile(FILE **file, char *fileName, char *mode); /** * Close a file. * @param file the file stream pointer. */ void closeFile(FILE *file); ``` ::: ## 4. Colorful Fantastic Render System [] Credit by: 40921135L 黃嘉 :::spoiler mid04.c ```c= #include <stdio.h> #include <stdlib.h> #define WIDTH 256 #define HEIGHT 256 #pragma pack(push, 1) typedef struct { unsigned short type; unsigned int size; unsigned short reserved1; unsigned short reserved2; unsigned int offset; unsigned int header_size; int32_t width; int32_t height; unsigned short planes; unsigned short bpp; unsigned int compression; unsigned int bitmap_size; int32_t hres; int32_t vres; unsigned int used; unsigned int important; } BMPHeader; #pragma pack(pop) typedef struct { unsigned char r,g,b; } RGB; typedef struct { BMPHeader header; RGB *pixels; } BMPImage; RGB changeColor(int colorindex) { RGB color; switch (colorindex) { case 0: color.r = 0x00; color.g = 0x00; color.b = 0x00; break; case 1: color.b = 0x33; color.g = 0x66; color.r = 0xff; break; case 2: color.b = 0x00; color.g = 0xcc; color.r = 0x00; break; case 3: color.b = 0x00; color.g = 0xcc; color.r = 0xcc; break; case 4: color.b = 0xcc; color.g = 0x00; color.r = 0x00; break; case 5: color.b = 0xcc; color.g = 0x00; color.r = 0xcc; break; case 6: color.b = 0xcc; color.g = 0xcc; color.r = 0x00; break; case 7: color.b = 0xff; color.g = 0xff; color.r = 0xff; break; } return color; } int32_t y=128; int32_t x = 127; int32_t dy[8] = {1,1,0,-1,-1,-1,0,1}; int32_t dx[8] = {0,1,1,1,0,-1,-1,-1}; int32_t d_index =0; int32_t color_index = 7; void route(BMPImage *bmp,const char* commands,int start,int level) { for(int i=start;commands[i]!='\0';i++) { if(commands[i]=='F') { // printf("F"); bmp->pixels[y*WIDTH+x] = changeColor(color_index); y+=dy[d_index]; x+=dx[d_index]; } else if(commands[i]=='R') { // printf("R"); d_index++; d_index%=8; } else if(commands[i]=='C') { // printf("C"); color_index++; color_index%=8; } else if(commands[i]=='[') { route(bmp,commands,i+1,1); level++; } else if(commands[i]==']') { level--; if(level==0) { break; } } } } int main() { char filename[100]; int32_t r; int32_t g; int32_t b; char commands[300]; printf("Enter the output filename: "); scanf("%99s", filename); getchar(); printf("Enter the background color (R,G,B): "); scanf("(%d,%d,%d)", &r, &g, &b); printf("Type code here: "); scanf("%s",commands); BMPImage bmp; bmp.header.type = 0x4D42; bmp.header.size = 54 + 256*256*3; bmp.header.reserved1=0; bmp.header.reserved2=0; bmp.header.offset = 54; bmp.header.header_size = 40; bmp.header.width = 256; bmp.header.height = 256; bmp.header.planes = 1; bmp.header.bpp = 24; bmp.header.compression = 0; bmp.header.bitmap_size = 256*256*3; bmp.header.hres = 0; bmp.header.vres = 0; bmp.header.used = 0; bmp.header.important = 0; bmp.pixels = (RGB*)malloc(bmp.header.bitmap_size); for(int i = 0; i<(int)(bmp.header.bitmap_size)/3; i++) { bmp.pixels[i].b = r; bmp.pixels[i].g = g; bmp.pixels[i].r = b; } route(&bmp,commands,0,0); FILE *file = fopen(filename,"wb"); fwrite(&bmp.header,sizeof(BMPHeader),1,file); fwrite(bmp.pixels,sizeof(RGB),bmp.header.bitmap_size/3,file); fclose(file); return 0; } ``` :::