Kotlin食人族和传教士算法-如何转换为完整FP

时间:2018-06-29 14:03:11

标签: algorithm functional-programming kotlin

关于如何改进以下代码以使其更面向功能编程的任何建议。具体来说,如何删除表示历史状态的MutableList。有两个数据类:银行,代表河岸(传教士人数和目前在银行的食人族人数),以及银行状态,代表两个银行的历史状态(源银行,目标银行和boatAtSource-一个布尔值,指示船只当前位于来源银行还是目标银行)。重载的运算符功能加上将传教士和食人者添加到河岸,功能减负将其从河岸删除。船功能是最重的功能。您可以这样从fun main(app.kt)中调用以下算法:

app.kt

fun main(args:Array<String>) {
    val source:Bank = Bank(3,3)
    val target:Bank = Bank()
    source boat target
}

Bank.kt

data class Bank(val missionaries:Int=0,val cannibals:Int=0)
data class BankState(val sourceTarget:Pair<Bank,Bank>,val boatAtSource:Boolean)

operator fun Bank.plus(b:Pair<Int,Int>):Bank = Bank(this.missionaries+b.first,this.cannibals+b.second)
operator fun Bank.minus(b:Pair<Int,Int>):Bank = Bank(this.missionaries-b.first,this.cannibals-b.second)
infix fun Bank.boat(target:Bank):List<BankState> {
    val begin = Pair(this,target)
    val history = mutableListOf<BankState>(BankState(begin,true))
    boat(begin,true,this.missionaries,this.cannibals,history)   
    return history
}

fun boat(sourceTarget:Pair<Bank,Bank>,
         boatAtSource:Boolean,
         totalMissionaries:Int,
         totalCannibals:Int,
         history:MutableList<BankState>):Boolean {

    if(sourceTarget.first.cannibals+sourceTarget.second.cannibals==totalCannibals &&
            sourceTarget.first.missionaries + sourceTarget.second.missionaries==totalMissionaries &&
            sourceTarget.first.cannibals>=0 &&
            sourceTarget.first.missionaries>=0 &&
            sourceTarget.second.cannibals>=0 &&
            sourceTarget.second.missionaries>=0 &&
            (sourceTarget.first.missionaries==0 || sourceTarget.first.missionaries>=sourceTarget.first.cannibals) &&
            (sourceTarget.second.missionaries==0 || sourceTarget.second.missionaries >= sourceTarget.second.cannibals)) {


            if(sourceTarget.second.missionaries==totalMissionaries &&
                    sourceTarget.second.cannibals==totalCannibals) {
                history.forEach(::println)              
                return true
            } else {


                val deltas = listOf(Pair(0,1),Pair(1,1),Pair(1,0),Pair(2,0),Pair(0,2))

                val comparator = object : Comparator<Pair<Pair<Boolean,Int>,Pair<Bank,Bank>>> {
                    override fun compare(arg1:Pair<Pair<Boolean,Int>,Pair<Bank,Bank>>,arg2:Pair<Pair<Boolean,Int>,Pair<Bank,Bank>>):Int {
                        if(arg1.first.first && arg2.first.first) {
                            return if(arg1.first.second<arg2.first.second) -1 else if(arg1.first.second>arg2.first.second) 1 else 0
                        } else if(arg1.first.first){
                            return 1
                        } else if(arg2.first.first) {
                            return -1
                        }
                        return 0
                    }
                }

                val result = deltas.map{
                    checkNext(it.first,it.second,totalMissionaries,totalCannibals,history,sourceTarget,boatAtSource)
                }.maxWith(comparator)


                if(result?.first?.first!=null && result.first.first) {
                    history.add(BankState(result.second,!boatAtSource))
                    return true;
                }       

            }
    }

    return false
}

fun checkNext(missionariesDelta:Int,
              cannibalsDelta:Int,
              totalMissionaries:Int,
              totalCannibals:Int,
              history:MutableList<BankState>,
              sourceTarget:Pair<Bank,Bank>,
              boatAtSource:Boolean):Pair<Pair<Boolean,Int>,Pair<Bank,Bank>> {
                val nextSrcTgt = if(boatAtSource) Pair(sourceTarget.first-Pair(missionariesDelta,cannibalsDelta),sourceTarget.second+Pair(missionariesDelta,cannibalsDelta))
                                    else Pair(sourceTarget.first+Pair(missionariesDelta,cannibalsDelta),sourceTarget.second-Pair(missionariesDelta,cannibalsDelta))
                val bankState:BankState = BankState(nextSrcTgt,!boatAtSource)
                if(!history.contains(bankState)) {
                    history.add(bankState)
                    val combo2:Boolean = boat(nextSrcTgt,!boatAtSource,totalMissionaries,totalCannibals,history)
                    val combo2Depth = history.size
                    history.remove(bankState)
                    return Pair(Pair(combo2,combo2Depth),nextSrcTgt)
                } else {
                    return Pair(Pair(false,0),nextSrcTgt)
                }
}

0 个答案:

没有答案