OSDN Git Service

Revert "Revert "Merge branch 'master' of git.osdn.net:/gitroot/hengband/hengband""
[hengband/hengband.git] / src / util / sort.c
1 #include "util/sort.h"
2 #include "dungeon/quest.h"
3 #include "grid/feature.h"
4 #include "grid/grid.h"
5 #include "monster-race/monster-race.h"
6 #include "monster-race/race-flags1.h"
7 #include "monster/monster-flag-types.h"
8 #include "system/artifact-type-definition.h"
9 #include "system/floor-type-definition.h"
10
11 /*
12  * @brief クイックソートの実行 / Quick sort in place
13  * @param u アイテムやモンスター等への配列
14  * @param v 条件基準IDへの参照ポインタ
15  * @param a 比較対象のID1
16  * @param b 比較対象のID2
17  * @param ang_sort_comp 比較用の関数ポインタ
18  * @param ang_sort_swap スワップ用の関数ポインタ
19  * @return なし
20  */
21 static void exe_ang_sort(player_type *player_ptr, vptr u, vptr v, int p, int q, bool (*ang_sort_comp)(player_type *, vptr, vptr, int, int),
22     void (*ang_sort_swap)(player_type *, vptr, vptr, int, int))
23 {
24     if (p >= q)
25         return;
26
27     int z = p;
28     int a = p;
29     int b = q;
30     while (TRUE) {
31         /* Slide i2 */
32         while (!(*ang_sort_comp)(player_ptr, u, v, b, z))
33             b--;
34
35         /* Slide i1 */
36         while (!(*ang_sort_comp)(player_ptr, u, v, z, a))
37             a++;
38
39         if (a >= b)
40             break;
41
42         (*ang_sort_swap)(player_ptr, u, v, a, b);
43
44         a++, b--;
45     }
46
47     /* Recurse left side */
48     exe_ang_sort(player_ptr, u, v, p, b, ang_sort_comp, ang_sort_swap);
49
50     /* Recurse right side */
51     exe_ang_sort(player_ptr, u, v, b + 1, q, ang_sort_comp, ang_sort_swap);
52 }
53
54 /*
55  * @brief クイックソートの受け付け / Accepting auick sort in place
56  * @param u アイテムやモンスター等への配列
57  * @param v 条件基準IDへの参照ポインタ
58  * @param a 比較対象のID1
59  * @param b 比較対象のID2
60  * @param ang_sort_comp 比較用の関数ポインタ
61  * @param ang_sort_swap スワップ用の関数ポインタ
62  * @return なし
63  */
64 void ang_sort(player_type *player_ptr, vptr u, vptr v, int n, bool (*ang_sort_comp)(player_type *, vptr, vptr, int, int),
65     void (*ang_sort_swap)(player_type *, vptr, vptr, int, int))
66 {
67     exe_ang_sort(player_ptr, u, v, 0, n - 1, ang_sort_comp, ang_sort_swap);
68 }
69
70 /*
71  * Sorting hook -- comp function -- by "distance to player"
72  *
73  * We use "u" and "v" to point to arrays of "x" and "y" positions,
74  * and sort the arrays by double-distance to the player.
75  */
76 bool ang_sort_comp_distance(player_type *player_ptr, vptr u, vptr v, int a, int b)
77 {
78     POSITION *x = (POSITION *)(u);
79     POSITION *y = (POSITION *)(v);
80
81     /* Absolute distance components */
82     POSITION kx = x[a];
83     kx -= player_ptr->x;
84     kx = ABS(kx);
85     POSITION ky = y[a];
86     ky -= player_ptr->y;
87     ky = ABS(ky);
88
89     /* Approximate Double Distance to the first point */
90     POSITION da = ((kx > ky) ? (kx + kx + ky) : (ky + ky + kx));
91
92     /* Absolute distance components */
93     kx = x[b];
94     kx -= player_ptr->x;
95     kx = ABS(kx);
96     ky = y[b];
97     ky -= player_ptr->y;
98     ky = ABS(ky);
99
100     /* Approximate Double Distance to the first point */
101     POSITION db = ((kx > ky) ? (kx + kx + ky) : (ky + ky + kx));
102
103     /* Compare the distances */
104     return (da <= db);
105 }
106
107 /*
108  * Sorting hook -- comp function -- by importance level of grids
109  *
110  * We use "u" and "v" to point to arrays of "x" and "y" positions,
111  * and sort the arrays by level of monster
112  */
113 bool ang_sort_comp_importance(player_type *player_ptr, vptr u, vptr v, int a, int b)
114 {
115     POSITION *x = (POSITION *)(u);
116     POSITION *y = (POSITION *)(v);
117     grid_type *ca_ptr = &player_ptr->current_floor_ptr->grid_array[y[a]][x[a]];
118     grid_type *cb_ptr = &player_ptr->current_floor_ptr->grid_array[y[b]][x[b]];
119     monster_type *ma_ptr = &player_ptr->current_floor_ptr->m_list[ca_ptr->m_idx];
120     monster_type *mb_ptr = &player_ptr->current_floor_ptr->m_list[cb_ptr->m_idx];
121     monster_race *ap_ra_ptr, *ap_rb_ptr;
122
123     /* The player grid */
124     if (y[a] == player_ptr->y && x[a] == player_ptr->x)
125         return TRUE;
126
127     if (y[b] == player_ptr->y && x[b] == player_ptr->x)
128         return FALSE;
129
130     /* Extract monster race */
131     if (ca_ptr->m_idx && ma_ptr->ml)
132         ap_ra_ptr = &r_info[ma_ptr->ap_r_idx];
133     else
134         ap_ra_ptr = NULL;
135
136     if (cb_ptr->m_idx && mb_ptr->ml)
137         ap_rb_ptr = &r_info[mb_ptr->ap_r_idx];
138     else
139         ap_rb_ptr = NULL;
140
141     if (ap_ra_ptr && !ap_rb_ptr)
142         return TRUE;
143
144     if (!ap_ra_ptr && ap_rb_ptr)
145         return FALSE;
146
147     /* Compare two monsters */
148     if (ap_ra_ptr && ap_rb_ptr) {
149         /* Unique monsters first */
150         if ((ap_ra_ptr->flags1 & RF1_UNIQUE) && !(ap_rb_ptr->flags1 & RF1_UNIQUE))
151             return TRUE;
152         if (!(ap_ra_ptr->flags1 & RF1_UNIQUE) && (ap_rb_ptr->flags1 & RF1_UNIQUE))
153             return FALSE;
154
155         /* Shadowers first (あやしい影) */
156         if ((ma_ptr->mflag2 & MFLAG2_KAGE) && !(mb_ptr->mflag2 & MFLAG2_KAGE))
157             return TRUE;
158         if (!(ma_ptr->mflag2 & MFLAG2_KAGE) && (mb_ptr->mflag2 & MFLAG2_KAGE))
159             return FALSE;
160
161         /* Unknown monsters first */
162         if (!ap_ra_ptr->r_tkills && ap_rb_ptr->r_tkills)
163             return TRUE;
164         if (ap_ra_ptr->r_tkills && !ap_rb_ptr->r_tkills)
165             return FALSE;
166
167         /* Higher level monsters first (if known) */
168         if (ap_ra_ptr->r_tkills && ap_rb_ptr->r_tkills) {
169             if (ap_ra_ptr->level > ap_rb_ptr->level)
170                 return TRUE;
171             if (ap_ra_ptr->level < ap_rb_ptr->level)
172                 return FALSE;
173         }
174
175         /* Sort by index if all conditions are same */
176         if (ma_ptr->ap_r_idx > mb_ptr->ap_r_idx)
177             return TRUE;
178         if (ma_ptr->ap_r_idx < mb_ptr->ap_r_idx)
179             return FALSE;
180     }
181
182     /* An object get higher priority */
183     if (player_ptr->current_floor_ptr->grid_array[y[a]][x[a]].o_idx && !player_ptr->current_floor_ptr->grid_array[y[b]][x[b]].o_idx)
184         return TRUE;
185
186     if (!player_ptr->current_floor_ptr->grid_array[y[a]][x[a]].o_idx && player_ptr->current_floor_ptr->grid_array[y[b]][x[b]].o_idx)
187         return FALSE;
188
189     /* Priority from the terrain */
190     if (f_info[ca_ptr->feat].priority > f_info[cb_ptr->feat].priority)
191         return TRUE;
192
193     if (f_info[ca_ptr->feat].priority < f_info[cb_ptr->feat].priority)
194         return FALSE;
195
196     /* If all conditions are same, compare distance */
197     return ang_sort_comp_distance(player_ptr, u, v, a, b);
198 }
199
200 /*
201  * Sorting hook -- swap function -- by "distance to player"
202  *
203  * We use "u" and "v" to point to arrays of "x" and "y" positions,
204  * and sort the arrays by distance to the player.
205  */
206 void ang_sort_swap_distance(player_type *player_ptr, vptr u, vptr v, int a, int b)
207 {
208     /* Unused */
209     (void)player_ptr;
210
211     POSITION *x = (POSITION *)(u);
212     POSITION *y = (POSITION *)(v);
213
214     POSITION temp = x[a];
215     x[a] = x[b];
216     x[b] = temp;
217
218     temp = y[a];
219     y[a] = y[b];
220     y[b] = temp;
221 }
222
223 /*
224  * Sorting hook -- Comp function -- see below
225  *
226  * We use "u" to point to array of monster indexes,
227  * and "v" to select the type of sorting to perform on "u".
228  */
229 bool ang_sort_art_comp(player_type *player_ptr, vptr u, vptr v, int a, int b)
230 {
231     /* Unused */
232     (void)player_ptr;
233
234     u16b *who = (u16b *)(u);
235     u16b *why = (u16b *)(v);
236
237     int w1 = who[a];
238     int w2 = who[b];
239
240     int z1, z2;
241
242     /* Sort by total kills */
243     if (*why >= 3) {
244         /* Extract total kills */
245         z1 = a_info[w1].tval;
246         z2 = a_info[w2].tval;
247
248         /* Compare total kills */
249         if (z1 < z2)
250             return TRUE;
251
252         if (z1 > z2)
253             return FALSE;
254     }
255
256     /* Sort by monster level */
257     if (*why >= 2) {
258         /* Extract levels */
259         z1 = a_info[w1].sval;
260         z2 = a_info[w2].sval;
261
262         /* Compare levels */
263         if (z1 < z2)
264             return TRUE;
265
266         if (z1 > z2)
267             return FALSE;
268     }
269
270     /* Sort by monster experience */
271     if (*why >= 1) {
272         /* Extract experience */
273         z1 = a_info[w1].level;
274         z2 = a_info[w2].level;
275
276         /* Compare experience */
277         if (z1 < z2)
278             return TRUE;
279
280         if (z1 > z2)
281             return FALSE;
282     }
283
284     /* Compare indexes */
285     return (w1 <= w2);
286 }
287
288 /*
289  * Sorting hook -- Swap function -- see below
290  *
291  * We use "u" to point to array of monster indexes,
292  * and "v" to select the type of sorting to perform.
293  */
294 void ang_sort_art_swap(player_type *player_ptr, vptr u, vptr v, int a, int b)
295 {
296     /* Unused */
297     (void)player_ptr;
298     (void)v;
299
300     u16b *who = (u16b *)(u);
301     u16b holder = who[a];
302     who[a] = who[b];
303     who[b] = holder;
304 }
305
306 bool ang_sort_comp_quest_num(player_type *player_ptr, vptr u, vptr v, int a, int b)
307 {
308     /* Unused */
309     (void)player_ptr;
310     (void)v;
311
312     QUEST_IDX *q_num = (QUEST_IDX *)u;
313     quest_type *qa = &quest[q_num[a]];
314     quest_type *qb = &quest[q_num[b]];
315     return (qa->comptime != qb->comptime) ? (qa->comptime < qb->comptime) : (qa->level <= qb->level);
316 }
317
318 void ang_sort_swap_quest_num(player_type *player_ptr, vptr u, vptr v, int a, int b)
319 {
320     /* Unused */
321     (void)player_ptr;
322     (void)v;
323
324     QUEST_IDX *q_num = (QUEST_IDX *)u;
325     QUEST_IDX tmp = q_num[a];
326     q_num[a] = q_num[b];
327     q_num[b] = tmp;
328 }
329
330 /*!
331  * @brief ペット入りモンスターボールをソートするための比較関数
332  * @param u 所持品配列の参照ポインタ
333  * @param v 未使用
334  * @param a 所持品ID1
335  * @param b 所持品ID2
336  * @return 1の方が大であればTRUE
337  */
338 bool ang_sort_comp_pet(player_type *player_ptr, vptr u, vptr v, int a, int b)
339 {
340     /* Unused */
341     (void)v;
342
343     u16b *who = (u16b *)(u);
344
345     int w1 = who[a];
346     int w2 = who[b];
347
348     monster_type *m_ptr1 = &player_ptr->current_floor_ptr->m_list[w1];
349     monster_type *m_ptr2 = &player_ptr->current_floor_ptr->m_list[w2];
350     monster_race *r_ptr1 = &r_info[m_ptr1->r_idx];
351     monster_race *r_ptr2 = &r_info[m_ptr2->r_idx];
352
353     if (m_ptr1->nickname && !m_ptr2->nickname)
354         return TRUE;
355
356     if (m_ptr2->nickname && !m_ptr1->nickname)
357         return FALSE;
358
359     if ((r_ptr1->flags1 & RF1_UNIQUE) && !(r_ptr2->flags1 & RF1_UNIQUE))
360         return TRUE;
361
362     if ((r_ptr2->flags1 & RF1_UNIQUE) && !(r_ptr1->flags1 & RF1_UNIQUE))
363         return FALSE;
364
365     if (r_ptr1->level > r_ptr2->level)
366         return TRUE;
367
368     if (r_ptr2->level > r_ptr1->level)
369         return FALSE;
370
371     if (m_ptr1->hp > m_ptr2->hp)
372         return TRUE;
373
374     if (m_ptr2->hp > m_ptr1->hp)
375         return FALSE;
376
377     return w1 <= w2;
378 }
379
380 /*!
381  * @brief モンスター種族情報を特定の基準によりソートするための比較処理
382  * Sorting hook -- Comp function -- see below
383  * @param u モンスター種族情報の入れるポインタ
384  * @param v 条件基準ID
385  * @param a 比較するモンスター種族のID1
386  * @param b 比較するモンスター種族のID2
387  * @return 2の方が大きければTRUEを返す
388  * We use "u" to point to array of monster indexes,
389  * and "v" to select the type of sorting to perform on "u".
390  */
391 bool ang_sort_comp_hook(player_type *player_ptr, vptr u, vptr v, int a, int b)
392 {
393     /* Unused */
394     (void)player_ptr;
395
396     u16b *who = (u16b *)(u);
397     u16b *why = (u16b *)(v);
398
399     int w1 = who[a];
400     int w2 = who[b];
401
402     int z1, z2;
403
404     /* Sort by player kills */
405     if (*why >= 4) {
406         /* Extract player kills */
407         z1 = r_info[w1].r_pkills;
408         z2 = r_info[w2].r_pkills;
409
410         /* Compare player kills */
411         if (z1 < z2)
412             return TRUE;
413         if (z1 > z2)
414             return FALSE;
415     }
416
417     /* Sort by total kills */
418     if (*why >= 3) {
419         /* Extract total kills */
420         z1 = r_info[w1].r_tkills;
421         z2 = r_info[w2].r_tkills;
422
423         /* Compare total kills */
424         if (z1 < z2)
425             return TRUE;
426         if (z1 > z2)
427             return FALSE;
428     }
429
430     /* Sort by monster level */
431     if (*why >= 2) {
432         /* Extract levels */
433         z1 = r_info[w1].level;
434         z2 = r_info[w2].level;
435
436         /* Compare levels */
437         if (z1 < z2)
438             return TRUE;
439         if (z1 > z2)
440             return FALSE;
441     }
442
443     /* Sort by monster experience */
444     if (*why >= 1) {
445         /* Extract experience */
446         z1 = r_info[w1].mexp;
447         z2 = r_info[w2].mexp;
448
449         /* Compare experience */
450         if (z1 < z2)
451             return TRUE;
452         if (z1 > z2)
453             return FALSE;
454     }
455
456     /* Compare indexes */
457     return (w1 <= w2);
458 }
459
460 /*!
461  * @brief モンスター種族情報を特定の基準によりソートするためのスワップ処理
462  * Sorting hook -- Swap function -- see below
463  * @param u モンスター種族情報の入れるポインタ
464  * @param v 未使用
465  * @param a スワップするモンスター種族のID1
466  * @param b スワップするモンスター種族のID2
467  * @return なし
468  * @details
469  * We use "u" to point to array of monster indexes,
470  * and "v" to select the type of sorting to perform.
471  */
472 void ang_sort_swap_hook(player_type *player_ptr, vptr u, vptr v, int a, int b)
473 {
474     /* Unused */
475     (void)player_ptr;
476     (void)v;
477
478     u16b *who = (u16b *)(u);
479     u16b holder;
480
481     holder = who[a];
482     who[a] = who[b];
483     who[b] = holder;
484 }
485
486 /*
487  * hook function to sort monsters by level
488  */
489 bool ang_sort_comp_monster_level(player_type *player_ptr, vptr u, vptr v, int a, int b)
490 {
491     /* Unused */
492     (void)player_ptr;
493     (void)v;
494
495     u16b *who = (u16b *)(u);
496
497     int w1 = who[a];
498     int w2 = who[b];
499
500     monster_race *r_ptr1 = &r_info[w1];
501     monster_race *r_ptr2 = &r_info[w2];
502
503     if (r_ptr2->level > r_ptr1->level)
504         return TRUE;
505
506     if (r_ptr1->level > r_ptr2->level)
507         return FALSE;
508
509     if ((r_ptr2->flags1 & RF1_UNIQUE) && !(r_ptr1->flags1 & RF1_UNIQUE))
510         return TRUE;
511
512     if ((r_ptr1->flags1 & RF1_UNIQUE) && !(r_ptr2->flags1 & RF1_UNIQUE))
513         return FALSE;
514
515     return w1 <= w2;
516 }
517
518 /*!
519  * @brief ペットになっているモンスターをソートするための比較処理
520  * @param u モンスターの構造体配列
521  * @param v 未使用
522  * @param a 比較対象のモンスターID1
523  * @param b 比較対象のモンスターID2
524  * @return 2番目が大ならばTRUEを返す
525  */
526 bool ang_sort_comp_pet_dismiss(player_type *player_ptr, vptr u, vptr v, int a, int b)
527 {
528     /* Unused */
529     (void)v;
530
531     u16b *who = (u16b *)(u);
532
533     int w1 = who[a];
534     int w2 = who[b];
535
536     monster_type *m_ptr1 = &player_ptr->current_floor_ptr->m_list[w1];
537     monster_type *m_ptr2 = &player_ptr->current_floor_ptr->m_list[w2];
538     monster_race *r_ptr1 = &r_info[m_ptr1->r_idx];
539     monster_race *r_ptr2 = &r_info[m_ptr2->r_idx];
540
541     if (w1 == player_ptr->riding)
542         return TRUE;
543
544     if (w2 == player_ptr->riding)
545         return FALSE;
546
547     if (m_ptr1->nickname && !m_ptr2->nickname)
548         return TRUE;
549
550     if (m_ptr2->nickname && !m_ptr1->nickname)
551         return FALSE;
552
553     if (!m_ptr1->parent_m_idx && m_ptr2->parent_m_idx)
554         return TRUE;
555
556     if (!m_ptr2->parent_m_idx && m_ptr1->parent_m_idx)
557         return FALSE;
558
559     if ((r_ptr1->flags1 & RF1_UNIQUE) && !(r_ptr2->flags1 & RF1_UNIQUE))
560         return TRUE;
561
562     if ((r_ptr2->flags1 & RF1_UNIQUE) && !(r_ptr1->flags1 & RF1_UNIQUE))
563         return FALSE;
564
565     if (r_ptr1->level > r_ptr2->level)
566         return TRUE;
567
568     if (r_ptr2->level > r_ptr1->level)
569         return FALSE;
570
571     if (m_ptr1->hp > m_ptr2->hp)
572         return TRUE;
573
574     if (m_ptr2->hp > m_ptr1->hp)
575         return FALSE;
576
577     return w1 <= w2;
578 }
579
580 /*!
581  * @brief フロア保存時のgrid情報テンプレートをソートするための比較処理
582  * @param u gridテンプレートの参照ポインタ
583  * @param v 未使用
584  * @param a スワップするモンスター種族のID1
585  * @param b スワップするモンスター種族のID2
586  * @return aの方が大きければtrue
587  */
588 bool ang_sort_comp_cave_temp(player_type *player_ptr, vptr u, vptr v, int a, int b)
589 {
590     /* Unused */
591     (void)player_ptr;
592     (void)v;
593
594     grid_template_type *who = (grid_template_type *)(u);
595
596     u16b o1 = who[a].occurrence;
597     u16b o2 = who[b].occurrence;
598
599     return o2 <= o1;
600 }
601
602 /*!
603  * @brief フロア保存時のgrid情報テンプレートをソートするためのスワップ処理 / Sorting hook -- Swap function
604  * @param u gridテンプレートの参照ポインタ
605  * @param v 未使用
606  * @param a スワップするモンスター種族のID1
607  * @param b スワップするモンスター種族のID2
608  * @return なし
609  */
610 void ang_sort_swap_cave_temp(player_type *player_ptr, vptr u, vptr v, int a, int b)
611 {
612     /* Unused */
613     (void)player_ptr;
614     (void)v;
615
616     grid_template_type *who = (grid_template_type *)(u);
617     grid_template_type holder;
618
619     holder = who[a];
620     who[a] = who[b];
621     who[b] = holder;
622 }
623
624 /*!
625  * @brief 進化ツリーをソートするためモンスター種族の判定関数 /
626  * Sorting hook -- Comp function
627  * @param u 進化木構造データ
628  * @param v 未使用
629  * @param a 比較したいモンスター種族ID1
630  * @param b 比較したいモンスター種族ID2
631  * @return 2が大きければTRUEを返す
632  */
633 bool ang_sort_comp_evol_tree(player_type *player_ptr, vptr u, vptr v, int a, int b)
634 {
635     /* Unused */
636     (void)player_ptr;
637     (void)v;
638
639     int **evol_tree = (int **)u;
640
641     int w1 = evol_tree[a][0];
642     int w2 = evol_tree[b][0];
643     monster_race *r1_ptr = &r_info[w1];
644     monster_race *r2_ptr = &r_info[w2];
645
646     /* Used tree first */
647     if (w1 && !w2)
648         return TRUE;
649
650     if (!w1 && w2)
651         return FALSE;
652
653     /* Sort by monster level */
654     if (r1_ptr->level < r2_ptr->level)
655         return TRUE;
656
657     if (r1_ptr->level > r2_ptr->level)
658         return FALSE;
659
660     /* Sort by monster experience */
661     if (r1_ptr->mexp < r2_ptr->mexp)
662         return TRUE;
663
664     if (r1_ptr->mexp > r2_ptr->mexp)
665         return FALSE;
666
667     /* Compare indexes */
668     return w1 <= w2;
669 }
670
671 /*!
672  * @brief 進化ツリーをソートするため木構造のスワップ関数 /
673  * Sorting hook -- Swap function
674  * @param u 進化木構造データ
675  * @param v 未使用
676  * @param a スワップしたい木構造1
677  * @param b スワップしたい木構造2
678  * @return 2が大きければTRUEを返す
679  */
680 void ang_sort_swap_evol_tree(player_type *player_ptr, vptr u, vptr v, int a, int b)
681 {
682     /* Unused */
683     (void)player_ptr;
684     (void)v;
685
686     int **evol_tree = (int **)u;
687     int *holder;
688
689     holder = evol_tree[a];
690     evol_tree[a] = evol_tree[b];
691     evol_tree[b] = holder;
692 }