├── Makefile ├── README.md ├── compiler ├── Makefile ├── analyze.cpp ├── analyze.hpp ├── bitstream.cpp ├── bitstream.hpp ├── block.cpp ├── block.hpp ├── check.cpp ├── check.hpp ├── chunk.cpp ├── chunk.hpp ├── color.cpp ├── color.hpp ├── main.cpp ├── predicate.cpp ├── predicate.hpp ├── world.cpp └── world.hpp ├── interpreter ├── Makefile ├── bytestream.cpp ├── bytestream.hpp ├── main.cpp ├── node.cpp ├── node.hpp └── predicate.hpp └── target └── .gitignore /Makefile: -------------------------------------------------------------------------------- 1 | all: target/mc-run target/mc-compile 2 | 3 | target/mc-run: 4 | cd interpreter && make 5 | mv interpreter/mc-run target/ 6 | 7 | target/mc-compile: 8 | cd compiler && make 9 | mv compiler/mc-compile target/ 10 | 11 | clean: 12 | cd interpreter && make clean 13 | cd compiler && make clean 14 | rm -f target/* 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 진짜 최종 구데기컵 2 - A+B (MC) 2 | 3 | ## 컴파일러 및 인터프리터 설치 4 | 5 | 이 프로그램을 `make`하면 `target` 폴더에 실행 파일 두 개가 생깁니다. `make`할 때 zlib 라이브러리가 필요할 수 있습니다. 6 | 7 | 만일 이외의 이유로 컴파일 오류가 나는 경우 즉시 연락 주세요. 8 | 9 | 각 서브태스크의 컴파일과 실행은 다음 명령으로 합니다: 10 | 11 | * 컴파일: `./mc-compile (file name) lime light_blue` 12 | * 실행: 13 | * 서브태스크 1: `./mc-run a.out` 14 | * 서브태스크 2: `./mc-run a.out --ban-block comparator` 15 | * 서브태스크 3: `./mc-run a.out --ban-block torch` 16 | * 서브태스크 4: `./mc-run a.out --max-tick 15` 17 | -------------------------------------------------------------------------------- /compiler/Makefile: -------------------------------------------------------------------------------- 1 | all: mc-compile 2 | 3 | mc-compile: main.o chunk.o predicate.o bitstream.o world.o analyze.o check.o block.o color.o 4 | g++ -o mc-compile main.o chunk.o predicate.o bitstream.o world.o analyze.o check.o block.o color.o -lz 5 | 6 | chunk.o: chunk.cpp chunk.hpp bitstream.hpp predicate.hpp 7 | g++ -c chunk.cpp -O2 -std=gnu++17 8 | 9 | main.o: main.cpp world.hpp predicate.hpp check.hpp color.hpp 10 | g++ -c main.cpp -O2 -std=gnu++17 11 | 12 | predicate.o: predicate.cpp predicate.hpp 13 | g++ -c predicate.cpp -O2 -std=gnu++17 14 | 15 | bitstream.o: bitstream.cpp bitstream.hpp predicate.hpp 16 | g++ -c bitstream.cpp -O2 -std=gnu++17 17 | 18 | world.o: world.cpp world.hpp chunk.hpp predicate.hpp 19 | g++ -c world.cpp -O2 -std=gnu++17 20 | 21 | analyze.o: analyze.cpp analyze.hpp world.hpp predicate.hpp 22 | g++ -c analyze.cpp -O2 -std=gnu++17 23 | 24 | block.o: block.cpp block.hpp predicate.hpp 25 | g++ -c block.cpp -O2 -std=gnu++17 26 | 27 | check.o: check.cpp check.hpp world.hpp predicate.hpp block.hpp 28 | g++ -c check.cpp -O2 -std=gnu++17 29 | 30 | color.o: color.cpp color.hpp predicate.hpp 31 | g++ -c color.cpp -O2 -std=gnu++17 32 | 33 | clean: 34 | rm -f *.o mc-compile 35 | -------------------------------------------------------------------------------- /compiler/analyze.cpp: -------------------------------------------------------------------------------- 1 | #include "analyze.hpp" 2 | 3 | inline int abs(int x) { 4 | return x < 0 ? -x : x; 5 | } 6 | 7 | int pack(int x, int y, int z) { 8 | const int cx = x >> 4, cy = y >> 4, cz = z >> 4; 9 | const int ix = x & 15, iy = y & 15, iz = z & 15; 10 | return (((cz << 9) | (cx << 4) | cy) << 12) | ((iz << 8) | (ix << 4) | iy); 11 | } 12 | 13 | bool test_facing(const world &w, int x, int y, int z, std::function f) { 14 | byte b = w.getXYZ(x, y, z); 15 | switch (b & 3) { 16 | case EAST: 17 | ++x; 18 | break; 19 | case WEST: 20 | --x; 21 | break; 22 | case SOUTH: 23 | ++z; 24 | break; 25 | case NORTH: 26 | --z; 27 | break; 28 | } 29 | return f(w, x, y, z); 30 | } 31 | 32 | bool test_opposite_facing(const world &w, int x, int y, int z, std::function f) { 33 | byte b = w.getXYZ(x, y, z); 34 | switch (b & 3) { 35 | case EAST: 36 | --x; 37 | break; 38 | case WEST: 39 | ++x; 40 | break; 41 | case SOUTH: 42 | --z; 43 | break; 44 | case NORTH: 45 | ++z; 46 | break; 47 | } 48 | return f(w, x, y, z); 49 | } 50 | 51 | bool redstone_into(const world &w, int x, int y, int z, int ox, int oy, int oz) { 52 | if (abs(x - ox) + abs(y - oy) + abs(z - oz) != 1) return false; 53 | if (x == ox && y - 1 == oy && z == oz) return true; 54 | if (y != oy) return false; 55 | 56 | bool block_upper = is_opaque(w.getXYZ(x, y + 1, z)); 57 | #define f(dx,dz) (\ 58 | (w.getXYZ(x + dx, y, z + dz) & BLOCK_ONLY) == REDSTONE_WIRE\ 59 | || ((w.getXYZ(x + dx, y + 1, z + dz) & BLOCK_ONLY) == REDSTONE_WIRE && !block_upper)\ 60 | || ((w.getXYZ(x + dx, y - 1, z + dz) & BLOCK_ONLY) == REDSTONE_WIRE && !is_opaque(w.getXYZ(x + dx, y, z + dz)))\ 61 | ) 62 | bool east = f(1, 0); 63 | bool west = f(-1, 0); 64 | bool south = f(0, 1); 65 | bool north = f(0, -1); 66 | #undef f 67 | int flag = east + west + south + north; 68 | if (!flag) { 69 | east = west = south = north = true; 70 | } else if (flag == 1) { 71 | if (east) west = true; 72 | else if (west) east = true; 73 | else if (south) north = true; 74 | else if (north) south = true; 75 | } 76 | if (x + 1 == ox) return east; 77 | else if (x - 1 == ox) return west; 78 | else if (z + 1 == oz) return south; 79 | else if (z - 1 == oz) return north; 80 | return false; 81 | } 82 | 83 | // world must be error-free 84 | int analyze(const world &w, int x, int y, int z, vector &result) { 85 | byte this_block = w.getXYZ(x, y, z); 86 | if ((this_block & BLOCK_ONLY) == REDSTONE_WIRE) { 87 | vector side; 88 | for (int i=0; i> 3) & 3); 229 | } else if ((this_block & BLOCK_ONLY) == COMPARATOR) { 230 | test_facing(w, x, y, z, [&] (const world &w, int bx, int by, int bz) { 231 | byte facing = w.getXYZ(bx, by, bz); 232 | if (is_opaque(facing)) { 233 | for (int i=0; i 5 | #include "predicate.hpp" 6 | #include "world.hpp" 7 | 8 | int analyze(const world &w, int x, int y, int z, vector &result); 9 | int pack(int x, int y, int z); 10 | 11 | const int wide_len = 25; 12 | const int wide_dx[] = {-2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2}; 13 | const int wide_dy[] = { 0, -1, 0, 0, 0, 1, -2, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 2, -1, 0, 0, 0, 1, 0}; 14 | const int wide_dz[] = { 0, 0, -1, 0, 1, 0, 0, -1, 0, 1, -2, -1, 1, 2, -1, 0, 1, 0, 0, -1, 0, 1, 0, 0}; 15 | 16 | const int narrow_len = 6; 17 | const int narrow_dx[] = {-1, 0, 0, 0, 0, 1}; 18 | const int narrow_dy[] = { 0, -1, 0, 0, 1, 0}; 19 | const int narrow_dz[] = { 0, 0, -1, 1, 0, 0}; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /compiler/bitstream.cpp: -------------------------------------------------------------------------------- 1 | #include "bitstream.hpp" 2 | 3 | int bitreader::read(int bit) { 4 | int x = 0, u = 0; 5 | if (this->remaining < bit) { 6 | x = this->temp; 7 | bit -= this->remaining; 8 | u = this->remaining; 9 | this->remaining = 64; 10 | this->temp = 0; 11 | for (int i=0; i<8; ++i) { 12 | (this->temp <<= 8) |= this->data[this->pos++]; 13 | } 14 | } 15 | x |= (this->temp & ((1ULL << bit) - 1)) << u; 16 | this->temp >>= bit; 17 | this->remaining -= bit; 18 | return x; 19 | } 20 | 21 | void bitreader::init(const byte *data, bool copy) { 22 | // TODO: implement copy if needed 23 | this->data = data; 24 | this->pos = 0; 25 | this->remaining = 0; 26 | } 27 | 28 | bool bitreader::init_needed() { 29 | return !this->data; 30 | } 31 | -------------------------------------------------------------------------------- /compiler/bitstream.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BITSTREAM_HPP 2 | #define BITSTREAM_HPP 3 | 4 | #include "predicate.hpp" 5 | 6 | class bitreader { 7 | private: 8 | const byte *data; 9 | int pos, remaining; 10 | u64 temp; 11 | public: 12 | bitreader() { 13 | init(nullptr, false); 14 | } 15 | bitreader(const byte *buf, bool copy = false) { 16 | init(buf, copy); 17 | } 18 | void init(const byte *buf, bool copy = false); 19 | int read(int bit); 20 | bool init_needed(); 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /compiler/block.cpp: -------------------------------------------------------------------------------- 1 | #include "block.hpp" 2 | 3 | string block_to_string(byte block) { 4 | switch (block & BLOCK_ONLY) { 5 | case AIR: return "air"; 6 | case BEDROCK: return "bedrock"; 7 | case STONE: return "stone"; 8 | case SANDSTONE: return "sandstone"; 9 | case REDSTONE_WIRE: return "redstone_wire"; 10 | case REDSTONE_TORCH: 11 | case REDSTONE_WALL_TORCH: return "redstone_torch"; 12 | case COMPARATOR: return "comparator"; 13 | case REPEATER: 14 | case REPEATER | 16: return "repeater"; 15 | case REDSTONE_LAMP: return "redstone_lamp"; 16 | case LEVER: return "lever"; 17 | case CONCRETE: return "concrete"; 18 | } 19 | return "unknown"; 20 | } 21 | 22 | bool is_repeater(byte block) { 23 | return (block & 224) == REPEATER; 24 | } 25 | 26 | bool is_opaque(byte block) { 27 | switch (block & BLOCK_ONLY) { 28 | case BEDROCK: 29 | case STONE: 30 | case SANDSTONE: 31 | case REDSTONE_LAMP: 32 | case CONCRETE: 33 | return true; 34 | } 35 | return false; 36 | } 37 | -------------------------------------------------------------------------------- /compiler/block.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BLOCK_HPP 2 | #define BLOCK_HPP 3 | 4 | #include "predicate.hpp" 5 | 6 | const byte AIR = 0; 7 | const byte BEDROCK = 16; 8 | const byte STONE = 32; 9 | const byte SANDSTONE = 48; 10 | const byte REDSTONE_WIRE = 64; 11 | const byte REDSTONE_TORCH = 80; 12 | const byte REDSTONE_WALL_TORCH = 96; 13 | const byte COMPARATOR = 112; 14 | const byte REPEATER = 128; 15 | const byte REDSTONE_LAMP = 160; 16 | const byte LEVER = 176; 17 | const byte CONCRETE = 192; 18 | 19 | const byte BLOCK_ONLY = 240; 20 | 21 | const byte EAST = 0; 22 | const byte NORTH = 1; 23 | const byte SOUTH = 2; 24 | const byte WEST = 3; 25 | const byte POWERED = 4; 26 | const byte SUBTRACT = 8; 27 | 28 | const int ATTR_FACING = 1; 29 | const int ATTR_FACE = 2; 30 | const int ATTR_POWER = 4; 31 | const int ATTR_POWERED = 8; 32 | const int ATTR_LIT = 16; 33 | const int ATTR_DELAY = 32; 34 | const int ATTR_MODE = 64; 35 | const int ATTR_LOCKED = 128; 36 | const int ATTR_EAST = 256; 37 | const int ATTR_WEST = 512; 38 | const int ATTR_SOUTH = 1024; 39 | const int ATTR_NORTH = 2048; 40 | 41 | string block_to_string(byte block); 42 | bool is_repeater(byte block); 43 | bool is_opaque(byte block); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /compiler/check.cpp: -------------------------------------------------------------------------------- 1 | #include "check.hpp" 2 | 3 | bool is_redstone_component(const world &w, int x, int y, int z) { 4 | byte fetched = w.getXYZ(x, y, z); 5 | if ((fetched & BLOCK_ONLY) == REDSTONE_WALL_TORCH || (fetched & BLOCK_ONLY) == LEVER) { 6 | switch (fetched & 3) { 7 | case EAST: --x; break; 8 | case WEST: ++x; break; 9 | case SOUTH: --z; break; 10 | case NORTH: ++z; break; 11 | } 12 | if (!is_opaque(w.getXYZ(x, y, z))) { 13 | throw NO_SUPPORTING_BLOCK_ERROR; 14 | } 15 | return true; 16 | } else if ((fetched & BLOCK_ONLY) == REDSTONE_WIRE || (fetched & BLOCK_ONLY) == REDSTONE_TORCH || is_repeater(fetched) || (fetched & BLOCK_ONLY) == COMPARATOR) { 17 | if (!is_opaque(w.getXYZ(x, y-1, z))) { 18 | throw NO_SUPPORTING_BLOCK_ERROR; 19 | } 20 | return true; 21 | } 22 | return (fetched & BLOCK_ONLY) == REDSTONE_LAMP; 23 | } 24 | -------------------------------------------------------------------------------- /compiler/check.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CHECK_HPP 2 | #define CHECK_HPP 3 | 4 | #include "predicate.hpp" 5 | #include "world.hpp" 6 | #include "block.hpp" 7 | 8 | bool is_redstone_component(const world &w, int x, int y, int z); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /compiler/chunk.cpp: -------------------------------------------------------------------------------- 1 | #include "chunk.hpp" 2 | 3 | //#define CHUNK_DEBUG 4 | 5 | int need_progress(int stage, string name) { 6 | if (stage == 0 && name == "") return 1; 7 | else if (stage == 1 && name == "Level") return 2; 8 | else if (stage == 2 && name == "Sections") return 3; 9 | else if (stage == 3 && name == "Palette") return 4; 10 | else if (stage == 4 && name == "Properties") return 5; 11 | return stage; 12 | } 13 | 14 | void chunk::feed(int y) { 15 | this->y = y; 16 | #ifdef CHUNK_DEBUG 17 | printf("Y : %d\n", y); 18 | #endif 19 | } 20 | 21 | void chunk::feed(string name) { 22 | if (name == "minecraft:air") { 23 | (this->block &= 15) |= AIR; 24 | } else if (name == "minecraft:bedrock") { 25 | (this->block &= 15) |= BEDROCK; 26 | } else if (name == "minecraft:stone") { 27 | (this->block &= 15) |= STONE; 28 | } else if (name == "minecraft:sandstone") { 29 | (this->block &= 15) |= SANDSTONE; 30 | } else if (name == "minecraft:redstone_wire") { 31 | (this->block &= 15) |= REDSTONE_WIRE; 32 | } else if (name == "minecraft:redstone_torch") { 33 | (this->block &= 15) |= REDSTONE_TORCH; 34 | } else if (name == "minecraft:redstone_wall_torch") { 35 | (this->block &= 15) |= REDSTONE_WALL_TORCH; 36 | } else if (name == "minecraft:repeater") { 37 | (this->block &= 31) |= REPEATER; 38 | } else if (name == "minecraft:comparator") { 39 | (this->block &= 15) |= COMPARATOR; 40 | } else if (name == "minecraft:redstone_lamp") { 41 | (this->block &= 15) |= REDSTONE_LAMP; 42 | } else if (name == "minecraft:lever") { 43 | (this->block &= 15) |= LEVER; 44 | } else if (name.length() >= 19 && name.substr(0, 10) == "minecraft:" && name.substr(name.length() - 9) == "_concrete") { 45 | int color = color_to_int(name.substr(10, name.length() - 19)); 46 | if (color < 0) { 47 | fprintf(stderr, "Error: unknown block name '%s'\n", name.c_str()); 48 | throw UNKNOWN_BLOCK_ERROR; 49 | } 50 | this->block = CONCRETE | color; 51 | } else { 52 | fprintf(stderr, "Error: unknown block name '%s'\n", name.c_str()); 53 | throw UNKNOWN_BLOCK_ERROR; 54 | } 55 | #ifdef CHUNK_DEBUG 56 | printf(" Block : %s\n", name.c_str()); 57 | #endif 58 | } 59 | 60 | void chunk::feed(string attr, string val) { 61 | if (attr == "facing") { 62 | if (val == "east") { 63 | this->block |= EAST; 64 | } else if (val == "west") { 65 | this->block |= WEST; 66 | } else if (val == "south") { 67 | this->block |= SOUTH; 68 | } else if (val == "north") { 69 | this->block |= NORTH; 70 | } else { 71 | throw ATTR_VALUE_MISMATCH_ERROR; 72 | } 73 | this->attr |= ATTR_FACING; 74 | } else if (attr == "face") { 75 | if (val != "wall") { 76 | throw NOT_SUPPORTED_LEVER; 77 | } 78 | this->attr |= ATTR_FACE; 79 | } else if (attr == "power") { 80 | int power; 81 | if (sscanf(val.c_str(), "%d", &power) != 1 || !(0 <= power && power <= 15)) { 82 | throw ATTR_VALUE_MISMATCH_ERROR; 83 | } 84 | (this->block &= 240) |= power; 85 | this->attr |= ATTR_POWER; 86 | } else if (attr == "lit" || attr == "powered") { 87 | if (val == "true") { 88 | this->block |= POWERED; 89 | } else if (val != "false") { 90 | throw ATTR_VALUE_MISMATCH_ERROR; 91 | } 92 | this->attr |= attr == "lit" ? ATTR_LIT : ATTR_POWERED; 93 | } else if (attr == "delay") { 94 | int delay; 95 | if (sscanf(val.c_str(), "%d", &delay) != 1 || !(1 <= delay && delay <= 4)) { 96 | throw ATTR_VALUE_MISMATCH_ERROR; 97 | } 98 | this->block |= (delay - 1) << 3; 99 | this->attr |= ATTR_DELAY; 100 | } else if (attr == "mode") { 101 | if (val == "subtract") { 102 | this->block |= SUBTRACT; 103 | } else if (val != "compare") { 104 | throw ATTR_VALUE_MISMATCH_ERROR; 105 | } 106 | this->attr |= ATTR_MODE; 107 | } else if (attr == "locked") { 108 | if (val != "true" && val != "false") { 109 | throw ATTR_VALUE_MISMATCH_ERROR; 110 | } 111 | this->attr |= ATTR_LOCKED; 112 | } else if (attr == "east") { 113 | if (val != "none" && val != "side" && val != "up") { 114 | throw ATTR_VALUE_MISMATCH_ERROR; 115 | } 116 | this->attr |= ATTR_EAST; 117 | } else if (attr == "west") { 118 | if (val != "none" && val != "side" && val != "up") { 119 | throw ATTR_VALUE_MISMATCH_ERROR; 120 | } 121 | this->attr |= ATTR_WEST; 122 | } else if (attr == "south") { 123 | if (val != "none" && val != "side" && val != "up") { 124 | throw ATTR_VALUE_MISMATCH_ERROR; 125 | } 126 | this->attr |= ATTR_SOUTH; 127 | } else if (attr == "north") { 128 | if (val != "none" && val != "side" && val != "up") { 129 | throw ATTR_VALUE_MISMATCH_ERROR; 130 | } 131 | this->attr |= ATTR_NORTH; 132 | } else { 133 | fprintf(stderr, "Error: unknown attribute name '%s'\n", attr.c_str()); 134 | throw UNKNOWN_ATTR_ERROR; 135 | } 136 | #ifdef CHUNK_DEBUG 137 | printf(" %s : %s\n", attr.c_str(), val.c_str()); 138 | #endif 139 | } 140 | 141 | void chunk::init() { 142 | this->block = 0; 143 | this->y = 255; 144 | this->palette.clear(); 145 | this->world_data = new byte *[16]; 146 | this->attr = 0; 147 | memset(this->world_data, 0, sizeof(byte *) * 16); 148 | } 149 | 150 | void chunk::feed(const byte *data, int len) { 151 | this->br.init(data); 152 | #ifdef CHUNK_DEBUG 153 | printf("world data read\n"); 154 | #endif 155 | } 156 | 157 | void chunk::flush_section() { 158 | if (0 <= this->y && this->y < 16) { 159 | if (!this->br.init_needed()) { 160 | if (this->world_data[this->y]) { 161 | fprintf(stderr, "Error: duplicate section y = %d; did you edit the world using hex editor?\n", this->y); 162 | throw DUPLICATE_Y_SECTION_ERROR; 163 | } 164 | this->world_data[this->y] = new byte[4096]; 165 | const int needed_bit = this->palette.size() < 2U ? 4 : std::max(4, 32 - __builtin_clz((int)this->palette.size() - 1)); 166 | for (int i=0; i<4096; ++i) { 167 | int x = this->br.read(needed_bit); 168 | this->world_data[this->y][i] = this->palette[x]; 169 | } 170 | } 171 | } 172 | this->block = 0; 173 | this->y = 255; 174 | this->palette.clear(); 175 | this->br.init(nullptr); 176 | #ifdef CHUNK_DEBUG 177 | printf("section end\n"); 178 | #endif 179 | } 180 | 181 | void chunk::flush_block() { 182 | this->palette.push_back(this->block); 183 | // attribute validation 184 | const int attributes[] = { 185 | 0, 0, 0, 0, ATTR_POWER | ATTR_EAST | ATTR_WEST | ATTR_SOUTH | ATTR_NORTH /* wire */, 186 | ATTR_LIT /* torch */, ATTR_LIT | ATTR_FACING /* wall torch */, 187 | ATTR_FACING | ATTR_MODE | ATTR_POWERED /* comparator */, 188 | ATTR_DELAY | ATTR_FACING | ATTR_LOCKED | ATTR_POWERED, 189 | ATTR_DELAY | ATTR_FACING | ATTR_LOCKED | ATTR_POWERED /* repeater */, 190 | ATTR_LIT /* lamp */, ATTR_FACE | ATTR_FACING | ATTR_POWERED /* lever */, 0 191 | }; 192 | if (attributes[this->block >> 4] != this->attr) { 193 | fprintf(stderr, "Error: block has missing or extra attribute; did you edit the world using hex editor?\n"); 194 | throw ATTR_MISMATCH_ERROR; 195 | } 196 | #ifdef CHUNK_DEBUG 197 | printf("block = %02X\n", this->block); 198 | #endif 199 | this->block = 0; 200 | this->attr = 0; 201 | } 202 | 203 | bool chunk::read(const byte *data, int *pos, int tag_type, int stage) { 204 | bool named; 205 | string name; 206 | if (tag_type < 0) { 207 | tag_type = data[(*pos)++]; 208 | if (!tag_type) { 209 | return false; 210 | } 211 | 212 | int len = data[(*pos)++]; 213 | (len <<= 8) |= data[(*pos)++]; 214 | name = bytes_to_string(data+*pos, len); 215 | named = true; 216 | *pos += len; 217 | } else { 218 | named = false; 219 | } 220 | switch (tag_type) { 221 | case 1: 222 | if (stage == 3 && named && name == "Y") { 223 | this->feed((int)data[*pos]); 224 | } 225 | ++*pos; 226 | break; 227 | case 2: 228 | *pos += 2; 229 | break; 230 | case 3: 231 | if (stage == 2 && named && (name == "xPos" || name == "zPos")) { 232 | u32 coord = 0; 233 | for (int i=0; i<4; ++i) { 234 | (coord <<= 8) |= data[(*pos)++]; 235 | } 236 | (name[0] == 'x' ? this->x : this->z) = (int)coord; 237 | } else *pos += 4; 238 | break; 239 | case 4: 240 | *pos += 8; 241 | break; 242 | case 5: 243 | *pos += 4; 244 | break; 245 | case 6: 246 | *pos += 8; 247 | break; 248 | case 7: 249 | { 250 | int len = 0; 251 | for (int i=0; i<4; ++i) { 252 | (len <<= 8) |= data[(*pos)++]; 253 | } 254 | *pos += len; 255 | } 256 | break; 257 | case 8: 258 | { 259 | int len = data[(*pos)++]; 260 | (len <<= 8) |= data[(*pos)++]; 261 | if (stage == 4 && named && name == "Name") this->feed(bytes_to_string(data+*pos, len)); 262 | if (stage == 5 && named) this->feed(name, bytes_to_string(data+*pos, len)); 263 | *pos += len; 264 | } 265 | break; 266 | case 9: 267 | { 268 | byte subid = data[(*pos)++]; 269 | int len = 0; 270 | for (int i=0; i<4; ++i) { 271 | (len <<= 8) |= data[(*pos)++]; 272 | } 273 | this->troubleshoot_bit = len >> 6; 274 | int next_stage = named ? need_progress(stage, name) : stage; 275 | while (len--) { 276 | this->read(data, pos, (int)subid, next_stage); 277 | if (stage == 2 && next_stage == 3) this->flush_section(); 278 | if (stage == 3 && next_stage == 4) this->flush_block(); 279 | } 280 | } 281 | break; 282 | case 10: 283 | { 284 | int next_stage = named ? need_progress(stage, name) : stage; 285 | while (this->read(data, pos, -1, next_stage)); 286 | } 287 | break; 288 | case 11: 289 | { 290 | int len = 0; 291 | for (int i=0; i<4; ++i) { 292 | (len <<= 8) |= data[(*pos)++]; 293 | } 294 | *pos += len * 4; 295 | } 296 | break; 297 | case 12: 298 | { 299 | int len = 0; 300 | for (int i=0; i<4; ++i) { 301 | (len <<= 8) |= data[(*pos)++]; 302 | } 303 | if (stage == 3 && named && name == "BlockStates") { 304 | this->feed(data+*pos, len * 8); 305 | } 306 | *pos += len * 8; 307 | } 308 | break; 309 | } 310 | return true; 311 | } 312 | 313 | void chunk::read(const byte *data) { 314 | int pos = 0; 315 | this->init(); 316 | this->read(data, &pos); 317 | } 318 | 319 | chunk::~chunk() { 320 | if (this->world_data) { 321 | int i; 322 | for (i=0; i<16; ++i) { 323 | if (this->world_data[i]) { 324 | delete [](this->world_data[i]); 325 | } 326 | } 327 | delete []this->world_data; 328 | this->world_data = nullptr; 329 | } 330 | } 331 | 332 | byte chunk::getXYZ(int x, int y, int z) { 333 | if (!this->world_data) return AIR; 334 | int idx = y >> 4; 335 | if (!this->world_data[idx]) return AIR; 336 | return this->world_data[idx][((y & 15) << 8) | ((z & 15) << 4) | (x & 15)]; 337 | } 338 | 339 | bool chunk::has_world_data(int cy) const { 340 | if (!(0 <= cy && cy < 16)) return false; 341 | if (!this->world_data) return false; 342 | if (!this->world_data[cy]) return false; 343 | return true; 344 | } 345 | 346 | bool chunk::troubleshoot(int x, int z) { 347 | const int target = (int)this->palette.size(); 348 | if (0 <= this->y && this->y < 16 && !this->br.init_needed()) { 349 | for (int i=0; i<4096; ++i) { 350 | int x = this->br.read(this->troubleshoot_bit); 351 | if (x == target) { 352 | const int y_coord = (this->y << 4) | (i >> 8); 353 | if (0 <= y_coord && y_coord < 256) { 354 | fprintf(stderr, "exact location might be (%d, %d, %d)\n", (x << 4) | (i & 15), y_coord, (z << 4) | ((i >> 4) & 15)); 355 | } else { 356 | fprintf(stderr, "exact location might be (%d, ?, %d)\n", (x << 4) | (i & 15), (z << 4) | ((i >> 4) & 15)); 357 | } 358 | return true; 359 | } 360 | } 361 | } 362 | return false; 363 | } 364 | -------------------------------------------------------------------------------- /compiler/chunk.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CHUNK_HPP 2 | #define CHUNK_HPP 3 | 4 | #include "predicate.hpp" 5 | #include "block.hpp" 6 | #include "bitstream.hpp" 7 | #include "color.hpp" 8 | 9 | class chunk { 10 | private: 11 | int x, y, z, block, attr; 12 | int troubleshoot_bit; 13 | vector palette; 14 | byte **world_data; 15 | bitreader br; 16 | 17 | void feed(int y); 18 | void feed(string name); 19 | void feed(string attr, string val); 20 | void feed(const byte *data, int len); 21 | void flush_section(); 22 | void flush_block(); 23 | bool read(const byte *data, int *pos, int tag_type = -1, int stage = 0); 24 | void init(); 25 | public: 26 | void read(const byte *data); 27 | byte getXYZ(int x, int y, int z); 28 | bool has_world_data(int cy) const; 29 | bool troubleshoot(int x, int z); 30 | ~chunk(); 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /compiler/color.cpp: -------------------------------------------------------------------------------- 1 | #include "color.hpp" 2 | 3 | int color_to_int(string s) { 4 | if (s == "white") return 0; 5 | else if (s == "orange") return 1; 6 | else if (s == "magenta") return 2; 7 | else if (s == "light_blue") return 3; 8 | else if (s == "yellow") return 4; 9 | else if (s == "lime") return 5; 10 | else if (s == "pink") return 6; 11 | else if (s == "gray") return 7; 12 | else if (s == "light_gray") return 8; 13 | else if (s == "cyan") return 9; 14 | else if (s == "purple") return 10; 15 | else if (s == "blue") return 11; 16 | else if (s == "brown") return 12; 17 | else if (s == "green") return 13; 18 | else if (s == "red") return 14; 19 | else if (s == "black") return 15; 20 | return -1; 21 | } 22 | -------------------------------------------------------------------------------- /compiler/color.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COLOR_HPP 2 | #define COLOR_HPP 3 | 4 | #include "predicate.hpp" 5 | 6 | int color_to_int(string s); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /compiler/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "world.hpp" 3 | #include "analyze.hpp" 4 | #include "check.hpp" 5 | #include "color.hpp" 6 | 7 | const int BUFSIZE = 1048576; 8 | byte data[BUFSIZE]; 9 | 10 | void traverse_world(const world &w, std::function f) { 11 | int cx, cy, cz; 12 | for (cz=0; cz<32; ++cz) { 13 | for (cx=0; cx<32; ++cx) { 14 | for (cy=0; cy<16; ++cy) { 15 | if (w.has_world_data(cx, cy, cz)) { 16 | int x, y, z; 17 | for (z=0; z<16; ++z) { 18 | for (x=0; x<16; ++x) { 19 | for (y=0; y<16; ++y) { 20 | f((cx << 4) | x, (cy << 4) | y, (cz << 4) | z); 21 | } 22 | } 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | 30 | void write_byte(FILE *fp, byte c) { 31 | fwrite(&c, 1, 1, fp); 32 | } 33 | 34 | void write_int(FILE *fp, u32 x) { 35 | write_byte(fp, x >> 24); 36 | write_byte(fp, (x >> 16) & 255); 37 | write_byte(fp, (x >> 8) & 255); 38 | write_byte(fp, x & 255); 39 | } 40 | 41 | int main(int argc, char *argv[]) { 42 | if (argc <= 1) { 43 | fprintf(stderr, "Usage: %s [input list]\n", argv[0]); 44 | return -1; 45 | } else if (argc == 2) { 46 | fprintf(stderr, "Warning: no input specified\n"); 47 | } 48 | vector input_order; 49 | for (int i=2; i> 4) << 9) | ((x >> 4) << 4) | (y >> 4)); 72 | if (!*ptr) { 73 | *ptr = new int[4096]; 74 | memset(*ptr, 0, sizeof(int) * 4096); 75 | } 76 | (*ptr)[((z & 15) << 8) | ((x & 15) << 4) | (y & 15)] = ++cnt; 77 | } 78 | }); 79 | 80 | fp = fopen("a.out", "wb"); 81 | traverse_world(w, [&] (int x, int y, int z) { 82 | vector info; 83 | const int type = analyze(w, x, y, z, info); 84 | if (type) { 85 | int byte_type = 0; 86 | if (type == 1) { 87 | byte_type = 16 | (w.getXYZ(x, y, z) & 15); 88 | } else { 89 | byte_type = (type << 4) | (w.getXYZ(x, y, z) & POWERED ? 15 : 0); 90 | } 91 | write_byte(fp, byte_type); 92 | for (const int &x : info) { 93 | write_int(fp, x >= 0 ? u[x >> 12][x & 4095] : -1); 94 | } 95 | write_int(fp, -1); 96 | if (type == 1 || type == 2) { 97 | for (int i=0; i temp; 101 | analyze(w, nx, ny, nz, temp); 102 | const int target = pack(x, y, z); 103 | const int idx = pack(nx, ny, nz); 104 | for (const int &v : temp) { 105 | if (v == target) { 106 | write_int(fp, u[idx >> 12][idx & 4095]); 107 | break; 108 | } 109 | } 110 | } 111 | } 112 | } else { 113 | for (int i=0; i> 12][idx & 4095]); 118 | } 119 | if (type != 10) { 120 | switch (w.getXYZ(x, y, z) & 3) { 121 | case EAST: --nx; break; 122 | case WEST: ++nx; break; 123 | case SOUTH: --nz; break; 124 | case NORTH: ++nz; break; 125 | } 126 | if (is_redstone_component(w, nx, ny, nz) && !(nx == x && nz == z)) { 127 | int idx = pack(nx, ny, nz); 128 | write_int(fp, u[idx >> 12][idx & 4095]); 129 | } 130 | } 131 | } 132 | } 133 | write_int(fp, -1); 134 | } 135 | }); 136 | write_byte(fp, -1); 137 | 138 | vector > inputs[16], output; 139 | traverse_world(w, [&] (int x, int y, int z) { 140 | byte fetched = w.getXYZ(x, y, z); 141 | if ((fetched & BLOCK_ONLY) == LEVER) { 142 | int nx = x, ny = y, nz = z; 143 | switch (fetched & 3) { 144 | case EAST: --nx; break; 145 | case WEST: ++nx; break; 146 | case SOUTH: --nz; break; 147 | case NORTH: ++nz; break; 148 | } 149 | byte facing = w.getXYZ(nx, ny, nz); 150 | if ((facing & BLOCK_ONLY) == CONCRETE) { 151 | inputs[facing & 15].emplace_back((z << 17) | (x << 8) | y, pack(x, y, z)); 152 | } 153 | } else if ((fetched & BLOCK_ONLY) == REDSTONE_LAMP) { 154 | output.emplace_back((z << 17) | (x << 8) | y, pack(x, y, z)); 155 | } 156 | }); 157 | for (int i=0; i<16; ++i) { 158 | sort(inputs[i].begin(), inputs[i].end()); 159 | } 160 | sort(output.begin(), output.end()); 161 | 162 | for (const int &i : input_order) { 163 | for (const auto &[_, idx] : inputs[i]) { 164 | write_int(fp, u[idx >> 12][idx & 4095]); 165 | } 166 | write_int(fp, -1); 167 | } 168 | write_int(fp, -1); 169 | for (const auto &[_, idx] : output) { 170 | write_int(fp, u[idx >> 12][idx & 4095]); 171 | } 172 | write_int(fp, -1); 173 | fclose(fp); 174 | return 0; 175 | } 176 | -------------------------------------------------------------------------------- /compiler/predicate.cpp: -------------------------------------------------------------------------------- 1 | #include "predicate.hpp" 2 | 3 | string bytes_to_string(const byte *data, int len) { 4 | char *str = new char[len + 1]; 5 | memcpy(str, data, len); 6 | str[len] = 0; 7 | string res(str); 8 | delete []str; 9 | return res; 10 | } 11 | -------------------------------------------------------------------------------- /compiler/predicate.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PREDICATE_HPP 2 | #define PREDICATE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using std::string; 10 | using std::vector; 11 | 12 | typedef unsigned char byte; 13 | typedef unsigned int u32; 14 | typedef unsigned long long u64; 15 | 16 | string bytes_to_string(const byte *data, int len); 17 | 18 | // errors 19 | const int UNKNOWN_BLOCK_ERROR = -1; 20 | const int ATTR_VALUE_MISMATCH_ERROR = -2; 21 | const int DUPLICATE_Y_SECTION_ERROR = -3; 22 | 23 | const int UNSUPPORTED_COMPRESSION_ERROR = -4; 24 | const int TOO_BIG_SECTION_ERROR = -5; 25 | 26 | const int NO_SUPPORTING_BLOCK_ERROR = -6; 27 | 28 | const int UNKNOWN_ATTR_ERROR = -7; 29 | const int ATTR_MISMATCH_ERROR = -8; 30 | const int NOT_SUPPORTED_LEVER = -9; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /compiler/world.cpp: -------------------------------------------------------------------------------- 1 | #include "world.hpp" 2 | 3 | world::world() { 4 | this->world_data = nullptr; 5 | } 6 | 7 | void world::init(FILE *fp) { 8 | int *arr = new int[1024]; 9 | byte *temp = new byte[1048576]; 10 | byte *inflated = new byte[1048576]; 11 | int i; 12 | 13 | fseek(fp, 0, SEEK_SET); 14 | fread(temp, 1, 4096, fp); 15 | 16 | for (i=0; i<1024; ++i) { 17 | arr[i] = (temp[i << 2] << 16) | (temp[(i << 2) | 1] << 8) | temp[(i << 2) | 2]; 18 | } 19 | 20 | // for performance issues 21 | for (i=0; i<1024; ++i) { 22 | if (arr[i]) { 23 | fseek(fp, arr[i] << 12, SEEK_SET); 24 | fread(temp, 1, 5, fp); 25 | int sz = (temp[0] << 24) | (temp[1] << 16) | (temp[2] << 8) | temp[3]; 26 | if (temp[4] != 2) { 27 | throw UNSUPPORTED_COMPRESSION_ERROR; 28 | } 29 | fread(temp, 1, sz - 1, fp); 30 | 31 | { 32 | z_stream infstream; 33 | infstream.zalloc = Z_NULL; 34 | infstream.zfree = Z_NULL; 35 | infstream.opaque = Z_NULL; 36 | 37 | infstream.avail_in = (uInt)(sz - 1); 38 | infstream.next_in = (Bytef *)temp; 39 | infstream.avail_out = (uInt)1048576; 40 | infstream.next_out = (Bytef *)inflated; 41 | 42 | inflateInit(&infstream); 43 | if (inflate(&infstream, Z_NO_FLUSH) != Z_STREAM_END) { 44 | throw TOO_BIG_SECTION_ERROR; 45 | } 46 | inflateEnd(&infstream); 47 | } 48 | 49 | if (!this->world_data) { 50 | this->world_data = new chunk *[1024]; 51 | memset(this->world_data, 0, sizeof(chunk *) * 1024); 52 | } 53 | this->world_data[i] = new chunk(); 54 | try { 55 | this->world_data[i]->read(inflated); 56 | } catch (int reason) { 57 | if (reason == ATTR_VALUE_MISMATCH_ERROR) { 58 | fprintf(stderr, "Error: attribute does not have possible value; did you edit the world using hex editor?\n"); 59 | } 60 | if (!this->world_data[i]->troubleshoot(i & 31, i >> 5)) { 61 | fprintf(stderr, "in chunk (%d, %d), exact position unknown.\n", i & 31, i >> 5); 62 | } 63 | throw reason; 64 | } 65 | } 66 | } 67 | delete []temp; 68 | delete []inflated; 69 | delete []arr; 70 | } 71 | 72 | byte world::getXYZ(int x, int y, int z) const { 73 | if (!(0 <= x && x < 512 && 0 <= y && y < 255 && 0 <= z && z < 512)) return AIR; 74 | if (!this->world_data) return AIR; 75 | int idx = ((x >> 4) & 31) | (((z >> 4) & 31) << 5); 76 | if (!this->world_data[idx]) return AIR; 77 | return this->world_data[idx]->getXYZ(x, y, z); 78 | } 79 | 80 | world::~world() { 81 | if (this->world_data) { 82 | int i; 83 | for (i=0; i<1024; ++i) { 84 | if (this->world_data[i]) { 85 | delete this->world_data[i]; 86 | } 87 | } 88 | delete []this->world_data; 89 | this->world_data = nullptr; 90 | } 91 | } 92 | 93 | bool world::has_world_data(int cx, int cy, int cz) const { 94 | if (!(0 <= cx && cx < 32 && 0 <= cy && cy < 16 && 0 <= cz && cz < 32)) return false; 95 | if (!this->world_data) return false; 96 | if (!this->world_data[(cz << 5) | cx]) return false; 97 | return this->world_data[(cz << 5) | cx]->has_world_data(cy); 98 | } 99 | -------------------------------------------------------------------------------- /compiler/world.hpp: -------------------------------------------------------------------------------- 1 | #ifndef WORLD_HPP 2 | #define WORLD_HPP 3 | 4 | #include "predicate.hpp" 5 | #include "chunk.hpp" 6 | #include "zlib.h" 7 | 8 | class world { 9 | private: 10 | chunk **world_data; 11 | 12 | public: 13 | world(); 14 | ~world(); 15 | void init(FILE *fp); 16 | byte getXYZ(int x, int y, int z) const; 17 | bool has_world_data(int cx, int cy, int cz) const; 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /interpreter/Makefile: -------------------------------------------------------------------------------- 1 | all: mc-run 2 | 3 | mc-run: main.o bytestream.o node.o 4 | g++ -o mc-run main.o bytestream.o node.o 5 | 6 | main.o: main.cpp 7 | g++ -c main.cpp -O2 -std=gnu++17 8 | 9 | bytestream.o: bytestream.cpp bytestream.hpp predicate.hpp 10 | g++ -c bytestream.cpp -O2 -std=gnu++17 11 | 12 | node.o: node.cpp node.hpp predicate.hpp 13 | g++ -c node.cpp -O2 -std=gnu++17 14 | 15 | clean: 16 | rm -f *.o mc-run 17 | -------------------------------------------------------------------------------- /interpreter/bytestream.cpp: -------------------------------------------------------------------------------- 1 | #include "bytestream.hpp" 2 | 3 | bytereader::bytereader(const char *s) { 4 | fp = nullptr; 5 | buf = new byte[1048576]; 6 | open(s); 7 | } 8 | 9 | bytereader::~bytereader() { 10 | close(); 11 | delete []buf; 12 | } 13 | 14 | void bytereader::open(const char *s) { 15 | close(); 16 | fp = fopen(s, "rb"); 17 | pos = len = 0; 18 | } 19 | 20 | void bytereader::close() { 21 | if (fp) { 22 | fclose(fp); 23 | fp = nullptr; 24 | pos = len = 0; 25 | } 26 | } 27 | 28 | byte bytereader::read_byte() { 29 | if (pos == len) { 30 | if ((len = fread(buf, 1, 1048576, fp)) <= 0) { 31 | throw EOF_ERROR; 32 | } 33 | pos = 0; 34 | } 35 | return buf[pos++]; 36 | } 37 | 38 | int bytereader::read_int() { 39 | u32 x; 40 | int i; 41 | for (i=0; i<4; ++i) { 42 | (x <<= 8) |= read_byte(); 43 | } 44 | return (int)x; 45 | } 46 | -------------------------------------------------------------------------------- /interpreter/bytestream.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BYTESTREAM_HPP 2 | #define BYTESTREAM_HPP 3 | 4 | #include "predicate.hpp" 5 | 6 | class bytereader { 7 | private: 8 | FILE *fp; 9 | byte *buf; 10 | int pos, len; 11 | public: 12 | bytereader(const char *); 13 | ~bytereader(); 14 | void open(const char *); 15 | void close(); 16 | byte read_byte(); 17 | int read_int(); 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /interpreter/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using std::string; 9 | using std::queue, std::vector; 10 | using std::mt19937; 11 | 12 | #include "node.hpp" 13 | #include "bytestream.hpp" 14 | 15 | //#define UPDATE_DEBUG 16 | 17 | using std::queue; 18 | 19 | void help(string fn) { 20 | fprintf(stderr, "Usage: %s [other flags ...]\n", fn.c_str()); 21 | fprintf(stderr, "\n"); 22 | fprintf(stderr, "flags include:\n"); 23 | fprintf(stderr, " --max-tick (number)\n limit execution tick to given number of ticks maximum.\n"); 24 | fprintf(stderr, " --ban-block (wire|torch|repeater|comparator)\n if given circuit contains the block, rejects the execution.\n"); 25 | } 26 | 27 | int main(int argc, char *argv[]) { 28 | int ban_block = 0, tick_limit = -1; 29 | int parse_status = 0; 30 | string fn = ""; 31 | for (int i=1; i graph; 69 | byte b; 70 | graph.push_back(nullptr); 71 | while ((b = bs.read_byte()) != 255) { 72 | node *n = nullptr; 73 | if (ban_block & (1 << (b >> 4))) { 74 | fprintf(stderr, "stopping execution from error: banned block used\n"); 75 | return -2; 76 | } 77 | switch (b >> 4) { 78 | case 1: // redstone wire 79 | n = new wire; 80 | break; 81 | case 2: // redstone torch 82 | n = new torch; 83 | break; 84 | case 3: 85 | case 4: 86 | case 5: 87 | case 6: // repeater 88 | n = new repeater((b >> 4) - 2); 89 | break; 90 | case 7: // comparator 91 | n = new comparator; 92 | break; 93 | case 8: // subtractor 94 | n = new subtractor; 95 | break; 96 | case 9: // lever 97 | n = new lever; 98 | break; 99 | case 10: // lamp 100 | n = new lamp; 101 | break; 102 | } 103 | switch (b >> 4) { 104 | case 2: // redstone torch 105 | case 9: // lever 106 | case 10: // lamp 107 | { 108 | int u; 109 | while ((u = bs.read_int()) >= 0) { 110 | n->input.push_back(u); 111 | } 112 | } 113 | break; 114 | case 1: // redstone wire 115 | case 3: 116 | case 4: 117 | case 5: 118 | case 6: // repeater 119 | case 7: // comparator 120 | case 8: // subtractor 121 | for (int i=0; i<2; ++i) { 122 | int u; 123 | while ((u = bs.read_int()) >= 0) { 124 | n->input.push_back(u); 125 | } 126 | if (i == 0) n->input.push_back(-1); 127 | } 128 | break; 129 | } 130 | if (!n) { 131 | fprintf(stderr, "stopping execution from serious error: corrupted file!\n"); 132 | return -2; 133 | } 134 | { 135 | int u; 136 | while ((u = bs.read_int()) >= 0) { 137 | n->need_update.push_back(u); 138 | } 139 | } 140 | n->power = b & 15; 141 | graph.push_back(n); 142 | } 143 | vector input[16], output; 144 | int input_count = 0; 145 | { 146 | int u; 147 | while ((u = bs.read_int()) >= 0) { 148 | do { 149 | input[input_count].push_back(u); 150 | } while ((u = bs.read_int()) >= 0); 151 | ++input_count; 152 | } 153 | while ((u = bs.read_int()) >= 0) { 154 | output.push_back(u); 155 | } 156 | } 157 | queue temp[5], *update[5]; 158 | for (int i=0; i<5; ++i) { 159 | update[i] = &temp[i]; 160 | } 161 | for (int i=0; iset_as(t & 1)) { 167 | for (const int &x : n->need_update) { 168 | update[graph[x]->delay]->push(x); 169 | } 170 | } 171 | t >>= 1; 172 | } 173 | } 174 | int tick = 0, last_updated_tick = 0; 175 | mt19937 gen(std::chrono::steady_clock::now().time_since_epoch().count()); 176 | while (!update[0]->empty() || !update[1]->empty() || !update[2]->empty() || !update[3]->empty() || !update[4]->empty()) { 177 | if (tick_limit >= 0 && tick > tick_limit + 4) { 178 | fprintf(stderr, "stopping execution from error: tick limit exceeded\n"); 179 | return -2; 180 | } 181 | { 182 | vector temp; 183 | while (!update[0]->empty()) { 184 | temp.push_back(update[0]->front()); 185 | update[0]->pop(); 186 | } 187 | shuffle(temp.begin(), temp.end(), gen); 188 | for (const int &x : temp) { 189 | update[0]->push(x); 190 | } 191 | } 192 | while (!update[0]->empty()) { 193 | const int f = update[0]->front(); 194 | update[0]->pop(); 195 | node *now_node = graph[f]; 196 | int a = -1, b = -1; 197 | for (const int &other : now_node->input) { 198 | if (other >= 0) { 199 | a = std::max(a, graph[other]->power); 200 | } else { 201 | b = std::max(a, 0); 202 | a = 0; 203 | } 204 | } 205 | bool result = false; 206 | if (b < 0) { 207 | result = now_node->update(std::max(a, 0)); 208 | } else { 209 | result = now_node->update(b, a); 210 | } 211 | #ifdef UPDATE_DEBUG 212 | fprintf(stderr, "updated node %d, now strength = %d, redstone update = %s\n", f, now_node->power, result ? "true" : "false"); 213 | #endif 214 | if (result) { 215 | for (const int &other : now_node->need_update) { 216 | update[graph[other]->delay]->push(other); 217 | } 218 | for (const int &other : now_node->input) { 219 | if (other >= 0) { 220 | update[graph[other]->delay]->push(other); 221 | } 222 | } 223 | last_updated_tick = tick; 224 | } 225 | } 226 | ++tick; 227 | #ifdef UPDATE_DEBUG 228 | puts("==="); 229 | #endif 230 | { 231 | auto temp = update[0]; 232 | update[0] = update[1]; 233 | update[1] = update[2]; 234 | update[2] = update[3]; 235 | update[3] = update[4]; 236 | update[4] = temp; 237 | } 238 | } 239 | if (tick_limit >= 0 && last_updated_tick > tick_limit) { 240 | fprintf(stderr, "stopping execution from error: tick limit exceeded\n"); 241 | return -2; 242 | } 243 | u64 t = 0; 244 | int i; 245 | for (i=0; ipower ? 1 : 0) << i; 247 | } 248 | printf("%llu\n", t); 249 | return 0; 250 | } 251 | -------------------------------------------------------------------------------- /interpreter/node.cpp: -------------------------------------------------------------------------------- 1 | #include "node.hpp" 2 | 3 | bool node::update(int power) { 4 | return false; 5 | } 6 | 7 | bool node::update(int power, int side) { 8 | return false; 9 | } 10 | 11 | wire::wire() { 12 | this->delay = 0; 13 | } 14 | 15 | bool wire::update(int power, int side) { 16 | int calculated_power = std::max({power, side - 1, 0}); 17 | if (this->power == calculated_power) { 18 | return false; 19 | } 20 | this->power = calculated_power; 21 | return true; 22 | } 23 | 24 | torch::torch() { 25 | this->delay = 1; 26 | } 27 | 28 | bool torch::update(int power) { 29 | int calculated_power = power ? 0 : 15; 30 | if (this->power == calculated_power) { 31 | return false; 32 | } 33 | this->power = calculated_power; 34 | return true; 35 | } 36 | 37 | repeater::repeater(int delay) { 38 | this->delay = delay; 39 | this->lock = 0; 40 | } 41 | 42 | bool repeater::update(int power, int side) { 43 | if (side) { 44 | if (lock == side) { 45 | return false; 46 | } 47 | lock = side; 48 | return true; 49 | } 50 | int calculated_power = power ? 15 : 0; 51 | if (this->power == calculated_power && lock == side) { 52 | return false; 53 | } 54 | this->lock = side; 55 | this->power = calculated_power; 56 | return true; 57 | } 58 | 59 | comparator::comparator() { 60 | this->delay = 1; 61 | } 62 | 63 | bool comparator::update(int power, int side) { 64 | int calculated_power = power >= side ? power : 0; 65 | if (this->power == calculated_power) { 66 | return false; 67 | } 68 | this->power = calculated_power; 69 | return true; 70 | } 71 | 72 | subtractor::subtractor() { 73 | this->delay = 1; 74 | } 75 | 76 | bool subtractor::update(int power, int side) { 77 | int calculated_power = std::max(power - side, 0); 78 | if (this->power == calculated_power) { 79 | return false; 80 | } 81 | this->power = calculated_power; 82 | return true; 83 | } 84 | 85 | lever::lever() { 86 | this->delay = 0; 87 | } 88 | 89 | bool lever::update(int power) { 90 | return false; 91 | } 92 | 93 | bool lever::set_as(int power) { 94 | power = power ? 15 : 0; 95 | if (this->power == power) { 96 | return false; 97 | } 98 | this->power = power; 99 | return true; 100 | } 101 | 102 | lamp::lamp() { 103 | this->delay = 0; 104 | } 105 | 106 | bool lamp::update(int power) { 107 | this->power = power; 108 | return false; 109 | } 110 | 111 | -------------------------------------------------------------------------------- /interpreter/node.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NODE_HPP 2 | #define NODE_HPP 3 | 4 | #include "predicate.hpp" 5 | 6 | class node { 7 | public: 8 | vector input, need_update; 9 | int power, delay; 10 | virtual bool update(int power); 11 | virtual bool update(int power, int side); 12 | }; 13 | 14 | class wire : public node { 15 | public: 16 | wire(); 17 | bool update(int power, int side); 18 | }; 19 | 20 | class torch : public node { 21 | public: 22 | torch(); 23 | bool update(int power); 24 | }; 25 | 26 | class repeater : public node { 27 | public: 28 | int lock; 29 | repeater(int delay); 30 | bool update(int power, int side); 31 | }; 32 | 33 | class comparator : public node { 34 | public: 35 | comparator(); 36 | bool update(int power, int side); 37 | }; 38 | 39 | class subtractor : public node { 40 | public: 41 | subtractor(); 42 | bool update(int power, int side); 43 | }; 44 | 45 | class lever : public node { 46 | public: 47 | lever(); 48 | bool update(int power); 49 | bool set_as(int power); 50 | }; 51 | 52 | class lamp : public node { 53 | public: 54 | lamp(); 55 | bool update(int power); 56 | }; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /interpreter/predicate.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PREDICATE_HPP 2 | #define PREDICATE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using std::vector; 10 | using std::max; 11 | 12 | typedef unsigned char byte; 13 | typedef unsigned int u32; 14 | typedef long long int i64; 15 | typedef unsigned long long int u64; 16 | 17 | const int EOF_ERROR = -1; 18 | const int ADJUSTED_NONLEVER_ERROR = -2; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /target/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | --------------------------------------------------------------------------------