ThoughtWorks 코드 도전-FizzBuzzWhizz

20914 단어 코드
오랫동안 글을 발표하지 않았는데, 오늘 한 문장을 보았다면접이 가장 어려운 IT회사의 ThoughtWorks 코드 도전-Fizz BuzzWhizz 게임(C#해법)
LZ의 2B 청년 코드를 보니 참혹하기 때문에 이런 문제에 대한 일반적인 사고를 탐구하기 위해 글을 쓴다.
원제:
Fizz Buzz Whizzz 당신은 체육 선생님입니다. 어떤 수업이 끝나기 5분 전에 게임을 하기로 결정했습니다.이때 100명의 학생이 수업을 하고 있었다.게임의 규칙은:
1. 당신은 먼저 세 개의 다른 특수수를 말하고, 요구는 반드시 한 자리수여야 한다. 예를 들어 3, 5, 7.
2. 모든 학생을 한 팀으로 만들어 순서대로 번호를 매긴다.
3. 학생이 숫자를 보고할 때 만약에 보고한 숫자가 첫 번째 특수수(3)의 배수라면 이 숫자를 말하지 말고 Fizz를 말해야 한다.만약 보고된 숫자가 두 번째 특수수(5)의 배수라면 버즈라고 한다.만약 보고된 숫자가 세 번째 특수수(7)의 배수라면 Whizz라고 해야 한다.
4. 학생이 숫자를 보고할 때 만약에 보고한 숫자가 두 개의 특수수의 배수인 경우에도 특수하게 처리해야 한다. 예를 들어 첫 번째 특수수와 두 번째 특수수의 배수라면 이 숫자를 말하지 말고 피자버즈라고 해야 한다.만약 동시에 세 개의 특수수의 배수라면, 피자 버즈 위즈라고 해야 한다.5. 학생이 숫자를 보고할 때 만약에 보고한 숫자에 첫 번째 특수수가 포함된다면 그 숫자를 말하지 말고 해당하는 단어를 말해야 한다. 예를 들어 이 예에서 첫 번째 특수수가 3이라면 13을 보고해야 하는 학생은 Fizz라고 말해야 한다.만약 숫자에 첫 번째 특수수가 포함된다면 규칙 3과 규칙 4를 무시한다. 예를 들어 35를 보고하려는 학생은 Fizz만 보고하고 BuzzWhizz는 보고하지 않는다.
 
간단해 보이는 제목이 그렇게 간단하지는 않다. 직접 쓰면 다음과 같다.
if, if , else if , if , for, [0] [1] [2]….
우리는 이 문제를 이해하자.
1. 당신은 먼저 세 개의 다른 특수수를 말하고, 요구는 반드시 한 자리수여야 한다. 예를 들어 3, 5, 7.
다른 세 개의 수는 반드시 한 자리수여야 한다. 이것들은 모두 검증 조건이다. 너는 알아차렸니?
2. 모든 학생을 한 팀으로 만들어 순서대로 번호를 매긴다.
생성 순서의 숫자.
3. 학생이 숫자를 보고할 때 만약에 보고한 숫자가 첫 번째 특수수(3)의 배수라면 이 숫자를 말하지 말고 Fizz를 말해야 한다.만약 보고된 숫자가 두 번째 특수수(5)의 배수라면 버즈라고 한다.만약 보고된 숫자가 세 번째 특수수(7)의 배수라면 Whizz라고 해야 한다.
규칙: 특정한 수의 배수라면 대응하는 값을 출력하고, 그렇지 않으면 숫자를 출력합니다.
4. 학생이 숫자를 보고할 때 만약에 보고한 숫자가 두 개의 특수수의 배수인 경우에도 특수하게 처리해야 한다. 예를 들어 첫 번째 특수수와 두 번째 특수수의 배수라면 이 숫자를 말하지 말고 피자버즈라고 해야 한다.만약 동시에 세 개의 특수수의 배수라면, 피자 버즈 위즈라고 해야 한다.
규칙: 여러 개의 특수수의 배수라면 모든 대응값을 출력합니다.
5. 학생이 숫자를 보고할 때 만약에 보고한 숫자에 첫 번째 특수수가 포함된다면 그 숫자를 말하지 말고 해당하는 단어를 말해야 한다. 예를 들어 이 예에서 첫 번째 특수수가 3이라면 13을 보고해야 하는 학생은 Fizz라고 말해야 한다.만약 숫자에 첫 번째 특수수가 포함된다면 규칙 3과 규칙 4를 무시한다. 예를 들어 35를 보고하려는 학생은 Fizz만 보고하고 BuzzWhizz는 보고하지 않는다.
규칙: 첫 번째 특수 숫자를 포함하면 첫 번째 특수 숫자에 대응하는 값만 출력합니다.
 
OK, 우리가 어떻게 해야 할지 생각해 보자...
 
우리는 다음 제목을 추상적으로 이해한다. "당신에게 한 무더기의 숫자를 입력한 다음에 일정한 규칙에 따라parse를 진행하고parse의 결과를 출력합니다."
그래서 이 제목에서 고찰하고자 하는 것은 당신이 어떻게 이런 규칙을 정의하고 어떻게 이런 규칙을 응용하며 어떻게 Parse를 해야 하는가?
 
규칙 Rule을 살펴보겠습니다.
Rule, 우선 순위가 있고 입력에 대한 패스를 할 수 있으며, 패스에 대응하는 사전이 필요합니다.
그래서 Rule은 이렇게 한다.
abstract class Rule
    {
        public abstract int Priority { get; }

        public Dictionary<int, string> SpecialDictionary { get; set; }

        public Rule(Dictionary<int, string> specialDictionary)
        {
            this.SpecialDictionary = specialDictionary;
        }

        public bool ParseNum(int num, ref string result)
        {
            if ((SpecialDictionary != null) && (SpecialDictionary.Count > 0))
            {
                return ParseNumCore(num, ref result);
            }
            else
            {
                return false;
            }
        }

        protected abstract bool ParseNumCore(int num, ref string result);
    }

 
이어서 Rule3: 만약에 특정한 수의 배수라면 대응하는 값을 출력해야 한다. 그렇지 않으면 출력 숫자를 출력하고 출력 숫자는 내가 가장 바깥쪽에 놓고 처리한다. 물론 필요하면 Rule2를 쓸 수도 있다.
class Rule3 : Rule
    {
        public Rule3(Dictionary<int, string> specialDictionary)
            : base(specialDictionary)
        {
        }

        public override int Priority
        {
            get { return 3; }
        }

        protected override bool ParseNumCore(int num, ref string result)
        {
            foreach (var special in SpecialDictionary)
            {
                if (num % special.Key == 0)
                {
                    result = special.Value;
                    return true;
                }
            }

            return false;
        }
    }

 
Rule4: 특수수의 배수가 여러 개인 경우 해당 값을 모두 내보냅니다.
class Rule4 : Rule
    {
        public Rule4(Dictionary<int, string> specialDictionary)
            : base(specialDictionary)
        {
        }

        public override int Priority
        {
            get { return 4; }
        }

        protected override bool ParseNumCore(int num, ref string result)
        {
            List<string> matches = new List<string>();

            foreach (var special in SpecialDictionary)
            {
                if (num % special.Key == 0)
                {
                    matches.Add(special.Value);
                }
            }

            if (matches.Count > 1)
            {
                result = string.Join("", matches);
                return true;
            }
            else
            {
                return false;
            }
        }
    }

 
Rule5: 첫 번째 특수 숫자가 포함된 경우 첫 번째 특수 숫자에 해당하는 값만 출력됩니다.
class Rule5 : Rule
    {
        public Rule5(Dictionary<int, string> specialDictionary)
            : base(specialDictionary)
        {
        }

        public override int Priority
        {
            get { return 5; }
        }

        protected override bool ParseNumCore(int num, ref string result)
        {
            if (SpecialDictionary.Count > 0)
            {
                var firstSpecial = SpecialDictionary.First();
                if (num.ToString().Contains(firstSpecial.Key.ToString()))
                {
                    result = firstSpecial.Value;
                    return true;
                }
            }

            return false;
        }
    }

 
다음: 가장 중요한 것은 바로 Parse 논리입니다. 이 Rule을 어떻게 호출해야 할지 생각해 보세요(visitor?):
foreach (var student in studentNums)
                    {
                        string parseResult = student.ToString();
                        foreach (Rule rule in rules)
                        {
                            if (rule.ParseNum(student, ref parseResult))
                            {
                                break;
                            }
                        }

                        Console.WriteLine(parseResult);
                    }

 
다음은 전체 코드입니다.
private static void FizzBuzz()
        {
            bool isValidInput = false;
            do
            {
                Console.WriteLine("please input three numbers which is units digit, use ',' division ");
                string[] inputNums = Console.ReadLine().Split(',');

                if (ValidSpecialInput(inputNums))
                {
                    isValidInput = true;

                    // create special dictionary to parse the students nums.
                    Dictionary<int, string> special = new Dictionary<int, string>();
                    special.Add(Int32.Parse(inputNums[0]), "Fizz");
                    special.Add(Int32.Parse(inputNums[1]), "Buzz");
                    special.Add(Int32.Parse(inputNums[2]), "Whizz");

                    // get students nums.
                    int studentsCount = 100;
                    var studentNums = Enumerable.Range(1, studentsCount);

                    // create rules to parse.
                    var rules = new List<Rule>() 
                    { 
                        new Rule5(special),
                        new Rule4(special), 
                        new Rule3(special), 
                    }.OrderByDescending(r => r.Priority);

                    // parse logic.
                    foreach (var student in studentNums)
                    {
                        string parseResult = student.ToString();
                        foreach (Rule rule in rules)
                        {
                            if (rule.ParseNum(student, ref parseResult))
                            {
                                break;
                            }
                        }

                        Console.WriteLine(parseResult);
                    }

                    Console.ReadLine();
                }
                else
                {
                    Console.WriteLine("the input is not valid.");
                }
            }
            while (isValidInput == false);
        }

        private static bool ValidSpecialInput(string[] specialInputs)
        {
            bool result = false;
            if (specialInputs.Length == 3)
            {
                return specialInputs.All(input =>
                    {
                        int num = 0;
                        return Int32.TryParse(input, out num) && (num > 0) && (num < 10);
                    });
            }

            return result;
        }

 
몇 가지 후속 사고:
1: 만약 입력한 것이 세 개가 아니라 네 개, 다섯 개의 스페셜이라면 어떻게 고쳐야 합니까?
2:학생 수가 100명이 아니면 1000명?
3: Rule3을 제한적으로 고려하고 그 다음에 Rule4, Rule5를 고려하면 어떻게 고쳐야 합니까?
4: 만약 또 다른 제한 조건이 있다면: 예를 들어 숫자가 소수라면 대응하는 값을 반순으로 출력하면 어떻게 처리합니까?
5: 숫자가 아닌 문자열을 입력하면 어떻게 처리해야 합니까?
 
전체 소스 다운로드:http://files.cnblogs.com/LoveJenny/FizzBuzz.7z

좋은 웹페이지 즐겨찾기