Source

ICFP 2011 ICRS / src / Icfp2011.Icrs / LtgCards.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Icfp2011.Icrs
{
    public static class LtgCards
    {
        public static readonly LtgValue Zero = new LtgNumber(0);

        public static readonly LtgFunction ICombinator = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                return arg;
            });

        public static readonly LtgFunction Succ = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                var n = arg as LtgNumber;
                if (n == null)
                    return null;
                return new LtgNumber(Math.Min(n.Number + 1, LtgUtilities.MaxNumber));
            });

        public static readonly LtgFunction Dbl = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                var n = arg as LtgNumber;
                if (n == null)
                    return null;
                return new LtgNumber(Math.Min(n.Number * 2, LtgUtilities.MaxNumber));
            });

        public static readonly LtgFunction Get = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                var i = arg as LtgNumber;
                if (i == null || i.Number < 0 || i.Number >= propSlots.Length)
                    return null;
                var ps = propSlots[i.Number];
                if (!ps.IsAlive)
                    return null;
                return ps.Value;
            });

        public static readonly LtgFunction Put = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                return ICombinator;
            });

        public static readonly LtgFunction SCombinator = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                return new LtgFunction(SCombinator, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2) =>
                    {
                        return new LtgFunction(SCombinator, new[] { arg, arg2 }, (depth3, propSlots3, oppSlots3, arg3) =>
                            {
                                var f = arg as LtgFunction;
                                if (f == null)
                                    return null;

                                var g = arg2 as LtgFunction;
                                if (g == null)
                                    return null;

                                var h = f.Evaluate(ref depth3, propSlots, oppSlots, arg3);
                                var y = g.Evaluate(ref depth3, propSlots, oppSlots, arg3);
                                return h.Evaluate(ref depth3, propSlots, oppSlots, y);
                            });
                    });
            });

        public static readonly LtgFunction KCombinator = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                return new LtgFunction(KCombinator, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2) => arg);
            });

        public static readonly LtgFunction Inc = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                var i = arg as LtgNumber;
                if (i == null || i.Number < 0 || i.Number >= propSlots.Length)
                    return null;
                var ps = propSlots[i.Number];
                if (ps.Vitality > 0 && ps.Vitality < LtgUtilities.MaxVitality)
                    ps.Vitality++;

                return LtgCards.ICombinator;
            });

        public static readonly LtgFunction Dec = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                var i = arg as LtgNumber;
                if (i == null || i.Number < 0 || i.Number >= oppSlots.Length)
                    return null;
                var os = oppSlots[oppSlots.Length - 1 - i.Number];
                if (os.Vitality > 0)
                    os.Vitality--;

                return LtgCards.ICombinator;
            });

        public static readonly LtgFunction Attack = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                return new LtgFunction(Attack, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2) =>
                {
                    return new LtgFunction(Attack, new[] { arg, arg2 }, (depth3, propSlots3, oppSlots3, arg3) =>
                        {
                            var i = arg as LtgNumber;
                            if (i == null || i.Number < 0 || i.Number >= propSlots.Length)
                                return null;
                            var ps = propSlots[i.Number];

                            var j = arg2 as LtgNumber;
                            if (j == null || j.Number < 0 || j.Number >= oppSlots2.Length)
                                return null;
                            var os = oppSlots[oppSlots.Length - 1 - j.Number];

                            var n = arg3 as LtgNumber;
                            if (n == null || n.Number > ps.Vitality)
                                return null;

                            ps.Vitality = ps.Vitality - n.Number;
                            os.Vitality = Math.Max(os.Vitality - (n.Number * 9 / 10), 0);

                            return LtgCards.ICombinator;
                        });
                });
            });

        public static readonly LtgFunction Help = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                return new LtgFunction(Help, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2) =>
                {
                    return new LtgFunction(Help, new[] { arg, arg2 }, (depth3, propSlots3, oppSlots3, arg3) =>
                    {
                        var i = arg as LtgNumber;
                        if (i == null || i.Number < 0 || i.Number >= propSlots.Length)
                            return null;
                        var ps1 = propSlots[i.Number];

                        var j = arg2 as LtgNumber;
                        if (j == null || j.Number < 0 || j.Number >= propSlots2.Length)
                            return null;
                        var ps2 = propSlots[j.Number];

                        var n = arg3 as LtgNumber;
                        if (n == null || n.Number > ps1.Vitality)
                            return null;

                        ps1.Vitality = ps1.Vitality - n.Number;
                        ps2.Vitality = Math.Min(ps2.Vitality + (n.Number * 11 / 10), LtgUtilities.MaxVitality);

                        return LtgCards.ICombinator;
                    });
                });
            });

        public static readonly LtgFunction Copy = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                var i = arg as LtgNumber;
                if (i == null || i.Number < 0 || i.Number >= oppSlots.Length)
                    return null;
                var os = oppSlots[i.Number];

                return os.Value;
            });

        public static readonly LtgFunction Revive = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                var i = arg as LtgNumber;
                if (i == null || i.Number < 0 || i.Number >= propSlots.Length)
                    return null;
                var ps = propSlots[i.Number];
                if (ps.Vitality <= 0)
                    ps.Vitality = 1;

                return LtgCards.ICombinator;
            });

        public static readonly LtgFunction Zombie = new LtgFunction((depth, propSlots, oppSlots, arg) =>
            {
                return new LtgFunction(Zombie, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2) =>
                    {
                        var i = arg as LtgNumber;
                        if (i == null || i.Number < 0 || i.Number >= oppSlots.Length)
                            return null;
                        var os = oppSlots[oppSlots.Length - 1 - i.Number];
                        if (os.IsAlive)
                            return null;
                        os.Vitality = -1;

                        return LtgCards.ICombinator;
                    });
            });

        public static LtgValue FromName(string name)
        {
            if (name == "I")
                return ICombinator;
            else if (name == "zero")
                return Zero;
            else if (name == "succ")
                return Succ;
            else if (name == "dbl")
                return Dbl;
            else if (name == "get")
                return Get;
            else if (name == "put")
                return Put;
            else if (name == "S")
                return SCombinator;
            else if (name == "K")
                return KCombinator;
            else if (name == "inc")
                return Inc;
            else if (name == "dec")
                return Dec;
            else if (name == "attack")
                return Attack;
            else if (name == "help")
                return Help;
            else if (name == "copy")
                return Copy;
            else if (name == "revive")
                return Revive;
            else if (name == "zombie")
                return Zombie;

            return null;
        }

        public static string ToName(this LtgValue card)
        {
            if (card == ICombinator)
                return "I";
            else if (card == Zero)
                return "zero";
            else if (card == Succ)
                return "succ";
            else if (card == Dbl)
                return "dbl";
            else if (card == Get)
                return "get";
            else if (card == Put)
                return "put";
            else if (card == SCombinator)
                return "S";
            else if (card == KCombinator)
                return "K";
            else if (card == Inc)
                return "inc";
            else if (card == Dec)
                return "dec";
            else if (card == Attack)
                return "attack";
            else if (card == Help)
                return "help";
            else if (card == Copy)
                return "copy";
            else if (card == Revive)
                return "revive";
            else if (card == Zombie)
                return "zombie";

            if (card is LtgNumber)
                return ((LtgNumber)card).Number.ToString();

            return null;
        }
    }
}