Recoded my TH from scratch and used interfaces :D

Hello, everyone!

I’ve recently started this course, but I already had some experience with Unity and C#, so I challenged myself to crack the code behind the Terminal prefab and to write something using some concepts that were still somewhat new to me (interfaces, delegates, events and some others)

So I did it!

I called it “Terminal Hacker 1980” and rewrote everything from scratch, trying to peek at the original code as little as I could.
After that, I refactored it to use an interface I made called “IProgram” and used it with “BIOS” (main menu) and “hacking program” (the anagram game).
The “Hacker” script only passes its input to the current active program.
As for the anagram game itself, I made it so level 1 requires 3 correct words to win, level 2 requires 4, and level 3 requires 5. I made two stacks, one with remaining words and one with unused words (to pull new words and give the player new tries).

Below are some screenshots and codes!
(it’s in Portuguese because I plan on sharing with a few friends that don’t speak english very well)

2 Likes

Screenshot_17
Screenshot_18
Screenshot_19
Screenshot_20
Screenshot_21
image

1 Like
 
public interface IProgram
{

    void ReceiveUserInput(string input);

    void InitializeProgram();

    void ShowMainMenu();

}

public class HackingProgram1980 : IProgram
{
    enum Screen {
        MainMenu,
        Password,
        Win,
        Lose
    }

    Screen currentScreen;

    Level[] levels = { new Level1(), new Level2(), new Level3() };

    Level currentLevel;

    string currentWord = "";


    public void InitializeProgram() {
        currentScreen = Screen.MainMenu;
        ShowMainMenu();
    }

    public void ShowMainMenu() {
        Terminal1980.ClearScreen();
        Terminal1980.WriteLine("");
        Terminal1980.WriteLine("CODE 0004 - TROJAN IMPLANTED");
        Terminal1980.WriteLine("Overriding with language: pt_BR");
        Terminal1980.WriteLine("------------------------------------");
        Terminal1980.WriteLine("=== PROGRAMA 01: Hack ===");
        Terminal1980.WriteLine("Escolha qual terminal hackear:");
        Terminal1980.WriteLine($"- 1: Biblioteca Municipal{levels[0].IsCompletedText}");
        Terminal1980.WriteLine($"- 2: Polícia Federal{levels[1].IsCompletedText}");
        Terminal1980.WriteLine($"- 3: NASA{levels[2].IsCompletedText}");
        currentScreen = Screen.MainMenu;

        int completedLevels = 0;
        foreach (Level level in levels) {
            if (level.isCompleted) {
                completedLevels++;
            }
        }

        if (completedLevels == levels.Length) {
            Terminal1980.WriteLine("Você é o HACKERMAN.");
        }
    }

    void ShowPasswordScreen() {
        Terminal1980.ClearScreen();
        Terminal1980.WriteLine("");
        Terminal1980.WriteLine("Você pode digitar 'menu' ou 'bios'\na qualquer momento para retornar");
        GetWordList();
        ShowPasswordQuiz();
    }

    void ShowWinScreen() {
        Terminal1980.ClearScreen();
        currentScreen = Screen.Win;
        currentLevel.isCompleted = true;
        currentLevel.ShowWinScreen();
        Terminal1980.WriteLine("Digite algo para retornar ao menu.");
    }

    public void ReceiveUserInput(string input) {
        switch (currentScreen) {
            case Screen.MainMenu:
                HandleMenuInput(input);
                return;
            case Screen.Password:
                HandlePasswordInput(input);
                return;
            case Screen.Win:
                ShowMainMenu();
                return;
            case Screen.Lose:
                ShowMainMenu();
                return;
        }


    }

    private void HandleMenuInput(string input) {
        int menuIndex;
        Debug.Log($"input : {input}");
        if (int.TryParse(input, out menuIndex)) {

            switch (menuIndex) {
                case 1:
                    currentLevel = levels[0];
                    currentScreen = Screen.Password;
                    ShowPasswordScreen();
                    return;
                case 2:
                    currentLevel = levels[1];
                    currentScreen = Screen.Password;
                    ShowPasswordScreen();
                    return;
                case 3:
                    currentLevel = levels[2];
                    currentScreen = Screen.Password;
                    ShowPasswordScreen();
                    return;
                default:
                    break;
            }

        }

        Terminal1980.WriteLine("Selecione um terminal válido.");
    }

    private void HandlePasswordInput(string input) {
        if (input == currentWord) {
            Terminal1980.WriteLine("Correto!");
            if (currentLevel.remainingWords.Count == 0) {
                ShowWinScreen();
                return;
            }
            ShowPasswordQuiz();
        }
        else {
            Terminal1980.WriteLine("Senha incorreta!");
            if (AddExtraWord()) {
                ShowPasswordQuiz();
            }
            else {
                Terminal1980.WriteLine("As senhas se esgotaram\nERROR 484 TROJAN DETECTADO");
                Terminal1980.WriteLine("Digite algo para retornar ao menu.");
                currentScreen = Screen.Lose;
            }
        }
    }


    void GetWordList() {
        currentLevel.remainingWords.Clear();
        currentLevel.unusedWords.Clear();

        List<string> temporaryWordList = new List<string>();
        foreach (string word in currentLevel.AllWordsList) {
            temporaryWordList.Add(word);
        }

        int iterator = 0;
        while (temporaryWordList.Count > 0) {
            int index = UnityEngine.Random.Range(0, temporaryWordList.Count);

            if (iterator < currentLevel.MinWordsForWin) {
                currentLevel.remainingWords.Push(temporaryWordList[index]);
            }
            else {
                currentLevel.unusedWords.Push(temporaryWordList[index]);
            }

            temporaryWordList.RemoveAt(index);
            iterator++;
        }
    }

    string GetRandomWord() {
        return currentLevel.remainingWords.Pop();
    }

    bool AddExtraWord() {
        if (currentLevel.unusedWords.Count > 0) {
            currentLevel.remainingWords.Push(currentLevel.unusedWords.Pop());
            return true;
        }
        else {
            return false;
        }
    }

    void ShowPasswordQuiz() {
        currentWord = GetRandomWord();
        int currentPasswordCount = currentLevel.MinWordsForWin - currentLevel.remainingWords.Count;

        Terminal1980.WriteLine($"Decifre a senha {currentPasswordCount}/{currentLevel.MinWordsForWin} : { currentWord.Anagram() }");

    }


    abstract class Level {
        string isCompletedText = " => HACKD";


        public bool isCompleted;


        public abstract string[] AllWordsList { get; }

        public abstract int MinWordsForWin { get; }


        public string IsCompletedText {
            get {
                return isCompleted ? isCompletedText : "";
            }
        }

        public abstract void ShowWinScreen();

        public Stack<string> remainingWords = new Stack<string>();
        public Stack<string> unusedWords = new Stack<string>();

    }


    class Level1 : Level {

        public override int MinWordsForWin => 3;

        public override string[] AllWordsList { get => new string[] { "livro", "cadeira", "marcador", "prateleira", "página", "capítulo", "romance", "mesa" }; }

        public override void ShowWinScreen() {
            Terminal1980.WriteLine(@"
      ______ ______
    _/      Y      \_
   // ~~ ~~ | ~~ ~  \\
  // ~ ~ ~~ | ~~~ ~~ \\
 //________.|.________\\
`----------`-'----------'");
            Terminal1980.WriteLine("A biblioteca foi hackeada.");
        }
    }

    class Level2 : Level {
        public override string[] AllWordsList => new string[] { "viatura", "jurisprudência", "aprisionamento", "acompanhamento", "resguardo", "fiscalização", "segurança" };

        public override int MinWordsForWin => 4;

        public override void ShowWinScreen() {
            Terminal1980.WriteLine(@"
             ,
        _.- ` `'-.
       '._ __{}_(
         |'--.__\
        (   -_\-
         |   _ |
         )\___/
     .--'`:._]
    /  \      '-.");
            Terminal1980.WriteLine("A polícia foi hackeada.");
        }
    }

    class Level3 : Level {
        public override string[] AllWordsList => new string[] { "cosmologia", "entropia", "meteorito", "astrofísica", "lançamento", "espaço sideral" };

        public override int MinWordsForWin => 5;

        public override void ShowWinScreen() {
            Terminal1980.WriteLine(@"
        |
       / \
      / _ \
     |.o '.|
     |'._.'|
     |     |
   ,'|  |  |`.
  /  |  |  |  \
  |,-'--|--'-.| ");
            Terminal1980.WriteLine("A NASA foi hackeada.");
        }
    }


1 Like

If anyone is interested I can upload the entire project.

That title screen is Awesome!

I decided to add some more functionality to my Terminal Hacker too. And I as well found that Lists offered more solutions than the Arrays in the lesson.

But I’m still glad to be forced to use Arrays as part of the instruction as I’ve struggled with them in the past.

Great job!

1 Like

Thanks for the words!

Good to hear that you’re enjoying the course as well.

This is the best beginner course I’ve seen (and I’ve paid for two others, besides around other 5 free ones).

I totally agree.

I’ve messed around watching Unity tutorials on YouTube for YEARS, and while there is a ton of great free stuff out there, I think having a course that teaches in the context of making finalized projects really helps the info sink in.

I love that you challenged yourself to write it all by yourself!

Privacy & Terms