LoginSignup
0
0

More than 5 years have passed since last update.

「オフラインリアルタイムどう書く第25回(めぐるセル)」の問題を解いてみた

Posted at

横浜へなちょこプログラミング勉強会にて過去に出題されためぐるセルを解いてみた。
回答にかかった時間はぎりぎり60分。

  1. 指定セルの外周を取得
  2. 外周を時計回りさせやすいようにソート
  3. Array.rotateで時計回りとなるようにセルの入れ替え
  4. 入れ替えたセルの内容を返す

もうちょっとうまいやり方があったんじゃないだろうかと思うが、考えているばかりで時間が過ぎてしまったのでひとまず真っ先に思いついた方法で実装してしまった。

class RotationBox
  def initialize
    chars = (?a..?y).to_a
    @sort_priority = [:top_left, :top, :top_right, :right, :bottom_right, :bottom, :bottom_left, :left]
    @box = 5.times.map{|y|
      5.times.map{|x|
        chars[(y * 5) + x]
      }
    }
  end

  def rotate_all input
    last = input.scan(/(\w)(\w)/).inject([]){|r, (a, b)|
      rotate a, b
    }
    last.empty? ? "none" : last.sort.join
  end

  private

  def axis val
    @box.each.with_index.inject([nil, nil]){|r, (line, y)|
      if x = line.find_index(val)
        break [x, y]
      else
        r
      end
    }
  end

  def rotate a, b
    ax, ay = axis a
    bx, by = axis b
    top, bottom, left, right = [
      ay < by ? ay : by,
      ay > by ? ay : by,
      ax < bx ? ax : bx,
      ax > bx ? ax : bx
    ]
    round = round(top, bottom, left, right).sort{|(axx, ayy), (bxx, byy)|
      position_a = position axx, ayy, top, bottom, left, right
      position_b = position bxx, byy, top, bottom, left, right
      if position_a == :top and position_b == :top
        axx <=> bxx
      elsif position_a == :right and position_b == :right
        ayy <=> byy
      elsif position_a == :bottom and position_b == :bottom
        (axx <=> bxx) * -1
      elsif position_a == :left and position_b == :left
        (ayy <=> byy) * -1
      else
        @sort_priority.index(position_a) <=> @sort_priority.index(position_b)
      end
    }
    round.map{|(x, y)| @box[y][x]}.rotate(-1).each.with_index{|c, i|
      x, y = round[i]
      @box[y][x] = c
    }
  end

  def block top, bottom, left, right
    5.times.select{|x|
      x.between? left, right
    }.product(5.times.select{|y|
      y.between? top, bottom
    })
  end

  def round top, bottom, left, right
    block = block top, bottom, left, right
    block.map{|(x, y)|
      [
        [x - 1, y - 1], [x    , y - 1], [x + 1, y - 1],
        [x - 1, y    ], [x + 1, y    ],
        [x - 1, y + 1], [x    , y + 1], [x + 1, y + 1]
      ].select{|xx, yy|
        xx.between?(0, 4) && yy.between?(0, 4) && !block.include?([xx, yy])
      }
    }.flatten(1).uniq
  end

  def position x, y, top, bottom, left, right
    if top > y
      left > x ? :top_left : (right < x ? :top_right : :top)
    elsif bottom < y
      left > x ? :bottom_left : (right < x ? :bottom_right : :bottom)
    elsif left > x
      :left
    elsif right < x
      :right
    end
  end
end

test = <<_TEST
/*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" );
_TEST

require 'minitest/autorun'

describe 'Rotate' do
  test.split("\n").each do |line|
    t, n, input, expect = line.match(/^\/\*(\d+)\*\/\s*test\(\s*"([^"]+)",\s*"([^"]+)"\s*\);*\s*$/).to_a
    box = RotationBox.new
    it input do
      assert_equal expect, box.rotate_all(input)
    end
  end
end
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0