#include <iostream>
const int MAX_SIZE = 10;
void update(int* TREE, int idx, int value) {
for (++idx; idx <= MAX_SIZE+1; idx += (idx & -idx))
TREE[idx] += value;
}
int sum(int *TREE, int s) {
int r = 0;
for (++s; s > 0; s &= (s-1))
r += TREE[s];
return r;
}
int main(int argc, char **argv) {
int TBL[MAX_SIZE] = {0};
int TREE[MAX_SIZE+1] = {0, };
for (auto i = 0; i < MAX_SIZE; i++) {
TBL[i] = i+1;
update(TREE, i, TBL[i]);
}
// GET SUM from 1 ~ N
for (auto i = 0; i < MAX_SIZE; i++)
std::cout << sum(TREE, i) << ", ";
std::cout << std::endl;
return 0;
}
이번에 구현 할 테트리스 게임은 아케이드 모드, 퍼즐 모드, 아이템 모드 총 3개의 모드로 구성이 됩니다.
1.2.1 아케이드 모드
테트리스의 기본 형태로, 모두가 잘 알고 있는 내용이라, 자세한 설명은 생략합니다.
1.2.2 퍼즐모드
퍼즐 모드 테트리스는 고전적인 테트리스 게임을 벗어나, 플레이어의 두뇌와 반응 속도를 동시에 시험하는 독특한 경험을 제공합니다. 이 게임에는 70가지 이상의의 다양한 퍼즐이 포함되어 있어, 게임을 진행하면서 플레이어의 전략적 사고력을 향상시키는 동시에 문제 해결 능력을 증진시키는 데 도움이 됩니다. 각 스테이지의 목표는 화면에 보이는 색상이 있는 블록을 모두 제거하는 것입니다. 이는 단순히 블록을 빠르게 쌓는 것을 넘어서, 플레이어가 어떻게 블록을 배치하고 어떤 블록을 사용할지를 신중하게 고려해야 하는 전략적인 요소를 게임에 도입합니다.
1.2.3 아이템 모드
아이템 모드는 다양한 아이템들이 포함된 전략적인 게임을 제공 합니다. 이 모드의 주요 아이템들은 Yellow Thunder, Black Thunder, Orange Thunder, Red Thunder, Blue Boom, Black Boom, Green Boom, 그리고 Red Boom입니다.
Yellow Thunder는 화면의 모든 검은 폭탄을 폭발시키며, Black Thunder는 최대 3개의 폭탄을 화면에 추가합니다. Orange Thunder는 아이콘이 바닥에 닿을 때 중심을 기준으로 3x3 영역을 지웁니다. 단, 아이콘이 포함된 줄이 꽉 차있다면 작동하지 않습니다. Red Thunder는 아이콘이 바닥에 닿으면 현재 위치한 세로 라인과 오른쪽 세로 라인을 지웁니다.
Blue Boom은 아이콘이 바닥에 닿았을 때 중심 주변 3x3 크기를 회색 블록으로 채웁니다. Black Boom은 폭탄이 포함된 줄이 블록으로 꽉 차면 위 아래 한 줄씩 총 3줄을 삭제합니다. Green Boom은 원형의 회색 블록을 추가합니다. 단, 아이콘이 포함된 줄이 꽉 차있다면 작동하지 않습니다. Orange Boom은 아이콘 중심으로 빈 3x3 사각형을 그립니다. 마찬가지로, 아이콘이 포함된 줄이 꽉 차있다면 작동하지 않습니다. Red Boom은 아이콘이 위치한 한 줄을 지웁니다.
아이템 테트리스는 이러한 독특한 아이템들을 활용해 주어진 판의 블록들을 모두 제거하면서, 전략적으로 높은 점수를 달성하는 것이 목표입니다.
from enum import Enum
class Command(Enum):
PUSH = 'PUSH'
POP = 'POP'
ADD = 'ADD'
SUB = 'SUB'
MUL = 'MUL'
DIV = 'DIV'
MOD = 'MOD'
DUP = 'DUP'
SWAP = 'SWAP'
JMP = 'JMP'
JG = 'JG'
JL = 'JL'
JZ = 'JZ'
JNZ = 'JNZ'
CMP = 'CMP'
MOV = 'MOV'
NOP = 'NOP'
HALT = 'HALT'
class StackMachine:
"""
PUSH <value>: Push a value onto the stack. e.g., PUSH 10
POP: Remove and return the top value from the stack.
ADD: Remove the top two values from the stack, calculate their sum, and push the result onto the stack.
SUB: Remove the top two values from the stack, calculate their difference, and push the result onto the stack.
MUL: Remove the top two values from the stack, calculate their product, and push the result onto the stack.
DIV: Remove the top two values from the stack, calculate their division, and push the result onto the stack.
MOD: Remove the top two values from the stack, calculate their remainder, and push the result onto the stack.
DUP: Copy the top value from the stack and push it onto the stack.
SWAP: Swap the top two values on the stack.
JMP <label>: Move program execution to the given label. e.g., JMP LOOP
JG <label>: If the top value on the stack is greater than 0, move program execution to the given label.
JL <label>: If the top value on the stack is less than 0, move program execution to the given label.
JZ <label>: If the top value on the stack is 0, move program execution to the given label.
JNZ <label>: If the top value on the stack is not 0, move program execution to the given label.
CMP: Compare the top two values on the stack and push the result onto the stack.
(-1: First value is smaller, 0: Both values are equal, 1: First value is larger)
MOV <register>: Move the top value from the stack to the specified register (AX, BX, CX, or DX).
NOP: Perform no operation. This command is ignored in the program.
HALT: Stop program execution.
"""
def __init__(self):
self.stack = []
self.program = []
self.labels = {}
self.registers = {'AX': 0, 'BX': 0, 'CX': 0, 'DX': 0}
self.instruction_pointer = 0
def load_program(self, program):
self.program = program
self.labels = {line[:-1]: i for i, line in enumerate(program) if line.endswith(':')}
def parse_command(self, command_string):
command, *args = command_string.split()
if command not in Command.__members__:
raise ValueError(f"Invalid command: {command}")
return Command[command], args
def execute_command(self, command, args):
if command == Command.PUSH:
value = int(args[0]) if 'X' not in args[0] else self.registers[args[0]]
self.stack.append(value)
elif command == Command.POP:
self.stack.pop()
elif command == Command.ADD:
self.stack.append(self.stack.pop() + self.stack.pop())
elif command == Command.SUB:
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a - b)
elif command == Command.MUL:
self.stack.append(self.stack.pop() * self.stack.pop())
elif command == Command.DIV:
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a // b)
elif command == Command.MOD:
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a % b)
elif command == Command.DUP:
self.stack.append(self.stack[-1])
elif command == Command.SWAP:
self.stack[-1], self.stack[-2] = self.stack[-2], self.stack[-1]
elif command == Command.JMP:
self.instruction_pointer = self.labels[args[0]]
return
elif command == Command.JG:
if self.stack.pop() == 1:
self.instruction_pointer = self.labels[args[0]]
return
elif command == Command.JL:
if self.stack.pop() == -1:
self.instruction_pointer = self.labels[args[0]]
return
elif command == Command.JZ:
if self.stack.pop() == 0:
self.instruction_pointer = self.labels[args[0]]
return
elif command == Command.JNZ:
if self.stack.pop() != 0:
self.instruction_pointer = self.labels[args[0]]
return
elif command == Command.CMP:
b, a = self.stack.pop(), self.stack.pop()
self.stack.append((a > b) - (a < b))
elif command == Command.MOV:
self.registers[args[0]] = self.stack[-1]
elif command == Command.NOP:
pass
elif command == Command.HALT:
return
else:
raise ValueError(f"Unknown command: {command}")
self.instruction_pointer += 1
def run(self):
for _ in range(20000):
if self.instruction_pointer >= len(self.program):
break
command_string = self.program[self.instruction_pointer]
command, args = self.parse_command(command_string)
self.execute_command(command, args)
생성된 코드를 돌려보면, 역시 안됩니다.
디버깅 하면, Label 처리가 안되었을 알 수 있습니다.
9. Label 처리를 위한 코드를 손으로 추가 하여 수정 합니다.
from enum import Enum
class Command(Enum):
PUSH = 'PUSH'
POP = 'POP'
ADD = 'ADD'
SUB = 'SUB'
MUL = 'MUL'
DIV = 'DIV'
MOD = 'MOD'
DUP = 'DUP'
SWAP = 'SWAP'
JMP = 'JMP'
JG = 'JG'
JL = 'JL'
JZ = 'JZ'
JNZ = 'JNZ'
CMP = 'CMP'
MOV = 'MOV'
NOP = 'NOP'
HALT = 'HALT'
LABEL = 'LABEL'
class StackMachine:
"""
PUSH <value>: Push a value onto the stack. e.g., PUSH 10
POP: Remove and return the top value from the stack.
ADD: Remove the top two values from the stack, calculate their sum, and push the result onto the stack.
SUB: Remove the top two values from the stack, calculate their difference, and push the result onto the stack.
MUL: Remove the top two values from the stack, calculate their product, and push the result onto the stack.
DIV: Remove the top two values from the stack, calculate their division, and push the result onto the stack.
MOD: Remove the top two values from the stack, calculate their remainder, and push the result onto the stack.
DUP: Copy the top value from the stack and push it onto the stack.
SWAP: Swap the top two values on the stack.
JMP <label>: Move program execution to the given label. e.g., JMP LOOP
JG <label>: If the top value on the stack is greater than 0, move program execution to the given label.
JL <label>: If the top value on the stack is less than 0, move program execution to the given label.
JZ <label>: If the top value on the stack is 0, move program execution to the given label.
JNZ <label>: If the top value on the stack is not 0, move program execution to the given label.
CMP: Compare the top two values on the stack and push the result onto the stack.
(-1: First value is smaller, 0: Both values are equal, 1: First value is larger)
MOV <register>: Move the top value from the stack to the specified register (AX, BX, CX, or DX).
NOP: Perform no operation. This command is ignored in the program.
HALT: Stop program execution.
"""
def __init__(self):
self.stack = []
self.program = []
self.labels = {}
self.registers = {'AX': 0, 'BX': 0, 'CX': 0, 'DX': 0}
self.instruction_pointer = 0
def load_program(self, program):
self.program = program
self.labels = {line[:-1]: i for i, line in enumerate(program) if line.endswith(':')}
def parse_command(self, command_string):
command, *args = command_string.split()
if command not in Command.__members__:
if ':' in command:
return Command['LABEL'], args
else:
raise ValueError(f"Unknown command: {command}")
return Command[command], args
def execute_command(self, command, args):
if command == Command.PUSH:
value = int(args[0]) if 'X' not in args[0] else self.registers[args[0]]
self.stack.append(value)
elif command == Command.POP:
self.stack.pop()
elif command == Command.ADD:
self.stack.append(self.stack.pop() + self.stack.pop())
elif command == Command.SUB:
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a - b)
elif command == Command.MUL:
self.stack.append(self.stack.pop() * self.stack.pop())
elif command == Command.DIV:
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a // b)
elif command == Command.MOD:
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a % b)
elif command == Command.DUP:
self.stack.append(self.stack[-1])
elif command == Command.SWAP:
self.stack[-1], self.stack[-2] = self.stack[-2], self.stack[-1]
elif command == Command.JMP:
self.instruction_pointer = self.labels[args[0]]
return
elif command == Command.JG:
if self.stack.pop() == 1:
self.instruction_pointer = self.labels[args[0]]
return
elif command == Command.JL:
if self.stack.pop() == -1:
self.instruction_pointer = self.labels[args[0]]
return
elif command == Command.JZ:
if self.stack.pop() == 0:
self.instruction_pointer = self.labels[args[0]]
return
elif command == Command.JNZ:
if self.stack.pop() != 0:
self.instruction_pointer = self.labels[args[0]]
return
elif command == Command.CMP:
b, a = self.stack.pop(), self.stack.pop()
self.stack.append((a > b) - (a < b))
elif command == Command.MOV:
self.registers[args[0]] = self.stack[-1]
elif command == Command.NOP:
pass
elif command == Command.HALT:
return
elif command == Command.LABEL:
pass
else:
raise ValueError(f"Unknown command: {command}")
self.instruction_pointer += 1
def run(self):
for _ in range(20000):
if self.instruction_pointer >= len(self.program):
break
command_string = self.program[self.instruction_pointer]
command, args = self.parse_command(command_string)
self.execute_command(command, args)
10. execute_command() 함수 안의 수 많은 if - else 조합을 없애기 위해서 약간 코드를 고칩니다.
def command_push(self, args):
value = int(args[0]) if 'X' not in args[0] else self.registers[args[0]]
self.stack.append(value)
def command_pop(self, args):
self.stack.pop()
위와 같이 함수를 2개 추가하고, 코드를 약간 고쳐 줍니다.
11. 수정 된 코드를 넣고, 리팩토링을 부탁합니다.
from enum import Enum
class Command(Enum):
PUSH = 'PUSH'
POP = 'POP'
ADD = 'ADD'
SUB = 'SUB'
MUL = 'MUL'
DIV = 'DIV'
MOD = 'MOD'
DUP = 'DUP'
SWAP = 'SWAP'
JMP = 'JMP'
JG = 'JG'
JL = 'JL'
JZ = 'JZ'
JNZ = 'JNZ'
CMP = 'CMP'
MOV = 'MOV'
NOP = 'NOP'
HALT = 'HALT'
LABEL = 'LABEL'
class StackMachine:
"""
PUSH <value>: Push a value onto the stack. e.g., PUSH 10
POP: Remove and return the top value from the stack.
ADD: Remove the top two values from the stack, calculate their sum, and push the result onto the stack.
SUB: Remove the top two values from the stack, calculate their difference, and push the result onto the stack.
MUL: Remove the top two values from the stack, calculate their product, and push the result onto the stack.
DIV: Remove the top two values from the stack, calculate their division, and push the result onto the stack.
MOD: Remove the top two values from the stack, calculate their remainder, and push the result onto the stack.
DUP: Copy the top value from the stack and push it onto the stack.
SWAP: Swap the top two values on the stack.
JMP <label>: Move program execution to the given label. e.g., JMP LOOP
JG <label>: If the top value on the stack is greater than 0, move program execution to the given label.
JL <label>: If the top value on the stack is less than 0, move program execution to the given label.
JZ <label>: If the top value on the stack is 0, move program execution to the given label.
JNZ <label>: If the top value on the stack is not 0, move program execution to the given label.
CMP: Compare the top two values on the stack and push the result onto the stack.
(-1: First value is smaller, 0: Both values are equal, 1: First value is larger)
MOV <register>: Move the top value from the stack to the specified register (AX, BX, CX, or DX).
NOP: Perform no operation. This command is ignored in the program.
HALT: Stop program execution.
"""
def __init__(self):
self.stack = []
self.program = []
self.labels = {}
self.registers = {'AX': 0, 'BX': 0, 'CX': 0, 'DX': 0}
self.command_list = {}
self.instruction_pointer = 0
self._init_command_list()
def _init_command_list(self):
self.command_list[Command.PUSH] = self.command_push
self.command_list[Command.POP] = self.command_pop
self.command_list[Command.ADD] = self.command_add
self.command_list[Command.SUB] = self.command_sub
self.command_list[Command.MUL] = self.command_mul
self.command_list[Command.DIV] = self.command_div
self.command_list[Command.MOD] = self.command_mod
self.command_list[Command.DUP] = self.command_dup
self.command_list[Command.SWAP] = self.command_swap
self.command_list[Command.JMP] = self.command_jmp
self.command_list[Command.JG] = self.command_jg
self.command_list[Command.JL] = self.command_jl
self.command_list[Command.JZ] = self.command_jz
self.command_list[Command.JNZ] = self.command_jnz
self.command_list[Command.CMP] = self.command_cmp
self.command_list[Command.MOV] = self.command_mov
self.command_list[Command.NOP] = self.command_nop
self.command_list[Command.HALT] = self.command_halt
self.command_list[Command.LABEL] = self.command_label
def load_program(self, program):
self.program = program
self.labels = {line[:-1]: i for i, line in enumerate(program) if line.endswith(':')}
def parse_command(self, command_string):
command, *args = command_string.split()
if command not in Command.__members__:
if ':' in command:
return Command['LABEL'], args
else:
raise ValueError(f"Unknown command: {command}")
return Command[command], args
def execute_command(self, command, args):
if command in self.command_list:
self.command_list[command](args)
else:
raise ValueError(f"Unknown command: {command}")
self.instruction_pointer += 1
def command_push(self, args):
value = int(args[0]) if 'X' not in args[0] else self.registers[args[0]]
self.stack.append(value)
def command_pop(self, args):
self.stack.pop()
def command_add(self, args):
self.stack.append(self.stack.pop() + self.stack.pop())
def command_sub(self, args):
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a - b)
def command_mul(self, args):
self.stack.append(self.stack.pop() * self.stack.pop())
def command_div(self, args):
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a // b)
def command_mod(self, args):
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a % b)
def command_dup(self, args):
self.stack.append(self.stack[-1])
def command_swap(self, args):
self.stack[-1], self.stack[-2] = self.stack[-2], self.stack[-1]
def command_jmp(self, args):
self.instruction_pointer = self.labels[args[0]]
def command_jg(self, args):
if self.stack.pop() == 1:
self.instruction_pointer = self.labels[args[0]]
def command_jl(self, args):
if self.stack.pop() == -1:
self.instruction_pointer = self.labels[args[0]]
def command_jz(self, args):
if self.stack.pop() == 0:
self.instruction_pointer = self.labels[args[0]]
def command_jnz(self, args):
if self.stack.pop() != 0:
self.instruction_pointer = self.labels[args[0]]
def command_cmp(self, args):
b, a = self.stack.pop(), self.stack.pop()
self.stack.append((a > b) - (a < b))
def command_mov(self, args):
self.registers[args[0]] = self.stack[-1]
def command_nop(self, args):
pass
def command_halt(self, args):
pass
def command_label(self, args):
pass
def run(self):
for _ in range(20000):
if self.instruction_pointer >= len(self.program):
break
command_string = self.program[self.instruction_pointer]
command, args = self.parse_command(command_string)
self.execute_command(command, args)