Formatter.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include <errno.h>
  2. #include <stdbool.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. static int lineWidth = 0;
  7. static FILE* file = NULL;
  8. typedef struct {
  9. char* data;
  10. int length;
  11. } Word;
  12. static Word* words = NULL;
  13. static int wordAmount = 0;
  14. static int wordCapacity = 0;
  15. static int randA = 0;
  16. static int randB = 0;
  17. static const char* beforeWord = "";
  18. static int beforeWordLength = 0;
  19. static const char* afterWord = "";
  20. static int afterWordLength = 0;
  21. static const char* afterLine = "";
  22. static int afterLineLength = 0;
  23. typedef struct {
  24. int a;
  25. int b;
  26. } Swap;
  27. static Swap swaps[50];
  28. static int swapIndex = 0;
  29. static void addSwap(int a, int b) {
  30. if(swapIndex >= (int)(sizeof(swaps) / sizeof(swaps[0]))) {
  31. return;
  32. }
  33. swaps[swapIndex].a = a;
  34. swaps[swapIndex++].b = b;
  35. }
  36. static void addWord(char* word) {
  37. if(wordAmount >= wordCapacity) {
  38. wordCapacity = wordCapacity * 2 + 1;
  39. words = (Word*)realloc(words, (size_t)wordCapacity * sizeof(Word));
  40. }
  41. int index = wordAmount++;
  42. words[index].data = word;
  43. words[index].length =
  44. beforeWordLength + (int)strlen(word) + afterWordLength;
  45. }
  46. static int compareWords(const void* a, const void* b) {
  47. const Word* ra = (const Word*)a;
  48. const Word* rb = (const Word*)b;
  49. return ra->length == rb->length ? 0 : ra->length < rb->length ? 1 : -1;
  50. }
  51. static void parseFile(void) {
  52. while(true) {
  53. int c = fgetc(file);
  54. while(c == ' ' || c == '\n') {
  55. c = fgetc(file);
  56. }
  57. if(c == EOF) {
  58. break;
  59. }
  60. int capacity = 8;
  61. int index = 0;
  62. char* word = (char*)malloc((size_t)capacity * sizeof(char));
  63. while(c != ' ' && c != EOF && c != '\n') {
  64. if(index >= capacity) {
  65. capacity *= 2;
  66. word = (char*)realloc(word, (size_t)capacity);
  67. }
  68. word[index++] = (char)c;
  69. c = fgetc(file);
  70. }
  71. if(index >= capacity) {
  72. capacity *= 2;
  73. word = (char*)realloc(word, (size_t)capacity);
  74. }
  75. word[index++] = '\0';
  76. addWord(word);
  77. }
  78. }
  79. static void clean(void) {
  80. if(words != NULL) {
  81. for(int i = 0; i < wordAmount; i++) {
  82. free(words[i].data);
  83. }
  84. free(words);
  85. }
  86. }
  87. static int getScore(void) {
  88. int score = 0;
  89. int length = 0;
  90. for(int i = 0; i < wordAmount; i++) {
  91. int l = words[i].length;
  92. if(length + l <= lineWidth - afterLineLength) {
  93. length += l;
  94. } else {
  95. score += lineWidth - length;
  96. length = l;
  97. }
  98. }
  99. return score;
  100. }
  101. static void print(void) {
  102. for(int i = 1; i <= lineWidth; i++) {
  103. putchar('0' + (i % 10));
  104. }
  105. putchar('\n');
  106. int length = 0;
  107. for(int i = 0; i < wordAmount; i++) {
  108. int l = (int)words[i].length;
  109. if(length + l <= lineWidth - afterLineLength) {
  110. printf("%s%s%s", beforeWord, words[i].data, afterWord);
  111. length += l;
  112. } else {
  113. length = l;
  114. printf("%s\n%s%s%s", afterLine, beforeWord, words[i].data,
  115. afterWord);
  116. }
  117. }
  118. putchar('\n');
  119. }
  120. static void generateRandom(void) {
  121. randA = rand() % wordAmount;
  122. randB = rand() % wordAmount;
  123. }
  124. static void swap(int indexA, int indexB) {
  125. Word tmp = words[indexA];
  126. words[indexA] = words[indexB];
  127. words[indexB] = tmp;
  128. }
  129. static void optimize(void) {
  130. int globalMin = getScore();
  131. for(int k = 0; k < 5000; k++) {
  132. int minScore = getScore();
  133. for(int i = 0; i < 100000; i++) {
  134. generateRandom();
  135. swap(randA, randB);
  136. int score = getScore();
  137. if(score < minScore) {
  138. minScore = score;
  139. } else {
  140. swap(randA, randB);
  141. }
  142. }
  143. if(minScore < globalMin) {
  144. globalMin = minScore;
  145. print();
  146. printf("\nscore: %d\n", minScore);
  147. }
  148. for(int i = 0; i < 50; i++) {
  149. generateRandom();
  150. swap(randA, randB);
  151. }
  152. }
  153. }
  154. static int findIndexOfLargestMatch(int sum, int start, int end) {
  155. for(int i = start; i < end; i++) {
  156. if(sum + words[i].length <= lineWidth - afterLineLength) {
  157. return i;
  158. }
  159. }
  160. return -1;
  161. }
  162. static void sort(int start, int end) {
  163. if(start >= end) {
  164. return;
  165. }
  166. qsort(words + start, (size_t)(end - start), sizeof(words[0]), compareWords);
  167. }
  168. static int analyseRecursion(int sum, int start, int globalIndex, int end) {
  169. if(start >= end) {
  170. return -1;
  171. } else if(sum == lineWidth - afterLineLength) {
  172. return 0;
  173. }
  174. int index = findIndexOfLargestMatch(sum, start, end);
  175. if(index < 0) {
  176. return -1;
  177. }
  178. int r = analyseRecursion(sum + words[index].length, index + 1,
  179. globalIndex + 1, end);
  180. if(r < 0) {
  181. // no match with this index, try starting from next
  182. return analyseRecursion(sum, start + 1, globalIndex, end);
  183. }
  184. addSwap(index, globalIndex);
  185. return r + 1;
  186. }
  187. static void analyse(void) {
  188. int i = 0;
  189. int end = wordAmount;
  190. while(i < end) {
  191. sort(i, end);
  192. int r = analyseRecursion(0, i, i, end);
  193. if(r > 0) {
  194. i += r;
  195. while(--swapIndex >= 0) {
  196. swap(swaps[swapIndex].a, swaps[swapIndex].b);
  197. }
  198. swapIndex = 0;
  199. } else {
  200. end--;
  201. swap(i, end);
  202. }
  203. }
  204. print();
  205. }
  206. int main(int argAmount, const char* const* args) {
  207. if(argAmount <= 0) {
  208. puts("... <mode> <width> <file> <before> <after> <line>");
  209. return 0;
  210. } else if(argAmount < 7) {
  211. printf("%s <mode> <width> <file> <before> <after> <line>\n", args[0]);
  212. return 0;
  213. }
  214. lineWidth = atoi(args[2]);
  215. if(lineWidth <= 0) {
  216. printf("%s is an invalid line width\n", args[2]);
  217. return 0;
  218. }
  219. file = fopen(args[3], "rb");
  220. if(file == NULL) {
  221. printf("%s is an invalid file: %s\n", args[3], strerror(errno));
  222. return 0;
  223. }
  224. beforeWord = args[4];
  225. beforeWordLength = (int)strlen(args[4]);
  226. afterWord = args[5];
  227. afterWordLength = (int)strlen(args[5]);
  228. afterLine = args[6];
  229. afterLineLength = (int)strlen(args[6]);
  230. parseFile();
  231. if(strcmp(args[1], "random") == 0) {
  232. optimize();
  233. } else if(strcmp(args[1], "think") == 0) {
  234. analyse();
  235. }
  236. clean();
  237. if(fclose(file)) {
  238. printf("close error: %s\n", strerror(errno));
  239. }
  240. return 0;
  241. }