Created
October 12, 2014 13:56
-
-
Save joker1007/fa5407ecef312d94cb30 to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env ruby | |
require 'pp' | |
require 'rspec-power_assert' | |
class Point | |
attr_reader :row, :col | |
def initialize(row, col) | |
@row, @col = row, col | |
end | |
def ==(other) | |
other.is_a?(Point) && row == other.row && col == other.col | |
end | |
def is_out_of_table?(table) | |
!(table.row_range.cover?(row) && table.col_range.cover?(col)) | |
end | |
def around_points_with_direction(direction) | |
start_point = Point.new(row - 1, col - 1) | |
direction.new(start_point).map(&:itself) | |
end | |
def right_point | |
Point.new(row, col + 1) | |
end | |
def left_point | |
Point.new(row, col - 1) | |
end | |
def up_point | |
Point.new(row - 1, col) | |
end | |
def down_point | |
Point.new(row + 1, col) | |
end | |
end | |
class Table | |
attr_reader :data, :min_row, :min_col, :max_row, :max_col, :last_rotate_chars | |
def initialize(size = 5) | |
@min_row, @min_col = 0, 0 | |
@max_row, @max_col = size - 1, size - 1 | |
initial_char = 'a' | |
@data = size.times.each_with_object([]) do |_, table| | |
table << [] | |
size.times do | |
table.last << initial_char | |
initial_char = initial_char.succ | |
end | |
end | |
end | |
def row_range | |
@min_row..@max_row | |
end | |
def col_range | |
@min_col..@max_col | |
end | |
def get_point_of(char) | |
@data.each_with_index do |row, row_count| | |
row.each_with_index do |col, col_count| | |
if col == char | |
return Point.new(row_count, col_count) | |
end | |
end | |
end | |
nil | |
end | |
def result | |
@last_rotate_chars.sort.join | |
end | |
def rotate(cmds) | |
cmds.each do |cmd| | |
do_rotate(cmd) | |
end | |
self | |
end | |
def do_rotate(cmd) | |
@last_rotate_chars = [] | |
point = get_point_of(cmd.char) | |
around_points = point.around_points_with_direction(cmd.direction).reject do |pt| | |
pt.is_out_of_table?(self) | |
end | |
around_points.inject(@data[around_points.last.row][around_points.last.col]) do |pre, pt| | |
store = @data[pt.row][pt.col].dup | |
@last_rotate_chars << store | |
@data[pt.row][pt.col] = pre | |
store | |
end | |
end | |
end | |
module DirectionStep | |
module Up | |
def self.next_point_from(point) | |
point.up_point | |
end | |
end | |
module Down | |
def self.next_point_from(point) | |
point.down_point | |
end | |
end | |
module Right | |
def self.next_point_from(point) | |
point.right_point | |
end | |
end | |
module Left | |
def self.next_point_from(point) | |
point.left_point | |
end | |
end | |
end | |
class DirectionTraverser | |
include Enumerable | |
def initialize(start_point) | |
@start_point = start_point | |
@point = nil | |
end | |
def each | |
if block_given? | |
while set_next_point | |
yield @point | |
end | |
else | |
Enumerator.new do |y| | |
while set_next_point | |
y << @point | |
end | |
end | |
end | |
end | |
def set_next_point | |
unless @point | |
@point = @start_point | |
return @point | |
end | |
@point = @direction.next_point_from(@point) | |
set_direction | |
@point == @start_point ? nil : @point | |
end | |
end | |
class ClockwiseTraverser < DirectionTraverser | |
def initialize(start_point) | |
super | |
@direction = DirectionStep::Right | |
end | |
def set_direction | |
if @point.col == @start_point.col + 2 && @point.row < @start_point.row + 2 | |
@direction = DirectionStep::Down | |
elsif @point.row == @start_point.row + 2 && @point.col > @start_point.col | |
@direction = DirectionStep::Left | |
elsif @point.col == @start_point.col | |
@direction = DirectionStep::Up | |
end | |
end | |
end | |
class CounterClockwiseTraverser < DirectionTraverser | |
def initialize(start_point) | |
super | |
@direction = DirectionStep::Down | |
end | |
def set_direction | |
if @point.row == @start_point.row + 2 && @point.col < @start_point.col + 2 | |
@direction = DirectionStep::Right | |
elsif @point.col == @start_point.col + 2 && @point.row > @start_point.row | |
@direction = DirectionStep::Up | |
elsif @point.row == @start_point.row | |
@direction = DirectionStep::Left | |
end | |
end | |
end | |
class Command | |
attr_reader :direction, :char | |
def initialize(direction, char) | |
@direction, @char = direction, char.downcase | |
end | |
def self.parse(str) | |
str.each_char.map do |c| | |
if c == c.upcase | |
Command.new(CounterClockwiseTraverser, c) | |
else | |
Command.new(ClockwiseTraverser, c) | |
end | |
end | |
end | |
end | |
TEST_DATA = [ | |
[ "YokoHamarb", "acdfp" ], | |
[ "Ruby", "twx" ], | |
[ "ruby", "nst" ], | |
[ "PHP", "gkluv" ], | |
[ "a", "bfg" ], | |
[ "b", "acfgh" ], | |
[ "m", "ghilnqrs" ], | |
[ "mg", "bcdhilmq" ], | |
[ "Mg", "fhiklmpq" ], | |
[ "MS", "ijmnoqrt" ], | |
[ "mG", "bcdhilmq" ], | |
[ "lf", "abcghklp" ], | |
[ "paq", "lprvw" ], | |
[ "bFH", "abcfg" ], | |
[ "Agh", "abcfgklm" ], | |
[ "Msul", "pruvw" ], | |
[ "RSRX", "jorty" ], | |
[ "xTsn", "ijmos" ], | |
[ "FHwnQ", "lmorsvwx" ], | |
[ "jIDIb", "cfghilmo" ], | |
[ "rLGPq", "ilmnprvx" ], | |
[ "WRiFhd", "ceg" ], | |
[ "gkfLfh", "cfglmpqr" ], | |
[ "STydYQ", "hklmpruv" ], | |
[ "spaeAWJ", "cdehimns" ], | |
[ "xTxTXwY", "mwx" ], | |
[ "xyQMkMi", "cdejlnow" ], | |
[ "HJkxpWxA", "cdhkp" ], | |
[ "hgaGDodg", "djo" ], | |
[ "abKBmkBc", "bdfik" ], | |
[ "mCvlhnilm", "adfgikqr" ], | |
[ "StyxTYsIh", "imnostxy" ], | |
[ "HLHnhLMLC", "ahlmn" ], | |
[ "DuHmbFQysI", "ehj" ], | |
[ "cGfGCaLgCq", "acguv" ], | |
[ "OisYOrOXwq", "ilnstvwx" ], | |
[ "wMnYIukHAvO", "bdefhjmn" ], | |
[ "HCfBhKHkhDF", "abdghikn" ], | |
[ "pUPmwrHsYSH", "morsy" ], | |
[ "PnCYYWnPoUxq", "bfopv" ], | |
[ "DiojiYXowowr", "cilmnstw" ], | |
[ "HLNsiNMnbAnn", "abdkm" ], | |
] | |
TEST_DATA.each do |td| | |
describe "めぐるセル #{td[0]}" do | |
let(:table) { Table.new } | |
let(:cmds) { Command.parse(td[0]) } | |
before do | |
table.rotate(cmds) | |
end | |
it_is_asserted_by { table.result == td[1] } | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment