Last active
March 6, 2017 10:31
-
-
Save mizuhara/b6a63b78d99915393c39edb63c497e9f to your computer and use it in GitHub Desktop.
An answer of http://mtsmfm.github.io/2017/03/04/doukaku-e12.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <vector> | |
#include <string> | |
#include <memory> | |
#include <iostream> | |
#include <algorithm> | |
#include <unordered_map> | |
struct is_tetromino | |
{ | |
bool operator()(char chr) | |
{ | |
return std::string("ILOST").find(chr) != std::string::npos; | |
} | |
}; | |
auto parse(const std::string & src) | |
{ | |
auto s { src }; | |
std::vector<std::pair<int, std::string>> res; | |
for(auto it = std::find_if(s.begin(), s.end(), is_tetromino()); it != s.end();) { | |
const auto pos = std::distance(s.begin(), it); | |
const auto move = std::stoi(s.substr(0, pos)); | |
const auto shape = s.substr(pos, 1); | |
res.push_back({ move, shape }); | |
s = s.substr(pos + 1); | |
it = std::find_if(s.begin(), s.end(), is_tetromino()); | |
} | |
return res; | |
} | |
class Board | |
{ | |
public: | |
void update(int x, int y) | |
{ | |
if(board_.find(x) == board_.end()) { | |
board_.insert({ x, y }); | |
} else { | |
board_[x] = y; | |
} | |
} | |
auto height_at(int x) const | |
{ | |
const auto found = board_.find(x); | |
return (found == board_.end()) ? 0 : found->second; | |
} | |
auto max_height() const | |
{ | |
auto max { 0 }; | |
for(auto && p : board_) { | |
max = std::max(max, p.second); | |
} | |
return max; | |
} | |
private: | |
std::unordered_map<int, int> board_; | |
}; | |
class HeightCalculator | |
{ | |
public: | |
virtual std::vector<std::pair<int, int>> height(const Board & board, int move) const = 0; | |
virtual ~HeightCalculator() = default; | |
}; | |
class HeightCalculatorI :public HeightCalculator | |
{ | |
public: | |
std::vector<std::pair<int, int>> height(const Board & board, int move) const | |
{ | |
return { { move, board.height_at(move) + 4 } }; | |
} | |
}; | |
class HeightCalculatorL :public HeightCalculator | |
{ | |
public: | |
std::vector<std::pair<int, int>> height(const Board & board, int move) const | |
{ | |
const auto y0 = board.height_at(move); | |
const auto y1 = board.height_at(move + 1); | |
const auto offset = std::max(y0, y1); | |
return { { move, offset + 3 }, { move + 1, offset + 1 } }; | |
} | |
}; | |
class HeightCalculatorO :public HeightCalculator | |
{ | |
public: | |
std::vector<std::pair<int, int>> height(const Board & board, int move) const | |
{ | |
const auto y0 = board.height_at(move); | |
const auto y1 = board.height_at(move + 1); | |
const auto offset = std::max(y0, y1); | |
return { { move, offset + 2 }, { move + 1, offset + 2 } }; | |
} | |
}; | |
class HeightCalculatorS :public HeightCalculator | |
{ | |
public: | |
std::vector<std::pair<int, int>> height(const Board & board, int move) const | |
{ | |
const auto y0 = board.height_at(move); | |
const auto y1 = board.height_at(move + 1); | |
const auto y2 = board.height_at(move + 2); | |
if((2 <= y2 - y0) && (2 <= y2 - y1)) { | |
return { { move, y2 }, { move + 1, y2 + 1 }, { move + 2, y2 + 1 } }; | |
} | |
if((2 < y2 - y0) && (2 < y2 - y1)) { | |
return { { move, 1 }, { move + 1, 2 }, { move + 2, 2 } }; | |
} | |
const auto offset = std::max(y0, y1); | |
return { { move, offset + 1 }, { move + 1, offset + 2 }, { move + 2, offset + 2 } }; | |
} | |
}; | |
class HeightCalculatorT :public HeightCalculator | |
{ | |
public: | |
std::vector<std::pair<int, int>> height(const Board & board, int move) const | |
{ | |
const auto y0 = board.height_at(move); | |
const auto y1 = board.height_at(move + 1); | |
const auto y2 = board.height_at(move + 2); | |
if(y0 <= y1 && y2 <= y1) { | |
const auto offset = y1 + 2; | |
return { { move, offset }, { move + 1, offset }, { move + 2, offset } }; | |
} | |
const auto offset = std::max(y0, y2) + 1; | |
return { { move, offset }, { move + 1, offset }, { move + 2, offset } }; | |
} | |
}; | |
std::unique_ptr<HeightCalculator> make_height_calculator(const std::string & shape) | |
{ | |
if(shape == "I") { | |
return std::make_unique<HeightCalculatorI>(); | |
} | |
if(shape == "L") { | |
return std::make_unique<HeightCalculatorL>(); | |
} | |
if(shape == "O") { | |
return std::make_unique<HeightCalculatorO>(); | |
} | |
if(shape == "S") { | |
return std::make_unique<HeightCalculatorS>(); | |
} | |
return std::make_unique<HeightCalculatorT>(); | |
} | |
auto solve(const std::string & src) | |
{ | |
Board board; | |
const auto move_and_shape = parse(src); | |
for(auto && e : move_and_shape) { | |
const auto move = e.first; | |
const auto shape = e.second; | |
const auto height_calculator = make_height_calculator(shape); | |
for(auto && p : height_calculator->height(board, move)) { | |
board.update(p.first, p.second); | |
} | |
} | |
return std::to_string(board.max_height()); | |
} | |
void test(const std::string & src, const std::string & expected) | |
{ | |
const auto actual = solve(src); | |
std::cout << (actual == expected ? "ok" : "***NG***") << std::endl; | |
} | |
int main() | |
{ | |
/*0*/ test("1O3L0I0T", "5"); | |
/*1*/ test("0I", "4"); | |
/*2*/ test("0I0I", "8"); | |
/*3*/ test("0I1I2I3I4I", "4"); | |
/*4*/ test("0S0I", "5"); | |
/*5*/ test("0I0S", "6"); | |
/*6*/ test("2S0T2O3I", "8"); | |
/*7*/ test("4O4T1T0S4L1L3L", "10"); | |
/*8*/ test("0S2S4S6S8S10S12S14S", "16"); | |
/*9*/ test("14S12S10S8S6S4S2S0S", "2"); | |
/*10*/ test("5I2O10I0O4L10T9T11L8I2I10I12O7L12T12T12S11T9O10O13I12O10O7I9I7O0S1O2S0L1L", "23"); | |
/*11*/ test("9T14L10L8T4I1T3S5I8T12O3S7L9O7L14T2I7O3S6S2L0L13T10O4I9T7L8S0I12O9S11L11T14T", "27"); | |
/*12*/ test("9S9S7O11O16I2T9O12L10T9O0O13I9O1I2T14S7O9S11T5L7I14T13O0T12I3S10L10O7I15I6S2L12S8I16I3L", "23"); | |
/*13*/ test("11T13I16S15T7O10L12S1I5I8S5I13I15O8S9I1T12I1S5S0L14I12L16T2S2S8L2S14L16O4I13L15L13S11S9T13S9S3L6O", "22"); | |
/*14*/ test("12L10S7I5L14T12S9L1T14I0I5L1T2O18T9L0I15I16L10S1O15I0L17O5L18T4I18L7L7I13I3I12I2S3T5T3S16L14S14O11O15T14S", "17"); | |
/*15*/ test("0S18S2S19I14T7L14L2L6I9I0L4I5L13L15I8S8T2I5I7O18T3S1T7I2L8O0S20T9I14T5L5I1T4L9O8T19T5S12O16T19L4O10O10T14L", "24"); | |
/*16*/ test("7T5L6S4S8T6S10I19O20L14I18L21S7I11S11O1L13T20O9I7L2T8L2S20L3O14L9T17I8L8S14I6T2O11T21O18O6T15T1S3L6O19S18O20S19O16T6S14T", "26"); | |
/*17*/ test("18S2I4S16L13S17I21O8I17T8I14O12T20I20S19S16S13T12T20I22I15O2I2I8I2S18I9I9T6O13O13L17I2L20L2L4I9I19O11T3S10O2S18T12I5O11S19O21S6I17T17S", "26"); | |
/*18*/ test("11L5S0T22S18O13T2O22S15I12I21T16I3I1I22L11L11L22O13S24S15L13T15S19L10O15T7S24T19L0T13O11I12T13S4I24L15O3S19O10L19O0S20L7O11L21I22S18T19T23O8I22S24L0S", "21"); | |
/*19*/ test("7L7I11T7S18O17L8S15L9I3O24S3O1O5O14L9T13S2O25S22T10T8L24S18S13T1O1L6I10I4S13O3S7L10T1T4L17S20I18O15S25S23S21I19T6O24S9L2O2O15L12L8L8O18I18L0T5O", "31"); | |
/*20*/ test("999I999I999I999I999I999I999I999I999I999I999I", "44"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment