オフラインリアルタイムどう書く E05 に出した問題の実装例(ruby, C11)


問題 http://nabetani.sakura.ne.jp/hena/orde05dokitruck/
実装リンク集 http://qiita.com/Nabetani/items/c516875b13a4d282affe
です。

で。

実装方針はいくつかあって。

  • 右から行くか、左から行くか。
  • ひとつひとつ行くか、一気に行くか。
  • データを何で持つか

辺りで自由に選べるつもり。

私は、後ろから、一気に計算して、データはビット。

まずは、C11かC99 ぐらいによる実装:

// clang -std=c11 -Wall
// clang x86_64-apple-darwin15.5.0
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <memory.h>

char * build_ans( int s )
{
  char * r = calloc(4, 1);
  for( int i=0 ; i<3 ; ++i ){
    if ( s&(1<<i) ){
      strcat( r, (char[2]){'a'+i});
    }
  }
  if ( !*r ){
    r[0]='-';
  }
  return r;
}

char * solve( char const * src )
{
  int s=7;
  for( char const * it = src + strlen( src ) -1 ; src<=it ; --it ){
    switch(*it-'0'){
    case 1: s|=s/2; break;
    case 2: s|=(s&2)*2+!!(s&4); break;
    case 3: s|=!!(s&4)+(s&1)*2; break;
    case 4: s|=s*2; break;
    case 5: s|=(s&1)*4+(s&4)/2; break;
    case 6: s|=(s&1)*4+!!(s&2); break;
    case 7: s&=5; break;
    case 8: s&=6; break;
    case 9: s&=3; break;
    }
  }
  return build_ans(s);
}

void test( char const * src, char const * expected )
{
  char const * actual = solve( src );
  bool okay = 0==strcmp( actual, expected );
  printf( "%s %s->%s ( e:%s )\n", ( okay ? "ok" : "**NG**" ), src, actual , expected );
  free( actual );
}

int main()
{
  /*0*/ test( "1728398", "bc" );    
  // 略
  /*36*/ test( "697535114542", "ac" );
  return 0;
}

いつも通り、テストデータの大半は省略。

状態は生死の二種類が3個なので、3bit で表現すれば良い。
生を 1 にしたので、「&=」で死をもたらし、「|=」が生きる可能性を増やしている。

solve の中がごちゃごちゃしているけど、コースを構成するブロックのごちゃごちゃ具合を表現しているので仕方ない。
データで持てればかっこいいけど、今回はコードで表現している。
念の為に書いておくと「!!」は、論理否定二回で、 0 以外を 1 にするという趣旨の計算を意味している。

全く同じ趣旨の計算を ruby で書いたものが以下。というか、先に ruby で書いていた。

def apply( s, c )
  case c
  when "0";    s
  when "1";    s | s[1] | s[2]*2
  when "2";    s | s[1]*4 | s[2]
  when "3";    s | s[0]*2 | s[2]
  when "4";    s | s[0]*2 | s[1]*4
  when "5";    s | s[0]*4 | s[2]*2
  when "6";    s | s[0]*4 | s[1]
  when "7";    s & 5
  when "8";    s & 6
  when "9";    s & 3
  end
end

def solve( src )
  r=src.chars.reverse.inject(7) do |s,c|
    apply( s, c )
  end
  %w( a b c ).each.with_index(0).map{ |c,ix|
    r[ix]==0 ? "" : c
  }.join.tap{ |x| return x.empty? ? "-" : x }
end

$stdout.sync=true

DATA.map do |line|
  num, src, expected = line.split(/\s+/)
  actual = solve( src )
  okay = actual==expected
  puts( "%s %2d %s->%s ( e:%s )" % [ ( okay ? "ok" : "**NG**" ), num, src, actual, expected ] )
  okay
end.all?.tap{|x| puts( x ? "everything is ok" : "something wrong" ) }

__END__
0 1728398 bc  
1 789 - 
2 274 ac  
3 185 abc 

36  697535114542  ac  

bit 演算すら、ruby の方が楽に書ける。