static char *ParseReciEnd(char *tok, slice_index start, slice_index proxy) { slice_index op1; slice_index op2; TraceFunctionEntry(__func__); TraceFunctionParam("%s",tok); TraceFunctionParam("%u",start); TraceFunctionParam("%u",proxy); TraceFunctionParamListEnd(); op1 = alloc_proxy_slice(); op2 = alloc_proxy_slice(); tok = ParseReciGoal(tok,start,op1,op2); if (SLICE_NEXT1(op1)!=no_slice && SLICE_NEXT1(op2)!=no_slice) { slice_index const reci = alloc_and_slice(op1,op2); pipe_link(proxy,reci); } TraceFunctionExit(__func__); TraceFunctionResult("%s",tok); TraceFunctionResultEnd(); return tok; }
static char *ParseReciGoal(char *tok, slice_index start, slice_index proxy_nonreci, slice_index proxy_reci) { char *result = 0; TraceFunctionEntry(__func__); TraceFunctionParam("%s",tok); TraceFunctionParamListEnd(); if (*tok=='(') { char const *closingParenPos = strchr(tok,')'); if (closingParenPos!=0) { slice_index const proxy_to_reci = alloc_proxy_slice(); tok = ParseGoal(tok+1,start,proxy_to_reci); if (tok!=0) { if (tok==closingParenPos) { slice_index const proxy_to_nonreci = alloc_proxy_slice(); result = ParseGoal(tok+1,start,proxy_to_nonreci); if (result!=NULL) { slice_index const nonreci = SLICE_NEXT1(proxy_to_nonreci); SLICE_STARTER(nonreci) = Black; alloc_reci_end(proxy_nonreci,proxy_reci, proxy_to_nonreci,proxy_to_reci); } } else output_plaintext_input_error_message(UnrecStip, 0); } } else output_plaintext_input_error_message(UnrecStip, 0); } else { slice_index const proxy_to_nonreci = alloc_proxy_slice(); result = ParseGoal(tok,start,proxy_to_nonreci); if (result!=NULL) { slice_index const nonreci_testing = SLICE_NEXT1(proxy_to_nonreci); slice_index const nonreci_tester = SLICE_NEXT1(nonreci_testing); slice_index const proxy_to_reci = stip_deep_copy(proxy_to_nonreci); alloc_reci_end(proxy_nonreci,proxy_reci, proxy_to_nonreci,proxy_to_reci); SLICE_STARTER(nonreci_tester) = Black; } } TraceFunctionExit(__func__); TraceFunctionResult("%s",result); TraceFunctionResultEnd(); return result; }
/* Insert slices into a goal branch. * The inserted slices are copies of the elements of prototypes). * Each slice is inserted at a position that corresponds to its predefined rank. * @param si identifies starting point of insertion * @param prototypes contains the prototypes whose copies are inserted * @param nr_prototypes number of elements of array prototypes */ static void goal_branch_insert_slices_nested(slice_index si, slice_index const prototypes[], unsigned int nr_prototypes) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParam("%u",nr_prototypes); TraceFunctionParamListEnd(); { slice_type const prototype_type = SLICE_TYPE(prototypes[0]); unsigned int prototype_rank = get_goal_slice_rank(prototype_type); if (prototype_rank==no_goal_slice_type) { if (nr_prototypes>1) goal_branch_insert_slices_nested(si,prototypes+1,nr_prototypes-1); } else do { slice_index const next = SLICE_NEXT1(si); if (SLICE_TYPE(next)==STProxy) si = next; else if (SLICE_TYPE(next)==STOr || SLICE_TYPE(next)==STAnd) { goal_branch_insert_slices_nested(SLICE_NEXT1(next), prototypes,nr_prototypes); goal_branch_insert_slices_nested(SLICE_NEXT2(next), prototypes,nr_prototypes); break; } else { unsigned int const rank_next = get_goal_slice_rank(SLICE_TYPE(next)); if (rank_next==no_goal_slice_type) break; else if (rank_next>prototype_rank) { slice_index const copy = copy_slice(prototypes[0]); pipe_append(si,copy); if (nr_prototypes>1) goal_branch_insert_slices_nested(copy,prototypes+1,nr_prototypes-1); break; } else si = next; } } while (prototype_type!=SLICE_TYPE(si)); } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Traverse operand 1 of a binary slice * @param binary_slice identifies the binary slice * @param st address of structure defining traversal */ void stip_traverse_moves_binary_operand1(slice_index binary_slice, stip_moves_traversal *st) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",binary_slice); TraceFunctionParam("%p",st); TraceFunctionParamListEnd(); if (SLICE_NEXT1(binary_slice)!=no_slice) stip_traverse_moves(SLICE_NEXT1(binary_slice),st); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Parse a move inversion * @param tok input token * @param start index of entry into solving machinery * @param proxy index of branch; no_slice if operator couldn't be parsed * @param level nesting level of the operand (0 means top level) * @return remainder of input token; 0 if parsing failed */ static char *ParseStructuredStip_move_inversion(char *tok, slice_index start, slice_index proxy, expression_type *type, unsigned int level) { TraceFunctionEntry(__func__); TraceFunctionParam("%s",tok); TraceFunctionParam("%u",start); TraceFunctionParam("%u",proxy); TraceFunctionParam("%u",level); TraceFunctionParamListEnd(); tok = ParseStructuredStip_operand(tok+1,start,proxy,type,level); { slice_index const operand = SLICE_NEXT1(proxy); if (tok!=0 && operand!=no_slice) { slice_index const prototype = alloc_move_inverter_slice(); slice_insertion_insert(proxy,&prototype,1); } } TraceFunctionExit(__func__); TraceFunctionResult("%s",tok); TraceFunctionResultEnd(); return tok; }
static void instrument_negated_tester(slice_index si, stip_structure_traversal *st) { in_branch_insertion_state_type * const state = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); if (state->in_goal_tester!=no_goal) { /* make sure that not_slice doesn't convert previous_move_has_not_solved into * previous_move_has_solved if the last move caused a self-check */ slice_index const proxy_not = alloc_proxy_slice(); slice_index const proxy_selfcheck = alloc_proxy_slice(); slice_index const guard = alloc_selfcheck_guard_slice(); slice_index const leaf_selfcheck = alloc_true_slice(); if (is_goal_move_oriented(SLICE_NEXT1(si),st)) pipe_link(SLICE_PREV(si),alloc_and_slice(proxy_not,proxy_selfcheck)); else pipe_link(SLICE_PREV(si),alloc_and_slice(proxy_selfcheck,proxy_not)); pipe_link(proxy_not,si); pipe_link(proxy_selfcheck,guard); pipe_link(guard,leaf_selfcheck); state->is_branch_instrumented = true; } else stip_traverse_structure_children_pipe(si,st); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Instrument a help branch with a STIfThenElse slice * @param adapter identifies adapter slice into the help branch */ void help_branch_insert_check_zigzag(slice_index adapter) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",adapter); TraceFunctionParamListEnd(); { slice_index const ready = help_branch_locate_ready(adapter); slice_index const proxy1 = alloc_proxy_slice(); slice_index const proxy2 = alloc_proxy_slice(); slice_index const played = alloc_help_move_played_slice(); slice_index const condition = alloc_goal_check_reached_tester_slice(goal_applies_to_starter); slice_index const jump = alloc_if_then_else_slice(proxy1,proxy2,condition); slice_index const landing_proto = alloc_pipe(STCheckZigzagLanding); assert(ready!=no_slice); pipe_link(condition,alloc_true_slice()); help_branch_insert_slices(ready,&landing_proto,1); pipe_link(proxy2,SLICE_NEXT1(ready)); pipe_link(proxy1,played); pipe_link(ready,jump); { slice_index const landing = branch_find_slice(STCheckZigzagLanding, ready, stip_traversal_context_help); assert(landing!=no_slice); link_to_branch(played,landing); } } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
static void copy_end_of_branch_goal_if_necessary(slice_index si, stip_structure_traversal *st) { stip_deep_copies_type * const copies = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); { slice_index const tester = branch_find_slice(STGoalReachedTester,SLICE_NEXT2(si),st->context); if (tester==no_slice /* avoid considering moves that lead to self-check illegal if they reach the goal: */ || branch_find_slice(STSelfCheckGuard,SLICE_NEXT2(tester),st->context)==no_slice) regular_deep_copy_end_of_branch_goal(si,st); else { /* Rely on the tests in the goal reached tester: */ (*copies)[si] = alloc_proxy_slice(); stip_traverse_structure_children_pipe(si,st); pipe_link((*copies)[si],(*copies)[SLICE_NEXT1(si)]); } } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Parse a structured stipulation (keyword sstipulation) * @param start index of entry into solving machinery * @return remainder of input token; 0 if parsing failed */ char *ParseStructuredStip(char *tok, slice_index start) { slice_index const root_slice_hook = alloc_proxy_slice(); Side starter; TraceFunctionEntry(__func__); TraceFunctionParam("%s",tok); TraceFunctionParam("%u",root_slice_hook); TraceFunctionParamListEnd(); stipulation_reset(); starter = ParseStructuredStip_starter(tok); if (starter!=no_side) { expression_type type; tok = ReadNextTokStr(); tok = ParseStructuredStip_expression(tok,start,root_slice_hook,&type,0); if (tok==0) tok = ReadNextTokStr(); else if (SLICE_NEXT1(root_slice_hook)!=no_slice) { solving_impose_starter(root_slice_hook,starter); move_effect_journal_do_insert_sstipulation(start,root_slice_hook); } } /* signal to our caller that the stipulation has changed */ SLICE_STARTER(root_slice_hook) = no_side; TraceFunctionExit(__func__); TraceFunctionResult("%s",tok); TraceFunctionResultEnd(); return tok; }
/* Create a shallow copy of the visited fork slice * @param si visited slice * @param st structure representing the copying traversal */ static void copy_shallow(slice_index si, stip_structure_traversal *st) { stip_deep_copies_type * const copies = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); assert((*copies)[si]==no_slice); (*copies)[si] = copy_slice(si); stip_traverse_structure_children_pipe(si,st); if (SLICE_NEXT1(si)!=no_slice) link_to_branch((*copies)[si],(*copies)[SLICE_NEXT1(si)]); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Add the copy of a slice into the set play branch * @param si slice index * @param st state of traversal */ static void copy_to_setplay(slice_index si, stip_structure_traversal *st) { spin_off_state_type * const state = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); stip_traverse_structure_children_pipe(si,st); TraceValue("%u",state->spun_off[SLICE_NEXT1(si)]); TraceEOL(); state->spun_off[si] = copy_slice(si); link_to_branch(state->spun_off[si],state->spun_off[SLICE_NEXT1(si)]); TraceValue("%u",state->spun_off[si]); TraceEOL(); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Spin a STContraintSolver slice off a STContraintTester sliceto add it to the * root or set play branch * @param si identifies (non-root) slice * @param st address of structure representing traversal */ void constraint_tester_make_root(slice_index si, stip_structure_traversal *st) { spin_off_state_type * const state = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); stip_traverse_structure_children_pipe(si,st); if (state->spun_off[SLICE_NEXT1(si)]!=no_slice) { state->spun_off[si] = alloc_constraint_solver_slice(stip_deep_copy(SLICE_NEXT2(si))); link_to_branch(state->spun_off[si],state->spun_off[SLICE_NEXT1(si)]); } TraceValue("%u\n",state->spun_off[si]); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
static void substitute_king_first(slice_index si, stip_structure_traversal *st) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); assert(SLICE_STARTER(si)!=no_side); stip_traverse_structure_children_pipe(si,st); /* this optimisation doesn't work if an ultra-mummer condition applies * to the side to be immobilised */ if (mummer_strictness[SLICE_STARTER(si)]<=mummer_strictness_regular) { slice_index const proxy1 = alloc_proxy_slice(); slice_index const proxy2 = alloc_proxy_slice(); slice_index const king_branch = SLICE_NEXT1(si); slice_index const nonking_branch = stip_deep_copy(king_branch); slice_index const king_move_tester = alloc_pipe(STImmobilityTester); slice_index const nonking_move_tester = alloc_pipe(STImmobilityTester); pipe_link(si,alloc_and_slice(proxy1,proxy2)); pipe_link(proxy1,king_move_tester); link_to_branch(king_move_tester,king_branch); { slice_index const generator = branch_find_slice(STMoveGenerator, king_branch, stip_traversal_context_intro); assert(generator!=no_slice); pipe_substitute(generator,alloc_king_move_generator_slice()); } pipe_link(proxy2,nonking_move_tester); link_to_branch(nonking_move_tester,nonking_branch); { slice_index const generator = branch_find_slice(STMoveGenerator, nonking_branch, stip_traversal_context_intro); assert(generator!=no_slice); pipe_substitute(generator,alloc_non_king_move_generator_slice()); } pipe_remove(si); } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
static void stip_traverse_moves_pipe(slice_index si, stip_moves_traversal *st) { slice_index const next = SLICE_NEXT1(si); TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); assert(next!=no_slice); stip_traverse_moves(next,st); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Callback to stip_spin_off_testers * Spin a tester slice off a fork slice * @param si identifies the testing pipe slice * @param st address of structure representing traversal */ void stip_spin_off_testers_fork(slice_index si, stip_structure_traversal *st) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); SLICE_TESTER(si) = copy_slice(si); stip_traverse_structure_children(si,st); link_to_branch(SLICE_TESTER(si),SLICE_TESTER(SLICE_NEXT1(si))); SLICE_NEXT2(SLICE_TESTER(si)) = SLICE_TESTER(SLICE_NEXT2(si)); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Spin a copy off a conditional pipe to add it to the root or set play branch * @param si identifies (non-root) slice * @param st address of structure representing traversal */ void conditional_pipe_spin_off_copy(slice_index si, stip_structure_traversal *st) { spin_off_state_type * const state = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); state->spun_off[si] = copy_slice(si); stip_traverse_structure_children_pipe(si,st); if (state->spun_off[SLICE_NEXT1(si)]==no_slice) { dealloc_slice(state->spun_off[si]); state->spun_off[si] = no_slice; } else link_to_branch(state->spun_off[si],state->spun_off[SLICE_NEXT1(si)]); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Produce slices representing set play. * @param adapter identifies the adapter slice at the beginning of the branch * @param state address of structure holding state */ void series_branch_make_setplay(slice_index adapter, spin_off_state_type *state) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",adapter); TraceFunctionParamListEnd(); { slice_index const next = SLICE_NEXT1(adapter); slice_index const prototypes[] = { alloc_help_adapter_slice(0,0), alloc_pipe(STEndOfRoot) }; enum { nr_prototypes = sizeof prototypes / sizeof prototypes[0] }; help_branch_insert_slices(next,prototypes,nr_prototypes); { slice_index const set_adapter = branch_find_slice(STHelpAdapter, next, stip_traversal_context_help); assert(set_adapter!=no_slice); if (SLICE_TYPE(SLICE_NEXT1(set_adapter))==STDeadEnd) ; /* set play not applicable */ else help_branch_make_root_slices(set_adapter,state); TraceValue("%u\n",state->spun_off[set_adapter]); state->spun_off[adapter] = state->spun_off[set_adapter]; pipe_remove(set_adapter); } } TraceValue("%u\n",state->spun_off[adapter]); TraceFunctionExit(__func__); TraceFunctionParamListEnd(); }
static void skip_copying(slice_index si, stip_structure_traversal *st) { stip_deep_copies_type * const copies = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); (*copies)[si] = alloc_proxy_slice(); stip_traverse_structure_children_pipe(si,st); pipe_link((*copies)[si],(*copies)[SLICE_NEXT1(si)]); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
static void stip_traverse_moves_fork_on_remaining(slice_index si, stip_moves_traversal *st) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); if (st->remaining<=SLICE_U(si).fork_on_remaining.threshold) stip_traverse_moves(SLICE_NEXT2(si),st); else stip_traverse_moves(SLICE_NEXT1(si),st); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
static void connect_solver_to_tester(slice_index si, stip_structure_traversal *st) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); if (st->activity==stip_traversal_activity_solving) { assert(SLICE_TESTER(SLICE_PREV(si))!=no_slice); SLICE_TESTER(si) = SLICE_NEXT1(SLICE_TESTER(SLICE_PREV(si))); } stip_traverse_structure_children_pipe(si,st); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
static slice_index make_mate_tester_fork(Side side) { slice_index result; if (CondFlag[exclusive] || CondFlag[republican]) { Goal const mate_goal = { goal_mate, initsquare }; slice_index const mate_tester = alloc_goal_mate_reached_tester_system(); result = alloc_goal_reached_tester_slice(mate_goal,mate_tester); dealloc_slice(SLICE_NEXT1(result)); solving_impose_starter(result,side); } else result = alloc_proxy_slice(); return result; }
/* Instrument a battle branch with a STIfThenElse slice providing a * shortcut for the defense moe * @param adapter identifies adapter slice into the battle branch */ void battle_branch_insert_defense_check_zigzag(slice_index adapter) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",adapter); TraceFunctionParamListEnd(); { slice_index const ready = branch_find_slice(STReadyForDefense, adapter, stip_traversal_context_intro); slice_index const deadend = branch_find_slice(STDeadEnd, ready, stip_traversal_context_defense); slice_index const proxy1 = alloc_proxy_slice(); slice_index const proxy2 = alloc_proxy_slice(); slice_index const dummy = alloc_pipe(STDummyMove); slice_index const played = alloc_defense_played_slice(); slice_index const condition = alloc_goal_check_reached_tester_slice(goal_applies_to_starter); slice_index const jump = alloc_if_then_else_slice(proxy1,proxy2,condition); slice_index const landing_proto = alloc_pipe(STCheckZigzagLanding); assert(ready!=no_slice); assert(deadend!=no_slice); pipe_link(condition,alloc_true_slice()); defense_branch_insert_slices(ready,&landing_proto,1); pipe_link(proxy2,SLICE_NEXT1(deadend)); /* the dummy move is needed to make sure that the killer move mechanism * applies to the same play whether the attacker has delivered check or not * TODO only insert the dummy move if the killer move optimisation is used */ pipe_link(proxy1,dummy); pipe_link(dummy,played); pipe_link(deadend,jump); { slice_index const landing = branch_find_slice(STCheckZigzagLanding, deadend, stip_traversal_context_defense); assert(landing!=no_slice); link_to_branch(played,landing); } } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Produce slices representing set play. * @param adapter identifies the adapter slice at the beginning of the branch * @param state address of structure holding state */ void help_branch_make_setplay(slice_index adapter, spin_off_state_type *state) { stip_length_type const length = SLICE_U(adapter).branch.length; stip_length_type min_length = SLICE_U(adapter).branch.min_length; TraceFunctionEntry(__func__); TraceFunctionParam("%u",adapter); TraceFunctionParamListEnd(); assert(SLICE_TYPE(adapter)==STHelpAdapter); if (min_length==0) min_length = 2; if (length>1) { slice_index const next = SLICE_NEXT1(adapter); slice_index const prototypes[] = { alloc_help_adapter_slice(length-1,min_length-1), alloc_pipe(STEndOfRoot) }; enum { nr_prototypes = sizeof prototypes / sizeof prototypes[0] }; help_branch_insert_slices(next,prototypes,nr_prototypes); { slice_index const set_adapter = branch_find_slice(STHelpAdapter, next, stip_traversal_context_help); assert(set_adapter!=no_slice); help_branch_make_root_slices(set_adapter,state); state->spun_off[adapter] = state->spun_off[set_adapter]; pipe_remove(set_adapter); } } TraceValue("%u\n",state->spun_off[adapter]); TraceFunctionExit(__func__); TraceFunctionParamListEnd(); }
static void instrument_doublestalemate_tester(slice_index si, stip_structure_traversal *st) { in_branch_insertion_state_type * const state = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); stip_traverse_structure_children(si,st); if (state->in_goal_tester==goal_dblstale) { slice_index const prototype = alloc_selfcheck_guard_slice(); /* no need to instrument the operand that tests for stalemate of the * starting side */ goal_branch_insert_slices(SLICE_NEXT1(si),&prototype,1); state->is_branch_instrumented = true; } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Shorten a help branch by 1 half move * @param identifies entry slice of branch to be shortened */ void help_branch_shorten(slice_index adapter) { slice_index const next = SLICE_NEXT1(adapter); TraceFunctionEntry(__func__); TraceFunctionParam("%u",adapter); TraceFunctionParamListEnd(); assert(SLICE_TYPE(adapter)==STHelpAdapter); { /* find the new spot for adapter by inserting a copy */ slice_index const prototype = copy_slice(adapter); help_branch_insert_slices(next,&prototype,1); } { /* move adapter to its new spot */ slice_index const copy = branch_find_slice(STHelpAdapter, next, stip_traversal_context_help); assert(copy!=no_slice); pipe_link(SLICE_PREV(adapter),next); pipe_append(copy,adapter); pipe_remove(copy); } /* adjust the length and min_length members */ --SLICE_U(adapter).branch.length; if (SLICE_U(adapter).branch.min_length<=0) increase_min_length(adapter); --SLICE_U(adapter).branch.min_length; branch_shorten_slices(next,STHelpAdapter,stip_traversal_context_help); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Detect starter field with the starting side if possible. * @param si identifies slice being traversed * @param st status of traversal */ void fork_detect_starter(slice_index si, stip_structure_traversal *st) { slice_index const fork = SLICE_NEXT2(si); TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); stip_traverse_structure_next_branch(si,st); if (SLICE_STARTER(si)==no_side) { if (SLICE_STARTER(fork)==no_side) { stip_traverse_structure_children_pipe(si,st); SLICE_STARTER(si) = SLICE_STARTER(SLICE_NEXT1(si)); } else SLICE_STARTER(si) = SLICE_STARTER(fork); } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Parse a stipulation expression * @param tok input token * @param start index of entry into solving machinery * @param proxy index of expression slice; no_slice if expression * can't be parsed * @param level nesting level of the operand (0 means top level) * @return remainder of input token; 0 if parsing failed */ static char *ParseStructuredStip_expression(char *tok, slice_index start, slice_index proxy, expression_type *type, unsigned int level) { TraceFunctionEntry(__func__); TraceFunctionParam("%s",tok); TraceFunctionParam("%u",start); TraceFunctionParam("%u",proxy); TraceFunctionParam("%u",level); TraceFunctionParamListEnd(); { slice_index const operand1 = alloc_proxy_slice(); tok = ParseStructuredStip_operand(tok,start,operand1,type,level); if (tok!=0 && SLICE_NEXT1(operand1)!=no_slice) { slice_type operator_type; tok = ParseStructuredStip_operator(tok,&operator_type); if (tok!=0 && operator_type!=no_slice_type) { if (*type==expression_type_defense) tok = 0; else { slice_index const operand2 = alloc_proxy_slice(); expression_type type2; tok = ParseStructuredStip_expression(tok,start,operand2,&type2,level); if (tok!=0 && SLICE_NEXT1(operand2)!=no_slice) { if (*type==type2) switch (operator_type) { case STAnd: { slice_index const and = alloc_and_slice(operand1,operand2); pipe_link(proxy,and); break; } case STOr: { slice_index const or = alloc_or_slice(operand1,operand2); pipe_link(proxy,or); break; } default: assert(0); break; } else tok = 0; } } } else { if (SLICE_PREV(SLICE_NEXT1(operand1))==operand1) pipe_link(proxy,SLICE_NEXT1(operand1)); else pipe_set_successor(proxy,SLICE_NEXT1(operand1)); dealloc_slice(operand1); } } } TraceFunctionExit(__func__); TraceFunctionResult("%s",tok); TraceFunctionResultEnd(); return tok; }
static char *ParsePlay(char *tok, slice_index start, slice_index proxy, play_length_type play_length) { /* seriesmovers with introductory moves */ char *result = 0; char *arrowpos; slice_index const proxy_next = alloc_proxy_slice(); TraceFunctionEntry(__func__); TraceFunctionParam("%s",tok); TraceFunctionParam("%u",start); TraceFunctionParam("%u",proxy); TraceFunctionParamListEnd(); if (token_starts_with("exact-",tok)) { play_length = play_length_exact; tok += 6; } arrowpos = strstr(tok,"->"); if (arrowpos!=0) { char *end; unsigned long const intro_len= strtoul(tok,&end,10); if (intro_len<1 || tok==end || end!=arrowpos) output_plaintext_input_error_message(WrongInt, 0); else { result = ParsePlay(arrowpos+2,start,proxy_next,play_length); if (result!=0 && SLICE_NEXT1(proxy_next)!=no_slice) { /* >=1 move of starting side required */ slice_index const branch = alloc_series_branch(2*intro_len-1,1); help_branch_set_end(branch,proxy_next,1); link_to_branch(proxy,branch); select_output_mode(proxy,output_mode_line); } } } else if (token_starts_with("ser-reci-h",tok)) { /* skip over "ser-reci-h" */ tok = ParseReciEnd(tok+10,start,proxy_next); if (tok!=0 && SLICE_NEXT1(proxy_next)!=no_slice) { stip_length_type length; stip_length_type min_length; result = ParseSeriesLength(tok,&length,&min_length,play_length); if (result!=0) { slice_index const branch = alloc_series_branch(length-1,min_length+1); help_branch_set_end(branch,proxy_next,1); link_to_branch(proxy,branch); solving_impose_starter(proxy_next,Black); select_output_mode(proxy,output_mode_line); } } } else if (token_starts_with("ser-hs",tok)) { tok = ParseGoal(tok+6,start,proxy_next); /* skip over "ser-hs" */ if (tok!=0) { stip_length_type length; stip_length_type min_length; result = ParseSeriesLength(tok,&length,&min_length,play_length); if (result!=0) { slice_index const defense_branch = MakeEndOfSelfPlay(proxy_next); /* in ser-hs, the series is 1 half-move longer than in usual * series play! */ if (length==0) pipe_link(proxy,defense_branch); else { slice_index const series = alloc_series_branch(length,min_length); slice_index const help_proxy = alloc_proxy_slice(); slice_index const help = alloc_help_branch(1,1); link_to_branch(help_proxy,help); help_branch_set_end_forced(help_proxy,defense_branch,1); help_branch_set_end(series,help_proxy,1); link_to_branch(proxy,series); } solving_impose_starter(proxy_next,White); select_output_mode(proxy,output_mode_line); } } } else if (token_starts_with("ser-h",tok)) { result = ParseSeries(tok+5,start,proxy,proxy_next,play_length); /* skip over "ser-h" */ if (result!=0) { slice_index const help = alloc_help_branch(1,1); help_branch_set_end_goal(help,proxy_next,1); help_branch_set_end(proxy,help,1); { slice_index const next = SLICE_NEXT1(proxy_next); assert(next!=no_slice); if (SLICE_TYPE(next)==STGoalReachedTester && SLICE_U(next).goal_handler.goal.type==goal_proofgame) solving_impose_starter(proxy_next,White); else solving_impose_starter(proxy_next,Black); } } } else if (token_starts_with("ser-s",tok)) { result = ParseSeries(tok+5,start,proxy,proxy_next,play_length); /* skip over "ser-s" */ if (result!=0) { help_branch_set_end_forced(proxy,MakeEndOfSelfPlay(proxy_next),1); solving_impose_starter(proxy_next,White); } } else if (token_starts_with("ser-r",tok)) { result = ParseSeries(tok+5,start,proxy,proxy_next,play_length); /* skip over "ser-r" */ if (result!=0) { slice_index const proxy_semi = MakeSemireflexBranch(proxy_next); help_branch_set_end_forced(proxy,proxy_semi,1); series_branch_insert_constraint(proxy,MakeReflexBranch(proxy_semi)); solving_impose_starter(proxy_next,White); } } else if (token_starts_with("ser-",tok)) { result = ParseSeries(tok+4,start,proxy,proxy_next,play_length); /* skip over "ser-" */ if (result!=0) { help_branch_set_end_goal(proxy,proxy_next,1); solving_impose_starter(proxy_next,Black); } } else if (token_starts_with("phser-r",tok)) { boolean const shorten = true; result = ParseHelp(tok+7, /* skip over phser-r */ start, proxy,proxy_next, play_length,shorten); if (result!=0) { slice_index const proxy_semi = MakeSemireflexBranch(proxy_next); help_branch_set_end_forced(proxy,proxy_semi,1); if (help_branch_insert_constraint(proxy,MakeReflexBranch(proxy_semi),0)) { help_branch_insert_check_zigzag(proxy); solving_impose_starter(proxy_next,White); } else result = 0; } } else if (token_starts_with("phser-s",tok)) { boolean const shorten = true; result = ParseHelp(tok+7, /* skip over phser-s */ start, proxy,proxy_next, play_length,shorten); if (result!=0) { help_branch_set_end_forced(proxy,MakeEndOfSelfPlay(proxy_next),1); help_branch_insert_check_zigzag(proxy); solving_impose_starter(proxy_next,White); } } else if (token_starts_with("phser-",tok)) { boolean const shorten = true; result = ParseHelp(tok+6, /* skip over phser- */ start, proxy,proxy_next, play_length,shorten); if (result!=0) { help_branch_set_end_goal(proxy,proxy_next,1); help_branch_insert_check_zigzag(proxy); solving_impose_starter(proxy_next,Black); } } else if (token_starts_with("pser-hs",tok)) { tok = ParseGoal(tok+7,start,proxy_next); /* skip over "ser-hs" */ if (tok!=0) { stip_length_type length; stip_length_type min_length; result = ParseSeriesLength(tok,&length,&min_length,play_length); if (result!=0) { slice_index const series = alloc_help_branch(length,min_length); slice_index const help_proxy = alloc_proxy_slice(); slice_index const help = alloc_help_branch(1,1); slice_index const defense_branch = MakeEndOfSelfPlay(proxy_next); link_to_branch(help_proxy,help); help_branch_set_end_forced(help_proxy,defense_branch,1); help_branch_set_end(series,help_proxy,1); link_to_branch(proxy,series); help_branch_insert_check_zigzag(proxy); solving_impose_starter(proxy_next,White); select_output_mode(proxy,output_mode_line); } } } else if (token_starts_with("pser-h",tok)) { boolean const shorten = true; result = ParseHelp(tok+6, /* skip over pser-h */ start, proxy,proxy_next, play_length,shorten); if (result!=0) { slice_index const to_goal = SLICE_NEXT1(proxy_next); slice_index const nested = alloc_help_branch(1,1); help_branch_set_end_goal(nested,proxy_next,1); help_branch_set_end(proxy,nested,1); help_branch_insert_check_zigzag(proxy); if (SLICE_TYPE(to_goal)==STGoalReachedTester && SLICE_U(to_goal).goal_handler.goal.type==goal_proofgame) solving_impose_starter(proxy_next,White); else solving_impose_starter(proxy_next,Black); } } else if (token_starts_with("pser-r",tok)) { boolean const ends_on_defense = false; result = ParseBattle(tok+6, /* skip over pser-r */ start, proxy,proxy_next, play_length,ends_on_defense); if (result!=0) { slice_index const proxy_semi = MakeSemireflexBranch(proxy_next); battle_branch_insert_end_of_branch_forced(proxy,proxy_semi); battle_branch_insert_attack_constraint(proxy,MakeReflexBranch(proxy_semi)); battle_branch_insert_defense_check_zigzag(proxy); select_output_mode(proxy,output_mode_line); solving_impose_starter(proxy_next,White); } } else if (token_starts_with("pser-s",tok)) { boolean const ends_on_defense = false; result = ParseBattle(tok+6, /* skip over pser-s */ start, proxy,proxy_next, play_length,ends_on_defense); if (result!=0) { battle_branch_insert_direct_end_of_branch(proxy, MakeEndOfSelfPlay(proxy_next)); solving_impose_starter(proxy_next,Black); select_output_mode(proxy,output_mode_line); battle_branch_insert_defense_check_zigzag(proxy); } } else if (token_starts_with("pser-",tok)) { boolean const ends_on_defense = false; result = ParseBattle(tok+5, /* skip over pser- */ start, proxy,proxy_next, play_length,ends_on_defense); if (result!=0) { select_output_mode(proxy,output_mode_line); battle_branch_insert_direct_end_of_branch_goal(proxy,proxy_next); battle_branch_insert_defense_check_zigzag(proxy); } } else if (token_starts_with("reci-h",tok)) { char * const tok2 = ParseReciEnd(tok+6, /* skip over "reci-h" */ start,proxy_next); if (tok2!=0 && SLICE_NEXT1(proxy_next)!=no_slice) { stip_length_type length; stip_length_type min_length; result = ParseHelpLength(tok2,&length,&min_length,play_length); if (length==1) { /* at least 2 half moves requried for a reciprocal stipulation */ output_plaintext_input_error_message(StipNotSupported,0); result = 0; } if (result!=0) { if (length==2) { pipe_link(proxy,SLICE_NEXT1(proxy_next)); dealloc_slice(proxy_next); } else { stip_length_type const min_length2 = (min_length<2 ? min_length : min_length-2); slice_index const branch = alloc_help_branch(length-2,min_length2); help_branch_set_end(branch,proxy_next,1); attach_help_branch(length,proxy,branch); } solving_impose_starter(proxy_next,Black); select_output_mode(proxy,output_mode_line); } } } else if (token_starts_with("dia",tok)) { result = ParseHelpDia(tok,start,proxy,proxy_next,play_length); if (result!=0) solving_impose_starter(proxy,White); } else if (token_starts_with("a=>b",tok)) { result = ParseHelpDia(tok,start,proxy,proxy_next,play_length); if (result!=0) solving_impose_starter(proxy,Black); } else if (token_starts_with("hs",tok)) { boolean const shorten = true; result = ParseHelp(tok+2, /* skip over "hs" */ start, proxy,proxy_next, play_length,shorten); if (result!=0) { help_branch_set_end_forced(proxy,MakeEndOfSelfPlay(proxy_next),1); solving_impose_starter(proxy_next,White); } } else if (token_starts_with("hr",tok)) { boolean const shorten = true; result = ParseHelp(tok+2, /* skip over "hr" */ start, proxy,proxy_next, play_length,shorten); if (result!=0) { slice_index const proxy_semi = MakeSemireflexBranch(proxy_next); help_branch_set_end_forced(proxy,proxy_semi,1); if (help_branch_insert_constraint(proxy,MakeReflexBranch(proxy_semi),0)) solving_impose_starter(proxy_next,White); else result = 0; } } else if (token_starts_with("h",tok)) { boolean const shorten = false; result = ParseHelp(tok+1, /* skip over "h" */ start, proxy,proxy_next, play_length,shorten); if (result!=0) { help_branch_set_end_goal(proxy,proxy_next,1); solving_impose_starter(proxy_next,Black); } } else if (token_starts_with("semi-r",tok)) { boolean const ends_on_defense = false; result = ParseBattle(tok+6, /* skip over "semi-r" */ start, proxy,proxy_next, play_length,ends_on_defense); if (result!=0) { battle_branch_insert_end_of_branch_forced(proxy, MakeSemireflexBranch(proxy_next)); select_output_mode(proxy,output_mode_tree); solving_impose_starter(proxy_next,White); } } else if (token_starts_with("s",tok)) { boolean const ends_on_defense = true; result = ParseBattle(tok+1, /* skip over 's' */ start, proxy,proxy_next, play_length,ends_on_defense); if (result!=0) { select_output_mode(proxy,output_mode_tree); battle_branch_insert_self_end_of_branch_goal(proxy,proxy_next); } } else if (token_starts_with("r",tok)) { boolean const ends_on_defense = false; result = ParseBattle(tok+1, /* skip over 'r' */ start, proxy,proxy_next, play_length,ends_on_defense); if (result!=0) { slice_index const proxy_semi = MakeSemireflexBranch(proxy_next); battle_branch_insert_end_of_branch_forced(proxy,proxy_semi); battle_branch_insert_attack_constraint(proxy,MakeReflexBranch(proxy_semi)); select_output_mode(proxy,output_mode_tree); solving_impose_starter(proxy_next,White); } } else { boolean const ends_on_defense = false; result = ParseBattle(tok,start,proxy,proxy_next,play_length,ends_on_defense); if (result!=0) { select_output_mode(proxy,output_mode_tree); battle_branch_insert_direct_end_of_branch_goal(proxy,proxy_next); } } if (result==0) dealloc_slices(proxy_next); TraceFunctionExit(__func__); TraceFunctionResult("%s",result); TraceFunctionResultEnd(); return result; }
static void spin_off_measuring_branch(slice_index si, stip_structure_traversal *st) { instrumentation_state_type const * const state = st->param; stip_deep_copies_type copies; stip_structure_traversal st_nested; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); if (SLICE_NEXT2(si)==no_slice) { SLICE_NEXT2(si) = alloc_proxy_slice(); init_deep_copy(&st_nested,st,&copies); stip_structure_traversal_override_single(&st_nested, STMummerDeadend, &stop_copying); stip_structure_traversal_override_single(&st_nested, STRestartGuard, &skip_copying); stip_structure_traversal_override_single(&st_nested, STDeadEndGoal, &skip_copying); stip_structure_traversal_override_single(&st_nested, STGoalReachableGuardFilterMate, &skip_copying); stip_structure_traversal_override_single(&st_nested, STGoalReachableGuardFilterStalemate, &skip_copying); stip_structure_traversal_override_single(&st_nested, STGoalReachableGuardFilterProof, &skip_copying); stip_structure_traversal_override_single(&st_nested, STGoalReachableGuardFilterProofFairy, &skip_copying); stip_structure_traversal_override_by_function(&st_nested, slice_function_move_removing_optimiser, &skip_copying); if (mummer_strictness[state->current_side]!=mummer_strictness_regular) { stip_structure_traversal_override_single(&st_nested, STEndOfBranchGoal, &skip_copying); stip_structure_traversal_override_single(&st_nested, STSelfCheckGuard, &skip_copying); } else { regular_deep_copy_end_of_branch_goal = st_nested.map.visitors[STEndOfBranchGoal]; stip_structure_traversal_override_single(&st_nested, STEndOfBranchGoal, ©_end_of_branch_goal_if_necessary); stip_structure_traversal_override_single(&st_nested, STEndOfBranchGoalImmobile, ©_end_of_branch_goal_if_necessary); } stip_traverse_structure(SLICE_NEXT1(si),&st_nested); link_to_branch(SLICE_NEXT2(si),copies[SLICE_NEXT1(si)]); { slice_index const prototype = alloc_pipe(STMummerBookkeeper); switch (st->context) { case stip_traversal_context_attack: attack_branch_insert_slices_behind_proxy(SLICE_NEXT2(si),&prototype,1,si); break; case stip_traversal_context_defense: defense_branch_insert_slices_behind_proxy(SLICE_NEXT2(si),&prototype,1,si); break; case stip_traversal_context_help: help_branch_insert_slices_behind_proxy(SLICE_NEXT2(si),&prototype,1,si); break; default: assert(0); break; } } if (mummer_strictness[state->current_side]!=mummer_strictness_regular) { slice_index const prototype = alloc_pipe(STUltraMummerMeasurerDeadend); slice_insertion_insert_contextually(copies[SLICE_NEXT1(si)],st->context,&prototype,1); } } stip_traverse_structure_children(si,st); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }