Автономер на четырех языках. Часть 2


    Что такое 8037?


    Это небольшая математическая игра: вы идете по улице, и просто считаете сумму цифр в автомобильных номерах. Эту игру мы реализуем в консольном варианте, на четырех языках: Swift, Objective-C, Java и C#.


    В первой части мы написали часть приложения, которая спрашивает у пользователя ответ пока тот не введет слово для выхода из приложения. Как резонно заметили в комментариях, в таком случае правильнее все-таки использовать цикл вместо рекурсии. Поэтому первое, что мы сделаем — уберем рекурсию и напишем вместо нее цикл в методе startGame.


    Swift:


    func startGame() {
        var inputWord: String
        repeat {
            print(GreetingMessage.replacingOccurrences(of: ExitWordPlaceholder, with: self.exitWord))
            inputWord = readLine() ?? ""
        } while check(inputWord: inputWord)
    }
    
    private func check(inputWord: String) -> Bool {
        let isExitWord = (inputWord == self.exitWord)
        print(isExitWord ? GoodByeMessage : InputAcceptMessage.replacingOccurrences(of: InputWordPlaceholder, with: inputWord))
        return !isExitWord
    }

    Objective-C:


    - (void)startGame {
        NSString *inputWord;
    
        do {
            NSLog(GreetingMessage, self.exitWord);
            inputWord = [self readLine];
        } while ([self checkInputWord:inputWord]);
    }
    
    - (BOOL)checkInputWord:(NSString *)inputWord {
        BOOL isExitWord = [inputWord isEqualToString:self.exitWord];
        isExitWord ? NSLog(@"%@", GoodByeMessage) : NSLog(InputAcceptMessage, inputWord);
        return !isExitWord;
    }

    Java:


    void startGame() {
        String inputWord;
    
        do {
            System.out.println(String.format(GreetingMessage, exitWord));
            inputWord = readLine();
        } while (checkInputWord(inputWord));
    }
    
    private boolean checkInputWord(String inputWord) {
        boolean isExitWord = inputWord.equals(exitWord);
        System.out.println(isExitWord ? GoodByeMessage : String.format(InputAcceptMessage, inputWord));
        return !isExitWord;
    }

    C#:


    public void startGame()
    {
        string inputWord;
        do
        {
            Console.WriteLine(string.Format(GreetingMessage, exitWord));
            inputWord = Console.ReadLine();
        }
        while (checkInputWord(inputWord));
    }
    
    bool checkInputWord(string inputWord)
    {
        bool isExitWord = inputWord.Equals(exitWord);
        Console.WriteLine(isExitWord ? GoodByeMessage : string.Format(InputAcceptMessage, inputWord));
        return !isExitWord;
    }

    Ну а дальше — мы, наконец, создадим класс нашей игры (как вы помните, мы специально создавали интерфейс (протокол) Game, который мы должны реализовать в нашем классе):


    class Game8037: Game {
    
        // MARK: - Game
    
        func greet(with exitWord: String) {
    
        }
    
        func check(userAnswer: String) {
    
        }
    
    }

    Оставим пока что методы протокола пустыми, и займемся организацией функциональности класса. В первую очередь нам понадобится enum с уровнями сложности:


    private enum Level: String {
        case easy
        case normal
        case hard1
        case hard2
    
        func forSelect() -> String {
            return LevelForSelect.replacingOccurrences(of: LevelPlaceholder, with: self.rawValue)
                    .replacingOccurrences(of: LevelNumberPlaceholder, with: "\(self.hashValue+1)")
        }
    }

    В enum мы добавили метод forSelect() он будет для каждого уровня сложности создавать строку вида 1 - easy (номер уровня и его название). Это нам пригодится для предложения пользователю выбрать уровень сложности. Дальше нам понадобятся два свойства которые будут содержать в себе выбранный уровень и правильный ответ на задание:


    private var level: Level
    private var result: UInt32

    Теперь мы можем написать наш инициализатор:


    init?() {
        self.result = 0
        let levels = Level.easy.forSelect() + Level.normal.forSelect() + Level.hard1.forSelect() + Level.hard2.forSelect()
        print(StartGreeting.replacingOccurrences(of: LevelsPlaceholder, with: levels))
    
        let selectedLevel = readLine() ?? ""
        switch selectedLevel {
        case "\(Level.easy.hashValue+1)", Level.easy.rawValue:
            self.level = .easy
        case "\(Level.normal.hashValue+1)", Level.normal.rawValue:
            self.level = .normal
        case "\(Level.hard1.hashValue+1)", Level.hard1.rawValue:
            self.level = .hard1
        case "\(Level.hard2.hashValue+1)", Level.hard2.rawValue:
            self.level = .hard2
        default:
            print(ErrorLevelMessage)
            return nil
        }
    }

    Как видите, для начала, мы задаем значение по-умолчанию для свойства result (оно у нас пока что хранит в себе ноль). Дальше мы формируем информационную строку для пользователя о необходимости выбрать уровень сложности. В консоли это выглядит так:



    Ну и потом, мы считываем введенный пользователем уровень сложности и, если он корректен — сохраняем его в свойстве level.


    Теперь нам понадобится метод расчета правильного ответа на задание в зависимости от уровня:


    private func result(with level: Level, and randomizer: Randomizer) -> UInt32 {
        let result: UInt32
    
        switch level {
        case .easy:
            result = randomizer.firstNumber + randomizer.secondNumber + randomizer.thirdNumber + randomizer.fourthNumber
        case .normal:
            result = randomizer.firstNumber*10 + randomizer.secondNumber + randomizer.thirdNumber*10 + randomizer.fourthNumber
        case .hard1:
            let firstNumber = (randomizer.firstNumber == 0) ? 1 : randomizer.firstNumber
            let secondNumber = (randomizer.secondNumber == 0) ? 1 : randomizer.secondNumber
            let thirdNumber = (randomizer.thirdNumber == 0) ? 1 : randomizer.thirdNumber
            let fourthNumber = (randomizer.fourthNumber == 0) ? 1 : randomizer.fourthNumber
            result = firstNumber * secondNumber * thirdNumber * fourthNumber
        case .hard2:
            result = (randomizer.firstNumber*10 + randomizer.secondNumber) * (randomizer.thirdNumber*10 + randomizer.fourthNumber)
        }
    
        return result
    }

    И, наконец, нужно реализовать методы протокола Game.
    Метод greet(with exitWord: String):


    func greet(with exitWord: String) {
        let randomizer = Randomizer()
        self.result = self.result(with: self.level, and: randomizer)
        let task = BaseGreeting.replacingOccurrences(of: FirstNumberPlaceholder, with: "\(randomizer.firstNumber)")
                .replacingOccurrences(of: SecondNumberPlaceholder, with: "\(randomizer.secondNumber)")
                .replacingOccurrences(of: ThirdNumberPlaceholder, with: "\(randomizer.thirdNumber)")
                .replacingOccurrences(of: FourthNumberPlaceholder, with: "\(randomizer.fourthNumber)")
    
        print(TaskMessage.replacingOccurrences(of: TaskPlaceholder, with: task)
                .replacingOccurrences(of: ExitWordPlaceholder, with: exitWord))
    }

    Тут мы создаем новый Randomizer и рассчитываем правильный ответ для текущего уровня сложности. После чего показываем пользователю задание.


    Метод check(userAnswer: String):


    func check(userAnswer: String) {
        if self.result == UInt32(userAnswer) {
            print(CorrectMessage)
        } else {
            print(WrongMessage)
        }
    }

    Тут все просто: мы просто сравниваем правильный ответ с тем, что ввел пользователь и выводим информационное сообщение на экран.


    Итак полный текст класса в Swift выглядит так:


    private let LevelsPlaceholder = "{levels}"
    private let LevelNumberPlaceholder = "{levelNumber}"
    private let LevelPlaceholder = "{level}"
    
    private let FirstNumberPlaceholder = "{firstNumber}"
    private let SecondNumberPlaceholder = "{secondNumber}"
    private let ThirdNumberPlaceholder = "{thirdNumber}"
    private let FourthNumberPlaceholder = "{fourthNumber}"
    
    private let ExitWordPlaceholder = "{exitWord}"
    private let TaskPlaceholder = "{taskPlaceholder}"
    
    private let StartGreeting = "Hello, let's play. Please select difficulty level:\(LevelsPlaceholder)"
    private let LevelForSelect = "\n\(LevelNumberPlaceholder) - \(LevelPlaceholder)"
    private let BaseGreeting = "\(FirstNumberPlaceholder) \(SecondNumberPlaceholder) \(ThirdNumberPlaceholder) \(FourthNumberPlaceholder)"
    private let TaskMessage = "The next task is \(TaskPlaceholder)\n(enter \"\(ExitWordPlaceholder)\" for exit)"
    private let CorrectMessage = "Absolutely right.\n"
    private let WrongMessage = "Sorry, you made a mistake. Try again.\n"
    private let ErrorLevelMessage = "Sorry, you have selected wrong level. Good bye.\n"
    
    class Game8037: Game {
    
        private enum Level: String {
            case easy
            case normal
            case hard1
            case hard2
    
            func forSelect() -> String {
                return LevelForSelect.replacingOccurrences(of: LevelPlaceholder, with: self.rawValue)
                    .replacingOccurrences(of: LevelNumberPlaceholder, with: "\(self.hashValue+1)")
            }
        }
    
        private var level: Level
        private var result: UInt32
    
        init?() {
            self.result = 0
            let levels = Level.easy.forSelect() + Level.normal.forSelect() + Level.hard1.forSelect() + Level.hard2.forSelect()
            print(StartGreeting.replacingOccurrences(of: LevelsPlaceholder, with: levels))
    
            let selectedLevel = readLine() ?? ""
            switch selectedLevel {
            case "\(Level.easy.hashValue+1)", Level.easy.rawValue:
                self.level = .easy
            case "\(Level.normal.hashValue+1)", Level.normal.rawValue:
                self.level = .normal
            case "\(Level.hard1.hashValue+1)", Level.hard1.rawValue:
                self.level = .hard1
            case "\(Level.hard2.hashValue+1)", Level.hard2.rawValue:
                self.level = .hard2
            default:
                print(ErrorLevelMessage)
                return nil
            }
        }
    
        private func result(with level: Level, and randomizer: Randomizer) -> UInt32 {
            let result: UInt32
    
            switch level {
            case .easy:
                result = randomizer.firstNumber + randomizer.secondNumber + randomizer.thirdNumber + randomizer.fourthNumber
            case .normal:
                result = randomizer.firstNumber*10 + randomizer.secondNumber + randomizer.thirdNumber*10 + randomizer.fourthNumber
            case .hard1:
                let firstNumber = (randomizer.firstNumber == 0) ? 1 : randomizer.firstNumber
                let secondNumber = (randomizer.secondNumber == 0) ? 1 : randomizer.secondNumber
                let thirdNumber = (randomizer.thirdNumber == 0) ? 1 : randomizer.thirdNumber
                let fourthNumber = (randomizer.fourthNumber == 0) ? 1 : randomizer.fourthNumber
                result = firstNumber * secondNumber * thirdNumber * fourthNumber
            case .hard2:
                result = (randomizer.firstNumber*10 + randomizer.secondNumber) * (randomizer.thirdNumber*10 + randomizer.fourthNumber)
            }
    
            return result
        }
    
        // MARK: - Game
    
        func greet(with exitWord: String) {
            let randomizer = Randomizer()
            self.result = self.result(with: self.level, and: randomizer)
            let task = BaseGreeting.replacingOccurrences(of: FirstNumberPlaceholder, with: "\(randomizer.firstNumber)")
                .replacingOccurrences(of: SecondNumberPlaceholder, with: "\(randomizer.secondNumber)")
                .replacingOccurrences(of: ThirdNumberPlaceholder, with: "\(randomizer.thirdNumber)")
                .replacingOccurrences(of: FourthNumberPlaceholder, with: "\(randomizer.fourthNumber)")
    
            print(TaskMessage.replacingOccurrences(of: TaskPlaceholder, with: task)
                .replacingOccurrences(of: ExitWordPlaceholder, with: exitWord))
        }
    
        func check(userAnswer: String) {
            if self.result == UInt32(userAnswer) {
                print(CorrectMessage)
            } else {
                print(WrongMessage)
            }
        }
    
    }

    Реализация этого же класса в Objective-C:


    // файл заголовка Game8037.h
    @interface Game8037 : NSObject <Game>
    
    @end
    
    // файл реализации GameStart.m
    const NSString *EasyLevelNumber = @"1";
    const NSString *NormalLevelNumber = @"2";
    const NSString *Hard1LevelNumber = @"3";
    const NSString *Hard2LevelNumber = @"4";
    
    const NSString *EasyLevelName = @"easy";
    const NSString *NormalLevelName = @"normal";
    const NSString *Hard1LevelName = @"hard1";
    const NSString *Hard2LevelName = @"hard2";
    
    const NSString *StartGreeting = @"Hello, let's play. Please select difficulty level:%@";
    const NSString *LevelForSelect = @"\n%@ - %@";
    const NSString *BaseGreeting = @"%i %i %i %i";
    const NSString *TaskMessage = @"The next task is %@\n(enter \"%@\" for exit)";
    const NSString *CorrectMessage = @"Absolutely right.\n";
    const NSString *WrongMessage = @"Sorry, you made a mistake. Try again.\n";
    const NSString *ErrorLevelMessage = @"Sorry, you have selected wrong level. Good bye.\n";
    
    typedef enum {
        LevelEasy,
        LevelNormal,
        LevelHard1,
        LevelHard2
    } Level;
    
    @interface Game8037()
    
    @property (assign, nonatomic) Level level;
    @property (assign, nonatomic) NSInteger result;
    
    @end
    
    @implementation Game8037
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            self.result = 0;
            NSString *levels = [NSString stringWithFormat:@"%@%@%@%@",
                                [self levelForSelect:LevelEasy],
                                [self levelForSelect:LevelNormal],
                                [self levelForSelect:LevelHard1],
                                [self levelForSelect:LevelHard2]];
    
            NSLog(StartGreeting, levels);
            NSString *selectedLevel = [self readLine];
            if ([selectedLevel isEqualToString:EasyLevelNumber] || [selectedLevel isEqualToString:EasyLevelName]) {
                self.level = LevelEasy;
            } else if ([selectedLevel isEqualToString:NormalLevelNumber] || [selectedLevel isEqualToString:NormalLevelName]) {
                self.level = LevelNormal;
            } else if ([selectedLevel isEqualToString:Hard1LevelNumber] || [selectedLevel isEqualToString:Hard1LevelName]) {
                self.level = LevelHard1;
            } else if ([selectedLevel isEqualToString:Hard2LevelNumber] || [selectedLevel isEqualToString:Hard2LevelName]) {
                self.level = LevelHard2;
            } else {
                NSLog(@"%@", ErrorLevelMessage);
                return nil;
            }
        }
        return self;
    }
    
    - (NSString *)levelForSelect:(Level)level {
        NSString *levelNumber;
        NSString *levelName;
    
        switch (level) {
            case LevelEasy:
                levelNumber = EasyLevelNumber;
                levelName = EasyLevelName;
                break;
            case LevelNormal:
                levelNumber = NormalLevelNumber;
                levelName = NormalLevelName;
                break;
            case LevelHard1:
                levelNumber = Hard1LevelNumber;
                levelName = Hard1LevelName;
                break;
            case LevelHard2:
                levelNumber = Hard2LevelNumber;
                levelName = Hard2LevelName;
                break;
        }
    
        return [NSString stringWithFormat:LevelForSelect, levelNumber, levelName];
    }
    
    - (NSInteger)resultWithLevel:(Level)level andRandomizer:(Randomizer *)randomizer {
        NSInteger result = 0;
    
        switch (level) {
            case LevelEasy:
                result = randomizer.firstNumber + randomizer.secondNumber + randomizer.thirdNumber + randomizer.fourthNumber;
                break;
            case LevelNormal:
                result = randomizer.firstNumber*10 + randomizer.secondNumber + randomizer.thirdNumber*10 + randomizer.fourthNumber;
                break;
            case LevelHard1:
                result = (randomizer.firstNumber == 0 ? 1 : randomizer.firstNumber) * (randomizer.secondNumber == 0 ? 1 : randomizer.secondNumber) * (randomizer.thirdNumber == 0 ? 1 : randomizer.thirdNumber) * (randomizer.fourthNumber == 0 ? 1 : randomizer.fourthNumber);
                break;
            case LevelHard2:
                result = (randomizer.firstNumber*10 + randomizer.secondNumber) * (randomizer.thirdNumber*10 + randomizer.fourthNumber);
                break;
        }
    
        return result;
    }
    
    - (NSString *)descriptionOfLevel:(Level)level {
        NSString *result = @"";
    
        switch (level) {
            case LevelEasy:
                result = EasyLevelName;
                break;
            case LevelNormal:
                result = NormalLevelName;
                break;
            case LevelHard1:
                result = Hard1LevelName;
                break;
            case LevelHard2:
                result = Hard2LevelName;
                break;
        }
    
        return result;
    }
    
    - (NSString *)readLine {
        char inputValue;
        scanf("%s", &inputValue);
        return [NSString stringWithUTF8String:&inputValue];
    }
    
    #pragma mark - Game
    
    - (void)greetWithExitWord:(NSString *)exitWord {
        Randomizer *randomizer = [[Randomizer alloc] init];
        self.result = [self resultWithLevel:self.level andRandomizer:randomizer];
        NSString *task = [NSString stringWithFormat:BaseGreeting,
                          randomizer.firstNumber,
                          randomizer.secondNumber,
                          randomizer.thirdNumber,
                          randomizer.fourthNumber];
    
        NSLog(TaskMessage, task, exitWord);
    }
    
    - (void)checkUserAnswer:(NSString *)userAnswer {
        if (self.result == [userAnswer integerValue]) {
            NSLog(@"%@", CorrectMessage);
        } else {
            NSLog(@"%@", WrongMessage);
        }
    }
    
    @end

    Java:


    public class Game8037 implements Game {
    
        private static final String EasyLevelNumber = "1";
        private static final String NormalLevelNumber = "2";
        private static final String Hard1LevelNumber = "3";
        private static final String Hard2LevelNumber = "4";
    
        private static final String EasyLevelName = "easy";
        private static final String NormalLevelName = "normal";
        private static final String Hard1LevelName = "hard1";
        private static final String Hard2LevelName = "hard2";
    
        private static final String StartGreeting = "Hello, let's play. Please select difficulty level:%s";
        private static final String LevelForSelect = "\n%s - %s";
        private static final String BaseGreeting = "%s %s %s %s";
        private static final String TaskMessage = "The next task is %s\n(enter \"%s\" for exit)";
        private static final String CorrectMessage = "Absolutely right.\n";
        private static final String WrongMessage = "Sorry, you made a mistake. Try again.\n";
        private static final String ErrorLevelMessage = "Sorry, you have selected wrong level. Good bye.\n";
    
        private enum Level {
            Easy {
                public String toString() {
                    return EasyLevelName;
                }
            },
            Normal {
                public String toString() {
                    return NormalLevelName;
                }
            },
            Hard1 {
                public String toString() {
                    return Hard1LevelName;
                }
            },
            Hard2 {
                public String toString() {
                    return Hard2LevelName;
                }
            }
        }
    
        private Level level;
        private int result;
    
        private Game8037(Level level) {
            this.level = level;
            this.result = 0;
        }
    
        @Nullable
        public static Game8037 Create() {
            String levels = String.format("%s%s%s%s", levelForSelect(Level.Easy), levelForSelect(Level.Normal), levelForSelect(Level.Hard1), levelForSelect(Level.Hard2));
            System.out.println(String.format(StartGreeting, levels));
    
            Game8037 game8037;
    
            String selectedLevel = readLine();
            switch (selectedLevel) {
                case EasyLevelNumber:
                case EasyLevelName:
                    game8037 = new Game8037(Level.Easy);
                    break;
                case NormalLevelNumber:
                case NormalLevelName:
                    game8037 = new Game8037(Level.Normal);
                    break;
                case Hard1LevelNumber:
                case Hard1LevelName:
                    game8037 = new Game8037(Level.Hard1);
                    break;
                case Hard2LevelNumber:
                case Hard2LevelName:
                    game8037 = new Game8037(Level.Hard2);
                    break;
                default:
                    game8037 = null;
                    System.out.println(ErrorLevelMessage);
                    break;
            }
    
            return game8037;
        }
    
        private static String levelForSelect(Level level) {
            String levelNumber = "";
            String levelName = "";
    
            switch (level) {
                case Easy:
                    levelNumber = EasyLevelNumber;
                    levelName = EasyLevelName;
                    break;
                case Normal:
                    levelNumber = NormalLevelNumber;
                    levelName = NormalLevelName;
                    break;
                case Hard1:
                    levelNumber = Hard1LevelNumber;
                    levelName = Hard1LevelName;
                    break;
                case Hard2:
                    levelNumber = Hard2LevelNumber;
                    levelName = Hard2LevelName;
                    break;
            }
    
            return String.format(LevelForSelect, levelNumber, levelName);
        }
    
        private int resultWithLevelAndRandomizer(Level level, Randomizer randomizer) {
            int result = 0;
    
            switch (level) {
                case Easy:
                    result = randomizer.firstNumber + randomizer.secondNumber + randomizer.thirdNumber + randomizer.fourthNumber;
                    break;
                case Normal:
                    result = randomizer.firstNumber*10 + randomizer.secondNumber + randomizer.thirdNumber*10 + randomizer.fourthNumber;
                    break;
                case Hard1:
                    int firstNumber = (randomizer.firstNumber == 0) ? 1 : randomizer.firstNumber;
                    int secondNumber = (randomizer.secondNumber == 0) ? 1 : randomizer.secondNumber;
                    int thirdNumber = (randomizer.thirdNumber == 0) ? 1 : randomizer.thirdNumber;
                    int fourthNumber = (randomizer.fourthNumber == 0) ? 1 : randomizer.fourthNumber;
                    result = firstNumber * secondNumber * thirdNumber * fourthNumber;
                    break;
                case Hard2:
                    result = (randomizer.firstNumber*10 + randomizer.secondNumber) * (randomizer.thirdNumber*10 + randomizer.fourthNumber);
                    break;
            }
    
            return result;
        }
    
        static private String readLine() {
            java.util.Scanner scanner = new java.util.Scanner(System.in);
            return scanner.next();
        }
    
        @Override
        public void greet(String exitWord) {
            Randomizer randomizer = new Randomizer();
            result = resultWithLevelAndRandomizer(level, randomizer);
    
            String task = String.format(BaseGreeting, randomizer.firstNumber, randomizer.secondNumber, randomizer.thirdNumber, randomizer.fourthNumber);
            System.out.println(String.format(TaskMessage, task, exitWord));
        }
    
        @Override
        public void checkUserAnswer(String userAnswer) {
            int answer;
    
            try {
                answer = Integer.parseInt(userAnswer);
            } catch (Exception e) {
                System.out.println(WrongMessage);
                return;
            }
    
            if (result == answer) {
                System.out.println(CorrectMessage);
            } else {
                System.out.println(WrongMessage);
            }
        }
    }

    C#:


    public class Game8037 : IGame
    {
        const string EasyLevelNumber = "1";
        const string NormalLevelNumber = "2";
        const string Hard1LevelNumber = "3";
        const string Hard2LevelNumber = "4";
    
        const string EasyLevelName = "easy";
        const string NormalLevelName = "normal";
        const string Hard1LevelName = "hard1";
        const string Hard2LevelName = "hard2";
    
        const string StartGreeting = "Hello, let's play. Please select difficulty level:{0}";
        const string LevelForSelect = "\n{0} - {1}";
        const string BaseGreeting = "{0} {1} {2} {3}";
        const string TaskMessage = "The next task is {0}\n(enter \"{1}\" for exit)";
        const string CorrectMessage = "Absolutely right.\n";
        const string WrongMessage = "Sorry, you made a mistake. Try again.\n";
        const string ErrorLevelMessage = "Sorry, you have selected wrong level. Good bye.\n";
    
        enum Level { Easy, Normal, Hard1, Hard2 };
    
        Level level;
        int result;
    
        private Game8037(Level level)
        {
            this.level = level;
            result = 0;
        }
    
        public static Game8037 Create()
        {
            string levels = string.Format("{0}{1}{2}{3}", levelForSelect(Level.Easy), levelForSelect(Level.Normal), levelForSelect(Level.Hard1), levelForSelect(Level.Hard2));
            Console.WriteLine(string.Format(StartGreeting, levels));
    
            Game8037 game8037;
    
            string selectedLevel = Console.ReadLine();
            switch (selectedLevel)
            {
                case EasyLevelNumber:
                case EasyLevelName:
                    game8037 = new Game8037(Level.Easy);
                    break;
                case NormalLevelNumber:
                case NormalLevelName:
                    game8037 = new Game8037(Level.Normal);
                    break;
                case Hard1LevelNumber:
                case Hard1LevelName:
                    game8037 = new Game8037(Level.Hard1);
                    break;
                case Hard2LevelNumber:
                case Hard2LevelName:
                    game8037 = new Game8037(Level.Hard2);
                    break;
                default:
                    game8037 = null;
                    Console.WriteLine(ErrorLevelMessage);
                    break;
            }
    
            return game8037;
        }
    
        static string levelForSelect(Level level)
        {
            string levelNumber = "";
            string levelName = "";
    
            switch (level)
            {
                case Level.Easy:
                    levelNumber = EasyLevelNumber;
                    levelName = EasyLevelName;
                    break;
                case Level.Normal:
                    levelNumber = NormalLevelNumber;
                    levelName = NormalLevelName;
                    break;
                case Level.Hard1:
                    levelNumber = Hard1LevelNumber;
                    levelName = Hard1LevelName;
                    break;
                case Level.Hard2:
                    levelNumber = Hard2LevelNumber;
                    levelName = Hard2LevelName;
                    break;
            }
    
            return string.Format(LevelForSelect, levelNumber, levelName);
        }
    
        int resultWithLevelAndRandomizer(Level level, Randomizer randomizer)
        {
            int result = 0;
    
            switch (level)
            {
                case Level.Easy:
                    result = randomizer.firstNumber + randomizer.secondNumber + randomizer.thirdNumber + randomizer.fourthNumber;
                    break;
                case Level.Normal:
                    result = randomizer.firstNumber * 10 + randomizer.secondNumber + randomizer.thirdNumber * 10 + randomizer.fourthNumber;
                    break;
                case Level.Hard1:
                    int firstNumber = (randomizer.firstNumber == 0) ? 1 : randomizer.firstNumber;
                    int secondNumber = (randomizer.secondNumber == 0) ? 1 : randomizer.secondNumber;
                    int thirdNumber = (randomizer.thirdNumber == 0) ? 1 : randomizer.thirdNumber;
                    int fourthNumber = (randomizer.fourthNumber == 0) ? 1 : randomizer.fourthNumber;
                    result = firstNumber* secondNumber * thirdNumber * fourthNumber;
                    break;
                case Level.Hard2:
                    result = (randomizer.firstNumber * 10 + randomizer.secondNumber) * (randomizer.thirdNumber * 10 + randomizer.fourthNumber);
                    break;
            }
    
            return result;
        }
    
        string descriptionOfLevel(Level level)
        {
            string result = "";
    
            switch (level)
            {
                case Level.Easy:
                    result = "easy";
                    break;
                case Level.Normal:
                    result = "normal";
                    break;
                case Level.Hard1:
                    result = "hard1";
                    break;
                case Level.Hard2:
                    result = "hard2";
                    break;
            }
    
            return result;
        }
    
        public void greet(string exitWord)
        {
            Randomizer randomizer = new Randomizer();
            result = resultWithLevelAndRandomizer(level, randomizer);
    
            string task = string.Format(BaseGreeting, randomizer.firstNumber, randomizer.secondNumber, randomizer.thirdNumber, randomizer.fourthNumber);
            Console.WriteLine(string.Format(TaskMessage, task, exitWord));
        }
    
        public void checkUserAnswer(string userAnswer)
        {
            int answer;
    
            try
            {
                answer = int.Parse(userAnswer);
            }
            catch
            {
                Console.WriteLine(WrongMessage);
                return;
            }
    
            if (result == answer)
            {
                Console.WriteLine(CorrectMessage);
            }
            else
            {
                Console.WriteLine(WrongMessage);
            }
        }
    }

    В Java и C# есть нюанс при создании объекта класса Game8037. Дело в том, что здесь нет failable инициализаторов, поэтому мы воспользовались статическим методом для создания объекта.


    Нам остается добавить создание нашей игры в класс GameStart и воспользоваться методами greet(...) и check(...). Теперь класс GameStart выглядит так.


    Swift:


    class GameStart {
    
        private var exitWord: String
        private var game: Game
    
        init?(with exitWord: String) {
            self.exitWord = exitWord
            if let game = Game8037() {
                self.game = game
            } else {
                return nil
            }
        }
    
        func startGame() {
            var inputWord: String
            repeat {
                self.game.greet(with: self.exitWord)
                inputWord = readLine() ?? ""
            } while check(inputWord: inputWord)
        }
    
        private func check(inputWord: String) -> Bool {
            let isExitWord = (inputWord == self.exitWord)
            if isExitWord {
                print(GoodByeMessage)
            } else {
                self.game.check(userAnswer: inputWord)
            }
            return !isExitWord
        }
    
    }

    Objective-C:


    @interface GameStart()
    
    @property (strong, nonatomic) NSString *exitWord;
    @property (strong, nonatomic) id<Game> game;
    
    @end
    
    @implementation GameStart
    
    - (instancetype)initWithExitWord:(NSString *)exitWord {
        self = [super init];
        if (self) {
            self.exitWord = exitWord;
            self.game = [[Game8037 alloc] init];
        }
        return self;
    }
    
    - (void)startGame {
        if (self.game) {
            NSString *inputWord;
    
            do {
                [self.game greetWithExitWord:self.exitWord];
                inputWord = [self readLine];
            } while ([self checkInputWord:inputWord]);
        }
    }
    
    - (BOOL)checkInputWord:(NSString *)inputWord {
        BOOL isExitWord = [inputWord isEqualToString:self.exitWord];
        if (isExitWord) {
            NSLog(@"%@", GoodByeMessage);
        } else {
            [self.game checkUserAnswer:inputWord];
        }
        return !isExitWord;
    }
    
    - (NSString *)readLine {
        char inputValue;
        scanf("%s", &inputValue);
        return [NSString stringWithUTF8String:&inputValue];
    }
    
    @end

    Java:


    public class GameStart {
    
        private static final String GreetingMessage = "Please enter your answer (enter \"%s\" for exit):";
        private static final String InputAcceptMessage = "You entered \"%s\".\n";
        private static final String GoodByeMessage = "Good bye.\n";
    
        private String exitWord;
        private Game game;
    
        public GameStart(String exitWord) {
            this.exitWord = exitWord;
            this.game = Game8037.Create();
        }
    
        void startGame() {
            if (game != null) {
                String inputWord;
    
                do {
                    game.greet(exitWord);
                    inputWord = readLine();
                } while (checkInputWord(inputWord));
            }
        }
    
        private boolean checkInputWord(String inputWord) {
            boolean isExitWord = inputWord.equals(exitWord);
            if (isExitWord) {
                System.out.println(GoodByeMessage);
            } else {
                game.checkUserAnswer(inputWord);
            }
            return !isExitWord;
        }
    
        private String readLine() {
            java.util.Scanner scanner = new java.util.Scanner(System.in);
            return scanner.next();
        }
    
    }

    C#:


    public class GameStart
    {
        const string GreetingMessage = "Please enter your answer (enter \"{0}\" for exit):";
        const string InputAcceptMessage = "You entered \"{0}\".\n";
        const string GoodByeMessage = "Good bye.\n";
    
        readonly string exitWord;
        readonly IGame iGame;
    
        public GameStart(string exitWord)
        {
            this.exitWord = exitWord;
            iGame = Game8037.Create();
        }
    
        public void startGame()
        {
            if (iGame != null)
            {
                string inputWord;
                do
                {
                    iGame.greet(exitWord);
                    inputWord = Console.ReadLine();
                }
                while (checkInputWord(inputWord));
            }
        }
    
        bool checkInputWord(string inputWord)
        {
            bool isExitWord = inputWord.Equals(exitWord);
            if (isExitWord)
            {
                Console.WriteLine(GoodByeMessage);
            }
            else
            {
                iGame.checkUserAnswer(inputWord);
            }
            return !isExitWord;
        }
    }

    Как видите, у нас добавилось свойство game типа Game (или IGame в C#). Также в методе startGame() мы вызываем self.game.greet(...), а в методе check(...)self.game.check(...). Таким образом, в будущем можно будет вместо Game8037 подставить туда любую другую игру, которая реализует наш протокол Game.


    Заключение


    На этом работа над нашим приложением окончена, исходный код всего этого можно найти здесь. Всем спасибо за внимание, замечания, критику, советы, пожелания. :)

    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 5
    • +2
      Если смотреть по диагонали (слишком длинно всматриваться, не зная что искать), программы похожи почти как близнецы.

      А какая мораль сей басни?
      • +2
        И из всего можно сделать вывод, что пишите код сразу на всех языках, они идентичные :-)

        За Крымско-Украинские номера плюс летит. Давно таких тут нет.
        • 0
          Статья ни о чем. На кол ее.
          • 0
            Возможно, статья для новичков, чтобы показать, как можно построить структуру программы. Её можно написать в maine (как многие новички делают), а можно грамотно разбить на классы и методы.
          • +2

            Возможно. Но тогда материал, надо было по другому преподнести.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.