Алгоритм Kotlin Cannibals и Missionaries - Как конвертировать в полный FP - PullRequest
0 голосов
/ 29 июня 2018

Любые предложения о том, как улучшить следующий код, чтобы сделать его более ориентированным на функциональное программирование. В частности, как удалить MutableList, который обозначает исторические состояния. Существует два класса данных: Bank, который представляет речной берег (количество миссионеров и количество каннибалов, находящихся в настоящее время в банке) и BankState, который представляет историческое состояние двух банков (исходный банк, целевой банк и boatAtSource - логическое значение, которое указывает находится ли лодка в данный момент в исходном или целевом банке). перегруженная функция оператора plus добавляет миссионеров и каннибалов на берег реки, а функция минус удаляет их с берега реки. Функция лодки - та, которая несет наибольший вес. Вы можете вызвать следующий алгоритм из 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)
                }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...