• 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 ?
    
  • 相关阅读:
    说说毕业两年多的经历
    egret: if判断语句不能写在addEventListener监听事件外面吗?
    egret wing exml文件突然在设计和预览模式下不可见!
    egret:设置滚动视图、隐藏滚动条以及层级的问题
    egret:list网格布局
    egret 自动播放音乐问题:ios 自动播放音乐失效
    private static和public static的意义
    setTimeout()的第三个参数
    egret 学习之once()与addEventListener()
    egret 入门学习笔记之问题解决
  • 原文地址:https://www.cnblogs.com/ornithopter/p/3937978.html
Copyright © 2020-2023  润新知