combi.c 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. #include <assert.h>
  2. #include <string.h>
  3. #include "puzzles.h"
  4. /* horrific and doesn't check overflow. */
  5. static long factx(long x, long y)
  6. {
  7. long acc = 1, i;
  8. for (i = y; i <= x; i++)
  9. acc *= i;
  10. return acc;
  11. }
  12. void reset_combi(combi_ctx *combi)
  13. {
  14. int i;
  15. combi->nleft = combi->total;
  16. for (i = 0; i < combi->r; i++)
  17. combi->a[i] = i;
  18. }
  19. combi_ctx *new_combi(int r, int n)
  20. {
  21. long nfr, nrf;
  22. combi_ctx *combi;
  23. assert(r <= n);
  24. assert(n >= 1);
  25. combi = snew(combi_ctx);
  26. memset(combi, 0, sizeof(combi_ctx));
  27. combi->r = r;
  28. combi->n = n;
  29. combi->a = snewn(r, int);
  30. memset(combi->a, 0, r * sizeof(int));
  31. nfr = factx(n, r+1);
  32. nrf = factx(n-r, 1);
  33. combi->total = (int)(nfr / nrf);
  34. reset_combi(combi);
  35. return combi;
  36. }
  37. /* returns NULL when we're done otherwise returns input. */
  38. combi_ctx *next_combi(combi_ctx *combi)
  39. {
  40. int i = combi->r - 1, j;
  41. if (combi->nleft == combi->total)
  42. goto done;
  43. else if (combi->nleft <= 0)
  44. return NULL;
  45. while (combi->a[i] == combi->n - combi->r + i)
  46. i--;
  47. combi->a[i] += 1;
  48. for (j = i+1; j < combi->r; j++)
  49. combi->a[j] = combi->a[i] + j - i;
  50. done:
  51. combi->nleft--;
  52. return combi;
  53. }
  54. void free_combi(combi_ctx *combi)
  55. {
  56. sfree(combi->a);
  57. sfree(combi);
  58. }