মাস্টারমাইন্ড ঘোড়ার ব্যাটারি স্ট্যাপল


48

উদ্দেশ্য

তিন-শব্দের পাসফ্রেজের একটি তালিকা দেওয়া হয়েছে, সেগুলি ক্র্যাক করুন। প্রতিবার অনুমান করার পরে, আপনাকে মাস্টারমাইন্ডের স্টাইলে একটি ক্লু দেওয়া হবে , এতে বর্ণিত হয় যে পাসওয়ার্ডটির সাথে কতগুলি অক্ষর মেলে এবং কতগুলি তাদের সঠিক অবস্থানে রয়েছে। উদ্দেশ্য সমস্ত পরীক্ষার ক্ষেত্রে অনুমানের মোট সংখ্যা হ্রাস করা।

পরিচয়-পংক্তি

আমার সিস্টেমের ডিফল্ট শব্দের তালিকা থেকে, আমি এলোমেলোভাবে এই চ্যালেঞ্জটির জন্য অভিধান তৈরি করতে 10,000 টি পৃথক শব্দ বেছে নিয়েছি। সমস্ত শব্দ a-zশুধুমাত্র গঠিত । এই অভিধানটি এখানে পাওয়া যাবে ( কাঁচা )।

এই অভিধান থেকে, আমি প্রতিটিতে তিনটি এলোমেলো স্পেস-বিভাজিত শব্দের সমন্বয়ে 1000 পাসফ্রেজ তৈরি করেছি ( apple jacks feverউদাহরণস্বরূপ)। পৃথক শব্দ প্রতিটি পাসফ্রেজের মধ্যে পুনরায় ব্যবহার করা যেতে পারে ( hungry hungry hippos)। আপনি এখানে পাসফ্রেজের তালিকা পেতে পারেন ( কাঁচা) প্রতি লাইনে একটি সঙ্গে,)।

আপনার প্রোগ্রামটি আপনি চাইলেও অভিধান ফাইলটি ব্যবহার / বিশ্লেষণ করতে পারেন। আপনি এই নির্দিষ্ট তালিকার জন্য অনুকূলিতকরণের জন্য পাসফ্রেজগুলি বিশ্লেষণ করতে পারবেন না । আপনার অ্যালগরিদম এখনও বাক্যাংশের একটি পৃথক তালিকা দেওয়া কাজ করা উচিত

মনন

অনুমান করার জন্য, আপনি একটি পরীক্ষকের কাছে একটি স্ট্রিং জমা দিন। এটি কেবল ফিরে আসতে হবে :

  • পাসফ্রেজে আপনার স্ট্রিংয়ের অক্ষরের সংখ্যা ( নেই) সঠিক অবস্থান মধ্যে)
  • সঠিক অবস্থানে অক্ষরের সংখ্যা

যদি আপনার স্ট্রিংটি একটি নিখুঁত ম্যাচ হয় তবে এটি (খনি ব্যবহার করে) এমন কোনও কিছু আউটপুট করতে পারে -1 প্রথম মানের জন্য ব্যবহার করে)।

উদাহরণস্বরূপ, যদি পাসফ্রেজ হয় the big catএবং আপনি অনুমান করেন tiger baby mauling, চেকারের ফিরে আসা উচিত 7,1। Characters টি অক্ষর ( ige<space>ba<space>) উভয় স্ট্রিতে রয়েছে তবে ভিন্ন অবস্থানে রয়েছে এবং উভয়টিতে 1 ( t) একই অবস্থানে রয়েছে। স্পেস গণনা লক্ষ্য করুন।

আমি জাভাতে একটি উদাহরণ (পড়ুন: অনুকূলিত নয়) ফাংশন লিখেছি, তবে যতক্ষণ না এটি কেবল প্রয়োজনীয় তথ্য দেয় ততক্ষণ নিজের লিখতে নির্দ্বিধায়।

int[] guess(String in){
    int chars=0, positions=0;
    String pw = currentPassword; // set elsewhere, contains current pass
    for(int i=0;i<in.length()&&i<pw.length();i++){
        if(in.charAt(i)==pw.charAt(i))
            positions++;
    }
    if(positions == pw.length() && pw.length()==in.length())
        return new int[]{-1,positions};
    for(int i=0;i<in.length();i++){
        String c = String.valueOf(in.charAt(i));
        if(pw.contains(c)){
            pw = pw.replaceFirst(c, "");
            chars++;
        }
    }
    chars -= positions;
    return new int[]{chars,positions};
}

স্কোরিং

আপনার স্কোরটি কেবল পরীক্ষার সমস্ত বাক্যাংশের জন্য আপনি চেকারের কাছে জমা দেওয়া অনুমানের সংখ্যা (চূড়ান্ত গণনা, একটি সঠিক) correct সর্বনিম্ন স্কোর জয়।

আপনাকে অবশ্যই তালিকার সমস্ত বাক্যাংশ ক্র্যাক করতে হবে । আপনার প্রোগ্রাম যদি সেগুলির কোনওটিতে ব্যর্থ হয় তবে তা অবৈধ।

আপনার প্রোগ্রাম অবশ্যই নির্দোষ হতে হবে। যদি পাসফ্রেজগুলির একই সেটটিতে দু'বার চালানো হয় তবে এটি একই ফলাফলটি ফিরে আসবে should

প্রথমবারের মতো টাই করার ক্ষেত্রে, আমি আমার কম্পিউটারে প্রতিটি বারে চারবার আবদ্ধ এন্ট্রিগুলি চালাব এবং সমস্ত 1000 কেস জয় করার জন্য সর্বনিম্ন গড় সময়টি জিতবে। আপনার কম্পিউটারে কোনও পার্থক্য তৈরি হয় সেই ক্ষেত্রে, আমার কম্পিউটার একটি আই 7-3770 কে এবং 16 গিগাবাইট র‌্যামের সাথে উবুন্টু 14.04 চলছে । সেই কারণে এবং পরীক্ষার সুবিধার্থে আপনার উত্তরটি এমন একটি ভাষায় হওয়া উচিত যার একটি সংকলক / দোভাষী রয়েছে যা ওয়েব থেকে বিনামূল্যে ডাউনলোড করা যায় (নিখরচায় ট্রায়াল সহ নয়) এবং সাইন আপ / নিবন্ধকরণের প্রয়োজন হয় না।

XKCD থেকে শিরোনাম রূপান্তরিত


1
TITLE থেকে xkcd.com/936
NinjaBearMonkey

আমি স্ট্রিংতে জমা করার জন্য এ..জেড এবং স্পেস ব্যতীত অন্য কোনও অক্ষর রাখতে পারি?
রায়

@ রে আমি এই মুহুর্তে না হওয়ার কারণটি ভাবতে পারি না তবে এটি আপনাকে কী লাভ করবে তা আমি নিশ্চিত নই। এর জন্য যান, আমি কৌতূহলী।
Geobits

3
মানুষ কি নিজেকে জমা দিতে পারে? আমি শুরু করব: "শট করার জন্য মূল্যবান"
AndoDaan

2
@ এন্ডোডান প্রথম বাক্যাংশের জন্য? 9 0। এটি কিছুক্ষণ সময় নিতে পারে: পি
জিওবিটস

উত্তর:


13

স্কালা 9146 (মিনিট 7, সর্বোচ্চ 15, গড় 9.15) সময়: 2000 সেকেন্ড

অনেক এন্ট্রিগুলির মতো আমি মোট দৈর্ঘ্য পেয়ে শুরু করি, তারপরে স্পেসগুলি সন্ধান করে, আরও কিছু তথ্য পেয়েছি, বাকী প্রার্থীদের হ্রাস করে এবং তারপর বাক্যাংশ অনুমান করে।

মূল xkcd কমিক দ্বারা অনুপ্রাণিত হয়ে আমি তথ্য তত্ত্ব সম্পর্কে আমার প্রাথমিক বোঝার প্রয়োগ করার চেষ্টা করেছি। একটি ট্রিলিয়ন সম্ভাব্য বাক্যাংশ রয়েছে বা এন্টারপপির মাত্র 40 বিটের নিচে। আমি পরীক্ষার বাক্যাংশে 10 টি অনুমানের নীচে একটি লক্ষ্য রেখেছি, যার অর্থ আমাদের ক্যোয়ারিতে গড়ে প্রায় 5 বিট শিখতে হবে (যেহেতু শেষটি অকেজো)। প্রতিটি অনুমানের সাথে আমরা দুটি সংখ্যা ফিরে পাই এবং মোটামুটিভাবে এই সংখ্যার বৃহত সম্ভাব্য পরিসরটি বলি, আমরা তত বেশি শিখতে আশা করি।

যুক্তিটি সহজ করার জন্য, আমি প্রতিটি ক্যোয়ারিকে কার্যকরভাবে দুটি পৃথক প্রশ্ন হিসাবে ব্যবহার করি যাতে প্রতিটি অনুমানের স্ট্রিং দুটি অংশ হয়, সঠিক অবস্থানের সংখ্যায় আগ্রহী একটি বাম দিক (মাস্টারমাইন্ডের কালো পেগ) এবং সঠিক অক্ষরের সংখ্যাতে আগ্রহী একটি ডান দিক ( মোট পেগ)। এখানে একটি সাধারণ খেলা:

Phrase:        chasteness legume such
 1: p0 ( 1/21) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -aaaaaaaaaaaabbbbbbbbbcccccccccdddddddddeeeeeeeeeeeeeeefffffffffgggggggggggghhhhhhhhhiiiiiiiiiiiiiiiiiijjjjjjkkkkkkkkkllllllllllllmmmmmmmmmnnnnnnnnnnnnoooooooooooopppppppppqqqrrrrrrrrrrrrssssssssssssssstttttttttuuuuuuuuuuuuvvvvvvwwwwwwxxxyyyyyyyyyzzzzzz
 2: p1 ( 0/ 8)   -  - -  ---    - ---aaaaaaaaaaaadddddddddeeeeeeeeeeeeeeefffffffffjjjjjjkkkkkkkkkllllllllllllooooooooooooqqqwwwwwwxxxyyyyyyyyyzzzzzz
 3: p1 ( 0/11) ----- ------ ---------bbbbbbbbbdddddddddeeeeeeeeeeeeeeefffffffffgggggggggggghhhhhhhhhiiiiiiiiiiiiiiiiiikkkkkkkkkllllllllllllppppppppptttttttttvvvvvv
 4: p1 ( 2/14) ---------- ------ ----ccccccccceeeeeeeeeeeeeeehhhhhhhhhkkkkkkkkkllllllllllllmmmmmmmmmooooooooooooqqqrrrrrrrrrrrrsssssssssssssssvvvvvvwwwwwwzzzzzz
 5: p3 ( 3/ 3) iaaiiaaiai iaaiia iaaiaaaaaaaaaaaabbbbbbbbbdddddddddiiiiiiiiiiiiiiiiiikkkkkkkkkllllllllllllqqquuuuuuuuuuuuvvvvvvyyyyyyyyy
 6: p3 ( 3/11) aaaasassaa aaaasa aaaaaaaaaaaaaaaabbbbbbbbbcccccccccdddddddddfffffffffhhhhhhhhhppppppppprrrrrrrrrrrrssssssssssssssstttttttttuuuuuuuuuuuuwwwwwwxxxyyyyyyyyy
 7: p4 ( 4/10) accretions shrive pews
 8: p4 ( 4/ 6) barometric terror heir
 9: p4 SUCCESS chasteness legume such

জায়গাগুলি অনুমান করা

প্রতিটি স্পেস অনুমান সর্বাধিক 2 টি কালো খোঁচায় ফিরে আসতে পারে; আমি যথাক্রমে 1 / 4,1 / 2, এবং 1/4 সম্ভাব্যতা সহ 0,1, এবং 2 পেগ ফেরত অনুমানগুলি তৈরি করার চেষ্টা করেছি। আমি বিশ্বাস করি তথ্যের প্রত্যাশিত 1.5 বাইটের জন্য আপনি সবচেয়ে ভাল এটি করতে পারেন। আমি এলোমেলোভাবে উত্পন্ন উত্পন্ন প্রথম অনুমানের জন্য একটি বিকল্প স্ট্রিংয়ে স্থির হয়েছি, যদিও এটি সক্রিয় হয় যে সাধারণত দ্বিতীয় বা তৃতীয় চেষ্টা সম্পর্কে অনুমান করা শুরু করা সার্থক কারণ আমরা শব্দ দৈর্ঘ্যের ফ্রিকোয়েন্সি জানি।

চরিত্র সেট গণনা শেখা

ডান পাশের অনুমানগুলির জন্য আমি এলোমেলো (সর্বদা ই / i / a / s এর 2) টি অক্ষর বাছাই করি যাতে প্রত্যাশিত সংখ্যাটি বাক্য দৈর্ঘ্যের অর্ধেক হয়। উচ্চতর পরিবর্তনের অর্থ আরও তথ্য এবং দ্বিপদী বিতরণে উইকিপিডিয়া পৃষ্ঠা থেকে আমি প্রতি ক্যোয়ারী সম্পর্কে প্রায় 3.5 বিট অনুমান করছি (তথ্য অপ্রয়োজনীয় হওয়ার আগে কমপক্ষে প্রথম কয়েকের জন্য)। একবার স্পেসিংয়ের কথা জানা গেলে, আমি বাম দিকের সর্বাধিক সাধারণ অক্ষরের এলোমেলো স্ট্রিং ব্যবহার করি, যাতে ডান পাশের সাথে দ্বন্দ্ব না হওয়ার জন্য বেছে নেওয়া হয়।

বাকি প্রার্থীদের কোলেসিং করা হচ্ছে

এই গেমটি একটি গণনা গতি / ক্যোয়ারি দক্ষতা ট্রেড অফ এবং বাকী প্রার্থীদের সংখ্যা নির্দিষ্ট অক্ষরের মতো কাঠামোগত তথ্য ব্যতীত সত্যই দীর্ঘ সময় নিতে পারে। আমি মূলত শব্দের ক্রমের সাথে অদ্বিতীয় তথ্য সংগ্রহ করে এই অংশটিটি অনুকূলিত করেছি, যা আমাকে প্রতিটি স্বতন্ত্র শব্দের জন্য চরিত্র-সেট গণনাগুলি পূর্ববর্তী করতে এবং কোয়েরি থেকে শিখতে থাকা সংখ্যার সাথে তুলনা করে। আমি এই গণনাগুলিকে লম্বা পূর্ণসংখ্যায় প্যাক করি, আমার সমস্ত চরিত্রের গুণকে পেরেলেলের সাথে পরীক্ষার জন্য মেশিনের সমতা তুলনাকারী এবং সংযোজক ব্যবহার করে। এটি ছিল বিশাল জয়। আমি লম্বায় 9 টি গণনা প্যাক করতে পারি তবে আমি দেখতে পেলাম অতিরিক্ত তথ্য সংগ্রহ করা এটির পক্ষে উপযুক্ত নয় এবং 6 থেকে 7 এ স্থির হয়েছিল।

বাকি প্রার্থীরা পরিচিত হওয়ার পরে, সেটটি যদি যুক্তিযুক্তভাবে ছোট হয় তবে আমি অবশিষ্ট প্রার্থীদের সবচেয়ে কম প্রত্যাশিত লগ সহ একটি বেছে নিই pick এই সময়টি গ্রাস করার জন্য যদি সেটটি যথেষ্ট বড় হয় তবে আমি একটি ছোট নমুনা সেট থেকে বেছে নিই।

ধন্যবাদ সবাইকে. এটি একটি মজাদার খেলা ছিল এবং আমাকে সাইটে সাইন আপ করার জন্য প্ররোচিত করেছিল।

আপডেট: অ্যালগরিদমে সামান্য টুইট সহ সরলতা এবং পঠনযোগ্যতার জন্য কোড সাফ করে, ফলে উন্নত স্কোর হয়।
আসল স্কোর: 9447 (মিনিট 7, সর্বোচ্চ 13, গড় 9.45) সময়: 1876 সেকেন্ড

নতুন কোডটি নীচে স্কেলার 278 টি লাইন

object HorseBatteryStapleMastermind {
  def main(args: Array[String]): Unit = run() print ()

  val n = 1000       // # phrases to run
  val verbose = true // whether to print each game

  //tweakable parameters
  val prob = 0.132   // probability threshold to guess spacing 
  val rngSeed = 11   // seed for random number generator
  val minCounts = 6  // minimum char-set counts before guessing

  val startTime = System.currentTimeMillis()
  def time = System.currentTimeMillis() - startTime

  val phraseList = io.Source.fromFile("pass.txt").getLines.toArray
  val wordList = io.Source.fromFile("words.txt").getLines.toArray

  case class Result(num: Int = 0, total: Int = 0, min: Int = Int.MaxValue, max: Int = 0) {
    def update(count: Int) = Result(num + 1, total + count, Math.min(count, min), Math.max(count, max))

    def resultString = f"#$num%4d  Total: $total%5d  Avg: ${total * 1.0 / num}%2.2f  Range: ($min%2d-$max%2d)"
    def timingString = f"Time:  Total: ${time / 1000}%5ds Avg: ${time / (1000.0 * num)}%2.2fs"
    def print() = println(s"$resultString\n$timingString")
  }

  def run(indices: Set[Int] = (0 until n).to[Set], prev: Result = Result()): Result = {
    if (verbose && indices.size < n) prev.print()

    val result = prev.update(Querent play Oracle(indices.head, phraseList(indices.head)))

    if (indices.size == 1) result else run(indices.tail, result)
  }

  case class Oracle(idx: Int, phrase: String) {
    def query(guess: String) = Grade.compute(guess, phrase)
  }

  object Querent {

    def play(oracle: Oracle, n: Int = 0, notes: Notes = Notes0): Int = {
      if (verbose && n == 0) println("=" * 100 + f"\nPhrase ${oracle.idx}%3d:    ${oracle.phrase}")

      val guess = notes.bestGuess
      val grade = oracle.query(guess)

      if (verbose) println(f"${n + 1}%2d: p${notes.phase} $grade $guess")

      if (grade.success) n + 1 else play(oracle, n + 1, notes.update(guess, grade))
    }

    abstract class Notes(val phase: Int) {
      def bestGuess: String
      def update(guess: String, grade: Grade): Notes
    }

    case object Notes0 extends Notes(0) {
      def bestGuess = GuessPack.firstGuess

      def genSpaceCandidates(grade: Grade): List[Spacing] = (for {
        wlen1 <- WordList.lengthRange
        wlen2 <- WordList.lengthRange
        spacing = Spacing(wlen1, wlen2, grade.total)
        if spacing.freq > 0
        if grade.black == spacing.black(bestGuess)
      } yield spacing).sortBy(-_.freq).toList

      def update(guess: String, grade: Grade) =
        Notes1(grade.total, genSpaceCandidates(grade), Limiter(Counts.withMax(grade.total - 2), Nil), GuessPack.stream)
    }

    case class Notes1(phraseLength: Int, spacingCandidates: List[Spacing], limiter: Limiter, guesses: Stream[GuessPack]) extends Notes(1) {
      def bestGuess = (chance match {
        case x if x < prob => guesses.head.spacing.take(phraseLength)
        case _             => spacingCandidates.head.mkString
      }) + guesses.head.charSet

      def totalFreq = spacingCandidates.foldLeft(0l)({ _ + _.freq })
      def chance = spacingCandidates.head.freq * 1.0 / totalFreq

      def update(guess: String, grade: Grade) = {
        val newLim = limiter.update(guess, grade)
        val newCands = spacingCandidates.filter(_.black(guess) == grade.black)

        newCands match {
          case best :: Nil if newLim.full => Notes3(newLim.allCandidates(best))
          case best :: Nil                => Notes2(best, newLim, guesses.tail)
          case _                          => Notes1(phraseLength, newCands, newLim, guesses.tail)
        }
      }
    }

    case class Notes2(spacing: Spacing, limiter: Limiter, guesses: Stream[GuessPack]) extends Notes(2) {
      def bestGuess = tile(guesses.head.pattern) + guesses.head.charSet

      def whiteSide(guess: String): String = guess.drop(spacing.phraseLength)
      def blackSide(guess: String): String = guess.take(spacing.phraseLength)

      def tile(guess: String) = spacing.lengths.map(guess.take).mkString(" ")
      def untile(guess: String) = blackSide(guess).split(" ").maxBy(_.length) + "-"

      def update(guess: String, grade: Grade) = {
        val newLim = limiter.updateBoth(whiteSide(guess), untile(guess), grade)

        if (newLim.full)
          Notes3(newLim.allCandidates(spacing))
        else
          Notes2(spacing, newLim, guesses.tail)
      }
    }

    case class Notes3(candidates: Array[String]) extends Notes(3) {
      def bestGuess = sample.minBy(expLogNRC)

      def update(guess: String, grade: Grade) =
        Notes3(candidates.filter(phrase => grade == Grade.compute(guess, phrase)))

      def numRemCands(phrase: String, guess: String): Int = {
        val grade = Grade.compute(guess, phrase)
        sample.count(phrase => grade == Grade.compute(guess, phrase))
      }

      val sample = if (candidates.size <= 32) candidates else candidates.sortBy(_.hashCode).take(32)

      def expLogNRC(guess: String): Double = sample.map(phrase => Math.log(1.0 * numRemCands(phrase, guess))).sum
    }

    case class Spacing(wl1: Int, wl2: Int, phraseLength: Int) {
      def wl3 = phraseLength - 2 - wl1 - wl2
      def lengths = Array(wl1, wl2, wl3)
      def pos = Array(wl1, wl1 + 1 + wl2)
      def freq = lengths.map(WordList.freq).product
      def black(guess: String) = pos.count(guess(_) == ' ')
      def mkString = lengths.map("-" * _).mkString(" ")
    }

    case class Limiter(counts: Counts, guesses: List[String], extraGuesses: List[(String, Grade)] = Nil) {
      def full = guesses.size >= minCounts

      def update(guess: String, grade: Grade) =
        if (guesses.size < Counts.Max)
          Limiter(counts.update(grade.total - 2), guess :: guesses)
        else
          Limiter(counts, guesses, (guess, grade) :: extraGuesses)

      def updateBoth(whiteSide: String, blackSide: String, grade: Grade) =
        Limiter(counts.update(grade.total - 2).update(grade.black - 2), blackSide :: whiteSide :: guesses)

      def isCandidate(phrase: String): Boolean = extraGuesses forall {
        case (guess, grade) => grade == Grade.compute(guess, phrase)
      }

      def allCandidates(spacing: Spacing): Array[String] = {

        val order = Array(0, 1, 2).sortBy(-spacing.lengths(_)) //longest word first
        val unsort = Array.tabulate(3)(i => order.indexWhere(i == _))

        val wordListI = WordList.byLength(spacing.lengths(order(0)))
        val wordListJ = WordList.byLength(spacing.lengths(order(1)))
        val wordListK = WordList.byLength(spacing.lengths(order(2)))

        val gsr = guesses.reverse
        val countsI = wordListI.map(Counts.compute(_, gsr).z)
        val countsJ = wordListJ.map(Counts.compute(_, gsr).z)
        val countsK = wordListK.map(Counts.compute(_, gsr).z)

        val rangeI = 0 until wordListI.size
        val rangeJ = 0 until wordListJ.size
        val rangeK = 0 until wordListK.size

        (for {
          i <- rangeI.par
          if Counts(countsI(i)) <= counts
          j <- rangeJ
          countsIJ = countsI(i) + countsJ(j)
          if Counts(countsIJ) <= counts
          k <- rangeK
          if countsIJ + countsK(k) == counts.z
          words = Array(wordListI(i), wordListJ(j), wordListK(k))
          phrase = unsort.map(words).mkString(" ")
          if isCandidate(phrase)
        } yield phrase).seq.toArray
      }
    }

    object Counts {
      val Max = 9
      val range = 0 until Max
      def withMax(size: Int): Counts = Counts(range.foldLeft(size.toLong) { (z, i) => (z << 6) | size })

      def compute(word: String, x: List[String]): Counts = x.foldLeft(Counts.withMax(word.length)) { (c: Counts, s: String) =>
        c.update(if (s.last == '-') Grade.computeBlack(word, s) else Grade.computeTotal(word, s))
      }
    }

    case class Counts(z: Long) extends AnyVal {
      @inline def +(that: Counts): Counts = Counts(z + that.z)
      @inline def apply(i: Int): Int = ((z >> (6 * i)) & 0x3f).toInt
      @inline def size: Int = this(Counts.Max)

      def <=(that: Counts): Boolean =
        Counts.range.forall { i => (this(i) <= that(i)) && (this.size - this(i) <= that.size - that(i)) }

      def update(c: Int): Counts = Counts((z << 6) | c)
      override def toString = Counts.range.map(apply).map(x => f"$x%2d").mkString(f"Counts[$size%2d](", " ", ")")
    }

    case class GuessPack(spacing: String, charSet: String, pattern: String)

    object GuessPack {
      util.Random.setSeed(rngSeed)
      val RBF: Any => Boolean = _ => util.Random.nextBoolean() //Random Boolean Function

      def genCharsGuess(q: Char => Boolean): String =
        (for (c <- 'a' to 'z' if q(c); j <- 1 to WordList.maxCount(c)) yield c).mkString

      def charChooser(i: Int)(c: Char): Boolean = c match {
        case 'e' => Array(true, true, true, false, false, false)(i % 6)
        case 'i' => Array(false, true, false, true, false, true)(i % 6)
        case 'a' => Array(true, false, false, true, true, false)(i % 6)
        case 's' => Array(false, false, true, false, true, true)(i % 6)
        case any => RBF(any)
      }

      def genSpaceGuess(q: Int => Boolean = RBF): String = genPatternGuess(" -", q)

      def genPatternGuess(ab: String, q: Int => Boolean = RBF) =
        (for (i <- 0 to 64) yield (if (q(i)) ab(0) else ab(1))).mkString

      val firstGuess = genSpaceGuess(i => (i % 2) == 1) + genCharsGuess(_ => true)

      val stream: Stream[GuessPack] = Stream.from(0).map { i =>
        GuessPack(genSpaceGuess(), genCharsGuess(charChooser(i)), genPatternGuess("eias".filter(charChooser(i))))
      }
    }
  }

  object WordList {
    val lengthRange = wordList.map(_.length).min until wordList.map(_.length).max

    val byLength = Array.tabulate(lengthRange.end)(i => wordList.filter(_.length == i))

    def freq(wordLength: Int): Long = if (lengthRange contains wordLength) byLength(wordLength).size else 0

    val maxCount: Map[Char, Int] = ('a' to 'z').map(c => (c -> wordList.map(_.count(_ == c)).max * 3)).toMap
  }

  object Grade {
    def apply(black: Int, white: Int): Grade = Grade(black | (white << 8))
    val Success = Grade(-1)

    def computeBlack(guess: String, phrase: String): Int = {
      @inline def posRange: Range = 0 until Math.min(guess.length, phrase.length)
      @inline def sameChar(p: Int): Boolean = (guess(p) == phrase(p)) && guess(p) != '-'
      posRange count sameChar
    }

    def computeTotal(guess: String, phrase: String): Int = {
      @inline def minCount(c: Char): Int = Math.min(phrase.count(_ == c), guess.count(_ == c))
      minCount(' ') + ('a' to 'z').map(minCount).sum
    }

    def compute(guess: String, phrase: String): Grade = {
      val black = computeBlack(guess, phrase)
      if (black == guess.length && black == phrase.length)
        Grade.Success
      else
        Grade(black, computeTotal(guess, phrase) - black)
    }
  }

  case class Grade(z: Int) extends AnyVal {
    def black: Int = z & 0xff
    def white: Int = z >> 8
    def total: Int = black + white
    def success: Boolean = this == Grade.Success
    override def toString = if (success) "SUCCESS" else f"($black%2d/$white%2d)"
  }
}

2
সাইটে স্বাগতম, এবং অভিনন্দন! আপনি বেশি পরিমাণে অনুগ্রহ কাটফাঁটি করেননি, তবে আপনি এটি তৈরি করেছেন। কিছু কাল্পনিক ইন্টারনেট পয়েন্ট আছে!
জিওবিটস

কেবল ব্রিল্যান্ট

অসাধারণ সমাধান! এটি 10,000 মার্কের নীচে একমাত্র!
সঞ্জয় জৈন

15

সি - মোট: 37171, মিনিট: 24, সর্বোচ্চ: 55, সময়: প্রায় 10 সেকেন্ড

আমি ফাঁকের সাথে অনুমান করে প্রতিটি শব্দের দৈর্ঘ্য সন্ধান করার জন্য রে এর ধার ধার নিয়েছিলাম, আমি রৈখিকের চেয়ে বাইনারি অনুসন্ধান না করে যা আমার অনুমানগুলি অনেকটা সঞ্চয় করে।

আমি যখন কোনও শব্দের দৈর্ঘ্য নির্ধারণ করি, তখন অনুমান করি প্রথম শব্দটি যা এর দৈর্ঘ্যের সাথে মেলে এবং আমি সঠিক অবস্থানগুলির সংখ্যা রেকর্ড করি। তারপরে আমি সমস্ত শব্দগুলির সেট থেকে প্রথম শব্দটি নির্বাচন করি যা রহস্য শব্দ হিসাবে আমার প্রথম অনুমানের সাথে একই সংখ্যক অবস্থান ভাগ করে দেয়। আমার তৃতীয় অনুমানের জন্য আমি সমস্ত শব্দগুলির সেট থেকে প্রথম শব্দটি নির্বাচন করি যা রহস্য শব্দ হিসাবে আমার প্রথম অনুমানের সাথে একই সংখ্যার অবস্থান ভাগ করে এবং রহস্য শব্দের সাথে আমার দ্বিতীয় অনুমান হিসাবে একই পজিশন ইত্যাদি etc.

এই পদ্ধতিটি ব্যবহার করে আমি প্রায় 5-10 অনুমানে প্রতিটি শব্দ একবারে একটি করে অনুমান করতে সক্ষম। স্পষ্টতই তৃতীয় শব্দটি আমাকে কিছুটা আলাদাভাবে করতে হবে কারণ আমি এর দৈর্ঘ্য জানি না, তবে পদ্ধতিটি একই। আমি এমন একটি ফাইল ব্যবহার করি যার মধ্যে প্রতিটি শব্দ ভাগ করে নেওয়ার মতামতের একটি ম্যাট্রিক্স থাকে যা আমি প্রাক বন্ধ করে দিয়েছি। প্রম্পম্পিউড ডেটা লোড করার সময় বেশিরভাগ রান-টাইম ব্যয় করা হয়। আপনি এখানে সবকিছু ডাউনলোড করতে পারেন ।

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>

#define DICTIONARY_SIZE 10000
#define PHRASE_COUNT 1000
#define MAX_STRING 512
#define MAX_SAVED_GUESSES 100
#define DEBUG

typedef struct {
    int wordlen;
    char word[MAX_STRING];
} dictionary_entry;

static int g_guesses;
static int g_max_word_len;
static int g_min_word_len;
static char *g_password;
static dictionary_entry g_dictionary[DICTIONARY_SIZE];
static char g_phrases[PHRASE_COUNT][MAX_STRING];
static int g_pos_matrix[DICTIONARY_SIZE][DICTIONARY_SIZE];

/* Returns true if the guess was correct and false otherwise */
int guess(char *in, int *chars, int *positions)
{
    int i, j, contains;
    char c, pw[1024];

    /* Increment the total guess count */
    g_guesses++;

    strcpy(pw, g_password);
    *chars = 0;
    *positions = 0;
    for (i = 0; (i < strlen(in)) && (i < strlen(pw)); i++)
        if (in[i] == pw[i])
            (*positions)++;
    if (strcmp(in, pw) == 0) {
        *chars = -1;
        return 1;
    }
    for (i = 0; i < strlen(in); i++) {
        for (j = 0; j < strlen(pw); j++) {
            if (pw[j] == in[i]) {
                (*chars)++;
                pw[j] = '*';
                break;
            }
        }
    }
    (*chars) -= (*positions);
    return 0;
}

int checker() {
    char guess_str[MAX_STRING], *guess_ptr;
    int i, j, saved_guesses, word;
    int guesses;
    int chars, positions;
    int wordlen[3], wordidx[3];
    int guesswordidx[MAX_SAVED_GUESSES];
    int guesswordpos[MAX_SAVED_GUESSES];
    int tryit, finished;

    /* Initialize everything */
    finished = 0;
    guess_ptr = guess_str;
    for (i = 0; i < 3; i++) {
        wordlen[i] = -1;
        wordidx[i] = -1;
    }

    guesses = 0;
    for (word = 0; word < 3; word++) {
        saved_guesses = 0;

        // If we're not on the last word, figure out how long the word is by
        // doing a binary search using spaces
        if (word < 2) {
            int a = g_min_word_len, b = g_max_word_len;
            int c;
            while (wordlen[word] == -1) {
                c = (b + a) / 2;
                for (i = 0; i <= c; i++) {
                    guess_ptr[i] = ' ';
                }
                guess_ptr[i] = '\0';
                guess(guess_str, &chars, &positions);
                guesses++;
                if (positions == 0) {
                    if (b - a < 2)
                        wordlen[word] = b;
                    a = c;
                } else {
                    if (b - a < 2)
                        wordlen[word] = c;
                    b = c;
                }
            }
            #ifdef DEBUG
            printf("\tLength of next word is %d.\n", wordlen[word]);
            #endif
        }


        // Look for words using matching positions from previous guesses to improve our search
        for (i = 0; i < DICTIONARY_SIZE; i++) {
            tryit = 1;
            for (j = 0; j < saved_guesses; j++) {
                if (g_pos_matrix[guesswordidx[j]][i] != guesswordpos[j]) {
                    tryit = 0;
                    break;
                }
            }
            // If the word length is incorrect then don't bother
            if ((word < 2) && (g_dictionary[i].wordlen != wordlen[word]))
                tryit = 0;
            if (tryit) {
                strcpy(guess_ptr, g_dictionary[i].word);
                guess(guess_str, &chars, &positions);
                guesses++;
                #ifdef DEBUG
                printf("\tWe guessed \"%s\", it had %d correct positions.\n", g_dictionary[i].word, positions);
                #endif
                guesswordidx[saved_guesses] = i;
                guesswordpos[saved_guesses] = positions;
                saved_guesses++;

                // If we're on the last word and all the positions matched then check if we've found the phrase
                if ((word == 2) && (g_dictionary[i].wordlen == positions)) {
                    sprintf(guess_ptr, "%s %s %s", g_dictionary[wordidx[0]].word, g_dictionary[wordidx[1]].word, g_dictionary[i].word);
                    guesses++;
                    if (guess(guess_ptr, &chars, &positions)) {
                        finished = 1;
                        break;
                    }
                }
            }
        }
        wordidx[word] = guesswordidx[saved_guesses - 1];
        wordlen[word] = g_dictionary[guesswordidx[saved_guesses - 1]].wordlen;
        #ifdef DEBUG
        printf("\tThe next word is \"%s\".\n", g_dictionary[wordidx[word]].word);
        #endif
        guess_ptr += wordlen[word] + 1;
        for (i = 0; i < guess_ptr - guess_str; i++) {
            guess_str[i] = '#';
        }
    }
    #ifdef DEBUG
    if (finished) {
        sprintf(guess_str, "%s %s %s", g_dictionary[wordidx[0]].word, g_dictionary[wordidx[1]].word, g_dictionary[wordidx[2]].word);
        printf("\tPhrase is \"%s\". Found in %d guesses.\n", guess_str, guesses);
    } else {
        printf("Oh noes! Something went wrong!\n");
        exit(1);
    }
    #endif
    return guesses;
}

int main(int argc, char **argv)
{
    FILE *dictfp, *phrasefp, *precompfp;
    int i, j, total_count, chars, positions;

    g_max_word_len = 0;
    g_min_word_len = 9999;
    dictfp = fopen("dictionary.txt", "r");
    for (i = 0; i < DICTIONARY_SIZE; i++) {
        fgets(g_dictionary[i].word, MAX_STRING, dictfp);
        while (!isalpha(g_dictionary[i].word[strlen(g_dictionary[i].word) - 1]))
            g_dictionary[i].word[strlen(g_dictionary[i].word) - 1] = '\0';
        g_dictionary[i].wordlen = strlen(g_dictionary[i].word);
        if (g_dictionary[i].wordlen < g_min_word_len)
            g_min_word_len = g_dictionary[i].wordlen;
        if (g_dictionary[i].wordlen > g_max_word_len)
            g_max_word_len = g_dictionary[i].wordlen;
    }
    fclose(dictfp);

    phrasefp = fopen("phrases.txt", "r");
    for (i = 0; i < PHRASE_COUNT; i++) {
        fgets(g_phrases[i], MAX_STRING, phrasefp);
        while (!isalpha(g_phrases[i][strlen(g_phrases[i]) - 1]))
            g_phrases[i][strlen(g_phrases[i]) - 1] = '\0';
    }
    fclose(phrasefp);

    precompfp = fopen("precomp.txt", "r");
    for (i = 0; i < DICTIONARY_SIZE; i++) {
        for (j = 0; j < DICTIONARY_SIZE; j++) {
            fscanf(precompfp, "%d ", &(g_pos_matrix[i][j]));
        }
    }

    g_guesses = 0;
    int min = 9999, max = 0, g;
    for (i = 0; i < PHRASE_COUNT; i++) {
        g_password = g_phrases[i];
        #ifdef DEBUG
        printf("Testing passphrase \"%s\"...\n", g_password);
        #endif
        g = checker();
        if (g < min) min = g;
        if (g > max) max = g;
    }

    printf("Total %d. Min %d. Max %d.\n", g_guesses, min, max);
    return 0;
}

এটি কথায় সংকীর্ণ দেখতে মজাদার:

Testing passphrase "somebody sighed intimater"...
    Length of next word is 8.
    We guessed "abashing", it had 0 correct positions.
    We guessed "backlogs", it had 1 correct positions.
    We guessed "befitted", it had 0 correct positions.
    We guessed "caldwell", it had 0 correct positions.
    We guessed "disgusts", it had 0 correct positions.
    We guessed "encroach", it had 0 correct positions.
    We guessed "forenoon", it had 3 correct positions.
    We guessed "hotelman", it had 2 correct positions.
    We guessed "somebody", it had 8 correct positions.
    The next word is "somebody".
    Length of next word is 6.
    We guessed "abacus", it had 0 correct positions.
    We guessed "baboon", it had 0 correct positions.
    We guessed "celery", it had 0 correct positions.
    We guessed "diesel", it had 2 correct positions.
    We guessed "dimple", it had 1 correct positions.
    We guessed "duster", it had 1 correct positions.
    We guessed "hinged", it had 3 correct positions.
    We guessed "licked", it had 3 correct positions.
    We guessed "sighed", it had 6 correct positions.
    The next word is "sighed".
    We guessed "aaas", it had 0 correct positions.
    We guessed "b", it had 0 correct positions.
    We guessed "c", it had 0 correct positions.
    We guessed "debauchery", it had 2 correct positions.
    We guessed "deceasing", it had 0 correct positions.
    We guessed "echinoderm", it had 3 correct positions.
    We guessed "enhanced", it had 1 correct positions.
    We guessed "intimater", it had 9 correct positions.
    The next word is "intimater".
    Phrase is "somebody sighed intimater". Found in 38 guesses.

1
আমি এটি পছন্দ করি, একটি অনুজ্ঞাত পরবর্তী পদক্ষেপটি আপনি যে অনুমান করার জন্য ব্যবহার করেন সেই শব্দ তালিকাটি একটি শক্তিশালী উপায়ে অর্ডার করা হয়েছে তা নিশ্চিত করা যায়। অন্তত প্রতিটি অক্ষরের জন্য আপনার একটি ভাল শুরু শব্দ আছে তা নিশ্চিত করুন।
ডেনিস জাহেরউদ্দিন

এটি দারুণ ভাবনা. সাহায্য করার জন্য ধন্যবাদ.
অরবি

15

পাইথন 3.4 - মিনিট: 21, সর্বোচ্চ: 29, মোট: 25146, সময়: 20 মিনিট

মিনিট: 30, সর্বোচ্চ: 235, মোট: 41636, সময়: 4 মিনিট

হালনাগাদ:

  1. স্থান খুঁজতে বাইনারি অনুসন্ধান ব্যবহার করুন। ধারণাটি অর্বির উত্তর থেকে ধার করা হয়েছে । একটি জায়গা যেখানে আমি অপ্টিমাইজ করেছিলাম তা হ'ল যদি প্রথম স্থান অনুসন্ধানের জন্য আপনি যদি কোনও পরিসরে 2 টি স্পেস পেয়ে থাকেন তবে আপনি দ্বিতীয় স্থানটির অনুসন্ধানের সীমাটি সংকুচিত করতে পারেন।
  2. তাদের ফলাফলের সাথে ভুল অনুমানগুলি সংরক্ষণ করুন। নিম্নলিখিত অনুমানগুলির সাথে তাদের সাথে তুলনা করুন। এটি অনেক কিছু বাঁচাতে পারে।
  3. # 2 আপডেট করার জন্য ধন্যবাদ, চিঠিপত্রের গণনা 12 টি হ্রাস করুন।

এখানে চিত্র বর্ণনা লিখুন


এই মেহোড এলোমেলোভাবে ব্যবহার করবে না যাতে স্কোর পরিবর্তন হবে না।

প্রথমে উত্তরের প্রথম এবং দ্বিতীয় স্থান খুঁজে পেতে এটি নীচের মতো অনুমানগুলি ব্যবহার করে।

. ......................
.. .....................
... ....................
.... ...................
# more follows, until two spaces found.

তারপর, এটি মনন দ্বারা প্রতিটি চিঠির সংঘটন গণনা aaaaa..., bbbbb....... এই পরে 40 পদক্ষেপ সম্পর্কে খরচ হবে। আসলে, আমাদের সমস্ত অক্ষর চেষ্টা করার প্রয়োজন নেই এবং আমরা সেগুলি সালিসি ক্রমে চেষ্টা করতে পারি। বেশিরভাগ ক্ষেত্রে, প্রায় 20 টি অক্ষর চেষ্টা করা যথেষ্ট। এখানে আমি 21 পছন্দ করি।

এখন এটি প্রথম শব্দের দৈর্ঘ্য এবং দ্বিতীয় শব্দটি জানেন যাতে এটি এই দুটি শব্দের জন্য প্রার্থীদের একটি তালিকা ফিল্টার করতে পারে। সাধারণত এটির প্রত্যেকটির জন্য প্রায় 100 জন প্রার্থী থাকবে।

তারপরে এটি কেবল প্রথম এবং দ্বিতীয় শব্দটি গণনা করবে। প্রথম দুটি শব্দ একবার অঙ্কিত হয়ে গেলে, আমরা সমস্ত বৈধ তৃতীয় শব্দ অনুমান করতে পারি যেহেতু আমরা জানি যে এটির চরিত্রের গণনা রয়েছে।

গতির জন্য অনুকূলিত করতে, আমি concurrent.futuresপ্রোগ্রামটিতে মাল্টিপ্রসেসিং যুক্ত করতে ব্যবহার করি । সুতরাং এটি চালানোর জন্য আপনার পাইথন 3 প্রয়োজন এবং আমি এটি আমার লিনাক্স বাক্সে পাইথন 3.4 দিয়ে পরীক্ষা করেছি। এছাড়াও, আপনি ইনস্টল করা প্রয়োজন numpy

import sys
import functools
from collections import defaultdict
from concurrent.futures import ProcessPoolExecutor
import numpy as np


def debug(*args, **kwargs):
    return
    print(*args, **kwargs)


def compare(answer, guess):
    b = sum(1 for x, y in zip(guess, answer) if x == y)
    a = 0
    c = defaultdict(int)
    for x in answer:
        c[x] += 1

    for x in guess:
        if c.get(x, 0) > 0:
            a += 1
            c[x] -= 1
    return a, b


def checker_task(guesser):
    @functools.wraps(guesser)
    def task(case):
        i, answer = case
        return (i, answer, run_checker(answer, guesser))
    return task


def run_checker(answer, guesser):
    guess_count = 0
    guesser = guesser()
    guess = next(guesser)
    while True:
        guess_count += 1
        if answer == guess:
            break
        try:
            guess = guesser.send(compare(answer, guess))
        except StopIteration:
            raise Exception('Invalid guesser')
    try:
        guesser.send((-1, -1))
    except StopIteration:
        pass
    return guess_count


# Preprocessing
words = list(map(str.rstrip, open('dict.txt')))
words_with_len = defaultdict(list)
for word in words:
    words_with_len[len(word)].append(word)

M = 12
chars = 'eiasrntolcdupmghbyfvkwzxjq'[:M]
char_ord = {c: i for i, c in enumerate(chars)}

def get_fingerprint(word):
    counts = [0] * (M + 1)
    for c in word:
        counts[char_ord.get(c, M)] += 1
    return tuple(counts[:-1])

word_counts = {word: np.array(get_fingerprint(word)) for word in words}

# End of preprocessing


# @profile
@checker_task
def guesser1():
    # Find spaces using binary search
    max_word_len = max(map(len, words))
    max_len = max_word_len * 3 + 2
    # debug('max_len', max_len)
    s_l = [1, 3]
    s_r = [max_len - 3, max_len - 1]

    for i in range(2):
        while s_l[i] + 1 < s_r[i]:
            # debug(list(zip(s_l, s_r)))
            mid = (s_l[i] + s_r[i]) // 2
            guess = '.' * s_l[i] + ' ' * (mid - s_l[i])
            a, b = yield guess
            if b > 1 and i == 0:
                s_l[1] = max(s_l[1], s_l[0] + 2)
                s_r[1] = min(s_r[1], mid)
                s_r[0] = mid - 2
            elif b > 0:
                s_r[i] = mid
            else:
                s_l[i] = mid
        if i == 0:
            s_l[1] = max(s_l[1], s_l[0] + 2)

    spaces = s_l
    del s_l, s_r

    word_lens = [spaces[0], spaces[1] - spaces[0] - 1, None]
    debug('word_lens', word_lens)
    debug('spaces', spaces)
    char_counts = [0] * M
    for i, c in enumerate(chars):
        guess = c * max_len
        _, char_counts[i] = yield guess

    char_counts = np.array(char_counts)

    candidates = [words_with_len[word_lens[0]], words_with_len[word_lens[1]], words]
    for i, ws in enumerate(candidates):
        candidates[i] = [word for word in ws if np.alltrue(char_counts >= word_counts[word])]
    P = defaultdict(list)
    for word in candidates[2]:
        P[get_fingerprint(word)].append(word)
    debug('candidates', list(map(len, candidates)))

    wrong_guesses = []
    # @profile
    def search(i, counts, current):
        if i == 2:
            rests = tuple(char_counts - counts)
            for word in P[rests]:
                current[i] = word
                guess_new = ' '.join(current)
                for guess, t in wrong_guesses:
                    if t != compare(guess_new, guess):
                        break
                else:
                    yield current
            return
        for word in candidates[i]:
            counts += word_counts[word]
            if np.alltrue(char_counts >= counts):
                current[i] = word
                yield from search(i + 1, counts, current)
            counts -= word_counts[word]

    try_count = 0
    for result in search(0, np.array([0] * M), [None] * 3):
        guess = ' '.join(result)
        a, b = yield guess
        try_count += 1
        if a == -1:
            break
        wrong_guesses.append((guess, (a, b)))
    debug('try_count', try_count)


def test(test_file, checker_task):
    cases = list(enumerate(map(str.rstrip, open(test_file))))
    scores = [None] * len(cases)
    with ProcessPoolExecutor() as executor:
        for i, answer, score in executor.map(checker_task, cases):
            print('-' * 80)
            print('case', i)
            scores[i] = score
            print('{}: {}'.format(answer, score))
            sys.stdout.flush()
    print(scores)
    print('sum:{} max:{} min:{}'.format(sum(scores), max(scores), min(scores)))


if __name__ == '__main__':
    test(sys.argv[1], guesser1)

1
এটাকে বোকা বানাতে আমার খুব কষ্ট হচ্ছে। সুন্দর কাজ.
অরবি

1
আপনি গ্রাফটি কীভাবে তৈরি করলেন?
বিটা ক্ষয়

1
@ বেটাডেকে ম্যাপপ্ল্লিটিব ব্যবহার করে একটি স্ক্রিপ্ট।
রে

1
@ ডেনিসজাহেরউদ্দিন, হ্যাঁ, এটি খুব কুরুচিপূর্ণ। এখনই স্থির।
রায়

1
আমি মনে করি আপনি matplotlibs ব্যবহার করা উচিত গ্রাফের জন্য xkcdify matplotlib.org/xkcd/examples/showcase/xkcd.html
MrLemon

14

জাভা 13,923 (মিনিট: 11, সর্বাধিক: 17)

আপডেট: উন্নত স্কোর (<14 / ক্র্যাক গড় ভেঙে!), নতুন কোড

  • পরিচিত চরিত্রগুলি এখন ঘনঘন করা হচ্ছে (এখন-আবাবিএবি *, -AAAA * এর পরিবর্তে)
  • যখন কোনও পরিচিত অক্ষর উপলব্ধ নেই, দুটি অজানা একক অনুমানে গণনা করা হবে
  • ভুল অনুমানগুলি সংরক্ষণ করা হয় এবং সম্ভাব্য ম্যাচগুলি পরীক্ষা করতে ব্যবহৃত হয়
  • জায়গায় নতুন যুক্তি দিয়ে কিছু ধ্রুবক টুইট

আসল পোস্ট

আমি পারফরম্যান্সের পরিবর্তে অনুমানের পরিমাণের উপর সম্পূর্ণ ফোকাস করার সিদ্ধান্ত নিয়েছি (বিধি অনুসারে)। এটি একটি খুব ধীর স্মার্ট প্রোগ্রামের ফলস্বরূপ ।

পরিচিত প্রোগ্রামগুলি থেকে চুরি করার পরিবর্তে আমি স্ক্র্যাচ থেকে সবকিছু লেখার সিদ্ধান্ত নিয়েছি, তবে এটি থেকে দেখা গেছে / বেশিরভাগ ধারণাগুলি একই।

অ্যালগরিদম

এইভাবে আমার কাজ করে:

  1. একটি একক কোয়েরি করুন যার ফলশ্রুতিতে ই এর পরিমাণ এবং মোট অক্ষর রয়েছে
  2. এর পরে আমরা শূন্যস্থানগুলির সন্ধান করি, একটি অক্ষর গণনা পেতে শেষে কিছু অজানা অক্ষর যুক্ত করি
  3. একবার স্পেসগুলি পাওয়া গেলে আমরা আরও চরিত্রের সংখ্যা অনুসন্ধান করতে চাই, এর মাঝামাঝি সময়ে আমি আমি পরিচিত অক্ষরগুলির উপর আরও ডেটা পাই (যদি তারা এমনকি পজিশনে থাকে) যা আমাকে প্রচুর বাক্যাংশগুলি দূর করতে সহায়তা করবে।
  4. যখন আমরা একটি নির্দিষ্ট সীমাতে পৌঁছে যাই (ট্রেইল / ত্রুটি) এটি সমস্ত সম্ভাব্য বাক্যাংশ তৈরি করে এবং একটি বাইনারি অনুসন্ধান শুরু করে, বেশিরভাগ সময় এখনও শেষে অজানা অক্ষর যুক্ত করা হয়।
  5. শেষ পর্যন্ত আমরা কিছু অনুমান করি!

অনুমান উদাহরণ

এখানে একটি বাস্তব উদাহরণ:

Phase 1 (find the e's and total character count):
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbccccccccccccccccccddddddddddddddddddffffffffffffffffffgggggggggggggggggghhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkllllllllllllllllllmmmmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnnnnooooooooooooooooooppppppppppppppppppqqqqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrssssssssssssssssssttttttttttttttttttuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzz
Phase 2 (find the spaces):
        ----------------iiiiiiiiiiiiiiiiii
              ----------aaaaaaaaaaaa
           -------------sssssssssssssss
          --------------rrrrrrrrrrrr
         ---------------nnnnnnnnnnn
                 -------ttttttttt
               ---------oooooooo
                --------lllllll
Phase 3 (discovery of characters, collecting odd/even information):
eieieieieieieieieieieieicccccc
ararararararararararararddddd
ntntntntntntntntntntntntuuuuu
Phase 4 (binary search with single known character):
------------r------------ppppp
Phase 5 (actual guessing):
enveloper raging charter
racketeer rowing halpern

কারণ আমার কোডটি কখনও সত্যই একক শব্দের উপরে মনোনিবেশ করে না এবং কেবলমাত্র পুরো বাক্যাংশের তথ্য সংগ্রহ করে যা এটিকে অনেক ধীরে ধীরে তৈরি করে gene

কোড

এবং অবশেষে এখানে (কুরুচিপূর্ণ) কোডটি রয়েছে, এটি বোঝার চেষ্টাও করবেন না, দুঃখিত:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MastermindV3 {

    // Order of characters to analyze:
    // eiasrntolcdupmghbyfvkwzxjq - 97
    private int[] lookup = new int[] {4, 8, 0, 18, 17, 13, 19, 14, 11, 2, 3, 20, 15, 12, 6, 7, 1, 24, 5, 21, 10, 22, 25, 23, 9, 16};

    public static void main(String[] args) throws Exception {
        new MastermindV3().run();
    }

    private void run() throws Exception {
        long beforeTime = System.currentTimeMillis();
        Map<Integer, List<String>> wordMap = createDictionary();
        List<String> passPhrases = createPassPhrases();

        int min = Integer.MAX_VALUE;
        int max = 0;
        for(String phrase:passPhrases) {

            int before = totalGuesses;
            solve(wordMap, phrase);
            int amount = totalGuesses - before;

            min = Math.min(min, amount);
            max = Math.max(max, amount);
            System.out.println("Amount of guesses: "+amount+" : min("+min+") max("+max+")");
        }
        System.out.println("Total guesses: " + totalGuesses);
        System.out.println("Took: "+ (System.currentTimeMillis()-beforeTime)+" ms");
    }

    /**
     * From the original question post:
     * I've added a boolean for the real passphrase.
     * I'm using this method to check previous guesses against my own matches (not part of Mastermind guesses)
     */
    int totalGuesses = 0;
    int[] guess(String in, String pw, boolean againstRealPassphrase) {
        if(againstRealPassphrase) {
            //Only count the guesses against the password, not against our own previous choices
            totalGuesses++;
        }
        int chars=0, positions=0;
        for(int i=0;i<in.length()&&i<pw.length();i++){
            if(in.charAt(i)==pw.charAt(i))
                positions++;
        }
        if(positions == pw.length() && pw.length()==in.length())
            return new int[]{-1,positions};
        for(int i=0;i<in.length();i++){
            String c = String.valueOf(in.charAt(i));
            if(pw.contains(c)){
                pw = pw.replaceFirst(c, "");
                chars++;
            }
        }
        chars -= positions;
        return new int[]{chars,positions};
    }

    private void solve(Map<Integer, List<String>> wordMap, String pw) {

        // Do one initial guess which gives us two things:
        // The amount of characters in total
        // The amount of e's

        int[] initialResult = guess(Facts.INITIAL_GUESS, pw, true);

        // Create the object that tracks all the known facts/bounds:
        Facts facts = new Facts(initialResult);

        // Determine a pivot and find the spaces (binary search)
        int center = ((initialResult[0] + initialResult[1]) / 3) + 1;
        findSpaces(center, facts, pw);

        // When finished finding the spaces (and some character information)
        // We can calculate the lengths:
        int length1 = (facts.spaceBounds[0]-1);
        int length2 = (facts.spaceBounds[2]-facts.spaceBounds[0]-1);
        int length3 = (facts.totalLength-facts.spaceBounds[2]+2);

        // Next we enter a discovery loop where we find out two things:
        // 1) The amount of a new character
        // 2) How many of a known character are on an even spot
        int oddPtr = 0;
        int pairCnt = 0;

        // Look for more characters, unless we have one HUGE word, which should be brute forcible easily
        int maxLength = Math.max(length1, Math.max(length2, length3));
        while(maxLength<17 && !facts.doneDiscovery()) { // We don't need all characters, the more unknowns the slower the code, but less guesses

            // Try to generate a sequence with ABABABABAB... with two characters with known length
            String testPhrase = "";
            int expected = 0;
            while(oddPtr < facts.charPtr && (facts.oddEvenUsed[oddPtr]!=-1 || facts.charBounds[lookup[oddPtr]] == 0)) {
                oddPtr++;
            }
            // If no character unknown, try pattern -A-A-A-A-A-A-A... with just one known pattern
            int evenPtr = oddPtr+1;
            while(evenPtr < facts.charPtr && (facts.oddEvenUsed[evenPtr]!=-1 || facts.charBounds[lookup[evenPtr]] == 0)) {
                evenPtr++;
            }

            if(facts.oddEvenUsed[oddPtr]==-1 && facts.charBounds[lookup[oddPtr]] > 0 && oddPtr < facts.charPtr) {
                if(facts.oddEvenUsed[evenPtr]==-1 && facts.charBounds[lookup[evenPtr]] > 0 && evenPtr < facts.charPtr) {
                    for(int i = 0; i < (facts.totalLength + 3) / 2; i++) {
                        testPhrase += ((char)(lookup[oddPtr] + 97) +""+ ((char)(lookup[evenPtr] + 97)));
                    }
                    expected += facts.charBounds[lookup[oddPtr]] + facts.charBounds[lookup[evenPtr]];
                } else {
                    for(int i = 0; i < (facts.totalLength + 3) / 2; i++) {
                        testPhrase += ((char)(lookup[oddPtr] + 97) + "-");
                    }
                    expected += facts.charBounds[lookup[oddPtr]];
                }
            }

            // If we don't have known characters to explore, use the phrase-length part to discover the count of an unknown character
            boolean usingTwoNew = false;
            if(testPhrase.length() == 0 && facts.charPtr < 25) {
                usingTwoNew = true;
                //Fill with a new character
                while(testPhrase.length() < (facts.totalLength+2)) {
                    testPhrase += (char)(lookup[facts.charPtr+1] + 97);
                }
            } else {
                while(testPhrase.length() < (facts.totalLength+2)) {
                    testPhrase += "-";
                }
            }

            // Use the part after the phrase-length to discover the count of an unknown character
            for(int i = 0; i<facts.charBounds[lookup[facts.charPtr]];i++) {
                testPhrase += (char)(lookup[facts.charPtr] + 97);
            }

            // Do the actual guess:
            int[] result = guess(testPhrase, pw, true);

            // Process the results, store the derived facts:
            if(oddPtr < facts.charPtr) {
                if(evenPtr < facts.charPtr) {
                    facts.oddEvenUsed[evenPtr] = pairCnt;
                }
                facts.oddEvenUsed[oddPtr] = pairCnt;
                facts.oddEvenPairScore[pairCnt] = result[1];
                pairCnt++;

            }
            if(usingTwoNew) {
                facts.updateCharBounds(result[0]);
                if(result[1] > 0) {
                    facts.updateCharBounds(result[1]);
                }
            } else {
                facts.updateCharBounds((result[0]+result[1]) - expected);
            }
        }

        // Next we generate a list of possible phrases for further analysis:
        List<String> matchingPhrases = new ArrayList<String>();

        // Hacked in for extra speed, loop over longest word first:
        int[] index = sortByLength(length1, length2, length3);

        @SuppressWarnings("unchecked")
        List<String>[] lists = new List[3];
        lists[index[0]] = wordMap.get(length1);
        lists[index[1]] = wordMap.get(length2);
        lists[index[2]] = wordMap.get(length3);

        for(String w1:lists[0]) {
            //Continue if (according to our facts) this word is a possible partial match:
            if(facts.partialMatches(w1)) {
                for(String w2:lists[1]) {
                    //Continue if (according to our facts) this word is a partial match:
                    if(facts.partialMatches(w1+w2)) {
                        for(String w3:lists[2]) {

                            // Reconstruct phrase in correct order:
                            String[] possiblePhraseParts = new String[] {w1, w2, w3};
                            String possiblePhrase = possiblePhraseParts[index[0]]+" "+possiblePhraseParts[index[1]]+" "+possiblePhraseParts[index[2]];

                            //If the facts form a complete match, continue:
                            if(facts.matches(possiblePhrase)) {
                                matchingPhrases.add(possiblePhrase);
                            }
                        }
                    }
                }
            }
        }
        //Sometimes we are left with too many matching phrases, do a smart match on them, binary search style:
        while(matchingPhrases.size() > 8) {
            int lowestError = Integer.MAX_VALUE;
            boolean filterCharacterIsKnown = false;
            int filterPosition = 0;
            int filterValue = 0;
            String filterPhrase = "";

            //We need to filter some more before trying:
            int targetBinaryFilter = matchingPhrases.size()/2;
            int[][] usedCharacters = new int[facts.totalLength+2][26];
            for(String phrase:matchingPhrases) {
                for(int i = 0; i<usedCharacters.length;i++) {
                    if(phrase.charAt(i) != ' ') {
                        usedCharacters[i][phrase.charAt(i)-97]++;
                    }
                }
            }

            //Locate a certain character/position combination which is closest to 50/50:
            for(int i = 0; i<usedCharacters.length;i++) {
                for(int x = 0; x<usedCharacters[i].length;x++) {
                    int error = Math.abs(usedCharacters[i][x]-targetBinaryFilter);
                    if(error < lowestError || (error == lowestError && !filterCharacterIsKnown)) {

                        //If we do the binary search with a known character we can append more information as well
                        //Reverse lookup if the character is known
                        filterCharacterIsKnown = false;
                        for(int f = 0; f<facts.charPtr; f++) {
                            if(lookup[f]==x) {
                                filterCharacterIsKnown = true;
                            }
                        }

                        filterPosition = i;
                        filterValue = x;
                        filterPhrase = "";
                        for(int e = 0; e<i; e++) {
                            filterPhrase += "-"; 
                        }
                        filterPhrase += ""+((char)(x+97));
                        lowestError = error;
                    }
                }
            }

            //Append new character information as well:
            while(filterPhrase.length() <= (facts.totalLength+2)) {
                filterPhrase += "-";
            }

            if(filterCharacterIsKnown && facts.charPtr < 26) {
                //Append new character to discover
                for(int i = 0; i<facts.charBounds[lookup[facts.charPtr]];i++) {
                    filterPhrase += (char)(lookup[facts.charPtr] + 97);
                }
            }
            //Guess with just that character:
            int[] result = guess(filterPhrase, pw, true);

            //Filter the 50%
            List<String> inFilter = new ArrayList<String>();
            for(String phrase:matchingPhrases) {
                if(phrase.charAt(filterPosition) == (filterValue+97)) {
                    inFilter.add(phrase);
                }
            }
            if(result[1]>0) {
                //If we have a match, retain all:
                matchingPhrases.retainAll(inFilter);
            } else {
                //No match, filter all
                matchingPhrases.removeAll(inFilter);
            }

            if(filterCharacterIsKnown && facts.charPtr < 26) {
                //Finally filter according to the discovered character:
                facts.updateCharBounds((result[0]+result[1]) - 1);

                List<String> toKeep = new ArrayList<String>();
                for(String phrase:matchingPhrases) {
                    if(facts.matches(phrase)) {
                        toKeep.add(phrase);
                    }
                }
                matchingPhrases = toKeep;
            }

        }

        // Finally we have some phrases left, try them!
        for(String phrase:matchingPhrases) {

            if(facts.matches(phrase)) {
                int[] result = guess(phrase, pw, true);

                System.out.println(phrase+" "+Arrays.toString(result));
                if(result[0]==-1) {
                    return;
                }
                // No match, update facts:
                facts.storeInvalid(phrase, result);
            }
        }
        throw new IllegalArgumentException("Unable to solve!?");
    }

    private int[] sortByLength(int length1, int length2, int length3) {
        //God this code is ugly, can't be bothered to fix
        int[] index;
        if(length3 > length2 && length2 > length1) {
             index = new int[] {2, 1, 0};
        } else if(length3 > length1 && length1 > length2) {
             index = new int[] {2, 0, 1};
        } else if(length2 > length3 && length3 > length1) {
             index = new int[] {1, 2, 0};
        } else if(length2 > length1 && length1 > length3) {
             index = new int[] {1, 0, 2};
        } else if(length2 > length3) {
            index = new int[]{0, 1, 2};
        } else {
            index = new int[]{0, 2, 1};
        }
        return index;
    }

    private void findSpaces(int center, Facts facts, String pw) {
        String testPhrase = "";
        //Place spaces for analysis:
        for(int i = 0; i<center; i++) {testPhrase+=" ";}while(testPhrase.length()<(facts.totalLength+2)) {testPhrase+="-";}

        //Append extra characters for added information early on:
        for(int i = 0; i<facts.charBounds[lookup[facts.charPtr]];i++) {
            testPhrase += (char)(lookup[facts.charPtr]+97);
        }

        //Update space lower and upper bounds:
        int[] answer = guess(testPhrase, pw, true);
        if(answer[1] == 0) {
            facts.spaceBounds[0] = Math.max(facts.spaceBounds[0], center+1);
            facts.spaceBounds[2] = Math.max(facts.spaceBounds[2], center+3);
        } else if(answer[1] == 1) {
            facts.spaceBounds[1] = Math.min(facts.spaceBounds[1], center);
            facts.spaceBounds[2] = Math.max(facts.spaceBounds[2], center+1);
        } else {
            facts.spaceBounds[3] = Math.min(facts.spaceBounds[3], center);
            facts.spaceBounds[1] = Math.min(facts.spaceBounds[1], center-2);
        }
        int correctAmountChars = (answer[0] + answer[1]) - 2;
        facts.updateCharBounds(correctAmountChars);
        //System.out.println(Arrays.toString(facts.spaceBounds));
        if(facts.spaceBounds[0]==facts.spaceBounds[1]) {
            if(facts.spaceBounds[2]==facts.spaceBounds[3]) return;
            findSpaces(facts.spaceBounds[2] + ((facts.spaceBounds[3]-facts.spaceBounds[2])/3), facts, pw);
        } else {
            findSpaces((facts.spaceBounds[0]+facts.spaceBounds[1])/2, facts, pw);
        }
    }

    private class Facts {

        private static final String INITIAL_GUESS = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbccccccccccccccccccddddddddddddddddddffffffffffffffffffgggggggggggggggggghhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkllllllllllllllllllmmmmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnnnnooooooooooooooooooppppppppppppppppppqqqqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrssssssssssssssssssttttttttttttttttttuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzz";
        private final int totalLength;
        private final int[] spaceBounds;
        // Pre-filled with maximum bounds obtained from dictionary:
        private final int[] charBounds = new int[] {12, 9, 9, 9, 15, 9, 12, 9, 18, 6, 9, 12, 9, 12, 12, 9, 3, 12, 15, 9, 12, 6, 6, 3, 9, 6};
        private final int[] oddEvenUsed = new int[] {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
        private final int[] oddEvenPairScore = new int[26];
        private int charPtr;

        public Facts(int[] initialResult) {

            totalLength = initialResult[0] + initialResult[1];
            spaceBounds = new int[] {2, Math.min(totalLength - 2, 22), 4, Math.min(totalLength + 1, 43)};

            //Eliminate firsts
            charBounds[lookup[0]] = initialResult[1];
            //Adjust:
            for(int i = 1; i<charBounds.length; i++) {
                charBounds[lookup[i]] = Math.min(charBounds[lookup[i]], totalLength-initialResult[1]);
            }
            charPtr = 1;
        }

        private List<String> previousGuesses = new ArrayList<String>();
        private List<int[]> previousResults = new ArrayList<int[]>(); 
        public void storeInvalid(String phrase, int[] result) {
            previousGuesses.add(phrase);
            previousResults.add(result);
        }

        public boolean doneDiscovery() {
            if(charPtr<12) { //Always do at least N guesses (speeds up and slightly improves score)
                return false;
            }
            return true;
        }

        public void updateCharBounds(int correctAmountChars) {

            // Update the bounds we know for a certain character:
            int knownCharBounds = 0;
            charBounds[lookup[charPtr]] = correctAmountChars;
            for(int i = 0; i <= charPtr;i++) {
                knownCharBounds += charBounds[lookup[i]];
            }
            // Also update the ones we haven't checked yet, we might know something about them now:
            for(int i = charPtr+1; i<charBounds.length; i++) {
                charBounds[lookup[i]] = Math.min(charBounds[lookup[i]], totalLength-knownCharBounds);
            }
            charPtr++;
            while(charPtr < 26 && charBounds[lookup[charPtr]]==0) {
                charPtr++;
            }
        }

        public boolean partialMatches(String phrase) {

            //Try to match a partial phrase, we can't be too picky because we don't know what else is next
            int[] cUsed = new int[26];
            for(int i = 0; i<phrase.length(); i++) {
                cUsed[phrase.charAt(i)-97]++;
            }
            for(int i = 0; i<cUsed.length; i++) {

                //Only eliminate the phrases that definitely have wrong characters:
                if(cUsed[lookup[i]] > charBounds[lookup[i]]) {
                    return false;
                }
            }
            return true;
        }

        public boolean matches(String phrase) {

            // Try to match a complete phrase, we can now use all information:
            int[] cUsed = new int[26];
            for(int i = 0; i<phrase.length(); i++) {
                if(phrase.charAt(i)!=' ') {
                    cUsed[phrase.charAt(i)-97]++;
                }
            }

            for(int i = 0; i<cUsed.length; i++) {
                if(i < charPtr) {
                    if(cUsed[lookup[i]] != charBounds[lookup[i]]) {
                        return false;
                    }
                } else {
                    if(cUsed[lookup[i]] > charBounds[lookup[i]]) {
                        return false;
                    }
                }
            }

            //Check against what we know for odd/even
            for(int pair = 0; pair < 26;pair++) {
                String input = "";
                for(int i = 0; i<26;i++) {
                    if(oddEvenUsed[i] == pair) {
                        input += (char)(lookup[i]+97);
                    }
                }
                if(input.length() == 1) {
                    input += "-";
                }
                String testPhrase = "";
                for(int i = 0; i<=(totalLength+1)/2 ; i++) {
                    testPhrase += input;
                }

                int[] result = guess(testPhrase, phrase, false);
                if(result[1] != oddEvenPairScore[pair]) {
                    return false;
                }
            }

            //Check again previous guesses:
            for(int i = 0; i<previousGuesses.size();i++) {
                // If the input phrase is the correct phrase it should score the same against previous tries:
                int[] result = guess(previousGuesses.get(i), phrase, false);
                int[] expectedResult = previousResults.get(i);
                if(!Arrays.equals(expectedResult, result)) {
                    return false;
                }
            }
            return true;
        }
    }


    private List<String> createPassPhrases() throws Exception {
        BufferedReader reader = new BufferedReader(new FileReader(new File("pass.txt")));
        List<String> phrases = new ArrayList<String>();
        String input;
        while((input = reader.readLine()) != null) {
            phrases.add(input);
        }
        return phrases;
    }

    private Map<Integer, List<String>> createDictionary() throws Exception {
        BufferedReader reader = new BufferedReader(new FileReader(new File("words.txt")));
        Map<Integer, List<String>> wordMap = new HashMap<Integer, List<String>>();
        String input;
        while((input = reader.readLine()) != null) {
            List<String> words = wordMap.get(input.length());
            if(words == null) {
                words = new ArrayList<String>();
            }
            words.add(input);
            wordMap.put(input.length(), words);
        }
        return wordMap;
    }

}

আপনি ছেলেরা এত স্মার্ট।
রে

2
স্থান সন্ধানের সমান্তরালে চরিত্রের ফ্রিক্স গণনা করা একটি উজ্জ্বল ধারণা।
রে

1
আমি অবশ্যই বলব যে আমি এমনকি আপনার এমনকি / বিজোড় কৌশলটির চারপাশে আমার মাথা গুটিয়ে নেওয়া শুরু করতে পারি না, বিমূর্ত চিন্তাভাবনা বা বিপরীত প্রকৌশল দ্বারা নয়। অতিরিক্ত অনুমান গণনা না করে আপনি যেভাবে পাসওয়ার্ডের সাথে ম্যাচিং ফাংশনটি কল করেন তা আমিও বুঝতে পারি না। কিছুটা ব্যাখ্যা স্বাগত হবে।

12

জাভা - 18,708 অনুসন্ধান; 2.4 সেকেন্ড 11,077 অনুসন্ধান; 125 মিনিট

ন্যূনতম: 8, সর্বাধিক: 13, কার্যকর প্রশ্নাবলী: 10,095

আমি এই উপর দীর্ঘ পথ ব্যয়। : P: P

কোডটি http://pastebin.com/7n9a50NM এ উপলব্ধ

রেভ ১। Http://pastebin.com/PSXU2bga এ উপলব্ধ

রেভ 2. http://pastebin.com/gRJjpbbu এ উপলব্ধ

আমার দ্বিতীয় সংশোধন। আমি পুরস্কার জিততে 11 কে বাধা ফাটানোর আশা করছিলাম, তবে আমি এই জন্তুটিকে অনুকূলিত করার জন্য খুব বেশি সময় পেলাম।

এটি পূর্ববর্তী দুটি সংস্করণ থেকে সম্পূর্ণ পৃথক নীতিতে কাজ করে (এবং এটি চালাতে প্রায় 3,500 বার সময় নেয়)। সাধারণ নীতিটি হ'ল প্রার্থী তালিকাটি পরিচালনাযোগ্য আকারে (সাধারণত ২-৮ মিলিয়ন এর মধ্যে) হ্রাস করার জন্য স্থান এবং এমনকি / বিজোড় চরিত্র অনুসন্ধান করা এবং তারপরে সর্বাধিক বৈষম্য শক্তি (যার আউটপুট বিতরণ সর্বাধিক এনট্রোপি অর্জন করে) নিয়ে পুনরাবৃত্তি জিজ্ঞাসা করা।

গতি নয় স্মৃতি হ'ল মূল সীমাবদ্ধতা। আমার জাভা ভিএম আমাকে কিছু অস্পষ্ট কারণে (সম্ভবত উইন্ডোজ)) এর জন্য ১,২০০ এমবি এর চেয়ে বড় গাদা সংরক্ষণ করতে দেবে না, এবং এই সীমাটি ছাড়িয়ে না দেয় এমন সর্বোত্তম সম্ভাব্য সমাধানের জন্য আমি পরামিতিগুলি সুর করেছি। এটি আমাকে উদ্রেক করে যে সঠিক পরামিতিগুলির সাথে একটি সঠিক রান কার্যকরকরণের সময়টিতে কোনও অর্থবহ বৃদ্ধির সাথে 11 কে ভেঙে দেয়। আমার একটি নতুন কম্পিউটার দরকার : P: P

আমাকে কেবল যেটি উদ্রেক করে তা হ'ল এই বাস্তবায়নের 982 টি প্রশ্নের ব্যর্থতা "বৈধতা" প্রশ্ন। এই নিয়মটি সন্তুষ্ট করা ছাড়া তাদের আর কোনও উদ্দেশ্য নেই যে ওরাকলকে অবশ্যই একটি নির্দিষ্ট "আপনি এটি পেয়েছেন" মানটি ফিরিয়ে আনতে হবে, যদিও আমার বাস্তবায়নের ক্ষেত্রে 98.2% ক্ষেত্রে এই প্রশ্নের আগে যথাযথ উত্তরটি নিশ্চিতভাবে নির্ধারণ করা হয়েছিল। অন্যান্য সাব-১১ কে জমা দেওয়ার বেশিরভাগই ফিল্টারিং কৌশলগুলিতে নির্ভর করে যা পরীক্ষার্থীদের স্ট্রিংকে ক্যোয়ারী স্ট্রিং হিসাবে ব্যবহার করে এবং তাই একই শাস্তি ভোগ করে না।

এই কারণে, যদিও আমার অফিশিয়াল ক্যোয়ারী গণনা 11,077 (নেতাদের সংক্ষিপ্তসার, তাদের কোডের সাথে সঙ্গতিপূর্ণ, ট্রু-টু-স্পেস, ইত্যাদি প্রমাণিত হয়েছে), আমি সাহসের সাথে বলেছি যে আমার কোডটি 10,095 কার্যকর অনুসন্ধান করে, যার অর্থ কেবল 10,095 অনুসন্ধানগুলি 100% সুনিশ্চিততার সাথে সমস্ত পাস বাক্যাংশ নির্ধারণ করার জন্য প্রয়োজনীয়। আমি নিশ্চিত নই যে অন্য কোনও বাস্তবায়ন এর সাথে মেলে, তাই আমি এটিকে আমার প্রথম বিজয় বিবেচনা করব। ;)


জেডপিসি ঠিক আছে, অন্যান্য এন্ট্রিগুলি সেগুলিও ব্যবহার করছে। আমি মনে করি সবচেয়ে সাধারণ .
জিওবিটস

বর্তমান কোডটিতে একটি "বৈধকরণ" ক্যোয়ারী অন্তর্ভুক্ত নয়। আমি এখন একটি যুক্ত করব।
সিটিও

আমি রেভিউ আপডেট করেছি। 1, যা বৈধকরণ ক্যোয়ারী অন্তর্ভুক্ত। আশ্চর্যের বিষয় নয়, ক্যোয়ারির সংখ্যা আগের সংস্করণটির তুলনায় হুবহু এক হাজার বেশি।
COTO

1
ইহা খুব সুন্দর. আপনার জাভা তাই জাভা-ওয়াই এটি ব্যাথা করে। আমি এই সাইটে কোডটি দেখতে
অভ্যস্ত নই

হচ্ছে মহাকাব্য এবং উভয় জন্য +1"perpetually exhausting pool"
cjfaure

8

জাভা - মিনিট: 22, সর্বাধিক: 41, মোট: 28353, সময়: 4 সেকেন্ড

প্রোগ্রামটি 3 টি ধাপে পাসওয়ার্ডটি অনুমান করে:

  1. বাইনারি অনুসন্ধানের সাথে স্পেস পজিশনগুলি সন্ধান করুন
  2. 3 টি শব্দের মধ্যে সর্বাধিক ঘন অক্ষরের উপস্থিতি গণনা করুন
  3. উপরে জড়ো করা তথ্য ব্যবহার করে বাম থেকে শুরু করে শব্দগুলি সন্ধান করুন

এটি "খারাপ চরিত্রগুলি" এর একটি সেটও সন্ধান করে যা অনুসন্ধানে শূন্য ফলাফল দেয় এবং পাসফ্রেজে অন্য কোথাও রাখা "" ভাল চরিত্রগুলির "সেট।

ধারাবাহিকভাবে অনুমানের জন্য পাঠানো মানগুলির উদাহরণের নীচে আপনি তিনটি পদক্ষেপ দেখতে পারবেন:

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**  **  **  **  **  **  **  **  **  **  **  **  **  **  **  **  *
****    ****    ****    ****    ****    ****    ****    ****    *
********        ********        ********        ********        *
****************                ****************                *
********** ******** *********************************************
eeeeeeeeeee
eeeeeeeeeee eeeeee
iiiiiiiiiii
iiiiiiiiiii iiiiii
aaaaaaaaaaa
aaaaaaaaaaa aaaaaa
sssssssssss
sssssssssss ssssss
rrrrrrrrrrr
rrrrrrrrrrr rrrrrr
nnnnnnnnnnn
ttttttttttt
ooooooooooo
ooooooooooo oooooo
lllllllllll
a
facilitates 
facilitates w
facilitates wis
facilitates widows 
facilitates widows e
facilitates widows briefcase 

কোড:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;



public class Main5 {

    private static String CHARS = "eiasrntolcdupmghbyfvkwzxjq "; 
    private static String currentPassword;
    private static List<String> words;
    private static List<String> passphrases;

    private static char [] filters = {'e', 'i', 'a', 's', 'r', 'n', 't', 'o', 'l'};

    private static int maxLength;       

    public static void main(String[] args) throws IOException {

        long start = System.currentTimeMillis();
        passphrases = getFile("passphrases.txt");
        words = getFile("words.txt");
        maxLength = 0;
        for (String word : words) {
            if (word.length() > maxLength) {
                maxLength = word.length();
            }
        }

        int total = 0;
        int min = Integer.MAX_VALUE;
        int max = 0;
        for (String passphrase : passphrases) {
            currentPassword = passphrase;
            int tries = findPassword();
            if (tries > max) max = tries;
            if (tries < min) min = tries;
            total += tries;
        }
        long end = System.currentTimeMillis();
        System.out.println("Min : " + min);
        System.out.println("Max : " + max);
        System.out.println("Total : " + total);
        System.out.println("Time : " + (end - start) / 1000);
    }


    public static int findPassword() {

        /**************************************
         * STEP 1 : find the spaces positions *
         **************************************/
        int tries = 0;
        Map<String, int []> res = new HashMap<String, int[]>();
        long maxBits = (long) Math.log((maxLength * 3+2) * Math.exp(2));
        for (int bit = 0; bit < maxBits-2; bit++) {
            String sp = buildSpace(maxLength*3+2, bit);
            tries++;
            int [] ret = guess(sp);
            res.put(sp, ret);
        }
        List<String> candidates = new ArrayList<String>();
        List<String> unlikely = new ArrayList<String>();
        for (int x1 = 1; x1 < maxLength + 1; x1++) {
            for (int x2 = x1+2; x2 < Math.min(x1+maxLength+1, maxLength*3+2); x2++) {
                boolean ok = true;
                for (String key : res.keySet()) {
                    int [] ret = res.get(key);
                    if (key.charAt(x1) == ' ' && key.charAt(x2) == ' ') {
                        // ret[1] should be 2
                        if (ret[1] != 2) ok = false;
                    } else if (key.charAt(x1) == '*' && key.charAt(x2) == '*') {
                        // ret[1] should be 0
                        if (ret[1] != 0) ok = false;
                    } else if (key.charAt(x1) == ' ' || key.charAt(x2) == ' ') {
                        // ret[1] should be 1
                        if (ret[1] != 1) ok = false;
                    }
                }
                if (ok) {
                    String s = "";
                    for (int i = 0; i < maxLength*3+2; i++) {
                        s += i == x1 || i == x2 ? " " : "*";
                    }
                    // too short or too long words are unlikely to occur
                    if (x1 < 4 || x2 - x1 - 1 < 4 || x1 > 12 || x2 - x1 - 1 > 12) {
                        unlikely.add(s);
                    } else {
                        candidates.add(s);
                    }
                }
            }
        }
        candidates.addAll(unlikely);
        String correct = null;
        if (candidates.size() > 1) {

            for (int i = 0; i < candidates.size(); i++) {
                String cand = candidates.get(i);
                int [] ret = null;
                if (i < candidates.size() - 1) {
                    tries++;
                    ret = guess(cand);
                }
                if (i == candidates.size() - 1 || ret[1] == 2) {
                    correct = cand;
                    break;
                }
            }
        } else {
            correct = candidates.get(0);
        }
        int spaceIdx1 = correct.indexOf(' ');
        int spaceIdx2 = correct.lastIndexOf(' ');

        /********************************************
         * STEP 2 : count the most frequent letters *
         ********************************************/
        // test the filter characters in the first, second, last words
        List<int []> f = new ArrayList<int []>();
        for (int k = 0; k < filters.length; k++) {
            char filter = filters[k];
            String testE = "";
            for (int i = 0; i < spaceIdx1; i++) {
                testE += filter;
            }
            int tmpCount = 0;
            for (int [] tmp : f) {
                tmpCount += tmp[0];
            }
            int [] result;
            if (tmpCount == spaceIdx1) {
                // we can infer the result
                result = new int[] {1, 0};
            } else {
                tries++;
                result = guess(testE);
            }
            int [] count = {result[1], 0, 0};
            if (result[0] > 0) {
                // test the character in the second word
                testE += " ";
                for (int i = 0; i < spaceIdx2-spaceIdx1-1; i++) {
                    testE += filter;
                }                   
                tries++;
                result = guess(testE);
                count[1] = result[1] - count[0] - 1;
                if (testE.length() - count[0] - count[1] > 8) { // no word has more than 8 similar letters
                    count[2] = result[0]; 
                } else {
                    if (result[0] > 0) {
                        // test the character in the third word
                        testE += " ";
                        for (int i = 0; i < maxLength; i++) {
                            testE += filter;
                        }
                        tries++;
                        result = guess(testE);
                        count[2] = result[1] - count[0] - count[1] - 2;
                    }
                }
            }
            f.add(new int[] {count[0], count[1], count[2]});
        }

        /***********************************************
         * STEP 3 : find the words, starting from left *
         ***********************************************/
        String phrase = "", word = "";
        int numWord = 0;
        Set<Character> badChars = new HashSet<Character>();
        Set<Character> goodChars = new HashSet<Character>();
        while (true) {
            boolean found = false;
            int wordLength = -1; // unknown
            if (numWord == 0) wordLength = spaceIdx1;
            if (numWord == 1) wordLength = spaceIdx2-spaceIdx1-1;


            // compute counts
            List<Integer> counts = new ArrayList<Integer>();
            for (int [] tmp : f) {
                counts.add(tmp[numWord]);
            }
            // what characters should we test after?
            String toTest = whatNext(word, badChars, numWord == 2 ? goodChars : null,
                    wordLength, counts);
            // if the word is already found.. complete it, no need to call guess
            if (toTest.length() == 1 && !toTest.equals(" ")) {
                phrase += toTest;
                word += toTest;
                goodChars.remove(toTest.charAt(0));
                continue;
            }
            // try all possible letters             
            for (int i = 0; i < toTest.length(); i++) {
                int [] result = null;
                char c = toTest.charAt(i);
                if (badChars.contains(c)) continue;
                boolean sureGuess = c != ' ' && i == toTest.length() - 1;
                if (!sureGuess) {
                    // we call guess ; increment the number of tries
                    tries++;
                    result = guess(phrase + c);
                    // if the letter is not present, add it to the set of "bad" characters
                    if (result[0] == 0 && result[1] == phrase.length()) {                       
                        badChars.add(c);
                    }
                    // if the letter is present somewhere else, add it to the set of "good" characters
                    if (result[0] == 1 && result[1] == phrase.length()) {                       
                        goodChars.add(c);
                    }
                }
                if (sureGuess || result[1] == phrase.length()+1) {
                    goodChars.remove(c);
                    phrase += c;
                    word += c;
                    if (toTest.charAt(i) == ' ') {
                        word = "";
                        numWord++;
                    }
                    found = true;
                    break;
                }
            }
            if (!found) break;
        }
        if (!phrase.equals(currentPassword)) System.err.println(phrase);
        return tries;
    }

    public static int[] guess(String in) {
        int chars=0, positions=0;
        String pw = currentPassword; // set elsewhere, contains current pass
        for(int i=0;i<in.length()&&i<pw.length();i++){
            if(in.charAt(i)==pw.charAt(i))
                positions++;
        }
        if(positions == pw.length() && pw.length()==in.length())
            return new int[]{-1,positions};
        for(int i=0;i<in.length();i++){
            String c = String.valueOf(in.charAt(i));
            if(pw.contains(c)){
                pw = pw.replaceFirst(c, "");
                chars++;
            }
        }
        chars -= positions;
        return new int[]{chars,positions};
    }


    private static String buildSpace(int length, int bit) {
        String sp = "";
        for (int i = 0; i < length; i++) {
            if (((i >> bit) & 1) != 0) {
                sp += " ";
            } else {
                sp += "*";
            }
        }
        return sp;
    }

    public static String whatNext(String s, Set<Character> badChars, Set<Character> goodChars, int length, List<Integer> counts) {
        String ret = "";
        Map<Character, Integer> freq = new HashMap<Character, Integer>();
        for (char c : CHARS.toCharArray()) {
            if (badChars.contains(c)) continue;
            freq.put(c, 0);
        }
        for (String word : words) {
            if (word.startsWith(s) && (word.length() == length || length == -1)) {
                char c1 = word.equals(s) ? ' ' : word.charAt(s.length());
                if (badChars.contains(c1)) continue;

                boolean badWord = false;
                for (int j = 0; j < counts.size(); j++) {
                    int cpt = 0;
                    for (int i = 0; i < word.length(); i++) {
                        if (word.charAt(i) == filters[j]) cpt++;    
                    }
                    if (cpt != counts.get(j)) {
                        badWord = true;
                        break;
                    }
                }
                if (badWord) continue;
                String endWord = word.substring(s.length());

                for (char bad : badChars) {
                    if (endWord.indexOf(bad) != -1) {
                        badWord = true;
                        break;
                    }
                }
                if (badWord) continue;
                if (goodChars != null) {
                    for (char good : goodChars) {
                        if (endWord.indexOf(good) == -1) {
                            badWord = true;
                            break;
                        }
                    }
                }
                if (badWord) continue;
                freq.put(c1, freq.get(c1)+1);
            }
        }
        while (true) {
            char choice = 0;
            int best = 0;
            for (char c : CHARS.toCharArray()) {
                if (freq.containsKey(c) && freq.get(c) > best) {
                    best = freq.get(c);
                    choice = c;
                }
            }
            if (choice == 0) break;
            ret += choice;
            freq.remove(choice);
        }
        return ret;
    }



    public static List<String> getFile(String filename) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(filename));
        List<String> lines = new ArrayList<String>();
        String line = null;
        while ((line = reader.readLine()) != null) {
            lines.add(line);
        }
        reader.close();
        return lines;
    }
}

7

পাইথন 2.7 - 156821 অনুমান, 0.6 সেকেন্ড

আমি সর্বনিম্ন অনুমানের চেয়ে গতির দিকে গিয়েছিলাম, যদিও আমি অনুমান করি যে আমার অনুমানের সংখ্যা এখনও কম, উদাহরণস্বরূপ কোনও ডাইরেক্ট আপ আক্রমণ হবে। আমি পাসওয়ার্ডে অক্ষরের সংখ্যা গণনা করি না তবে ভুল জায়গায়, যেহেতু আমার পদ্ধতি এটি ব্যবহার করে না, তবে আপনি যদি মনে করেন এটি আমাকে একটি অন্যায় সুবিধা দেয়, আমি এটি প্রয়োগ করব। আমি কেবল একটি খালি অনুমানের স্ট্রিং দিয়ে শুরু করি এবং এতে একটি অক্ষর প্রত্যয় যুক্ত করি যা আমার অক্ষরের তালিকার উপরে বৃদ্ধি করে, 'চেক' এর ফলাফলটি পরীক্ষা করে দেখতে হয় যে সঠিক অক্ষরের সংখ্যা অনুমানের দৈর্ঘ্যের সমান কিনা। উদাহরণস্বরূপ, যদি পাসওয়ার্ডটি 'খারাপ' হত তবে আমি অনুমান করব:

A, B

একটি

এ বি সি ডি

আমি ইংরেজি বর্ণের ফ্রিকোয়েন্সি অনুসারে চিঠিগুলি বাছাই করার চেষ্টাও করেছি, যা অনুমানের সংখ্যার প্রায় 35% পাশাপাশি সময়কে ছাঁটাই করে দিয়েছে। আমি 0.82 সেকেন্ডের মধ্যে সমস্ত পাসওয়ার্ড ক্র্যাক করেছি। পরিসংখ্যান শেষে মুদ্রিত হয়।

import string
import time

class Checker():

    def __init__(self):
        #self.chars          = string.ascii_lowercase + ' '  #ascii letters + space
        self.baseChars     = "eiasrnt olcdupmghbyfvkwzxjq"  #ascii letters in order of frequency, space thrown in a reasonable location
        self.subfreqs      = {}

        self.chars         = "eiasrnt olcdupmghbyfvkwzxjq"
        self.subfreqs['a'] = "tnlrcsb dmipguvykwfzxehajoq"
        self.subfreqs['b'] = "leaiour sbytjdhmvcnwgfpkqxz"
        self.subfreqs['c'] = "oaehtik rulcysqgnpzdmvbfjwx"
        self.subfreqs['d'] = "eioarus ldygnmvhbjwfptckqxz"
        self.subfreqs['e'] = "rsndlat cmepxfvgwiyobuqhzjk"
        self.subfreqs['f'] = "ioefalu rtysbcdgnhkjmqpwvxz"
        self.subfreqs['g'] = "erailho usngymtdwbfpckjqvxz"
        self.subfreqs['h'] = "eaoiurt ylmnsfdhwcbpgkjqvxz"
        self.subfreqs['i'] = "notscle amvdgrfzpbkuxqihjwy"
        self.subfreqs['j'] = "ueaoicb dgfhkjmlnqpsrtwvyxz"
        self.subfreqs['k'] = "eisalny owmurfptbhkcdjgqvxz"
        self.subfreqs['l'] = "eialyou stdmkvpfcngbhrwjqxz"
        self.subfreqs['m'] = "eaiopub msnylchfrwqvdgkjtxz"
        self.subfreqs['n'] = "gtesdia conufkvylhbmjrqpwzx"
        self.subfreqs['o'] = "nrumlts opcwdvgibafkeyxzhjq"
        self.subfreqs['p'] = "eroalih ptusybfgkdmwjcnqvxz"
        self.subfreqs['q'] = "uacbedg fihkjmlonqpsrtwvyxz"
        self.subfreqs['r'] = "eaiostm rdyuncgbplkvfhwjqzx"
        self.subfreqs['s'] = "tesihoc upalmnykwqfbdgrvjxz"
        self.subfreqs['t'] = "iearohs tyulcnwmfzbpdgvkjqx"
        self.subfreqs['u'] = "srnltmc adiebpgfozkxvyqhwuj"
        self.subfreqs['v'] = "eiaouyr bhpzcdgfkjmlnqstwvx"
        self.subfreqs['w'] = "aieonhs rlbcmpdkyfgutwvjqxz"
        self.subfreqs['x'] = "pitcaeh oyulgfbdkjmnqsrwvxz"
        self.subfreqs['y'] = "sepminl acortdwgubfkzhjqvyx"
        self.subfreqs['z'] = "eaizoly usrkmwxcbdgfhjnqptv"


        self.numGuessesTot  = 0
        self.numGuessesCur  = 0
        self.currentIndex   = 0
        self.passwords      = [line.strip() for line in open('passwords.txt', 'r').readlines()]
        self.currentPass    = self.passwords[self.currentIndex]
        self.numPasswords   = len(self.passwords)
        self.mostGuesses    = (0,   '')
        self.leastGuesses   = (1e9, '')

    def check(self, guess):
        self.numGuessesTot += 1
        self.numGuessesCur += 1
        numInPass  = 0
        numCorrect = 0
        lenPass    = len(self.currentPass)
        lenGuess   = len(guess)

        minLength  = min(lenPass, lenGuess)

        for i in range(minLength):
            if guess[i] == self.currentPass[i]:
                numCorrect += 1

        if numCorrect == len(self.currentPass):
            return -1, -1

        # numInPass is not calculated, as I don't use it
        return numInPass, numCorrect

    def nextPass(self):

        if self.numGuessesCur < self.leastGuesses[0]:
            self.leastGuesses = (self.numGuessesCur, self.currentPass)
        if self.numGuessesCur > self.mostGuesses[0]:
            self.mostGuesses  = (self.numGuessesCur, self.currentPass)

        self.numGuessesCur = 0
        self.currentIndex += 1

        if self.currentIndex < self.numPasswords:
            self.currentPass = self.passwords[self.currentIndex]

    def main(self):

        t0 = time.time()

        while self.currentIndex < self.numPasswords:
            guess = ''
            result = (0, 0)
            while result[0] is not -1:
                i = 0
                while i < len(self.chars) and result[1] < len(guess)+1 and result[1] is not -1:
                    result = self.check(guess + self.chars[i])

                    i += 1
                guess += self.chars[i-1]

                if self.chars[i-1] == " ":
                    self.chars = self.baseChars
                    i = 0
                else:
                    self.chars = self.subfreqs[self.chars[i-1]]
                    i = 0
            if result[0] == -1:
                #print self.currentIndex, self.currentPass
                self.nextPass()    

        elapsedTime = time.time() - t0
        print "  Total number of guesses: {}".format(self.numGuessesTot)
        print "  Avg number of guesses:   {}".format(self.numGuessesTot/self.numPasswords)
        print "  Least number of guesses: {} -> {}".format(self.leastGuesses[0], self.leastGuesses[1])
        print "  Most number of guesses:  {} -> {}".format(self.mostGuesses[0],  self.mostGuesses[1])
        print "  Total time:              {} seconds".format(elapsedTime)

if __name__ == "__main__":
    checker = Checker()
    checker.main()

সম্পাদনা: পরীক্ষার পূর্ববর্তী পুনরাবৃত্তির দুটি লুপ থেকে একটি বিপথগামী +1 এবং -1 সরিয়েছে, স্বতন্ত্র পাসওয়ার্ডের জন্য কমপক্ষে অনুমান এবং বেশিরভাগ অনুমানের জন্য অতিরিক্ত পরিসংখ্যানও যুক্ত করেছে।

EDIT2: প্রতি চিঠিতে সর্বাধিক সাধারণ 'পরবর্তী' চিঠির জন্য অনুসন্ধান সারণী যুক্ত করা হয়েছে। দুর্দান্ত গতি এবং অনুমানের সংখ্যা হ্রাস পেয়েছে


2
খুব দ্রুত, এটি অবশ্যই অনুমানের একগুচ্ছ ব্যবহার করে। আপনি সাধারণ ইংরেজির চেয়ে ডিক ফাইলের লেটার ফ্রিকোয়েন্সি ব্যবহার করে কিছুটা উন্নতি করতে সক্ষম হতে পারেন।
জিওবিটস

@ জিওবিটস বাগগুলি স্থির করেছেন, আমার পূর্ববর্তী পরীক্ষার পুনরাবৃত্তিগুলি থেকে উভয়ই নেক্সটপাস () এফ স্টেটমেন্টে একটি -1 এবং মূল লুপের লুপে একটি +1 ছিল। এখন প্রতিটি পাসওয়ার্ড কপি করে প্রিন্ট আউট একবার যদি আপনি লাইন 65 রাখা।
stokastic

7

সি ++ - 11383 10989 ম্যাচ!

হালনাগাদ

স্থির মেমরি ফাঁস, এবং পৃথক শব্দ অভিধানের মাপ হ্রাস করার জন্য আরও 1 টি চেষ্টা সরানো। আমার ম্যাক প্রোতে প্রায় 50 মিনিট সময় লাগে। আপডেটেড কোডটি গিথুবে রয়েছে।


আমি বাক্যাংশটি মিলে যাওয়ার কৌশলটিতে চলে এসে কোডটি পুনরায় তৈরি করেছি এবং এটি গিথুব https://github.com/snjyjn/mastermind এ আপডেট করেছি

বাক্যাংশ ভিত্তিক মিলের সাথে আমরা 11383 টি প্রচেষ্টাতে নেমে গেছি! গণনার ক্ষেত্রে এটি ব্যয়বহুল! আমিও কোড স্ট্রাকচার পছন্দ করি না! এবং এটি এখনও অন্যদের থেকে পিছনে রয়েছে :-(

আমি এটি এইভাবে করছি:

  1. উচ্চারণের দৈর্ঘ্য পরিমাপ করুন - সমস্ত 26 টি অক্ষরের সর্বাধিক বার (সর্বোচ্চ = 3 * ম্যাক্সওয়ার্ডেন + 2) এবং 2 স্পেস সহ স্ট্রিং ব্যবহার করুন। অভিধানে প্রথম অর্থাত্ সর্বোচ্চ অক্ষরগুলি হ'ল ই
  2. শূন্যস্থানগুলি সনাক্ত করতে বাইনারি চালনী ধরণের কৌশল ব্যবহার করুন - কয়েকটি সংখ্যক প্রচেষ্টা করুন এবং সম্ভাব্য জোড়াগুলি চিহ্নিত করুন। একটি জোড় হ্রাস করতে নির্দিষ্ট পরীক্ষার স্ট্রিং তৈরি করুন।
  3. সমান্তরালভাবে, বাক্যাংশটি সম্পর্কে আরও তথ্য পেতে 'নিক্ষিপ্ত' পরীক্ষার স্ট্রিং যুক্ত করুন। বর্তমান কৌশলটি নিম্নরূপ:

    ক। অভিধানে তাদের ফ্রিকোয়েন্সি অনুসারে অক্ষরগুলি ব্যবহার করুন।

    B ইংরেজী বর্ণমালার দ্বিতীয় অক্ষর. আমরা ইতিমধ্যে সবচেয়ে ঘন ঘন জন্য গণনা জানি

    গ। 1 ম পরীক্ষার স্ট্রিং = পরবর্তী 5 টি অক্ষর। এটি আমাদের বাক্যাংশে এই অক্ষরগুলির গণনা দেয়।

    ঘ। পরের 3 পরীক্ষার স্ট্রিং = প্রথম 5 টি অক্ষর, প্রথম 1 চর ছাড়াও 4 টি প্রচেষ্টায় মোট 20 টি অক্ষর coveringেকে দেয়। এটি আমাদের শেষ 5 টি অক্ষরের জন্য গণনা দেয়। 0 টি গণনা সহ সেটগুলি অভিধানের আকার হ্রাস করার জন্য দুর্দান্ত!

    ঙ। আগের পরীক্ষার জন্য এখন সর্বনিম্ন, শূন্য-নাগনের সংখ্যা ছিল, স্ট্রিংটিকে 2 তে বিভক্ত করুন এবং পরীক্ষার জন্য 1 ব্যবহার করুন। ফলস্বরূপ গণনাটি অন্যান্য বিভাজন সম্পর্কেও আমাদের জানায়।

    চ। অক্ষর (0-ভিত্তিক) দিয়ে পরীক্ষা পুনরাবৃত্তি করুন,

       1,6,11,16,21
       2,7,12,17,22
       3,8,13,18,23
       4,9,14,19,24
       এটি আমাদের 5,10,15,20,25 দেওয়া উচিত
g. After this, the next set of test strings are all 1 character long.
   though we dont expect to get so many tries!
  1. শূন্যস্থানগুলি চিহ্নিত হয়ে গেলে অভিধানের আকার হ্রাস করতে এখন পর্যন্ত সীমাবদ্ধতাগুলি ব্যবহার করুন (এই প্রচেষ্টাগুলিতে যতগুলি পরীক্ষা করা যেতে পারে)। এছাড়াও প্রতিটি শব্দের জন্য 3 টি উপ অভিধান তৈরি করুন।

  2. এখন প্রতিটি শব্দের জন্য কিছু অনুমান করুন এবং এটি পরীক্ষা করুন।
    পৃথক অভিধানের আকারগুলি হ্রাস করতে এই ফলাফলগুলি ব্যবহার করুন।
    এটিকে পরীক্ষার অক্ষরগুলির সাথে (দৈর্ঘ্যের পরে) সজ্জিত করুন বাক্যাংশটিতে আরও বাধা পেতে! আমি চূড়ান্ত সংস্করণে 3 অনুমান ব্যবহার করেছি - 1 শব্দের জন্য 2, এবং শব্দ 2 এর জন্য 1

  3. এটি অভিধানকে একটি পরিচালনাযোগ্য আকারে নিয়ে আসে। একটি শব্দগুচ্ছ অভিধান তৈরি করতে পূর্বের মতো সমস্ত প্রতিবন্ধকতা প্রয়োগ করে একটি ক্রস পণ্য সম্পাদন করুন।

  4. অনুমানের একটি ধারাবাহিকের মাধ্যমে শব্দগুচ্ছ অভিধানটি সমাধান করুন - এবার উভয় অবস্থান এবং চরিত্রের মিলের তথ্য ব্যবহার করে।

  5. এই পদ্ধতিটি আমাদের 11383 টি প্রচেষ্টার আওতায় নিয়েছে:

    ম্যাচারের পরিসংখ্যান
    ------------------
    দৈর্ঘ্য: 1000
    স্পেসস: 6375
    শব্দ 1: 1996
    শব্দ 2: 999
    বাক্যাংশ: 1013
    মোট: 11383

    অভিধান পরিসংখ্যান
    শব্দ 06517
    শব্দ 1 780 221 92
    শব্দ 2 791 233
    শব্দ 3 772
    বাক্যাংশ 186 20 4 2

    সমাধানের সময়: আমার ম্যাকবুক প্রোতে 20 মিনিট।

পূর্ববর্তী পোস্ট

আমি কোডটি সাফ করে দিয়েছি এবং https://github.com/snjyjn/mastermind এ আপলোড করেছি প্রক্রিয়াটিতে, আমি এটিকে উন্নত করেছি, এবং আরও একবার চেষ্টা করার চেষ্টা করেছি। আমি গতকাল যা করেছি তার থেকে 1 টি বড় পার্থক্য:

অভিধানে 1 এবং 2 শব্দের জন্য উচ্চ ফ্রিকোয়েন্সি অক্ষরের উপর ভিত্তি করে অক্ষরগুলির জন্য পৃথক অনুমানের স্বতন্ত্র সরানো হয়েছে এবং পরিবর্তে আমি সেই অবস্থানের জন্য সর্বোচ্চ ফ্রিকোয়েন্সি অক্ষরের উপর ভিত্তি করে একটি স্ট্রিং ব্যবহার করি।

পরিসংখ্যান এখন চেহারা:

স্পেসস: 6862
শব্দ 1: 5960
শব্দ 2: 5907
শব্দ 3: 2953
মোট: 21682

আসল পোস্ট

'উত্তরের' জন্য ক্ষমাপ্রার্থী, তবে আমি কেবল একটি অ্যাকাউন্ট তৈরি করেছি এবং একটি মন্তব্য যুক্ত করার মতো যথেষ্ট খ্যাতি নেই।

আমার কাছে একটি সি ++ প্রোগ্রাম রয়েছে, যা প্রায় 6.5 সেকেন্ড এবং 24107 ম্যাচের চেষ্টা করে। এটি সি ++ এর প্রায় 1400 লাইন। আমি কোডের গুণমান সম্পর্কে সন্তুষ্ট নই এবং অন্য কোনও দিন বা এটির আগে এটি পরিষ্কার করব। তবে সম্প্রদায়ের স্বার্থে এবং আলোচনায় অবদান রাখার জন্য, আমি এটাই করি:

  • অভিধানটি পড়ুন, এ সম্পর্কে কিছু প্রাথমিক তথ্য পান - ন্যূনতম / সর্বাধিক শব্দের দৈর্ঘ্য, অক্ষরের ফ্রিকোয়েন্সি ইত্যাদি

  • প্রথমে স্পেস শনাক্ত করুন - এটিতে 2 টি অর্ধ রয়েছে, প্রথমটি এমন একটি প্রশ্নের একটি সেট যা স্পেসকে বিভাজন অব্যাহত রাখে (এক সি সি চফুইনের অনুরূপ):

        ********
    **** ****
  ** ** ** **
 - * * * * * * * *

এটি ঠিক সঠিক নয়, যেহেতু আমি ন্যূনতম / সর্বাধিক শব্দের দৈর্ঘ্য ব্যবহার করি এবং আমি প্রতিটি পর্যায়ে ম্যাচ গণনাগুলি ব্যবহার করি তবে আপনি ধারণাটি পেয়ে যান। এই মুহুর্তে, 2 টি স্পেস পাওয়ার জন্য এখনও পর্যাপ্ত তথ্য নেই, তবে আমার কাছে এটি সংখ্যার কম সংখ্যায় হ্রাস করার পর্যাপ্ত পরিমাণ রয়েছে। এই সংমিশ্রণগুলি থেকে, আমি কয়েকটি নির্দিষ্ট প্রশ্ন তৈরি করতে পারি, এটি এটিকে 1 টি সংমিশ্রণে সংকুচিত করবে।

  • প্রথম শব্দ - একটি উপ-অভিধান পান, যার ডান দৈর্ঘ্যের শব্দ রয়েছে। উপ-অভিধানের নিজস্ব পরিসংখ্যান রয়েছে। সর্বাধিক ঘন অক্ষরের সাথে কয়েকটি অনুমান করুন, যাতে আপনি শব্দটিতে এই অক্ষরগুলির একটি সংখ্যা পান। এই তথ্যক্রমের ভিত্তিতে অভিধানটি আবার হ্রাস করুন। একটি অনুমান শব্দ তৈরি করুন, যার মধ্যে সর্বাধিক ভিন্ন অক্ষর রয়েছে এবং এটি ব্যবহার করুন। প্রতিটি প্রতিক্রিয়া আমাদের অভিধানের হ্রাস ঘটায় যতক্ষণ না আমাদের সঠিক মিল হয় বা অভিধানের আকার 1 হয়।

  • দ্বিতীয় শব্দ - প্রথম শব্দের অনুরূপ

  • তৃতীয় শব্দ - এটি অন্যান্য 2 থেকে সবচেয়ে পৃথক We এটির জন্য আমাদের কাছে আকারের তথ্য নেই, তবে আমাদের আগের সমস্ত প্রশ্ন রয়েছে (যা আমরা রেখেছি)। এই প্রশ্নগুলি আপনাকে অভিধান হ্রাস করতে দেয়। যুক্তিটি এর লাইনে রয়েছে:

 - ক্যোয়ারী এবি 1 টির একটি মিল গণনা ফিরিয়ে দিয়েছে
 - 1 এবং 2 শব্দটির বি বা সি নেই or
 - এটি স্পষ্ট যে খ বা সি 3 শব্দের অংশ হতে পারে না

সর্বাধিক বিচিত্র অক্ষরের সাথে অনুমান করার জন্য হ্রাসকৃত অভিধানটি ব্যবহার করুন এবং অভিধানটি আকার 1 পর্যন্ত কমিয়ে অবিরত করুন (শব্দ 1 এবং 2 হিসাবে)।

পরিসংখ্যানগুলি দেখতে দেখতে:

    স্থান সন্ধান: 7053
    শব্দ 1 অক্ষর: 2502
    শব্দ 1 শব্দ: 3864
    শব্দ 2 অক্ষর: 2530
    শব্দ 2 শব্দ: 3874
    শব্দ 3 অক্ষর: 2781
    শব্দ 3 শব্দ: 1503
    মোট: 24107

আসলে আপনি একক ক্যোয়ারির সাথে মোট দৈর্ঘ্য জানতে পারবেন।
রায়

ধন্যবাদ @ রায় আমি শেষ পর্যন্ত তা করেছি, কিন্তু সমস্যার মধ্য দিয়ে আমার প্রথম পাসে নয়। আমি স্রেফ আমার মূল পোস্টটি সম্পাদনা করিনি।
সঞ্জয় জৈন

6

যান - মোট: 29546

কিছু অপ্টিমাইজেশান সহ অন্যদের মতো।

  1. পরীক্ষার মাধ্যমে মোট দৈর্ঘ্য পান AAAAAAAABBBBBBBBCCCCCCCC...ZZZZZZZZ
  2. উভয় প্রান্ত থেকে ফাঁকা স্থান সরিয়ে তিনটি শব্দের প্রকৃত দৈর্ঘ্য নির্ধারণ করুন।
  3. প্রতিটি শব্দের কয়েকটি সাধারণ চিঠির চিঠির মাধ্যমে ফিল্টার করুন।
  4. স্ট্রিং পরীক্ষা করে এবং একই ফলাফল সরবরাহ না করে এমন অন্যান্য প্রার্থীদের অপসারণ করে প্রার্থীদের সেট হ্রাস করুন। বিজয়ী না পাওয়া পর্যন্ত পুনরাবৃত্তি করুন।

এটি বিশেষভাবে দ্রুত হয় না।

package main

import (
    "bytes"
    "fmt"
    "strings"
)

var totalGuesses = 0
var currentGuesses = 0

func main() {
    for i, password := range passphrases {
        currentGuesses = 0
        fmt.Println("#", i)
        currentPassword = password
        GuessPassword()
    }
    fmt.Println(totalGuesses)
}

func GuessPassword() {
    length := GetLength()
    first, second, third := GetWordSizes(length)

    firstWords := GetWordsOfLength(first, "")
    secondWords := GetWordsOfLength(second, strings.Repeat(".", first+1))
    thirdWords := GetWordsOfLength(third, strings.Repeat(".", first+second+2))
    //tells us number of unique letters in solution. As good as any for an initial pruning mechanism.
    RecordGuess("abcdefghijklmnopqrstuvwxyz")
    candidates := []string{}
    for _, a := range firstWords {
        for _, b := range secondWords {
            for _, c := range thirdWords {
                candidate := a + " " + b + " " + c
                if MatchesLastGuess(candidate) {
                    candidates = append(candidates, candidate)
                }
            }
        }
    }

    for {
        //fmt.Println(len(candidates))
        RecordGuess(candidates[0])
        if lastExist == -1 {
            fmt.Println(lastGuess, currentGuesses)
            return
        }
        candidates = Prune(candidates[1:])
    }
}

var lastGuess string
var lastExist, lastExact int

func RecordGuess(g string) {
    a, b := MakeGuess(g)
    lastGuess = g
    lastExist = a
    lastExact = b
}
func Prune(candidates []string) []string {
    surviving := []string{}
    for _, x := range candidates {
        if MatchesLastGuess(x) {
            surviving = append(surviving, x)
        }
    }
    return surviving
}
func MatchesLastGuess(candidate string) bool {
    a, b := Compare(candidate, lastGuess)
    return a == lastExist && b == lastExact
}

func GetWordsOfLength(i int, prefix string) []string {
    candidates := []string{}
    guess := prefix + strings.Repeat("e", i)
    _, es := MakeGuess(guess)
    guess = prefix + strings.Repeat("a", i)
    _, as := MakeGuess(guess)
    guess = prefix + strings.Repeat("i", i)
    _, is := MakeGuess(guess)
    guess = prefix + strings.Repeat("s", i)
    _, ss := MakeGuess(guess)
    guess = prefix + strings.Repeat("r", i)
    _, ts := MakeGuess(guess)
    for _, x := range allWords {
        if len(x) == i && strings.Count(x, "e") == es &&
            strings.Count(x, "a") == as &&
            strings.Count(x, "i") == is &&
            strings.Count(x, "r") == ts &&
            strings.Count(x, "s") == ss {
            candidates = append(candidates, x)
        }
    }
    return candidates
}

func GetLength() int {
    all := "  "
    for i := 'a'; i <= 'z'; i++ {
        all = all + strings.Repeat(string(i), 8)
    }
    a, b := MakeGuess(all)
    return a + b
}

func GetWordSizes(length int) (first, second, third int) {
    first = 0
    second = 0
    third = 0
    guess := bytes.Repeat([]byte{'.'}, length)
    left := 1
    right := length - 2
    for {
        guess[left] = ' '
        guess[right] = ' '
        _, exact := MakeGuess(string(guess))
        guess[left] = '.'
        guess[right] = '.'
        if exact == 0 {
            left++
            right--
        } else if exact == 1 {
            break
        } else if exact == 2 {
            first = left
            second = right - first - 1
            third = length - first - second - 2
            return
        }
    }
    //one end is decided, the other is not
    //move right in to see
    right--
    guess[left] = ' '
    guess[right] = ' '
    _, exact := MakeGuess(string(guess))
    guess[left] = '.'
    guess[right] = '.'
    if exact == 2 {
        //match was on left. We got lucky and found other match too!
        first = left
        second = right - first - 1
        third = length - first - second - 2
        return
    } else if exact == 0 {
        //match was on right, but we lost it.
        //keep going on left
        right++
        left++
        guess[right] = ' '
        for {
            guess[left] = ' '
            _, exact = MakeGuess(string(guess))

            guess[left] = '.'
            if exact == 2 {
                first = left
                second = right - first - 1
                third = length - first - second - 2
                return
            }
            left++
        }
    } else if exact == 1 {
        //exact == 1. Match was on left and still is. Keep going on right
        right--
        guess[left] = ' '
        for {
            guess[right] = ' '
            _, exact = MakeGuess(string(guess))

            guess[right] = '.'
            if exact == 2 {
                first = left
                second = right - first - 1
                third = length - first - second - 2
                return
            }
            right--
        }
    }
    return first, second, third
}

var currentPassword string

func MakeGuess(guess string) (exist, exact int) {
    totalGuesses++
    currentGuesses++
    return Compare(currentPassword, guess)
}

func Compare(target, guess string) (exist, exact int) {

    if guess == target {
        return -1, len(target)
    }
    exist = 0
    exact = 0
    for i := 0; i < len(target) && i < len(guess); i++ {
        if target[i] == guess[i] {
            exact++
        }
    }
    for i := 0; i < len(guess); i++ {
        if strings.IndexByte(target, guess[i]) != -1 {
            exist++
            target = strings.Replace(target, string(guess[i]), "", 1)
        }
    }
    exist -= exact
    return
}

আমি এই কোডটি সংকলন করতে পারি না। সংকলকটি তা বলেছে passphasesএবং allWordsএটি অপরিজ্ঞাত।
রায়

আপনার এই দুটি ফাইলের দরকার হবে: gist.github.com/captncraig/a136d0b9819d0ea948e6
ক্যাপচার্যাগ

6

জাভা: 58,233

(রেফারেন্স প্রোগ্রাম)

প্রত্যেককে বীট করার জন্য একটি সহজ বট। একটি অক্ষর গণনা প্রতিষ্ঠায় এটি প্রতিটি বাক্যাংশের জন্য প্রাথমিক 26 অনুমান ব্যবহার করে। তারপরে এটি এমন সমস্ত শব্দ মুছে ফেলে যা বাক্যে পাওয়া যায় না এমন অক্ষর ধারণ করে।

তারপরে বাকী শব্দের উপর একটি বিশাল ও (এন 3 ) লুপ আসে । প্রথমে এটি প্রতিটি পরীক্ষার্থীর বাক্যাংশটি পরীক্ষা করে এটি দেখার জন্য এটি কোনও এনগ্রাম। যদি তাই হয় তবে এটি এটি অনুমান করে, ফলাফলগুলি উপেক্ষা করে নিখুঁত মিল না থাকলে। আমি এ পর্যন্ত কোনও প্রদত্ত বাক্যাংশের জন্য এটি 28-510 অনুমানের মধ্যে ব্যবহার করতে দেখেছি।

এটি ধীর গতির এবং এটি প্রাথমিকভাবে 26 টি অনুমান থেকে সরাসরি কতগুলি শব্দের অপসারণ করা যায় তার উপর পুরোপুরি নির্ভর করে। বেশিরভাগ সময় এটি লুপ শেষ করতে 1000-4000 শব্দের মধ্যে চলে যায়। এখনই এটি কোথাও প্রায় 14 ঘন্টা চলছে, 180 ডলার / বাক্যাংশের হারে। আমি অনুমান করি এটি শেষ হতে 50 ঘন্টা সময় লাগবে, এবং সেই সময় স্কোরটি আপডেট করবে। এর চেয়ে আপনার সম্ভবত বুদ্ধিমান বা আরও বেশি কিছু প্রস্তুত করা উচিত ।

(আপডেট) শেষ পর্যন্ত এটি 60 কে অনুমানের অধীনে শেষ হয়েছে।

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;

public class Mastermind {

    String currentPassword;
    String[] tests;
    HashSet<String> dict;
    ArrayList<HashSet<String>> hasLetter;
    int maxLength = 0;
    int totalGuesses;

    public static void main(String[] args) {
        Mastermind master = new Mastermind();
        master.loadDict("dict-small");
        master.loadTests("passwords");
        System.out.println();
        master.run();
    }

    public Mastermind(){
        totalGuesses = 0;
        dict = new HashSet<String>();
        hasLetter = new ArrayList<HashSet<String>>(26);
        for(int i=0;i<26;i++)
            hasLetter.add(new HashSet<String>());
    }

    int run(){
        long start = System.currentTimeMillis();
        for(int i=0;i<tests.length;i++){
            long wordStart = System.currentTimeMillis();
            currentPassword = tests[i];
            int guesses = test();
            if(guesses < 0){
                System.out.println("Failed!");
                System.exit(0);
            }
            totalGuesses += guesses;
            long time = System.currentTimeMillis() - wordStart;
            System.out.println((i+1) + " found! " + guesses + " guesses, " + (time/1000) + "s ("+ ((System.currentTimeMillis()-start)/1000) +" total) : " + tests[i]);
        }
        System.out.println("\nTotal for " + tests.length + " tests: " + totalGuesses + " guesses, " + ((System.currentTimeMillis()-start)/1000) + " seconds total");
        return totalGuesses;
    }

    int[] guess(String in){
        int chars=0, positions=0;
        String pw = currentPassword;
        for(int i=0;i<in.length()&&i<pw.length();i++){
            if(in.charAt(i)==pw.charAt(i))
                positions++;
        }
        if(positions == pw.length() && pw.length()==in.length())
            return new int[]{-1,positions};
        for(int i=0;i<in.length();i++){
            String c = String.valueOf(in.charAt(i));
            if(pw.contains(c)){
                pw = pw.replaceFirst(c, "");
                chars++;
            }
        }
        chars -= positions;
        return new int[]{chars,positions};
    }

    int test(){
        int guesses = 0;
        HashSet<String> words = new HashSet<String>();
        words.addAll(dict);
        int[] counts = new int[26];
        for(int i=0;i<counts.length;i++){
            char[] chars = new char[maxLength];
            Arrays.fill(chars, (char)(i+97));
            int[] result = guess(new String(chars));
            counts[i] = result[0] + result[1];
            guesses++;
        }

        int length = 2;
        for(int i=0;i<counts.length;i++){
            length += counts[i];
            if(counts[i]==0)
                words.removeAll(hasLetter.get(i));
        }
        System.out.println(words.size() + ", " + Math.pow(words.size(),3));
        for(String a : words){
            for(String b : words){
                for(String c : words){
                    String check = a + " " + b + " " + c;
                    if(check.length() != length)
                        continue;
                    int[] letters = new int[26]; 
                    for(int i=0;i<check.length();i++){
                        if(check.charAt(i)!=' ')
                            letters[check.charAt(i)-97]++;
                    }
                    int matches = 0;
                    for(int i=0;i<letters.length;i++)
                        if(letters[i] == counts[i])
                            matches+=letters[i];
                    if(matches == check.length()-2){
                        guesses++;
                        int[] result = guess(check);
                        System.out.println(check + " : " + result[0] +", " + result[1]);
                        if(result[0] < 0)
                            return guesses;
                    }
                }
            }
        }
        return -guesses;
    }

    int loadDict(String filename){
        try {
            BufferedReader br = new BufferedReader(new FileReader(filename));
            String line;
            while ((line = br.readLine()) != null){
                if(line.length()*3+2 > maxLength)
                    maxLength = line.length()*3+2;
                dict.add(line);
                for(int i=0;i<line.length();i++){
                    hasLetter.get(line.charAt(i)-97).add(line);
                }
            }
            br.close();
        } catch (Exception e){};
        System.out.println("Loaded " + dict.size() + " words.");
        return dict.size();
    }

    int loadTests(String filename){
        ArrayList<String> tests = new ArrayList<String>();
        try {
            BufferedReader br = new BufferedReader(new FileReader(filename));
            String line;
            while ((line = br.readLine()) != null)
                if(line.length()>0)
                    tests.add(line);
            br.close();
        } catch (Exception e){};
        this.tests = tests.toArray(new String[tests.size()]);
        System.out.println("Loaded " + this.tests.length + " tests.");
        return this.tests.length;
    }
}

পোস্ট: গতকাল। শিরোনাম অন্তর্ভুক্ত (এখনও চলমান)। আমাকে হাসিয়ে দিয়েছিল, +1
ব্রায়ান বোয়েচার

@ ইনস্টা এটি আসলেই। আমি মনে করি প্রায় 6-7 ঘন্টা এটি করা উচিত। আনুমানিক ~ 58k অনুমান।
Geobits

এটাকে এত দিন চালিয়ে দেওয়ার মতো যথেষ্ট ধৈর্য আমি করব না
বিটা ডিকায়

4

জাভা: 28,340 26,185

ন্যূনতম 15, সর্বোচ্চ 35, সময় 2.5

যেহেতু আমার বোকা বট শেষ পর্যন্ত চলমান শেষ করেছে, আমি কিছুটা দ্রুত দ্রুত জমা দিতে চেয়েছিলাম । এটি কয়েক সেকেন্ডের মধ্যে চলে তবে একটি ভাল স্কোর পায় (বেশিরভাগ বিজয়ী নয় <<)।

প্রথমে শব্দটির মোট দৈর্ঘ্য পেতে এটি বড় প্যাড স্ট্রিং ব্যবহার করে। তারপরে অন্যদের মতো শূন্যস্থান অনুসন্ধান করতে বাইনারি অনুসন্ধান করুন। এটি করার সময়, এটি একবারে চিঠিগুলি একবারে পরীক্ষা করা শুরু করে (পিভট অর্ডারে) যাতে এটি পুরো বাক্যাংশের চেয়ে কোনও অক্ষরের বেশি শব্দ ধারণ করে eliminate

শব্দের দৈর্ঘ্য একবার হয়ে গেলে এটি শব্দ তালিকার জন্য পছন্দগুলি সঙ্কুচিত করতে একটি বাইনারি হ্রাস পদক্ষেপ ব্যবহার করে। এটি বৃহত্তম তালিকা এবং একটি অক্ষর বেছে নেয় যা প্রায় অর্ধেক শব্দের মধ্যে থাকে। কোনটি অর্ধে ফেলে দিতে হবে তা নির্ধারণ করতে এটি চিঠির একটি শব্দ-দৈর্ঘ্যের প্যাড অনুমান করে। এটি অন্যান্য তালিকাগুলিতে শব্দগুলির থেকে মুক্তি পাওয়ার জন্য ফলাফলগুলিও ব্যবহার করে যাতে চিঠিটি খুব বেশি থাকে।

একবারে তালিকাগুলি কেবল অ্যানগ্রামগুলি নিয়ে আসে, এটি কাজ করে না। এই মুহুর্তে আমি কেবলমাত্র দুটি অবধি (বা অন্য শব্দগুলি না জানা থাকলে একটি) অবধি কেবল তাদের মাধ্যমে লুপ করব।

আমার কাছে যদি মোট চারটি শব্দের গণনা থাকে (দু'জন পরিচিত এবং একটি দুটি বিকল্পের সাথে), আমি হ্রাস এবং আনগ্রাম ইনস্টলসটি এড়িয়ে চলেছি এবং একটি সম্পূর্ণ বাক্যাংশ হিসাবে কেবলমাত্র বিকল্পগুলির একটি অনুমান করি। যদি এটি কাজ না করে, তবে এটি অন্যটি হতে হবে, তবে আমি একটি অনুমান 50% সময় সঞ্চয় করি।

এখানে প্রথম উদাহরণটি ক্র্যাক করা হচ্ছে তা দেখানো একটি উদাহরণ:

                                             aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbccccccccccccccccccccddddddddddddddddddddeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffgggggggggggggggggggghhhhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkkkllllllllllllllllllllmmmmmmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnnnnnnooooooooooooooooooooppppppppppppppppppppqqqqqqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrrssssssssssssssssssssttttttttttttttttttttuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzzzz
         ..................................................................oooooooooooooooooooo
                 ..................................................................tttttttttttttttttttt
             ..................................................................nnnnnnnnnnnnnnnnnnnn
           ..................................................................llllllllllllllllllll
            ..................................................................iiiiiiiiiiiiiiiiiiii
                    ..................................................................dddddddddddddddddddd
                 ..................................................................uuuuuuuuuuuuuuuuuuuu
                   ..................................................................ssssssssssssssssssss
                  ..................................................................yyyyyyyyyyyyyyyyyyyy
............rrrrrr
............ssssss
...................ttttttttt
............aaaaaa
...................aaaaaaaaa
............iiiiii
sssssssssss
...................lllllllll
............dddddd
............eeeeee
lllllllllll
ccccccccccc
...................ccccccccc
rrrrrrrrrrr
...................bbbbbbbbb
facilitates wisdom briefcase
facilitates widows briefcase

এবং অবশ্যই, কোড:

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Splitter {

    int crack(){
        int curGuesses = guesses;
        none = "";
        int[] lens = getLengths();
        List<Set<String>> words = new ArrayList<Set<String>>();
        for(int i=0;i<3;i++){
            words.add(getWordsOfLength(lens[i]));
            exclude[i] = "";

            for(int j=0;j<26;j++){
                if(pCounts[j]>=0)
                    removeWordsWithMoreThan(words.get(i), pivots.charAt(j), pCounts[j]);
            }
        }
        while(!checkSimple(words)){
            if(numWords(words)>4)
                reduce(words, lens);
            if(numWords(words)>4)
                findAnagrams(words, lens);
        }
        return guesses - curGuesses;
    }

    boolean checkSimple(List<Set<String>> words){
        int total = numWords(words);
        if(total - words.size() == 1){
            int big=0;
            for(int i=0;i<words.size();i++)
                if(words.get(i).size()>1)
                    big=i;
            String pass = getPhrase(words);
            if(guess(pass)[0]<0)
                return true;
            words.get(big).remove(pass.split(" ")[big]);
        }

        total = numWords(words);
        if(total==words.size()){
            String pass = getPhrase(words);
            if(guess(pass)[0]<0)
                return true;
        }
        return false;
    }

    boolean findAnagrams(List<Set<String>> words, int[] lens){
        String test;
        Set<String> out;
        for(int k=0;k<words.size();k++){
            if(words.get(k).size() < 8){
                String sorted = "";
                boolean anagram = true;
                for(String word : words.get(k)){
                    char[] chars = word.toCharArray();
                    Arrays.sort(chars);
                    String next = new String(chars);
                    if(sorted.length()>1 && !next.equals(sorted)){
                        anagram = false;
                        break;
                    }
                    sorted = next;
                }
                if(anagram){
                    test = "";
                    for(int i=0;i<k;i++){
                        for(int j=0;j<=lens[i];j++)
                            test += '.';
                    }                   
                    while(words.get(k).size()>(numWords(words)>4?1:2)){
                        out = new HashSet<String>();
                        for(String word : words.get(k)){
                            int correct = guess(test+word)[1];
                            if(correct == lens[k]){
                                words.set(k, new HashSet<String>());
                                words.get(k).add(word);
                                break;
                            }else{
                                out.add(word);
                                break;
                            }
                        }
                        words.get(k).removeAll(out);
                    }
                }
            }
        }
        return false;
    }

    int numWords(List<Set<String>> words){
        int total = 0;
        for(Set<String> set : words)
            total += set.size();
        return total;
    }

    String getPhrase(List<Set<String>> words){
        String out = "";
        for(Set<String> set : words)
            for(String word : set){
                out += word + " ";
                break;
            }
        return out.trim();
    }

    void reduce(List<Set<String>> words, int[] lens){
        int k = 0;
        for(int i=1;i<words.size();i++)
            if(words.get(i).size()>words.get(k).size())
                k=i;
        if(words.get(k).size()<2)
            return;

        char pivot = getPivot(words.get(k), exclude[k]);
        exclude[k] += pivot;
        String test = "";
        for(int i=0;i<k;i++){
            for(int j=0;j<=lens[i];j++)
                test += '.';
        }
        for(int i=0;i<lens[k];i++)
            test += pivot;
        int[] res = guess(test);

        Set<String> out = new HashSet<String>();
        for(String word : words.get(k)){
            int charCount=0;
            for(int i=0;i<word.length();i++)
                if(word.charAt(i)==pivot)
                    charCount++;
            if(charCount != res[1])
                out.add(word);
            if(res[1]==0 && charCount>0)
                out.add(word);
        }
        words.get(k).removeAll(out);

        if(lens[k]>2 && res[0]<lens[k]-res[1]){
            for(int l=0;l<words.size();l++)
                if(l!=k)
                    removeWordsWithMoreThan(words.get(l), pivot, res[0]);
        }
    }

    void removeWordsWithMoreThan(Set<String> words, char c, int num){
        Set<String> out = new HashSet<String>();
        for(String word : words){
            int count = 0;
            for(int i=0;i<word.length();i++)
                if(word.charAt(i)==c)
                    count++;
            if(count > num)
                out.add(word);
        }
        words.removeAll(out);
    }

    char getPivot(Set<String> words, String exclude){
        int[] count = new int[26];
        for(String word : words){
            for(int i=0;i<26;i++)
                if(word.indexOf((char)(i+'a'))>=0)
                    count[i]++;
        }
        double diff = 999;
        double pivotPoint = words.size()/1.64d;
        int pivot = 0;
        for(int i=0;i<26;i++){
            if(exclude.indexOf((char)(i+'a'))>=0)
                continue;
            if(Math.abs(count[i]-pivotPoint)<diff){
                diff = Math.abs(count[i]-pivotPoint);
                pivot = i;
            }
        }
        return (char)(pivot+'a');
    }

    Set<String> getWordsOfLength(int len){
        Set<String> words = new HashSet<String>();
        for(String word : dict)
            if(word.length()==len)
                words.add(word);
        return words;
    }

    int[] pCounts;
    int[] getLengths(){
        String test = "";
        int pivot = 0;
        pCounts = new int[27];
        for(int i=0;i<27;i++)
            pCounts[i]=-1;
        for(int i=0;i<45;i++)
            test += ' ';
        for(int i=0;i<26;i++){
            for(int j=0;j<20;j++){
                test += (char)(i+'a');
            }
        }
        int[] res = guess(test);
        int len = res[0]+res[1];
        int[] lens = new int[3];

        int[] min = {1,3};
        int[] max = {len-4,len-2};
        int p = (int)((max[0]-min[0])/3+min[0]);
        while(lens[0] == 0){
            if(max[0]==min[0]){
                lens[0] = min[0];
                break;
            }
            String g = "", h = "";
            for(int i=0;i<=p;i++)
                g+=' ';
            if(pivot < pivots.length()){
                h += pad;
                for(int i=0;i<20;i++)
                    h += pivots.charAt(pivot);
            }
            res = guess(g+h);
            if(res[1]==0){
                min[0] = p+1;
                min[1] = max[0];
                pCounts[pivot] = g.length()>1?res[0]-2:res[0]-1; 
            }else if(res[1]==2){
                max[0] = p-2;
                max[1] = p;
                pCounts[pivot] = res[0]; 
            }else if(res[1]==1){
                max[0] = p;
                min[1] = p+1;
                pCounts[pivot] = g.length()>1?res[0]-1:res[0]; 
            }
            p = (int)((max[0]-min[0])/2+min[0]);
            pivot++;
        }

        min[1] = Math.max(min[1], lens[0]+2);
        while(lens[1] == 0){
            p = (max[1]-min[1])/2+min[1];
            if(max[1]==min[1]){
                lens[1] = min[1] - lens[0] - 1;
                break;
            }
            String g = "", h = "";
            for(int i=0;i<=p;i++)
                g+=' ';
            if(pivot < pivots.length()){
                h += pad;
                for(int i=0;i<20;i++)
                    h += pivots.charAt(pivot);
            }
            res = guess(g+h);
            if(res[1]<2){
                min[1] = p+1;
                pCounts[pivot] = res[0]-1;
            }else if(res[1]==2){
                max[1] = p;
                pCounts[pivot] = res[0]; 
            }
            pivot++;
        }
        lens[2] = len - lens[0] - lens[1] - 2;  
        return lens;
    }

    int[] guess(String in){
        guesses++;
        int chars=0, positions=0;
        String pw = curPhrase;

        for(int i=0;i<in.length()&&i<pw.length();i++){
            if(in.charAt(i)==pw.charAt(i))
                positions++;
        }
        if(positions == pw.length() && pw.length()==in.length()){
            System.out.println(in);
            return new int[]{-1,positions};
        }

        for(int i=0;i<in.length();i++){
            String c = String.valueOf(in.charAt(i));
            if(pw.contains(c)){
                pw = pw.replaceFirst(c, "");
                chars++;
            }
        }
        System.out.println(in);
        chars -= positions;
        return new int[]{chars,positions};
    }

    void start(){
        long timer = System.currentTimeMillis();
        loadDict("dict-small");
        loadPhrases("passwords");
        exclude = new String[3];
        int min=999,max=0;
        for(String phrase : phrases){
            curPhrase = phrase;
            int tries = crack();
            min=tries<min?tries:min;
            max=tries>max?tries:max;
        }
        System.out.println("\nTotal: " + guesses);
        System.out.println("Min: " + min);
        System.out.println("Max: " + max);
        System.out.println("Time: " + ((System.currentTimeMillis()-timer)/1000d));
    }

    int loadPhrases(String filename){
        phrases = new ArrayList<String>(1000);
        try {
            BufferedReader br = new BufferedReader(new FileReader(filename));
            String line;
            while ((line = br.readLine()) != null)
                if(line.length()>0)
                    phrases.add(line);
            br.close();
        } catch (Exception e){};
        System.out.println("Loaded " + phrases.size() + " phrases.");
        return phrases.size();
    }

    int loadDict(String filename){  
        dict = new HashSet<String>(10000);
        try {
            BufferedReader br = new BufferedReader(new FileReader(filename));
            String line;
            while ((line = br.readLine()) != null)
                dict.add(line);
            br.close();
        } catch (Exception e){};
        System.out.println("Loaded " + dict.size() + " words");     
        return dict.size();
    }

    int guesses;
    double sum = 0;
    List<String> phrases;
    Set<String> dict;
    String curPhrase;
    String[] exclude;
    String none;
    String pivots = "otnlidusypcbwmvfgeahkqrxzj";   // 26185
    String pad = "..................................................................";
    public static void main(String[] args){
        new Splitter().start();
    }   
}

4

সি # - 10649 (মিনিট 8, সর্বোচ্চ 14, গড়: 10.6) সময়: ~ 12 ঘন্টা

এটি দেখতে এটির মতো:

    13, whiteface rends opposed, 00:00:00.1282731, 00:01:53.0087971, 00:00:09.4368140
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkklllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooopppppppppp    pppppppppppppppppppppppppppppppppppppppppppppppppppppqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssstttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz  
.. . . .  . .  . .  .............................................rrrrrrrrrrrrrrrrrrssssssssssssssssssttttttttttttttttttiiiiiiiiiiiiiiiiiinnnnnnnnnnnnnnnnnnaaaaaaaaaaaaaaaaaa
. . .  . . . . . .  .............................................sssssssssssssssssslllllllllllllllllldddddddddddddddddduuuuuuuuuuuuuuuuuummmmmmmmmmmmmmmmmmrrrrrrrrrrrrrrrrrr
.. . .. ....... .................................................nnnnnnnnnnnnnnnnnnddddddddddddddddddiiiiiiiiiiiiiiiiiiggggggggggggggggggllllllllllllllllllffffffffffffffffff
.. . ............ ...............................................rrrrrrrrrrrrrrrrrrtttttttttttttttttthhhhhhhhhhhhhhhhhhddddddddddddddddddooooooooooooooooooffffffffffffffffff
....... . .......................................................ssssssssssssssssssttttttttttttttttttuuuuuuuuuuuuuuuuuuhhhhhhhhhhhhhhhhhhmmmmmmmmmmmmmmmmmmpppppppppppppppppp
....... ... .....................................................aaaaaaaaaaaaaaaaaa
......... ..... .................................................iiiiiiiiiiiiiiiiii
sheffield eject postwar
projected leigh gathers
portfolio felts escapee
fortescue ethyl affixes
whiteface rends opposed

সমাধানকারী

এটি একটি প্রত্যাশিত সলভার ব্যবহার করে। এটি অনুমান করার আগে, এটি বর্তমানে সম্ভাব্য পাসফ্রেজগুলি দিয়ে মাস্টারমাইন্ড থেকে প্রত্যাবর্তিত স্বতন্ত্র মানের সংখ্যা অনুমান করে। অনুমান যে পৃথক ফলাফলের সংখ্যা সর্বাধিক করে তোলে এটিই ব্যবহৃত হয়।

স্থান অনুমানের পর্বের জন্য এটি "" এবং "শুধুমাত্র সম্ভাব্য সংমিশ্রণগুলি বিবেচনা করে। অনুমানের পর্বের বাক্যাংশের জন্য, এটি বর্তমানে সম্ভাব্য পাসফ্রেজগুলির পুরো তালিকা তৈরি করে (যার কারণে এটি এত ধীর)।

চিঠি গণনা

স্থান সন্ধানের সাথে চিঠি সংখ্যা গণনা করা হয়। চিঠি সেটগুলি লোভী অনুসন্ধানের দ্বারা বেছে নেওয়া হয়েছিল, একবারে একটি করে চিঠি যুক্ত করে এবং সেটটি কতটা কার্যকর তা দেখার জন্য এলোমেলো পরীক্ষার বাক্যাংশ স্যাম্পল করে।

কোড এখানে: https://github.com/Tyler-Gelvin/MastermindContest

কোনও ইন্টারফেস নির্দিষ্ট করা হয়নি, সুতরাং সমস্ত ইনপুট হার্ডকোডযুক্ত এবং ইউনিট পরীক্ষাগুলি হ'ল একমাত্র ইন্টারফেস। "মূল" পরীক্ষাটি হল সলভারফাইচার Sসলভপ্যারালালএল।


আমি Mainআপনার কোডটিতে ফাংশনটি খুঁজে পাচ্ছি না । এটি একটি আছে?
রায়

ইউনিট পরীক্ষাটি SolverFixture.SolveSerialAllআমি পরীক্ষার ফলাফলগুলি উপরে পোস্ট করার জন্য ব্যবহার করি এবং Solver.Solveএটি প্রোগ্রামটির মূল বিষয়। এটি কোনও ইউনিট পরীক্ষার প্রকল্প যা কোনও একক অফিসিয়াল এন্ট্রি পয়েন্ট নেই, সুতরাং কোনও mainকার্যকারিতা নেই।
টাইলার গেলভিন

3

সি # - মোট: 1000, রান সময়: 305 সেকেন্ড, গড়: 24, ন্যূনতম: 14, সর্বোচ্চ: 32


বাহ এভজির <15 এটি বেশ ভাল, ভাল আমি এটি হারাতে পারি না তবে আমি এটির জন্য ছুরিকাঘাত করেছিলাম তাই এখানে আমার পদ্ধতির। আমি এটি কথায় কথায় ভেঙে ফেলেছি এবং পরবর্তীতে তাদের সমাধান করেছি। প্রথম দুটি শব্দের দৈর্ঘ্য নির্ধারণ করে এবং তারপরে কয়েকটি কৌশলগত অনুমান (প্রতিটি বার আগে অনুমান করা শব্দের দ্বারা ফিল্টারিং) দিয়ে আমি তুলনামূলকভাবে খুব কম সংখ্যার অনুমান দিয়ে উত্তরটি অর্জন করতে সক্ষম হয়েছি। আমি এই বিকাশের সময়কালে আমি দক্ষতার সাথে সংখ্যার প্রাক্কলনের (সংখ্যা অনুমানের) বেশিরভাগ অংশের অনুকূলকরণ করতে সক্ষম হয়েছি তবে এর সাথে দোষটি একবারে একটি শব্দকে যৌক্তিকভাবে সমাধান করার প্রাথমিক নকশার সিদ্ধান্তের সাথে সম্পর্কিত, এটি আমার কিছু অংশ ফেলে দিতে বাধ্য করে অনুমান এবং / অথবা অনুমানগুলি যতটা সম্ভব দক্ষতার সাথে চালানো যায় না যার ফলস্বরূপ আমি এইটিকে জিততে পারি না; (।

তবুও একটি আকর্ষণীয় নকশা (অন্তত আমি এটি মনে করি) অন্তর্ভুক্ত কোডটি সহ একটি জিনিস লক্ষ্য করুন, নির্দিষ্ট ক্ষেত্রে আমি কোনও অনুমান না চালিয়ে উত্তরটি নির্ধারণ করতে পারি যে -1 ফেরত আসে, যদি এটির জন্য সরল কোডের কোডের লাইন লাগানো প্রয়োজন হয় "এখানে যুক্ত করুন (যদি প্রয়োজন হয়)" (এবং আমার সমস্ত স্কোরগুলিতে +1 যোগ করুন :()


অ্যালগরিদম (আমার সুডোর কোড চিন্তাভাবনা)

সুতরাং সত্যিই এটির দুটি অংশ রয়েছে, প্রথম দুটি শব্দ এবং শেষ শব্দ। এটি আমার ব্যতীত অন্য কারও কাছে কোনও অর্থবোধ করতে পারে না, তবে আমি কোডটিতে পর্যাপ্ত মন্তব্য যুক্ত করার চেষ্টা করেছি যাতে এটি আরও অর্থবোধ করে:

নেক্সট ওয়ার্ড (দুটি প্রথম দুটি শব্দের মধ্যে একটি)

{

var দৈর্ঘ্যফফিউসিবলওয়ার্ড = শব্দের দৈর্ঘ্য নির্ধারণ করুন (কোড দেখুন: দৈর্ঘ্য সন্ধানের কার্যকর উপায়)

সম্ভাব্যতাগুলি তালিকা = সেই দৈর্ঘ্যের সমস্ত শব্দ (দৈর্ঘ্যফফিউজিবল ওয়ার্ড)

একটি অনুমান কর

সম্ভাবনা = সম্ভাবনা যেখানে (সমস্ত অনুমানের জন্য) the একই পদের অক্ষরের সংখ্যা সম্ভাব্য শব্দের সমান

(যদি আউটপ্লেস অক্ষর 0 এর সমান হয়) তবে যেখানে সমস্ত অক্ষর সম্ভাব্য শব্দের চেয়ে আলাদা}

}

লাস্ট ওয়ার্ড (প্রথম দুটি সমাধান হওয়ার পরে)

{

সম্ভাব্যতার তালিকা তৈরি করুন = সমস্ত শব্দ দ্বিতীয় শব্দের অফ পজিশন অক্ষর দ্বারা ফিল্টার করা হয়েছে (কোড দেখুন: সহায়ক সহায়ক)

একটি অনুমান কর

সম্ভাবনা = সম্ভাবনা যেখানে (সমস্ত অনুমানের জন্য) {

একই পদের অক্ষরের সংখ্যা সম্ভাব্য শব্দের সমান

অবস্থানের অক্ষরের সমষ্টি এবং বাহ্যিক পরিমাণ == সম্ভাব্য শব্দ (সমস্ত অনুমানের জন্য)

দৈর্ঘ্য সম্ভাব্য শব্দের দৈর্ঘ্যের (অবস্থানের অক্ষরের যোগফল এবং সমান) এর চেয়ে বড়

(যদি আউটপ্লেস অক্ষর 0 এর সমান হয়) তবে যেখানে সমস্ত অক্ষর সম্ভাব্য শব্দের চেয়ে আলাদা

}

}


কোড

এটি কাজ করার জন্য নোট করুন আপনাকে চলমান ডিরেক্টরিতে ppcg_mastermind_dict.txt এবং ppcg_mastermind_passes.txt অন্তর্ভুক্ত করতে হবে (বা একই ডিরেক্টরিতে ভিএসে এবং "আউটপুট ডিরেক্টরিতে সত্য অনুলিপি" সেট করতে হবে)। কোডের মানের জন্য আমি সত্যই এখনও ক্ষমাপ্রার্থী, এখনও এটিতে কাজ বরাদ্দ রয়েছে, যদিও এটি কাজ করা উচিত।

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;

namespace MastermindHorseBatteryStaple
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> results = new List<int>();
            var Start = DateTime.UtcNow;
            foreach (var element in File.ReadAllLines(Directory.GetCurrentDirectory() + "\\ppcg_mastermind_passes.txt").ToArray())
            {
                var pas1 = new PassPhrase(element);
                var pasSolve = new PassPhraseCracker();
                var answer = pasSolve.Solve(pas1);
                Console.WriteLine("Answer(C): " + answer);
                Console.WriteLine("Answer(R): " + pas1.currentPassword);
                Console.WriteLine("Equal: " + answer.Equals(pas1.currentPassword));
                Console.WriteLine("Total Cost: " + pas1.count);
                Console.WriteLine();
                results.Add(pas1.count);
            }
            Console.WriteLine("Final Run Time(Seconds): " + (DateTime.UtcNow - Start).TotalSeconds);
            Console.WriteLine("Final Total Cost: " + results.Average());
            Console.WriteLine("Min: " + results.Min());
            Console.WriteLine("Max: " + results.Max());
            Console.ReadLine(); 
        }
    }

class PassPhrase
    {
        public List<string> Words { get; set; }
        public int count = 0;         
        public string currentPassword { get; set; }

        /// <summary>
        /// Declare if you want the class to generate a random password
        /// </summary>
        public PassPhrase()
        {            
            Words = File.ReadAllLines(Directory.GetCurrentDirectory() + "\\ppcg_mastermind_dict.txt").ToList();
            Random random = new Random();
            currentPassword = Words[random.Next(Words.Count())] + " " + Words[random.Next(Words.Count())] + " " + Words[random.Next(Words.Count())];
        }
        /// <summary>
        /// Use if you want to supply a password
        /// </summary>
        /// <param name="Password">The password to be guessed agianst</param>
        public PassPhrase(string Password)
        {
            Words = File.ReadAllLines(Directory.GetCurrentDirectory() + "\\ppcg_mastermind_dict.txt").ToList();
            currentPassword = Password;
        }

        public int[] Guess(String guess)
        {
            count++;
            return Test(guess, currentPassword);
        }
        /// <summary>
        /// This method compares two string and return -1 if equal, 
        /// otherwise it returns the number of character with the same index matching, 
        /// and number of characters matching but in the wrong position
        /// </summary>
        /// <param name="value1">First value to compare</param>
        /// <param name="value2">Second value to compare</param>
        /// <returns>Returns {-1, -1} if equal, 
        /// Two ints the first(0) being the number of chars matching but not in the right postion
        /// The second(1) being the number of chars that match and are in the right position
        /// </returns>
        public int[] Test(String value1, String value2)
        {
            if (String.Equals(value1, value2)) return new int[] { -1, -1 };

            var results = new int[2];
            results[0] = TestNumberOfOutOfPositionCharacters(value1, value2);
            results[1] = TestNumberOfInPositionCharacters(value1, value2);

            return results;
        }
        public int TestNumberOfInPositionCharacters(String value1, String value2)
        {
            var result = 0;
            var value1Collection = value1.ToCharArray();
            var value2Collection = value2.ToCharArray();

            for (int i = 0; i < value1Collection.Count(); i++)
            {
                if (value2Collection.Count() - 1 < i) continue;
                if (value2Collection[i] == value1Collection[i]) result++;
            }
            return result;
        }
        public int TestNumberOfOutOfPositionCharacters(String value1, String value2)
        {
            return CommonCharacters(value1, value2) - TestNumberOfInPositionCharacters(value1, value2);                   
        }

        private int CommonCharacters(string s1, string s2)
        {
            bool[] matchedFlag = new bool[s2.Length];

            for (int i1 = 0; i1 < s1.Length; i1++)
            {
                for (int i2 = 0; i2 < s2.Length; i2++)
                {
                    if (!matchedFlag[i2] && s1.ToCharArray()[i1] == s2.ToCharArray()[i2])
                    {
                        matchedFlag[i2] = true;
                        break;
                    }
                }
            }

            return matchedFlag.Count(u => u);
        }
        private string GetRandomPassword()
        {
            Random rand = new Random();
            return Words[rand.Next(Words.Count())] + " " + Words[rand.Next(Words.Count())] + " " + Words[rand.Next(Words.Count())];
        }        
    }

class PassPhraseCracker
    {
        public class LengthAttempt
        {
            public int Length { get; set; }
            public int Result { get; set; }
        }
        public class WordInformation
        {
            public string Word { get; set; }
            public int[] Result { get; set; }
        }

        public string Solve(PassPhrase pas)
        {
            //The helperWords is used in the final word to lower the number of starting possibilites 
            var helperWords = new List<WordInformation>();
            var first = GetNextWord(pas, "", ref helperWords);

            //TODO: I'm ignoring the helperWords from the first word, 
            //I should do some comparisions with the results of the seconds, this may make finding the last word slightly faster 
            helperWords = new List<WordInformation>();
            var second = GetNextWord(pas, first + " ", ref helperWords);

            //The final Word can be found much faster as we can say that letters in the wrong position are in this word
            var third = GetLastWord(pas, first + " " + second + " ", helperWords);

            return first + " " + second + " " + third;
        }

        private string GetNextWord(PassPhrase pas, string final, ref List<WordInformation> HelperWords)
        {
            var result = new int[] { 0, 0 };
            var currentGuess = final;
            Random random = new Random();
            var triedValues = new List<WordInformation>();

            //The most efficient way to find length of the word that I could come up with
            var triedLengths = new List<LengthAttempt>();
            var lengthAttempts = new List<LengthAttempt>();
            var lengthOptions = pas.Words.AsParallel().GroupBy(a => a.ToCharArray().Count()).OrderByDescending(a => a.Count()).ToArray();
            var length = 0;
            while (length == 0)
            {
                //Find most frequency number of character word between already guessed ones
                var options = lengthOptions.AsParallel().Where(a =>
                    (!lengthAttempts.Any(b => b.Result == 1) || a.Key < lengthAttempts.Where(b => b.Result == 1).Select(b => b.Length).Min()) &&
                    (!lengthAttempts.Any(b => b.Result == 0) || a.Key > lengthAttempts.Where(b => b.Result == 0).Select(b => b.Length).Max()));

                //Rare condition that occurs when the number of characters is equal to 20 and the counter
                //Guesses 18 and 20
                if (!options.Any())
                {
                    length = lengthAttempts.Where(a => a.Result == 1).OrderBy(a => a.Length).First().Length;
                    break;
                }

                var tryValue = options.First();

                //Guess with the current length, plus one space
                //TODO: I can append characters to this and make it a more efficient use of the Guess function, 
                //this would speed up the calculation of the final Word somewhat
                //but this really highlights the failing of this design as characters in the wrong positions can't be deterministically used until the final word
                result = pas.Guess(currentGuess + new String(' ', tryValue.Key) + " ");

                //This part looks at all the attempts and tries to determine the length of the word
                lengthAttempts.Add(new LengthAttempt { Length = tryValue.Key, Result = result[1] - final.Length });

                //For words with length 1
                if (lengthAttempts.Any(a => a.Length == 1 && a.Result == 1))
                    length = 1;

                //For words with the max length 
                if (lengthAttempts.Any(a => a.Length == lengthOptions.Select(b => b.Key).Max() && a.Result == 1))
                    length = lengthAttempts.Single(a => a.Length == lengthOptions.Select(b => b.Key).Max() && a.Result == 1).Length;

                else if (lengthAttempts
                    .Any(a =>
                        a.Result == 1 &&
                        lengthAttempts.Any(b => b.Length == a.Length - 1) &&
                        lengthAttempts.Single(b => b.Length == a.Length - 1).Result == 0))
                    length = lengthAttempts
                        .Single(a =>
                            a.Result == 1 &&
                            lengthAttempts.Any(b => b.Length == a.Length - 1) &&
                            lengthAttempts.Single(b => b.Length == a.Length - 1).Result == 0).Length;
            }

            //Filter by length
            var currentOptions = pas.Words.Where(a => a.Length == length).ToArray();

            //Now try a word, if not found then filter based on all words tried            
            while (result[1] != final.Length + length + 1)
            {
                //Get farthest value, or middle randomly
                //TODO: I've struggled with this allot, and tried many way to some up with the best value to try
                //This is the best I have for now, but there may be a better way of doing it
                var options = currentOptions.AsParallel().OrderByDescending(a => ComputeLevenshteinDistance(a, triedValues.Count() == 0 ? currentOptions[0] : triedValues.Last().Word)).ToList();
                if (random.Next(2) == 1)
                    currentGuess = options.First();
                else
                    currentGuess = options.Skip((int)Math.Round((double)(options.Count() / 2))).First();

                //try it
                result = pas.Guess(final + currentGuess + " ");

                //add it to attempts
                triedValues.Add(new WordInformation { Result = result, Word = currentGuess });

                //filter any future options to things with the same length and equal or more letters in the same position and equal or less letters in the wrong position
                currentOptions = currentOptions.Except(triedValues.Select(a => a.Word)).AsParallel()
                    .Where(a => triedValues.All(b => pas.TestNumberOfInPositionCharacters(a, b.Word) == b.Result[1] - 1 - final.Length))
                    //Special Zero Case
                    .Where(a => triedValues
                    .Where(b => b.Result[1] - 1 - final.Length == 0)
                    .All(b => pas.TestNumberOfInPositionCharacters(a, b.Word) == 0))
                    .ToArray();
            }

            //Add attempts to helper list
            HelperWords = HelperWords.Concat(triedValues.Where(a => a.Result[0] - pas.TestNumberOfOutOfPositionCharacters(a.Word, currentGuess) > 0)
                .Select(a => new WordInformation { Word = a.Word, Result = new int[] { a.Result[0] - pas.TestNumberOfOutOfPositionCharacters(a.Word, currentGuess), a.Result[1] } }).ToList()).ToList();
            return currentGuess;
        }

        private string GetLastWord(PassPhrase pas, string final, List<WordInformation> HelperWords)
        {
            Random rand = new Random();
            var triedList = new List<WordInformation>();
            var result = new int[] { 0, 0 };

            //This uses the helperList from the previous word to attempt help filter the initial possiblities of the last word before preforming the first check
            var currentOptions = pas.Words.AsParallel().Where(a => HelperWords
                .All(b => pas.TestNumberOfOutOfPositionCharacters(a, b.Word) + pas.TestNumberOfInPositionCharacters(a, b.Word) >= b.Result[0])).ToArray();
            var current = final;
            while (result[0] != -1)
            {
                //Here we know the final word but their is no reason to submit it to the guesser(that would cost one more), just return it
                if (currentOptions.Count() == 1)
                {
                    //ADD GUESS HERE(if required)
                    //pas.Guess(final + current);
                    return currentOptions[0];
                }

                //Get farthest value, or middle randomly
                var options = currentOptions.AsParallel()
                    .OrderByDescending(a => ComputeLevenshteinDistance(a, triedList.Count() == 0 ? currentOptions[0] : triedList.Last().Word)).ToList();

                //Get the next value to try
                if (rand.Next(2) == 1)
                    current = options.First();
                else
                    current = options.Skip((int)Math.Round((double)(options.Count() / 2))).First();

                //try it
                result = pas.Guess(final + current);

                //If its the right word return it
                if (result[0] == -1)                     
                    return current;

                //add it to attempts
                triedList.Add(new WordInformation { Result = result, Word = current });

                //filter any future options to things with the same length and equal or more letters in the same position and equal or less letters in the wrong position
                currentOptions = currentOptions.Except(triedList.Select(a => a.Word)).AsParallel()
                    .Where(a => triedList
                        .All(b => pas.TestNumberOfInPositionCharacters(a, b.Word) == b.Result[1] - final.Length &&
                            pas.TestNumberOfInPositionCharacters(a, b.Word) + pas.TestNumberOfOutOfPositionCharacters(a, b.Word) == b.Result[0] + b.Result[1] - final.Length &&
                            a.Length >= pas.TestNumberOfInPositionCharacters(a, b.Word) + pas.TestNumberOfOutOfPositionCharacters(a, b.Word) - final.Length))
                    //Special zero match condition
                    .Where(a => triedList
                    .Where(b => b.Result[1] - final.Length == 0)
                    .All(b => pas.TestNumberOfInPositionCharacters(a, b.Word) == 0)).ToArray();
            }

            return current;
        }

        /// <summary>
        /// http://www.dotnetperls.com/levenshtein
        /// Returns the number of character edits (removals, inserts, replacements) that must occur to get from string A to string B.
        /// </summary>
        /// <param name="s">First string to compare</param>
        /// <param name="t">Second string to compare</param>
        /// <returns>Number of edits needed to turn one string into another</returns>
        private static int ComputeLevenshteinDistance(string s, string t)
        {
            int n = s.Length;
            int m = t.Length;
            int[,] d = new int[n + 1, m + 1];

            // Step 1
            if (n == 0)
            {
                return m;
            }

            if (m == 0)
            {
                return n;
            }

            // Step 2
            for (int i = 0; i <= n; d[i, 0] = i++)
            {
            }

            for (int j = 0; j <= m; d[0, j] = j++)
            {
            }

            // Step 3
            for (int i = 1; i <= n; i++)
            {
                //Step 4
                for (int j = 1; j <= m; j++)
                {
                    // Step 5
                    int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;

                    // Step 6
                    d[i, j] = Math.Min(
                        Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
                        d[i - 1, j - 1] + cost);
                }
            }
            // Step 7
            return d[n, m];
        }
    }
}

2

পাইথন - মিনিট: 87, সর্বোচ্চ: 108, মোট: 96063, সময়: 4 এস

এটি আমার দ্বিতীয় পোস্ট। এই পদ্ধতিতে সময় কম ব্যবহার হয় তবে স্কোর আরও খারাপ হয়। এবং এটি ব্যবহার করে চালানো যেতে পারে:

  • সিপিথন 2
  • সিপিথন ঘ
  • পাইপাই 2 (দ্রুততম)
  • পাইপি 3

পদক্ষেপ:

  • অনুমান পছন্দ ব্যবহার প্রথম 2 শূণ্যস্থান খুঁজুন . ...., .. ......
  • পাসওয়ার্ডে প্রতিটি শব্দের জন্য অক্ষর ফ্রিকোয়েন্সি গণনা করুন।
  • শব্দ দৈর্ঘ্য এবং অক্ষর ফ্রিকোয়েন্সি দ্বারা ফিল্টারিংয়ের পরে প্রতিটি বৈধ সংমিশ্রণের জন্য অনুমান করুন।

প্রতিটি পাসওয়ার্ডের জন্য এটির জন্য 90 টি অনুমান।

from __future__ import print_function
import sys
import itertools
from collections import defaultdict


def run_checker(answer, guesser):
    guess_count = 0
    guesser = guesser()
    guess = next(guesser)
    while True:
        char_count = len(set(guess) & set(answer))
        pos_count = sum(x == y for x, y in zip(answer, guess))
        guess_count += 1
        if answer == guess:
            break
        guess = guesser.send((char_count, pos_count))
    try:
        guesser.send((-1, -1))
    except StopIteration:
        pass
    return guess_count


# Preprocessing
words = list(map(str.rstrip, open('dict.txt')))

M = 26
ord_a = ord('a')

def get_fingerprint(word):
    counts = [0] * M
    for i in map(ord, word):
        counts[i - ord_a] += 1
    return tuple(counts)

P = defaultdict(list)
for word in words:
    P[get_fingerprint(word)].append(word)

# End of preprocessing


def guesser2():
    max_word_len = max(map(len, words))
    max_len = max_word_len * 3 + 2
    spaces = []
    for i in range(1, max_len - 1):
        guess = '.' * i + ' '
        char_count, pos_count = yield guess
        if pos_count > 0:
            spaces.append(i)
            if len(spaces) == 2:
                break

    word_lens = [spaces[0], spaces[1] - spaces[0] - 1, max_word_len]
    C = []
    for i in range(3):
        char_counts = [0] * M
        for j in range(M):
            guess = chr(ord_a + j) * (i + sum(word_lens[:i + 1]))
            _, char_counts[j] = yield guess
        C.append(char_counts)
    for i in (2, 1):
        for j in range(M):
            C[i][j] -= C[i - 1][j]

    candidates = []
    for i in range(3):
        candidates.append(P[tuple(C[i])])
    for i in range(2):
        candidates[i] = [w for w in candidates[i] if word_lens[i] == len(w)]

    try_count = 0
    for result in itertools.product(*candidates):
        guess = ' '.join(result)
        char_count, pos_count = yield guess
        try_count += 1
        if char_count == -1:
            break


def test(test_file, guesser):
    scores = []
    for i, answer in enumerate(map(str.rstrip, open(test_file))):
        print('\r{}'.format(i), end='', file=sys.stderr)
        scores.append(run_checker(answer, guesser))
    print(scores)
    print('sum:{} max:{} min:{}'.format(sum(scores), max(scores), min(scores)))


if __name__ == '__main__':
    test(sys.argv[1], guesser2)

2

পার্ল (এখনও চলছে ... এখন পর্যন্ত মিনিট / গড় / সর্বোচ্চ সর্বোচ্চ 8 / 9,2 / 11, এটি মোট রানটাইম 1500 300 ঘন্টা ধরে অনুমান করুন )

আপডেট: কিছুটা গতি বাড়ানোর জন্য প্রাথমিক অনুমানগুলি পরিবর্তন করা হয়েছে। একটি বাগ সংশোধন করা হয়েছে।

এই প্রতিযোগিতাটি শেষ হওয়ার আগে সম্ভবত এটি শেষ হবে না তবে আমি এটি পোস্ট করতে পারি। এটি পৃথক শব্দের দৈর্ঘ্য নির্ধারণ করে না, সুতরাং এটির পুরো অভিধানটি পরীক্ষা করতে হবে, যা ... কিছুটা সময় নেয়।

প্রথম দুটি অনুমানের সাহায্যে এটি মোট দৈর্ঘ্য, 'ই' এর গণনা এবং সেখানে কতগুলি পৃথক অক্ষর রয়েছে তা নির্ধারণ করে।

তারপরে এটি সেই সমস্ত সংমিশ্রণের চেষ্টা করে যা সেই পরিসংখ্যানের পাশাপাশি পূর্ববর্তী সমস্ত অনুমানগুলিকে যথেষ্ট করে দেয়।

এই সাম্প্রতিক (এবং শেষ) সংস্করণে এমপি যুক্ত হয়েছে এবং বর্তমানে একটি 24 কোর সিস্টেমে চলছে।

use strict;
use POSIX ":sys_wait_h";

$| = 1;

my( $buckets );

open my $dict, "<", "dict.txt";
while( <$dict> )
{
  chomp;
  push( @{$buckets->{length($_)}}, [ split // ] );
};
close $dict;


open my $pass, "<", "pass.txt";

my( @pids );
my( $ind ) = 0;

for( my $i = 0; $i < 1000; $i++ )
{
  my $phrase = <$pass>; chomp( $phrase );

  my( $pid ) = fork();

  if( $pid != 0 )
  {
    $pids[$ind] = $pid;
    print join( "; ", @pids ), "\n";

    for( my $j = 0; $j < 18; ++$j, $j %= 18 )
    {
      waitpid( $pids[$j], WNOHANG ) and $ind=$j,last;
      sleep( 1 );
    };
  }
  else
  {
    my( $r ) = &guessPassPhrase( $phrase, $buckets );

    open my $out, ">>", "result.txt";
    print $out "'$phrase' => $r\n";
    close $out;
    exit;
  };
};

close $pass;


sub guessPassPhrase
{
  our( $pp, $buckets ) = @_;
  our( @log ) = undef;
  our( @ppa ) = split //, $pp;
  our( $trys ) = 0;
  our( $invers ) = 1;
  our( $best ) = 0;

  print "Next   : ", $pp, "\n";

  my( @pw1 ) = map { @{$buckets->{$_}} } ( sort { $b <=> $a } keys( %$buckets ));
  my( @pw2, $llt1 );
  my( @pw3, $llt2 );

  my( $t ) = [ (" ")x9,("-")x58,("a".."z") x 64 ];
  my( $y, $c ) = &oracleMeThis( $t );
  my( $l ) = $y + $c;
  push( @log, [ [(" ")x9], 2-$c, $c ] );

  $t = [("a".."z")];
  my( $y, $c ) = &oracleMeThis( $t );
  push( @log, [ $t, $y, $c ] );
  if( $best < ($y + $c) ) { $best = ($y + $c); };
  print "Guessed ($pp:$trys/$best/$l):", @$t, "=> $y/$c             \n";

  $t = [("e")x4];
  my( $y, $c ) = &oracleMeThis( $t );
  push( @log, [ $t, $y, $c ] );
  if( $best < ($y + $c) ) { $best = ($y + $c); };
  print "Guessed ($pp:$trys/$best/$l):", @$t, "=> $y/$c             \n";

  $t = [("i")x6];
  my( $y, $c ) = &oracleMeThis( $t );
  push( @log, [ $t, $y, $c ] );
  if( $best < ($y + $c) ) { $best = ($y + $c); };
  print "Guessed ($pp:$trys/$best/$l):", @$t, "=> $y/$c             \n";

  LOOP1: for my $w1 ( @pw1 )
  {
    my( $t ) = [ @$w1, " " ];

    print "Pondering: ", @$t, "($trys;$best/$l;",$::e1,",",$::e2,")   \r";

    &EliminatePartial( $t ) && ++$::e1 && next;

    if( $llt1 != @$t )
    {
      @pw2 = map { $_ < $l - @$t ? @{$buckets->{$_}} : () } ( sort { $b <=> $a } keys( %$buckets ));
      $llt1 = @$t;
    };

    $llt2 = 0;

    LOOP2: for my $w2 ( @pw2 )
    {
      my( $t ) = [ @$w1, " ", @$w2, " " ];

#      print "Pondering: ", @$t, "(",$::e1,",",$::e2,")                             \r";

      &EliminatePartial( $t ) && ++$::e2 && next;

      if( $llt2 != @$t )
      {
        @pw3 = map { $_ == $l - @$t ? @{$buckets->{$_}} : () } ( sort { $b <=> $a } keys( %$buckets ));
        $llt2 = @$t;
      };

      LOOP3: for my $w3 ( @pw3 )
      {
        my( $t ) = [ @$w1, " ", @$w2, " ", @$w3 ];

        &EliminatePartial( $t ) && next LOOP3;

        my( $y, $c ) = &oracleMeThis( $t );
        push( @log, [ $t, $y, $c ] );
        if( $best < ($y + $c) ) { $best = ($y + $c); };
        print "Guessed ($pp:$trys/$best/$l):", @$t, "=> $y/$c             \n";

        if( $c == $l ) { return( $trys ); };

        if( $c == 0 ) { @pw2 = (); next LOOP1; };
        if( $c == 1 ) { @pw3 = (); next LOOP2; };
        if( $c < @$w1 ) { next LOOP1; };
        if( $c < @$w1 + @$w2 ) { next LOOP2; };

      };
    };
  };

  die( "Failed To Guess" );

  sub EliminatePartial
  {
    my( $guessn ) = @_;

    for my $log ( @log )
    {
      next if !$log;
      my( $guesso, $yo, $co ) = @$log;
      my( $guessos ) = join( "", @$guesso );

      my( $cn ) = scalar( map { $$guesso[$_] eq $$guessn[$_] ? ( 1 ) : () } ( 0 .. ( @$guesso < @$guessn ? @$guesso : @$guessn ) - 1 ));
      my( $yn ) = scalar( map { $guessos =~ s/$_// ? ( 1 ) : () } ( @$guessn )) - $cn;

      return( 1 ) if( $cn > $co || $yn > $yo );
      return( 1 ) if(( $yo - $yn ) + ( $co - $cn ) > $l - @$guessn );
      return( 1 ) if( @$guesso <= @$guessn && $co != $cn );
    };

    return( 0 );
  };

  sub oracleMeThis
  {
    my( $guessn ) = @_;

    $trys++;

    my( $pph ) = $pp;

    my( $cn ) = scalar( map { $ppa[$_] eq $$guessn[$_] ? ( 1 ) : () } ( 0 .. @$guessn - 1 ));
    my( $yn ) = scalar( map { $pph =~ s/$_// ? ( 1 ) : () } ( @$guessn )) - $cn;

    return( $yn, $cn );
  };
};

1

জাভা 10.026 (2.5 ঘন্টা মধ্যে)

এখানে আমার অপ্টিমাইজড কোড, গতি উন্নত করতে এখন বহু-থ্রেডযুক্ত:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class MastermindV4MT {

    /*
     * Total guesses: 10026
     * Took: 8461801 ms
     */

    // Order of characters to analyze:
    // eiasrntolcdupmghbyfvkwzxjq - 97
    private int[] lookup = new int[] { 4, 8, 0, 18, 17, 13, 19, 14, 11, 2, 3,
            20, 15, 12, 6, 7, 1, 24, 5, 21, 10, 22, 25, 23, 9, 16 };

    public static void main(String[] args) throws Exception {
        new MastermindV4MT().run();
    }

    int done = 0;
    int totalGuesses = 0;

    private void run() throws Exception {
        long beforeTime = System.currentTimeMillis();
        Map<Integer, List<char[]>> wordMap = createDictionary();
        List<String> passPhrases = createPassPhrases();

        ExecutorService executor = Executors.newFixedThreadPool(8);

        for(String phrase:passPhrases) {
            executor.execute(new Runnable() {
                public void run() {
                    int guesses = solve(wordMap, phrase);
                    totalGuesses+=guesses;
                    done++;
                    System.out.println("At "+done+" of "+passPhrases.size()+" just added "+guesses+" predicted score: "+((1.0*totalGuesses)/done)*passPhrases.size());
                };
            });
        }
        executor.shutdown();
        try {
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.HOURS);
        } catch (InterruptedException e) {
        }
        System.out.println("Total guesses: " + totalGuesses);
        System.out.println("Took: " + (System.currentTimeMillis() - beforeTime) + " ms");
    }

    int[] guess(char[] in, char[] pw, char[] pwsorted) {
        int chars = 0, positions = 0;

        char[] inc = Arrays.copyOf(in, in.length);

        for (int i = 0; i < inc.length && i < pw.length; i++) {
            if (inc[i] == pw[i])
                positions++;
        }
        if (positions == pw.length && pw.length == inc.length)
            return new int[] { -1, positions };

        Arrays.sort(inc);
        int i1 = 0;
        int i2 = 0;
        while(i1 < pwsorted.length && i2 < inc.length) {
            if(inc[i2]==pwsorted[i1]) {
                i1++;
                i2++;
                chars++;
            } else if(inc[i2]<pwsorted[i1]) {
                i2++;
            } else {
                i1++;
            }
        }

        chars -= positions;
        return new int[] { chars, positions };
    }

    private int solve(Map<Integer, List<char[]>> wordMap, String password) {

        // Do one initial guess which gives us two things:
        // The amount of characters in total
        // The amount of e's

        char[] pw = password.toCharArray();
        char[] pwsorted = password.toCharArray();
        Arrays.sort(pwsorted);

        int[] initialResult = guess(Facts.INITIAL_GUESS.toCharArray(), pw, pwsorted);
        int guesses = 1;

        // Create the object that tracks all the known facts/bounds:
        Facts facts = new Facts(initialResult);

        // Determine a pivot and find the spaces (binary search)
        int center = ((initialResult[0] + initialResult[1]) / 2) + 1;
        guesses += findSpaces(center, facts, pw, pwsorted);

        // We know the first word length, the second might have some bounds, but
        // is unknown:
        // We can calculate the lengths:
        int minLength1 = facts.spaceBounds[0] - 1;
        int maxLength1 = facts.spaceBounds[1] - 1;

        char[] phraseBuilder = new char[facts.totalLength+2];

        for (int length1 = minLength1; length1 <= maxLength1;length1++) {

            if (wordMap.get(length1) == null) {
                continue;
            }

            for (char[] w1 : wordMap.get(length1)) {
                for(int i = 0; i<w1.length;i++) {
                    phraseBuilder[i] = w1[i];
                }
                phraseBuilder[w1.length] = ' ';

                if (facts.partialMatches(phraseBuilder, facts.totalLength+1-w1.length)) {

                    int minLength2 = (facts.spaceBounds[2] - length1 - 2);
                    int maxLength2 = (facts.spaceBounds[3] - length1 - 2);

                    for (int length2 = minLength2; length2 <= maxLength2;length2++) {

                        if (wordMap.get(length2) == null) {
                            continue;
                        }

                        for (char[] w2 : wordMap.get(length2)) {

                            // Continue if (according to our facts) this word is a
                            // partial match:
                            for(int i = 0; i<length2;i++) {
                                phraseBuilder[w1.length+1+i] = w2[i];
                            }
                            phraseBuilder[w1.length+w2.length+1] = ' ';

                            if (facts.partialMatches(phraseBuilder, facts.totalLength-(w1.length+w2.length))) {

                                if (wordMap.get(facts.totalLength - length2 - length1) == null) {
                                    continue;
                                }

                                int length3 = facts.totalLength - length2 - length1;
                                for (char[] w3 : wordMap.get(length3)) {

                                    for(int i = 0; i<length3;i++) {
                                        phraseBuilder[w1.length+w2.length+2+i] = w3[i];
                                    }

                                    if (facts.matches(phraseBuilder)) {
                                        int[] result = guess(phraseBuilder, pw, pwsorted);
                                        guesses++;

                                        //String possiblePhrase = new String(phraseBuilder);
                                        //System.out.println(possiblePhrase + " " + Arrays.toString(result));
                                        if (result[0] == -1) {
                                            return guesses;
                                        }
                                        // No match, update facts:
                                        facts.storeInvalid(phraseBuilder.clone(), result);
                                    }
                                }
                                for(int i = 0; i<phraseBuilder.length-(w1.length+2+w2.length);i++) {
                                    phraseBuilder[w1.length+w2.length+2+i] = '-';
                                }
                            }
                        }
                        for(int i = 0; i<phraseBuilder.length-(w1.length+1);i++) {
                            phraseBuilder[w1.length+1+i] = '-';
                        }

                    }
                }
            }
        }
        throw new IllegalArgumentException("Unable to solve!?");
    }

    private int findSpaces(int center, Facts facts, char[] pw, char[] pwsorted) {
        char[] testPhrase = new char[facts.totalLength + 2+facts.charBounds[lookup[facts.charPtr]]];
        // Place spaces for analysis:
        int ptr = 0;
        for (int i = 0; i < center; i++) {
            testPhrase[ptr++] = ' ';
        }
        while (ptr < (facts.totalLength + 2)) {
            testPhrase[ptr++] = '-';
        }

        // Append extra characters for added information early on:
        for (int i = 0; i < facts.charBounds[lookup[facts.charPtr]]; i++) {
            testPhrase[ptr++] = (char) (lookup[facts.charPtr] + 97);
        }

        // Update space lower and upper bounds:
        int[] answer = guess(testPhrase, pw, pwsorted);
        if (answer[1] == 0) {
            facts.spaceBounds[0] = Math.max(facts.spaceBounds[0], center + 1);
            facts.spaceBounds[2] = Math.max(facts.spaceBounds[2], center + 3);
        } else if (answer[1] == 1) {
            facts.spaceBounds[1] = Math.min(facts.spaceBounds[1], center);
            facts.spaceBounds[2] = Math.max(facts.spaceBounds[2], center + 1);
        } else {
            facts.spaceBounds[3] = Math.min(facts.spaceBounds[3], center);
            facts.spaceBounds[1] = Math.min(facts.spaceBounds[1], center - 2);
        }
        int correctAmountChars = (answer[0] + answer[1]) - 2;
        facts.updateCharBounds(correctAmountChars);
        // System.out.println(Arrays.toString(facts.spaceBounds));
        if (facts.spaceBounds[1]-facts.spaceBounds[0]<5) {
            // Only find the first space
            return 1;
            //if(facts.spaceBounds[3]-facts.spaceBounds[2]<4) return;
            //findSpaces(facts.spaceBounds[2] + ((facts.spaceBounds[3]-facts.spaceBounds[2])/3), facts, pw, pwsorted);
        } else {
            return 1+findSpaces((facts.spaceBounds[0] + facts.spaceBounds[1]) / 2, facts, pw, pwsorted);
        }
    }

    private class Facts {

        private static final String INITIAL_GUESS = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbccccccccccccccccccddddddddddddddddddffffffffffffffffffgggggggggggggggggghhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkllllllllllllllllllmmmmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnnnnooooooooooooooooooppppppppppppppppppqqqqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrssssssssssssssssssttttttttttttttttttuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzz";
        private final int totalLength;
        private final int[] spaceBounds;
        // Pre-filled with maximum bounds obtained from dictionary:
        private final int[] charBounds = new int[] { 12, 9, 9, 9, 15, 9, 12, 9, 18, 6, 9, 12, 9, 12, 12, 9, 3, 12, 15, 9, 12, 6, 6, 3, 9, 6 };
        private int charPtr;

        public Facts(int[] initialResult) {

            totalLength = initialResult[0] + initialResult[1];
            spaceBounds = new int[] { 2, Math.min(totalLength - 2, 22), 4, Math.min(totalLength + 1, 43) };

            // Eliminate firsts
            charBounds[lookup[0]] = initialResult[1];
            // Adjust:
            for (int i = 1; i < charBounds.length; i++) {
                charBounds[lookup[i]] = Math.min(charBounds[lookup[i]], totalLength - initialResult[1]);
            }
            charPtr = 1;
        }

        private List<char[]> previousGuesses = new ArrayList<char[]>();
        private List<int[]> previousResults = new ArrayList<int[]>();

        public void storeInvalid(char[] phrase, int[] result) {
            previousGuesses.add(phrase);
            previousResults.add(result);
        }

        public void updateCharBounds(int correctAmountChars) {

            // Update the bounds we know for a certain character:
            int knownCharBounds = 0;
            charBounds[lookup[charPtr]] = correctAmountChars;
            for (int i = 0; i <= charPtr; i++) {
                knownCharBounds += charBounds[lookup[i]];
            }
            // Also update the ones we haven't checked yet, we might know
            // something about them now:
            for (int i = charPtr + 1; i < charBounds.length; i++) {
                charBounds[lookup[i]] = Math.min(charBounds[lookup[i]], totalLength - knownCharBounds);
            }
            charPtr++;
            while (charPtr < 26 && charBounds[lookup[charPtr]] == 0) {
                charPtr++;
            }
        }

        public boolean partialMatches(char[] phrase, int amountUnknown) {

            //Try to match a partial phrase, we can't be too picky because we don't know what else is next
            Arrays.fill(cUsed, 0);
            for(int i = 0; i<phrase.length; i++) {
                if(phrase[i]!=' ' && phrase[i]!='-'&&phrase[i]!=0) {
                    cUsed[phrase[i]-97]++;
                }
            }
            for(int i = 0; i<cUsed.length; i++) {
                //Only eliminate the phrases that definitely have wrong characters:
                if(cUsed[i] > charBounds[i]) {
                    return false;
                }
            }
            //Check again previous guesses:
            int cnt = 0;
            char[] phraseSorted = phrase.clone();
            Arrays.sort(phraseSorted);
            for(char[] previousGuess:previousGuesses) {
                // If the input phrase is the correct phrase it should score the same against previous tries:
                int[] result = guess(previousGuess, phrase, phraseSorted);
                int[] expectedResult = previousResults.get(cnt);

                //Some cases we can stop early:
                if(result[0]+result[1] > expectedResult[0]+expectedResult[1]) {
                    return false;
                }
                if(result[1]>expectedResult[1]) {
                    return false;
                }
                if(result[0]+amountUnknown<expectedResult[0]) {
                    return false;
                }
                if(result[1]+amountUnknown<expectedResult[1]) {
                    return false;
                }
                if(result[0]+result[1]+amountUnknown < expectedResult[1]+expectedResult[0]) {
                    return false;
                }
                cnt++;
            }
            return true;
        }

        int[] cUsed = new int[26];
        public boolean matches(char[] phrase) {

            // Try to match a complete phrase, we can now use all information:
            Arrays.fill(cUsed, 0);
            for (int i = 0; i < phrase.length; i++) {
                if(phrase[i]!=' ' && phrase[i]!='-'&&phrase[i]!=0) {
                    cUsed[phrase[i] - 97]++;
                }
            }

            for (int i = 0; i < cUsed.length; i++) {
                if (i < charPtr) {
                    if (cUsed[lookup[i]] != charBounds[lookup[i]]) {
                        return false;
                    }
                } else {
                    if (cUsed[lookup[i]] > charBounds[lookup[i]]) {
                        return false;
                    }
                }
            }

            // Check again previous guesses:
            char[] phraseSorted = phrase.clone();
            Arrays.sort(phraseSorted);
            int cnt = 0;
            for(char[] previousGuess:previousGuesses) {
                // If the input phrase is the correct phrase it should score the
                // same against previous tries:
                int[] result = guess(previousGuess, phrase, phraseSorted);
                int[] expectedResult = previousResults.get(cnt);
                if (!Arrays.equals(expectedResult, result)) {
                    return false;
                }
                cnt++;
            }
            return true;
        }
    }

    private List<String> createPassPhrases() throws Exception {
        BufferedReader reader = new BufferedReader(new FileReader(new File("pass.txt")));
        List<String> phrases = new ArrayList<String>();
        String input;
        while ((input = reader.readLine()) != null) {
            phrases.add(input);
        }
        return phrases;
    }

    private Map<Integer, List<char[]>> createDictionary() throws Exception {
        BufferedReader reader = new BufferedReader(new FileReader(new File("words.txt")));
        Map<Integer, List<char[]>> wordMap = new HashMap<Integer, List<char[]>>();
        String input;
        while ((input = reader.readLine()) != null) {
            List<char[]> words = wordMap.get(input.length());
            if (words == null) {
                words = new ArrayList<char[]>();
            }
            words.add(input.toCharArray());
            wordMap.put(input.length(), words);
        }
        return wordMap;
    }

}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.