summaryrefslogtreecommitdiff
path: root/src/among_us/program.cr
blob: cd7d6fcdf63bad58bdf9a912ec41b9e0b3e2daf9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
require "big"
require "random"

require "../util.cr"

struct AmongUs::Program < Flint::Program
  def interpret : Nil
    rand = Random.new

    code = Parser.new(@source_io).parse
    jumps = find_jumps(code)
    code_ptr = 0

    stack = [] of BigInt
    acc1 = BigInt.new
    acc2 = BigInt.new
    color = code.find &.is_a?(Color) 

    while code_ptr < code.size
      case code[code_ptr]
      in Color::RED
        color = Color::RED
      in Color::BLUE
        color = Color::BLUE
      in Color::PURPLE
        color = Color::PURPLE
      in Color::GREEN
        color = Color::GREEN
      in Color::YELLOW
        color = Color::YELLOW
      in Color::CYAN
        color = Color::CYAN
      in Color::BLACK
        color = Color::BLACK
      in Color::WHITE
        color = Color::WHITE
      in Color::BROWN
        color = Color::BROWN
      in Color::LIME
        color = Color::LIME
      in Color::PINK
        color = Color::PINK
      in Color::ORANGE
        color = Color::ORANGE

      in Command::SUS
        case color
        when Color::RED
          acc1 += 1
        when Color::BLUE
          stack << BigInt.new(acc1)
        when Color::PURPLE
          stack.pop unless stack.empty?
        when Color::GREEN
          print (stack.pop % 256).to_u8.chr unless stack.empty?
        when Color::YELLOW
          c = STDIN.read_char
          stack << BigInt.new(c.ord) unless c.nil?
        when Color::CYAN
          r = rand.rand(acc1 + 1)
          r.times do
            break if stack.empty?
            stack.pop
          end
        when Color::BLACK
          print stack.pop
        when Color::WHITE
          acc1 -= 1
        when Color::BROWN
          acc1 = stack.pop
        when Color::LIME
          stack[-1] *= 2
        when Color::PINK
          acc1 = 0
        when Color::ORANGE
          acc1 += 10
        when nil
          raise Util::InterpreterError.new("Tried to use SUS command with no color.")
        end
      in Command::VENTED
        acc2 += 10
      in Command::SUSSY
        acc2 -= 1
      in Command::ELECTRICAL
        acc2 = 0
      in Command::WHO
        code_ptr = jumps[code_ptr] if !stack.empty? && stack[-1] % 256 == acc2 % 256
      in Command::WHERE
        code_ptr = jumps[code_ptr] if !stack.empty? && stack[-1] % 256 != acc2 % 256
      end
      code_ptr += 1
    end
  end

  private def find_jumps(code : Array(Instruction)) : Hash(Int32, Int32)
    jumps = {} of Int32 => Int32
    stack = [] of Int32

    code.each_index do |i|
      case code[i]
      when Command::WHO
        stack << i
      when Command::WHERE
        jumps[i] = stack.pop
        jumps[jumps[i]] = i
      end
    end

    return jumps
  end
end