Example #1
0
        /// <summary>
        /// Creates a touch of a single method, and a list of calls in the order they should be called.
        /// </summary>
        /// <param name="method">The method of the touch.</param>
        /// <param name="calls">The calls in the order they should be called.</param>
        public Touch(Method method, Call [] calls)
        {
            BasicCall [] basic_calls = new BasicCall [calls.Length];

            for (int i = 0; i < calls.Length; i++)
            {
                basic_calls [i] = new BasicCall(calls [i], new Touch.CallLocationList());
            }

            this.basic_calls = basic_calls;
            start_method     = method;
        }
Example #2
0
        // Functions
        /// <summary>
        /// Generates all the changes in the touch (could be computationally intensive).  Called once when <see cref="TouchBase.changes"/> is accessed.
        /// </summary>
        public override Change[] ComputeChanges()
        {
            List <Change> changes = new List <Change> ();

            int method_call_length = method_calls == null ? 1 : method_calls.Length;
            int basic_call_length  = basic_calls == null ? 1 : basic_calls.Length;

            int max_lead_length = method_calls == null ?
                                  start_method.lead_length :
                                  Math.Max(start_method.lead_length, method_calls.Select(x => x.method.lead_length).Max());

            List <Change> [] change_states = new List <Change> [method_call_length * basic_call_length * max_lead_length];

            for (int i = 0; i < change_states.Length; i++)
            {
                change_states [i] = new List <Change> ();
            }

            margin_calls           = new Dictionary <int, char> ();
            right_hand_calls       = new Dictionary <int, string> ();
            lead_head_line_indices = new List <int> ();

            right_hand_calls.Add(-1, "Go " + start_method.title);

            int lead_index        = 0;
            int sub_lead_index    = 0;
            int call_index        = 0;
            int method_call_index = 0;

            int sub_splice_change_index = 0;
            int sub_splice_lead_index   = 0;

            int attempted_calls_since_last_call     = 0;
            int attempted_splices_since_last_splice = 0;

            int absolute_change_index = 0;

            CallPoint current_callpoint = null;

            Change current_change = Change.Rounds(stage);
            Method current_method = start_method;

            while (true)
            {
                #region Update calls
                if (current_callpoint == null)
                {
                    // Not in a call => Could be starting a call
                    if (basic_calls != null && basic_calls.Length > 0)
                    {
                        BasicCall basic_call = basic_calls [call_index];
                        Call      call       = basic_call.call;

                        if ((sub_lead_index - call.from + 1) % call.every == 0)
                        {
                            CallLocationParameters call_location_parameters = new CallLocationParameters(current_method, current_change, absolute_change_index, sub_lead_index, lead_index, attempted_calls_since_last_call, attempted_splices_since_last_splice, this);

                            if (basic_call.call_location.EvaluateBasicCall(call, call_location_parameters))
                            {
                                current_callpoint = new CallPoint(call, absolute_change_index);

                                attempted_calls_since_last_call = 0;

                                if (!call.is_plain)
                                {
                                    margin_calls.Add(absolute_change_index, call.preferred_notation);
                                }
                            }
                            else
                            {
                                attempted_calls_since_last_call += 1;
                            }
                        }
                    }
                }
                else
                {
                    // In a call, so could be stopping a call
                    if (absolute_change_index > current_callpoint.end_index)
                    {
                        sub_lead_index += current_callpoint.call.cover;

                        if (sub_lead_index >= current_method.place_notations.Length)
                        {
                            lead_head_line_indices.Add(absolute_change_index - 1);

                            sub_lead_index = 0;
                            lead_index    += 1;
                        }

                        call_index += 1;
                        if (call_index >= basic_calls.Length)
                        {
                            call_index = 0;
                        }

                        current_callpoint = null;
                    }
                }
                #endregion

                #region Update change (transposition)
                PlaceNotation notation;
                if (current_callpoint == null)
                {
                    notation = current_method.place_notations [sub_lead_index];
                }
                else
                {
                    notation = current_callpoint.GetNotationAtIndex(absolute_change_index);

                    if (notation == null)
                    {
                        notation = current_method.place_notations [sub_lead_index + absolute_change_index - current_callpoint.start_index];
                    }
                }

                current_change = current_change.Transpose(notation);

                // Add change to list
                changes.Add(current_change);
                #endregion

                #region Update method splicing calls
                if (method_calls != null && method_calls.Length > 0)
                {
                    MethodCall current_method_call = method_calls [method_call_index];

                    if (sub_lead_index == current_method.lead_length + current_method_call.splice_start_index - 1)
                    {
                        CallLocationParameters parameters = new CallLocationParameters(current_method, current_change, absolute_change_index, sub_lead_index, lead_index, attempted_calls_since_last_call, attempted_splices_since_last_splice, this);

                        if (current_method_call.location.EvaluateMethodCall(current_method_call, parameters))
                        {
                            current_method = current_method_call.method;

                            method_call_index += 1;

                            sub_lead_index = current_method_call.splice_end_index - 1;                             // Set to splice_end_index - 1, because later in this iteration of the while loop, 1 will be added to it, to get splice_end_index.

                            // Make sure that lead ends get counted even if there was a splice over the lead end.
                            if (current_method_call.splice_end_index == 0)
                            {
                                sub_lead_index = current_method.lead_length - 1;
                            }

                            sub_splice_change_index = 0;
                            sub_splice_lead_index   = 0;

                            attempted_splices_since_last_splice = 0;

                            right_hand_calls.Add(absolute_change_index, current_method.title);

                            if (method_call_index >= method_calls.Length)
                            {
                                method_call_index = 0;
                            }
                        }
                        else
                        {
                            attempted_splices_since_last_splice += 1;
                        }
                    }
                }
                #endregion

                #region Stop if it comes to rounds (to whatever is the target change is)
                if (current_change == target_change)
                {
                    // Add a final lead end.
                    int lead_index_to_check = sub_lead_index + 1;
                    if (current_callpoint != null && absolute_change_index == current_callpoint.end_index)
                    {
                        lead_index_to_check = sub_lead_index + current_callpoint.call.cover;
                    }

                    // Quickly check whether or not this is valid
                    bool is_valid = true;
                    if (rounds_checks == RoundsCheckLocations.AnyBackstroke && Utils.Mod(changes.Count, 2) == 1)
                    {
                        is_valid = false;
                    }
                    if (rounds_checks == RoundsCheckLocations.OnlyLeadEnds && lead_index_to_check != current_method.lead_length)
                    {
                        is_valid = false;
                    }

                    if (is_valid)
                    {
                        if (lead_index_to_check == current_method.lead_length)
                        {
                            lead_head_line_indices.Add(absolute_change_index);
                        }

                        comes_round = true;

                        break;
                    }
                }
                #endregion

                #region Update indices & lead ends.
                if (current_callpoint == null)
                {
                    sub_lead_index += 1;

                    if (sub_lead_index >= current_method.place_notations.Length)
                    {
                        lead_head_line_indices.Add(absolute_change_index);

                        sub_lead_index         = 0;
                        sub_splice_lead_index += 1;

                        lead_index += 1;
                    }
                }

                absolute_change_index   += 1;
                sub_splice_change_index += 1;
                #endregion

                #region Stop if touch goes on forever.  If 100,000,000 changes are reached, then the code will stop.
                List <Change> change_state_list = change_states [call_index + basic_call_length * (method_call_index + method_call_length * sub_lead_index)];

                if (change_state_list.Contains(current_change))
                {
                    comes_round = false;

                    break;
                }

                change_state_list.Add(current_change);

                // It should never get this far
                if (absolute_change_index > 1e4)
                {
                    throw new YourPealRingersDiedOfExhaustionException("Broke the laws of human endurance and got to 100,000,000 changes without coming round.");
                }
                #endregion
            }

            return(changes.ToArray());
        }