public void ANDIntoThis(LogicANFEquation other)
        {
            var thisTerms = terms.Keys.ToArray();
            this.terms.Clear();

            foreach (LogicANDTerm tTerm in thisTerms)
            {
                foreach (LogicANDTerm oTerm in other.terms.Keys)
                {
                    AddTerm(tTerm.Union(oTerm));
                }
            }
        }
        public void SubIntoPlainOr(LogicANFEquation subEq)
        {
            int subVarID = subEq.SubVarID;
            if (!subEq.IsFullyReduced || subVarID == 0)
            {
                throw new ArgumentException("subEq is not prepared to be substituted in.", "subEq");
            }
            if (!subEq.IsFullyReduced)
            {
                throw new ArgumentException("The equation you are trying to substitute into plainOrEq must be fully reduced.", "subEq");
            }
            bool subVarState = subEq.GetReducedState();
            LogicANDTerm subAnd;
            subVarID *= -1;
            if (subVarState)  // we have to reverse the state because we will be inversing the state of subVarID;
            {
                subAnd = LogicANDTerm.ConstantZero;
            }
            else
            {
                subAnd = LogicANDTerm.ConstantOne;
            }

            var array = plainOrEq.ToArray();
            plainOrEq.Clear();
            for (int i = 0; i < array.Length; i++)
            {
                var add = array[i].Key.SubstituteIn(subAnd, subVarID);
                if (add.IsConstantOne)
                {
                    throw new Exception("Danger Danger!  Logic error by programmer!");
                }
                if (!plainOrEq.Remove(add))
                {
                    plainOrEq.Add(add, null);
                }
            }
        }
        public string Solve()
        {
            LogicANFEquation[] subEqs = new LogicANFEquation[DataSize * 2];
            if (!encryptedData.GetBitState(0))
            {
                throw new Exception("I'm screwed.");
            }
            else
            {
                var isolated = encEqs[0].GetSingleTermVarIDs();
                int first = isolated.First();
                int last = isolated.Last();
                LogicANFEquation newEq1 = new LogicANFEquation();
                LogicANFEquation newEq2 = new LogicANFEquation();
                newEq1.AddTerm(new LogicANDTerm(new int[] { first }));
                newEq2.AddTerm(new LogicANDTerm(new int[] { last }));
                newEq1 = subEqs[first.VarIDToIndex()] = newEq1.CreateSubEq(first, true);
                newEq2 = subEqs[last.VarIDToIndex()] = newEq2.CreateSubEq(last, true);

                for (int i = 0; i < DataSize * 2 - 1; i++)
                {
                    encEqs[i].SubInEq(newEq1);
                    encEqs[i].SubInEq(newEq2);
                }

                for (int i = 1; i < DataSize; i++)
                {
                    LogicANFEquation newSub = encEqs[i].CreateSubEq(encryptedData.GetBitState(i));
                    for (int j = 0; j < DataSize; j++)
                    {
                        if (j > i)
                        {
                            encEqs[j].SubInEq(newSub);
                        }
                        if (subEqs[j] != null)
                        {
                            subEqs[j].SubInEq(newSub);
                        }
                    }
                    for (int j = DataSize; j < DataSize * 2; j++)
                    {
                        if (subEqs[j] != null)
                        {
                            subEqs[j].SubInEq(newSub);
                        }
                    }
                    subEqs[newSub.SubVarID.VarIDToIndex()] = newSub;
                }
            }

            for (int i = 0; i < DataSize * 2; i++)
            {
                if (subEqs[i] != null && subEqs[i].IsFullyReduced)
                {
                    SubIntoPlainOr(subEqs[i]);
                    for (int j = 0; j < DataSize * 2 - 1; j++)
                    {
                        if (!encEqs[j].IsFullyReduced)
                        encEqs[j].SubInEq(subEqs[i]);
                    }
                }
            }

            //encEqs[62].SubInEq(subEqs[63]);
            //encEqs[62].CreateSubEq(false);

            {
                //int i = DataSize;
                //while (subEqs[i] == null || subEqs[i].IsFullyReduced)
                //{
                //    i++;
                //}
                //while (i < DataSize * 2 && subEqs[i] != null && !subEqs[i].IsFullyReduced)
                //{
                //    for (int j = 0; j < DataSize * 2 - 1; j++)
                //    {
                //        encEqs[j].SubInEq(subEqs[i]);
                //        //LogicANFEquation test = null;
                //        //try
                //        //{
                //        //    test = encEqs[j].CreateSubEq(encryptedData.GetBitState(j));
                //        //}
                //        //catch { }

                //        //if (j == 60)
                //        //{
                //        //    //throw new Exception("tell me");
                //        //}
                //    }
                //    i++;
                //}
            }

            StringBuilder sb = new StringBuilder();
            sb.AppendLine("SubInEq's by index:");
            for (int i = 0; i < DataSize * 2; i++)
            {
                sb.Append(i);
                sb.Append(":  ");
                if (subEqs[i] == null)
                {
                    sb.Append("No Equation");
                }
                else
                {
                    subEqs[i].ToStringBuilder(sb);
                }
                sb.AppendLine();
            }
            sb.AppendLine();
            sb.AppendLine();

            sb.AppendLine("EncEq's by index:");
            for (int i = 0; i < DataSize * 2; i++)
            {
                sb.Append(i);
                sb.Append(":  ");
                if (encEqs[i] == null)
                {
                    sb.Append("No Equation");
                }
                else
                {
                    encEqs[i].ToStringBuilder(sb);
                }
                sb.AppendLine();
            }

            sb.AppendLine();
            sb.AppendLine();

            sb.AppendLine("plainOrEq:");
            foreach (var pair in plainOrEq)
            {
                pair.Key.ToStringBuilder(sb);
                sb.AppendLine(" | ");
            }

            return sb.ToString();
        }
        public void Initialize()
        {
            // this next set of 4 repeat loops (nested included) is just a faster way of creating a map of the
            // operations done to each bit to end up with the encripted bit located at the same index as the index
            // of xorEq[index].  Faster compared to mapping and getting rid of duplicate procedures of the algorithm
            // that was provided to us by Nintendo/Alpha Centari.
            // The variable IDs are equal to the unencrypted bit index + 1.  This makes it easy to indicate inverse states by
            // just making the ID negative.
            for (int ebitIndex = 0; ebitIndex < DataSize; ebitIndex++)
            {
                var tmpEq = new LogicANFEquation();
                encEqs[ebitIndex] = tmpEq;
                for (int termIndex = 0; termIndex <= ebitIndex; termIndex++)
                {
                    int[] tmp = new int[2] { termIndex + 1, DataSize + ebitIndex - termIndex + 1 };
                    tmpEq.AddTerm(new LogicANDTerm(tmp));
                }
            }
            for (int ebitIndex = DataSize * 2 - 2; ebitIndex >= DataSize; ebitIndex--)
            {
                var tmpEq = new LogicANFEquation();
                encEqs[ebitIndex] = tmpEq;
                for (int termIndex = 0; termIndex <= DataSize * 2 - ebitIndex - 2; termIndex++)
                {
                    int[] tmp = new int[2] { ebitIndex - DataSize + 2 + termIndex, DataSize * 2 - termIndex };
                    tmpEq.AddTerm(new LogicANDTerm(tmp));
                }
            }

            // Build additional masks based on repeated false values from the first bit or the last bit
            // These masks will be used as additional equations to further cut down the number of options we have to test.
            {
                int lastFalseIdx = DataSize * 2 - 2;
                while (lastFalseIdx >= DataSize && !encryptedData.GetBitState(lastFalseIdx))
                {
                    lastFalseIdx--;
                }
                lastFalseIdx++;

                int numOfTerms = DataSize * 2 - lastFalseIdx;
                int numOfVarPerTerm = numOfTerms - 1;
                int firstStart = DataSize * (-1);
                int secondStart = DataSize * (-2);

                int[] tmpVars = new int[numOfVarPerTerm];

                plainOrEq = new SortedDictionary<LogicANDTerm, object>();
                if (lastFalseIdx < DataSize * 2 - 2)
                {
                    for (int splitPoint = 0; splitPoint < numOfTerms; splitPoint++)
                    {
                        int varIdx = 0;
                        for (; varIdx < splitPoint; varIdx++)
                        {
                            tmpVars[varIdx] = secondStart + varIdx;
                        }
                        for (; varIdx < numOfVarPerTerm; varIdx++)
                        {
                            tmpVars[varIdx] = firstStart - splitPoint + varIdx;
                        }
                        plainOrEq.Add(new LogicANDTerm(tmpVars), null);
                    }
                }

            }
        }
        private void SubInEq(LogicANFEquation other, bool inverse, object diffSig)
        {
            int otherSubVarID;
            if (inverse)
            {
                otherSubVarID = other.SubVarID * -1;
            }
            else
            {
                otherSubVarID = other.SubVarID;
            }
            var subTerms = other.terms.Keys.ToArray();
            var thisTerms = terms.Keys.ToArray();
            terms.Clear();

            if (subTerms.Length == 0)
            {
                subTerms = new LogicANDTerm[] { LogicANDTerm.ConstantZero };
            }

            for (int i = 0; i < thisTerms.Length; i++)
            {
                if (thisTerms[i].ContainsVarID(otherSubVarID))
                {
                    for (int j = 0; j < subTerms.Length; j++)
                    {
                        AddTerm(thisTerms[i].SubstituteIn(subTerms[j], otherSubVarID));
                    }
                    if (inverse)
                    {
                        AddTerm(thisTerms[i].DeepCopy(otherSubVarID));
                    }
                }
                else
                {
                    AddTerm(thisTerms[i]);
                }
            }
        }
        private LogicANFEquation CreateSubEq(List<LogicANDTerm> possibles, bool encryptedBitState)
        {
            bool works = false;
            int newSubVarID = 0;
            int workIdx;
            for (workIdx = possibles.Count - 1; workIdx >= 0; workIdx--)
            {
                newSubVarID = possibles[workIdx].GetSingleVarID();
                works = true;
                foreach (var pair in terms)
                {
                    if (pair.Key != possibles[workIdx] && pair.Key.ContainsVarID(newSubVarID))
                    {
                        works = false;
                        break;
                    }
                }
                if (works)
                {
                    break;
                }
            }

            if (!works)
            {
                throw new Exception("Cannot make a subsitution equation from this equation.");
            }

            LogicANFEquation r = new LogicANFEquation();
            r.SubVarID = newSubVarID;
            foreach (var pair in terms)
            {
                if (pair.Key != possibles[workIdx])
                {
                    r.terms.Add(pair.Key, null);
                }
            }

            if (encryptedBitState)
            {
                r.AddTerm(LogicANDTerm.ConstantOne);
            }
            return r;
        }
 public void SubInEq(LogicANFEquation other, bool includeInverse = false)
 {
     #if DEBUG
     if (other.SubVarID == 0)
         throw new Exception("You are trying to sub in an LogicEquation that is not preped for subbing.");
     #endif
     SubInEq(other, false, (object)null);
     if (includeInverse)
     {
         SubInEq(other, true, (object)null);
     }
 }