static void insert_maxthreatlength_guard(slice_index si, stip_structure_traversal *st) { stip_length_type const length = SLICE_U(si).branch.length; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); stip_traverse_structure_children_pipe(si,st); if (length>=2*max_len_threat+slack_length) { boolean * const inserted = st->param; slice_index const threat_start = branch_find_slice(STMaxThreatLengthStart, si, st->context); slice_index const proxy = alloc_proxy_slice(); slice_index const dummy = alloc_pipe(STDummyMove); slice_index const played = alloc_defense_played_slice(); slice_index const prototype = alloc_maxthreatlength_guard(proxy); assert(threat_start!=no_slice); pipe_link(proxy,dummy); pipe_link(dummy,played); link_to_branch(played,threat_start); defense_branch_insert_slices(si,&prototype,1); *inserted = true; } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
static void insert_separator(slice_index si, stip_structure_traversal *st) { TraceFunctionEntry(__func__); TraceValue("%u",si); TraceFunctionParamListEnd(); stip_traverse_structure_children(si,st); { slice_index const proxy_standard = alloc_proxy_slice(); slice_index const standard = alloc_pipe(STMoveForPieceGeneratorStandardPath); slice_index const proxy_alternative = alloc_proxy_slice(); slice_index const alternative = alloc_pipe(STMoveForPieceGeneratorAlternativePath); slice_index const generator = alloc_binary_slice(STMoveForPieceGeneratorTwoPaths, proxy_standard, proxy_alternative); pipe_link(SLICE_PREV(si),generator); pipe_link(proxy_standard,standard); pipe_link(standard,si); pipe_link(proxy_alternative,alternative); pipe_link(alternative,si); } 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 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(); }
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 slice_index make_observation_geometry_validator(Side side) { slice_index const proxy = alloc_proxy_slice(); slice_index const result = alloc_conditional_pipe(STValidatingObservationGeometryFork,proxy); slice_index const enforce_walk = alloc_pipe(STEnforceObserverWalk); slice_index const testing = alloc_pipe(STValidatingObservationGeometry); pipe_link(proxy,testing); pipe_link(testing,enforce_walk); pipe_link(enforce_walk,alloc_true_slice()); solving_impose_starter(result,side); return result; }
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 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(); }
/* Instrument a series branch with STEndOfBranchForced slices (typically for a * hr stipulation) * @param si entry slice of branch to be instrumented * @param forced identifies branch forced on the defender * @param parity indicates after which help move of the branch to insert */ void help_branch_set_end_forced(slice_index si, slice_index forced, unsigned int parity) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParam("%u",forced); TraceFunctionParam("%u",parity); TraceFunctionParamListEnd(); TraceStipulation(si); TraceStipulation(forced); { slice_index const proxy = alloc_proxy_slice(); slice_index const fork = alloc_fork_slice(STEndOfBranchForced,proxy); #if !defined(NDEBUG) boolean const inserted = #endif help_branch_insert_end_of_branch(si,fork,parity); assert(inserted); pipe_link(proxy,forced); } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* 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(); }
static slice_index make_check_validator(Side side) { slice_index const proxy = alloc_proxy_slice(); slice_index const result = alloc_conditional_pipe(STValidatingCheckFork,proxy); slice_index const check = alloc_pipe(STValidatingCheck); slice_index const enforce_walk = alloc_pipe(STEnforceObserverWalk); slice_index const observer = alloc_pipe(STValidatingObserver); slice_index const geometry = alloc_pipe(STValidatingObservationGeometry); pipe_link(proxy,check); pipe_link(check,enforce_walk); pipe_link(enforce_walk,observer); pipe_link(observer,geometry); pipe_link(geometry,alloc_true_slice()); solving_impose_starter(result,side); return result; }
static void insert_avoid_unsolvable(slice_index si, stip_structure_traversal *st) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); stip_traverse_structure_children(si,st); if (st->context==stip_traversal_context_attack || st->context==stip_traversal_context_defense) { slice_index const proxy1 = alloc_proxy_slice(); slice_index const proxy2 = alloc_proxy_slice(); slice_index const fork = alloc_avoid_unsolvable_slice(proxy1,proxy2); pipe_link(SLICE_PREV(si),fork); pipe_append(si,proxy2); pipe_link(proxy1,si); } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
static slice_index make_move_generator(Side side) { slice_index const proxy = alloc_proxy_slice(); slice_index const result = alloc_conditional_pipe(STMoveGeneratorFork,proxy); slice_index const generating = alloc_pipe(STGeneratingMovesForPiece); slice_index const ortho = alloc_pipe(STMovesForPieceBasedOnWalkGenerator); slice_index const generated = create_slice(STGeneratedMovesForPiece); pipe_append(proxy,generating); pipe_append(generating,ortho); pipe_link(ortho,generated); solving_impose_starter(result,side); return result; }
static slice_index make_check_tester(void) { slice_index const proxy = alloc_proxy_slice(); slice_index const result = alloc_conditional_pipe(STCheckTesterFork,proxy); slice_index const testing = alloc_pipe(STTestingCheck); slice_index const initialiser = alloc_pipe(STKingSquareObservationTesterPlyInitialiser); slice_index const king_square_observation_tester = alloc_pipe(STKingSquareObservationTester); slice_index const tested = create_slice(STTestedCheck); link_to_branch(proxy,testing); pipe_append(testing,initialiser); pipe_append(initialiser,king_square_observation_tester); pipe_link(king_square_observation_tester,tested); solving_impose_starter(result,Black); return result; }
/* Allocate a system of slices that tests whether the side to be immobilised has * been * @return index of entry slice */ slice_index alloc_goal_immobile_reached_tester_system(void) { slice_index result; TraceFunctionEntry(__func__); TraceFunctionParamListEnd(); result = alloc_goal_immobile_reached_tester_slice(goal_applies_to_starter); pipe_link(result,alloc_true_slice()); TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
/* Allocate a system of slices that tests whether mate has been reached * @return index of entry slice */ slice_index alloc_goal_mate_reached_tester_system(void) { slice_index result; TraceFunctionEntry(__func__); TraceFunctionParamListEnd(); { slice_index const mate_tester = alloc_pipe(STGoalMateReachedTester); slice_index const check_tester = alloc_goal_check_reached_tester_slice(goal_applies_to_starter); slice_index const immobile_tester = alloc_goal_immobile_reached_tester_slice(goal_applies_to_starter); pipe_link(mate_tester,check_tester); pipe_link(check_tester,immobile_tester); pipe_link(immobile_tester,alloc_true_slice()); result = mate_tester; } TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
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(); }
/* Allocate a system of slices that tests whether steingewinn has been reached * @return index of entry slice */ slice_index alloc_goal_steingewinn_reached_tester_system(void) { slice_index result; slice_index steingewinn_tester; Goal const goal = { goal_steingewinn, initsquare }; TraceFunctionEntry(__func__); TraceFunctionParamListEnd(); steingewinn_tester = alloc_pipe(STGoalSteingewinnReachedTester); pipe_link(steingewinn_tester,alloc_true_slice()); result = alloc_goal_reached_tester_slice(goal,steingewinn_tester); TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
/* Allocate a system of slices that tests whether check has been reached * @return index of entry slice */ slice_index alloc_goal_check_reached_tester_system(void) { slice_index result; slice_index check_tester; Goal const goal = { goal_check, initsquare }; TraceFunctionEntry(__func__); TraceFunctionParamListEnd(); check_tester = alloc_goal_check_reached_tester_slice(goal_applies_to_starter); pipe_link(check_tester,alloc_true_slice()); result = alloc_goal_reached_tester_slice(goal,check_tester); TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
/* Allocate a system of slices that tests whether first row or last row has been reached * @return index of entry slice */ slice_index alloc_goal_kiss_reached_tester_system(square s) { slice_index result; slice_index kiss_tester; Goal const goal = { goal_kiss, s }; TraceFunctionEntry(__func__); TraceFunctionParamListEnd(); kiss_tester = alloc_pipe(STGoalKissReachedTester); pipe_link(kiss_tester,alloc_true_slice()); result = alloc_goal_reached_tester_slice(goal,kiss_tester); TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
/* Allocate a system of slices that tests whether king capture has been reached * @return index of entry slice */ slice_index alloc_goal_king_capture_reached_tester_system(void) { slice_index result; slice_index any_tester; Goal const goal = { goal_any, initsquare }; TraceFunctionEntry(__func__); TraceFunctionParamListEnd(); any_tester = alloc_pipe(STGoalKingCaptureReachedTester); pipe_link(any_tester,alloc_true_slice()); result = alloc_goal_reached_tester_slice(goal,any_tester); TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
static void attach_help_branch(stip_length_type length, slice_index proxy, slice_index branch) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",length); TraceFunctionParam("%u",proxy); TraceFunctionParam("%u",branch); TraceFunctionParamListEnd(); if (length%2==1) { slice_index const inverter = alloc_move_inverter_slice(); pipe_link(proxy,inverter); link_to_branch(inverter,branch); } else link_to_branch(proxy,branch); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Allocate a system of slices that tests whether a target square has been * reached * @return index of entry slice */ slice_index alloc_goal_target_reached_tester_system(square target) { slice_index result; slice_index target_tester; Goal const goal = { goal_target, target }; TraceFunctionEntry(__func__); TraceSquare(target); TraceFunctionParamListEnd(); target_tester = alloc_pipe(STGoalTargetReachedTester); SLICE_U(target_tester).goal_handler.goal.type = goal_target; SLICE_U(target_tester).goal_handler.goal.target = target; pipe_link(target_tester,alloc_true_slice()); result = alloc_goal_reached_tester_slice(goal,target_tester); TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
/* Allocate a STGoalImmobileReachedTester slice. * @param starter_or_adversary is the starter immobilised or its adversary? * @return index of allocated slice */ slice_index alloc_goal_immobile_reached_tester_slice(goal_applies_to_starter_or_adversary starter_or_adversary) { slice_index result; TraceFunctionEntry(__func__); TraceValue("%u",starter_or_adversary); TraceFunctionParamListEnd(); { slice_index const proxy = alloc_proxy_slice(); slice_index const tester = alloc_pipe(STImmobilityTester); result = alloc_conditional_pipe(STGoalImmobileReachedTester,proxy); pipe_link(proxy,tester); link_to_branch(tester,alloc_defense_branch(1,1)); SLICE_U(result).goal_filter.applies_to_who = starter_or_adversary; } TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
/* 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(); }
static void make_is_square_observed(Side side) { slice_index const proxy = alloc_proxy_slice(); slice_index const testing = alloc_pipe(STTestingIfSquareIsObserved); slice_index const determine_walk = alloc_pipe(STDetermineObserverWalk); slice_index const testing_specific = alloc_pipe(STTestingIfSquareIsObservedWithSpecificWalk); slice_index const optimising = alloc_pipe(STOptimisingObserverWalk); slice_index const track_back = alloc_pipe(STTrackBackFromTargetAccordingToObserverWalk); temporary_hack_is_square_observed[side] = alloc_conditional_pipe(STIsSquareObservedFork,proxy); temporary_hack_is_square_observed_specific[side] = alloc_conditional_pipe(STIsSquareObservedFork,testing_specific); pipe_link(proxy,testing); pipe_link(testing,determine_walk); pipe_link(determine_walk,testing_specific); pipe_link(testing_specific,optimising); pipe_link(optimising,track_back); pipe_link(track_back,alloc_false_slice()); solving_impose_starter(temporary_hack_is_square_observed[side],side); solving_impose_starter(temporary_hack_is_square_observed_specific[side],side); }
/* 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; }
/* Allocate a series branch * @param length maximum number of half-moves of slice (+ slack) * @param min_length minimum number of half-moves of slice (+ slack) * @return index of entry slice into allocated series branch */ slice_index alloc_series_branch(stip_length_type length, stip_length_type min_length) { slice_index result; TraceFunctionEntry(__func__); TraceFunctionParam("%u",length); TraceFunctionParam("%u",min_length); TraceFunctionParamListEnd(); { slice_index const adapter = alloc_help_adapter_slice(length,min_length); slice_index const ready = alloc_branch(STReadyForHelpMove, length,min_length); slice_index const testpre = alloc_pipe(STTestingPrerequisites); slice_index const generating = alloc_pipe(STGeneratingMoves); slice_index const done_generating = alloc_pipe(STDoneGeneratingMoves); slice_index const done_removing_illegal = alloc_pipe(STDoneRemovingIllegalMoves); slice_index const done_removing_futile = alloc_pipe(STDoneRemovingFutileMoves); slice_index const done_priorising = alloc_pipe(STDonePriorisingMoves); slice_index const move = alloc_pipe(STMove); slice_index const played1 = alloc_help_move_played_slice(); slice_index const not_end_goal1 = alloc_pipe(STNotEndOfBranchGoal); slice_index const played2 = alloc_help_move_played_slice(); slice_index const not_end_goal2 = alloc_pipe(STNotEndOfBranchGoal); slice_index const deadend = alloc_pipe(STDeadEnd); result = adapter; pipe_link(adapter,ready); pipe_link(ready,testpre); pipe_link(testpre,generating); pipe_link(generating,done_generating); pipe_link(done_generating,done_removing_illegal); pipe_link(done_removing_illegal,done_removing_futile); pipe_link(done_removing_futile,done_priorising); pipe_link(done_priorising,move); pipe_link(move,played1); pipe_link(played1,not_end_goal1); pipe_link(not_end_goal1,played2); pipe_link(played2,not_end_goal2); pipe_link(not_end_goal2,adapter); if (length%2==0) /* branch ends after the pseudo move */ pipe_append(not_end_goal2,deadend); else /* branch ends after the real move */ pipe_append(not_end_goal1,deadend); } TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
/* Allocate a help branch. * @param length maximum number of half-moves of slice (+ slack) * @param min_length minimum number of half-moves of slice (+ slack) * @param proxy_to_next identifies slice leading towards goal * @return index of entry slice into allocated series branch */ slice_index alloc_help_branch(stip_length_type length, stip_length_type min_length) { slice_index result; TraceFunctionEntry(__func__); TraceFunctionParam("%u",length); TraceFunctionParam("%u",min_length); TraceFunctionParamListEnd(); { slice_index const adapter = alloc_help_adapter_slice(length,min_length); slice_index const ready1 = alloc_branch(STReadyForHelpMove, length,min_length); slice_index const testpre1 = alloc_pipe(STTestingPrerequisites); slice_index const generating1 = alloc_pipe(STGeneratingMoves); slice_index const done_generating1 = alloc_pipe(STDoneGeneratingMoves); slice_index const done_removing_illegal1 = alloc_pipe(STDoneRemovingIllegalMoves); slice_index const done_removing_futile1 = alloc_pipe(STDoneRemovingFutileMoves); slice_index const done_priorising1 = alloc_pipe(STDonePriorisingMoves); slice_index const move1 = alloc_pipe(STMove); slice_index const played1 = alloc_help_move_played_slice(); slice_index const not_end_goal1 = alloc_pipe(STNotEndOfBranchGoal); slice_index const ready2 = alloc_branch(STReadyForHelpMove, length-1,min_length-1); slice_index const testpre2 = alloc_pipe(STTestingPrerequisites); slice_index const generating2 = alloc_pipe(STGeneratingMoves); slice_index const done_generating2 = alloc_pipe(STDoneGeneratingMoves); slice_index const done_removing_illegal2 = alloc_pipe(STDoneRemovingIllegalMoves); slice_index const done_removing_futile2 = alloc_pipe(STDoneRemovingFutileMoves); slice_index const done_priorising2 = alloc_pipe(STDonePriorisingMoves); slice_index const move2 = alloc_pipe(STMove); slice_index const played2 = alloc_help_move_played_slice(); slice_index const not_end_goal2 = alloc_pipe(STNotEndOfBranchGoal); slice_index const deadend = alloc_pipe(STDeadEnd); pipe_link(adapter,ready1); pipe_link(ready1,testpre1); pipe_link(testpre1,generating1); pipe_link(generating1,done_generating1); pipe_link(done_generating1,done_removing_illegal1); pipe_link(done_removing_illegal1,done_removing_futile1); pipe_link(done_removing_futile1,done_priorising1); pipe_link(done_priorising1,move1); pipe_link(move1,played1); pipe_link(played1,not_end_goal1); pipe_link(not_end_goal1,ready2); pipe_link(ready2,testpre2); pipe_link(testpre2,generating2); pipe_link(generating2,done_generating2); pipe_link(done_generating2,done_removing_illegal2); pipe_link(done_removing_illegal2,done_removing_futile2); pipe_link(done_removing_futile2,done_priorising2); pipe_link(done_priorising2,move2); pipe_link(move2,played2); pipe_link(played2,not_end_goal2); pipe_link(not_end_goal2,adapter); if (length%2==0) help_branch_insert_slices(adapter,&deadend,1); else help_branch_insert_slices(move1,&deadend,1); result = adapter; } TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
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; }