uehaj's blog

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

どう書く.org課題「化学反応式の完成」

どう書く.org課題「化学反応式の完成」をgroovyでそこはかとなく解いてみました。

Groovyには2つのリストを処理できるリスト処理(Haskellでいうzip関数みたいなもの)が無いことに気づいた。不便だ。実装がArrayListだとあまり効率よく処理できないとは思うが。
インデックス付きのcollectみたいなの(collectWithIndex?)があればせめて良いのだけど。

O = ["O"]
Mg = ["Mg"]
C = ["C"]
H = ["H"]
O2 = O*2
H2 = H*2
C2 = C*2
MgO = Mg + O
CO2 = C + O2
H2O = H2 + O

MAX=5

def expand(list, mult) {
  def result = []
  list.eachWithIndex { it, idx ->
    result += it * mult[idx]
  }
  return result.sort()
}

def printAnswer(list, mult) {
  list.eachWithIndex { it, idx ->
    print mult[idx]==1?"":mult[idx]
    print it.join().replaceAll(/(.)\1/, '$12')
    if (idx != list.size()-1) {
      print " + "
    }
  }
}

def resolv(pre, post) {
  preanswers = (([1..MAX]*pre.size()).combinations())
  postanswers = (([1..MAX]*post.size()).combinations())

  ([preanswers,postanswers].combinations()).grep {
    expand(pre, it[0]) == expand(post, it[1])
  }.each {
    printAnswer(pre, it[0])
    print " ==> "
    printAnswer(post, it[1])
    println();
  }

}

resolv([Mg, O2], [MgO])
// 以下が出力される
// 2Mg + O2 ==> 2MgO
// 4Mg + 2O2 ==> 4MgO

resolv([C2, H2, O2], [CO2, H2O])
// 以下が出力される
// C2 + 2H2 + 3O2 ==> 2CO2 + 2H2O
// 2C2 + 2H2 + 5O2 ==> 4CO2 + 2H2O
// C2 + 4H2 + 4O2 ==> 2CO2 + 4H2O