LoginSignup
0
0

More than 5 years have passed since last update.

「オフラインリアルタイムどう書く第19回(不良セクタの隣)」の問題を解いてみた

Posted at

横浜へなちょこプログラミング勉強会にて過去に出題された不良セクタの隣を解いてみた。
回答にかかった時間は100分程度と40分オーバー。

初めはDisckSectors#search_pending_sectorsの中にごちゃごちゃと条件文やら数式やら書いていたのだが、書いていて自分で混乱してしまったのでかなり細かくメソッドに分けることにした。
結果search_pending_sectorsの中身自体はすごくシンプルになったのだが、その代わりごちゃごちゃとプライベートメソッドを生やしすぎてしまった。
プライベートメソッドたちはリファクタリングすればもっと減らせる(そもそもメソッドにする必要すらないものもある)のだが、テストにパスした時点で目標時間60分を大幅に超えていたため、ひとまずこのままとすることにした。

class DiscSectors
  def search_pending_sectors bad_sectors
    bad_sectors = bad_sectors.split(",").map &:to_i
    neighbor_sectors = bad_sectors.inject([]){|addresses, addr|
      track, sec = addr.to_i.divmod(100)
      [
        addresses,
        next_address(track, sec),
        prev_address(track, sec),
        track < 4 ? next_track_addresses(track, sec) : nil,
        track > 1 ? prev_track_addresses(track, sec) : nil
      ].flatten
    } - bad_sectors
    pending = neighbor_sectors.compact.group_by{|v| v}.select{|addr, group| group.size > 1}.keys.sort
    pending.empty? ? ["none"] : pending
  end

  private

  def next_address track, sec
    track_address(track, sec + 1)
  end

  def prev_address track, sec
    track_address(track, sec - 1)
  end

  def next_track_addresses track, sec
    [
      (sec % track).zero? ? track_address(track + 1, next_track_bigger_sector(track, sec) - 1) : nil,
      track_address(track + 1, next_track_bigger_sector(track, sec)),
      track_address(track + 1, next_track_bigger_sector(track, sec) + 1)
    ].compact
  end

  def prev_track_addresses track, sec
    address = [
      track_address(track - 1, prev_track_bigger_sector(track, sec)),
      (sec % track).zero? ? nil : track_address(track - 1, prev_track_bigger_sector(track, sec) - 1)
    ].compact
  end

  def track_address track, sec
    track_address_group(track) + track_sector(track, sec)
  end

  def track_address_group track
    track * 100
  end

  def next_track_bigger_sector track, sec
    (track + 1) * (sec / track) + (sec % track)
  end

  def prev_track_bigger_sector track, sec
    (track - 1) * (sec / track) + (sec % track)
  end

  def track_sector track, serial_number
    serial_number % track_sectors(track)
  end

  def track_sectors track
    8 * track
  end
end

test = <<_TEST
/*0*/ test( "400,401,302", "300,301,402" );    
/*1*/ test( "105,100,306,414", "none" );    
/*2*/ test( "100", "none" );    
/*3*/ test( "211", "none" );    
/*4*/ test( "317", "none" );    
/*5*/ test( "414", "none" );    
/*6*/ test( "100,106", "107" );    
/*7*/ test( "205,203", "102,204" );    
/*8*/ test( "303,305", "304" );    
/*9*/ test( "407,409", "306,408" );    
/*10*/ test( "104,103", "207" );    
/*11*/ test( "204,203", "102,305" );    
/*12*/ test( "313,314", "209,418" );    
/*13*/ test( "419,418", "314" );    
/*14*/ test( "100,102,101", "201,203" );    
/*15*/ test( "103,206,309", "205,207,308,310" );    
/*16*/ test( "414,310,309", "206,311,413" );    
/*17*/ test( "104,102,206,307,102,202", "101,103,203,204,205,207,308" );    
/*18*/ test( "104,206,308,409,407", "103,205,207,306,307,309,408,410" );    
/*19*/ test( "313,406,213,301,409,422,412,102,428", "none" );    
/*20*/ test( "101,300,210,308,423,321,403,408,415", "none" );    
/*21*/ test( "304,316,307,207,427,402,107,431,412,418,424", "none" );    
/*22*/ test( "205,408,210,215,425,302,311,400,428,412", "none" );    
/*23*/ test( "200,311,306,412,403,318,427,105,420", "none" );    
/*24*/ test( "105,305,407,408,309,208,427", "104,209,306,406" );    
/*25*/ test( "311,304,322,404,429,305,316", "203,303,321,405,406,430" );    
/*26*/ test( "210,401,316,425,101", "211,315" );    
/*27*/ test( "414,403,404,416,428,421", "303,415" );    
/*28*/ test( "207,300,103,211,428", "104,206" );    
/*29*/ test( "322,314,310", "none" );    
/*30*/ test( "427,200,215", "100,323" );    
/*31*/ test( "311,402,424,307,318,430,323,305,201", "200,204,301,302,306,322,423,425,431" );    
/*32*/ test( "425,430,408", "none" );    
/*33*/ test( "202,320,209,426", "319,427" );    
/*34*/ test( "430,209,302,310,304,431,320", "202,303,323" );    
/*35*/ test( "208,206,406,424,213,312", "207,311,313" );    
/*36*/ test( "420,302,313,413,317,402", "301,403" );    
/*37*/ test( "319,306,309,418,204,411", "305,307,308,412" );    
/*38*/ test( "400,308,105,430,203,428,209", "104,210,429,431" );    
/*39*/ test( "200,305,214", "215" );    
/*40*/ test( "214,408,410,407,317,422", "306,316,409,423" );
_TEST

require 'minitest/autorun'

describe 'BadSector' do
  test.split("\n").each do |line|
    t, n, input, expect = line.match(/^\/\*(\d+)\*\/\s*test\(\s*"([^"]+)",\s*"([^"]+)"\s*\);\s*$/).to_a
    disc = DiscSectors.new
    it input do
      assert_equal expect, disc.search_pending_sectors(input).join(",")
    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