Last active
August 29, 2015 14:06
-
-
Save mizuhara/44897fdf3110b39a0870 to your computer and use it in GitHub Desktop.
An answer of http://nabetani.sakura.ne.jp/hena/ord25rotcell/
This file contains hidden or 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 <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