Skip to content

Instantly share code, notes, and snippets.

@mizuhara
Last active August 29, 2015 14:06
Show Gist options
  • Save mizuhara/44897fdf3110b39a0870 to your computer and use it in GitHub Desktop.
Save mizuhara/44897fdf3110b39a0870 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <set>
#include <string>
#include <vector>
#include <cassert>
using namespace std;
typedef pair<int, int> point_t;
typedef vector<vector<string>> board_t;
const int width = 5;
const int height = 5;
enum direction
{
U = 0, D, L, R,
};
struct range
{
int left;
int right;
int top;
int bottom;
range(int l, int r, int t, int b)
:left(l), right(r), top(t), bottom(b) {}
};
struct from_to
{
point_t from;
point_t to;
};
board_t rotate(const board_t &board, const vector<from_to> &ft)
{
board_t rot_board;
for(int h = 0; h < height; ++h) {
vector<string> tmp;
for(int w = 0; w < width; ++w) {
tmp.push_back(board[h][w]);
}
rot_board.push_back(tmp);
}
for(const auto &e : ft) {
rot_board[e.to.first][e.to.second] = board[e.from.first][e.from.second];
}
return rot_board;
}
vector<from_to> concat(const vector<vector<from_to>> &fts)
{
vector<from_to> v;
for(const auto &ft : fts) {
for(const auto &e : ft) {
v.push_back(e);
}
}
return v;
}
vector<string> split(const string &src)
{
vector<string> v;
string s = src;
size_t pos = s.find(",");
while(pos != string::npos) {
v.push_back(s.substr(0, pos));
s = s.substr(pos + 1);
pos = s.find(",");
}
if(!s.empty()) {
v.push_back(s);
}
return v;
}
range get_range(const board_t &board, const string &s)
{
point_t p1, p2;
for(int h = 0; h < height; ++h) {
const string s1 = s.substr(0, 1);
const string s2 = s.substr(1, 1);
for(int w = 0; w < width; ++w) {
if(s1 == board[h][w]) {
p1 = { h, w };
}
if(s2 == board[h][w]) {
p2 = { h, w };
}
}
}
range r( min(p1.second, p2.second), max(p1.second, p2.second), min(p1.first, p2.first), max(p1.first, p2.first) );
return r;
}
bool is_in_board(const point_t &p)
{
return (0 <= p.first && p.first < height) && (0<= p.second && p.second < width);
}
bool is_up_or_down(direction d)
{
return d == U || d == D;
}
point_t warp(const range &r, direction d)
{
const vector<vector<point_t>> points = {
{ {r.top, r.right + 1}, {r.bottom + 1, r.right}, {r.bottom, r.left - 1} },
{ {r.bottom, r.left - 1}, {r.top - 1, r.left}, {r.top, r.right + 1} },
{ {r.top - 1, r.left}, {r.top, r.right + 1}, {r.bottom + 1, r.right} },
{ {r.bottom + 1, r.right}, {r.bottom, r.left - 1}, {r.top - 1, r.left} },
};
const vector<point_t> point = points[d];
for(const auto &p : point) {
if(is_in_board(p)) {
return p;
}
}
assert(!"Invalid path.");
}
vector<from_to> move(direction d, const board_t &board, const range &r, const point_t &p, int n)
{
vector<from_to> v;
if(n <= -1 || width <= n) return v;
const point_t diffs[] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
for(int i = p.first; i <= p.second; ++i) {
if(i <= -1 || width <= i) continue;
const point_t diff = diffs[d];
point_t next = is_up_or_down(d) ? point_t( i + diff.first, n ) : point_t( n, i + diff.second );
if(!is_in_board(next)) {
next = warp(r, d);
}
from_to ft;
ft.from = is_up_or_down(d) ? point_t( i, n ) : point_t( n, i ); ft.to = next;
v.push_back(ft);
}
return v;
}
string join(const set<string> &s)
{
string str;
for(auto it = s.begin(); it != s.end(); ++it) {
str += (*it);
}
return str;
}
string format(const board_t &board, const vector<from_to> &ft)
{
if(ft.empty()) {
return "none";
}
set<string> s;
for(const auto &e : ft) {
s.insert(board[e.to.first][e.to.second]);
}
return join(s);
}
vector<from_to> solve_core(const board_t &board, const string &key)
{
const vector<point_t> diffs = {
{ 0, 1 }, { -1, 0 }, { 0, 1 }, { -1, 0 },
};
vector<vector<from_to>> fts;
const range r = get_range(board, key);
const vector<int> v = { r.left - 1, r.right + 1, r.bottom + 1, r.top - 1 };
for(const auto &d : { U, D, L, R }) {
const point_t diff = diffs[d];
const point_t p = is_up_or_down(d) ?
point_t( r.top + diff.first, r.bottom + diff.second ) :
point_t( r.left + diff.first, r.right + diff.second );
fts.push_back(move(d, board, r, p, v[d]));
}
return concat(fts);
}
string solve(const string &src)
{
const string a_to_y = "abcdefghijklmnopqrstuvwxy";
board_t board;
for(int h = 0; h < height; ++h) {
vector<string> tmp;
for(int w = 0; w < width; ++w) {
const int i = h * 5 + w;
tmp.push_back(a_to_y.substr(i, 1));
}
board.push_back(tmp);
}
vector<from_to> ft;
const vector<string> keys = split(src);
for(const auto &key : keys) {
ft = solve_core(board, key);
board = rotate(board, ft);
}
return format(board, ft);
}
void test(const string &src, const string &expected)
{
static int no = 0;
const string actual = solve(src);
if(actual == expected) {
cout << no << " -> OK" << endl;
} else {
cout << no << " -> ***NG*** (actual -> " << actual << ", expected -> " << expected << ")" << endl;
}
++no;
}
int main()
{
/*0*/ test( "ab,gg,uj,pt,an,ir,rr", "hpqsvwxy" );
/*1*/ test( "gs,ok", "abcdftvwxy" );
/*2*/ test( "gs,sg,ok", "none" );
/*3*/ test( "aa,bb,hh,nn", "hiostwxy" );
/*4*/ test( "ae,ko,uy,cw", "bdgilnqsvx" );
/*5*/ test( "am,gs,am,gs,am,gs,am,gs", "cfhkmqrvwx" );
/*6*/ test( "ay", "none" );
/*7*/ test( "gs,ay", "defjkoptuv" );
/*8*/ test( "bx,ay", "none" );
/*9*/ test( "ft,ay", "defjkoptuv" );
/*10*/ test( "ab,cd,ef,gh,ij,kl,mn,op,qr,st,uv,wx", "cdjmnry" );
/*11*/ test( "wx,uv,st,qr,op,mn,kl,ij,gh,ef,cd,ab", "kmoxy" );
/*12*/ test( "am,cj,ac,em,ss,cy,aa,ee,ff,vp", "none" );
/*13*/ test( "uf,oq,gn,ss,ca,hv,ej", "none" );
/*14*/ test( "cc,wk,uu,ws,bk,aa,vv", "bei" );
/*15*/ test( "tr,ou,ll,pp,jh,vf,yy,nr,rr,oo", "rxy" );
/*16*/ test( "ky,ov,ri,qm,nn,ee,ws,em,ca,ak", "biju" );
/*17*/ test( "ty", "nosx" );
/*18*/ test( "ll,uh,hq,ss,nx,ry,ku,ab,jj", "efouv" );
/*19*/ test( "yl,mu,qj,ss,ep", "mnqru" );
/*20*/ test( "kj,ee,qk", "fglruv" );
/*21*/ test( "xi,wd,hf", "ciknqr" );
/*22*/ test( "fx,ak,cc,ce", "bdhijnp" );
/*23*/ test( "li,jf,pp,qm,hg,sf", "akntuwx" );
/*24*/ test( "jw", "bcdeglqv" );
/*25*/ test( "uk,oe,xr", "dglmoqsy" );
/*26*/ test( "bb,ov,pd,dd,xk,is,hh,xd,xx,kq,pp,ku", "cfhjopqvy" );
/*27*/ test( "iq,fn,il,ww,ox,la,or,ga,wg,ef,us", "cfgjopvxy" );
/*28*/ test( "km,po", "abcdenqrst" );
/*29*/ test( "tc,mh,cw", "abefjkoptu" );
/*30*/ test( "fm,jx,xx,pi,gs,au,uq,ut,ap,vb", "cdghjmortux" );
/*31*/ test( "ik,xl,si", "abcdflorvwx" );
/*32*/ test( "nu,cc,lv,bu,tt,ww,xk,ia,in,sa,my", "abcefgpqrstu" );
/*33*/ test( "tt,ak,xh,tk,oo,yr,na,yv,gm,vh", "degiklmnquwx" );
/*34*/ test( "kk,ob,kk,fm,xk", "acdegjlopqruy" );
/*35*/ test( "uq,ko,pf,yy,ig,tu,ve,ve,qy,mh,oo,dv", "befjkoqrtuwxy" );
/*36*/ test( "aj,hb,ar,ii,np,ki,hg,vd", "cefhjlmopqtwxy" );
/*37*/ test( "vv,sf,ww,my,mm,sq,fb,ly,fu,ls", "bfghkmnptuvwxy" );
/*38*/ test( "jj,bp,gs", "abdefijkprtuvwxy" );
/*39*/ test( "sv,sn,mn,gn,gi", "abcdefhjnpqtuvxy" );
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment