多元宇宙と交差の課題

Habréで「Haskellに影響を与えるオオカミ、ヤギ、キャベツを川を渡って輸送する」という記事を読んだことがあるので、マルチパラダイム設計を使用して交差問題のクラス全体のフレームワークを作成することにしました。ようやく時間を見つけることができ、ほぼ1年後、フレームワークの準備が整いました。これで、キャラクター、それらの相互作用、および目的の結果の説明がドメイン固有言語を介して設定されます。これにより、この種のパズルを段階的に解決することができます。以下は、DSL実装の段階的な内訳です​​。この記事は、Kotlin言語を勉強している人、または単にその使用例に興味がある人に適しています。簡潔にするために、一部の細かい詳細(インポートや出力など)は省略されています。





キャラクターは、継承のためのオープンクラスとして簡単に説明できます。





open class Person(private val name: String)
      
      



, :





typealias Place = Set<Person>
      
      



. , , :





abstract class QuantumBoat(val left: Place, val right: Place) {
  
  abstract fun invert(): List<QuantumBoat>
  
  fun where(condition: Place.() -> Boolean, select: QuantumBoat.() -> Boolean) =
    Multiverse(this, condition).search(selector)
}
      
      



where, N . (condition) , (selector) . , , , ​:)

, :





class LeftBoat(left: Place, right: Place) : QuantumBoat(left, right) {

  override fun invert() =
    left.map {
      RightBoat(left - it - Farmer, right + it + Farmer)
    } + RightBoat(left - Farmer, right + Farmer)
}
      
      



. . , , . . , Kotlin .





, , , , . , :





typealias History = LinkedList<QuantumBoat>
  
fun Sequence<History>.fork() = sequence {
  for (history in this@fork) {
    for (forked in history.last.invert()) {
      yield((history.clone() as History).apply {
        add(forked)
      })
    }
  }
}
      
      



( ) (). , yield.





( ):





/**
 *   
 * @param boat   
 * @param condition   
 */
class Multiverse(boat: QuantumBoat, val condition: Place.() -> Boolean) {

  /**
   *     
   */
  private var multiverse = sequenceOf(historyOf(boat))

  /**
   *     
   * @param selector     
   * @return     
   */
  tailrec fun search(selector: QuantumBoat.() -> Boolean): List<History> {
    multiverse = multiverse.fork().distinct().filter {
      it.last.left.condition()
        && it.last.right.condition()
    }
    val results =  multiverse.filter { it.last.selector() }.toList()
    return when {
      results.isNotEmpty() -> results
      else -> search(selector)
    }
  }
}
      
      



, kotlinc . : . ( ), . !





, DSL , :





object Wolf : Person

object Goat : Person

object Cabbage : Person

fun Place.isCompatible() =
  contains(Farmer) ||
    (!contains(Wolf) || !contains(Goat)) &&
    (!contains(Goat) || !contains(Cabbage))

fun main() {

  val property = setOf(Wolf, Goat, Cabbage)

  //    
  LeftBoat(property)
     //    
    .where(Place::isCompatible)
    //      ,
    //       
    { right.containsAll(property) } 
    //     
    .forEach(History::prettyPrint)
}
      
      



Habrは絵文字を消化しないため、これが起こったことです。スクリーンショットを挿入します。





良い一日とあなた自身のDSLを書くためのより多くの時間を持ってください:)





ソースコードはこちらです:demidko / river-crossing-puzzle

批評家や、より良い方法についての提案を歓迎します。








All Articles