Exemple #1
0
        public void GetSplitPoints_OnlySpillsRight_SplitPointLengthIsCorrect()
        {
            Scope root = new Scope("012345");

            root.DefineInnerScope(3, 3);                                    //012|345

            List <SplitPoint> points = splitter.GetSplitPoints(root, 0, 5); //(012|34)5)

            Assert.AreEqual(1, points.Count);
            SplitPoint firstPoint = points[0];

            Assert.AreEqual(3, firstPoint.StartIndex);
            Assert.AreEqual(2, firstPoint.Length);
        }
Exemple #2
0
        public void Create(Vector2 field)
        {
            var max     = new Vector2(this.sectionX.y, this.sectionY.y);
            var pos     = Vector2.zero;
            var step    = Vector2.zero;
            var counter = 0;

            while (counter < 2)
            {
                (pos - field)
                .EachAction((i, p) => pos[i] >= 0f, (i, p) =>
                {
                    var isFrame = (p <= -field[i] == true || p >= field[i] == true);
                    var isMain  = Random.value < this.main.Rate && isFrame == false;

                    p += 0.5f * (isMain == true ? max[i] : 0f);
                    p  = p < field[i] - max[i] ? p : field[i];

                    var isLast = (p >= field[i]);
                    isMain     = (isMain || isFrame || isLast);

                    var sp = new SplitPoint(p, isMain == true ? this.main.Width : this.sub.Width);
                    (i == 0 ? this.PointsX : this.PointsY).Add(sp);

                    step[i] = (isMain == true ? max[i] : 0f);
                    if (isLast == true)
                    {
                        counter++;
                        pos[i] = -1f;
                    }
                });

                step += new Vector2(this.sectionX.Rand(), this.sectionY.Rand());
                pos   = pos.EachFunc(step, (v1, Vector2) => v1 + (v1 < 0f ? 0f : Vector2));
            }
        }
Exemple #3
0
 // ThreadPool::available_slave() tries to find an idle thread which is available
 // to join SplitPoint 'sp'.
 internal static Thread available_slave(SplitPoint sp)
 {
     return threads.FirstOrDefault(t => t.can_join(sp));
 }
Exemple #4
0
    // Thread::split() does the actual work of distributing the work at a node between
    // several available threads. If it does not succeed in splitting the node
    // (because no idle threads are available), the function immediately returns.
    // If splitting is possible, a SplitPoint object is initialized with all the
    // data that must be copied to the helper threads and then helper threads are
    // informed that they have been assigned work. This will cause them to instantly
    // leave their idle loops and call search(). When all threads have returned from
    // search() then split() returns.

    internal void split(
        Position pos,
        StackArrayWrapper ss,
        ValueT alpha,
        ValueT beta,
        ref ValueT bestValue,
        ref MoveT bestMove,
        Depth depth,
        int moveCount,
        MovePicker movePicker,
        NodeType nodeType,
        bool cutNode)
    {
        Debug.Assert(searching);
        Debug.Assert(
            -Value.VALUE_INFINITE < bestValue && bestValue <= alpha && alpha < beta && beta <= Value.VALUE_INFINITE);
        Debug.Assert(depth >= ThreadPool.minimumSplitDepth);
        Debug.Assert(splitPointsSize < _.MAX_SPLITPOINTS_PER_THREAD);

        // Pick and init the next available split point
        var sp = splitPoints[splitPointsSize];

        ThreadHelper.lock_grab(sp.spinLock); // No contention here until we don't increment splitPointsSize

        sp.master = this;
        sp.parentSplitPoint = activeSplitPoint;
        sp.slavesMask = 0;
        sp.slavesMask = (1u << idx);
        sp.depth = depth;
        sp.bestValue = bestValue;
        sp.bestMove = bestMove;
        sp.alpha = alpha;
        sp.beta = beta;
        sp.nodeType = nodeType;
        sp.cutNode = cutNode;
        sp.movePicker = movePicker;
        sp.moveCount = moveCount;
        sp.pos = pos;
        sp.nodes = 0;
        sp.cutoff = false;
        sp.ss = ss;
        sp.allSlavesSearching = true; // Must be set under lock protection

        ++splitPointsSize;
        activeSplitPoint = sp;
        activePosition = null;

        // Try to allocate available threads
        Thread slave;

        while (Bitcount.popcount_Full(sp.slavesMask) < _.MAX_SLAVES_PER_SPLITPOINT
               && (slave = ThreadPool.available_slave(sp)) != null)
        {
            ThreadHelper.lock_grab(slave.spinlock);

            if (slave.can_join(activeSplitPoint))
            {
                activeSplitPoint.slavesMask |= 1u << (slave.idx);
                slave.activeSplitPoint = activeSplitPoint;
                slave.searching = true;
            }

            ThreadHelper.lock_release(slave.spinlock);
        }

        // Everything is set up. The master thread enters the idle loop, from which
        // it will instantly launch a search, because its 'searching' flag is set.
        // The thread will return from the idle loop when all slaves have finished
        // their work at this split point.
        ThreadHelper.lock_release(sp.spinLock);

        base_idle_loop(null); // Force a call to base class idle_loop()

        // In the helpful master concept, a master can help only a sub-tree of its
        // split point and because everything is finished here, it's not possible
        // for the master to be booked.
        Debug.Assert(!searching);
        Debug.Assert(activePosition == null);

        // We have returned from the idle loop, which means that all threads are
        // finished. Note that decreasing splitPointsSize must be done under lock
        // protection to avoid a race with Thread::can_join().
        ThreadHelper.lock_grab(spinlock);

        searching = true;
        --splitPointsSize;
        activeSplitPoint = sp.parentSplitPoint;
        activePosition = pos;

        ThreadHelper.lock_release(spinlock);

        // Split point data cannot be changed now, so no need to lock protect
        pos.set_nodes_searched(pos.nodes_searched() + sp.nodes);
        bestMove = Move.Create(sp.bestMove);
        bestValue = Value.Create(sp.bestValue);
    }
Exemple #5
0
    // Make a local copy to be sure doesn't become zero under our feet while
    // Thread::can_join() checks whether the thread is available to join the split
    // point 'sp'. An obvious requirement is that thread must be idle. With more than
    // two threads, this is not sufficient: If the thread is the master of some split
    // point, it is only available as a slave for the split points below his active
    // one (the "helpful master" concept in YBWC terminology).

    internal bool can_join(SplitPoint sp)
    {
        if (searching)
        {
            return false;
        }

        // Make a local copy to be sure it doesn't become zero under our feet while
        // testing next condition and so leading to an out of bounds access.
        var size = splitPointsSize;

        // No split points means that the thread is available as a slave for any
        // other thread otherwise apply the "helpful master" concept if possible.
        var bitIsSet = (splitPoints[size - 1].slavesMask & (1u << sp.master.idx)) != 0;
        //splitPoints[size - 1].slavesMask.test(sp.master.idx)
        return size > 0 || bitIsSet;
    }
Exemple #6
0
    internal void base_idle_loop(ManualResetEvent initEvent)
    {
        // Pointer 'this_sp' is not null only if we are called from split(), and not
        // at the thread creation. This means we are the split point's master.
        var this_sp = splitPointsSize > 0 ? activeSplitPoint : null;
        Debug.Assert(this_sp == null || (this_sp.master == this && searching));

        while (!exit && this_sp == null && (this_sp.slavesMask == 0))
        {
            // If this thread has been assigned work, launch a search
            while (searching)
            {
                ThreadHelper.lock_grab(spinlock);

                Debug.Assert(activeSplitPoint != null);
                var sp = activeSplitPoint;

                ThreadHelper.lock_release(spinlock);

                var stack = new StackArrayWrapper(new Stack[_.MAX_PLY + 4]);
                var ss = new StackArrayWrapper(stack.table, 2);
                var pos = new Position(sp.pos, this);

                Array.Copy(sp.ss.table, ss.table, 5);
                ss[ss.current].splitPoint = sp;

                ThreadHelper.lock_grab(sp.spinLock);

                Debug.Assert(activePosition == null);

                activePosition = pos;

                if (sp.nodeType == NodeType.NonPV)
                {
                    //enable call to search
                    //search < NonPV, true > (pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode)
                }

                else if (sp.nodeType == NodeType.PV)
                {
                    //enable call to search
                    //search < PV, true > (pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode)
                }

                else if (sp.nodeType == NodeType.Root)
                {
                    //enable call to search
                    //search < Root, true > (pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
                }

                else
                {
                    Debug.Assert(false);
                }

                Debug.Assert(searching);

                ThreadHelper.lock_grab(spinlock);

                searching = false;
                activePosition = null;

                ThreadHelper.lock_release(spinlock);

                sp.slavesMask &= ~(1UL << idx); //sp.slavesMask.reset(idx);
                sp.allSlavesSearching = false;
                sp.nodes += pos.nodes_searched();

                // After releasing the lock we can't access any SplitPoint related data
                // in a safe way because it could have been released under our feet by
                // the sp master.
                ThreadHelper.lock_release(sp.spinLock);

                // Try to late join to another split point if none of its slaves has
                // already finished.
                SplitPoint bestSp = null;
                var minLevel = int.MaxValue;

                foreach (var th in ThreadPool.threads)
                {
                    var size = th.splitPointsSize; // Local copy
                    sp = size > 0 ? th.splitPoints[size - 1] : null;

                    if (sp != null && sp.allSlavesSearching
                        && Bitcount.popcount_Full(sp.slavesMask) < _.MAX_SLAVES_PER_SPLITPOINT && can_join(sp))
                    {
                        Debug.Assert(this != th);
                        Debug.Assert(!(this_sp != null && Bitcount.popcount_Full(sp.slavesMask) == 0));
                        Debug.Assert(ThreadPool.threads.Count > 2);

                        // Prefer to join to SP with few parents to reduce the probability
                        // that a cut-off occurs above us, and hence we waste our work.
                        var level = 0;
                        for (var p = th.activeSplitPoint; p != null; p = p.parentSplitPoint)
                        {
                            level++;
                        }

                        if (level < minLevel)
                        {
                            bestSp = sp;
                            minLevel = level;
                        }
                    }
                }

                if (bestSp != null)
                {
                    sp = bestSp;

                    // Recheck the conditions under lock protection
                    ThreadHelper.lock_grab(sp.spinLock);

                    if (sp.allSlavesSearching && Bitcount.popcount_Full(sp.slavesMask) < _.MAX_SLAVES_PER_SPLITPOINT)
                    {
                        ThreadHelper.lock_grab(spinlock);

                        if (can_join(sp))
                        {
                            sp.slavesMask &= ~(1UL << idx); //sp->slavesMask.set(idx);
                            activeSplitPoint = sp;
                            searching = true;
                        }

                        ThreadHelper.lock_release(spinlock);
                    }

                    ThreadHelper.lock_release(sp.spinLock);
                }

                // If search is finished then sleep, otherwise just yield
                if (!ThreadPool.main().thinking)
                {
                    Debug.Assert(this_sp == null);

                    ThreadHelper.lock_grab(spinlock);

                    while (!exit && !ThreadPool.main().thinking)
                        ThreadHelper.cond_wait(sleepCondition, spinlock /*mutex*/);

                    ThreadHelper.lock_release(spinlock);
                    
                }
                else
                {
                    System.Threading.Thread.Yield(); // Wait for a new job or for our slaves to finish
                }
            }
        }
    }
Exemple #7
0
 internal Thread(WaitHandle initEvent)
     : base(initEvent)
 {
     searching = false;
     maxPly = 0;
     splitPointsSize = 0;
     activeSplitPoint = null;
     activePosition = null;
     idx = ThreadPool.threads.Count; // Starts from 0
     for (var j = 0; j < _.MAX_SPLITPOINTS_PER_THREAD; j++)
     {
         splitPoints[j] = new SplitPoint();
     }
 }
    private void PrepareTargetList(PathList path)
    {
        _splitPoint = null;

        foreach (Transform target in path.pathPoints)
        {
            _listOfTargets.Add(target);
            SplitPoint split = target.GetComponent<SplitPoint>();
            if (split != null)
            {
                _splitPoint = split;
                //TODO this only accounts for two path choices.
                Vector3 midPosition = Vector3.zero;

                for (int i = 0; i < _splitPoint.newPaths.Length;i++)
                {
                    midPosition += _splitPoint.newPaths[i].pathPoints[2].position;
                }

                CreateChoiceItem();

                midPosition /= _splitPoint.newPaths.Length;

                _arrow = (Arrow)Instantiate(arrowPrefab,midPosition,Quaternion.identity);
                _arrow.transform.parent = _splitPoint.transform;
                _choiceIsReady = true;
                Transform nextPath = GetNextPathChoice();
                _arrow.SetTarget(nextPath);
                SetLabelsActive(nextPath);

                scoreManager.AddRound();
            }
        }
    }