10 #include "playout/moggy.h"
13 #define PLDEBUGL(n) DEBUGL_(p->debug_level, n)
17 bool ladders
, localassess
, ladderassess
, borderladders
;
18 int lcapturerate
, capturerate
, patternrate
;
19 /* These are relative to patternrate. */
20 int hanerate
, cut1rate
, cut2rate
;
31 * X: black; O: white; .: empty; #: edge
32 * x: !black; o: !white; ?: any
34 * X in the middle: pattern valid only for one side;
35 * otherwise, middle ignored. */
37 static char mogo_patterns_src
[][10] = {
38 /* hane pattern - enclosing hane */
42 /* hane pattern - non-cutting hane */
46 /* hane pattern - magari */
50 /* hane pattern - thin hane (SUSPICIOUS) */
54 /* cut1 pattern (kiri) - unprotected cut */
58 /* cut1 pattern (kiri) - peeped cut */
62 /* cut2 pattern (de) */
66 /* side pattern - chase */
70 /* side pattern - weirdness (SUSPICIOUS) */
74 /* side pattern - sagari (SUSPICIOUS) */
78 /* side pattern - weirdcut (SUSPICIOUS) */
82 /* side pattern - cut (SUSPICIOUS) */
87 #define mogo_patterns_src_n sizeof(mogo_patterns_src) / sizeof(mogo_patterns_src[0])
89 static char mogo_patterns
[mogo_patterns_src_n
* 8][10];
90 #define mogo_patterns_n sizeof(mogo_patterns) / sizeof(mogo_patterns[0])
92 static void __attribute__((constructor
))
95 for (int i
= 0; i
< mogo_patterns_src_n
; i
++)
98 strcpy(mogo_patterns
[i
], mogo_patterns_src
[i
]);
100 /* Transpositions: */
103 for (j
= 8; j
>= 0; j
--) {
104 mogo_patterns
[i
+ mogo_patterns_src_n
][8 - j
] = mogo_patterns
[i
][j
];
105 //printf("%s - %s\n", mogo_patterns[i], mogo_patterns[i + mogo_patterns_src_n]);
107 mogo_patterns
[i
+ mogo_patterns_src_n
][9] = 0;
109 /* reverse triplets */
110 for (j
= 2; j
>= 0; j
--)
111 memcpy(&mogo_patterns
[i
+ mogo_patterns_src_n
* 2][6 - j
* 3], &mogo_patterns
[i
][j
* 3], 3);
112 mogo_patterns
[i
+ mogo_patterns_src_n
* 2][9] = 0;
114 /* reverse reverse triplets */
115 for (j
= 2; j
>= 0; j
--)
116 memcpy(&mogo_patterns
[i
+ mogo_patterns_src_n
* 3][6 - j
* 3], &mogo_patterns
[i
+ mogo_patterns_src_n
][j
* 3], 3);
117 mogo_patterns
[i
+ mogo_patterns_src_n
* 3][9] = 0;
120 /* Now, swap colors: */
121 for (int i
= 0; i
< mogo_patterns_src_n
* 4; i
++)
123 for (int j
= 0; j
< 10; j
++) {
124 switch (mogo_patterns
[i
][j
]) {
125 case 'X': mogo_patterns
[mogo_patterns_src_n
* 4 + i
][j
] = 'O'; break;
126 case 'x': mogo_patterns
[mogo_patterns_src_n
* 4 + i
][j
] = 'o'; break;
127 case 'O': mogo_patterns
[mogo_patterns_src_n
* 4 + i
][j
] = 'X'; break;
128 case 'o': mogo_patterns
[mogo_patterns_src_n
* 4 + i
][j
] = 'x'; break;
129 default: mogo_patterns
[mogo_patterns_src_n
* 4 + i
][j
] = mogo_patterns
[i
][j
]; break;
135 for (int i
= 0; i
< mogo_patterns_n
; i
++) {
136 printf("%s\n", mogo_patterns
[i
]);
145 cut1_test_cut(struct playout_policy
*p
, struct board
*b
, coord_t base
, coord_t cut
)
148 * O(.)? X is base, (.) is cut
150 int x
= coord_x(base
, b
), y
= coord_y(base
, b
);
151 enum stone color
= board_at(b
, base
);
152 int xc
= coord_x(cut
, b
), yc
= coord_y(cut
, b
);
155 fprintf(stderr
, "Probing CUT1 %s -> %s\n", coord2sstr(base
, b
), coord2sstr(cut
, b
));
157 /* Kosumi available. Is it cutting? */
158 if (board_atxy(b
, x
, yc
) != stone_other(color
)
159 || board_atxy(b
, xc
, y
) != stone_other(color
))
162 /* It is! Is the cut protected? */
163 enum stone fix1
= board_atxy(b
, xc
, yc
- (y
- yc
));
164 enum stone fix2
= board_atxy(b
, xc
- (x
- xc
), yc
);
166 fprintf(stderr
, "Protection check: %d,%d\n", fix1
, fix2
);
167 if ((fix1
== stone_other(color
) || fix1
== S_OFFBOARD
) && fix2
!= color
)
169 if ((fix2
== stone_other(color
) || fix2
== S_OFFBOARD
) && fix1
!= color
)
172 /* Unprotected cut. Feast! */
174 fprintf(stderr
, "Passed.\n");
179 cut1_test(struct playout_policy
*p
, struct board
*b
, struct move
*m
, struct move_queue
*q
)
181 coord_t coord
= m
->coord
;
182 int x
= coord_x(coord
, b
), y
= coord_y(coord
, b
);
183 enum stone color
= board_at(b
, coord
);
185 /* Either last move was cutting threat... */
186 foreach_diag_neighbor(b
, coord
) {
187 if (board_at(b
, c
) != S_NONE
)
190 * O(.)? X is coord, (.) is c
192 if (cut1_test_cut(p
, b
, coord
, c
))
193 q
->move
[q
->moves
++] = c
;
194 } foreach_diag_neighbor_end
;
196 /* ...or a cuttable hane. */
197 #define cutbase_test(xb_, yb_) \
198 base = coord_xy_otf(xb_, yb_, b); \
199 if (board_at(b, base) == stone_other(color)) \
200 if (cut1_test_cut(p, b, base, c)) \
201 q->move[q->moves++] = c;
202 foreach_neighbor(b
, coord
, {
203 if (board_at(b
, c
) != S_NONE
)
206 * O(.)? O is coord, (.) is c
208 /* Check for X on both sides of O. */
209 int xc
= coord_x(c
, b
);
210 int yc
= coord_y(c
, b
);
212 /* Either x == xc or y == yc. */
213 cutbase_test(x
- (yc
- y
), y
- (xc
- x
));
214 cutbase_test(x
+ (yc
- y
), y
+ (xc
- x
));
220 cut2_test_cut(struct playout_policy
*p
, struct board
*b
, coord_t base
, coord_t cut
)
223 * O(.)O X is base, (.) is cut
225 int x
= coord_x(base
, b
), y
= coord_y(base
, b
);
226 enum stone color
= board_at(b
, base
);
227 int xc
= coord_x(cut
, b
), yc
= coord_y(cut
, b
);
230 fprintf(stderr
, "Probing CUT2 %s -> %s\n", coord2sstr(base
, b
), coord2sstr(cut
, b
));
232 /* Nobi available. Is it cutting? */
233 if (board_atxy(b
, xc
- (yc
- y
), yc
- (xc
- x
)) != stone_other(color
)
234 || board_atxy(b
, xc
+ (yc
- y
), yc
+ (xc
- x
)) != stone_other(color
))
237 /* It is! Is the cut protected? */
238 enum stone ocolor
= stone_other(color
);
241 fprintf(stderr
, "Protection check - row [%d,%d].\n", xc
, yc
+ (yc
- y
));
242 if (board_atxy(b
, xc
- 1, yc
+ (yc
- y
)) == ocolor
243 || board_atxy(b
, xc
, yc
+ (yc
- y
)) == ocolor
244 || board_atxy(b
, xc
+ 1, yc
+ (yc
- y
)) == ocolor
)
248 fprintf(stderr
, "Protection check - column [%d,%d].\n", xc
+ (xc
- x
), yc
);
249 if (board_atxy(b
, xc
+ (xc
- x
), yc
- 1) == ocolor
250 || board_atxy(b
, xc
+ (xc
- x
), yc
) == ocolor
251 || board_atxy(b
, xc
+ (xc
- x
), yc
+ 1) == ocolor
)
255 /* Unprotected cut. Feast! */
257 fprintf(stderr
, "Passed.\n");
262 cut2_test(struct playout_policy
*p
, struct board
*b
, struct move
*m
, struct move_queue
*q
)
264 coord_t coord
= m
->coord
;
265 int x
= coord_x(coord
, b
), y
= coord_y(coord
, b
);
266 enum stone color
= board_at(b
, coord
);
268 /* Either last move was cutting threat... */
269 foreach_neighbor(b
, coord
, {
270 if (board_at(b
, c
) != S_NONE
)
273 * O(.)O X is coord, (.) is c
275 if (cut2_test_cut(p
, b
, coord
, c
))
276 q
->move
[q
->moves
++] = c
;
279 /* ...or a cuttable ikken tobi. */
280 #define cutbase_test(xb_, yb_) \
281 base = coord_xy_otf(xb_, yb_, b); \
282 if (board_at(b, base) == stone_other(color)) \
283 if (cut2_test_cut(p, b, base, c)) \
284 q->move[q->moves++] = c;
285 foreach_neighbor(b
, coord
, {
286 if (board_at(b
, c
) != S_NONE
)
289 * O(.)O O is coord, (.) is c
291 /* Check for X on both sides of (.). */
292 int xc
= coord_x(c
, b
);
293 int yc
= coord_y(c
, b
);
295 /* Either x == xc or y == yc. */
296 cutbase_test(xc
- (yc
- y
), yc
- (xc
- x
));
297 cutbase_test(xc
+ (yc
- y
), yc
+ (xc
- x
));
304 /*** OPTIMIZE ME ***/
306 /* Check if we match a certain pattern transposition centered on given move. */
308 apply_one_pattern_here(struct playout_policy
*p
, char pattern
[10],
309 struct board
*b
, struct move
*m
, struct move_queue
*q
)
311 switch (pattern
[4]) {
312 case 'X': case 'o': if (m
->color
!= S_BLACK
) return; break;
313 case 'O': case 'x': if (m
->color
!= S_WHITE
) return; break;
315 for (int y
= 0; y
< 3; y
++) {
316 for (int x
= 0; x
< 3; x
++) {
317 if (x
== 1 && y
== 1)
319 enum stone color
= board_at(b
, m
->coord
+ x
- 1 + (y
- 1) * board_size(b
));
320 switch (pattern
[x
+ 3 * y
]) {
322 case '.': if (color
!= S_NONE
) return; break;
323 case '#': if (color
!= S_OFFBOARD
) return; break;
324 case 'X': if (color
!= S_BLACK
) return; break;
325 case 'O': if (color
!= S_WHITE
) return; break;
326 case 'x': if (color
== S_BLACK
) return; break;
327 case 'o': if (color
== S_WHITE
) return; break;
331 q
->move
[q
->moves
++] = m
->coord
;
334 /* Check if we match any pattern centered on given move. */
336 apply_pattern_here(struct playout_policy
*p
, char patternset
[][10], int patterns
,
337 struct board
*b
, struct move
*m
, struct move_queue
*q
)
339 for (int i
= 0; i
< patterns
; i
++)
340 apply_one_pattern_here(p
, patternset
[i
], b
, m
, q
);
343 /* Check if we match any pattern around given move (with the other color to play). */
345 apply_pattern(struct playout_policy
*p
, struct board
*b
, struct move
*m
, struct move
*testmove
)
347 //struct moggy_policy *pp = p->data;
351 /* Suicides do not make any patterns and confuse us. */
352 if (board_at(b
, m
->coord
) == S_NONE
|| board_at(b
, m
->coord
) == S_OFFBOARD
)
356 if (pp
->hanerate
> fast_random(100)) {
360 if (pp
->cut1rate
> fast_random(100)) {
361 cut1_test(p
, b
, m
, &q
);
364 if (pp
->cut2rate
> fast_random(100)) {
365 cut2_test(p
, b
, m
, &q
);
368 // FIXME: Fix assess callers
369 foreach_neighbor(b
, m
->coord
, {
370 struct move m2
; m2
.coord
= c
; m2
.color
= stone_other(m
->color
);
371 if (board_at(b
, c
) == S_NONE
)
372 apply_pattern_here(p
, mogo_patterns
, mogo_patterns_n
, b
, &m2
, &q
);
374 foreach_diag_neighbor(b
, m
->coord
) {
375 struct move m2
; m2
.coord
= c
; m2
.color
= stone_other(m
->color
);
376 if (board_at(b
, c
) == S_NONE
)
377 apply_pattern_here(p
, mogo_patterns
, mogo_patterns_n
, b
, &m2
, &q
);
378 } foreach_diag_neighbor_end
;
380 if (0){//PLDEBUGL(5)) {
381 fprintf(stderr
, "Pattern candidate moves: ");
382 for (int i
= 0; i
< q
.moves
; i
++) {
383 fprintf(stderr
, "%s ", coord2sstr(q
.move
[i
], b
));
385 fprintf(stderr
, "\n");
390 if (q
.move
[q
.moves
] == testmove
->coord
) {
392 fprintf(stderr
, "Found queried move.\n");
393 return testmove
->coord
;
398 int i
= fast_random(q
.moves
);
399 return q
.moves
? q
.move
[i
] : pass
;
404 /* Is this ladder breaker friendly for the one who catches ladder. */
406 ladder_catcher(struct board
*b
, int x
, int y
, enum stone laddered
)
408 enum stone breaker
= board_atxy(b
, x
, y
);
409 return breaker
== stone_other(laddered
) || breaker
== S_OFFBOARD
;
413 ladder_catches(struct playout_policy
*p
, struct board
*b
, coord_t coord
, group_t laddered
)
415 struct moggy_policy
*pp
= p
->data
;
417 /* This is very trivial and gets a lot of corner cases wrong.
418 * We need this to be just very fast. One important point is
419 * that we sometimes might not notice a ladder but if we do,
420 * it should always work; thus we can use this for strong
421 * negative hinting safely. */
422 //fprintf(stderr, "ladder check\n");
424 enum stone lcolor
= board_at(b
, group_base(laddered
));
425 int x
= coord_x(coord
, b
), y
= coord_y(coord
, b
);
427 /* First, special-case first-line "ladders". This is a huge chunk
428 * of ladders we actually meet and want to play. */
429 if (pp
->borderladders
430 && neighbor_count_at(b
, coord
, S_OFFBOARD
) == 1
431 && neighbor_count_at(b
, coord
, lcolor
) == 1) {
433 fprintf(stderr
, "border ladder\n");
434 /* Direction along border; xd is horiz. border, yd vertical. */
436 if (board_atxy(b
, x
+ 1, y
) == S_OFFBOARD
|| board_atxy(b
, x
- 1, y
) == S_OFFBOARD
)
440 /* Direction from the border; -1 is above/left, 1 is below/right. */
441 int dd
= (board_atxy(b
, x
+ yd
, y
+ xd
) == S_OFFBOARD
) ? 1 : -1;
443 fprintf(stderr
, "xd %d yd %d dd %d\n", xd
, yd
, dd
);
449 /* This is normally caught, unless we have friends both above
451 if (board_atxy(b
, x
+ xd
* 2, y
+ yd
* 2) == lcolor
452 && board_atxy(b
, x
- xd
* 2, y
- yd
* 2) == lcolor
)
454 /* ...or can't block where we need because of shortage
456 int libs1
= board_group_info(b
, group_atxy(b
, x
+ xd
- yd
* dd
, y
+ yd
- xd
* dd
)).libs
;
457 int libs2
= board_group_info(b
, group_atxy(b
, x
- xd
- yd
* dd
, y
- yd
- xd
* dd
)).libs
;
459 fprintf(stderr
, "libs1 %d libs2 %d\n", libs1
, libs2
);
460 if (libs1
< 2 && libs2
< 2)
462 if (board_atxy(b
, x
+ xd
* 2, y
+ yd
* 2) == lcolor
&& libs1
< 3)
464 if (board_atxy(b
, x
- xd
* 2, y
- yd
* 2) == lcolor
&& libs2
< 3)
469 /* Figure out the ladder direction */
471 xd
= board_atxy(b
, x
+ 1, y
) == S_NONE
? 1 : board_atxy(b
, x
- 1, y
) == S_NONE
? -1 : 0;
472 yd
= board_atxy(b
, x
, y
+ 1) == S_NONE
? 1 : board_atxy(b
, x
, y
- 1) == S_NONE
? -1 : 0;
474 /* We do only tight ladders, not loose ladders. Furthermore,
475 * the ladders need to be simple:
477 * c O X supported . c O unsupported
481 /* For given (xd,yd), we have two possibilities where to move
482 * next. Consider (-1,1):
487 if (!xd
|| !yd
|| !(ladder_catcher(b
, x
- xd
, y
, lcolor
) ^ ladder_catcher(b
, x
, y
- yd
, lcolor
))) {
488 /* Silly situation, probably non-simple ladder or suicide. */
489 /* TODO: In case of basic non-simple ladder, play out both variants. */
491 fprintf(stderr
, "non-simple ladder\n");
495 #define ladder_check(xd1_, yd1_, xd2_, yd2_) \
496 if (board_atxy(b, x, y) != S_NONE) { \
497 /* Did we hit a stone when playing out ladder? */ \
498 if (ladder_catcher(b, x, y, lcolor)) \
499 return true; /* ladder works */ \
500 if (board_group_info(b, group_atxy(b, x, y)).lib[0] > 0) \
501 return false; /* friend that's not in atari himself */ \
503 /* No. So we are at new position. \
504 * We need to check indirect ladder breakers. */ \
506 * . x o O 1 <- only at O we can check for o at 2 \
507 * x o o x . otherwise x at O would be still deadly \
509 * We check for o and x at 1, these are vital. \
510 * We check only for o at 2; x at 2 would mean we \
511 * need to fork (one step earlier). */ \
512 enum stone s1 = board_atxy(b, x + (xd1_), y + (yd1_)); \
513 if (s1 == lcolor) return false; \
514 if (s1 == stone_other(lcolor)) return true; \
515 enum stone s2 = board_atxy(b, x + (xd2_), y + (yd2_)); \
516 if (s2 == lcolor) return false; \
518 #define ladder_horiz do { if (PLDEBUGL(6)) fprintf(stderr, "%d,%d horiz step %d\n", x, y, xd); x += xd; ladder_check(xd, 0, -2 * xd, yd); } while (0)
519 #define ladder_vert do { if (PLDEBUGL(6)) fprintf(stderr, "%d,%d vert step %d\n", x, y, yd); y += yd; ladder_check(0, yd, xd, -2 * yd); } while (0)
521 if (ladder_catcher(b
, x
- xd
, y
, lcolor
))
531 group_atari_check(struct playout_policy
*p
, struct board
*b
, group_t group
)
533 struct moggy_policy
*pp
= p
->data
;
534 enum stone color
= board_at(b
, group_base(group
));
535 coord_t lib
= board_group_info(b
, group
).lib
[0];
537 assert(color
!= S_OFFBOARD
&& color
!= S_NONE
);
539 fprintf(stderr
, "atariiiiiiiii %s of color %d\n", coord2sstr(lib
, b
), color
);
540 assert(board_at(b
, lib
) == S_NONE
);
542 /* Do not suicide... */
543 if (!valid_escape_route(b
, color
, lib
))
546 fprintf(stderr
, "...escape route valid\n");
548 /* ...or play out ladders. */
549 if (pp
->ladders
&& ladder_catches(p
, b
, lib
, group
)) {
553 fprintf(stderr
, "...no ladder\n");
558 /* There is still hope - can't we capture some neighbor? */
559 foreach_in_group(b
, group
) {
560 foreach_neighbor(b
, c
, {
561 if (board_at(b
, c
) != stone_other(color
)
562 || board_group_info(b
, group_at(b
, c
)).libs
> 1)
565 fprintf(stderr
, "can capture group %d\n", group_at(b
, c
));
566 /* If we are saving our group, capture! */
567 if (b
->last_move
.color
== stone_other(color
))
568 return board_group_info(b
, group_at(b
, c
)).lib
[0];
569 /* If we chase the group, capture it now! */
572 } foreach_in_group_end
;
577 global_atari_check(struct playout_policy
*p
, struct board
*b
)
582 int g_base
= fast_random(b
->clen
);
583 for (int g
= g_base
; g
< b
->clen
; g
++) {
584 coord_t c
= group_atari_check(p
, b
, group_at(b
, group_base(b
->c
[g
])));
588 for (int g
= 0; g
< g_base
; g
++) {
589 coord_t c
= group_atari_check(p
, b
, group_at(b
, group_base(b
->c
[g
])));
597 local_atari_check(struct playout_policy
*p
, struct board
*b
, struct move
*m
, struct move
*testmove
)
602 /* Did the opponent play a self-atari? */
603 if (board_group_info(b
, group_at(b
, m
->coord
)).libs
== 1) {
604 coord_t l
= group_atari_check(p
, b
, group_at(b
, m
->coord
));
606 q
.move
[q
.moves
++] = l
;
609 foreach_neighbor(b
, m
->coord
, {
610 group_t g
= group_at(b
, c
);
611 if (!g
|| board_group_info(b
, g
).libs
!= 1)
613 coord_t l
= group_atari_check(p
, b
, g
);
615 q
.move
[q
.moves
++] = l
;
619 fprintf(stderr
, "Local atari candidate moves: ");
620 for (int i
= 0; i
< q
.moves
; i
++) {
621 fprintf(stderr
, "%s ", coord2sstr(q
.move
[i
], b
));
623 fprintf(stderr
, "\n");
628 if (q
.move
[q
.moves
] == testmove
->coord
) {
630 fprintf(stderr
, "Found queried move.\n");
631 return testmove
->coord
;
636 int i
= fast_random(q
.moves
);
637 return q
.moves
? q
.move
[i
] : pass
;
641 playout_moggy_choose(struct playout_policy
*p
, struct board
*b
, enum stone our_real_color
)
643 struct moggy_policy
*pp
= p
->data
;
647 board_print(b
, stderr
);
650 if (!is_pass(b
->last_move
.coord
)) {
651 /* Local group in atari? */
652 if (pp
->lcapturerate
> fast_random(100)) {
653 c
= local_atari_check(p
, b
, &b
->last_move
, NULL
);
658 /* Check for patterns we know */
659 if (pp
->patternrate
> fast_random(100)) {
660 c
= apply_pattern(p
, b
, &b
->last_move
, NULL
);
668 /* Any groups in atari? */
669 if (pp
->capturerate
> fast_random(100)) {
670 c
= global_atari_check(p
, b
);
679 playout_moggy_assess(struct playout_policy
*p
, struct board
*b
, struct move
*m
)
681 struct moggy_policy
*pp
= p
->data
;
683 if (is_pass(m
->coord
))
687 fprintf(stderr
, "ASSESS of %s:\n", coord2sstr(m
->coord
, b
));
688 board_print(b
, stderr
);
691 /* Are we dealing with atari? */
692 if (pp
->lcapturerate
> fast_random(100)) {
693 if (pp
->localassess
&& !is_pass(b
->last_move
.coord
)) {
694 if (local_atari_check(p
, b
, &b
->last_move
, m
) == m
->coord
)
697 foreach_neighbor(b
, m
->coord
, {
699 m2
.coord
= c
; m2
.color
= stone_other(m
->color
);
700 if (local_atari_check(p
, b
, &m2
, m
) == m
->coord
)
705 /* Assess ladders anywhere, local or not. */
706 /* In case we don't localassess, local_atari_check() will
707 * alaready do the job. */
708 if (!pp
->localassess
&& pp
->ladderassess
) {
709 //fprintf(stderr, "ASSESS %s\n", coord2sstr(m->coord, b));
710 foreach_neighbor(b
, m
->coord
, {
711 if (board_at(b
, c
) == S_NONE
|| board_at(b
, c
) == S_OFFBOARD
)
713 group_t g
= group_at(b
, c
);
714 if (board_group_info(b
, g
).libs
!= 1)
716 if (ladder_catches(p
, b
, m
->coord
, g
))
723 if (pp
->patternrate
> fast_random(100)) {
724 if (pp
->localassess
&& !is_pass(b
->last_move
.coord
)) {
725 if (apply_pattern(p
, b
, &b
->last_move
, m
) == m
->coord
)
728 foreach_neighbor(b
, m
->coord
, {
730 m2
.coord
= c
; m2
.color
= stone_other(m
->color
);
731 if (apply_pattern(p
, b
, &m2
, m
) == m
->coord
)
734 foreach_diag_neighbor(b
, m
->coord
) {
736 m2
.coord
= c
; m2
.color
= stone_other(m
->color
);
737 if (apply_pattern(p
, b
, &m2
, m
) == m
->coord
)
739 } foreach_diag_neighbor_end
;
747 struct playout_policy
*
748 playout_moggy_init(char *arg
)
750 struct playout_policy
*p
= calloc(1, sizeof(*p
));
751 struct moggy_policy
*pp
= calloc(1, sizeof(*pp
));
753 p
->choose
= playout_moggy_choose
;
754 p
->assess
= playout_moggy_assess
;
756 pp
->lcapturerate
= 75;
757 pp
->capturerate
= 75;
758 pp
->patternrate
= 75;
759 pp
->hanerate
= pp
->cut1rate
= pp
->cut2rate
= 75;
760 pp
->ladders
= pp
->borderladders
= true;
761 pp
->ladderassess
= true;
764 char *optspec
, *next
= arg
;
767 next
+= strcspn(next
, ":");
768 if (*next
) { *next
++ = 0; } else { *next
= 0; }
770 char *optname
= optspec
;
771 char *optval
= strchr(optspec
, '=');
772 if (optval
) *optval
++ = 0;
774 if (!strcasecmp(optname
, "lcapturerate") && optval
) {
775 pp
->lcapturerate
= atoi(optval
);
776 } else if (!strcasecmp(optname
, "capturerate") && optval
) {
777 pp
->capturerate
= atoi(optval
);
778 } else if (!strcasecmp(optname
, "patternrate") && optval
) {
779 pp
->patternrate
= atoi(optval
);
780 } else if (!strcasecmp(optname
, "hanerate") && optval
) {
781 pp
->hanerate
= atoi(optval
);
782 } else if (!strcasecmp(optname
, "cut1rate") && optval
) {
783 pp
->cut1rate
= atoi(optval
);
784 } else if (!strcasecmp(optname
, "cut2rate") && optval
) {
785 pp
->cut2rate
= atoi(optval
);
786 } else if (!strcasecmp(optname
, "ladders")) {
787 pp
->ladders
= optval
&& *optval
== '0' ? false : true;
788 } else if (!strcasecmp(optname
, "borderladders")) {
789 pp
->borderladders
= optval
&& *optval
== '0' ? false : true;
790 } else if (!strcasecmp(optname
, "localassess")) {
791 pp
->localassess
= optval
&& *optval
== '0' ? false : true;
792 } else if (!strcasecmp(optname
, "ladderassess")) {
793 pp
->ladderassess
= optval
&& *optval
== '0' ? false : true;
795 fprintf(stderr
, "playout-moggy: Invalid policy argument %s or missing value\n", optname
);