main_testing2/wordle.scala
changeset 439 97594b9998a8
parent 435 fda7c39f3b6a
child 463 0315d9983cd0
equal deleted inserted replaced
438:811cf79546da 439:97594b9998a8
     1 // Resit Part about an Evil Wordle Clone
     1 // Main Part 3 about Evil Wordle
     2 //==========================================
     2 //===============================
     3 //
       
     4 // Task description are on KEATS
       
     5 //
       
     6 // Make sure you use Scala Version 2.13 (not Scala 3)
       
     7 //
       
     8 // Upload your submision to OneSpace and give Senir and Christian
       
     9 // write access to the folder. The folder should have you email
       
    10 // address as name. Give us write permission by July 25th such
       
    11 // that we can download your solution by the closing date August 4th.
       
    12 
     3 
    13 object Resit {
     4 // test bash
       
     5 
       
     6 object M2 { 
    14 
     7 
    15 import io.Source
     8 import io.Source
    16 import scala.util._
     9 import scala.util._
    17 
    10 
    18 //=============================
    11 // ADD YOUR CODE BELOW
    19 // Task 1 [0.25 Marks]
    12 //======================
    20 
    13 
       
    14 // test import
       
    15 
       
    16 
       
    17 //(1)
    21 def get_wordle_list(url: String) : List[String] = {
    18 def get_wordle_list(url: String) : List[String] = {
    22     try{
    19   Try(Source.fromURL(url)("ISO-8859-1").getLines().toList).getOrElse(Nil)
    23 		val raw = Source.fromURL(url).mkString
       
    24 		raw.split("\n").toList
       
    25 	}
       
    26 	catch {
       
    27 		case e : Exception => List[String]()
       
    28     }
       
    29 }
    20 }
    30 
    21 
    31 
    22 
    32 // val secrets = get_wordle_list("https://nms.kcl.ac.uk/christian.urban/wordle.txt")
    23 // val secrets = get_wordle_list("https://nms.kcl.ac.uk/christian.urban/wordle.txt")
    33 // secrets.length => 12972
    24 // secrets.length // => 12972
    34 // secrets.filter(_.length != 5) => Nil
    25 // secrets.filter(_.length != 5) // => Nil
    35 
    26 
    36 //=============================
    27 //(2)
    37 // Task 2 [0.25 Marks]
    28 def removeN[A](xs: List[A], elem: A, n: Int) : List[A] = {
    38 
    29     if (n == 0) xs 
    39 def removeOne[A](xs: List[A], elem: A) : List[A] = {
    30     else xs match {
    40     val index = xs.indexOf(elem)
    31         case Nil => Nil
    41 	val first = xs.take(index)
    32         case x::xs => 
    42 	val second = xs.drop(index + 1)
    33             if (x == elem) removeN(xs, x, n - 1) 
    43 	first ::: second
    34             else x::removeN(xs, elem, n)
    44 }
    35     } 
    45 
    36 }    
    46 // removeOne(List(1,2,3,2,1), 3)  => List(1, 2, 2, 1)
       
    47 // removeOne(List(1,2,3,2,1), 2)  => List(1, 3, 2, 1)
       
    48 // removeOne(List(1,2,3,2,1), 1)  => List(2, 3, 2, 1)
       
    49 // removeOne(List(1,2,3,2,1), 0)  => List(1, 2, 3, 2, 1)
       
    50 
    37 
    51 
    38 
    52 //=============================
    39 // removeN(List(1,2,3,2,1), 3, 1)  // => List(1, 2, 2, 1)
    53 // Task 3 [1.5 Marks]
    40 // removeN(List(1,2,3,2,1), 2, 1)  // => List(1, 3, 2, 1)
       
    41 // removeN(List(1,2,3,2,1), 1, 1)  // => List(2, 3, 2, 1)
       
    42 // removeN(List(1,2,3,2,1), 0, 2)  // => List(1, 2, 3, 2, 1)
    54 
    43 
       
    44 // (3)
    55 abstract class Tip
    45 abstract class Tip
    56 case object Absent extends Tip
    46 case object Absent extends Tip
    57 case object Present extends Tip
    47 case object Present extends Tip
    58 case object Correct extends Tip
    48 case object Correct extends Tip
    59 
    49 
    60 def pool(secret: String, word: String) : List[Char]= {
    50 
       
    51 def pool(secret: String, word: String) : List[Char] = {
    61   for (i <- (0 to 4).toList 
    52   for (i <- (0 to 4).toList 
    62        if secret(i) != word(i))
    53        if secret(i) != word(i))
    63   yield secret(i) 
    54   yield secret(i) 
    64 }
    55 }
    65 
    56 
    66 def aux(secret: List[Char], word: List[Char], pool: List[Char]) : List[Tip] = (secret, word) match {
    57 def aux(secret: List[Char], word: List[Char], pool: List[Char]) : List[Tip] = (secret, word) match {
    67     case (Nil, Nil) => Nil
    58     case (Nil, Nil) => Nil
    68     case (s::srest, w::wrest) => {
    59     case (s::srest, w::wrest) => {
    69         if (s == w) Correct::aux(srest, wrest, pool)
    60         if (s == w) Correct::aux(srest, wrest, pool)
    70         else if (pool.contains(w)) Present::aux(srest, wrest, removeOne(pool, w))
    61         else if (pool.contains(w)) Present::aux(srest, wrest, removeN(pool, w, 1))
    71         else  Absent::aux(srest, wrest, pool)
    62         else  Absent::aux(srest, wrest, pool)
    72     }
    63     }
    73 }
    64 }
    74 
    65 
    75 def score(secret: String, word: String) : List[Tip] =
       
    76     aux(secret.toList, word.toList, pool(secret, word))
       
    77 
    66 
    78 /*
    67 def score(secret: String, word: String) : List[Tip] = 
    79 def pool(secret: String, word: String) : List[Char] = {
    68   aux(secret.toList, word.toList, pool(secret, word))
    80 	(secret zip word).collect {
       
    81 		case (c1, c2) if c1 != c2 => s"$c1"
       
    82 	}.toList.flatten
       
    83 }
       
    84 
       
    85 def aux2(secret: String, word: String, pool: List[Char], result: List[Tip]) : List[Tip] = {
       
    86     if (word.length == 0){
       
    87         result.reverse
       
    88     }
       
    89     else{
       
    90 		if (word.take(1) == secret.take(1)) {
       
    91 			val updated = Correct :: result	
       
    92 			aux2(secret.drop(1), word.drop(1), pool, updated)
       
    93 		}	
       
    94 		else {
       
    95 			if(pool.contains(word.take(1)(0))){
       
    96 				val updated = Present :: result
       
    97 				val removed = removeOne(pool, word.take(1)(0)).mkString.toList 
       
    98 				aux2(secret.drop(1), word.drop(1), removed, updated)
       
    99 			}
       
   100 			else{
       
   101 				val updated = Absent :: result
       
   102 				aux2(secret.drop(1), word.drop(1), pool, updated)
       
   103 			}
       
   104 		}
       
   105 	}
       
   106 }
       
   107 
       
   108 def aux(secret: List[Char], word: List[Char], pool: List[Char]) : List[Tip] = {
       
   109     aux2(secret.mkString, word.mkString, pool, List())
       
   110 }
       
   111 
       
   112 def score(secret: String, word: String) : List[Tip] = {
       
   113     aux(secret.toList, word.toList, pool(secret, word))
       
   114 }
       
   115 */
       
   116 
       
   117 // score("chess", "caves")
       
   118 // score("doses", "slide")
       
   119 // score("chess", "swiss")
       
   120 // score("chess", "eexss")
       
   121 
    69 
   122 
    70 
   123 //=============================
    71 // score("chess", "caves") // => List(Correct, Absent, Absent, Present, Correct)
   124 // Task 4 [0.5 Marks]
    72 // score("doses", "slide") // => List(Present, Absent, Absent, Present, Present)
       
    73 // score("chess", "swiss") // => List(Absent, Absent, Absent, Correct, Correct)
       
    74 // score("chess", "eexss") // => List(Present, Absent, Absent, Correct, Correct)
   125 
    75 
       
    76 // (4)
   126 def eval(t: Tip) : Int = t match {
    77 def eval(t: Tip) : Int = t match {
   127     case Correct => 10
    78     case Correct => 10
   128     case Present => 1
    79     case Present => 1
   129     case Absent => 0
    80     case Absent => 0
   130 }
    81 }
   131 
    82 
   132 def iscore(secret: String, word: String) : Int = {
    83 def iscore(secret: String, word: String) : Int = 
   133     val list = score(secret, word)
    84   score(secret, word).map(eval).sum
   134 	val values = list.map(n => eval(n))
    85 
   135 	values.sum
    86 //iscore("chess", "caves") // => 21
       
    87 //iscore("chess", "swiss") // => 20
       
    88 
       
    89 // (5)
       
    90 def lowest(secrets: List[String], word: String, current: Int, acc: List[String]) : List[String] = secrets match {
       
    91     case Nil => acc
       
    92     case s::srest => {
       
    93         val nscore = iscore(s, word)
       
    94         if (nscore < current) lowest(srest, word, nscore, List(s)) 
       
    95         else if (nscore == current) lowest(srest, word, current, s::acc)
       
    96         else  lowest(srest, word, current, acc)
       
    97     }
   136 }
    98 }
   137 
    99 
   138 // iscore("chess", "caves")
   100 def evil(secrets: List[String], word: String) = 
   139 // iscore("doses", "slide")
   101   lowest(secrets, word, Int.MaxValue, Nil)
   140 // iscore("chess", "swiss")
       
   141 // iscore("chess", "eexss")
       
   142 
       
   143 //=============================
       
   144 // Task 5 [1.5 Mark]
       
   145 
       
   146 def lowest(secrets: List[String], word: String, current: Int, acc: List[String]) : List[String] = {
       
   147     val mapped = secrets.map(x => (x, iscore(x, word)))
       
   148     val min = mapped.minBy(_._2)._2
       
   149     val filt = mapped.filter(_._2 == min)
       
   150     filt.map(x => x._1)
       
   151 }
       
   152 
       
   153 def evil(secrets: List[String], word: String) : List[String] = {
       
   154     lowest(secrets, word, Int.MaxValue, List())
       
   155 }
       
   156 
       
   157 //evil(secrets, "stent").length 
       
   158 //evil(secrets, "hexes").length 
       
   159 //evil(secrets, "horse").length 
       
   160 //evil(secrets, "hoise").length 
       
   161 //evil(secrets, "house").length 
       
   162 
   102 
   163 
   103 
   164 //=============================
   104 //evil(secrets, "stent").length
   165 // Task 6 [1 Mark]
   105 //evil(secrets, "hexes").length
       
   106 //evil(secrets, "horse").length
       
   107 //evil(secrets, "hoise").length
       
   108 //evil(secrets, "house").length
   166 
   109 
       
   110 // (6)
   167 def frequencies(secrets: List[String]) : Map[Char, Double] = {
   111 def frequencies(secrets: List[String]) : Map[Char, Double] = {
   168     val all = secrets.flatten
   112     val all = secrets.flatten
   169     all.groupBy(identity).view.mapValues(1.0D - _.size.toDouble / all.size ).toMap
   113     all.groupBy(identity).view.mapValues(1.0D - _.size.toDouble / all.size ).toMap
   170 }
   114 }
   171 
   115 
   172 //frequencies(secrets)('y')
   116 // (7)
   173 
       
   174 /*
       
   175 
       
   176 def frequencies(secrets: List[String]) : Map[Char, Double] = {
       
   177     val letters = secrets.flatten
       
   178     val totalLetters = letters.length.toDouble
       
   179     val alph = ('a' to 'z').toList
       
   180     val letterCount = alph.map(x => (x, letters.filter(_ == x).length.toDouble))
       
   181     letterCount.map(x => (x._1, 1.0-(letterCount.filter(_._1 == x._1)(0)._2/totalLetters))).toMap
       
   182 }
       
   183 */
       
   184 
       
   185 // frequencies(secrets)('y')
       
   186 // frequencies(secrets)('e')
       
   187 
       
   188 //=============================
       
   189 // Task 7 [1 Mark]
       
   190 
       
   191 def rank(frqs: Map[Char, Double], s: String) = {
   117 def rank(frqs: Map[Char, Double], s: String) = {
   192     s.map(frqs(_)).sum
   118     s.map(frqs(_)).sum
   193 }
   119 }
       
   120 
   194 
   121 
   195 def ranked_evil(secrets: List[String], word: String) = {
   122 def ranked_evil(secrets: List[String], word: String) = {
   196     val frqs = frequencies(secrets)
   123     val frqs = frequencies(secrets)
   197     val ev = evil(secrets, word)
   124     val ev = evil(secrets, word)
   198     ev.groupBy(rank(frqs, _)).toList.sortBy(_._1).reverse.head._2
   125     ev.groupBy(rank(frqs, _)).toList.sortBy(_._1).reverse.head._2
   199 }
   126 }
   200 
   127 
   201 /*
   128 
   202 def rank(frqs: Map[Char, Double], s: String) : Double = {
       
   203     val letters = s.toList
       
   204     val scores = letters.map(x => frqs(x).toDouble)
       
   205     scores.sum
       
   206 }
   129 }
   207 
   130 
   208 def ranked_evil(secrets: List[String], word: String) : List[String] = {
       
   209     val most = evil(secrets, word)
       
   210     val mapped = most.map(x => (x, rank(frequencies(secrets),x)))
       
   211     val mx = mapped.maxBy(_._2)._2
       
   212     val filt = mapped.filter(_._2 == mx)
       
   213     filt.map(x => x._1)
       
   214 }
       
   215 */
       
   216 //rank(frequencies(secrets), "adobe") 
       
   217 //rank(frequencies(secrets), "gaffe") 
       
   218 //rank(frequencies(secrets), "fuzzy") 
       
   219 
   131 
   220 //ranked_evil(secrets, "beats") 
       
   221 //ranked_evil(secrets, "vitae") 
       
   222 //ranked_evil(secrets, "bento") 
       
   223 //ranked_evil(secrets, "belts") 
       
   224 
   132 
   225 }
   133 
       
   134 
       
   135 
       
   136 // This template code is subject to copyright 
       
   137 // by King's College London, 2022. Do not 
       
   138 // make the template code public in any shape 
       
   139 // or form, and do not exchange it with other 
       
   140 // students under any circumstance.