uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

オフラインどう書く第九回の問題をCompileStatic指定してやってみた。

オフラインどう書く第九回の問題をやってみたという記事を書きましたが、今回はCompileStaticアノテーションを使って書きなおしてみました。

import groovy.transform.*

@CompileStatic
int ceil10(int n) { (Math.ceil(n/10) * 10) as Integer }

@CompileStatic
int half(int n) { ceil10(n/2) }

@CompileStatic
List parse(String input) {
  String[] tmp = input.split(':')
  String p = tmp[0]
  String list = tmp[1]
  return [Integer.parseInt(p), list.split(",") as List]
}

@CompileStatic
int calc(int basePrice, List<String> passengers) {
  Map<String,Closure> map
  map = [An:{int it->it},
         Ap:{int it->0},
         Aw:{int it->half((int)map.get('An')(it))},
         Cn:{int it->half((int)map.get('An')(it))},
         Cp:{int it->0},
         Cw:{int it->half((int)map.get('Cn')(it))},
         In:{int it->half((int)map.get('An')(it))},
         Ip:{int it->0},
         Iw:{int it->half((int)map.get('In')(it))},
        ]
  Map<String,List> groups = passengers.collect{String it -> [it, map.get(it)(basePrice)]}.groupBy{List<String> it -> it[0][0]}.withDefault{[]}
  return ((groups.get('A')+groups.get('C')+groups.get('I').sort{
            List<Integer> it -> it[1]
           }.take(groups.get('I').size()-(groups.get('A').size()*2))).sum{List<Integer> it -> it[1]}) as Integer
}

@CompileStatic
void test(String input, String expected) {
  List tmp = parse(input)
  int basePrice = (int)tmp[0]
  List<String> passengers = (List<String>)tmp[1]
  assert Integer.parseInt(expected)==calc(basePrice, passengers)
}

test( "1480:In,An,In,In,In,Iw,Cp,Cw,In,Aw,In,In,Iw,Cn,Aw,Iw", "5920" );

マップの要素指定がプロパティ形式でアクセスできなくなったり、クロージャの暗黙引数が省略できないケース(型推論できない場合)があったり、結構冗長になっていることがわかります。ちなみに上記の書き直しのために、staticalizerは役立ちます。

あと正しいTupleが欲しい。

本記事は、JJUG CCC 2013 Springのステマです。