7 import io.Source  | 
     7 import io.Source  | 
     8 import scala.util._  | 
     8 import scala.util._  | 
     9   | 
     9   | 
    10 // ADD YOUR CODE BELOW  | 
    10 // ADD YOUR CODE BELOW  | 
    11 //======================  | 
    11 //======================  | 
    12 // def main(args: Array[String]): Unit = { | 
         | 
    13   | 
    12   | 
    14 //     val secrets = get_wordle_list("https://nms.kcl.ac.uk/christian.urban/wordle.txt") | 
         | 
    15 //     println(ranked_evil(secrets, "beats")== List("fuzzy")) | 
         | 
    16 //     println(ranked_evil(secrets, "vitae") == List("fuzzy")) | 
         | 
    17 //     println(ranked_evil(secrets, "bento") == List("fuzzy")) | 
         | 
    18 //     println(ranked_evil(secrets, "belts") == List("fuzzy")) | 
         | 
    19 //     println(ranked_evil(secrets, "abbey") == List("whizz")) | 
         | 
    20 //     println(ranked_evil(secrets, "afear") == List("buzzy")) | 
         | 
    21 //     println(ranked_evil(secrets, "zincy") == List("jugum")) | 
         | 
    22 //     println(ranked_evil(secrets, "zippy") == List("chuff")) | 
         | 
    23      | 
         | 
    24       | 
         | 
    25 //    }  | 
         | 
    26   | 
    13   | 
    27 //(1)  | 
    14 //(1)  | 
    28 def get_wordle_list(url: String) : List[String] = { | 
    15 def get_wordle_list(url: String) : List[String] = { | 
    29     try { | 
    16     Try(Source.fromURL(url).getLines.toList).getOrElse(List())  | 
    30         Source.fromURL(url).getLines.toList;  | 
         | 
    31     }  | 
         | 
    32     catch { | 
         | 
    33         case _ : Throwable => List();  | 
         | 
    34     }      | 
         | 
    35 }  | 
    17 }  | 
         | 
    18   | 
    36 // val secrets = get_wordle_list("https://nms.kcl.ac.uk/christian.urban/wordle.txt") | 
    19 // val secrets = get_wordle_list("https://nms.kcl.ac.uk/christian.urban/wordle.txt") | 
    37 // secrets.length // => 12972  | 
    20 // secrets.length // => 12972  | 
    38 // secrets.filter(_.length != 5) // => Nil  | 
    21 // secrets.filter(_.length != 5) // => Nil  | 
    39   | 
    22   | 
    40 //(2)  | 
    23 //(2)   | 
    41 def removeN[A](xs: List[A], elem: A, n: Int) : List[A] = { | 
    24 def removeN[A](xs: List[A], elem: A, n: Int) : List[A] = xs match { | 
    42     if (xs.isEmpty || n == 0 || !xs.contains(elem)){ | 
    25     case Nil => Nil  | 
    43         xs  | 
    26     case x :: tail if x == elem && n > 0 => removeN(tail, elem, n - 1)  | 
    44     }  | 
    27     case x :: tail => x :: removeN(tail, elem, n)  | 
    45     else{ | 
         | 
    46         val (newLst,newLst2) = xs.splitAt(xs.indexOf(elem))  | 
         | 
    47         removeN(newLst ++ newLst2.tail,elem, n-1)  | 
         | 
    48     }  | 
         | 
    49 }  | 
    28 }  | 
         | 
    29   | 
    50   | 
    30   | 
    51 // removeN(List(1,2,3,2,1), 3, 1)  // => List(1, 2, 2, 1)  | 
    31 // removeN(List(1,2,3,2,1), 3, 1)  // => List(1, 2, 2, 1)  | 
    52 // removeN(List(1,2,3,2,1), 2, 1)  // => List(1, 3, 2, 1)  | 
    32 // removeN(List(1,2,3,2,1), 2, 1)  // => List(1, 3, 2, 1)  | 
    53 // removeN(List(1,2,3,2,1), 1, 1)  // => List(2, 3, 2, 1)  | 
    33 // removeN(List(1,2,3,2,1), 1, 1)  // => List(2, 3, 2, 1)  | 
    54 // removeN(List(1,2,3,2,1), 0, 2)  // => List(1, 2, 3, 2, 1)  | 
    34 // removeN(List(1,2,3,2,1), 0, 2)  // => List(1, 2, 3, 2, 1)  | 
    59 case object Present extends Tip  | 
    39 case object Present extends Tip  | 
    60 case object Correct extends Tip  | 
    40 case object Correct extends Tip  | 
    61   | 
    41   | 
    62   | 
    42   | 
    63 def pool(secret: String, word: String) : List[Char] = { | 
    43 def pool(secret: String, word: String) : List[Char] = { | 
    64     //print(secret.toList, word.toList)  | 
    44     (for(index <- (0 to word.length-1); if (word(index) != secret(index))) yield secret(index).toChar).toList  | 
    65     val lst= ((0 to 4).map(x => { | 
         | 
    66         if(!secret(x).equals(word(x))) Some(secret(x)) else None  | 
         | 
    67           | 
         | 
    68         }).toList)  | 
         | 
    69     lst.flatten  | 
         | 
    70 }  | 
    45 }  | 
    71   | 
    46 // t  | 
    72   | 
         | 
    73 def aux(secret: List[Char], word: List[Char], pool: List[Char]) : List[Tip] = { | 
    47 def aux(secret: List[Char], word: List[Char], pool: List[Char]) : List[Tip] = { | 
    74      | 
    48     if (secret.isEmpty) List()  | 
    75     if (secret.length == 1){ | 
         | 
    76         if (secret.head == word.head){ | 
         | 
    77             List(Correct)  | 
         | 
    78         }  | 
         | 
    79         else if (pool.contains(word.head)){ | 
         | 
    80             List(Present)   | 
         | 
    81         }  | 
         | 
    82         else { | 
         | 
    83             List(Absent)   | 
         | 
    84         }  | 
         | 
    85     }  | 
         | 
    86     else if (secret.head == word.head){ | 
         | 
    87         List(Correct) ++ aux(secret.tail, word.tail, pool)  | 
         | 
    88     }  | 
         | 
    89     else if (pool.contains(word.head)){ | 
         | 
    90         List(Present) ++ aux(secret.tail, word.tail, removeN(pool, word.head, 1))  | 
         | 
    91     }  | 
         | 
    92     else { | 
    49     else { | 
    93         List(Absent) ++ aux(secret.tail, word.tail, pool)  | 
    50         if (secret.head == word.head) Correct :: aux(secret.tail, word.tail, pool)  | 
         | 
    51         else if (pool.contains(word.head)) Present :: aux(secret.tail, word.tail, pool.filterNot(_ == word.head))  | 
         | 
    52         else Absent :: aux(secret.tail, word.tail, pool)  | 
    94     }  | 
    53     }  | 
    95 }  | 
    54 }  | 
    96   | 
    55   | 
    97 def score(secret: String, word: String) : List[Tip] = { | 
    56 def score(secret: String, word: String) : List[Tip] = aux(secret.toList, word.toList, pool(secret, word))  | 
    98     aux(secret.toList,word.toList,pool(secret,word))  | 
         | 
    99 }  | 
         | 
   100   | 
    57   | 
   101   | 
    58   | 
   102 // score("chess", "caves") // => List(Correct, Absent, Absent, Present, Correct) | 
    59 // score("chess", "caves") // => List(Correct, Absent, Absent, Present, Correct) | 
   103 // score("doses", "slide") // => List(Present, Absent, Absent, Present, Present) | 
    60 // score("doses", "slide") // => List(Present, Absent, Absent, Present, Present) | 
   104 // score("chess", "swiss") // => List(Absent, Absent, Absent, Correct, Correct) | 
    61 // score("chess", "swiss") // => List(Absent, Absent, Absent, Correct, Correct) | 
   105 // score("chess", "eexss") // => List(Present, Absent, Absent, Correct, Correct) | 
    62 // score("chess", "eexss") // => List(Present, Absent, Absent, Correct, Correct) | 
   106   | 
    63   | 
   107 // (4)  | 
    64 // (4)  | 
   108 def eval(t: Tip) : Int = { | 
    65 def eval(t: Tip) : Int = t match { | 
   109     if (t == Correct) 10  | 
    66     case Correct => 10  | 
   110     else if (t == Present) 1  | 
    67     case Present => 1  | 
   111     else 0  | 
    68     case Absent => 0   | 
   112 }  | 
    69 }  | 
   113   | 
    70   | 
   114 def iscore(secret: String, word: String) : Int = { | 
    71 def iscore(secret: String, word: String) : Int =  (for(current <- score(secret, word)) yield eval(current)).sum  | 
   115     val scoreList = score(secret,word)  | 
    72       | 
   116     scoreList.map(x =>(eval(x))).toList.sum  | 
         | 
   117 }  | 
         | 
   118   | 
    73   | 
   119 //iscore("chess", "caves") // => 21 | 
    74 //iscore("chess", "caves") // => 21 | 
   120 //iscore("chess", "swiss") // => 20 | 
    75 //iscore("chess", "swiss") // => 20 | 
   121   | 
    76   | 
   122 // (5)  | 
    77 // (5) t  | 
   123 def lowest(secrets: List[String], word: String, current: Int, acc: List[String]) : List[String] = { | 
    78 def lowest(secrets: List[String], word: String, current: Int, acc: List[String]) : List[String] = { | 
   124     if(secrets.isEmpty) acc  | 
    79     if (secrets.isEmpty) acc  | 
   125     else if (iscore(secrets.head,word)<current){ | 
    80     else { | 
   126         lowest(secrets.tail, word, iscore(secrets.head,word), List(secrets.head))  | 
    81         val score = iscore(secrets.head, word)  | 
         | 
    82           | 
         | 
    83         if (score == current) lowest(secrets.tail, word, current, secrets.head :: acc)  | 
         | 
    84         else if (score < current) lowest(secrets.tail, word, score, List(secrets.head))  | 
         | 
    85         else lowest(secrets.tail, word, current, acc)  | 
   127     }  | 
    86     }  | 
   128     else if (iscore(secrets.head,word)==current){ | 
         | 
   129         lowest(secrets.tail, word, current, acc :+ secrets.head)  | 
         | 
   130     }  | 
         | 
   131     else { | 
         | 
   132         lowest(secrets.tail, word, current, acc)  | 
         | 
   133     }  | 
         | 
   134   | 
         | 
   135 }  | 
    87 }  | 
   136   | 
    88   | 
   137 def evil(secrets: List[String], word: String) = { | 
    89 def evil(secrets: List[String], word: String) = lowest(secrets, word, Int.MaxValue ,List())  | 
   138     lowest(secrets, word, 100, List())  | 
         | 
   139 }  | 
         | 
   140   | 
    90   | 
   141   | 
    91   | 
   142 //evil(secrets, "stent").length  | 
    92 //evil(secrets, "stent").length  | 
   143 //evil(secrets, "hexes").length  | 
    93 //evil(secrets, "hexes").length  | 
   144 //evil(secrets, "horse").length  | 
    94 //evil(secrets, "horse").length  | 
   145 //evil(secrets, "hoise").length  | 
    95 //evil(secrets, "hoise").length  | 
   146 //evil(secrets, "house").length  | 
    96 //evil(secrets, "house").length  | 
   147   | 
    97   | 
   148 // (6)  | 
    98 // (6) t  | 
   149 def frequencies(secrets: List[String]) : Map[Char, Double] = { | 
    99 def frequencies(secrets: List[String]) : Map[Char, Double] = { | 
   150     val totalChar = secrets.flatMap(_.toList).size.toDouble  | 
   100     val occurrences = secrets.mkString.groupBy(identity).mapValues(_.length)  | 
   151     val freqMap = secrets.flatMap(_.toList).groupBy(identity)  | 
   101     val all_letters = secrets.mkString.length.toDouble  | 
   152     freqMap.map(x => (x._1, (1-(x._2.size.toDouble/ totalChar))))  | 
   102     occurrences.map{ case (c, n) => c -> (1 - n/all_letters) }.toMap | 
   153   | 
         | 
   154 }  | 
   103 }  | 
   155   | 
   104   | 
   156 // (7)  | 
   105 // (7)   | 
   157 def rank(frqs: Map[Char, Double], s: String) = { | 
   106 def rank(frqs: Map[Char, Double], s: String) : Double = s.map(c => frqs(c)).sum  | 
   158     s.map(x => (frqs(x))).toList.sum  | 
         | 
   159 }  | 
         | 
   160   | 
         | 
   161 def ranked_evil(secrets: List[String], word: String) : List[String]= { | 
         | 
   162     val evilWords = evil(secrets,word)  | 
         | 
   163     val returnVal = evilWords.map(x => (x, rank(frequencies(secrets),x))).toMap.maxBy(_._2)._1  | 
         | 
   164     List(returnVal)  | 
         | 
   165 }  | 
         | 
   166   | 
   107   | 
   167   | 
   108   | 
         | 
   109 def ranked_evil(secrets: List[String], word: String): List[String] = { | 
         | 
   110     val frqs = frequencies(secrets)  | 
         | 
   111     val ranked_secrets = evil(secrets, word).map(s => (s, rank(frqs, s)))  | 
         | 
   112     List((ranked_secrets.sortWith(_._2 > _._2)).map(_._1).head )  | 
         | 
   113 }  | 
         | 
   114       | 
   168 }  | 
   115 }  | 
   169   | 
   116   | 
   170   | 
   117   | 
   171   | 
   118   | 
   172   | 
   119   |