Example #1
0
    public void AsCancellationToken()
    {
        ((CancellationToken)Lifetime.Immortal).CanBeCanceled.AssertIsFalse();
        ((CancellationToken)Lifetime.Dead).IsCancellationRequested.AssertIsTrue();

        // cancelled on death
        var doomed           = new LifetimeSource();
        CancellationToken dt = doomed.Lifetime;

        dt.CanBeCanceled.AssertIsTrue();
        dt.IsCancellationRequested.AssertIsFalse();
        doomed.EndLifetime();
        dt.IsCancellationRequested.AssertIsTrue();
        // already cancelled when already dead
        ((CancellationToken)doomed.Lifetime).IsCancellationRequested.AssertIsTrue();

        // hangs on immortal
        var blessed          = new LifetimeSource();
        CancellationToken bt = blessed.Lifetime;

        bt.CanBeCanceled.AssertIsTrue();
        bt.IsCancellationRequested.AssertIsFalse();
        blessed.ImmortalizeLifetime();
        bt.IsCancellationRequested.AssertIsFalse();
        // knows can't be cancelled when already immortal
        ((CancellationToken)blessed.Lifetime).CanBeCanceled.AssertIsFalse();

        // hangs on limbo
        InvalidCallbackMaker.AssertNotCollectedAfter(action => {
            var r = new LifetimeSource();
            CancellationToken ct = r.Lifetime;
            ct.Register(action);
            return(ct);
        });
    }
Example #2
0
        ///<summary>A lifetime then ends after the lifetime created by a function (triggered when the given lifetime ends) ends.</summary>
        public static Lifetime ThenResurrect(this Lifetime lifetime, Func <Lifetime> resurrectedLifetimeFunc)
        {
            var r = new LifetimeSource();

            lifetime.WhenDead(() => resurrectedLifetimeFunc().WhenDead(r.EndLifetime));
            return(r.Lifetime);
        }
    public void IsResultThreadSafe()
    {
        foreach (var repeat in Enumerable.Range(0, 5))
        {
            var n      = 5000;
            var nt     = 4;
            var p      = new PerishableCollection <int>();
            var queues = Enumerable.Range(0, 4).Select(e => new Queue <LifetimeSource>()).ToArray();
            TestUtil.ConcurrencyTest(
                threadCount: nt,
                callbackCount: n,
                repeatedWork: (t, i) => {
                var r = new LifetimeSource();
                p.Add(i, r.Lifetime);
                if (i % 2 == 0)
                {
                    queues[t].Enqueue(r);
                }
                if (queues[t].Count > 20)
                {
                    queues[t].Dequeue().EndLifetime();
                }
            },
                finalWork: t => {
                while (queues[t].Count > 0)
                {
                    queues[t].Dequeue().EndLifetime();
                }
            });

            var expected = Enumerable.Range(0, n).Where(e => e % 2 != 0).SelectMany(e => Enumerable.Repeat(e, nt));
            p.CurrentItems().OrderBy(e => e.Value).Select(e => e.Value).AssertSequenceEquals(expected);
        }
    }
    public void CurrentAndFutureItems()
    {
        var source = new LifetimeSource();
        var p1     = new Perishable <int>(1, source.Lifetime);
        var p2     = new Perishable <int>(1, Lifetime.Immortal);
        var p      = new PerishableCollection <int>();

        var li0 = new List <Perishable <int> >();

        p.CurrentAndFutureItems().Subscribe(e => {
            li0.Add(e);
            e.Lifetime.WhenDead(() => li0.Remove(e));
        });
        li0.AssertSequenceEquals();

        p.Add(p1);
        li0.AssertSequenceEquals(p1);

        var li1 = new List <Perishable <int> >();

        p.CurrentAndFutureItems().Subscribe(e => {
            li1.Add(e);
            e.Lifetime.WhenDead(() => li1.Remove(e));
        });
        li1.AssertSequenceEquals(p1);

        p.Add(p2.Value, p2.Lifetime);
        li0.AssertSequenceEquals(p1, p2);
        li1.AssertSequenceEquals(p1, p2);

        source.EndLifetime();
        li0.AssertSequenceEquals(p2);
        li1.AssertSequenceEquals(p2);
    }
Example #5
0
    public void AllowsForGarbageCollection()
    {
        var mortal = new LifetimeSource();
        var lifes  = new[] {
            Lifetime.Immortal,
            Lifetime.Dead,
            mortal.Lifetime
        };

        // callbacks are not kept when the lifetime is not mortal
        var f = ValidCallbackMaker;

        foreach (var life in lifes)
        {
            // pre-finished
            f.AssertCollectedAfter(e => Lifetime.Immortal.WhenDead(e, life));
            f.AssertCollectedAfter(e => Lifetime.Dead.WhenDead(e, life));
            f.AssertCollectedAfter(e => LimboedLifetime.WhenDead(e, life));

            // post-finished
            f.AssertCollectedAfter(e => { using (var limbod = new LimboLife()) limbod.Lifetime.WhenDead(e, life); });
            f.AssertCollectedAfter(e => { using (var blessed = new BlessedLife()) blessed.Lifetime.WhenDead(e, life); });
            f.AssertCollectedAfter(e => { using (var doomed = new DoomedLife()) doomed.Lifetime.WhenDead(e, life); });
        }

        // callbacks are not kept when the subscription lifetime is dead or dies
        f.AssertCollectedAfter(e => { using (var doomed = new DoomedLife()) mortal.Lifetime.WhenDead(e, doomed.Lifetime); });
        f.AssertCollectedAfter(e => mortal.Lifetime.WhenDead(e, Lifetime.Dead));

        // callbacks are kept when the lifetime is mortal and the subscription lifetime does not die
        f.AssertNotCollectedAfter(e => mortal.Lifetime.WhenDead(e, Lifetime.Immortal));
        f.AssertNotCollectedAfter(e => mortal.Lifetime.WhenDead(e, mortal.Lifetime));

        GC.KeepAlive(mortal);
    }
Example #6
0
    public void Equality()
    {
        // mortals are not congruent or equal
        var s1 = new LifetimeSource();
        var s2 = new LifetimeSource();
        var a  = new Func <Lifetime>[] {
            () => Lifetime.Immortal,
            () => Lifetime.Dead,
            () => s1.Lifetime,
            () => s2.Lifetime
        };

        for (var i = 0; i < a.Length; i++)
        {
            for (var j = 0; j < a.Length; j++)
            {
                a[i]().IsCongruentTo(a[j]()).AssertEquals(i == j);
                a[i]().Equals(a[j]()).AssertEquals(i == j);
                if (i == j)
                {
                    a[i]().GetHashCode().AssertEquals(a[j]().GetHashCode());
                }
            }
        }

        // but mortals become congruent when set to the same phase
        s1.EndLifetime();
        s2.EndLifetime();
        s1.Lifetime.IsCongruentTo(s2.Lifetime).AssertIsTrue();
    }
    public void ConstructionProperties()
    {
        var source = new LifetimeSource();
        var p      = new Perishable <int>(2, source.Lifetime);

        p.Value.AssertEquals(2);
        p.Lifetime.AssertEquals(source.Lifetime);
    }
    public void Max()
    {
        Lifetime.Dead.Max(Lifetime.Dead).IsDead.AssertIsTrue();
        Lifetime.Dead.Max(Lifetime.Immortal).IsImmortal.AssertIsTrue();
        Lifetime.Immortal.Max(Lifetime.Dead).IsImmortal.AssertIsTrue();
        Lifetime.Immortal.Max(Lifetime.Immortal).IsImmortal.AssertIsTrue();

        var s1 = new LifetimeSource();
        var s2 = new LifetimeSource();
        var s3 = new LifetimeSource();
        var m1 = s1.Lifetime.Max(s2.Lifetime);
        var m2 = s1.Lifetime.Max(s3.Lifetime);
        var m3 = s2.Lifetime.Max(s3.Lifetime);
        var t1 = m1.WhenDeadTask();
        var t2 = m2.WhenDeadTask();
        var t3 = m3.WhenDeadTask();

        // equality optimization
        s1.Lifetime.Max(s1.Lifetime).AssertEquals(s1.Lifetime);
        m1.Max(m1).AssertEquals(m1);
        // dead optimization
        s1.Lifetime.Max(Lifetime.Dead).AssertEquals(s1.Lifetime);
        Lifetime.Dead.Max(m1).AssertEquals(m1);

        // when one becomes immortal, max becomes immortal
        (m1.IsImmortal || m1.IsDead).AssertIsFalse();
        (m2.IsImmortal || m2.IsDead).AssertIsFalse();
        s1.ImmortalizeLifetime();
        m1.IsImmortal.AssertIsTrue();
        m2.IsImmortal.AssertIsTrue();

        // when one becomes dead, max is unaffected
        s2.EndLifetime();

        // when both become dead, max is dead
        (m3.IsImmortal || m3.IsDead).AssertIsFalse();
        t3.AssertNotCompleted();
        s3.EndLifetime();
        m3.IsDead.AssertIsTrue();
        t3.AssertRanToCompletion();

        Task.WhenAny(t1, t2).AssertNotCompleted();

        // limbo allows collection
        InvalidCallbackMaker.AssertCollectedAfter(a => {
            var r1    = new LifetimeSource();
            var r2    = new LifetimeSource();
            var r3    = new LifetimeSource();
            var life1 = r1.Lifetime.Max(r2.Lifetime);
            var life2 = r1.Lifetime.Max(r3.Lifetime);
            var life3 = r2.Lifetime.Max(r3.Lifetime);
            life1.WhenDead(a);
            life2.WhenDead(a);
            life3.WhenDead(a);
            r1.EndLifetime(); // one dead has no effect on max going to limbo
            return(Tuple.Create(life1, life2, life3));
        });
    }
Example #9
0
    public void LifetimeDeathReentrancy()
    {
        var r  = new LifetimeSource();
        var r2 = new LifetimeSource();

        r.Lifetime.WhenDead(r2.EndLifetime, r2.Lifetime);
        r.Lifetime.WhenDead(r.EndLifetime);
        r.EndLifetime();
    }
    public void Equality()
    {
        var source = new LifetimeSource();
        var p      = new Perishable <int>(2, source.Lifetime);

        p.AssertEquals(new Perishable <int>(2, source.Lifetime));
        p.Equals(new Perishable <int>(3, source.Lifetime)).AssertIsFalse();
        p.Equals(new Perishable <int>(2, Lifetime.Immortal)).AssertIsFalse();
    }
    public void CreateDependentSource_Death()
    {
        var d1 = new LifetimeSource();
        var d2 = d1.Lifetime.CreateDependentSource();
        var d3 = d2.Lifetime.CreateDependentSource();

        d2.Lifetime.IsMortal.AssertIsTrue();
        d3.Lifetime.IsMortal.AssertIsTrue();

        d2.EndLifetime();
        d2.Lifetime.IsDead.AssertIsTrue();
        d3.Lifetime.IsDead.AssertIsTrue();

        d1.Lifetime.IsMortal.AssertIsTrue();
    }
Example #12
0
    public void LifetimeImmortalityConcurrency()
    {
        var repeats = 5;

        foreach (var _ in Enumerable.Range(0, repeats))
        {
            var n      = 0;
            var source = new LifetimeSource();
            TestUtil.ConcurrencyTest(
                threadCount: 4,
                callbackCount: 3000,
                repeatedWork: (t, i) => source.Lifetime.WhenDead(() => Interlocked.Increment(ref n)),
                finalWork: t => source.ImmortalizeLifetime());
            n.AssertEquals(0);
        }
    }
    public void CreateDependentSource_Garbage()
    {
        // an independent source will keep dependents alive
        var independent = new LifetimeSource();

        new Func <LifetimeSource>(() => independent.Lifetime.CreateDependentSource())
        .AssertNotCollectedAfter(e => e);
        independent.Lifetime.IsMortal.AssertIsTrue();

        // a dependent source does not keep its dependency alive
        LifetimeSource dependent = null;

        new Func <LifetimeSource>(() => new LifetimeSource())
        .AssertCollectedAfter(e => dependent = e.Lifetime.CreateDependentSource());
        dependent.Lifetime.IsMortal.AssertIsTrue();
    }
Example #14
0
    public void LifetimeDeathConcurrency()
    {
        var repeats = 5;

        foreach (var _ in Enumerable.Range(0, repeats))
        {
            var n             = 0;
            var source        = new LifetimeSource();
            var threadCount   = 4;
            var callbackCount = 3000;
            TestUtil.ConcurrencyTest(
                threadCount,
                callbackCount,
                repeatedWork: (t, i) => source.Lifetime.WhenDead(() => Interlocked.Increment(ref n)),
                finalWork: t => source.EndLifetime());
            n.AssertEquals(callbackCount * threadCount);
        }
    }
    public void CurrentItems()
    {
        var source = new LifetimeSource();
        var p1     = new Perishable <int>(1, source.Lifetime);
        var p2     = new Perishable <int>(1, Lifetime.Immortal);
        var p      = new PerishableCollection <int>();

        p.CurrentItems().AssertSequenceEquals();

        p.Add(p1);
        p.CurrentItems().AssertSequenceEquals(p1);

        p.Add(p2.Value, p2.Lifetime);
        p.CurrentItems().AssertSequenceEquals(p1, p2);

        source.EndLifetime();
        p.CurrentItems().AssertSequenceEquals(p2);
    }
    public void CurrentAndFutureItems_EndingDuringEnumerationDoesNotLockup()
    {
        var s = new LifetimeSource();
        var p = new PerishableCollection <int>();

        for (var i = 0; i < 1000; i++)
        {
            p.Add(i, Lifetime.Immortal);
        }

        var t = Task.Factory.StartNew(
            () => p.CurrentAndFutureItems().Subscribe(
                item => s.EndLifetime(),
                s.Lifetime));

        t.Wait(TimeSpan.FromMilliseconds(100));
        t.AssertRanToCompletion();
    }
    public void CreateDependentSource_Immortality()
    {
        var i1 = new LifetimeSource();
        var i2 = i1.Lifetime.CreateDependentSource();
        var i3 = i2.Lifetime.CreateDependentSource();

        i3.Lifetime.IsMortal.AssertIsTrue();
        i2.ImmortalizeLifetime();
        i2.Lifetime.IsImmortal.AssertIsTrue();

        i3.Lifetime.IsMortal.AssertIsTrue();
        i3.ImmortalizeLifetime();
        i3.Lifetime.IsImmortal.AssertIsTrue();

        i1.Lifetime.IsMortal.AssertIsTrue();
        TestUtil.ExpectException <InvalidOperationException>(i1.EndLifetime);
        i1.Lifetime.IsDead.AssertIsTrue();
    }
 public void IsEnumeratingWhileMutatingThreadSafe()
 {
     foreach (var repeat in Enumerable.Range(0, 5))
     {
         var n      = 5000;
         var nt     = 4;
         var p      = new PerishableCollection <int>();
         var queues = Enumerable.Range(0, 4).Select(e => new Queue <LifetimeSource>()).ToArray();
         TestUtil.ConcurrencyTest(
             threadCount: nt,
             callbackCount: n,
             repeatedWork: (t, i) => {
             if (t % 2 == 0)
             {
                 if (i % 500 != 0)
                 {
                     return;
                 }
                 var r = p.CurrentItems().OrderBy(e => e.Value).ToList();
                 (r.Count(e => e.Value % 2 == 0 && !e.Lifetime.IsDead) < nt / 2 * 20).AssertIsTrue();
             }
             else
             {
                 var r = new LifetimeSource();
                 p.Add(i, r.Lifetime);
                 if (i % 2 == 0)
                 {
                     queues[t].Enqueue(r);
                 }
                 if (queues[t].Count > 20)
                 {
                     queues[t].Dequeue().EndLifetime();
                 }
             }
         },
             finalWork: t => {
             while (queues[t].Count > 0)
             {
                 queues[t].Dequeue().EndLifetime();
             }
         });
     }
 }
Example #19
0
    public void Status()
    {
        // status of constants
        Lifetime.Immortal.IsMortal.AssertIsFalse();
        Lifetime.Immortal.IsImmortal.AssertIsTrue();
        Lifetime.Immortal.IsDead.AssertIsFalse();
        Lifetime.Dead.IsMortal.AssertIsFalse();
        Lifetime.Dead.IsImmortal.AssertIsFalse();
        Lifetime.Dead.IsDead.AssertIsTrue();

        // state before transition
        var mortal = new LifetimeSource();

        mortal.Lifetime.IsMortal.AssertIsTrue();
        mortal.Lifetime.IsImmortal.AssertIsFalse();
        mortal.Lifetime.IsDead.AssertIsFalse();

        // transition to dead
        var doomed = new LifetimeSource();

        doomed.EndLifetime();
        doomed.Lifetime.IsMortal.AssertIsFalse();
        doomed.Lifetime.IsImmortal.AssertIsFalse();
        doomed.Lifetime.IsDead.AssertIsTrue();

        // transition to immortal
        var blessed = new LifetimeSource();

        blessed.ImmortalizeLifetime();
        blessed.Lifetime.IsMortal.AssertIsFalse();
        blessed.Lifetime.IsImmortal.AssertIsTrue();
        blessed.Lifetime.IsDead.AssertIsFalse();

        // transition to immortal via limbo
        var limbo = new LimboLife();

        limbo.Dispose();
        GC.Collect();
        limbo.Lifetime.IsMortal.AssertIsFalse();
        limbo.Lifetime.IsImmortal.AssertIsTrue();
        limbo.Lifetime.IsDead.AssertIsFalse();
    }
    public void ObserveNonPerishedCount()
    {
        var li1 = new List <int>();

        new[] { new Perishable <int>(1, Lifetime.Immortal), new Perishable <int>(2, Lifetime.Immortal) }
        .ToObservable()
        .ObserveNonPerishedCount(completeWhenSourceCompletes: true)
        .Subscribe(li1.Add, () => li1.Add(-1));
        li1.AssertSequenceEquals(0, 1, 2, -1);

        var source = new LifetimeSource();
        var li2    = new List <int>();

        new[] { new Perishable <int>(1, source.Lifetime), new Perishable <int>(2, source.Lifetime) }
        .ToObservable()
        .ObserveNonPerishedCount(completeWhenSourceCompletes: false)
        .Subscribe(li2.Add, () => li2.Add(-1));
        li2.AssertSequenceEquals(0, 1, 2);
        source.EndLifetime();
        li2.AssertSequenceEquals(0, 1, 2, 1, 0, -1);
    }
Example #21
0
    public void WhenSet()
    {
        // called when immortal?
        var blessed        = new LifetimeSource();
        var preBlessedLife = blessed.Lifetime.WhenDeadTask();

        blessed.ImmortalizeLifetime();
        var bt = new[] {
            Lifetime.Immortal.WhenDeadTask(),
            blessed.Lifetime.WhenDeadTask(),
            preBlessedLife
        };

        Task.WhenAny(bt).AssertNotCompleted();

        // called when dead?
        var doomed        = new LifetimeSource();
        var preDoomedLife = doomed.Lifetime.WhenDeadTask();

        doomed.EndLifetime();
        var dt = new[] {
            preDoomedLife,
            doomed.Lifetime.WhenDeadTask(),
            Lifetime.Dead.WhenDeadTask()
        };

        Task.WhenAll(dt).AssertRanToCompletion();

        // never called from limbo
        var limboed      = new LimboLife();
        var preLimboLife = limboed.Lifetime.WhenDeadTask();

        limboed.Dispose();
        Task.WhenAny(
            preLimboLife,
            limboed.Lifetime.WhenDeadTask()
            ).AssertNotCompleted();
    }
    public void ToPerishableCollectionWithLifetime()
    {
        var source           = new LifetimeSource();
        var collectionSource = new LifetimeSource();
        var p1 = new Perishable <int>(1, source.Lifetime);
        var p2 = new Perishable <int>(1, Lifetime.Immortal);
        var p  = new PerishableCollection <int>();
        var q  = p.CurrentAndFutureItems().ToPerishableCollection(collectionSource.Lifetime);

        q.CurrentItems().AssertSequenceEquals();

        p.Add(p1);
        q.CurrentItems().AssertSequenceEquals(p1);

        collectionSource.EndLifetime();

        p.Add(p2.Value, p2.Lifetime);
        q.CurrentItems().AssertSequenceEquals(p1);

        source.EndLifetime();

        source.EndLifetime();
        q.CurrentItems().AssertSequenceEquals();
    }
Example #23
0
    public static void Main()
    {
        "=== Hit 'Enter' to advance ===".WriteLine();
        Break();

        ///////////////////////////////////////////////////
        "Manually inspecting a lifetime as it is killed:".WriteLine();
        var lifesource1 = new LifetimeSource();

        "Life #1: {0}".WriteLine(lifesource1);
        "Ending Life #1".WriteLine();
        lifesource1.EndLifetime();
        "Life #1: {0}".WriteLine(lifesource1);
        Break();

        ///////////////////////////////////////////////////
        "Manually inspecting a lifetime as it is immortalized:".WriteLine();
        var lifesource2 = new LifetimeSource();

        "Life #2: {0}".WriteLine(lifesource2);
        "Immortalizing Life #2".WriteLine();
        lifesource2.ImmortalizeLifetime();
        "Life #2: {0}".WriteLine(lifesource2);
        Break();

        ///////////////////////////////////////////////////
        "Using callbacks to inspect a lifetime as it is killed:".WriteLine();
        var lifesource3 = new LifetimeSource();

        "Life #3: {0}".WriteLine(lifesource3);
        "Registering WhenDead Life #3 (before)".WriteLine();
        lifesource3.Lifetime.WhenDead(() => "WhenDead Life #3 (before)".WriteLine());
        "Ending Life #3".WriteLine();
        lifesource3.EndLifetime();
        "Life #3: {0}".WriteLine(lifesource3);
        "Registering WhenDead Life #3 (after)".WriteLine();
        lifesource3.Lifetime.WhenDead(() => "WhenDead Life #3 (after)".WriteLine());
        Break();

        ///////////////////////////////////////////////////
        "Using conditional callbacks:".WriteLine();
        var lifesource4 = new LifetimeSource();
        var lifesource5 = new LifetimeSource();

        "Life #4: {0}".WriteLine(lifesource4);
        "Life #5: {0}".WriteLine(lifesource5);
        "Registering WhenDead 4 (requires 5)".WriteLine();
        lifesource4.Lifetime.WhenDead(
            () => "Running WhenDead 4 (requires 5)".WriteLine(),
            lifesource5.Lifetime);
        "Registering WhenDead 5 (requires 4)".WriteLine();
        lifesource5.Lifetime.WhenDead(
            () => "Running WhenDead 5 (requires 4)".WriteLine(),
            lifesource4.Lifetime);
        "Ending Life #4".WriteLine();
        lifesource4.EndLifetime();
        "Life #4: {0}".WriteLine(lifesource4);
        "Ending Life #5".WriteLine();
        lifesource5.EndLifetime();
        "Life #5: {0}".WriteLine(lifesource5);
        Break();

        ///////////////////////////////////////////////////
        CallbackGarbageTest(
            "Immortal Lifetime collectable callback test:",
            () => new LifetimeSource().Lifetime,
            (e, a) => e.WhenDead(a));
        ///////////////////////////////////////////////////
        var lifetimeMortal = new LifetimeSource();

        CallbackGarbageTest(
            "Conditioned-on-dying Lifetime collectable callback test:",
            () => lifetimeMortal.Lifetime,
            (e, a) => {
            var r = new LifetimeSource();
            e.WhenDead(a, r.Lifetime);
            r.EndLifetime();
        });
        GC.KeepAlive(lifetimeMortal);
        ///////////////////////////////////////////////////
        CallbackGarbageTest(
            "Immortal CancellationToken collectable callback test:",
            () => new CancellationTokenSource().Token,
            (e, a) => e.Register(a));

        ///////////////////////////////////////////////////
        "Garbage collection of a lifetime's source:".WriteLine();
        var lifesource6 = new LifetimeSource();
        var life6       = lifesource6.Lifetime;

        "Life #6: {0}".WriteLine(life6);
        "Allowing garbage collection of Life #6's source".WriteLine();
        lifesource6 = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        "Life #6: {0}".WriteLine(life6);
        Break();

        ///////////////////////////////////////////////////
        "=== Hit 'Enter' to close ===".WriteLine();
        Break();
    }
        private void SetupEnergyAndTime(Game game, double energyLossForCutting, double energyGainPerConnectorBroken)
        {
            var elapsed = TimeSpan.Zero;
            var living  = new LifetimeSource();

            living.Lifetime.WhenDead(() => {
                if (Best == elapsed)
                {
                    LabelTitle.Text       = "New High Score! Try Again?";
                    LabelTitle.Foreground = new SolidColorBrush(Colors.Green);
                }
                else
                {
                    LabelTitle.Text       = "Game Over! Try Again?";
                    LabelTitle.Foreground = new SolidColorBrush(Colors.Red);
                }
                MenuPanel.Visibility = Visibility.Visible;
            }, game.Life);

            // show energy status
            var gains     = 0.0;
            var loses     = 0.0;
            var energy    = 50.0;
            var maxEnergy = 50.0;

            game.LoopActions.Add(step => {
                // energy decays faster and faster over time
                var t   = step.TimeStep.TotalSeconds;
                energy -= t * Math.Log(elapsed.TotalSeconds / 15 + 1).Max(1);

                // quickly decrease the size of the red/blue bars that show changes
                gains -= t * 5;
                loses -= t * 5;
                gains *= Math.Pow(0.01, t);
                loses *= Math.Pow(0.01, t);

                // keep everything reasonable
                gains  = gains.Clamp(0, 10);
                loses  = loses.Clamp(0, 10);
                energy = energy.Clamp(0, maxEnergy);

                // "draw" energy
                var w           = canvas.ActualWidth;
                BarEnergy.Fill  = new SolidColorBrush(Colors.Yellow.LerpTo(Colors.Green, (energy * 2 / maxEnergy).Clamp(0, 1)));
                BarLoses.Width  = ((energy + loses) / maxEnergy * w).Clamp(0, w);
                BarGains.Width  = (energy / maxEnergy * w).Clamp(0, w);
                BarEnergy.Width = ((energy - gains) / maxEnergy * w).Clamp(0, w);

                // hit 0 energy? game over
                if (energy == 0)
                {
                    living.EndLifetime();
                }
            }, game.Life);

            // track energy changes due to connectors dying
            game.Connectors.CurrentAndFutureItems().Subscribe(e => e.Lifetime.WhenDead(() => {
                // breaking connectors gain you some energy
                if (living.Lifetime.IsMortal)
                {
                    energy += energyGainPerConnectorBroken;
                }
                gains += energyGainPerConnectorBroken;

                // but making cuts costs energy
                if (e.Value.CutPoint != null)
                {
                    energy -= energyLossForCutting;
                    loses  += energyLossForCutting;
                }
            }), game.Life);

            // track times
            game.LoopActions.Add(step => {
                // advance time
                if (living.Lifetime.IsMortal)
                {
                    elapsed += step.TimeStep;
                }
                Best = Best.Max(elapsed);

                // show time
                TimeLabel.Text = String.Format("Time: {0:0.0}s", elapsed.TotalSeconds);

                // show best time (green when making best time)
                TimeBest.Background = new SolidColorBrush(
                    Best == elapsed
                    ? Color.FromArgb(128, 0, 255, 0)
                    : Colors.Transparent);
                TimeBest.Text = String.Format("Best: {0:0.0}s", Best.TotalSeconds);
            }, game.Life);
        }
Example #25
0
 public void Dispose()
 {
     _source = null;
     GC.Collect();
     GC.WaitForPendingFinalizers();
 }