ThoughtWorks笔试题之Merchant's Guide To The Galaxy解析

我没有拿到具体的题目,只是参考了http://www.cnblogs.com/deepleo/p/thoughtworks.html,希望没有理解错误。

我觉得这里的重点之一是语义分析,需要在运行时解析各个“外星文”

代码如下(比较潦草,也没错误处理,罪过罪过。。。):

ProblemOne.cs

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

namespace Thoughtworks.Problems
{
    class ProblemOne
    {
        class Roman
        {
            private List<RomanPrimitive> Primitives;

            public Roman()
            {
                Primitives = new List<RomanPrimitive>();
            }
            private int _valueCache = 0;
            private bool _dirty = true;
            public int Calculate()
            {
                if (_dirty)
                {
                    _valueCache = 0;
                    var result = 0;
                    var length = Primitives.Count();
                    for (int i = 0; i < length; i++)
                    {
                        var current = Primitives[i];
                        result += current.OctValue;

                        if (i == length - 1)
                            return result;

                        var next = Primitives[i + 1];
                        if (current.OctValue < next.OctValue)
                        {
                            result = next.OctValue - result;
                            i++;
                        }
                        else if (current.OctValue == next.OctValue)
                        {
                            if (!current.AllowRepeat)
                            {
                                throw new Exception(string.Format("{0} can't be repeated", current.Symbol));
                            }
                            var count = 2;
                            for (int j = i + 2; j < length; j++)
                            {
                                if (Primitives[j].Symbol != current.Symbol)
                                    break;
                                count++;
                                result += current.OctValue;
                                i++;
                                if (count > 3)
                                {
                                    throw new Exception(string.Format("{0} can't be repeated more than 3 times", current.Symbol));
                                }
                            }
                        }
                    }
                    _valueCache = result;
                }
                
                return _valueCache;
            }

            public static Roman Parse(string str, Dictionary<string, RomanPrimitive> map)
            {
                var left = str.Split(' ');
                var number = new StringBuilder();
                for (int i = 0; i < left.Length; i++)
                {
                    number.Append(map[left[i]].Symbol);
                }
                var roman = Roman.Parse(number.ToString());
                return roman;
            }

            public static Roman Parse(string str)
            {
                var roman = new Roman();
                var chars = str.ToCharArray();
                for (int i = 0; i < chars.Length; i++)
                {
                    roman.Primitives.Add(RomanPrimitive.Parse(chars[i]));
                }
                return roman;
            }
        }
        class RomanPrimitive
        {
            private static ILookup<char, RomanPrimitive> Primitives = new List<RomanPrimitive>{
                new RomanPrimitive('I', 1, true, true),
                new RomanPrimitive('V', 5),
                new RomanPrimitive('X', 10, true, true),
                new RomanPrimitive('L', 50),
                new RomanPrimitive('C', 100, true, true),
                new RomanPrimitive('D', 500),
                new RomanPrimitive('M', 1000, true),
            }.ToLookup(_=>_.Symbol);

            private RomanPrimitive(char symbol, int octValue, bool allowRepeat = false, bool allowSubtract = false)
            {
                Symbol = symbol;
                OctValue = octValue;
                AllowRepeat = allowRepeat;
                AllowSubtract = allowSubtract;
            }

            public int OctValue { get; private set; }
            public char Symbol { get; private set; }
            public bool AllowRepeat { get; private set; }
            public bool AllowSubtract { get; private set; }
            public static RomanPrimitive Parse(char Symbol)
            {
                if (!Primitives.Contains(Symbol))
                    return null;
                return Primitives[Symbol].First();
            }
        }
        class Context
        {
            public string PrimUnit { get; set; }
            public Dictionary<string, RomanPrimitive> Primitives { get; set; }
            public Dictionary<string, double> Units { get; set; }
            public List<string> Questions { get; set; }

            public Context()
            {
                Primitives = new Dictionary<string, RomanPrimitive>();
                Units = new Dictionary<string, double>();
                Questions = new List<string>();
            }
        }
        abstract class Parser
        {
            public Context Context { get; private set; }
            public Parser(Context ctx)
            {
                Context = ctx;
            }

            public abstract bool Parse(string input);
        }

        class PrimitiveParser : Parser
        {
            public PrimitiveParser(Context ctx)
                : base(ctx)
            {

            }

            public override bool Parse(string input)
            {
                var lexers = input.Split(new []{" is "}, StringSplitOptions.RemoveEmptyEntries);
                if (lexers.Count() != 2)
                    return false;
                if (lexers[1].Length > 1)
                    return false;
                var roman = RomanPrimitive.Parse(lexers[1][0]);
                if (roman == null)
                {
                    throw new Exception("syntex error.");
                }
                var name = lexers[0].Trim();
                Context.Primitives[name] = roman;
                return true;
            }
        }

        class UnitParser : Parser
        {
            public UnitParser(Context ctx)
                : base(ctx)
            {

            }

            public override bool Parse(string input)
            {
                var lexers = input.Split(new[] { " is " }, StringSplitOptions.RemoveEmptyEntries);
                if (lexers.Count() != 2)
                    return false;

                var left = lexers[0].Split(' ');

                if (left.Length < 2)
                    return false;
                var rValue = int.Parse(lexers[1].Split(' ')[0]);
                var primUnit = lexers[1].Split(' ')[1];
                Context.PrimUnit = primUnit;
                

                var roman = Roman.Parse(String.Join(" ", left.Take(left.Length - 1)), Context.Primitives);
                var calculated = roman.Calculate();

                var unit = left.Last();
                var unitValue = (double)rValue / (double)calculated;

                Context.Units[unit] = unitValue;
                return true;
            }
        }

        class QuestionParser : Parser
        {
            public QuestionParser(Context ctx)
                : base(ctx)
            {

            }

            public override bool Parse(string input)
            {
                if (!input.EndsWith("?"))
                    return false;
                Context.Questions.Add(input.Replace("?", "").Trim());
                return true;
            }
        }
        abstract class Solver
        {
            public Context Context { get; private set; }
            public Solver(Context ctx)
            {
                Context = ctx;
            }

            public abstract bool Solve(string input, out string answer);
        }
        class UnitSolver : Solver
        {
            public UnitSolver(Context ctx)
                : base(ctx)
            {

            }
            public override bool Solve(string question, out string answer)
            {
                var primUnit = Context.PrimUnit;
                var qulifier = String.Format("how many {0} is", primUnit);
                if (!question.StartsWith(qulifier))
                {
                    answer = null;
                    return false;
                }
                var body = question.Substring(qulifier.Length + 1);
                var lexers = body.Split(' ');
                var unit = lexers.Last().Trim();
                var unitValue = Context.Units[unit];
                var value = Roman.Parse(String.Join(" ", lexers.Take(lexers.Length - 1)), Context.Primitives).Calculate();
                answer = value * unitValue + " " + primUnit;
                Console.WriteLine(body + " is " + answer);
                return true;
            }
        }

        class PrimitiveSolver : Solver
        {
            public PrimitiveSolver(Context ctx)
                : base(ctx)
            {

            }
            public override bool Solve(string question, out string answer)
            {
                var qulifier = "how much is";
                if (!question.StartsWith(qulifier))
                {
                    answer = null;
                    return false;
                }
                var body = question.Substring(qulifier.Length + 1);
                var value = Roman.Parse(body, Context.Primitives).Calculate();
                answer = value.ToString();
                Console.WriteLine(body + " is " + answer);
                return true;
            }
        }

        public static void Run(string[] input)
        {
            Console.WriteLine("Thinking....");
            var ctx = new Context();
            var parsers = new Parser[]
            {
                new PrimitiveParser(ctx),
                new UnitParser(ctx),
                new QuestionParser(ctx)
            };
            var solvers = new Solver[]
            {
                new PrimitiveSolver(ctx),
                new UnitSolver(ctx)
            };
            foreach (var cmd in input)
            {
                foreach (var parser in parsers)
                {
                    try
                    {
                        if (parser.Parse(cmd))
                        {
                            break;
                        }
                    }
                    catch
                    {

                    }
                }
            }

            foreach (var cmd in ctx.Questions)
            {
                var solved = false;
                foreach (var solver in solvers)
                {
                    string answer = "";
                    try
                    {
                        if (solver.Solve(cmd, out answer))
                        {
                            solved = true;
                            break;
                        }
                    }
                    catch
                    {

                    }
                }
                if (!solved)
                {
                    Console.WriteLine("I have no idea what you are talking about.");
                }
            }
            Console.WriteLine("done.");
            Console.ReadKey();
        }
    }
}

Program.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Thoughtworks.Problems;

namespace Thoughtworks
{
    class Program
    {
        static void Main(string[] args)
        {
            using (TextReader reader = new StreamReader("Problems/Input"))
            {
                var lines = new List<string>();
                string line = null;
                do
                {
                    line = reader.ReadLine();
                    if (line == null)
                        break;
                    Console.WriteLine(line);
                    lines.Add(line);
                }
                while (line != null);
                ProblemOne.Run(lines.ToArray());
            }
            
        }
    }
}

Input,位于Problems目录中

glob is I
prok is V
pish is X
tegj is L
glob glob Silver is 34 Credits
glob prok Gold is 57800 Credits
pish pish Iron is 3910 Credits
how much is pish tegj glob glob ?
how much is glob prok ?
how many Credits is glob prok Silver ?
how many Credits is glob prok Gold ?
how many Credits is glob prok Iron ?
how much wood could a woodchuck chuck if a woodchuck could chuck wood ?
原文地址:https://www.cnblogs.com/ornithopter/p/3937978.html