Пример #1
0
    //calculates the modular sum of each bool[] in nums which represents a number in binary
    public static bool[] CalcSum(bool[][] nums)
    {
        if (nums.Length == 1)
        {
            return(nums[0]);
        }

        bool[] total = nums[0];
        for (int i = 1; i < nums.Length; i++)
        {
            total = PathCutthroat.ModAdd(total, nums[i]);
        }

        return(total);
    }
Пример #2
0
    //calculates the modular sum of each bool[] in nums except for nums[notIndex]
    public static bool[] CalcSumOthers(bool[][] nums, int notIndex)
    {
        if (nums.Length == 1 && notIndex == 0)
        {
            return(new bool[1]);
        }

        bool[] total = (notIndex != 0) ? nums[0] : nums[1];
        for (int i = ((notIndex != 0) ? 1 : 2); i < nums.Length; i++)
        {
            if (i != notIndex)
            {
                total = PathCutthroat.ModAdd(total, nums[i]);
            }
        }

        return(total);
    }
Пример #3
0
    //calculate a winning move if one exists, otherwise just choose the first vertex of the first piece in pieces
    public static int CalcMove()
    {
        //piles represents the grundy numbers of the sizes of each Path in pieces, in binary
        bool[][] piles = new bool[pieces.Count][];
        for (int i = 0; i < pieces.Count; i++)
        {
            piles[i] = PathCutthroat.ToBinArray(grunds[pieces[i].Size()]);
        }
        //totalSum is the sum of all numbers in piles without carry-over
        bool[] totalSum = CalcSum(piles);
        //endAt is the largest index in totalSum to hold a 1 (true)
        int endAt;

        for (endAt = totalSum.Length - 1; endAt >= 0; endAt--)
        {
            if (totalSum[endAt] == true)
            {
                break;
            }
        }

        //endAt == -1 only if there is no winning move (i.e. totalSum == 0) and so return the first vertex of the first piece in pieces
        if (endAt == -1)
        {
            return(pieces[0].Front());
        }

        //coorPiles stores the binary numbers in piles truncated at the index endAt
        bool[][] coorPiles = new bool[pieces.Count][];
        for (int i = 0; i < pieces.Count; i++)
        {
            bool[] p = piles[i];
            coorPiles[i] = new bool[Math.Min(endAt + 1, p.Length)];
            for (int j = 0; j < p.Length && j <= endAt; j++)
            {
                coorPiles[i][j] = p[j];
            }
        }

        //the optimal move is to remove from the Path that corresponds to the max number in coorPiles
        int targetIndex = FindMax(coorPiles);
        //the optimal move is to make the targetIndex Path have the grundy number of the sum of all the other Paths (without carry-over)
        //first calculate what this sum is for the truncated numbers (coorPiles) since it is already equal to the sum for all places above since they were zero
        int lowerTargetVal = PathCutthroat.FromBinArray(CalcSumOthers(coorPiles, targetIndex));
        //diff stores the change that needs to happen to pieces[targetIndex] in terms of grundy numbers
        int diff = PathCutthroat.FromBinArray(coorPiles[targetIndex]) - lowerTargetVal;
        //targetVal then stores the grundy number that pieces[targetVal] must have (as an optimal move)
        int targetVal = PathCutthroat.FromBinArray(piles[targetIndex]) - diff;

        //Need to split pieces[targetIndex] so that the two paths sum to targetVal in grundy value
        //splitter will store the index of what needs to be removed in pieces[targetValue] where 0 is the front
        int splitter = 0;
        int n        = pieces[targetIndex].Size();

        for (int i = 0; i < n / 2 + 1; i++)
        {
            //when i is found such that it splits pieces[targetIndex] into two piles equivalent to a nim pile of targetVal, set splitter to i and break
            if (PathCutthroat.ModAdd(grunds[i], grunds[n - i - 1]) == targetVal)
            {
                splitter = i;
                break;
            }
        }
        //splitter stores how far into pieces[targetIndex] the vertex to be removed is
        return(pieces[targetIndex].Front() + splitter);
    }