2017-11-30 2 views
2

Ich habe mehrere Methoden, die ein Wort fälschen, und ich muss sie zufällig aufrufen, bis man erreicht, um einen "menschlichen Fehler" zu schaffen.Rufen Sie eine zufällige Methode, nicht zweimal

Ich möchte eine zufällige Methode aufrufen, dann ein anderes, bis es in Ordnung ist, aber zweimal nie gleich.
Wenn ich sie in ein Array (oder eine Liste) setze, schreibe ich jedes Mal, wenn ich eine Methode ausprobiere, ein Array um, das ist eine hässliche Rechenkomplexität und ich möchte "Scala Style" -Code schreiben, mit möglichst wenig Var und Mutability.

EDIT:

Die Oleg Pyzhcov solution funktioniert gut, aber jetzt habe ich einige Funktionen mit String params und andere ohne. Wie können Funktionen und ihre Aufrufparameter in einer Sammlung gespeichert werden?

val rand: Random = new Random() 

def m1(a: String): Boolean = rand.nextBoolean() 
def m2(): Boolean = rand.nextBoolean() 
def m3(a: String, b: String): Boolean = rand.nextBoolean() 
def m4(): Boolean = rand.nextBoolean() 

def tryUntilOk(): Unit = { 
    def out = rand.shuffle(Stream(m1 _, m2 _, m3 _, m4 _)) 
    .map(method => method()) // calling without params so error 
    .find(result => result) // stop when a method return true 
} 

EDIT 2:
DETAILS

ich mehrere Methoden, die ein Wort zu fälschen versucht, ohne Garantie, dass sie es erreichen. Einige Methoden nehmen die Stimmung und Zeit eines Verbs, um die Zeit oder die Stimmung zu ändern, andere nehmen nur das Wort richtig, um einige Buchstaben zu entfernen, andere nehmen das Geschlecht und die Nummer eines Nomens, um das Geschlecht zu ändern.

Ich möchte eine zufällige Methode unter allen möglichen nennen, und wenn es das Wort nicht fälschen kann (zum Beispiel das gegebene Substantiv nur in der weiblichen Form existiert), dann rufe einen anderen zufällig an. Wiederholen Sie diese Operation, bis keine weiteren Methoden verfügbar sind, also geben wir auf. Die Lösung von Oleg ist nett für den zufälligen Teil, aber ich kann nicht finden, wie Methoden Parameter Aufruf geben.

Beton exemple:

package Counterfeiters 

import Words.Noun 

object Noun extends Counterfeiter[Noun] { 
    override def counterfeit(word: Noun): Unit = { 
    // For now I call methods without random order 

    // This one take only one String param 
    // And split letters that are duplicated like boot -> bot 
    word.currentWriting = splitDoubleLetters(word.correctWriting) 

    // Then we compare word.currentWriting and word.correctWriting 
    // If the word wasn't containing double letters, it isn't counterfeited 
    if (!word.isCounterfeited) 
     // This one take 5 String params 
     // And counterfeit the gender or the number of the word, randomly 
     word.currentWriting = counterfeitGenderNumberWord("N", word.correctWriting, word.lemma, word.gender, word.number) 
    } 
} 

die Lösung von Oleg anwenden zu können, muß ich nur finden, wie Methoden zur Speicherung in einer Sammlung, mit entsprechendem params. In diesem Fall (splitDoubleLetters, (word.correctWriting)) und (counterfeitGenderNumberWord, ("N", word.correctWriting, word.lemma, word.gender, word.number)).

SOLUTION

Ich tat, was Oleg in einem Kommentar geraten:

object Noun extends Counterfeiter[Words.Noun] { 
    override def counterfeit(word: Words.Noun): Unit = { 
    if (word.isCounterfeited) return 

    def split:() => String =() => splitDoubleLetter(word.correctWriting) 

    def ctftGenderNumber:() => String =() => counterfeitGenderNumberWord("N", word.correctWriting, word.lemma, word.gender, word.number) 

    val methods: immutable.Seq[() => String] = Stream(split, ctftGenderNumber) 

    val res: Option[String] = randomizer.shuffle(methods) // Shuffle methods 
     .map(method => method()) // Call them one by one 
     .find(result => result != word.correctWriting) // Until one counterfeit the word 

    word.currentWriting = res match { 
     case None => word.correctWriting // If every methods failed 
     case _ => res.get 
    } 
    } 
} 

SergGr explained auch eine mögliche Architektur, ich dazu passen würde, wie es klar ist.
Sie können meinen vollständigen Projektcode auf GitHub finden, wenn Sie besser verstehen wollen, was ich tue.

+0

VNourdin, ist es nicht klar, was Sie erreichen wollen . Sie sollten uns Ihren "hässlichen" Code mitteilen, damit wir ihn verbessern und die Logik bewahren können. Insbesondere, wo Funktionsaufrufargumente in diesem Code herkommen? Müssen Sie nur Ihre Methoden in teilweise angewandte Funktionen umwandeln? Ist es etwas anderes? – SergGr

+0

Ok ich versuche ein bisschen zu verdeutlichen und konkretes Beispiel zu geben. – VNourdin

Antwort

2

Mit Stream für Faulheit und Methode können Sie erhalten:

import scala.util.Random 

def m1(): Boolean = Random.nextBoolean() 
def m2(): Boolean = Random.nextBoolean() 
def m3(): Boolean = Random.nextBoolean() 
def m4(): Boolean = Random.nextBoolean() 

def out = Random.shuffle(Stream(m1 _, m2 _, m3 _, m4 _)) 
    .map(method => method()) // pass in any necessary params 
    .find(result => !result) // do your check 

Hier hat outOption[Boolean] seit Methoden m1-m4 geben alle Boolean zurückkehren

+0

Ich habe Methoden mit verschiedenen Parametern und Zahlen, wie kann ich sie schön weitergeben? – VNourdin

+0

Was ist der Sinn der vier identischen Methoden? –

+0

Es ist nur zu vereinfachen, ist uns egal, was wirklich in meinen Methoden ist. Der Punkt ist, ich habe mehrere Methoden, versuche eine Aktion zu machen (in diesem Fall true) und sie haben unterschiedliche Parameter. Ich möchte einen von ihnen zufällig anrufen, dann einen anderen, während die Aktion fehlgeschlagen ist. – VNourdin

1

ich mit Oleg darüber einig, dass, was Sie brauchen, ist zu Konvertiere alle deine Methoden in eine Sammlung derselben Form.Ich nehme an, dass in word Paket Sie Basisklasse Word mit Unterklassen für verschiedene Teile der Sprache mit unterschiedlichen Eigenschaften haben. Etwas wie folgt aus:

abstract class Word(val correctWriting: String, var currentWriting: String, val lemma: String) { 

    def isCounterfeited: Boolean = !correctWriting.equals(currentWriting) 

} 

sealed trait Gender 
case object Masculine extends Gender 
case object Feminine extends Gender 
case object Neutral extends Gender 

sealed trait Number 
case object Singular extends Number 
case object Plural extends Number 

class Noun(correctWriting: String, currentWriting: String, lemma: String, val gender: Gender, val number: Number) extends Word(correctWriting, currentWriting, lemma) { 

} 

und Sie haben Merkmal Counterfeiter definiert als

trait Counterfeiter[-W <: Word] { 
    def counterfeit(word: W): Unit 
} 

Dann können Sie Hilfsklasse RandomCompoundCounterfeiter

type SimpleCounterfeiter[W <: Word] = (String, W) => String 

class RandomCompoundCounterfeiter[W <: Word](val children: Seq[SimpleCounterfeiter[W]]) extends Counterfeiter[W] { 
    override def counterfeit(word: W): Unit = { 
    Random.shuffle(children).takeWhile(c => { 
     word.currentWriting = c(word.correctWriting, word) 
     !word.isCounterfeited 
    }) 
    } 
} 

RandomCompoundCounterfeiter ist die Klasse definieren ist die die Hauptaufgabe Sie waren fragen nach: es gilt andere SimpleCounterfeiter in zufälliger Reihenfolge. Dies geschieht, indem zuerst die Liste children (d. H. Echte Fälscher) gemischt und angewendet wird, bis schließlich word.isCounterfeitedtrue ist oder die Liste erschöpft ist.

Beachten Sie, dass RandomCompoundCounterfeiter Fälscher bei jedem Anruf neu gemischt werden. Wenn Sie möchten, dass Ihre Reihenfolge zwischen verschiedenen Läufen der Anwendung unterschiedlich ist, aber für verschiedene Wörter innerhalb eines einzelnen Laufs gleich ist, verschieben Sie einfach das Mischen in den Konstruktor.

definieren Nun Liste der grundlegenden SimpleCounterfeiter s Funktionen wie

object Noun { 

    val singularCounterfeiter = (correctWriting: String, word: Noun) => { 
    if (word.number == Singular) 
     correctWriting 
    else 
     ??? 
    } 

    val pluralCounterfeiter = (correctWriting: String, word: Noun) => { 
    if (word.number == Plural) 
     correctWriting 
    else 
     ??? 
    } 


    def genderCounterfeiter(newGender: Gender): SimpleCounterfeiter[Noun] = (correctWriting: String, word: Noun) => { 
    if (word.gender == newGender) 
     correctWriting 
    else 
     ??? 
    } 


    val all = List(
    GenericCounterfeiters.splitDoubleLetters, 
    singularCounterfeiter, 
    pluralCounterfeiter, 
    genderCounterfeiter(Neutral), 
    genderCounterfeiter(Masculine), 
    genderCounterfeiter(Feminine)) 

    val nounCounterfeiter = new RandomCompoundCounterfeiter[Noun](all) 
} 

Jetzt können Sie Noun.nounCounterfeiter als zufällige Counterfeiter[Noun] verwenden. Die Grundidee ist hier, für jeden atomaren Fälscher die gleiche Form zu haben, und dies wird erreicht, indem immer die gesamte Word (oder ihre Unterklasse) an die Methode übergeben wird. So hat nun jede Methode Zugriff auf alle relevanten Informationen, wenn sie benötigt wird.

Wenn Sie es vorziehen, den typischen if Zustand in Fälscher zu einem einzigen Ort zu bewegen, können Sie Ihren Code ein bisschen mehr OOP-Wege-Refactoring:

class RandomCompoundCounterfeiter[W <: Word](val children: Seq[Counterfeiter[W]]) extends Counterfeiter[W] { 
    override def counterfeit(word: W): Unit = { 
    Random.shuffle(children).takeWhile(c => { 
     c.counterfeit(word) 
     !word.isCounterfeited 
    }) 
    } 
} 

trait SimpleCounterfeiter[-W <: Word] extends Counterfeiter[W] { 
    override def counterfeit(word: W): Unit = { 
    if (isApplicable(word)) 
     word.currentWriting = counterfeitImpl(word.correctWriting, word) 
    } 

    def isApplicable(word: W): Boolean 

    def counterfeitImpl(correctWriting: String, word: W): String 
} 

object GenericCounterfeiters { 
    val splitDoubleLetters = new SimpleCounterfeiter[Word] { 
    override def isApplicable(word: Word) = true 

    override def counterfeitImpl(correctWriting: String, word: Word) = ??? 
    } 
} 

object Noun { 

    val singularCounterfeiter = new SimpleCounterfeiter[Noun] { 
    override def isApplicable(word: Noun) = word.number != Singular 

    override def counterfeitImpl(correctWriting: String, word: Noun) = ??? 
    } 

    val pluralCounterfeiter = new SimpleCounterfeiter[Noun] { 
    override def isApplicable(word: Noun) = word.number != Plural 

    override def counterfeitImpl(correctWriting: String, word: Noun) = ??? 
    } 


    def genderCounterfeiter(newGender: Gender) = new SimpleCounterfeiter[Noun] { 
    override def isApplicable(word: Noun) = word.gender != newGender 

    override def counterfeitImpl(correctWriting: String, word: Noun) = ??? 
    } 

    val all = List(
    GenericCounterfeiters.splitDoubleLetters, 
    singularCounterfeiter, 
    pluralCounterfeiter, 
    genderCounterfeiter(Neutral), 
    genderCounterfeiter(Masculine), 
    genderCounterfeiter(Feminine)) 

    val nounCounterfeiter = new RandomCompoundCounterfeiter[Noun](all) 
} 
+0

übergeben Ich stimme auch mit Oleg und tat es. Ich bin ein Anfänger in Scala, ich habe es nicht so gut gemacht wie du rätst. Ich werde wahrscheinlich meine Vorstellung ändern, es ist schöner, was ich bisher getan habe. Sie können auf meinem GitHub sehen, wenn Sie interessiert sind. Danke für diese gut erklärte Hilfe. – VNourdin

Verwandte Themen