Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
5.4 KiB

  1. #include "pch.c"
  2. #pragma hdrstop
  3. static int left_turn[SOL_DIRS] =
  4. {
  5. SOL_DIR_DOWN, SOL_DIR_LEFT, SOL_DIR_UP, SOL_DIR_RIGHT
  6. };
  7. static int right_turn[SOL_DIRS] =
  8. {
  9. SOL_DIR_UP, SOL_DIR_RIGHT, SOL_DIR_DOWN, SOL_DIR_LEFT
  10. };
  11. static BYTE dir_wall[SOL_DIRS] =
  12. {
  13. MAZE_WALL_LEFT, MAZE_WALL_UP, MAZE_WALL_RIGHT, MAZE_WALL_DOWN
  14. };
  15. static int dir_cloff[SOL_DIRS][2] =
  16. {
  17. -1,0, 0,-1, 1,0, 0,1
  18. };
  19. static FaAngle dir_ang[SOL_DIRS];
  20. static FxPt2 dir_off[SOL_DIRS];
  21. /* We want to traverse one quarter of a circle in the given number of
  22. steps. The distance is the arc length which is r*pi/2. Divide that
  23. by the number of steps to get the distance each step should travel */
  24. #define ARC_STEP 5
  25. #define ARC_STEPS (90/ARC_STEP)
  26. #define REVERSE_STEP (2*ARC_STEP)
  27. #define REVERSE_STEPS (180/REVERSE_STEP)
  28. static void SetView(MazeSolution *sol, MazeView *vw)
  29. {
  30. vw->ang = dir_ang[sol->dir];
  31. vw->pos.x = CellToMfx(sol->clx)+dir_off[sol->dir].x;
  32. vw->pos.y = CellToMfx(sol->cly)+dir_off[sol->dir].y;
  33. }
  34. void SolveMazeSetGoals(MazeSolution *sol, MazeGoal *goals, int ngoals)
  35. {
  36. sol->goals = goals;
  37. sol->ngoals = ngoals;
  38. }
  39. void SolveMazeStart(MazeView *vw,
  40. Cell *maze, int w, int h,
  41. IntPt2 *start, int start_dir,
  42. MazeGoal *goals, int ngoals,
  43. int turn_to,
  44. MazeSolution *sol)
  45. {
  46. dir_ang[SOL_DIR_LEFT] = FaDeg(180);
  47. dir_ang[SOL_DIR_UP] = FaDeg(90);
  48. dir_ang[SOL_DIR_RIGHT] = FaDeg(0);
  49. dir_ang[SOL_DIR_DOWN] = FaDeg(270);
  50. dir_off[SOL_DIR_LEFT].x = CellToMfx(1)-FX_MIN_VALUE;
  51. dir_off[SOL_DIR_LEFT].y = CellToMfx(1)/2;
  52. dir_off[SOL_DIR_UP].x = CellToMfx(1)/2;
  53. dir_off[SOL_DIR_UP].y = CellToMfx(1)-FX_MIN_VALUE;
  54. dir_off[SOL_DIR_RIGHT].x = FxVal(0);
  55. dir_off[SOL_DIR_RIGHT].y = CellToMfx(1)/2;
  56. dir_off[SOL_DIR_DOWN].x = CellToMfx(1)/2;
  57. dir_off[SOL_DIR_DOWN].y = FxVal(0);
  58. sol->clx = start->x;
  59. sol->cly = start->y;
  60. sol->dir = start_dir;
  61. sol->maze = maze;
  62. sol->w = w;
  63. sol->h = h;
  64. sol->ani_state = ANI_STATE_NONE;
  65. switch(turn_to)
  66. {
  67. case SOL_TURN_RIGHT:
  68. sol->turn_to = left_turn;
  69. sol->turn_away = right_turn;
  70. sol->dir_sign = 1;
  71. break;
  72. case SOL_TURN_LEFT:
  73. sol->turn_to = right_turn;
  74. sol->turn_away = left_turn;
  75. sol->dir_sign = -1;
  76. break;
  77. }
  78. SolveMazeSetGoals(sol, goals, ngoals);
  79. SetView(sol, vw);
  80. }
  81. #define MazeAt(x, y) (sol->maze+(x)+(y)*(sol->w))
  82. MazeGoal *SolveMazeStep(MazeView *vw, MazeSolution *sol)
  83. {
  84. Cell *cell;
  85. int i, dir, turn_to;
  86. if (sol->ani_state != ANI_STATE_NONE)
  87. {
  88. if (--sol->ani_count == 0)
  89. {
  90. sol->ani_state = ANI_STATE_NONE;
  91. SetView(sol, vw);
  92. }
  93. }
  94. switch(sol->ani_state)
  95. {
  96. case ANI_STATE_TURN_TO:
  97. vw->pos.x += FxMulDiv(FaCos(vw->ang),
  98. FxFltVal(PI*MAZE_CELL_SIZE/2),
  99. FxVal(ARC_STEPS*2));
  100. vw->pos.y += FxMulDiv(FaSin(vw->ang),
  101. FxFltVal(PI*MAZE_CELL_SIZE/2),
  102. FxVal(ARC_STEPS*2));
  103. vw->ang = FaAdd(vw->ang, sol->dir_sign*FaDeg(ARC_STEP));
  104. return NULL;
  105. case ANI_STATE_TURN_AWAY:
  106. vw->pos.x += FxMulDiv(FaCos(vw->ang),
  107. FxFltVal(PI*MAZE_CELL_SIZE/2),
  108. FxVal(ARC_STEPS*2));
  109. vw->pos.y += FxMulDiv(FaSin(vw->ang),
  110. FxFltVal(PI*MAZE_CELL_SIZE/2),
  111. FxVal(ARC_STEPS*2));
  112. vw->ang = FaAdd(vw->ang, sol->dir_sign * -FaDeg(ARC_STEP));
  113. return NULL;
  114. case ANI_STATE_FORWARD:
  115. vw->pos.x += FxMulDiv(FaCos(vw->ang), MAZE_CELL_SIZE, ARC_STEPS);
  116. vw->pos.y += FxMulDiv(FaSin(vw->ang), MAZE_CELL_SIZE, ARC_STEPS);
  117. return NULL;
  118. case ANI_STATE_REVERSE:
  119. vw->ang = FaAdd(vw->ang, sol->dir_sign*FaDeg(REVERSE_STEP));
  120. return NULL;
  121. }
  122. for (i = 0; i < sol->ngoals; i++)
  123. {
  124. if (sol->clx == sol->goals[i].clx &&
  125. sol->cly == sol->goals[i].cly)
  126. {
  127. return &sol->goals[i];
  128. }
  129. }
  130. cell = MazeAt(sol->clx, sol->cly);
  131. dir = sol->dir;
  132. for (i = 0; i < SOL_DIRS-1; i++)
  133. {
  134. turn_to = sol->turn_to[dir];
  135. if ((dir_wall[turn_to] & cell->can_see) == 0)
  136. {
  137. /* No wall present when turned, so turn that way */
  138. sol->clx += dir_cloff[turn_to][0];
  139. sol->cly += dir_cloff[turn_to][1];
  140. sol->dir = turn_to;
  141. sol->ani_count = ARC_STEPS;
  142. switch(i)
  143. {
  144. case 0:
  145. sol->ani_state = ANI_STATE_TURN_TO;
  146. break;
  147. case 1:
  148. sol->ani_state = ANI_STATE_FORWARD;
  149. break;
  150. case 2:
  151. sol->ani_state = ANI_STATE_TURN_AWAY;
  152. break;
  153. }
  154. break;
  155. }
  156. else
  157. {
  158. /* Wall present, turn away and check again */
  159. dir = sol->turn_away[dir];
  160. }
  161. }
  162. if (i == SOL_DIRS-1)
  163. {
  164. /* Dead end. Turn around */
  165. dir = sol->turn_to[sol->turn_to[sol->dir]];
  166. sol->clx += dir_cloff[dir][0];
  167. sol->cly += dir_cloff[dir][1];
  168. sol->dir = dir;
  169. sol->ani_state = ANI_STATE_REVERSE;
  170. sol->ani_count = REVERSE_STEPS;
  171. }
  172. return NULL;
  173. }