added
authorChristian Urban <christian.urban@kcl.ac.uk>
Mon, 11 Apr 2022 23:55:27 +0100
changeset 424 daf561a83ba6
parent 423 e9d14d58be3c
child 425 957808dcb367
added
README
core_marking1/collatz.scala
core_marking1/collatz_test.sh
core_marking1/collatz_test1.scala
core_marking1/collatz_test2.scala
core_marking1/collatz_test3.scala
core_marking1/mk_core1
core_marking2/docdiff.scala
core_marking2/docdiff_test.sh
core_marking2/docdiff_test1.scala
core_marking2/docdiff_test2.scala
core_marking2/docdiff_test3.scala
core_marking2/docdiff_test4.scala
core_marking2/mk_core2
core_marking3/mk_core3
core_marking3/postfix.scala
core_marking3/postfix2.scala
core_marking3/postfix_test.sh
core_marking3/postfix_test1.scala
core_marking3/postfix_test2.scala
core_marking3/postfix_test3.scala
core_marking3/postfix_test4.scala
cws/core_cw01.pdf
cws/core_cw02.pdf
cws/core_cw03.pdf
cws/cw03.pdf
cws/cw04.pdf
cws/cw05.pdf
cws/cw06.pdf
cws/disclaimer.sty
cws/main_cw01.pdf
cws/main_cw02.pdf
cws/main_cw03.pdf
cws/main_cw03.tex
cws/main_cw04.pdf
cws/main_cw05.pdf
main_marking1/drumb.scala
main_marking1/drumb_test.sh
main_marking1/drumb_test1.scala
main_marking1/drumb_test2.scala
main_marking1/drumb_test3.scala
main_marking1/drumb_test4.scala
main_marking1/drumb_test5.scala
main_marking1/drumb_test6.scala
main_marking1/drumb_test7.scala
main_marking1/mk
main_marking1/mk_main1
main_marking2/danube_test.sh
main_marking2/danube_test1.scala
main_marking2/danube_test2.scala
main_marking2/danube_test3.scala
main_marking2/danube_test4.scala
main_marking2/danube_test5.scala
main_marking2/danube_test6.scala
main_marking2/danube_test7a.scala
main_marking2/danube_test7b.scala
main_marking2/mk
main_marking2/mk_main2
main_marking3/mk
main_marking3/mk_main3
main_marking3/re.scala
main_marking3/re_test.sh
main_marking3/re_test1.scala
main_marking3/re_test2.scala
main_marking3/re_test3.scala
main_marking3/re_test3a.scala
main_marking3/re_test4.scala
main_marking3/re_test5.scala
main_marking3/re_test6.scala
main_marking3/re_test7.scala
main_marking4/knight1.scala
main_marking4/knight1_test1.scala
main_marking4/knight1_test2.scala
main_marking4/knight1_test3a.scala
main_marking4/knight1_test3b.scala
main_marking4/knight1_test3c.scala
main_marking4/knight1_test4.scala
main_marking4/knight1_test5.scala
main_marking4/knight2.scala
main_marking4/knight2_test.sh
main_marking4/knight2_test6.scala
main_marking4/knight2_test7.scala
main_marking4/knight2_test8.scala
main_marking4/knight3.scala
main_marking4/knight3_test9.scala
main_marking4/knight_test.sh
main_marking4/mk
main_marking4/mk_main4
main_marking5/bf.scala
main_marking5/bf_test.sh
main_marking5/bf_test1.scala
main_marking5/bf_test2.scala
main_marking5/bf_test3.scala
main_marking5/bf_test4.scala
main_marking5/bf_test4b.scala
main_marking5/bf_test5.scala
main_marking5/bf_test6.scala
main_marking5/bf_test7.scala
main_marking5/bfc.scala
main_marking5/mk
main_marking5/mk_main5
main_solution3/re.scala
main_solution5/bf.scala
main_templates3/re.scala
main_testing2/danube_test.sh
main_testing3/re.scala
main_testing3/re_test.sh
main_testing4/knight1.scala
pre_marking1/collatz.scala
pre_marking1/collatz_test.sh
pre_marking1/collatz_test1.scala
pre_marking1/collatz_test2.scala
pre_marking1/collatz_test3.scala
pre_marking1/mk
pre_marking2/docdiff.scala
pre_marking2/docdiff_test.sh
pre_marking2/docdiff_test1.scala
pre_marking2/docdiff_test2.scala
pre_marking2/docdiff_test3.scala
pre_marking2/docdiff_test4.scala
pre_marking2/mk
pre_marking3/mk
pre_marking3/postfix.scala
pre_marking3/postfix2.scala
pre_marking3/postfix_test.sh
pre_marking3/postfix_test1.scala
pre_marking3/postfix_test2.scala
pre_marking3/postfix_test3.scala
pre_marking3/postfix_test4.scala
pre_marking4/knight1_test.sh
pre_marking4/knight1_test1.scala
pre_marking4/knight1_test2.scala
pre_marking4/knight1_test3a.scala
pre_marking4/knight1_test3b.scala
pre_marking4/knight1_test3c.scala
progs/mandelbrot3.sc
--- a/README	Thu Jan 13 12:55:03 2022 +0000
+++ b/README	Mon Apr 11 23:55:27 2022 +0100
@@ -1,3 +1,12 @@
+https://github.com/5CCS2PEP/assignment2021scala-shrisiva02/issues/30
+
+Screenshot 2022-01-13 at 21.15.00
+
+problems with .vscode in files
+
+=============
+
+
 TA meeting
 
 https://web.microsoftstream.com/video/cec0d34d-77f5-4940-9bad-628416d4c521
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking1/collatz.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,51 @@
+// Core Part 1 about the 3n+1 conjecture
+//==================================
+
+// generate jar with
+//   > scala -d collatz.jar  collatz.scala
+
+object C1 { // for purposes of generating a jar
+
+def collatz(n: Long): Long =
+  if (n == 1) 0 else
+    if (n % 2 == 0) 1 + collatz(n / 2) else 
+      1 + collatz(3 * n + 1)
+
+
+def collatz_max(bnd: Long): (Long, Long) = {
+  val all = for (i <- (1L to bnd)) yield (collatz(i), i)
+  all.maxBy(_._1)
+}
+
+//collatz_max(1000000)
+
+
+/* some test cases
+val bnds = List(10, 100, 1000, 10000, 100000, 1000000)
+
+for (bnd <- bnds) {
+  val (steps, max) = collatz_max(bnd)
+  println(s"In the range of 1 - ${bnd} the number ${max} needs the maximum steps of ${steps}")
+}
+
+*/
+
+
+def is_pow(n: Long) : Boolean = (n & (n - 1)) == 0
+
+def is_hard(n: Long) : Boolean = is_pow(3 * n + 1)
+
+def last_odd(n: Long) : Long = 
+  if (is_hard(n)) n else
+    if (n % 2 == 0) last_odd(n / 2) else 
+      last_odd(3 * n + 1)
+
+
+
+//for (i <- 130 to 10000) println(s"$i: ${last_odd(i)}")
+//for (i <- 1 to 100) println(s"$i: ${collatz(i)}")
+
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking1/collatz_test.sh	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,145 @@
+#!/bin/bash
+
+# to make the script fail safely
+set -euo pipefail
+
+
+out=${1:-output}
+
+echo -e "" > $out
+
+echo `date` | tee -a $out
+echo "" >> $out
+echo "Below is the feedback and provisional marks for your submission" >> $out
+echo "for the Core Part 1 (Scala).  Please note all marks are provisional until" >> $out
+echo "ratified by the assessment board -- this is not an official" >> $out
+echo "results transcript." >> $out
+echo "" >> $out
+
+echo "The feedback for your submission for collatz.scala" >> $out
+echo "" >> $out
+
+# marks for core part 1
+marks=$(( 0 ))
+
+# compilation tests
+
+function scala_compile {
+  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -Xprint:parser "$1" 2> c$out 1> c$out)
+}
+
+# functional tests
+
+function scala_assert {
+  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -nc -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)
+}
+ 
+# purity test
+function scala_vars {
+   (sed 's/immutable/ok/g' c$out > cb$out;
+    egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' cb$out 2> /dev/null 1> /dev/null)
+}
+
+
+### compilation test
+
+echo -e "collatz.scala runs?" >> $out
+
+if (scala_compile collatz.scala)
+then
+    echo -e "  --> success" >> $out
+    tsts0=$(( 0 ))
+else
+    echo -e "  --> SCALA DID NOT RUN collatz.scala\n" >> $out
+    tsts0=$(( 1 )) 
+fi
+
+# var, .par return, ListBuffer test
+#
+
+if  [ $tsts0 -eq 0 ]
+then
+   echo -e "collatz.scala does not contain VARS, RETURNS etc?" >> $out
+    
+   if (scala_vars collatz.scala)
+   then
+      echo -e "  --> test failed\n" >> $out
+      tsts=$(( 1 ))
+   else
+      echo -e "  --> success" >> $out
+      tsts=$(( 0 )) 
+   fi
+else
+   tsts=$(( 1 ))  
+fi    
+
+
+echo >> $out
+
+### collatz tests
+
+if [ $tsts -eq 0 ]
+then
+  echo "collatz.scala tests:"  | tee -a $out
+  echo "  collatz(1) == 0"     | tee -a $out
+  echo "  collatz(6) == 8"     | tee -a $out
+  echo "  collatz(9) == 19"    | tee -a $out
+  echo "  collatz(9000) == 47" | tee -a $out
+
+  if (scala_assert "collatz.scala" "collatz_test1.scala")
+  then
+      echo "  --> success" | tee -a $out
+      marks=$(( marks + 1 ))
+  else
+    echo "  --> one of the tests failed" | tee -a $out
+  fi
+fi
+
+### collatz-max tests
+
+if [ $tsts -eq 0 ]
+then
+  echo "  collatz_max(10) == (19, 9)" | tee -a $out
+  echo "  collatz_max(100) == (118, 97)" | tee -a $out
+  echo "  collatz_max(1000) == (178, 871)" | tee -a $out
+  echo "  collatz_max(10000) == (261, 6171)" | tee -a $out
+  echo "  collatz_max(100000) == (350, 77031)" | tee -a $out
+  echo "  collatz_max(1000000) == (524, 837799)" | tee -a $out
+  #  echo "  collatz_max(2) == (1, 2) || collatz_max(2) == (0, 1)" | tee -a $out
+  echo "  collatz_max(2) == (1, 2)" | tee -a $out
+  echo "  collatz_max(77000) == (339, 52527)" | tee -a $out
+
+  if (scala_assert "collatz.scala" "collatz_test2.scala") 
+  then
+      echo "  --> success" | tee -a $out
+      marks=$(( marks + 1 ))
+  else
+    echo "  --> one of the tests failed" | tee -a $out
+  fi
+fi
+
+### last-odd tests
+
+if [ $tsts -eq 0 ]
+then
+  echo "  last_odd(113) == 85" | tee -a $out
+  echo "  last_odd(84) == 21" | tee -a $out
+  echo "  last_odd(605) == 341" | tee -a $out
+
+  if (scala_assert "collatz.scala" "collatz_test3.scala") 
+  then
+      echo "  --> success" | tee -a $out
+      marks=$(( marks + 1 ))
+  else
+    echo "  --> one of the tests failed" | tee -a $out
+  fi
+fi
+
+
+
+## final marks
+echo >> $out
+echo "Overall mark for the Core Part 1 (Scala)" | tee -a $out
+echo " $marks" | tee -a $out
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking1/collatz_test1.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,8 @@
+
+
+assert(C1.collatz(1) == 0)
+assert(C1.collatz(6) == 8)
+assert(C1.collatz(9) == 19)
+assert(C1.collatz(9000) == 47)
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking1/collatz_test2.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,10 @@
+import C1._
+
+assert(collatz_max(10) == (19, 9))
+assert(collatz_max(100) == (118, 97))
+assert(collatz_max(1000) == (178, 871))
+assert(collatz_max(10000) == (261, 6171))
+assert(collatz_max(100000) == (350, 77031))
+assert(collatz_max(1000000) == (524, 837799))
+assert(collatz_max(2) == (1, 2))
+assert(collatz_max(77000) == (339, 52527))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking1/collatz_test3.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,4 @@
+
+assert(C1.last_odd(113) == 85)
+assert(C1.last_odd(84) == 21)
+assert(C1.last_odd(605) == 341)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking1/mk_core1	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,26 @@
+#!/bin/bash
+set -euo pipefail
+
+trap "exit" INT
+
+files=${1:-*/core1}
+
+for sd in $files; do
+  echo -e "\n"
+  cd $sd
+  echo $sd
+  touch .
+  cp ../../../../../core_marking1/collatz_test.sh .
+  cp ../../../../../core_marking1/collatz_test1.scala .
+  cp ../../../../../core_marking1/collatz_test2.scala .
+  cp ../../../../../core_marking1/collatz_test3.scala .
+  ./collatz_test.sh output
+  rm collatz_test.sh
+  rm collatz_test1.scala
+  rm collatz_test2.scala
+  rm collatz_test3.scala
+  cd ..
+  cd ..
+done
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking2/docdiff.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,117 @@
+// Preliminary Part about Code Similarity
+//========================================
+
+
+object C2 { 
+
+//(1) Complete the clean function below. It should find
+//    all words in a string using the regular expression
+//    \w+  and the library function 
+//
+//         some_regex.findAllIn(some_string)
+//
+//    The words should be Returned as a list of strings.
+
+def clean(s: String) : List[String] = 
+  ("""\w+""".r).findAllIn(s).toList
+
+
+//(2) The function occurrences calculates the number of times  
+//    strings occur in a list of strings. These occurrences should 
+//    be calculated as a Map from strings to integers.
+
+def occurrences(xs: List[String]): Map[String, Int] =
+  (for (x <- xs.distinct) yield (x, xs.count(_ == x))).toMap
+
+//(3) This functions calculates the dot-product of two documents
+//    (list of strings). For this it calculates the occurrence
+//    maps from (2) and then multiplies the corresponding occurrences. 
+//    If a string does not occur in a document, the product is zero.
+//    The function finally sums up all products. 
+
+def prod(lst1: List[String], lst2: List[String]) : Int = {
+    val words = (lst1 ::: lst2).distinct
+    val occs1 = occurrences(lst1)
+    val occs2 = occurrences(lst2)
+    words.map{ w => occs1.getOrElse(w, 0) * occs2.getOrElse(w, 0) }.sum
+}          
+
+//(4) Complete the functions overlap and similarity. The overlap of
+//    two documents is calculated by the formula given in the assignment
+//    description. The similarity of two strings is given by the overlap
+//    of the cleaned (see (1)) strings.  
+
+def overlap(lst1: List[String], lst2: List[String]) : Double = {
+    val m1 = prod(lst1, lst1)
+    val m2 = prod(lst2, lst2) 
+    prod(lst1, lst2).toDouble / (List(m1, m2).max)
+}
+
+def similarity(s1: String, s2: String) : Double =
+  overlap(clean(s1), clean(s2))
+
+
+/*
+
+
+val list1 = List("a", "b", "b", "c", "d") 
+val list2 = List("d", "b", "d", "b", "d")
+
+occurrences(List("a", "b", "b", "c", "d"))   // Map(a -> 1, b -> 2, c -> 1, d -> 1)
+occurrences(List("d", "b", "d", "b", "d"))   // Map(d -> 3, b -> 2)
+
+prod(list1,list2) // 7 
+
+overlap(list1, list2)   // 0.5384615384615384
+overlap(list2, list1)   // 0.5384615384615384
+overlap(list1, list1)   // 1.0
+overlap(list2, list2)   // 1.0
+
+// Plagiarism examples from 
+// https://desales.libguides.com/avoidingplagiarism/examples
+
+val orig1 = """There is a strong market demand for eco-tourism in
+Australia. Its rich and diverse natural heritage ensures Australia's
+capacity to attract international ecotourists and gives Australia a
+comparative advantage in the highly competitive tourism industry."""
+
+val plag1 = """There is a high market demand for eco-tourism in
+Australia. Australia has a comparative advantage in the highly
+competitive tourism industry due to its rich and varied natural
+heritage which ensures Australia's capacity to attract international
+ecotourists."""
+
+similarity(orig1, plag1)
+
+
+// Plagiarism examples from 
+// https://www.utc.edu/library/help/tutorials/plagiarism/examples-of-plagiarism.php
+
+val orig2 = """No oil spill is entirely benign. Depending on timing and
+location, even a relatively minor spill can cause significant harm to
+individual organisms and entire populations. Oil spills can cause
+impacts over a range of time scales, from days to years, or even
+decades for certain spills. Impacts are typically divided into acute
+(short-term) and chronic (long-term) effects. Both types are part of a
+complicated and often controversial equation that is addressed after
+an oil spill: ecosystem recovery."""
+
+val plag2 = """There is no such thing as a "good" oil spill. If the
+time and place are just right, even a small oil spill can cause damage
+to sensitive ecosystems. Further, spills can cause harm days, months,
+years, or even decades after they occur. Because of this, spills are
+usually broken into short-term (acute) and long-term (chronic)
+effects. Both of these types of harm must be addressed in ecosystem
+recovery: a controversial tactic that is often implemented immediately
+following an oil spill."""
+
+overlap(clean(orig2), clean(plag2))
+similarity(orig2, plag2)
+
+// The punchline: everything above 0.6 looks suspicious and 
+// should be looked at by staff.
+
+*/
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking2/docdiff_test.sh	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,171 @@
+#!/bin/zsh
+
+# to make the script fail safely
+set -euo pipefail
+
+
+out=${1:-output}
+
+echo "" > $out
+
+echo `date` >> $out
+echo -e "Below is the feedback and provisional marks for your submission" >> $out
+echo -e "for the Core Part 2 (Scala).  Please note all marks are provisional until" >> $out
+echo -e "ratified by the assessment board -- this is not an official" >> $out
+echo -e "results transcript." >> $out
+echo -e "" >> $out
+
+echo -e "Below is the feedback for your submission docdiff.scala" >> $out
+echo -e "" >> $out
+
+# marks for C2 core part
+marks=$(( 0.0 ))
+
+
+# compilation tests
+
+function scala_compile {
+  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -Xprint:parser "$1" 2> c$out 1> c$out)
+}
+
+# functional tests
+
+function scala_assert {
+  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -nc -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)
+}
+
+# purity test
+function scala_vars {
+   (sed 's/immutable/ok/g' c$out > cb$out;
+    egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' cb$out 2> /dev/null 1> /dev/null)
+}
+
+
+
+### compilation test
+
+echo -e "docdiff.scala runs?" |  tee -a $out
+
+if (scala_compile docdiff.scala)
+then
+    echo -e "  --> success" |  tee -a $out
+    tsts=$(( 0 ))
+else
+    echo -e "  --> SCALA DID NOT RUN docdiff.scala\n" |  tee -a $out
+    tsts=$(( 1 )) 
+fi
+
+
+# var, .par return, ListBuffer test
+#
+
+if  [ $tsts -eq 0 ]
+then     
+   echo -e "docdiff.scala does not contain VARS, RETURNS etc?" |  tee -a $out
+
+   if (scala_vars docdiff.scala)
+   then
+      echo -e "  --> test failed\n" | tee -a $out  
+      tsts=$(( 1 ))
+   else
+      echo -e "  --> success" |  tee -a $out
+      tsts=$(( 0 )) 
+   fi
+else
+   tsts=$(( 1 ))  
+fi 
+
+echo >> $out
+
+
+### docdiff clean tests
+
+if [ $tsts -eq 0 ]
+then
+  echo -e "docdiff.scala tests:" |  tee -a $out
+  echo -e "  clean(\"ab a abc\") == List(\"ab\", \"a\", \"abc\")" |  tee -a $out
+  echo -e "  clean(\"ab*a abc1\") == List(\"ab\", \"a\", \"abc1\")" |  tee -a $out
+
+  if (scala_assert "docdiff.scala" "docdiff_test1.scala")
+  then
+      echo -e "  --> success" |  tee -a $out
+      marks=$(( marks + 0.5 ))
+  else
+      echo -e "  --> ONE OF THE TESTS FAILED\n" |  tee -a $out
+  fi
+fi
+
+### docdiff occurrences tests
+
+if [ $tsts -eq 0 ]
+then
+  echo -e "  occurrences(List(\"a\", \"b\", \"b\", \"c\", \"d\")) == " |  tee -a $out
+  echo -e "      Map(\"a\" -> 1, \"b\" -> 2, \"c\" -> 1, \"d\" -> 1)"  |  tee -a $out
+  echo -e "  " |  tee -a $out
+  echo -e "  occurrences(List(\"d\", \"b\", \"d\", \"b\", \"d\")) == " |  tee -a $out
+  echo -e "      Map(\"d\" -> 3, \"b\" -> 2)" |  tee -a $out
+  echo -e "  " |  tee -a $out
+  echo -e "  occurrences(Nil) == Map() " |  tee -a $out
+  echo -e "  " |  tee -a $out
+  echo -e "  occurrences(List(\"b\", \"b\", \"b\", \"b\", \"b\")) == Map(\"b\" -> 5)" |  tee -a $out
+
+  if (scala_assert "docdiff.scala" "docdiff_test2.scala") 
+  then
+      echo -e "  --> success" |  tee -a $out
+      marks=$(( marks + 1.0 ))
+  else
+      echo -e "  --> ONE OF THE TESTS FAILED\n" |  tee -a $out
+  fi
+fi
+
+### docdiff prod tests
+
+if [ $tsts -eq 0 ]
+then
+  echo -e "  val l1 = List(\"a\", \"b\", \"b\", \"c\", \"d\")" |  tee -a $out
+  echo -e "  val l2 = List(\"d\", \"b\", \"d\", \"b\", \"d\")" |  tee -a $out
+  echo -e "  " |  tee -a $out
+  echo -e "  prod(l1, l2) == 7 " |  tee -a $out
+  echo -e "  prod(l1, l1) == 7 " |  tee -a $out
+  echo -e "  prod(l2, l2) == 13 " |  tee -a $out
+  echo -e "  " |  tee -a $out
+  echo -e "  val l3 = List(\"1\", \"2\", \"3\", \"4\", \"5\")" |  tee -a $out
+  echo -e "  prod(l1, l3) == 0 " |  tee -a $out
+
+  if (scala_assert "docdiff.scala" "docdiff_test3.scala") 
+  then
+      echo -e "  --> success" |  tee -a $out
+      marks=$(( marks + 1.0 ))
+  else
+      echo -e "  --> ONE OF THE TESTS FAILED\n" |  tee -a $out
+  fi
+fi
+
+### docdiff overlap tests
+
+if [ $tsts -eq 0 ]
+then
+  echo -e "  val l1 = List(\"a\", \"b\", \"b\", \"c\", \"d\")" |  tee -a $out
+  echo -e "  val l2 = List(\"d\", \"b\", \"d\", \"b\", \"d\")" |  tee -a $out
+  echo -e "  " |  tee -a $out
+  echo -e "  overlap(l1, l2) == 0.5384615384615384 " |  tee -a $out
+  echo -e "  overlap(l1, l1) == 1.0 " |  tee -a $out
+  echo -e "  overlap(l2, l2) == 1.0 " |  tee -a $out
+
+  if (scala_assert "docdiff.scala" "docdiff_test4.scala") 
+  then
+      echo -e "  --> success" |  tee -a $out
+      marks=$(( marks + 0.5 ))
+  else
+      echo -e "  --> ONE OF THE TESTS FAILED\n" |  tee -a $out
+  fi
+fi
+
+
+## final marks
+echo -e "Overall mark for the Core Part 2 (Scala)" | tee -a $out
+printf " %0.1f\n" $marks | tee -a $out
+
+
+#echo -e " $marks" | tee -a $out
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking2/docdiff_test1.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,4 @@
+import C2._
+
+assert(clean("ab a abc") == List("ab", "a", "abc"))
+assert(clean("ab*a abc1") == List("ab", "a", "abc1"))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking2/docdiff_test2.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,10 @@
+
+import C2._
+
+assert(occurrences(List("a", "b", "b", "c", "d")) == Map("a" -> 1, "b" -> 2, "c" -> 1, "d" -> 1))
+
+assert(occurrences(List("d", "b", "d", "b", "d")) == Map("d" -> 3, "b" -> 2))
+
+assert(occurrences(List("b", "b", "b", "b", "b")) == Map("b" -> 5))
+
+assert(occurrences(Nil) == Map())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking2/docdiff_test3.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,15 @@
+
+import C2._
+
+val urban_list1 = List("a", "b", "b", "c", "d")
+val urban_list2 = List("d", "b", "d", "b", "d")
+
+assert(prod(urban_list1, urban_list2) == 7)
+assert(prod(urban_list1, urban_list1) == 7)
+assert(prod(urban_list2, urban_list2) == 13)
+
+
+val urban_listA = List("a", "b", "b", "c", "d")
+val urban_listB = List("1", "2", "3", "4", "5")
+
+assert(prod(urban_listA, urban_listB) == 0)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking2/docdiff_test4.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,9 @@
+
+import C2._
+
+val urban_list1 = List("a", "b", "b", "c", "d")
+val urban_list2 = List("d", "b", "d", "b", "d")
+
+assert(overlap(urban_list1, urban_list2) == 0.5384615384615384)
+assert(overlap(urban_list1, urban_list1) == 1.0)
+assert(overlap(urban_list2, urban_list2) == 1.0)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking2/mk_core2	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,29 @@
+#!/bin/bash
+set -euo pipefail
+
+
+trap "exit" INT
+
+files=${1:-*/core2}
+
+for sd in $files; do
+  echo -e "\n"
+  cd $sd
+  echo $sd
+  touch .
+  cp ../../../../../core_marking2/docdiff_test.sh .
+  cp ../../../../../core_marking2/docdiff_test1.scala .
+  cp ../../../../../core_marking2/docdiff_test2.scala .
+  cp ../../../../../core_marking2/docdiff_test3.scala .
+  cp ../../../../../core_marking2/docdiff_test4.scala .
+  ./docdiff_test.sh output
+  rm docdiff_test.sh
+  rm docdiff_test1.scala
+  rm docdiff_test2.scala
+  rm docdiff_test3.scala
+  rm docdiff_test4.scala
+  cd ..
+  cd ..
+done
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking3/mk_core3	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,29 @@
+#!/bin/bash
+set -euo pipefail
+
+
+trap "exit" INT
+
+files=${1:-*/core3}
+
+for sd in $files; do
+  echo -e "\n"  
+  cd $sd
+  echo $sd
+  touch .
+  cp ../../../../../core_marking3/postfix_test.sh .
+  cp ../../../../../core_marking3/postfix_test1.scala .
+  cp ../../../../../core_marking3/postfix_test2.scala .
+  cp ../../../../../core_marking3/postfix_test3.scala .
+  cp ../../../../../core_marking3/postfix_test4.scala .
+  ./postfix_test.sh output
+  rm postfix_test.sh
+  rm postfix_test1.scala
+  rm postfix_test2.scala
+  rm postfix_test3.scala
+  rm postfix_test4.scala
+  cd ..
+  cd ..
+done
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking3/postfix.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,103 @@
+// Shunting Yard Algorithm
+// by Edsger Dijkstra
+// ========================
+
+object C3a {
+
+type Toks = List[String]
+
+// the operations in the simple version
+val ops = List("+", "-", "*", "/")
+
+// the precedences of the operators
+val precs = Map("+" -> 1,
+		"-" -> 1,
+		"*" -> 2,
+		"/" -> 2)
+
+// helper function for splitting strings into tokens
+def split(s: String) : Toks = s.split(" ").toList
+
+// (6) Implement below the shunting yard algorithm. The most
+// convenient way to this in Scala is to implement a recursive 
+// function and to heavily use pattern matching. The function syard 
+// takes some input tokens as first argument. The second and third 
+// arguments represent the stack and the output of the shunting yard 
+// algorithm.
+//
+// In the marking, you can assume the function is called only with 
+// an empty stack and an empty output list. You can also assume the
+// input os  only properly formatted (infix) arithmetic expressions
+// (all parentheses will be well-nested, the input only contains 
+// operators and numbers).
+
+// You can implement any additional helper function you need. I found 
+// it helpful to implement two auxiliary functions for the pattern matching:  
+// 
+ 
+def is_op(op: String) : Boolean = ops.contains(op)
+
+def prec(op1: String, op2: String) : Boolean = precs(op1) <= precs(op2)
+
+
+def syard(toks: Toks, st: Toks = Nil, out: Toks = Nil) : Toks = (toks, st, out) match {
+  case (Nil, _, _) => out.reverse ::: st
+  case (num::in, st, out) if (num.forall(_.isDigit)) => 
+    syard(in, st, num :: out)
+  case (op1::in, op2::st, out)  if (is_op(op1) && is_op(op2) && prec(op1, op2)) =>
+    syard(op1::in, st, op2 :: out) 
+  case (op1::in, st, out) if (is_op(op1)) => syard(in, op1::st, out)
+  case ("("::in, st, out) => syard(in, "("::st, out)
+  case (")"::in, op2::st, out) =>
+    if (op2 == "(") syard(in, st, out) else syard(")"::in, st, op2 :: out)
+  case (in, st, out) => {
+    println(s"in: ${in}   st: ${st}   out: ${out.reverse}")
+    Nil
+  }  
+} 
+
+
+// test cases
+//syard(split("3 + 4 * ( 2 - 1 )"))  // 3 4 2 1 - * +
+//syard(split("10 + 12 * 33"))       // 10 12 33 * +
+//syard(split("( 5 + 7 ) * 2"))      // 5 7 + 2 *
+//syard(split("5 + 7 / 2"))          // 5 7 2 / +
+//syard(split("5 * 7 / 2"))          // 5 7 * 2 /
+//syard(split("9 + 24 / ( 7 - 3 )")) // 9 24 7 3 - / +
+
+//syard(split("3 + 4 + 5"))           // 3 4 + 5 +
+//syard(split("( ( 3 + 4 ) + 5 )"))    // 3 4 + 5 +
+//syard(split("( 3 + ( 4 + 5 ) )"))    // 3 4 5 + +
+//syard(split("( ( ( 3 ) ) + ( ( 4 + ( 5 ) ) ) )")) // 3 4 5 + +
+
+// (7) Implement a compute function that evaluates an input list
+// in postfix notation. This function takes a list of tokens
+// and a stack as argumenta. The function should produce the 
+// result as an integer using the stack. You can assume 
+// this function will be only called with proper postfix 
+// expressions.    
+
+def op_comp(s: String, n1: Int, n2: Int) = s match {
+  case "+" => n2 + n1
+  case "-" => n2 - n1
+  case "*" => n2 * n1
+  case "/" => n2 / n1
+} 
+
+def compute(toks: Toks, st: List[Int] = Nil) : Int = (toks, st) match {
+  case (Nil, st) => st.head
+  case (op::in, n1::n2::st) if (is_op(op)) => compute(in, op_comp(op, n1, n2)::st)
+  case (num::in, st) => compute(in, num.toInt::st)  
+}
+
+// test cases
+// compute(syard(split("3 + 4 * ( 2 - 1 )")))  // 7
+// compute(syard(split("10 + 12 * 33")))       // 406
+// compute(syard(split("( 5 + 7 ) * 2")))      // 24
+// compute(syard(split("5 + 7 / 2")))          // 8
+// compute(syard(split("5 * 7 / 2")))          // 17
+// compute(syard(split("9 + 24 / ( 7 - 3 )"))) // 15
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking3/postfix2.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,100 @@
+// Shunting Yard Algorithm 
+// including Associativity for Operators 
+// =====================================
+
+object C3b {
+
+// type of tokens
+type Toks = List[String]
+
+// helper function for splitting strings into tokens
+def split(s: String) : Toks = s.split(" ").toList
+
+// left- and right-associativity
+abstract class Assoc
+case object LA extends Assoc
+case object RA extends Assoc
+
+// power is right-associative,
+// everything else is left-associative
+def assoc(s: String) : Assoc = s match {
+  case "^" => RA
+  case _ => LA
+}
+
+// the precedences of the operators
+val precs = Map("+" -> 1,
+  		 "-" -> 1,
+		 "*" -> 2,
+		 "/" -> 2,
+                 "^" -> 4)
+
+// the operations in the basic version of the algorithm
+val ops = List("+", "-", "*", "/", "^")
+
+// (8) Implement the extended version of the shunting yard algorithm.
+// This version should properly account for the fact that the power 
+// operation is right-associative. Apart from the extension to include
+// the power operation, you can make the same assumptions as in 
+// basic version.
+
+def is_op(op: String) : Boolean = ops.contains(op)
+
+def prec(op1: String, op2: String) : Boolean = assoc(op1) match {
+  case LA => precs(op1) <= precs(op2)
+  case RA => precs(op1) < precs(op2)
+}
+
+def syard(toks: Toks, st: Toks = Nil, out: Toks = Nil) : Toks = (toks, st, out) match {
+  case (Nil, _, _) => out.reverse ::: st
+  case (num::in, st, out) if (num.forall(_.isDigit)) => 
+    syard(in, st, num :: out)
+  case (op1::in, op2::st, out) if (is_op(op1) && is_op(op2) && prec(op1, op2)) =>
+    syard(op1::in, st, op2 :: out) 
+  case (op1::in, st, out) if (is_op(op1)) => syard(in, op1::st, out)
+  case ("("::in, st, out) => syard(in, "("::st, out)
+  case (")"::in, op2::st, out) =>
+    if (op2 == "(") syard(in, st, out) else syard(")"::in, st, op2 :: out)
+  case (in, st, out) => {
+    println(s"in: ${in}   st: ${st}   out: ${out.reverse}")
+    Nil
+  }  
+} 
+
+def op_comp(s: String, n1: Int, n2: Int) = s match {
+  case "+" => n2 + n1
+  case "-" => n2 - n1
+  case "*" => n2 * n1
+  case "/" => n2 / n1
+  case "^" => BigInt(n2).pow(n1).toInt
+} 
+
+def compute(toks: Toks, st: List[Int] = Nil) : Int = (toks, st) match {
+  case (Nil, st) => st.head
+  case (op::in, n1::n2::st) if (is_op(op)) => compute(in, op_comp(op, n1, n2)::st)
+  case (num::in, st) => compute(in, num.toInt::st)  
+}
+
+
+
+
+//compute(syard(split("3 + 4 * ( 2 - 1 )")))   // 7
+//compute(syard(split("10 + 12 * 33")))       // 406
+//compute(syard(split("( 5 + 7 ) * 2")))      // 24
+//compute(syard(split("5 + 7 / 2")))          // 8
+//compute(syard(split("5 * 7 / 2")))          // 17
+//compute(syard(split("9 + 24 / ( 7 - 3 )"))) // 15
+
+//compute(syard(split("4 ^ 3 ^ 2")))      // 262144
+//compute(syard(split("4 ^ ( 3 ^ 2 )")))  // 262144
+//compute(syard(split("( 4 ^ 3 ) ^ 2")))  // 4096
+//compute(syard(split("( 3 + 1 ) ^ 2 ^ 3")))   // 65536
+
+//syard(split("3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3"))  // 3 4 8 * 5 1 - 2 3 ^ ^ / +
+//compute(syard(split("3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3"))) // 3
+
+//compute(syard(split("( 3 + 1 ) ^ 2 ^ 3")))   // 65536
+
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking3/postfix_test.sh	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,201 @@
+#!/bin/zsh
+set -euo pipefail
+
+
+out=${1:-output}
+
+echo -e "" > $out
+
+echo `date` >> $out
+echo -e "Below is the feedback and provisional marks for your submission" >> $out
+echo -e "of the Core Part 3 (Scala).  Please note all marks are provisional until" >> $out
+echo -e "ratified by the assessment board -- this is not an official" >> $out
+echo -e "results transcript." >> $out
+echo -e "" >> $out
+
+echo -e "Below is the feedback for your submission docdiff.scala" >> $out
+echo -e "" >> $out
+
+
+# marks for CW9 preliminary
+marks=$(( 0.0 ))
+
+
+# compilation tests
+
+function scala_compile {
+  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -Xprint:parser "$1" 2> c$out 1> c$out)
+}
+
+# functional tests
+
+function scala_assert {
+  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)
+}
+
+# purity test
+function scala_vars {
+   (sed 's/immutable/ok/g' c$out > cb$out;
+    egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' cb$out 2> /dev/null 1> /dev/null)
+}
+
+
+# compilation test
+
+echo -e "postfix.scala runs?" | tee -a $out
+
+if (scala_compile postfix.scala)
+then
+   echo -e "  --> success" | tee -a $out
+   tsts=$(( 0 ))
+else
+   echo -e "  --> SCALA DID NOT RUN postfix.scala\n" | tee -a $out
+   tsts=$(( 1 ))
+fi
+
+
+
+# var, return, ListBuffer test
+#
+if  [ $tsts -eq 0 ]
+  then   
+  echo -e "postfix.scala does not contain VARS, RETURNS etc?" | tee -a $out
+
+  if (scala_vars postfix.scala)
+  then
+    echo -e "  --> FAIL\n" | tee -a $out  
+    tsts=$(( 1 ))
+  else
+    echo -e "  --> success" | tee -a $out  
+    tsts=$(( 0 )) 
+  fi
+else
+  tsts=$(( 1 ))  
+fi  
+
+
+
+### postfix tests
+
+if [ $tsts -eq 0 ]
+then
+  echo -e " syard(split(\"3 + 4 * ( 2 - 1 )\")) == List(\"3\", \"4\", \"2\", \"1\", \"-\", \"*\", \"+\")" | tee -a $out
+  echo -e " syard(split(\"( ( ( 3 ) ) + ( ( 4 + ( 5 ) ) ) )\")) == List(\"3\", \"4\", \"5\", \"+\", \"+\")" | tee -a $out
+  echo -e " syard(split(\"5 + 7 / 2\")) == List(\"5\", \"7\", \"2\", \"/\", \"+\")" | tee -a $out
+  echo -e " syard(split(\"5 * 7 / 2\")) == List(\"5\", \"7\", \"*\", \"2\", \"/\")" | tee -a $out
+  
+  if (scala_assert "postfix.scala" "postfix_test1.scala")
+  then
+    echo -e "  --> success" | tee -a $out
+    marks=$(( marks + 1.0 ))
+  else
+    echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
+  fi
+fi
+
+
+
+if [ $tsts -eq 0 ]
+then
+  echo -e " compute(syard(split(\"3 + 4 * ( 2 - 1 )\"))) == 7" | tee -a $out
+  echo -e " compute(syard(split(\"10 + 12 * 33\"))) == 406" | tee -a $out
+  echo -e " compute(syard(split(\"( 5 + 7 ) * 2\"))) == 24" | tee -a $out
+  echo -e " compute(syard(split(\"5 + 7 / 2\"))) == 8" | tee -a $out
+  echo -e " compute(syard(split(\"5 * 7 / 2\"))) == 17" | tee -a $out
+  echo -e " compute(syard(split(\"9 + 24 / ( 7 - 3 )\"))) == 15" | tee -a $out
+  
+  if (scala_assert "postfix.scala" "postfix_test2.scala")
+  then
+     echo -e "  --> success" | tee -a $out
+     marks=$(( marks + 1.0 ))
+  else
+     echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
+  fi
+fi
+
+
+
+### postfix2 tests
+
+echo -e "Below is the feedback for your submission postfix2.scala" >> $out
+echo -e "" >> $out
+
+# compilation test
+
+echo -e "postfix2.scala runs?" | tee -a $out
+
+if (scala_compile postfix2.scala)
+then
+   echo -e "  --> success" | tee -a $out
+   tsts=$(( 0 ))
+else
+   echo -e "  --> SCALA DID NOT RUN postfix2.scala\n" | tee -a $out
+   tsts=$(( 1 )) 
+fi
+
+
+# var, return, ListBuffer test
+#
+if  [ $tsts -eq 0 ]
+then     
+  echo -e "postfix2.scala does not contain VARS, RETURNS etc?" | tee -a $out
+
+  if (scala_vars postfix2.scala)
+  then
+    echo -e "  --> FAIL\n" | tee -a $out  
+    tsts=$(( 1 ))
+  else
+    echo -e "  --> success" | tee -a $out  
+    tsts=$(( 0 )) 
+  fi
+else
+  tsts=$(( 1 ))  
+fi
+
+
+
+
+if [ $tsts -eq 0 ]
+then
+  echo -e " syard(split(\"3 + 4 * ( 2 - 1 )\")) == List(\"3\", \"4\", \"2\", \"1\", \"-\", \"*\", \"+\")" | tee -a $out
+  echo -e " syard(split(\"( ( ( 3 ) ) + ( ( 4 + ( 5 ) ) ) )\")) == List(\"3\", \"4\", \"5\", \"+\", \"+\")" | tee -a $out
+  echo -e " syard(split(\"5 + 7 / 2\")) == List(\"5\", \"7\", \"2\", \"/\", \"+\")" | tee -a $out
+  echo -e " syard(split(\"5 * 7 / 2\")) == List(\"5\", \"7\", \"*\", \"2\", \"/\")" | tee -a $out
+  echo -e " syard(split(\"3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3\")) == " | tee -a $out
+  echo -e "         List(\"3\", \"4\", \"8\", \"*\", \"5\", \"1\", \"-\", \"2\", \"3\", \"^\", \"^\", \"/\", \"+\")" | tee -a $out
+  
+  if (scala_assert "postfix2.scala" "postfix_test3.scala")
+  then
+      echo -e "  --> success" | tee -a $out
+      marks=$(( marks + 0.5 ))
+  else
+      echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
+  fi
+fi
+
+if [ $tsts -eq 0 ]
+then
+  echo -e " compute(syard(split(\"3 + 4 * ( 2 - 1 )\"))) == 7" | tee -a $out
+  echo -e " compute(syard(split(\"10 + 12 * 33\"))) == 406" | tee -a $out
+  echo -e " compute(syard(split(\"( 5 + 7 ) * 2\"))) == 24" | tee -a $out
+  echo -e " compute(syard(split(\"5 + 7 / 2\"))) == 8" | tee -a $out
+  echo -e " compute(syard(split(\"5 * 7 / 2\"))) == 17" | tee -a $out
+  echo -e " compute(syard(split(\"9 + 24 / ( 7 - 3 )\"))) == 15" | tee -a $out
+  echo -e " compute(syard(split(\"4 ^ 3 ^ 2\"))) == 262144" | tee -a $out
+  echo -e " compute(syard(split(\"4 ^ ( 3 ^ 2 )\"))) == 262144" | tee -a $out
+  echo -e " compute(syard(split(\"( 4 ^ 3 ) ^ 2\"))) == 4096" | tee -a $out
+  echo -e " compute(syard(split(\"( 3 + 1 ) ^ 2 ^ 3\"))) == 65536" | tee -a $out
+  
+  if (scala_assert "postfix2.scala" "postfix_test4.scala")
+  then
+      echo -e "  --> success" | tee -a $out
+      marks=$(( marks + 0.5 ))
+  else
+      echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
+  fi
+fi
+
+## final marks
+echo -e "Overall mark for the Core Part 3 (Scala)" | tee -a $out
+printf " %0.1f\n" $marks | tee -a $out
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking3/postfix_test1.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,7 @@
+import C3a._
+
+
+assert(syard(split("3 + 4 * ( 2 - 1 )")) == List("3", "4", "2", "1", "-", "*", "+"))
+assert(syard(split("( ( ( 3 ) ) + ( ( 4 + ( 5 ) ) ) )")) == List("3", "4", "5", "+", "+"))
+assert(syard(split("5 + 7 / 2")) == List("5", "7", "2", "/", "+"))
+assert(syard(split("5 * 7 / 2")) == List("5", "7", "*", "2", "/"))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking3/postfix_test2.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,8 @@
+import C3a._
+
+assert(compute(syard(split("3 + 4 * ( 2 - 1 )"))) == 7)
+assert(compute(syard(split("10 + 12 * 33"))) == 406)
+assert(compute(syard(split("( 5 + 7 ) * 2"))) == 24)
+assert(compute(syard(split("5 + 7 / 2"))) == 8)
+assert(compute(syard(split("5 * 7 / 2"))) == 17)
+assert(compute(syard(split("9 + 24 / ( 7 - 3 )"))) == 15)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking3/postfix_test3.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,9 @@
+import C3b._
+
+
+assert(syard(split("3 + 4 * ( 2 - 1 )")) == List("3", "4", "2", "1", "-", "*", "+"))
+assert(syard(split("( ( ( 3 ) ) + ( ( 4 + ( 5 ) ) ) )")) == List("3", "4", "5", "+", "+"))
+assert(syard(split("5 + 7 / 2")) == List("5", "7", "2", "/", "+"))
+assert(syard(split("5 * 7 / 2")) == List("5", "7", "*", "2", "/"))
+assert(syard(split("3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3")) == List("3", "4", "8", "*", "5", "1", "-", "2", "3", "^", "^", "/", "+"))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core_marking3/postfix_test4.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,13 @@
+import C3b._
+
+
+assert(compute(syard(split("3 + 4 * ( 2 - 1 )"))) == 7)
+assert(compute(syard(split("10 + 12 * 33"))) == 406)
+assert(compute(syard(split("( 5 + 7 ) * 2"))) == 24)
+assert(compute(syard(split("5 + 7 / 2"))) == 8)
+assert(compute(syard(split("5 * 7 / 2"))) == 17)
+assert(compute(syard(split("9 + 24 / ( 7 - 3 )"))) == 15)
+assert(compute(syard(split("4 ^ 3 ^ 2"))) == 262144)
+assert(compute(syard(split("4 ^ ( 3 ^ 2 )"))) == 262144)
+assert(compute(syard(split("( 4 ^ 3 ) ^ 2"))) == 4096)
+assert(compute(syard(split("( 3 + 1 ) ^ 2 ^ 3"))) == 65536)
Binary file cws/core_cw01.pdf has changed
Binary file cws/core_cw02.pdf has changed
Binary file cws/core_cw03.pdf has changed
Binary file cws/cw03.pdf has changed
Binary file cws/cw04.pdf has changed
Binary file cws/cw05.pdf has changed
Binary file cws/cw06.pdf has changed
--- a/cws/disclaimer.sty	Thu Jan 13 12:55:03 2022 +0000
+++ b/cws/disclaimer.sty	Mon Apr 11 23:55:27 2022 +0100
@@ -4,8 +4,8 @@
 \begin{itemize}
 \item #1  
 \item Make sure the files you submit can be processed by just calling\\
-  \mbox{\texttt{scala <<filename.scala>>}} on the commandline.\footnote{All
-    major OSes, including Windows, have a commandline. So there is no
+  \mbox{\texttt{scala <<filename.scala>>}} on the command line.\footnote{All
+    major OSes, including Windows, have a command line. So there is no
     good reason to not download Scala, install it and run it on your
     own computer. Just do it!} Use the
   template files provided and do not make any changes to arguments of
@@ -37,8 +37,8 @@
 
 \begin{itemize}
 \item Make sure the files you submit can be processed by just calling\\
-  \mbox{\texttt{scala <<filename.scala>>}} on the commandline.\footnote{All
-    major OSes, including Windows, have a commandline. So there is no
+  \mbox{\texttt{scala <<filename.scala>>}} on the command line.\footnote{All
+    major OSes, including Windows, have a command line. So there is no
     good reason to not download Scala, install it and run it on your
     own computer. Just do it!} Use the
   template files provided and do not make any changes to arguments of
@@ -71,7 +71,7 @@
 
 \begin{itemize}
 \item Make sure the files you submit can be processed by just calling\\
-  \mbox{\texttt{scala <<filename.scala>>}} on the commandline. Use the
+  \mbox{\texttt{scala <<filename.scala>>}} on the command line. Use the
   template file provided and do not make any changes to arguments of
   functions or to any types. You are free to implement any auxiliary
   function you might need.
Binary file cws/main_cw01.pdf has changed
Binary file cws/main_cw02.pdf has changed
Binary file cws/main_cw03.pdf has changed
--- a/cws/main_cw03.tex	Thu Jan 13 12:55:03 2022 +0000
+++ b/cws/main_cw03.tex	Mon Apr 11 23:55:27 2022 +0100
@@ -176,6 +176,7 @@
 5000000: 1.29659 secs.
 \end{lstlisting}%$
 
+
 \subsection*{Preliminaries}
 
 The task is to implement a regular expression matcher that is based on
@@ -241,8 +242,10 @@
 The alternative regular expressions comes in two versions: one is
 binary (+ / \texttt{ALT}) and the other is n-ary ($\sum$ /
 \texttt{ALTs}). The latter takes a list of regular expressions as
-arguments.  In what follows we shall use $rs$ to stand for lists of
-regular expressions.  The binary alternative can be seen as an abbreviation,
+argument.  In what follows we shall use $rs$ to stand for lists of
+regular expressions. When the list is empty, we shall write $\sum\,[]$;
+if it is non-empty, we sometimes write $\sum\,[r_1,..., r_n]$.
+The binary alternative can be seen as an abbreviation,
 that is $r_1 + r_2 \dn \sum\,[r_1, r_2]$. As a result we can ignore the
 binary version and only implement the n-ary alternative.
 
@@ -267,7 +270,7 @@
 
 \item[(2)] Implement a function, called \textit{der}, by recursion over
   regular expressions. It takes a character and a regular expression
-  as arguments and calculates the derivative of a regular expression according
+  as arguments and calculates the \emph{derivative} of a regular expression according
   to the rules:
 
 \begin{center}
@@ -337,8 +340,8 @@
     \end{tabular}  
   \end{center}  
 
-  The first clause just states that empty lists cannot be further
-  flattened. The second removes all $\ZERO$s from the list.
+  The first clause states that empty lists cannot be further
+  flattened. The second removes the first $\ZERO$ from the list and recurses.
   The third is when the first regular expression is an \texttt{ALTs}, then
   the content of this alternative should be spilled out and appended
   with the flattened rest of the list. The last case is for all other
@@ -366,16 +369,16 @@
 expressions $r_1,.. ,r_n$; then flatten the resulting list using
 \texttt{flts}; finally remove all duplicates in this list (this can be
 done in Scala using the function
-\texttt{\_.distinct}). \textcolor{red}{When you perform these
+\texttt{\_.distinct}). When you perform these
   operations, you end up with three cases, namely where the list is
   empty, contains a single element and ``otherwise''. These cases
-  should be processed as follows}
+  should be processed as follows
 \begin{center}
-\textcolor{red}{\begin{tabular}{l@{\hspace{4mm}}c@{\hspace{4mm}}ll}
+\begin{tabular}{l@{\hspace{4mm}}c@{\hspace{4mm}}ll}
 $\sum\;[]$ & $\mapsto$ & $\ZERO$\\ 
 $\sum\;[r]$ & $\mapsto$ & $r$\\ 
 $\sum\;rs$ & $\mapsto$ & $\sum\;rs$ & ``otherwise''\\ 
-\end{tabular}}
+\end{tabular}
 \end{center}
 
   
@@ -515,7 +518,7 @@
 \begin{center}
 \begin{tabular}{@{}cc@{}}
 \multicolumn{2}{c}{Graph: $(a^*)^*\cdot b$ and strings 
-           $\underbrace{a\ldots a}_{n}$}\bigskip\\
+           $\underbrace{a\ldots a}_{n}$}\medskip\\
   
 \begin{tikzpicture}
 \begin{axis}[
@@ -531,7 +534,7 @@
     scaled ticks=false,
     axis lines=left,
     width=6cm,
-    height=5.0cm, 
+    height=5.5cm, 
     legend entries={Python, Java 8, JavaScript, Swift, Dart},  
     legend pos=north west,
     legend cell align=left]
@@ -557,7 +560,7 @@
     scaled ticks=false,
     axis lines=left,
     width=6cm,
-    height=5.0cm, 
+    height=5.5cm, 
     legend entries={Java 9},  
     legend pos=north west]
 \addplot[cyan,mark=*, mark options={fill=white}] table {re-java9.data};
Binary file cws/main_cw04.pdf has changed
Binary file cws/main_cw05.pdf has changed
--- a/main_marking1/drumb.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking1/drumb.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,7 +1,12 @@
-// Main Part about a really dumb investment strategy
-//======================================================
+// Main Part 1 about a really dumb investment strategy
+//=====================================================
+
 
-object CW6b {
+// generate jar with
+//   > scala -d drumb.jar  drumb.scala
+
+
+object M1 { 
 
 
 //two test portfolios
@@ -19,7 +24,7 @@
 //     strings for each line in the CSV-file.
 
 def get_january_data(symbol: String, year: Int) : List[String] = 
-  Source.fromFile(symbol ++ ".csv")("ISO-8859-1").getLines.toList.filter(_.startsWith(year.toString))
+  Source.fromFile(symbol ++ ".csv")("ISO-8859-1").getLines().toList.filter(_.startsWith(year.toString))
 
 
 //test cases
@@ -164,10 +169,28 @@
 
 //test cases for the two portfolios given above
 
-//println("Real data: " + investment(rstate_portfolio, 1978 to 2019, 100))
-//println("Blue data: " + investment(blchip_portfolio, 1978 to 2019, 100))
+  println("Real data: " + investment(rstate_portfolio, 1978 to 2019, 100))
+  println("Blue data: " + investment(blchip_portfolio, 1978 to 2019, 100))
+
 
 }
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- a/main_marking1/drumb_test.sh	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking1/drumb_test.sh	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/zsh
 
 # to make the script fail safely
 set -euo pipefail
@@ -16,7 +16,7 @@
 echo -e "" >> $out
 
 # marks for CW6 main part 
-marks=$(( 0 ))
+marks=$(( 0.0 ))
 
 
 echo -e "" >> $out
@@ -38,10 +38,11 @@
 
 
 # purity test
+function scala_vars {
+   (sed 's/immutable/ok/g' c$out > cb$out;
+    egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' cb$out 2> /dev/null 1> /dev/null)
+}
 
-function scala_vars {
-   (egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' c$out 2> /dev/null 1> /dev/null)
-}
 
 # compilation test
 echo -e "drumb.scala runs?" | tee -a $out
@@ -76,8 +77,6 @@
 
 echo >> $out
 
-sleep 15
-
 ### get january tests
 
 if [ $tsts -eq 0 ]
@@ -88,7 +87,7 @@
   if (scala_assert "drumb.scala" "drumb_test1.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 0.5 ))
   else
       echo -e "  --> TEST FAILED\n" | tee -a $out
   fi
@@ -104,7 +103,7 @@
   if (scala_assert "drumb.scala" "drumb_test2.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 1.0 ))
   else
       echo -e "  --> TEST FAILED\n" | tee -a $out
   fi
@@ -126,7 +125,7 @@
   if (scala_assert "drumb.scala" "drumb_test3.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 1.0 ))
   else
       echo -e "  --> TEST FAILED\n" | tee -a $out
   fi
@@ -144,7 +143,7 @@
   if (scala_assert "drumb.scala" "drumb_test4.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 1.0 ))
   else
       echo -e "  --> TEST FAILED\n" | tee -a $out
   fi
@@ -166,7 +165,7 @@
   if (scala_assert "drumb.scala" "drumb_test5.scala") 
   then
      echo -e "  --> success" | tee -a $out
-     marks=$(( marks + 1 ))
+     marks=$(( marks + 1.0 ))
   else
      echo -e "  --> TEST FAILED\n" | tee -a $out
   fi
@@ -184,7 +183,7 @@
   if (scala_assert "drumb.scala" "drumb_test6.scala") 
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 1.0 ))
   else
       echo -e "  --> TEST FAILED\n" | tee -a $out
   fi
@@ -210,7 +209,7 @@
   if (scala_assert "drumb.scala" "drumb_test7.scala") 
   then
     echo -e "  --> success" | tee -a $out
-    marks=$(( marks + 1 ))
+    marks=$(( marks + 0.5 ))
   else
     echo -e "  --> TEST FAILED\n" | tee -a $out
   fi
@@ -219,7 +218,6 @@
 ## final marks
 echo -e "" >> $out
 echo -e "Overall mark for Main Part 1 (Scala)" | tee -a $out
-echo -e "$marks" | tee -a $out
+printf " %0.1f\n" $marks | tee -a $out
 
 
-sleep 10
--- a/main_marking1/drumb_test1.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking1/drumb_test1.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,12 +1,5 @@
-/*def myassert(cond : => Boolean) = {
-  try {
-    assert(cond)
-  } catch { 
-    case _ : Throwable => System.exit(1)
-  }
-}
-*/
+
 
-assert(CW6b.get_january_data("GOOG", 1980) == List())
-assert(CW6b.get_january_data("GOOG", 2010).head == "2010-01-04,312.204773")
+assert(M1.get_january_data("GOOG", 1980) == List())
+assert(M1.get_january_data("GOOG", 2010).head == "2010-01-04,312.204773")
 
--- a/main_marking1/drumb_test2.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking1/drumb_test2.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,12 +1,4 @@
-/*def myassert(cond : => Boolean) = {
-  try {
-    assert(cond)
-  } catch { 
-    case _ : Throwable => System.exit(1)
-  }
-}
-*/
 
-assert(CW6b.get_first_price("GOOG", 1980) == None)
-assert(CW6b.get_first_price("GOOG", 2010) == Some(312.204773))
+assert(M1.get_first_price("GOOG", 1980) == None)
+assert(M1.get_first_price("GOOG", 2010) == Some(312.204773))
 
--- a/main_marking1/drumb_test3.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking1/drumb_test3.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,17 +1,11 @@
-/*def myassert(cond : => Boolean) = {
-  try {
-    assert(cond)
-  } catch { 
-    case _ : Throwable => System.exit(1)
-  }
-}
-*/
-assert(CW6b.get_prices(List("BIDU"), 2004 to 2008) ==
+import M1._
+
+assert(get_prices(List("BIDU"), 2004 to 2008) ==
    List(List(None), List(None), List(Some(6.35)), 
         List(Some(12.241)), List(Some(38.188))))
 
 
-assert(CW6b.get_prices(List("GOOG", "AAPL"), 2010 to 2012) ==
+assert(get_prices(List("GOOG", "AAPL"), 2010 to 2012) ==
    List(List(Some(312.204773), Some(26.782711)), 
         List(Some(301.0466), Some(41.244694)), 
         List(Some(331.462585), Some(51.464207))))
--- a/main_marking1/drumb_test4.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking1/drumb_test4.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,6 +1,6 @@
 
 
-assert(CW6b.get_delta(None, None) == None)
-assert(CW6b.get_delta(Some(50.0), None) == None)
-assert(CW6b.get_delta(None, Some(100.0)) == None)
-assert(CW6b.get_delta(Some(50.0), Some(100.0)) == Some(1.0))
+assert(M1.get_delta(None, None) == None)
+assert(M1.get_delta(Some(50.0), None) == None)
+assert(M1.get_delta(None, Some(100.0)) == None)
+assert(M1.get_delta(Some(50.0), Some(100.0)) == Some(1.0))
--- a/main_marking1/drumb_test5.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking1/drumb_test5.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,18 +1,10 @@
-/*def myassert(cond : => Boolean) = {
-  try {
-    assert(cond)
-  } catch { 
-    case _ : Throwable => System.exit(1)
-  }
-}
-*/
-// get_prices(List("GOOG", "AAPL"), 2010 to 2012)
+
 val urban_prices = List(List(Some(312.204773), Some(26.782711)), 
                         List(Some(301.0466), Some(41.244694)), 
                         List(Some(331.462585), Some(51.464207)))
 
 
-assert(CW6b.get_deltas(urban_prices) == List(List(Some(-0.03573991804411003), Some(0.539974575389325)), 
+assert(M1.get_deltas(urban_prices) == List(List(Some(-0.03573991804411003), Some(0.539974575389325)), 
                                           List(Some(0.10103414222249969), Some(0.24777764141006836))))
 
 
@@ -22,6 +14,6 @@
                          List(Some(38.188)))
 
 
-assert(CW6b.get_deltas(urban_prices2) == List(List(None), List(None), 
+assert(M1.get_deltas(urban_prices2) == List(List(None), List(None), 
                                         List(Some(0.9277165354330709)), 
                                         List(Some(2.119679764725104))))
--- a/main_marking1/drumb_test6.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking1/drumb_test6.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,18 +1,9 @@
-//val urban_deltas = get_deltas(get_prices(List("GOOG", "AAPL"), 2010 to 2012))
-/*
-def myassert(cond : => Boolean) = {
-  try {
-    assert(cond)
-  } catch { 
-    case _ : Throwable => System.exit(1)
-  }
-}
-*/
+
 
 val ds_urban = List(List(Some(-0.03573991804411003), Some(0.539974575389325)), 
                     List(Some(0.10103414222249969), Some(0.24777764141006836)))
 
 
 
-assert(CW6b.yearly_yield(ds_urban, 100, 0) == 125)
-assert(CW6b.yearly_yield(ds_urban, 100, 1) == 117)
+assert(M1.yearly_yield(ds_urban, 100, 0) == 125)
+assert(M1.yearly_yield(ds_urban, 100, 1) == 117)
--- a/main_marking1/drumb_test7.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking1/drumb_test7.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,24 +1,16 @@
-/*
-def myassert(cond : => Boolean) = {
-  try {
-    assert(cond)
-  } catch { 
-    case _ : Throwable => System.exit(1)
-  }
-}
-*/
+
 
-assert(CW6b.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2000, 100) == 100)
-assert(CW6b.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2001, 100) == 27)
-assert(CW6b.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2002, 100) == 42)
-assert(CW6b.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2003, 100) == 27)
-assert(CW6b.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2004, 100) == 38)
+assert(M1.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2000, 100) == 100)
+assert(M1.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2001, 100) == 27)
+assert(M1.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2002, 100) == 42)
+assert(M1.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2003, 100) == 27)
+assert(M1.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2004, 100) == 38)
 
 // 113
-assert((112 to 114).contains(CW6b.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2005, 100)))
+assert((112 to 114).contains(M1.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2005, 100)))
 // 254
-assert((252 to 256).contains(CW6b.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2006, 100)))
+assert((252 to 256).contains(M1.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2006, 100)))
 // 349
-assert((346 to 352).contains(CW6b.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2007, 100)))
+assert((346 to 352).contains(M1.investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2007, 100)))
 //11504
-assert((11389 to 11619).contains(CW6b.investment(List("GOOG", "AAPL", "BIDU"), 1990 to 2017, 100)))
+assert((11389 to 11619).contains(M1.investment(List("GOOG", "AAPL", "BIDU"), 1990 to 2017, 100)))
--- a/main_marking1/mk	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-#!/bin/sh
-###set -e
-
-trap "exit" INT
-
-files=${1:-*/main1}
-
-for sd in $files; do
-  cd $sd
-  echo $sd
-  sleep 5
-  touch .
-  cp ../../../../../main_marking1/drumb_test.sh .
-  cp ../../../../../main_marking1/drumb_test1.scala .
-  cp ../../../../../main_marking1/drumb_test2.scala .
-  cp ../../../../../main_marking1/drumb_test3.scala .
-  cp ../../../../../main_marking1/drumb_test4.scala .
-  cp ../../../../../main_marking1/drumb_test5.scala .
-  cp ../../../../../main_marking1/drumb_test6.scala .
-  cp ../../../../../main_marking1/drumb_test7.scala .
-  cp ../../../../../main_marking1/*.csv .
-  ./drumb_test.sh output
-  rm drumb_test.sh
-  rm drumb_test1.scala
-  rm drumb_test2.scala
-  rm drumb_test3.scala
-  rm drumb_test4.scala
-  rm drumb_test5.scala
-  rm drumb_test6.scala
-  rm drumb_test7.scala
-  rm *.csv
-  cd ..
-  cd ..
-done
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking1/mk_main1	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,36 @@
+#!/bin/bash
+###set -e
+
+trap "exit" INT
+
+files=${1:-*/main1}
+
+for sd in $files; do
+  echo -e "\n"  
+  cd $sd
+  echo $sd
+  touch .
+  cp ../../../../../main_marking1/drumb_test.sh .
+  cp ../../../../../main_marking1/drumb_test1.scala .
+  cp ../../../../../main_marking1/drumb_test2.scala .
+  cp ../../../../../main_marking1/drumb_test3.scala .
+  cp ../../../../../main_marking1/drumb_test4.scala .
+  cp ../../../../../main_marking1/drumb_test5.scala .
+  cp ../../../../../main_marking1/drumb_test6.scala .
+  cp ../../../../../main_marking1/drumb_test7.scala .
+  cp ../../../../../main_marking1/*.csv .
+  ./drumb_test.sh output
+  rm drumb_test.sh
+  rm drumb_test1.scala
+  rm drumb_test2.scala
+  rm drumb_test3.scala
+  rm drumb_test4.scala
+  rm drumb_test5.scala
+  rm drumb_test6.scala
+  rm drumb_test7.scala
+  rm *.csv
+  cd ..
+  cd ..
+done
+
+
--- a/main_marking2/danube_test.sh	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking2/danube_test.sh	Mon Apr 11 23:55:27 2022 +0100
@@ -37,9 +37,9 @@
 }
 
 # purity test
-
 function scala_vars {
-   (egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' c$out 2> /dev/null 1> /dev/null)
+   (sed 's/immutable/ok/g' c$out > cb$out;
+    egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' cb$out 2> /dev/null 1> /dev/null)
 }
 
 
@@ -111,6 +111,9 @@
   echo -e  "  " | tee -a $out
   echo -e  "  good_ratings.length == 48580 " | tee -a $out
   echo -e  "  movie_names.length == 9742 " | tee -a $out
+  echo -e  "  "  | tee -a $out
+  echo -e  "  val r_elems = List((\"1\",\"1\"), (\"1\",\"3\"), (\"1\",\"6\"), (\"1\",\"47\")) " | tee -a $out
+  echo -e  "  r_elems.forall(good_ratings.contains(_)) == true" | tee -a $out
 
   if (scala_assert "danube.scala" "danube_test2.scala") 
   then
@@ -201,57 +204,6 @@
   fi
 fi
 
-### danube most_recommended 1
-gd=$(( 0 ))
-
-if [ $tsts -eq 0 ]
-then
-    echo -e  "  val rmap =  Map(\"1\" -> List(\"b\", \"a\"), " | tee -a $out
-    echo -e  "                  \"2\" -> List(\"y\", \"x\"), " | tee -a $out
-    echo -e  "                  \"3\" -> List(\"c\", \"a\")) " | tee -a $out
-    echo -e  "  val nmap = Map(\"a\" -> \"A\", \"b\" -> \"B\", \"c\" -> \"C\",  " | tee -a $out
-    echo -e  "                 \"x\" -> \"X\", \"y\" -> \"Y\") " | tee -a $out
-    echo -e  "  most_recommended(rmap, nmap).toSet == " | tee -a $out
-    echo -e  "      Set((\"A\",2), (\"B\",1), (\"C\",1), (\"X\",1), (\"Y\",1)) " | tee -a $out
-
-  if (scala_assert "danube.scala" "danube_test7a.scala") 
-  then
-      echo -e  "  --> success (0.5% Marks)" | tee -a $out
-      marks=$(( marks + 0.5 ))
-  else
-      echo -e  "  --> TEST FAILED\n" | tee -a $out
-      gd=$(( 1 ))
-  fi
-fi
-
-### danube most_recommended 2
-
-sleep 10
-
-if [ $gd -eq 0 ]
-then
-   if [ $tsts -eq 0 ]
-   then
-       echo -e  "  most_recommended(ratings_map, movie_map) runs within allocated time? " | tee -a $out
-       START=$(date +%s)
-       
-       if (scala_assert_thirty "danube.scala" "danube_test7b.scala") 
-       then
-	   END=$(date +%s)
-	   DIFF=$(( $END - $START ))
-	   echo "   This test ran for $DIFF seconds." | tee -a $out 
-	   echo -e  "  --> success (0.5% Marks)" | tee -a $out
-	   marks=$(( marks + 0.5 ))  
-       else
-	   END=$(date +%s)
-	   DIFF=$(( $END - $START ))
-	   echo "  This test ran for $DIFF seconds." | tee -a $out 
-	   echo -e  "  --> TEST FAILED\n" | tee -a $out
-       fi
-   fi
-fi   
-
-sleep 10
 
 
 ## final marks
--- a/main_marking2/danube_test1.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking2/danube_test1.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,5 +1,5 @@
 
-import CW7b._
+import M2._
 
 val urban_mov_url = """https://nms.kcl.ac.uk/christian.urban/movies.csv"""
 //val urban_mov_url = """http://localhost:8000/movies.csv"""
--- a/main_marking2/danube_test2.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking2/danube_test2.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -2,7 +2,7 @@
 import io.Source
 import scala.util._
 
-import CW7b._
+import M2._
 
 def urban_get_csv_file(name: String) : List[String] = {
   val csv = Source.fromFile(name)
@@ -12,8 +12,11 @@
 val urban_ratings = urban_get_csv_file("ratings.csv")
 val urban_movies = urban_get_csv_file("movies.csv")
 
+val urban_res1 = process_ratings(urban_ratings)
+val urban_rat_elems = List(("1","1"), ("1","3"), ("1","6"), ("1","47"))
 
-assert(process_ratings(urban_ratings).length == 48580)
+assert(urban_res1.length == 48580)
+assert(urban_rat_elems.forall(urban_res1.contains(_)))
 
 assert(process_movies(urban_movies).length == 9742)
 
--- a/main_marking2/danube_test3.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking2/danube_test3.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW7b._
+import M2 ._
 
 
 // first test 
--- a/main_marking2/danube_test4.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking2/danube_test4.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,7 +1,7 @@
 
 // first test 
 
-import CW7b._
+import M2._
 
 def urban_groupById(ratings: List[(String, String)]) = 
   ratings.groupBy(_._1).view.mapValues(_.map(_._2)).toMap 
--- a/main_marking2/danube_test5.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking2/danube_test5.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,7 +1,7 @@
 
 // first test 
 
-import CW7b._
+import M2._
 
 def urban_groupById(ratings: List[(String, String)]) = 
   ratings.groupBy(_._1).view.mapValues(_.map(_._2)).toMap 
--- a/main_marking2/danube_test6.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking2/danube_test6.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,5 +1,5 @@
 
-import CW7b._
+import M2._
 
 // first test 
 
--- a/main_marking2/danube_test7a.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-
-import CW7b._
-
-val urban_recs = 
-  Map("1" -> List("b", "a"), 
-      "2" -> List("y", "x"), 
-      "3" -> List("a", "c"))
-
-val urban_names = Map("a" -> "A", "b" -> "B", "c" -> "C", "x" -> "X", "y" -> "Y")
-
-assert(most_recommended(urban_recs, urban_names).toSet ==
-        Set(("A",2), ("B",1), ("C",1), ("X",1), ("Y",1)))
-
--- a/main_marking2/danube_test7b.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-
-import CW7b._
-
-def urban_groupById(ratings: List[(String, String)]) = 
-  ratings.groupBy(_._1).view.mapValues(_.map(_._2)).toMap 
-
-def urban_get_csv_file(name: String) : List[String] = {
-  import io.Source
-  import scala.util._
-  val csv = Source.fromFile(name)
-  csv.mkString.split("\n").toList.drop(1)
-}
-
-def urban_process_ratings(lines: List[String]) : List[(String, String)] = {
-  for (cols <- lines.map(_.split(",").toList); 
-       if (cols(2).toFloat >= 4)) yield (cols(0), cols(1))  
-}
-
-def urban_process_movies(lines: List[String]) : List[(String, String)] = {
-  for (cols <- lines.map(_.split(",").toList)) yield (cols(0), cols(1))  
-}
-
-
-val urban_good_ratings = process_ratings(urban_get_csv_file("ratings.csv"))
-val urban_movie_names = process_movies(urban_get_csv_file("movies.csv")).toMap
-
-val urban_ratings_map = urban_groupById(urban_good_ratings)
-
-def urban_test() = 
-  { most_recommended(urban_ratings_map, urban_movie_names) ; true }
-
-assert(urban_test())
-
-
--- a/main_marking2/mk	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-#!/bin/sh
-###set -e
-
-trap "exit" INT
-
-files=${1:-*/main2}
-
-
-for sd in $files; do
-  cd $sd
-  echo $sd
-  touch .
-  cp ../../../../../main_marking2/danube_test.sh .
-  cp ../../../../../main_marking2/danube_test1.scala .
-  cp ../../../../../main_marking2/danube_test2.scala .
-  cp ../../../../../main_marking2/danube_test3.scala .
-  cp ../../../../../main_marking2/danube_test4.scala .
-  cp ../../../../../main_marking2/danube_test5.scala .
-  cp ../../../../../main_marking2/danube_test6.scala .
-  cp ../../../../../main_marking2/danube_test7a.scala .
-  cp ../../../../../main_marking2/danube_test7b.scala .
-  cp ../../../../../main_marking2/movies.csv .
-  cp ../../../../../main_marking2/ratings.csv .
-  ./danube_test.sh output
-  rm danube_test.sh
-  rm danube_test1.scala
-  rm danube_test2.scala
-  rm danube_test3.scala
-  rm danube_test4.scala
-  rm danube_test5.scala
-  rm danube_test6.scala
-  rm danube_test7a.scala
-  rm danube_test7b.scala
-  rm ratings.csv
-  rm movies.csv
-  cd ..
-  cd ..
-done
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking2/mk_main2	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,37 @@
+#!/bin/bash
+###set -e
+
+trap "exit" INT
+
+files=${1:-*/main2}
+
+
+for sd in $files; do
+  echo -e "\n"
+  cd $sd
+  echo $sd
+  touch .
+  cp ../../../../../main_marking2/danube_test.sh .
+  cp ../../../../../main_marking2/danube_test1.scala .
+  cp ../../../../../main_marking2/danube_test2.scala .
+  cp ../../../../../main_marking2/danube_test3.scala .
+  cp ../../../../../main_marking2/danube_test4.scala .
+  cp ../../../../../main_marking2/danube_test5.scala .
+  cp ../../../../../main_marking2/danube_test6.scala .
+  cp ../../../../../main_marking2/movies.csv .
+  cp ../../../../../main_marking2/ratings.csv .
+  ./danube_test.sh output
+  rm danube_test.sh
+  rm danube_test1.scala
+  rm danube_test2.scala
+  rm danube_test3.scala
+  rm danube_test4.scala
+  rm danube_test5.scala
+  rm danube_test6.scala
+  rm ratings.csv
+  rm movies.csv
+  cd ..
+  cd ..
+done
+
+
--- a/main_marking3/mk	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#!/bin/sh
-###set -e
-
-trap "exit" INT
-
-files=${1:-*/main3}
-
-for sd in $files; do
-  cd $sd
-  echo $sd
-  touch .
-  cp ../../../../../main_marking3/re_test.sh .
-  cp ../../../../../main_marking3/re_test1.scala .
-  cp ../../../../../main_marking3/re_test2.scala .
-  cp ../../../../../main_marking3/re_test3.scala .
-  cp ../../../../../main_marking3/re_test4.scala .
-  cp ../../../../../main_marking3/re_test5.scala .
-  cp ../../../../../main_marking3/re_test6.scala .
-  cp ../../../../../main_marking3/re_test7.scala .
-  ./re_test.sh output
-  rm re_test.sh
-  rm re_test1.scala
-  rm re_test2.scala
-  rm re_test3.scala
-  rm re_test4.scala
-  rm re_test5.scala
-  rm re_test6.scala
-  rm re_test7.scala
-  cd ..
-  cd ..
-done
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking3/mk_main3	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,36 @@
+#!/bin/bash
+###set -e
+
+trap "exit" INT
+
+files=${1:-*/main3}
+
+for sd in $files; do
+  echo -e "\n"  
+  cd $sd
+  echo $sd
+  touch .
+  cp ../../../../../main_marking3/re_test.sh .
+  cp ../../../../../main_marking3/re_test1.scala .
+  cp ../../../../../main_marking3/re_test2.scala .
+  cp ../../../../../main_marking3/re_test3.scala .
+  cp ../../../../../main_marking3/re_test3a.scala .
+  cp ../../../../../main_marking3/re_test4.scala .
+  cp ../../../../../main_marking3/re_test5.scala .
+  cp ../../../../../main_marking3/re_test6.scala .
+  cp ../../../../../main_marking3/re_test7.scala .
+  ./re_test.sh output
+  rm re_test.sh
+  rm re_test1.scala
+  rm re_test2.scala
+  rm re_test3.scala
+  rm re_test3a.scala
+  rm re_test4.scala
+  rm re_test5.scala
+  rm re_test6.scala
+  rm re_test7.scala
+  cd ..
+  cd ..
+done
+
+
--- a/main_marking3/re.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking3/re.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,23 +1,25 @@
-// Core Part about Regular Expression Matching
+// Main Part 3 about Regular Expression Matching
 //=============================================
 
-object CW8c {
+object M3 {
 
 // Regular Expressions
 abstract class Rexp
 case object ZERO extends Rexp
 case object ONE extends Rexp
 case class CHAR(c: Char) extends Rexp
-case class ALT(r1: Rexp, r2: Rexp) extends Rexp 
-case class SEQ(r1: Rexp, r2: Rexp) extends Rexp 
-case class STAR(r: Rexp) extends Rexp 
+case class ALTs(rs: List[Rexp]) extends Rexp      // alternatives 
+case class SEQ(r1: Rexp, r2: Rexp) extends Rexp   // sequence
+case class STAR(r: Rexp) extends Rexp             // star
+
+
+//the usual binary choice can be defined in terms of ALTs
+def ALT(r1: Rexp, r2: Rexp) = ALTs(List(r1, r2))
 
 // some convenience for typing in regular expressions
-
 import scala.language.implicitConversions    
 import scala.language.reflectiveCalls 
 
-
 def charlist2rexp(s: List[Char]): Rexp = s match {
   case Nil => ONE
   case c::Nil => CHAR(c)
@@ -49,7 +51,7 @@
   case ZERO => false
   case ONE => true
   case CHAR(_) => false
-  case ALT(r1, r2) => nullable(r1) || nullable(r2)
+  case ALTs(rs) => rs.exists(nullable)
   case SEQ(r1, r2) => nullable(r1) && nullable(r2)
   case STAR(_) => true
 }
@@ -63,25 +65,39 @@
   case ZERO => ZERO
   case ONE => ZERO
   case CHAR(d) => if (c == d) ONE else ZERO
-  case ALT(r1, r2) => ALT(der(c, r1), der(c, r2))
+  case ALTs(rs) => ALTs(rs.map(der(c, _)))
   case SEQ(r1, r2) => 
     if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2))
     else SEQ(der(c, r1), r2)
   case STAR(r1) => SEQ(der(c, r1), STAR(r1))
 }
 
-// (3) Complete the simp function according to
+
+// (3) Implement the flatten function flts. It
+// deletes 0s from a list of regular expressions
+// and also 'spills out', or flattens, nested 
+// ALTernativeS.
+
+def flts(rs: List[Rexp]) : List[Rexp] = rs match {
+  case Nil => Nil
+  case ZERO::tl => flts(tl)
+  case ALTs(rs1)::rs2 => rs1 ::: flts(rs2)  
+  case r::rs => r :: flts(rs) 
+}
+
+// (4) Complete the simp function according to
 // the specification given in the coursework; this
 // function simplifies a regular expression from
 // the inside out, like you would simplify arithmetic 
 // expressions; however it does not simplify inside 
 // STAR-regular expressions.
 
+
 def simp(r: Rexp) : Rexp = r match {
-  case ALT(r1, r2) => (simp(r1), simp(r2)) match {
-    case (ZERO, r2s) => r2s
-    case (r1s, ZERO) => r1s
-    case (r1s, r2s) => if (r1s == r2s) r1s else ALT (r1s, r2s)
+  case ALTs(rs) => (flts(rs.map(simp)).distinct) match {
+    case Nil => ZERO
+    case r::Nil => r  
+    case rs => ALTs(rs)
   }
   case SEQ(r1, r2) =>  (simp(r1), simp(r2)) match {
     case (ZERO, _) => ZERO
@@ -93,8 +109,9 @@
   case r => r
 }
 
+simp(ALT(ONE | CHAR('a'), CHAR('a') | ONE))
 
-// (4) Complete the two functions below; the first 
+// (5) Complete the two functions below; the first 
 // calculates the derivative w.r.t. a string; the second
 // is the regular expression matcher taking a regular
 // expression and a string and checks whether the
@@ -108,7 +125,7 @@
 // main matcher function
 def matcher(r: Rexp, s: String) = nullable(ders(s.toList, r))
 
-// (5) Complete the size function for regular
+// (6) Complete the size function for regular
 // expressions according to the specification 
 // given in the coursework.
 
@@ -117,7 +134,7 @@
   case ZERO => 1
   case ONE => 1
   case CHAR(_) => 1
-  case ALT(r1, r2) => 1 + size(r1) + size (r2)
+  case ALTs(rs) => 1 + rs.map(size).sum
   case SEQ(r1, r2) => 1 + size(r1) + size (r2)
   case STAR(r1) => 1 + size(r1)
 }
@@ -130,18 +147,21 @@
 //matcher(("a" ~ "b") ~ "c", "ab")   // => false
 
 // the supposedly 'evil' regular expression (a*)* b
-val EVIL = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
+// val EVIL = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
 
-//matcher(EVIL, "a" * 1000 ++ "b")   // => true
-//matcher(EVIL, "a" * 1000)          // => false
+//println(matcher(EVIL, "a" * 1000 ++ "b"))   // => true
+//println(matcher(EVIL, "a" * 1000))          // => false
 
 // size without simplifications
-//size(der('a', der('a', EVIL)))             // => 28
-//size(der('a', der('a', der('a', EVIL))))   // => 58
+//println(size(der('a', der('a', EVIL))))             // => 28
+//println(size(der('a', der('a', der('a', EVIL)))))   // => 58
 
 // size with simplification
-//size(simp(der('a', der('a', EVIL))))           // => 8
-//size(simp(der('a', der('a', der('a', EVIL))))) // => 8
+//println(simp(der('a', der('a', EVIL))))          
+//println(simp(der('a', der('a', der('a', EVIL)))))
+
+//println(size(simp(der('a', der('a', EVIL)))))           // => 8
+//println(size(simp(der('a', der('a', der('a', EVIL)))))) // => 8
 
 // Python needs around 30 seconds for matching 28 a's with EVIL. 
 // Java 9 and later increase this to an "astonishing" 40000 a's in
@@ -155,11 +175,11 @@
   val start = System.nanoTime()
   for (j <- 1 to i) code
   val end = System.nanoTime()
-  (end - start)/(i * 1.0e9)
+  "%.5f".format((end - start)/(i * 1.0e9))
 }
 
 //for (i <- 0 to 5000000 by 500000) {
-//  println(i + " " + "%.5f".format(time_needed(2, matcher(EVIL, "a" * i))) + " secs.") 
+//  println(s"$i ${time_needed(2, matcher(EVIL, "a" * i))} secs.") 
 //}
 
 // another "power" test case 
@@ -169,7 +189,7 @@
 //
 //      SEQ(SEQ(SEQ(..., ONE | ONE) , ONE | ONE), ONE | ONE)
 //
-//    where SEQ is nested 100 times.
+//    where SEQ is nested 50 times.
  
 
 
--- a/main_marking3/re_test.sh	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking3/re_test.sh	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/zsh
 
 # to make the script fail safely
 set -euo pipefail
@@ -16,7 +16,7 @@
 echo -e "" >> $out
 
 # marks for CW8
-marks=$(( 0 ))
+marks=$(( 0.0 ))
 
 # compilation tests
 
@@ -35,10 +35,11 @@
 }
 
 # purity test
+function scala_vars {
+   (sed 's/immutable/ok/g' c$out > cb$out;
+    egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' cb$out 2> /dev/null 1> /dev/null)
+}
 
-function scala_vars {
-   (egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' c$out 2> /dev/null 1> /dev/null)
-}
 
 echo -e "" >> $out
 echo -e  "Below is the feedback for your submission re.scala" >> $out
@@ -97,7 +98,7 @@
   if (scala_assert "re.scala" "re_test1.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 0.5 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
@@ -131,7 +132,7 @@
   if (scala_assert "re.scala" "re_test2.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 1.0 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
@@ -161,12 +162,33 @@
   if (scala_assert "re.scala" "re_test3.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 1.0 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
 fi
 
+### re3a flts test
+
+if [ $tsts -eq 0 ]
+then
+  echo -e " flts(Nil) == Nil" | tee -a $out
+  echo -e " flts(ZERO::ZERO::Nil) == Nil" | tee -a $out
+  echo -e " flts(ZERO::ONE::ZERO::ONE::Nil) == List(ONE, ONE)" | tee -a $out
+  echo -e " flts(ONE::ALTs(List(ONE))::ONE::Nil) == List(ONE, ONE, ONE)" | tee -a $out
+  echo -e " flts(ONE::ALTs(List(ONE))::ONE::ALTs(List(ONE))::Nil) == List(ONE, ONE, ONE, ONE)" | tee -a $out
+  
+  if (scala_assert "re.scala" "re_test3a.scala")
+  then
+      echo -e "  --> success" | tee -a $out
+      marks=$(( marks + 1.0 ))
+  else
+      echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
+  fi
+fi
+
+
+
 ### re4 test
 
 if [ $tsts -eq 0 ]
@@ -191,7 +213,7 @@
   if (scala_assert "re.scala" "re_test4.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 1.0 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
@@ -211,7 +233,7 @@
   if (scala_assert "re.scala" "re_test5.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 0.5 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
@@ -219,7 +241,6 @@
 
 ### re6 'power' test 1
 
-sleep 5
 
 if [ $tsts -eq 0 ]
 then
@@ -240,7 +261,7 @@
       DIFF=$(( $END - $START ))
       echo "   This test ran for $DIFF seconds" | tee -a $out
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 0.5 ))
   else
       END=$(date +%s)
       DIFF=$(( $END - $START ))
@@ -249,7 +270,6 @@
   fi
 fi
 
-sleep 10
 
 ### re7 'power' test 2
 
@@ -266,7 +286,7 @@
       DIFF=$(( $END - $START ))
       echo "   This test ran for $DIFF seconds" | tee -a $out
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 0.5 ))
   else
       END=$(date +%s)
       DIFF=$(( $END - $START ))
@@ -275,10 +295,11 @@
   fi
 fi
 
-sleep 10
+
 
 ## final marks
 echo -e "Overall mark for Main Part 3 (Scala)" | tee -a $out
-echo -e "$marks" | tee -a $out
+printf " %0.1f\n" $marks | tee -a $out
 
 
+
--- a/main_marking3/re_test1.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking3/re_test1.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW8c._
+import M3._
 
 assert(nullable(ZERO) == false)
 assert(nullable(ONE) == true)
--- a/main_marking3/re_test2.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking3/re_test2.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW8c._
+import M3._
 
 assert(der('a', ZERO | ONE) == (ZERO | ZERO))
 assert(der('a', (CHAR('a') | ONE) ~ CHAR('a')) == ALT((ONE | ZERO) ~ CHAR('a'), ONE))
--- a/main_marking3/re_test3.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking3/re_test3.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW8c._
+import M3._
 
 
 assert(simp(ZERO | ONE) == ONE)
@@ -16,6 +16,7 @@
 assert(simp((ZERO | ((ZERO | ZERO) | (ZERO | ZERO))) ~ ((ONE | ZERO) | ONE ) ~ (CHAR('a'))) == ZERO)
 assert(simp(ALT(ONE | ONE, ONE | ONE)) == ONE)
 assert(simp(ALT(ZERO | CHAR('a'), CHAR('a') | ZERO)) == CHAR('a'))
-assert(simp(ALT(ONE | CHAR('a'), CHAR('a') | ONE)) == ALT(ONE | CHAR('a'), CHAR('a') | ONE))
+assert(simp(ALT(ONE | CHAR('a'), CHAR('a') | ONE)) == ALT(ONE, CHAR('a')))
 
 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking3/re_test3a.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,8 @@
+import M3._
+
+
+assert(flts(Nil) == Nil)
+assert(flts(ZERO::ZERO::Nil) == Nil)
+assert(flts(ZERO::ONE::ZERO::ONE::Nil) == List(ONE, ONE))
+assert(flts(ONE::ALTs(List(ONE))::ONE::Nil) == List(ONE, ONE, ONE))
+assert(flts(ONE::ALTs(List(ONE))::ONE::ALTs(List(ONE))::Nil) == List(ONE, ONE, ONE, ONE))
--- a/main_marking3/re_test4.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking3/re_test4.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW8c._
+import M3._
 
 val EVIL_urban = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
 
--- a/main_marking3/re_test5.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking3/re_test5.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW8c._
+import M3._
  
 val EVIL_urban = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
 
--- a/main_marking3/re_test6.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking3/re_test6.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW8c._
+import M3._
 
 assert(simp(Iterator.iterate(ONE:Rexp)(r => SEQ(r, ONE | ONE)).drop(50).next) == ONE)
 assert(simp(Iterator.iterate(ONE:Rexp)(r => ALT(r, r)).drop(20).next) == ONE)
--- a/main_marking3/re_test7.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking3/re_test7.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW8c._
+import M3._
 
 val EVIL_urban = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
 
--- a/main_marking4/knight1.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking4/knight1.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,13 +1,119 @@
-// Part 1 about finding and counting Knight's tours
-//==================================================
+// Main Part 4 about finding Knight's tours
+//==========================================
+import scala.annotation.tailrec
+
+
+object M4a {
 
-object CW9a {   // for preparing the jar
+// If you need any auxiliary functions, feel free to 
+// implement them, but do not make any changes to the
+// templates below. Also have a look whether the functions
+// at the end of the file are of any help.
+
+
 
 type Pos = (Int, Int)    // a position on a chessboard 
 type Path = List[Pos]    // a path...a list of positions
 
+//(1) Complete the function that tests whether the position x
+//    is inside the board and not yet element in the path.
 
-// for measuring time in the JAR
+def is_legal(dim: Int, path: Path, x: Pos) : Boolean = {
+  (x._1 < dim) && (x._2 < dim) && (!path.contains(x))
+}
+
+
+
+//(2) Complete the function that calculates for a position x
+//    all legal onward moves that are not already in the path. 
+//    The moves should be ordered in a "clockwise" manner.
+ 
+def legal_moves(dim: Int, path: Path, x: Pos) : List[Pos] = {
+    val movesets = List(
+    (x._1 + 1, x._2 + 2),
+    (x._1 + 2, x._2 + 1),
+    (x._1 + 2, x._2 - 1),
+    (x._1 + 1, x._2 - 2),
+    (x._1 - 1, x._2 - 2),
+    (x._1 - 2, x._2 - 1),
+    (x._1 - 2, x._2 + 1),
+    (x._1 - 1, x._2 + 2)
+  )
+  movesets.filter(is_legal(dim, path, _))
+}
+
+
+//some testcases
+//
+//assert(legal_moves(8, Nil, (2,2)) == 
+//  List((3,4), (4,3), (4,1), (3,0), (1,0), (0,1), (0,3), (1,4)))
+//assert(legal_moves(8, Nil, (7,7)) == List((6,5), (5,6)))
+//assert(legal_moves(8, List((4,1), (1,0)), (2,2)) == 
+//  List((3,4), (4,3), (3,0), (0,1), (0,3), (1,4)))
+//assert(legal_moves(8, List((6,6)), (7,7)) == List((6,5), (5,6)))
+
+
+//(3) Complete the two recursive functions below. 
+//    They exhaustively search for knight's tours starting from the 
+//    given path. The first function counts all possible tours, 
+//    and the second collects all tours in a list of paths.
+
+def count_tours(dim: Int, path: Path) : Int = {
+  if (dim <= 4) 0 else {
+    if (path.length >= (dim * dim)) 1 else {
+      val movesets = legal_moves(dim, path, path.head)
+      (for (move <- movesets) yield count_tours(dim, move :: path)).sum
+    }
+  }
+}
+
+def enum_tours(dim: Int, path: Path) : List[Path] = {
+  if (dim <= 4) Nil else {
+    if (path.length >= (dim * dim)) List(path) else {
+      val movesets = legal_moves(dim, path, path.head)
+      (for (move <- movesets) yield enum_tours(dim, move :: path)).flatten
+    }
+  }
+}
+
+
+//(4) Implement a first-function that finds the first 
+//    element, say x, in the list xs where f is not None. 
+//    In that case Return f(x), otherwise None. If possible,
+//    calculate f(x) only once.
+
+@tailrec
+def first(xs: List[Pos], f: Pos => Option[Path]) : Option[Path] = {
+  xs match {
+    case Nil => None
+    case head :: rest => {
+      val result = f(head)
+      if (result.isEmpty) first(rest, f) else result
+    }
+  }
+}
+
+
+// testcases
+//
+//def foo(x: (Int, Int)) = if (x._1 > 3) Some(List(x)) else None
+//
+//first(List((1, 0),(2, 0),(3, 0),(4, 0)), foo)   // Some(List((4,0)))
+//first(List((1, 0),(2, 0),(3, 0)), foo)          // None
+
+
+//(5) Implement a function that uses the first-function from (4) for
+//    trying out onward moves, and searches recursively for a
+//    knight tour on a dim * dim-board.
+
+def first_tour(dim: Int, path: Path) : Option[Path] = ???
+ 
+
+
+/* Helper functions
+
+
+// for measuring time
 def time_needed[T](code: => T) : T = {
   val start = System.nanoTime()
   val result = code
@@ -16,6 +122,14 @@
   result
 }
 
+// can be called for example with
+//
+//     time_needed(count_tours(dim, List((0, 0))))
+//
+// in order to print out the time that is needed for 
+// running count_tours
+
+
 // for printing a board
 def print_board(dim: Int, path: Path): Unit = {
   println()
@@ -27,151 +141,7 @@
   } 
 }
 
-def is_legal(dim: Int, path: Path, x: Pos): Boolean = 
-  0 <= x._1 && 0 <= x._2 && x._1 < dim && x._2 < dim && !path.contains(x)
 
-// testcases
-//assert(is_legal(8, Nil, (3, 4)) == true)
-//assert(is_legal(8, List((4, 1), (1, 0)), (4, 1)) == false)
-//assert(is_legal(2, Nil, (0, 0)) == true)
-
-
-def add_pair(x: Pos, y: Pos): Pos = 
-  (x._1 + y._1, x._2 + y._2)
-
-def moves(x: Pos): List[Pos] = 
-  List(( 1,  2),( 2,  1),( 2, -1),( 1, -2),
-       (-1, -2),(-2, -1),(-2,  1),(-1,  2)).map(add_pair(x, _))
-
-// 1 mark
-
-def legal_moves(dim: Int, path: Path, x: Pos): List[Pos] = 
-  moves(x).filter(is_legal(dim, path, _))
-
-
-
-// testcases
-//assert(legal_moves(8, Nil, (2,2)) == 
-//  List((3,4), (4,3), (4,1), (3,0), (1,0), (0,1), (0,3), (1,4)))
-//assert(legal_moves(8, Nil, (7,7)) == List((6,5), (5,6)))
-//assert(legal_moves(8, List((4,1), (1,0)), (2,2)) == 
-//  List((3,4), (4,3), (3,0), (0,1), (0,3), (1,4)))
-//assert(legal_moves(8, List((6,6)), (7,7)) == List((6,5), (5,6)))
-//assert(legal_moves(8, Nil, (0,1)) == List((1,3), (2,2), (2,0)))
-//assert(legal_moves(1, Nil, (0,0)) == List())
-//assert(legal_moves(2, Nil, (0,0)) == List())
-//assert(legal_moves(3, Nil, (0,0)) == List((1,2), (2,1)))
-
-// 2 marks
-
-def tcount_tours(dim: Int, path: Path): Int = {
-  if (path.length == dim * dim) 1
-  else 
-    (for (x <- legal_moves(dim, path, path.head)) yield tcount_tours(dim, x::path)).sum
-}
-
-def count_tours(dim: Int, path: Path) =
-  time_needed(tcount_tours(dim: Int, path: Path))
-
-
-def tenum_tours(dim: Int, path: Path): List[Path] = {
-  if (path.length == dim * dim) List(path)
-  else 
-    (for (x <- legal_moves(dim, path, path.head)) yield tenum_tours(dim, x::path)).flatten
-}
-
-def enum_tours(dim: Int, path: Path) =
-  time_needed(tenum_tours(dim: Int, path: Path))
-
-// test cases
-
-/*
-def count_all_tours(dim: Int) = {
-  for (i <- (0 until dim).toList; 
-       j <- (0 until dim).toList) yield count_tours(dim, List((i, j)))
-}
-
-def enum_all_tours(dim: Int): List[Path] = {
-  (for (i <- (0 until dim).toList; 
-        j <- (0 until dim).toList) yield enum_tours(dim, List((i, j)))).flatten
-}
-
-
-println("Number of tours starting from (0, 0)")
-
-for (dim <- 1 to 5) {
-  println(s"${dim} x ${dim} " + time_needed(0, count_tours(dim, List((0, 0)))))
-}
-
-println("Number of tours starting from all fields")
-
-for (dim <- 1 to 5) {
-  println(s"${dim} x ${dim} " + time_needed(0, count_all_tours(dim)))
-}
-
-for (dim <- 1 to 5) {
-  val ts = enum_tours(dim, List((0, 0)))
-  println(s"${dim} x ${dim} ")   
-  if (ts != Nil) {
-    print_board(dim, ts.head)
-    println(ts.head)
-  }
-}
 */
 
-// 1 mark
-
-def first(xs: List[Pos], f: Pos => Option[Path]): Option[Path] = xs match {
-  case Nil => None
-  case x::xs => {
-    val result = f(x)
-    if (result.isDefined) result else first(xs, f)
-  }
 }
-
-// test cases
-//def foo(x: (Int, Int)) = if (x._1 > 3) Some(List(x)) else None
-//
-//first(List((1, 0),(2, 0),(3, 0),(4, 0)), foo)
-//first(List((1, 0),(2, 0),(3, 0)), foo)
-
-
-// 1 mark
-
-def tfirst_tour(dim: Int, path: Path): Option[Path] = {
-  if (path.length == dim * dim) Some(path)
-  else
-    first(legal_moves(dim, path, path.head), (x:Pos) => tfirst_tour(dim, x::path))
-}
-
-def first_tour(dim: Int, path: Path) = 
-  time_needed(tfirst_tour(dim: Int, path: Path))
-
-
-/*
-for (dim <- 1 to 8) {
-  val t = first_tour(dim, List((0, 0)))
-  println(s"${dim} x ${dim} " + (if (t == None) "" else { print_board(dim, t.get) ; "" }))
-}
-*/
-
-// 15 secs for 8 x 8
-//val ts1 = time_needed(0,first_tour(8, List((0, 0))).get)
-//val ts1 = time_needed(0,first_tour(8, List((1, 1))).get)
-
-// no result for 4 x 4
-//val ts2 = time_needed(0, first_tour(4, List((0, 0))))
-
-// 0.3 secs for 6 x 6
-//val ts3 = time_needed(0, first_tour(6, List((0, 0))))
-
-// 15 secs for 8 x 8
-//time_needed(0, print_board(8, first_tour(8, List((0, 0))).get))
-
-
-
-
-
-}
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking4/knight1_test1.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,9 @@
+import M4a._
+
+assert(is_legal(8, Nil, (3, 4)) == true)
+assert(is_legal(8, List((4, 1), (1, 0)), (4, 1)) == false)
+assert(is_legal(2, Nil, (0, 0)) == true)
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking4/knight1_test2.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,13 @@
+import M4a._
+
+assert(legal_moves(8, Nil, (2,2)) == 
+             List((3,4), (4,3), (4,1), (3,0), (1,0), (0,1), (0,3), (1,4)))
+assert(legal_moves(8, Nil, (7,7)) == List((6,5), (5,6)))
+assert(legal_moves(8, List((4,1), (1,0)), (2,2)) == 
+       List((3,4), (4,3), (3,0), (0,1), (0,3), (1,4)))
+assert(legal_moves(8, Nil, (0,1)) == List((1,3), (2,2), (2,0)))
+assert(legal_moves(8, List((6,6)), (7,7)) == List((6,5), (5,6)))
+assert(legal_moves(1, Nil, (0,0)) == Nil)
+assert(legal_moves(2, Nil, (0,0)) == Nil)
+assert(legal_moves(3, Nil, (0,0)) == List((1,2), (2,1)))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking4/knight1_test3a.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,14 @@
+import M4a._
+
+def count_all_tours_urban(dim: Int) = {
+  for (i <- (0 until dim).toList; 
+       j <- (0 until dim).toList) yield count_tours(dim, List((i, j)))
+}
+
+
+assert(count_all_tours_urban(1) == List(1))
+assert(count_all_tours_urban(2) == List(0, 0, 0, 0))
+assert(count_all_tours_urban(3) == List(0, 0, 0, 0, 0, 0, 0, 0, 0))
+assert(count_all_tours_urban(4) == List(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking4/knight1_test3b.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,19 @@
+import M4a._
+//type Pos = (Int, Int)    // a position on a chessboard 
+//type Path = List[Pos]    // a path...a list of positions
+
+/*
+def count_all_tours_urban(dim: Int) = {
+  for (i <- (0 until dim).toList; 
+       j <- (0 until dim).toList) yield count_tours(dim, List((i, j)))
+}
+*/
+
+def count_all_tours_urban(dim: Int) = {
+  for (i <- (0 until 3).toList; 
+       j <- (0 until dim).toList) yield count_tours(dim, List((i, j)))
+}
+
+
+assert(count_all_tours_urban(5) == List(304, 0, 56, 0, 304, 0, 56, 0, 56, 0, 56, 0, 64, 0, 56))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking4/knight1_test3c.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,33 @@
+import M4a._
+
+//type Pos = (Int, Int)    // a position on a chessboard 
+//type Path = List[Pos]    // a path...a list of positions
+
+def add_pair_urban(x: Pos)(y: Pos): Pos = 
+  (x._1 + y._1, x._2 + y._2)
+
+def is_legal_urban(dim: Int, path: Path)(x: Pos): Boolean = 
+  0 <= x._1 && 0 <= x._2 && x._1 < dim && x._2 < dim && !path.contains(x)
+
+def moves_urban(x: Pos): List[Pos] = 
+  List(( 1,  2),( 2,  1),( 2, -1),( 1, -2),
+       (-1, -2),(-2, -1),(-2,  1),(-1,  2)).map(add_pair_urban(x))
+
+def legal_moves_urban(dim: Int, path: Path, x: Pos): List[Pos] = 
+  moves_urban(x).filter(is_legal_urban(dim, path))
+
+def correct_urban(dim: Int)(p: Path): Boolean = p match {
+  case Nil => true
+  case x::Nil => true
+  case x::y::p => if (legal_moves_urban(dim, p, y).contains(x)) correct_urban(dim)(y::p) else false
+}
+
+
+val ts00_urban = enum_tours(5, List((0, 0)))
+assert(ts00_urban.map(correct_urban(5)).forall(_ == true) == true)
+assert(ts00_urban.length == 304)  
+
+
+val ts_urban = enum_tours(5, List((0, 2)))
+assert(ts_urban.map(correct_urban(5)).forall(_ == true) == true)
+assert(ts_urban.length == 56)  
--- a/main_marking4/knight1_test4.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking4/knight1_test4.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW9a._
+import M4a._
 
 
 val f_urban = (x:(Int, Int)) => if (x._1 > 3) Some(List(x)) else None
--- a/main_marking4/knight1_test5.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking4/knight1_test5.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW9a._
+import M4a._
 
 //type Pos = (Int, Int)    // a position on a chessboard 
 //type Path = List[Pos]    // a path...a list of positions
--- a/main_marking4/knight2.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking4/knight2.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,7 +1,7 @@
-// Part 3 about finding a single tour using the Warnsdorf Rule
+// Part 2 about finding a single tour using the Warnsdorf Rule
 //=============================================================
 
-object CW9b {
+object M4b { // for preparing the jar
 
 type Pos = (Int, Int)
 type Path = List[Pos]
@@ -67,7 +67,6 @@
 def first_closed_tour_heuristic(dim: Int, path: Path) =
  time_needed(tfirst_closed_tour_heuristics(dim: Int, path: Path))
 
-
 // heuristic cannot be used to search for closed tours on 7 x 7 an beyond
 //for (dim <- 1 to 6) {
 //  val t = time_needed(0, first_closed_tour_heuristics(dim, List((dim / 2, dim / 2))))
--- a/main_marking4/knight2_test.sh	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,310 +0,0 @@
-#!/bin/bash
-
-# to make the script fail safely
-set -euo pipefail
-
-
-out=${1:-output}
-
-echo "" > $out
-
-echo -e `date` >> $out
-echo -e  "" >> $out
-echo "Below is the feedback and provisional marks for your submission" >> $out
-echo "for the Main Part 4 (Scala).  Please note all marks are provisional until" >> $out
-echo "ratified by the assessment board -- this is not an official" >> $out
-echo "results transcript." >> $out
-echo "" >> $out
-
-# marks for Main CW4
-marks=$(( 0 ))
-
-# compilation tests
-
-function scala_compile {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -Xprint:parser "$1" 2> c$out 1> c$out)
-}
-
-# functional tests
-
-function scala_assert {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)
-}
-
-function scala_assert_thirty {
-  (ulimit -t 40; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)  
-}
-
-# purity test
-
-function scala_vars {
-   (egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' c$out 2> /dev/null 1> /dev/null)
-}
-
-echo -e "" >> $out
-echo -e  "Below is the feedback for your submission knight1.scala" >> $out
-echo -e  "" >> $out
-
-
-# compilation test
-
-echo -e "knight1.scala is present?" | tee -a $out
-
-if [ -f "knight1.scala" ]; then
-    echo -e "  --> success" | tee -a $out
-    tsts=$(( 0 ))
-else 
-    echo -e "  --> knight1.scala is not present\n" | tee -a $out
-    tsts=$(( 1 )) 
-fi
-
-
-
-
-if [ $tsts -eq 0 ]
-then
-    echo -e "knight1.scala runs?" | tee -a $out
-    
-    if (scala_compile knight1.scala)
-    then
-	echo -e "  --> success " | tee -a $out
-	tsts=$(( 0 ))
-    else
-	echo -e "  --> SCALA DID NOT RUN knight1.scala\n" | tee -a $out
-	tsts=$(( 1 )) 
-    fi
-else
-    tsts=$(( 1 ))  
-fi 
-
-# knights1: purity test
-
-
-if [ $tsts -eq 0 ]
-then 
-    echo -e "knight1.scala does not contain VARS, RETURNS etc?" | tee -a $out
-
-    if (scala_vars knight1.scala)
-    then
-	echo -e "  --> TEST FAILED\n" | tee -a $out
-	tsts=$(( 1 ))
-    else
-	echo -e "  --> success" | tee -a $out
-	tsts=$(( 0 )) 
-    fi
-else
-    tsts=$(( 1 ))  
-fi    
-
-
-### knight4 test
-
-if [ $tsts -eq 0 ]
-then
-  echo -e " Let f = (x:(Int, Int)) => if (x._1 > 3) Some(List(x)) else None " | tee -a $out
-  echo -e "   first(List((1,0),(2,0),(3,0),(4,0)), f) == Some(List((4,0)))" | tee -a $out
-  echo -e "   first(List((1,0),(2,0),(3,0)), f) == None" | tee -a $out  
-  
-  if (scala_assert "knight1.scala" "knight1_test4.scala") 
-  then
-      echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
-  else
-      echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
-  fi
-fi
-
-sleep 4
-
-### knight5 test
-
-if [ $tsts -eq 0 ]
-then
-  echo -e " is first_tour(6, List((0,0))) ok? " | tee -a $out
-  echo -e " is first_tour(4, List((0,0))) == None " | tee -a $out
-  START=$(date +%s)
-  
-  if (scala_assert_thirty "knight1.scala" "knight1_test5.scala") 
-  then
-      END=$(date +%s)
-      DIFF=$(( $END - $START ))
-      echo -e "  This test ran for $DIFF seconds" | tee -a $out  
-      echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
-  else
-      END=$(date +%s)
-      DIFF=$(( $END - $START ))
-      echo -e "  This test ran for $DIFF seconds" | tee -a $out 
-      echo -e "  --> TEST FAILED\n" | tee -a $out
-  fi
-fi
-
-
-echo -e "" >> $out
-echo -e  "Below is the feedback for your submission knight2.scala" >> $out
-echo -e  "" >> $out
-
-
-# knights2: compilation test
-
-echo "knight2.scala runs?" | tee -a $out
-
-if (scala_compile knight2.scala)
-then
-    echo -e "  --> success" | tee -a $out
-    tsts=$(( 0 ))
-else
-    echo -e "  --> SCALA DID NOT RUN knight2.scala\n" | tee -a $out
-    tsts=$(( 1 )) 
-fi
-
-
-
-# knights2: purity test
-#
-if [ $tsts -eq 0 ]
-then 
-    echo "knight2.scala does not VARS, RETURNS etc?" | tee -a $out
-
-    if (scala_vars knight2.scala)
-    then   
-	echo -e "  --> TEST FAILED\n" | tee -a $out
-	tsts=$(( 1 ))
-    else
-	echo -e "  --> success" | tee -a $out
-	tsts=$(( 0 )) 
-    fi
-else
-    tsts=$(( 1 ))  
-fi
-
-
-# ordered move test
-
-if [ $tsts -eq 0 ]
-then
-  echo -e " ordered_moves(8, List((3,4), (3,2)), (1,3)) == List((0,1), (0,5), (2,1), (2,5))" | tee -a $out
-  echo -e " ordered_moves(8, List((4,0)), (0,0)) == List((2,1), (1,2))" | tee -a $out
-  echo -e " ordered_moves(8, List((0,4)), (0,0)) == List((1,2), (2,1))" | tee -a $out
-  
-  if (scala_assert "knight2.scala" "knight2_test6.scala")
-  then
-      echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
-  else
-      echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
-  fi
-fi
-
-sleep 4
-
-# first-closed-tour test
-
-if [ $tsts -eq 0 ]
-then
-  echo -e " first_closed_tour_heuristics(6, List((3,3))) found and correct?" | tee -a $out
-  START=$(date +%s)
-  
-  if (scala_assert_thirty "knight2.scala" "knight2_test7.scala")
-  then
-      END=$(date +%s)
-      DIFF=$(( $END - $START ))
-      echo -e "  This test ran for $DIFF seconds" | tee -a $out 
-      echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
-  else
-      END=$(date +%s)
-      DIFF=$(( $END - $START ))
-      echo -e "  This test ran for $DIFF seconds." | tee -a $out 
-      echo -e "  --> TEST FAILED\n" | tee -a $out
-  fi
-fi
-
-sleep 4
-
-# first-tour test
-
-if [ $tsts -eq 0 ]
-then
-  echo -e " first_tour_heuristics(8, List((0,0))) found and correct?" | tee -a $out
-  echo -e " first_tour_heuristics(30, List((0,0))) found and correct?" | tee -a $out
-  START=$(date +%s)
-  
-  if (scala_assert_thirty "knight2.scala" "knight2_test8.scala")
-  then
-      END=$(date +%s)
-      DIFF=$(( $END - $START ))
-      echo "  This test ran for $DIFF seconds" | tee -a $out
-      echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
-  else
-      END=$(date +%s)
-      DIFF=$(( $END - $START ))
-      echo "  This test ran for $DIFF seconds." | tee -a $out
-      echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
-  fi
-fi
-
-echo -e "" >> $out
-echo -e  "Below is the feedback for your submission knight3.scala" >> $out
-echo -e  "" >> $out
-
-# compilation test
-echo "knight3.scala runs?" | tee -a $out
-
-if (scala_compile knight3.scala)
-then
-    echo "  --> success" | tee -a $out
-    tsts=$(( 0 ))
-else
-    echo -e "  --> SCALA DID NOT RUN knight3.scala\n" | tee -a $out  
-    tsts=$(( 1 )) 
-fi
-
-
-# knights3: purity test
-#
-if [ $tsts -eq 0 ]
-then 
-    echo -e "knight3.scala does not contain VARS, RETURNS etc?" | tee -a $out
-
-    if (scala_vars knight3.scala)
-    then
-	echo "  --> TEST FAILED\n" | tee -a $out
-	tsts=$(( 1 ))
-    else
-	echo "  --> success" | tee -a $out
-	tsts=$(( 0 )) 
-    fi
-else
-    tsts=$(( 1 ))  
-fi
-
-sleep 4
-
-if [ $tsts -eq 0 ]
-then
-  echo -e " tour_on_mega_board(70, List((0,0))) found and correct?" | tee -a $out
-  START=$(date +%s)
-  
-  if (scala_assert_thirty "knight3.scala" "knight3_test9.scala")
-  then
-      END=$(date +%s)
-      DIFF=$(( $END - $START ))
-      echo -e "  This test ran for $DIFF seconds." | tee -a $out
-      echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
-  else
-      END=$(date +%s)
-      DIFF=$(( $END - $START ))
-      echo -e "  This test ran for $DIFF seconds." | tee -a $out
-      echo -e "  --> TEST FAILED\n" | tee -a $out 
-  fi
-fi
-
-sleep 4
-
-## final marks
-echo -e "" >> $out
-echo -e "Overall mark for Main Part 4 (Scala)" | tee -a $out
-echo -e "$marks" | tee -a $out
--- a/main_marking4/knight2_test6.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking4/knight2_test6.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,19 +1,6 @@
-import CW9b._
+import M4b._
 
 assert(ordered_moves(8, List((3,4), (3,2)), (1, 3)) == List((0,1), (0,5), (2,1), (2,5)))
 assert(ordered_moves(8, List((4,0)), (0,0)) == List((2,1), (1,2)))
 assert(ordered_moves(8, List((0,4)), (0,0)) == List((1,2), (2,1)))
 
-
-
-/*
-import scala.concurrent._
-import scala.concurrent.duration._
-import ExecutionContext.Implicits.global
-import scala.language.postfixOps 
-
-lazy val f = Future {
-}
-
-Await.result(f, 120 second)
-*/
--- a/main_marking4/knight2_test7.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking4/knight2_test7.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW9b._
+import M4b._
 
 //type Pos = (Int, Int)
 //type Path = List[Pos]
--- a/main_marking4/knight2_test8.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking4/knight2_test8.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW9b._
+import M4b._
 
 //type Pos = (Int, Int)
 //type Path = List[Pos]
--- a/main_marking4/knight3.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking4/knight3.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,7 +1,7 @@
 // Part 3 about finding a single tour using the Warnsdorf Rule
 //=============================================================
 
-object CW9c { 
+object M4c { // for preparing the jar
 
 type Pos = (Int, Int)
 type Path = List[Pos]
@@ -60,4 +60,8 @@
 def tour_on_mega_board(dim: Int, path: Path) =
   time_needed(ttour_on_mega_board(dim: Int, path: Path))
 
+
+// testcases
+//print_board(70, tour_on_mega_board(70, List((0, 0))).get)
+
 }
--- a/main_marking4/knight3_test9.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking4/knight3_test9.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW9c._
+import M4c._
 
 //type Pos = (Int, Int)
 //type Path = List[Pos]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking4/knight_test.sh	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,419 @@
+#!/bin/zsh
+
+# to make the script fail safely
+set -euo pipefail
+
+out=${1:-output}
+
+echo "" > $out
+
+echo `date` >> $out
+echo -e "" >> $out
+echo -e "Below is the feedback and provisional marks for your submission" >> $out
+echo -e "of the Main Part 4 (Scala).  Please note all marks are provisional until" >> $out
+echo -e "ratified by the assessment board -- this is not an official" >> $out
+echo -e "results transcript." >> $out
+echo -e "" >> $out
+
+echo -e "" >> $out
+echo -e "Below is the feedback for your submission knight1.scala" >> $out
+echo -e "" >> $out
+
+
+
+# marks for CW8 part 1
+marks=$(( 0.0 ))
+
+# compilation tests
+
+function scala_compile {
+  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -Xprint:parser "$1" 2> c$out 1> c$out)
+}
+
+# functional tests
+
+function scala_assert {
+  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)
+}
+
+function scala_assert_slow {
+  (ulimit -t 120; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)  
+}
+
+function scala_assert_thirty {
+  (ulimit -t 40; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)  
+}
+
+function scala_assert_quick {
+  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)    
+}
+
+function scala_assert_long {
+  (ulimit -t 60; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)    
+}
+
+function scala_assert_elong {
+  (ulimit -t 90; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null) 
+}
+
+# purity test
+function scala_vars {
+   (sed 's/immutable/ok/g' c$out > cb$out;
+    egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' cb$out 2> /dev/null 1> /dev/null)
+}
+
+
+
+# compilation test
+
+echo -e "knight1.scala runs?" | tee -a $out
+
+if (scala_compile knight1.scala)
+then
+    echo -e "  --> success " | tee -a $out
+    tsts=$(( 0 ))
+else
+    echo -e "  --> SCALA DID NOT RUN KNIGHT1.SCALA\n" | tee -a $out
+    tsts=$(( 1 )) 
+fi
+
+
+# knights1: purity test
+if  [ $tsts -eq 0 ]
+  then   
+  echo -e "knight1.scala does not contain VARS, RETURNS etc?" | tee -a $out
+
+  if (scala_vars knight1.scala)
+  then
+     echo -e "  --> FAIL\n" | tee -a $out
+     tsts=$(( 1 ))
+  else
+     echo -e "  --> success" | tee -a $out
+     tsts=$(( 0 )) 
+  fi
+else
+  tsts=$(( 1 ))  
+fi
+
+echo >> $out
+
+### knight1 test
+
+if [ $tsts -eq 0 ]
+then
+    echo " is_legal(8, Nil, (3, 4)) == true " | tee -a $out
+    echo " is_legal(8, List((4, 1), (1, 0)), (4, 1)) == false " | tee -a $out
+    echo " is_legal(2, Nil, (0, 0)) == true" | tee -a $out                          
+
+    if (scala_assert "knight1.scala" "knight1_test1.scala")
+    then
+        echo -e "  --> success" | tee -a $out
+	marks=$(( marks + 1.0 ))
+    else
+        echo -e "  --> \n ONE TEST FAILED\n"| tee -a $out
+    fi
+fi
+
+### knight2 test
+
+if [ $tsts -eq 0 ]
+then
+  echo " legal_moves(8, Nil, (2,2)) == List((3,4), (4,3), (4,1), (3,0), (1,0), (0,1), (0,3), (1,4))" | tee -a $out
+  echo " legal_moves(8, Nil, (7,7)) == List((6,5), (5,6))" | tee -a $out
+  echo " legal_moves(8, List((4,1), (1,0)), (2,2)) == List((3,4), (4,3), (3,0), (0,1), (0,3), (1,4))" | tee -a $out
+  echo " legal_moves(8, Nil, (0,1)) == List((1,3), (2,2), (2,0))" | tee -a $out
+  echo " legal_moves(8, List((6,6)), (7,7)) == List((6,5), (5,6))" | tee -a $out
+  echo " legal_moves(1, Nil, (0,0)) == Nil" | tee -a $out
+  echo " legal_moves(2, Nil, (0,0)) == Nil" | tee -a $out
+  echo " legal_moves(3, Nil, (0,0)) == List((1,2), (2,1))" | tee -a $out
+  
+  if (scala_assert "knight1.scala" "knight1_test2.scala")
+  then
+     echo -e "  --> success\n" | tee -a $out
+     marks=$(( marks + 1 ))
+  else
+     echo -e "  --> ONE TEST FAILED\n" | tee -a $out
+  fi
+fi
+
+
+### knight3 test
+
+if [ $tsts -eq 0 ]
+then
+  echo " count_tours from every position on the board 1 - 4 (0.5% marks)" | tee -a $out
+  echo " dim = 1: 1" | tee -a $out
+  echo "       2: 0,0,0,0" | tee -a $out
+  echo "       3: 0,0,0,0,0,0,0,0,0" | tee -a $out
+  echo "       4: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" | tee -a $out
+  START=$(date +%s)
+  
+  if (scala_assert_thirty "knight1.scala" "knight1_test3a.scala") 
+  then
+     END=$(date +%s)
+     DIFF=$(( $END - $START ))
+     #echo " This test ran for $DIFF seconds." | tee -a $out  
+     echo -e "  --> success\n" | tee -a $out
+     marks=$(( marks + 0.5 ))
+  else
+     END=$(date +%s)
+     DIFF=$(( $END - $START ))
+     echo " This test ran for $DIFF seconds." | tee -a $out 
+     echo -e "  --> ONE TEST FAILED\n" | tee -a $out
+  fi
+fi
+
+
+
+if [ $tsts -eq 0 ]
+then
+  echo " count_tours from every position on the board of dim 5 for the first 3 rows (0.25% marks)" | tee -a $out
+  echo " dim = 5: 304,0,56,0,304,0,56,0,56,0,56,0,64,0,56)" | tee -a $out
+  START=$(date +%s)
+  
+  if (scala_assert_thirty "knight1.scala" "knight1_test3b.scala") 
+  then
+     END=$(date +%s)
+     DIFF=$(( $END - $START ))
+     #echo " This test ran for $DIFF seconds." | tee -a $out  
+     echo -e "  --> success\n" | tee -a $out
+     marks=$(( marks + 0.25 ))
+  else
+     END=$(date +%s)
+     DIFF=$(( $END - $START ))
+     echo " This test ran for $DIFF seconds." | tee -a $out 
+     echo -e "  --> ONE TEST FAILED\n" | tee -a $out
+  fi
+fi
+
+
+
+if [ $tsts -eq 0 ]
+then
+  echo " enum_tours(5, List((0,2)) ) => 56 tours? and all correct?" | tee -a $out
+  echo " enum_tours(5, List((0,0)) ) => 304 tours? and all correct?" | tee -a $out
+  echo " (0.25% marks) " | tee -a $out
+  START=$(date +%s)
+  
+  if (scala_assert_thirty "knight1.scala" "knight1_test3c.scala") 
+  then
+     END=$(date +%s)
+     DIFF=$(( $END - $START ))
+     #echo " This test ran for $DIFF seconds." | tee -a $out 
+     echo -e "  --> success\n" | tee -a $out
+     marks=$(( marks + 0.25 ))
+  else
+     END=$(date +%s)
+     DIFF=$(( $END - $START ))
+     echo " This test ran for $DIFF seconds." | tee -a $out 
+     echo -e "  --> \n ONE TEST FAILED\n" | tee -a $out
+  fi
+fi
+
+
+### knight4 test
+
+if [ $tsts -eq 0 ]
+then
+  echo -e " Let f = (x:(Int, Int)) => if (x._1 > 3) Some(List(x)) else None " | tee -a $out
+  echo -e "   first(List((1,0),(2,0),(3,0),(4,0)), f) == Some(List((4,0)))" | tee -a $out
+  echo -e "   first(List((1,0),(2,0),(3,0)), f) == None" | tee -a $out  
+  
+  if (scala_assert "knight1.scala" "knight1_test4.scala") 
+  then
+      echo -e "  --> success" | tee -a $out
+      marks=$(( marks + 1.0 ))
+  else
+      echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
+  fi
+fi
+
+### knight5 test
+
+if [ $tsts -eq 0 ]
+then
+  echo -e " is first_tour(6, List((0,0))) ok? " | tee -a $out
+  echo -e " is first_tour(4, List((0,0))) == None " | tee -a $out
+  START=$(date +%s)
+  
+  if (scala_assert_thirty "knight1.scala" "knight1_test5.scala") 
+  then
+      END=$(date +%s)
+      DIFF=$(( $END - $START ))
+      echo -e "  This test ran for $DIFF seconds" | tee -a $out  
+      echo -e "  --> success" | tee -a $out
+      marks=$(( marks + 1.0 ))
+  else
+      END=$(date +%s)
+      DIFF=$(( $END - $START ))
+      echo -e "  This test ran for $DIFF seconds" | tee -a $out 
+      echo -e "  --> TEST FAILED\n" | tee -a $out
+  fi
+fi
+
+echo -e "" >> $out
+echo -e  "Below is the feedback for your submission knight2.scala" >> $out
+echo -e  "" >> $out
+
+
+# knights2: compilation test
+
+echo "knight2.scala runs?" | tee -a $out
+
+if (scala_compile knight2.scala)
+then
+    echo -e "  --> success" | tee -a $out
+    tsts=$(( 0 ))
+else
+    echo -e "  --> SCALA DID NOT RUN knight2.scala\n" | tee -a $out
+    tsts=$(( 1 )) 
+fi
+
+
+
+# knights2: purity test
+#
+if [ $tsts -eq 0 ]
+then 
+    echo "knight2.scala does not VARS, RETURNS etc?" | tee -a $out
+
+    if (scala_vars knight2.scala)
+    then   
+	echo -e "  --> TEST FAILED\n" | tee -a $out
+	tsts=$(( 1 ))
+    else
+	echo -e "  --> success" | tee -a $out
+	tsts=$(( 0 )) 
+    fi
+else
+    tsts=$(( 1 ))  
+fi
+
+
+# ordered move test
+
+if [ $tsts -eq 0 ]
+then
+  echo -e " ordered_moves(8, List((3,4), (3,2)), (1,3)) == List((0,1), (0,5), (2,1), (2,5))" | tee -a $out
+  echo -e " ordered_moves(8, List((4,0)), (0,0)) == List((2,1), (1,2))" | tee -a $out
+  echo -e " ordered_moves(8, List((0,4)), (0,0)) == List((1,2), (2,1))" | tee -a $out
+  
+  if (scala_assert "knight2.scala" "knight2_test6.scala")
+  then
+      echo -e "  --> success" | tee -a $out
+      marks=$(( marks + 1.0 ))
+  else
+      echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
+  fi
+fi
+
+
+# first-closed-tour test
+
+if [ $tsts -eq 0 ]
+then
+  echo -e " first_closed_tour_heuristics(6, List((3,3))) found and correct?" | tee -a $out
+  START=$(date +%s)
+  
+  if (scala_assert_thirty "knight2.scala" "knight2_test7.scala")
+  then
+      END=$(date +%s)
+      DIFF=$(( $END - $START ))
+      echo -e "  This test ran for $DIFF seconds" | tee -a $out 
+      echo -e "  --> success" | tee -a $out
+      marks=$(( marks + 1.0 ))
+  else
+      END=$(date +%s)
+      DIFF=$(( $END - $START ))
+      echo -e "  This test ran for $DIFF seconds." | tee -a $out 
+      echo -e "  --> TEST FAILED\n" | tee -a $out
+  fi
+fi
+
+
+# first-tour test
+
+if [ $tsts -eq 0 ]
+then
+  echo -e " first_tour_heuristics(8, List((0,0))) found and correct?" | tee -a $out
+  echo -e " first_tour_heuristics(30, List((0,0))) found and correct?" | tee -a $out
+  START=$(date +%s)
+  
+  if (scala_assert_thirty "knight2.scala" "knight2_test8.scala")
+  then
+      END=$(date +%s)
+      DIFF=$(( $END - $START ))
+      echo "  This test ran for $DIFF seconds" | tee -a $out
+      echo -e "  --> success" | tee -a $out
+      marks=$(( marks + 1.0 ))
+  else
+      END=$(date +%s)
+      DIFF=$(( $END - $START ))
+      echo "  This test ran for $DIFF seconds." | tee -a $out
+      echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
+  fi
+fi
+
+echo -e "" >> $out
+echo -e  "Below is the feedback for your submission knight3.scala" >> $out
+echo -e  "" >> $out
+
+# compilation test
+echo "knight3.scala runs?" | tee -a $out
+
+if (scala_compile knight3.scala)
+then
+    echo "  --> success" | tee -a $out
+    tsts=$(( 0 ))
+else
+    echo -e "  --> SCALA DID NOT RUN knight3.scala\n" | tee -a $out  
+    tsts=$(( 1 )) 
+fi
+
+
+# knights3: purity test
+#
+if [ $tsts -eq 0 ]
+then 
+    echo -e "knight3.scala does not contain VARS, RETURNS etc?" | tee -a $out
+
+    if (scala_vars knight3.scala)
+    then
+	echo "  --> TEST FAILED\n" | tee -a $out
+	tsts=$(( 1 ))
+    else
+	echo "  --> success" | tee -a $out
+	tsts=$(( 0 )) 
+    fi
+else
+    tsts=$(( 1 ))  
+fi
+
+
+if [ $tsts -eq 0 ]
+then
+  echo -e " tour_on_mega_board(70, List((0,0))) found and correct?" | tee -a $out
+  START=$(date +%s)
+  
+  if (scala_assert_thirty "knight3.scala" "knight3_test9.scala")
+  then
+      END=$(date +%s)
+      DIFF=$(( $END - $START ))
+      echo -e "  This test ran for $DIFF seconds." | tee -a $out
+      echo -e "  --> success" | tee -a $out
+      marks=$(( marks + 1.0 ))
+  else
+      END=$(date +%s)
+      DIFF=$(( $END - $START ))
+      echo -e "  This test ran for $DIFF seconds." | tee -a $out
+      echo -e "  --> TEST FAILED\n" | tee -a $out 
+  fi
+fi
+
+
+## final marks
+echo -e "" >> $out
+echo -e "Overall mark for Main Part 4 (Scala)" | tee -a $out
+printf " %0.2f\n" $marks | tee -a $out
+
+
--- a/main_marking4/mk	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-#!/bin/sh
-###set -e
-
-trap "exit" INT
-
-files=${1:-*/main4}
-
-for sd in $files; do
-  cd $sd
-  echo $sd
-  sleep 5
-  touch .
-  cp ../../../../../main_marking4/knight2_test.sh .
-  cp ../../../../../main_marking4/knight1_test4.scala .
-  cp ../../../../../main_marking4/knight1_test5.scala .
-  cp ../../../../../main_marking4/knight2_test6.scala .
-  cp ../../../../../main_marking4/knight2_test7.scala .
-  cp ../../../../../main_marking4/knight2_test8.scala .
-  cp ../../../../../main_marking4/knight3_test9.scala .
-  ./knight2_test.sh output
-  rm knight2_test.sh
-  rm knight1_test4.scala
-  rm knight1_test5.scala
-  rm knight2_test6.scala
-  rm knight2_test7.scala
-  rm knight2_test8.scala
-  rm knight3_test9.scala
-  cd ..
-  cd ..
-done
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking4/mk_main4	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,42 @@
+#!/bin/bash
+###set -e
+
+trap "exit" INT
+
+files=${1:-*/main4}
+
+for sd in $files; do
+  echo -e "\n"
+  cd $sd
+  echo $sd
+  touch .
+  cp ../../../../../main_marking4/knight_test.sh .
+  cp ../../../../../main_marking4/knight1_test1.scala .
+  cp ../../../../../main_marking4/knight1_test2.scala .
+  cp ../../../../../main_marking4/knight1_test3a.scala .
+  cp ../../../../../main_marking4/knight1_test3b.scala .
+  cp ../../../../../main_marking4/knight1_test3c.scala .
+  cp ../../../../../main_marking4/knight1_test4.scala .
+  cp ../../../../../main_marking4/knight1_test5.scala .
+  cp ../../../../../main_marking4/knight2_test6.scala .
+  cp ../../../../../main_marking4/knight2_test7.scala .
+  cp ../../../../../main_marking4/knight2_test8.scala .
+  cp ../../../../../main_marking4/knight3_test9.scala .
+  ./knight_test.sh output
+  rm knight_test.sh
+  rm knight1_test1.scala
+  rm knight1_test2.scala
+  rm knight1_test3a.scala 
+  rm knight1_test3b.scala
+  rm knight1_test3c.scala
+  rm knight1_test4.scala
+  rm knight1_test5.scala
+  rm knight2_test6.scala
+  rm knight2_test7.scala
+  rm knight2_test8.scala
+  rm knight3_test9.scala
+  cd ..
+  cd ..
+done
+
+
--- a/main_marking5/bf.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking5/bf.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -2,7 +2,7 @@
 // the Brainf***++ language
 //==============================================
 
-object CW10a {  
+object M5a {  
 
 
 // representation of Bf memory 
@@ -96,18 +96,11 @@
       case '+' => (pc + 1, mp, write(mem, mp, sread(mem, mp) + 1))
       case '-' => (pc + 1, mp, write(mem, mp, sread(mem, mp) - 1))
       case '.' => { print(sread(mem, mp).toChar); (pc + 1, mp, mem) }
-      //case ',' => (pc + 1, mp, write(mem, mp, Console.in.read().toByte))
-      //case ',' => (pc + 1, mp, write(mem, mp, scala.io.StdIn.readByte()))
       case '['  => 
 	      if (sread(mem, mp) == 0) (jumpRight(prog, pc + 1, 0), mp, mem) else (pc + 1, mp, mem) 
       case ']'  => 
 	      if (sread(mem, mp) != 0) (jumpLeft(prog, pc - 1, 0), mp, mem) else (pc + 1, mp, mem) 
  
-      // new commands
-      case '@' => (pc + 1, mp, write(mem, sread(mem, mp), sread(mem, mp - 1)))
-      case '*' => (pc + 1, mp, write(mem, mp, sread(mem, mp) * sread(mem, mp -1)))
-      case '#' => { println(s"${sread(mem, mp)}"); (pc + 1, mp, mem) }
-      
       case _ => (pc + 1, mp, mem)
     }		     
     compute(prog, new_pc, new_mp, new_mem)	
@@ -142,15 +135,6 @@
 // prints out numbers 0 to 9
 //run("""+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]""")
 
-// bf++ program calculating the cube-function, 10 * 10 * 10 = 1000
-//run("""++++++++++#>+***#""")           // Map(0 -> 10, 1 -> 1000)
-
-
-// bf++ program copies 3 from 0-cell to to cells 1, 4, 5, 6 and 7
-// (note that because of how the program wprks cell 1 will contain 7) 
-//run("""+++>+@+@+@+@+@""")   // Map(0 -> 3, 1 -> 7, 4 -> 3, 5 -> 3, 6 -> 3, 7 -> 3)
-
-
 
 // some more "useful" programs
 //-----------------------------
@@ -225,3 +209,7 @@
 //run(load_bff("collatz.bf"))
 
 }
+
+
+//M5a.run(M5a.load_bff("mandelbrot.bf"))
+//M5a.run(M5a.load_bff("collatz.bf"))
--- a/main_marking5/bf_test.sh	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking5/bf_test.sh	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/zsh
 
 # to make the script fail safely
 set -euo pipefail
@@ -17,7 +17,7 @@
 echo -e "" >> $out
 
 # marks for CW10 part 1
-marks=$(( 0 ))
+marks=$(( 0.0 ))
 
 # compilation tests
 
@@ -36,9 +36,9 @@
 }
 
 # purity test
-
 function scala_vars {
-   (egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' c$out 2> /dev/null 1> /dev/null)
+   (sed 's/immutable/ok/g' c$out > cb$out;
+    egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' cb$out 2> /dev/null 1> /dev/null)
 }
 
 
@@ -90,7 +90,7 @@
   if (scala_assert "bf.scala" "bf_test1.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 0.5 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
@@ -109,7 +109,7 @@
   if (scala_assert "bf.scala" "bf_test2.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 0.5 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
@@ -131,7 +131,7 @@
   if (scala_assert "bf.scala" "bf_test3.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 2 ))
+      marks=$(( marks + 2.0 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
@@ -144,8 +144,6 @@
   echo -e " run(\"[-]\", Map(0 -> 100)) == Map(0 -> 0)" | tee -a $out
   echo -e " run(\"[->+<]\", Map(0 -> 10)) == Map(0 -> 0, 1 -> 10)" | tee -a $out
   echo -e " run(\"[>>+>>+<<<<-]\", Map(0 -> 42)) == Map(0 -> 0, 2 -> 42, 4 -> 42)" | tee -a $out
-  echo -e " run(\"++++++++++#>+***#\") == Map(0 -> 10, 1 -> 1000)" | tee -a $out
-  echo -e " run(\"+++>+@+@+@+@+@\") == Map(0 -> 3, 1 -> 7, 4 -> 3, 5 -> 3, 6 -> 3, 7 -> 3)" | tee -a $out
   
   echo -e " run(\"\"\"+++++[->++++++++++<]>--<+++[->>++++++++++" | tee -a $out
   echo -e "        <<]>>++<<----------[+>.>.<+<]\"\"\") == Map(0 -> 0, 1 -> 58, 2 -> 32)" | tee -a $out
@@ -156,14 +154,13 @@
   
   if (scala_assert "bf.scala" "bf_test4.scala")
   then
-      echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      echo -e "  --> success (mark 1%)" | tee -a $out
+      marks=$(( marks + 1.0 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
 fi
 
-sleep 10
 
 if [ $tsts -eq 0 ]
 then
@@ -180,8 +177,8 @@
       END=$(date +%s)
       DIFF=$(( $END - $START ))
       echo -e "  This test ran for $DIFF seconds" | tee -a $out  
-      echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      echo -e "  --> success (mark 1%)" | tee -a $out
+      marks=$(( marks + 1.0 ))
   else
       END=$(date +%s)
       DIFF=$(( $END - $START ))
@@ -190,7 +187,6 @@
   fi
 fi
 
-sleep 10
 
 echo -e "" >> $out
 echo -e "Below is the feedback for your submission of bfc.scala" >> $out
@@ -250,7 +246,7 @@
   if (scala_assert "bfc.scala" "bf_test5.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 1.0 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
@@ -276,7 +272,7 @@
   if (scala_assert "bfc.scala" "bf_test6.scala")
   then
       echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
+      marks=$(( marks + 1.0 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
@@ -301,7 +297,7 @@
   if (scala_assert "bfc.scala" "bf_test7.scala")
   then
       echo -e "  --> success (+ 2%)" | tee -a $out
-      marks=$(( marks + 2 ))
+      marks=$(( marks + 2.0 ))
   else
       echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
   fi
@@ -310,6 +306,5 @@
 
 ## final marks
 echo -e "Overall mark for Part 5 (Scala)" | tee -a $out
-echo -e "$marks" | tee -a $out
+printf " %0.1f\n" $marks | tee -a $out
 
-sleep 12
--- a/main_marking5/bf_test1.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking5/bf_test1.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW10a._ 
+import M5a._ 
 
 assert(load_bff("benchmark.bf").length == 188)
 assert(load_bff("foobar.bf") == "")
--- a/main_marking5/bf_test2.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking5/bf_test2.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW10a._
+import M5a._
 
 assert(sread(Map(), 2) == 0)
 assert(sread(Map(2 -> 1), 2) == 1)
--- a/main_marking5/bf_test3.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking5/bf_test3.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW10a._
+import M5a._
 
 assert(jumpRight("[xxxxxx]xxx", 1, 0) == 8)
 assert(jumpRight("[xx[x]x]xxx", 1, 0) == 8)
--- a/main_marking5/bf_test4.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking5/bf_test4.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,10 +1,9 @@
-import CW10a._
+import M5a._
 
 assert(run("[-]", Map(0 -> 100)) == Map(0 -> 0))
 assert(run("[->+<]", Map(0 -> 10)) == Map(0 -> 0, 1 -> 10))
 assert(run("[>>+>>+<<<<-]", Map(0 -> 42)) == Map(0 -> 0, 2 -> 42, 4 -> 42))
-assert(run("++++++++++#>+***#") == Map(0 -> 10, 1 -> 1000))
-assert(run("+++>+@+@+@+@+@") == Map(0 -> 3, 1 -> 7, 4 -> 3, 5 -> 3, 6 -> 3, 7 -> 3))
+
 
 val hw_urban = """+++++[->++++++++++<]>--<+++[->>++++++++++
                   <<]>>++<<----------[+>.>.<+<]"""
--- a/main_marking5/bf_test4b.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking5/bf_test4b.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW10a._
+import M5a._
 
 val urban_bench = 
 """>+[<+++++++++++++>-]<[[>+>+<<-]>[<+>-]++++++++
--- a/main_marking5/bf_test5.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking5/bf_test5.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW10b._
+import M5b._
 
 val hw_urban = """+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]"""
 assert(jtable(hw_urban) == Map(69 -> 61, 5 -> 20, 60 -> 70, 27 -> 44, 43 -> 28, 19 -> 6))
--- a/main_marking5/bf_test6.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking5/bf_test6.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW10b._
+import M5b._
 
 assert(optimise(load_bff("benchmark.bf")).length == 181)
 assert(optimise(load_bff("mandelbrot.bf")).length == 11205)
--- a/main_marking5/bf_test7.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking5/bf_test7.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-import CW10b._
+import M5b._
 
 assert(combine(optimise(load_bff("benchmark.bf"))).length == 134)
 assert(combine(optimise(load_bff("mandelbrot.bf"))).length == 6511)
--- a/main_marking5/bfc.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_marking5/bfc.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,7 +1,7 @@
 // Part 2 about a "Compiler" for the Brainf*** language
 //======================================================
 
-object CW10b {
+object M5b {
 
 // !!! Copy any function you need from file bf.scala !!!
 //
@@ -170,14 +170,14 @@
 // that is write(mem, mp, 0). 
 //
 // The easiest way to modify a string in this way is to use the regular
-// expression """[^<>+-.\[\]@*#]""", which recognises everything that is 
+// expression """[^<>+-.\[\]""", which recognises everything that is 
 // not a bf-command and replace it by the empty string. Similarly the
 // regular expression """\[-\]""" finds all occurences of [-] and 
 // by using the Scala method .replaceAll you can repplace it with the 
 // string "0" standing for the new bf-command.
 
 def optimise(s: String) : String = {
-  s.replaceAll("""[^<>+-.\[\]@*#]""","")
+  s.replaceAll("""[^<>+-.\[\]]""","")
    .replaceAll("""\[-\]""", "0")
 }
 
@@ -212,9 +212,10 @@
 
 //println(optimise(load_bff("collatz.bf")))
 //optimise(load_bff("benchmark.bf"))          // should have inserted 0's
-//optimise(load_bff("mandelbrot.bf")).length  // => 11203
+//optimise(load_bff("mandelbrot.bf")).length  // => 11205
  
 //time_needed(1, run3(load_bff("benchmark.bf")))
+//time_needed(1, run3(load_bff("mandelbrot.bf")))
 
 
 
--- a/main_marking5/mk	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-#!/bin/sh
-###set -e
-
-trap "exit" INT
-
-files=${1:-*/main5}
-
-for sd in $files; do
-  cd $sd
-  echo $sd
-  touch .
-  cp ../../../../../main_marking5/bf_test.sh .
-  cp ../../../../../main_marking5/bf_test1.scala .
-  cp ../../../../../main_marking5/bf_test2.scala .
-  cp ../../../../../main_marking5/bf_test3.scala .
-  cp ../../../../../main_marking5/bf_test4.scala .
-  cp ../../../../../main_marking5/bf_test4b.scala .
-  cp ../../../../../main_marking5/bf_test5.scala .
-  cp ../../../../../main_marking5/bf_test6.scala .
-  cp ../../../../../main_marking5/bf_test7.scala .
-  cp ../../../../../main_marking5/*.bf .
-  ./bf_test.sh output
-  rm bf_test.sh
-  rm bf_test1.scala
-  rm bf_test2.scala
-  rm bf_test3.scala
-  rm bf_test4.scala
-  rm bf_test4b.scala
-  rm bf_test5.scala
-  rm bf_test6.scala
-  rm bf_test7.scala
-  rm *.bf
-  cd ..
-  cd ..
-done
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main_marking5/mk_main5	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,38 @@
+#!/bin/bash
+###set -e
+
+trap "exit" INT
+
+files=${1:-*/main5}
+
+for sd in $files; do
+  echo -e "\n"  
+  cd $sd
+  echo $sd
+  touch .
+  cp ../../../../../main_marking5/bf_test.sh .
+  cp ../../../../../main_marking5/bf_test1.scala .
+  cp ../../../../../main_marking5/bf_test2.scala .
+  cp ../../../../../main_marking5/bf_test3.scala .
+  cp ../../../../../main_marking5/bf_test4.scala .
+  cp ../../../../../main_marking5/bf_test4b.scala .
+  cp ../../../../../main_marking5/bf_test5.scala .
+  cp ../../../../../main_marking5/bf_test6.scala .
+  cp ../../../../../main_marking5/bf_test7.scala .
+  cp ../../../../../main_marking5/*.bf .
+  ./bf_test.sh output
+  rm bf_test.sh
+  rm bf_test1.scala
+  rm bf_test2.scala
+  rm bf_test3.scala
+  rm bf_test4.scala
+  rm bf_test4b.scala
+  rm bf_test5.scala
+  rm bf_test6.scala
+  rm bf_test7.scala
+  rm *.bf
+  cd ..
+  cd ..
+done
+
+
--- a/main_solution3/re.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_solution3/re.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,4 +1,4 @@
-// Core Part about Regular Expression Matching
+// Main Part 3 about Regular Expression Matching
 //=============================================
 
 object M3 {
@@ -12,17 +12,14 @@
 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp   // sequence
 case class STAR(r: Rexp) extends Rexp             // star
 
-// some convenience for typing in regular expressions
-
 
 //the usual binary choice can be defined in terms of ALTs
 def ALT(r1: Rexp, r2: Rexp) = ALTs(List(r1, r2))
 
-
+// some convenience for typing in regular expressions
 import scala.language.implicitConversions    
 import scala.language.reflectiveCalls 
 
-
 def charlist2rexp(s: List[Char]): Rexp = s match {
   case Nil => ONE
   case c::Nil => CHAR(c)
@@ -76,6 +73,10 @@
 }
 
 
+// (3) Implement the flatten function flts. It
+// deletes 0s from a list of regular expressions
+// and also 'spills out', or flattens, nested 
+// ALTernativeS.
 
 def flts(rs: List[Rexp]) : List[Rexp] = rs match {
   case Nil => Nil
@@ -84,7 +85,7 @@
   case r::rs => r :: flts(rs) 
 }
 
-// (3) Complete the simp function according to
+// (4) Complete the simp function according to
 // the specification given in the coursework; this
 // function simplifies a regular expression from
 // the inside out, like you would simplify arithmetic 
@@ -110,7 +111,7 @@
 
 simp(ALT(ONE | CHAR('a'), CHAR('a') | ONE))
 
-// (4) Complete the two functions below; the first 
+// (5) Complete the two functions below; the first 
 // calculates the derivative w.r.t. a string; the second
 // is the regular expression matcher taking a regular
 // expression and a string and checks whether the
@@ -124,7 +125,7 @@
 // main matcher function
 def matcher(r: Rexp, s: String) = nullable(ders(s.toList, r))
 
-// (5) Complete the size function for regular
+// (6) Complete the size function for regular
 // expressions according to the specification 
 // given in the coursework.
 
@@ -146,7 +147,7 @@
 //matcher(("a" ~ "b") ~ "c", "ab")   // => false
 
 // the supposedly 'evil' regular expression (a*)* b
-val EVIL = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
+// val EVIL = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
 
 //println(matcher(EVIL, "a" * 1000 ++ "b"))   // => true
 //println(matcher(EVIL, "a" * 1000))          // => false
--- a/main_solution5/bf.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_solution5/bf.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -211,4 +211,5 @@
 }
 
 
-M5a.run(M5a.load_bff("mandelbrot.bf"))
+//M5a.run(M5a.load_bff("mandelbrot.bf"))
+M5a.run(M5a.load_bff("collatz.bf"))
--- a/main_templates3/re.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_templates3/re.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -12,28 +12,12 @@
 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp   // sequence
 case class STAR(r: Rexp) extends Rexp             // star
 
-import scala.language.implicitConversions    
-import scala.language.reflectiveCalls 
-
-def charlist2rexp(s: List[Char]): Rexp = s match {
-  case Nil => ONE
-  case c::Nil => CHAR(c)
-  case c::s => SEQ(CHAR(c), charlist2rexp(s))
-}
-implicit def string2rexp(s: String): Rexp = charlist2rexp(s.toList)
-
-
-// "a|b"
-ALT(CHAR('a'), CHAR('b'))
-
-val reg : Rexp = "a" | "b" // CHAR('a')
-
-// some convenience for typing regular expressions
-
 //the usual binary choice can be defined in terms of ALTs
 def ALT(r1: Rexp, r2: Rexp) = ALTs(List(r1, r2))
 
 
+// some convenience for typing regular expressions
+
 import scala.language.implicitConversions    
 import scala.language.reflectiveCalls 
 
@@ -44,9 +28,6 @@
 }
 implicit def string2rexp(s: String): Rexp = charlist2rexp(s.toList)
 
-
-
-
 implicit def RexpOps (r: Rexp) = new {
   def | (s: Rexp) = ALT(r, s)
   def % = STAR(r)
@@ -61,6 +42,11 @@
   def ~ (r: String) = SEQ(s, r)
 }
 
+
+// ALT(CHAR('a'), CHAR('b'))
+// val reg : Rexp = "a" | "b" 
+
+
 // (1) Complete the function nullable according to
 // the definition given in the coursework; this 
 // function checks whether a regular expression
--- a/main_testing2/danube_test.sh	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_testing2/danube_test.sh	Mon Apr 11 23:55:27 2022 +0100
@@ -5,8 +5,8 @@
 
 
 
-#scalafile=${2:-danube.scala}
-out=${1:-output}
+scalafile=${1:-danube.scala}
+out=${2:-output}
 
 
 
@@ -25,7 +25,7 @@
 # functional tests
 
 function scala_assert {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "") # 2> /dev/null 1> /dev/null)
+  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)
 }
 
 # purity test
--- a/main_testing3/re.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_testing3/re.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -13,12 +13,10 @@
 case class STAR(r: Rexp) extends Rexp             // star
 
 
-// some convenience for typing regular expressions
-
 //the usual binary choice can be defined in terms of ALTs
 def ALT(r1: Rexp, r2: Rexp) = ALTs(List(r1, r2))
 
-
+// some convenience for typing in regular expressions
 import scala.language.implicitConversions    
 import scala.language.reflectiveCalls 
 
@@ -52,18 +50,12 @@
 def nullable (r: Rexp) : Boolean = r match {
   case ZERO => false
   case ONE => true
-  case CHAR(c) => false
-  case ALTs(rs) => {
-    if (rs.size == 0) false
-    else if (nullable(rs.head)) true
-    else nullable(ALTs(rs.tail))
-  }
-  case SEQ(c, s) => nullable(c) && nullable(s)
-  case STAR(r) => true
-  case _ => false
+  case CHAR(_) => false
+  case ALTs(rs) => rs.exists(nullable)
+  case SEQ(r1, r2) => nullable(r1) && nullable(r2)
+  case STAR(_) => true
 }
 
-
 // (2) Complete the function der according to
 // the definition given in the coursework; this
 // function calculates the derivative of a 
@@ -72,16 +64,12 @@
 def der (c: Char, r: Rexp) : Rexp = r match {
   case ZERO => ZERO
   case ONE => ZERO
-  case CHAR(x) => {
-    if (x==c) ONE
-    else ZERO
-  }
-  case ALTs(rs) => ALTs(for (i <- rs) yield der(c, i))
-  case SEQ(x, y) => {
-    if (nullable(x)) ALTs(List(SEQ(der(c, x), y), der(c, y)))
-    else SEQ(der(c, x), y)
-  }
-  case STAR(x) => SEQ(der(c, x), STAR(x))
+  case CHAR(d) => if (c == d) ONE else ZERO
+  case ALTs(rs) => ALTs(rs.map(der(c, _)))
+  case SEQ(r1, r2) => 
+    if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2))
+    else SEQ(der(c, r1), r2)
+  case STAR(r1) => SEQ(der(c, r1), STAR(r1))
 }
 
 
@@ -92,118 +80,119 @@
 
 def flts(rs: List[Rexp]) : List[Rexp] = rs match {
   case Nil => Nil
-  case ZERO::rest => flts(rest)
-  case ALTs(rs_other)::rest => rs_other ::: flts(rest)
-  case r::rest => r::flts(rest)
+  case ZERO::tl => flts(tl)
+  case ALTs(rs1)::rs2 => rs1 ::: flts(rs2)  
+  case r::rs => r :: flts(rs) 
 }
 
 
 
 // (4) Complete the simp function according to
-// the specification given in the coursework description; 
-// this function simplifies a regular expression from
+// the specification given in the coursework; this
+// function simplifies a regular expression from
 // the inside out, like you would simplify arithmetic 
 // expressions; however it does not simplify inside 
-// STAR-regular expressions. Use the _.distinct and 
-// flts functions.
+// STAR-regular expressions.
+
 
 def simp(r: Rexp) : Rexp = r match {
-  case SEQ(x, ZERO) => ZERO
-  case SEQ(ZERO, x) => ZERO
-  case SEQ(x, ONE) => x
-  case SEQ(ONE, x) => x
-  case SEQ(x, y) => SEQ(simp(x), simp(y))
-  case ALTs(rs) => {
-    val list = flts(for (x <- rs) yield simp(x)).distinct
-    if (list.size == 0) ZERO
-    else if (list.size == 1) list.head
-    else ALTs(list)
+  case ALTs(rs) => (flts(rs.map(simp)).distinct) match {
+    case Nil => ZERO
+    case r::Nil => r  
+    case rs => ALTs(rs)
   }
-  case x => x
+  case SEQ(r1, r2) =>  (simp(r1), simp(r2)) match {
+    case (ZERO, _) => ZERO
+    case (_, ZERO) => ZERO
+    case (ONE, r2s) => r2s
+    case (r1s, ONE) => r1s
+    case (r1s, r2s) => SEQ(r1s, r2s)
+  }
+  case r => r
 }
 
+simp(ALT(ONE | CHAR('a'), CHAR('a') | ONE))
 
 // (5) Complete the two functions below; the first 
 // calculates the derivative w.r.t. a string; the second
 // is the regular expression matcher taking a regular
 // expression and a string and checks whether the
-// string matches the regular expression
+// string matches the regular expression.
 
 def ders (s: List[Char], r: Rexp) : Rexp = s match {
   case Nil => r
-  case c::rest => {
-    val deriv = simp(der(c,r))
-    ders(rest, deriv)
-  }
+  case c::s => ders(s, simp(der(c, r)))
 }
 
-def matcher(r: Rexp, s: String): Boolean = nullable(ders(s.toList, r))
-
+// main matcher function
+def matcher(r: Rexp, s: String) = nullable(ders(s.toList, r))
 
 // (6) Complete the size function for regular
 // expressions according to the specification 
 // given in the coursework.
 
+
 def size(r: Rexp): Int = r match {
-  case Nil => 0
   case ZERO => 1
   case ONE => 1
-  case CHAR(x) => 1
-  case ALTs(rs) => 1 + (for (x <- rs) yield size(x)).sum
-  case SEQ(x, y) => 1 + size(x) + size(y)
-  case STAR(x) => 1 + size(x)
+  case CHAR(_) => 1
+  case ALTs(rs) => 1 + rs.map(size).sum
+  case SEQ(r1, r2) => 1 + size(r1) + size (r2)
+  case STAR(r1) => 1 + size(r1)
 }
 
 
+
 // some testing data
 
-
-// matcher(("a" ~ "b") ~ "c", "abc")  // => true
-// matcher(("a" ~ "b") ~ "c", "ab")   // => false
+//matcher(("a" ~ "b") ~ "c", "abc")  // => true
+//matcher(("a" ~ "b") ~ "c", "ab")   // => false
 
 // the supposedly 'evil' regular expression (a*)* b
 // val EVIL = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
 
-// matcher(EVIL, "a" * 1000 ++ "b")   // => true
-// matcher(EVIL, "a" * 1000)          // => false
+//println(matcher(EVIL, "a" * 1000 ++ "b"))   // => true
+//println(matcher(EVIL, "a" * 1000))          // => false
 
 // size without simplifications
-// size(der('a', der('a', EVIL)))             // => 28
-// size(der('a', der('a', der('a', EVIL))))   // => 58
+//println(size(der('a', der('a', EVIL))))             // => 28
+//println(size(der('a', der('a', der('a', EVIL)))))   // => 58
 
 // size with simplification
-// size(simp(der('a', der('a', EVIL))))           // => 8
-// size(simp(der('a', der('a', der('a', EVIL))))) // => 8
+//println(simp(der('a', der('a', EVIL))))          
+//println(simp(der('a', der('a', der('a', EVIL)))))
+
+//println(size(simp(der('a', der('a', EVIL)))))           // => 8
+//println(size(simp(der('a', der('a', der('a', EVIL)))))) // => 8
 
 // Python needs around 30 seconds for matching 28 a's with EVIL. 
 // Java 9 and later increase this to an "astonishing" 40000 a's in
-// 30 seconds.
+// around 30 seconds.
 //
-// Lets see how long it really takes to match strings with 
-// 5 Million a's...it should be in the range of a couple
-// of seconds.
+// Lets see how long it takes to match strings with 
+// 5 Million a's...it should be in the range of a 
+// couple of seconds.
 
-// def time_needed[T](i: Int, code: => T) = {
-//   val start = System.nanoTime()
-//   for (j <- 1 to i) code
-//   val end = System.nanoTime()
-//   "%.5f".format((end - start)/(i * 1.0e9))
-// }
+def time_needed[T](i: Int, code: => T) = {
+  val start = System.nanoTime()
+  for (j <- 1 to i) code
+  val end = System.nanoTime()
+  "%.5f".format((end - start)/(i * 1.0e9))
+}
 
-// for (i <- 0 to 5000000 by 500000) {
-//   println(s"$i ${time_needed(2, matcher(EVIL, "a" * i))} secs.") 
-// }
+//for (i <- 0 to 5000000 by 500000) {
+//  println(s"$i ${time_needed(2, matcher(EVIL, "a" * i))} secs.") 
+//}
 
 // another "power" test case 
-// simp(Iterator.iterate(ONE:Rexp)(r => SEQ(r, ONE | ONE)).drop(50).next()) == ONE
+//simp(Iterator.iterate(ONE:Rexp)(r => SEQ(r, ONE | ONE)).drop(100).next) == ONE
 
 // the Iterator produces the rexp
 //
 //      SEQ(SEQ(SEQ(..., ONE | ONE) , ONE | ONE), ONE | ONE)
 //
 //    where SEQ is nested 50 times.
+ 
 
-// This a dummy comment. Hopefully it works!
 
 }
-
--- a/main_testing3/re_test.sh	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_testing3/re_test.sh	Mon Apr 11 23:55:27 2022 +0100
@@ -108,8 +108,8 @@
   echo -e " simp(ZERO | ONE) == ONE" >> $out
   echo -e " simp(STAR(ZERO | ONE)) == STAR(ZERO | ONE)" >> $out
   echo -e " simp(ONE ~ (ONE ~ (ONE ~ CHAR('a')))) == CHAR('a')" >> $out
-  echo -e " simp(((ONE ~ ONE) ~ ONE) ~ CHAR('a')) == CHAR('a'))" >> $out
-  echo -e " simp(((ONE | ONE) ~ ONE) ~ CHAR('a')) == CHAR('a'))" >> $out
+  echo -e " simp(((ONE ~ ONE) ~ ONE) ~ CHAR('a')) == CHAR('a')" >> $out
+  echo -e " simp(((ONE | ONE) ~ ONE) ~ CHAR('a')) == CHAR('a')" >> $out
   echo -e " simp(ONE ~ (ONE ~ (ONE ~ ZERO))) == ZERO" >> $out
   echo -e " simp(ALT(ONE ~ (ONE ~ (ONE ~ ZERO)), CHAR('a'))) == CHAR('a')" >> $out
   echo -e " simp(CHAR('a') | CHAR('a')) == CHAR('a')" >> $out
--- a/main_testing4/knight1.scala	Thu Jan 13 12:55:03 2022 +0000
+++ b/main_testing4/knight1.scala	Mon Apr 11 23:55:27 2022 +0100
@@ -1,13 +1,119 @@
-// Part 1 about finding and counting Knight's tours
-//==================================================
+// Main Part 4 about finding Knight's tours
+//==========================================
+import scala.annotation.tailrec
+
+
+object M4a {
 
-object M4a {   // for preparing the jar
+// If you need any auxiliary functions, feel free to 
+// implement them, but do not make any changes to the
+// templates below. Also have a look whether the functions
+// at the end of the file are of any help.
+
+
 
 type Pos = (Int, Int)    // a position on a chessboard 
 type Path = List[Pos]    // a path...a list of positions
 
+//(1) Complete the function that tests whether the position x
+//    is inside the board and not yet element in the path.
 
-// for measuring time in the JAR
+def is_legal(dim: Int, path: Path, x: Pos) : Boolean = {
+  (x._1 < dim) && (x._2 < dim) && (!path.contains(x))
+}
+
+
+
+//(2) Complete the function that calculates for a position x
+//    all legal onward moves that are not already in the path. 
+//    The moves should be ordered in a "clockwise" manner.
+ 
+def legal_moves(dim: Int, path: Path, x: Pos) : List[Pos] = {
+    val movesets = List(
+    (x._1 + 1, x._2 + 2),
+    (x._1 + 2, x._2 + 1),
+    (x._1 + 2, x._2 - 1),
+    (x._1 + 1, x._2 - 2),
+    (x._1 - 1, x._2 - 2),
+    (x._1 - 2, x._2 - 1),
+    (x._1 - 2, x._2 + 1),
+    (x._1 - 1, x._2 + 2)
+  )
+  movesets.filter(is_legal(dim, path, _))
+}
+
+
+//some testcases
+//
+//assert(legal_moves(8, Nil, (2,2)) == 
+//  List((3,4), (4,3), (4,1), (3,0), (1,0), (0,1), (0,3), (1,4)))
+//assert(legal_moves(8, Nil, (7,7)) == List((6,5), (5,6)))
+//assert(legal_moves(8, List((4,1), (1,0)), (2,2)) == 
+//  List((3,4), (4,3), (3,0), (0,1), (0,3), (1,4)))
+//assert(legal_moves(8, List((6,6)), (7,7)) == List((6,5), (5,6)))
+
+
+//(3) Complete the two recursive functions below. 
+//    They exhaustively search for knight's tours starting from the 
+//    given path. The first function counts all possible tours, 
+//    and the second collects all tours in a list of paths.
+
+def count_tours(dim: Int, path: Path) : Int = {
+  if (dim <= 4) 0 else {
+    if (path.length >= (dim * dim)) 1 else {
+      val movesets = legal_moves(dim, path, path.head)
+      (for (move <- movesets) yield count_tours(dim, move :: path)).sum
+    }
+  }
+}
+
+def enum_tours(dim: Int, path: Path) : List[Path] = {
+  if (dim <= 4) Nil else {
+    if (path.length >= (dim * dim)) List(path) else {
+      val movesets = legal_moves(dim, path, path.head)
+      (for (move <- movesets) yield enum_tours(dim, move :: path)).flatten
+    }
+  }
+}
+
+
+//(4) Implement a first-function that finds the first 
+//    element, say x, in the list xs where f is not None. 
+//    In that case Return f(x), otherwise None. If possible,
+//    calculate f(x) only once.
+
+@tailrec
+def first(xs: List[Pos], f: Pos => Option[Path]) : Option[Path] = {
+  xs match {
+    case Nil => None
+    case head :: rest => {
+      val result = f(head)
+      if (result.isEmpty) first(rest, f) else result
+    }
+  }
+}
+
+
+// testcases
+//
+//def foo(x: (Int, Int)) = if (x._1 > 3) Some(List(x)) else None
+//
+//first(List((1, 0),(2, 0),(3, 0),(4, 0)), foo)   // Some(List((4,0)))
+//first(List((1, 0),(2, 0),(3, 0)), foo)          // None
+
+
+//(5) Implement a function that uses the first-function from (4) for
+//    trying out onward moves, and searches recursively for a
+//    knight tour on a dim * dim-board.
+
+def first_tour(dim: Int, path: Path) : Option[Path] = ???
+ 
+
+
+/* Helper functions
+
+
+// for measuring time
 def time_needed[T](code: => T) : T = {
   val start = System.nanoTime()
   val result = code
@@ -16,6 +122,14 @@
   result
 }
 
+// can be called for example with
+//
+//     time_needed(count_tours(dim, List((0, 0))))
+//
+// in order to print out the time that is needed for 
+// running count_tours
+
+
 // for printing a board
 def print_board(dim: Int, path: Path): Unit = {
   println()
@@ -27,145 +141,7 @@
   } 
 }
 
-def is_legal(dim: Int, path: Path, x: Pos): Boolean = 
-  0 <= x._1 && 0 <= x._2 && x._1 < dim && x._2 < dim && !path.contains(x)
 
-// testcases
-//assert(is_legal(8, Nil, (3, 4)) == true)
-//assert(is_legal(8, List((4, 1), (1, 0)), (4, 1)) == false)
-//assert(is_legal(2, Nil, (0, 0)) == true)
-
-
-def add_pair(x: Pos, y: Pos): Pos = 
-  (x._1 + y._1, x._2 + y._2)
-
-def moves(x: Pos): List[Pos] = 
-  List(( 1,  2),( 2,  1),( 2, -1),( 1, -2),
-       (-1, -2),(-2, -1),(-2,  1),(-1,  2)).map(add_pair(x, _))
-
-def legal_moves(dim: Int, path: Path, x: Pos): List[Pos] = 
-  moves(x).filter(is_legal(dim, path, _))
-
-
-
-// testcases
-//assert(legal_moves(8, Nil, (2,2)) == 
-//  List((3,4), (4,3), (4,1), (3,0), (1,0), (0,1), (0,3), (1,4)))
-//assert(legal_moves(8, Nil, (7,7)) == List((6,5), (5,6)))
-//assert(legal_moves(8, List((4,1), (1,0)), (2,2)) == 
-//  List((3,4), (4,3), (3,0), (0,1), (0,3), (1,4)))
-//assert(legal_moves(8, List((6,6)), (7,7)) == List((6,5), (5,6)))
-//assert(legal_moves(8, Nil, (0,1)) == List((1,3), (2,2), (2,0)))
-//assert(legal_moves(1, Nil, (0,0)) == List())
-//assert(legal_moves(2, Nil, (0,0)) == List())
-//assert(legal_moves(3, Nil, (0,0)) == List((1,2), (2,1)))
-
-
-def tcount_tours(dim: Int, path: Path): Int = {
-  if (path.length == dim * dim) 1
-  else 
-    (for (x <- legal_moves(dim, path, path.head)) yield tcount_tours(dim, x::path)).sum
-}
-
-def count_tours(dim: Int, path: Path) =
-  time_needed(tcount_tours(dim: Int, path: Path))
-
-
-def tenum_tours(dim: Int, path: Path): List[Path] = {
-  if (path.length == dim * dim) List(path)
-  else 
-    (for (x <- legal_moves(dim, path, path.head)) yield tenum_tours(dim, x::path)).flatten
-}
-
-def enum_tours(dim: Int, path: Path) =
-  time_needed(tenum_tours(dim: Int, path: Path))
-
-// test cases
-
-/*
-def count_all_tours(dim: Int) = {
-  for (i <- (0 until dim).toList; 
-       j <- (0 until dim).toList) yield count_tours(dim, List((i, j)))
-}
-
-def enum_all_tours(dim: Int): List[Path] = {
-  (for (i <- (0 until dim).toList; 
-        j <- (0 until dim).toList) yield enum_tours(dim, List((i, j)))).flatten
-}
-
-
-println("Number of tours starting from (0, 0)")
-
-for (dim <- 1 to 5) {
-  println(s"${dim} x ${dim} " + time_needed(0, count_tours(dim, List((0, 0)))))
-}
-
-println("Number of tours starting from all fields")
-
-for (dim <- 1 to 5) {
-  println(s"${dim} x ${dim} " + time_needed(0, count_all_tours(dim)))
-}
-
-for (dim <- 1 to 5) {
-  val ts = enum_tours(dim, List((0, 0)))
-  println(s"${dim} x ${dim} ")   
-  if (ts != Nil) {
-    print_board(dim, ts.head)
-    println(ts.head)
-  }
-}
 */
 
-
-def first(xs: List[Pos], f: Pos => Option[Path]): Option[Path] = xs match {
-  case Nil => None
-  case x::xs => {
-    val result = f(x)
-    if (result.isDefined) result else first(xs, f)
-  }
 }
-
-// test cases
-//def foo(x: (Int, Int)) = if (x._1 > 3) Some(List(x)) else None
-//
-//first(List((1, 0),(2, 0),(3, 0),(4, 0)), foo)
-//first(List((1, 0),(2, 0),(3, 0)), foo)
-
-
-def tfirst_tour(dim: Int, path: Path): Option[Path] = {
-  if (path.length == dim * dim) Some(path)
-  else
-    first(legal_moves(dim, path, path.head), (x:Pos) => tfirst_tour(dim, x::path))
-}
-
-def first_tour(dim: Int, path: Path) = 
-  time_needed(tfirst_tour(dim: Int, path: Path))
-
-
-/*
-for (dim <- 1 to 8) {
-  val t = first_tour(dim, List((0, 0)))
-  println(s"${dim} x ${dim} " + (if (t == None) "" else { print_board(dim, t.get) ; "" }))
-}
-*/
-
-// 15 secs for 8 x 8
-//val ts1 = time_needed(0,first_tour(8, List((0, 0))).get)
-//??val ts1 = time_needed(0,first_tour(8, List((1, 1))).get)
-
-// no result for 4 x 4
-//val ts2 = time_needed(0, first_tour(4, List((0, 0))))
-
-// 0.3 secs for 6 x 6
-//val ts3 = time_needed(0, first_tour(6, List((0, 0))))
-
-// 15 secs for 8 x 8
-//time_needed(0, print_board(8, first_tour(8, List((0, 0))).get))
-
-
-
-
-
-}
-
-
--- a/pre_marking1/collatz.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-// Basic Part about the 3n+1 conjecture
-//==================================
-
-// generate jar with
-//   > scala -d collatz.jar  collatz.scala
-
-object CW6a { // for purposes of generating a jar
-
-def collatz(n: Long): Long =
-  if (n == 1) 0 else
-    if (n % 2 == 0) 1 + collatz(n / 2) else 
-      1 + collatz(3 * n + 1)
-
-
-def collatz_max(bnd: Long): (Long, Long) = {
-  val all = for (i <- (1L to bnd)) yield (collatz(i), i)
-  all.maxBy(_._1)
-}
-
-//collatz_max(1000000)
-//collatz_max(10000000)
-//collatz_max(100000000)
-
-/* some test cases
-val bnds = List(10, 100, 1000, 10000, 100000, 1000000)
-
-for (bnd <- bnds) {
-  val (steps, max) = collatz_max(bnd)
-  println(s"In the range of 1 - ${bnd} the number ${max} needs the maximum steps of ${steps}")
-}
-
-*/
-
-def is_pow(n: Long) : Boolean = (n & (n - 1)) == 0
-
-def is_hard(n: Long) : Boolean = is_pow(3 * n + 1)
-
-def last_odd(n: Long) : Long = 
-  if (is_hard(n)) n else
-    if (n % 2 == 0) last_odd(n / 2) else 
-      last_odd(3 * n + 1)
-
-
-//for (i <- 130 to 10000) println(s"$i: ${last_odd(i)}")
-//for (i <- 1 to 100) println(s"$i: ${collatz(i)}")
-
-}
-
-
-
--- a/pre_marking1/collatz_test.sh	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-#!/bin/bash
-
-# to make the script fail safely
-set -euo pipefail
-
-
-out=${1:-output}
-
-echo "" > $out
-
-echo `date` >> $out
-echo >> $out
-echo "Below is the feedback and provisional marks for your submission" >> $out
-echo "for the Preliminary Part of Part 1 (Scala).  Please note all marks are provisional until" >> $out
-echo "ratified by the assessment board -- this is not an official" >> $out
-echo "results transcript." >> $out
-echo "" >> $out
-
-echo "The feedback for your submission for collatz.scala" >> $out
-echo "" >> $out
-
-# marks for CW6 preliminary part
-marks=$(( 0 ))
-
-# compilation tests
-
-function scala_compile {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -Xprint:parser "$1" 2> c$out 1> c$out)
-}
-
-# functional tests
-
-function scala_assert {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -nc -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)
-}
-
-# purity test
-
-function scala_vars {
-   (egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' c$out 2> /dev/null 1> /dev/null)
-}
-
-
-### compilation test
-
-echo -e "collatz.scala runs?" >> $out
-
-if (scala_compile collatz.scala)
-then
-    echo -e "  --> success" >> $out
-    tsts0=$(( 0 ))
-else
-    echo -e "  --> SCALA DID NOT RUN collatz.scala\n" >> $out
-    tsts0=$(( 1 )) 
-fi
-
-# var, .par return, ListBuffer test
-#
-
-if  [ $tsts0 -eq 0 ]
-then
-   echo -e "collatz.scala does not contain VARS, RETURNS etc?" >> $out
-    
-   if (scala_vars collatz.scala)
-   then
-      echo -e "  --> test failed\n" >> $out
-      tsts=$(( 1 ))
-   else
-      echo -e "  --> success" >> $out
-      tsts=$(( 0 )) 
-   fi
-else
-   tsts=$(( 1 ))  
-fi    
-
-
-echo >> $out
-
-### collatz tests
-
-if [ $tsts -eq 0 ]
-then
-  echo "collatz.scala tests:" | tee -a $out
-  echo "  collatz(1) == 0" | tee -a $out
-  echo "  collatz(6) == 8" | tee -a $out
-  echo "  collatz(9) == 19" | tee -a $out
-  echo "  collatz(9000) == 47" | tee -a $out
-
-  if (scala_assert "collatz.scala" "collatz_test1.scala")
-  then
-      echo "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
-  else
-    echo "  --> one of the tests failed" | tee -a $out
-  fi
-fi
-
-### collatz-max tests
-
-if [ $tsts -eq 0 ]
-then
-  echo "  collatz_max(10) == (19, 9)" | tee -a $out
-  echo "  collatz_max(100) == (118, 97)" | tee -a $out
-  echo "  collatz_max(1000) == (178, 871)" | tee -a $out
-  echo "  collatz_max(10000) == (261, 6171)" | tee -a $out
-  echo "  collatz_max(100000) == (350, 77031)" | tee -a $out
-  echo "  collatz_max(1000000) == (524, 837799)" | tee -a $out
-  #  echo "  collatz_max(2) == (1, 2) || collatz_max(2) == (0, 1)" | tee -a $out
-  echo "  collatz_max(2) == (1, 2)" | tee -a $out
-  echo "  collatz_max(77000) == (339, 52527)" | tee -a $out
-
-  if (scala_assert "collatz.scala" "collatz_test2.scala") 
-  then
-      echo "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
-  else
-    echo "  --> one of the tests failed" | tee -a $out
-  fi
-fi
-
-### last-odd tests
-
-if [ $tsts -eq 0 ]
-then
-  echo "  last_odd(113) == 85" | tee -a $out
-  echo "  last_odd(84) == 21" | tee -a $out
-  echo "  last_odd(605) == 341" | tee -a $out
-
-  if (scala_assert "collatz.scala" "collatz_test3.scala") 
-  then
-      echo "  --> success" | tee -a $out
-      marks=$(( marks + 1 ))
-  else
-    echo "  --> one of the tests failed" | tee -a $out
-  fi
-fi
-
-
-
-## final marks
-echo >> $out
-echo "Overall mark for the Preliminary Part 1 (Scala)" | tee -a $out
-echo " $marks" | tee -a $out
-
-
--- a/pre_marking1/collatz_test1.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-
-
-assert(CW6a.collatz(1) == 0)
-assert(CW6a.collatz(6) == 8)
-assert(CW6a.collatz(9) == 19)
-assert(CW6a.collatz(9000) == 47)
-
-
--- a/pre_marking1/collatz_test2.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-//def myassert(cond : => Boolean) = {
-//  try {
-//    assert(cond)
-//  } catch { 
-//    case _ : Throwable => System.exit(1)
-//  }
-//}
-
-assert(CW6a.collatz_max(10) == (19, 9))
-assert(CW6a.collatz_max(100) == (118, 97))
-assert(CW6a.collatz_max(1000) == (178, 871))
-assert(CW6a.collatz_max(10000) == (261, 6171))
-assert(CW6a.collatz_max(100000) == (350, 77031))
-assert(CW6a.collatz_max(1000000) == (524, 837799))
-assert(CW6a.collatz_max(2) == (1, 2))
-assert(CW6a.collatz_max(77000) == (339, 52527))
--- a/pre_marking1/collatz_test3.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-
-assert(CW6a.last_odd(113) == 85)
-assert(CW6a.last_odd(84) == 21)
-assert(CW6a.last_odd(605) == 341)
--- a/pre_marking1/mk	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-#!/bin/bash
-set -euo pipefail
-
-trap "exit" INT
-
-files=${1:-*/pre1}
-
-for sd in $files; do
-  cd $sd
-  echo $sd
-  sleep 5
-  touch .
-  cp ../../../../../pre_marking1/collatz_test.sh .
-  cp ../../../../../pre_marking1/collatz_test1.scala .
-  cp ../../../../../pre_marking1/collatz_test2.scala .
-  cp ../../../../../pre_marking1/collatz_test3.scala .
-  ./collatz_test.sh output
-  rm collatz_test.sh
-  rm collatz_test1.scala
-  rm collatz_test2.scala
-  rm collatz_test3.scala
-  cd ..
-  cd ..
-done
-
-
--- a/pre_marking2/docdiff.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-// Preliminary Part about Code Similarity
-//========================================
-
-
-object CW7a { 
-
-//(1) Complete the clean function below. It should find
-//    all words in a string using the regular expression
-//    \w+  and the library function 
-//
-//         some_regex.findAllIn(some_string)
-//
-//    The words should be Returned as a list of strings.
-
-def clean(s: String) : List[String] = 
-  ("""\w+""".r).findAllIn(s).toList
-
-
-//(2) The function occurrences calculates the number of times  
-//    strings occur in a list of strings. These occurrences should 
-//    be calculated as a Map from strings to integers.
-
-def occurrences(xs: List[String]): Map[String, Int] =
-  (for (x <- xs.distinct) yield (x, xs.count(_ == x))).toMap
-
-//(3) This functions calculates the dot-product of two documents
-//    (list of strings). For this it calculates the occurrence
-//    maps from (2) and then multiplies the corresponding occurrences. 
-//    If a string does not occur in a document, the product is zero.
-//    The function finally sums up all products. 
-
-def prod(lst1: List[String], lst2: List[String]) : Int = {
-    val words = (lst1 ::: lst2).distinct
-    val occs1 = occurrences(lst1)
-    val occs2 = occurrences(lst2)
-    words.map{ w => occs1.getOrElse(w, 0) * occs2.getOrElse(w, 0) }.sum
-}
-
-//(4) Complete the functions overlap and similarity. The overlap of
-//    two documents is calculated by the formula given in the assignment
-//    description. The similarity of two strings is given by the overlap
-//    of the cleaned (see (1)) strings.  
-
-def overlap(lst1: List[String], lst2: List[String]) : Double = {
-    val m1 = prod(lst1, lst1)
-    val m2 = prod(lst2, lst2) 
-    prod(lst1, lst2).toDouble / (List(m1, m2).max)
-}
-
-def similarity(s1: String, s2: String) : Double =
-  overlap(clean(s1), clean(s2))
-
-
-/*
-
-
-val list1 = List("a", "b", "b", "c", "d") 
-val list2 = List("d", "b", "d", "b", "d")
-
-occurrences(List("a", "b", "b", "c", "d"))   // Map(a -> 1, b -> 2, c -> 1, d -> 1)
-occurrences(List("d", "b", "d", "b", "d"))   // Map(d -> 3, b -> 2)
-
-prod(list1,list2) // 7 
-
-overlap(list1, list2)   // 0.5384615384615384
-overlap(list2, list1)   // 0.5384615384615384
-overlap(list1, list1)   // 1.0
-overlap(list2, list2)   // 1.0
-
-// Plagiarism examples from 
-// https://desales.libguides.com/avoidingplagiarism/examples
-
-val orig1 = """There is a strong market demand for eco-tourism in
-Australia. Its rich and diverse natural heritage ensures Australia's
-capacity to attract international ecotourists and gives Australia a
-comparative advantage in the highly competitive tourism industry."""
-
-val plag1 = """There is a high market demand for eco-tourism in
-Australia. Australia has a comparative advantage in the highly
-competitive tourism industry due to its rich and varied natural
-heritage which ensures Australia's capacity to attract international
-ecotourists."""
-
-similarity(orig1, plag1)
-
-
-// Plagiarism examples from 
-// https://www.utc.edu/library/help/tutorials/plagiarism/examples-of-plagiarism.php
-
-val orig2 = """No oil spill is entirely benign. Depending on timing and
-location, even a relatively minor spill can cause significant harm to
-individual organisms and entire populations. Oil spills can cause
-impacts over a range of time scales, from days to years, or even
-decades for certain spills. Impacts are typically divided into acute
-(short-term) and chronic (long-term) effects. Both types are part of a
-complicated and often controversial equation that is addressed after
-an oil spill: ecosystem recovery."""
-
-val plag2 = """There is no such thing as a "good" oil spill. If the
-time and place are just right, even a small oil spill can cause damage
-to sensitive ecosystems. Further, spills can cause harm days, months,
-years, or even decades after they occur. Because of this, spills are
-usually broken into short-term (acute) and long-term (chronic)
-effects. Both of these types of harm must be addressed in ecosystem
-recovery: a controversial tactic that is often implemented immediately
-following an oil spill."""
-
-overlap(clean(orig2), clean(plag2))
-similarity(orig2, plag2)
-
-// The punchline: everything above 0.6 looks suspicious and 
-// should be looked at by staff.
-
-*/
-
-
-}
--- a/pre_marking2/docdiff_test.sh	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,170 +0,0 @@
-#!/bin/zsh
-
-# to make the script fail safely
-set -euo pipefail
-
-
-out=${1:-output}
-
-echo "" > $out
-
-echo `date` >> $out
-echo -e "Below is the feedback and provisional marks for your submission" >> $out
-echo -e "for the Preliminary Part of Part 2 (Scala).  Please note all marks are provisional until" >> $out
-echo -e "ratified by the assessment board -- this is not an official" >> $out
-echo -e "results transcript." >> $out
-echo -e "" >> $out
-
-echo -e "Below is the feedback for your submission docdiff.scala" >> $out
-echo -e "" >> $out
-
-# marks for CW7 preliminary part
-marks=$(( 0.0 ))
-
-
-# compilation tests
-
-function scala_compile {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -Xprint:parser "$1" 2> c$out 1> c$out)
-}
-
-# functional tests
-
-function scala_assert {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -nc -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)
-}
-
-# purity test
-
-function scala_vars {
-   (egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' c$out 2> /dev/null 1> /dev/null)
-}
-
-
-### compilation test
-
-echo -e "docdiff.scala runs?" |  tee -a $out
-
-if (scala_compile docdiff.scala)
-then
-    echo -e "  --> success" |  tee -a $out
-    tsts=$(( 0 ))
-else
-    echo -e "  --> SCALA DID NOT RUN docdiff.scala\n" |  tee -a $out
-    tsts=$(( 1 )) 
-fi
-
-
-# var, .par return, ListBuffer test
-#
-
-if  [ $tsts -eq 0 ]
-then     
-   echo -e "docdiff.scala does not contain VARS, RETURNS etc?" |  tee -a $out
-
-   if (scala_vars docdiff.scala)
-   then
-      echo -e "  --> test failed\n" | tee -a $out  
-      tsts=$(( 1 ))
-   else
-      echo -e "  --> success" |  tee -a $out
-      tsts=$(( 0 )) 
-   fi
-else
-   tsts=$(( 1 ))  
-fi 
-
-echo >> $out
-
-
-### docdiff clean tests
-
-if [ $tsts -eq 0 ]
-then
-  echo -e "docdiff.scala tests:" |  tee -a $out
-  echo -e "  clean(\"ab a abc\") == List(\"ab\", \"a\", \"abc\")" |  tee -a $out
-  echo -e "  clean(\"ab*a abc1\") == List(\"ab\", \"a\", \"abc1\")" |  tee -a $out
-
-  if (scala_assert "docdiff.scala" "docdiff_test1.scala")
-  then
-      echo -e "  --> success" |  tee -a $out
-      marks=$(( marks + 0.5 ))
-  else
-      echo -e "  --> ONE OF THE TESTS FAILED\n" |  tee -a $out
-  fi
-fi
-
-### docdiff occurrences tests
-
-if [ $tsts -eq 0 ]
-then
-  echo -e "  occurrences(List(\"a\", \"b\", \"b\", \"c\", \"d\")) == " |  tee -a $out
-  echo -e "      Map(\"a\" -> 1, \"b\" -> 2, \"c\" -> 1, \"d\" -> 1)" |  tee -a $out
-  echo -e "  " |  tee -a $out
-  echo -e "  occurrences(List(\"d\", \"b\", \"d\", \"b\", \"d\")) == " |  tee -a $out
-  echo -e "      Map(\"d\" -> 3, \"b\" -> 2)" |  tee -a $out
-  echo -e "  " |  tee -a $out
-  echo -e "  occurrences(Nil) == Map() " |  tee -a $out
-  echo -e "  " |  tee -a $out
-  echo -e "  occurrences(List(\"b\", \"b\", \"b\", \"b\", \"b\")) == Map(\"b\" -> 5)" |  tee -a $out
-
-  if (scala_assert "docdiff.scala" "docdiff_test2.scala") 
-  then
-      echo -e "  --> success" |  tee -a $out
-      marks=$(( marks + 1.0 ))
-  else
-      echo -e "  --> ONE OF THE TESTS FAILED\n" |  tee -a $out
-  fi
-fi
-
-### docdiff prod tests
-
-if [ $tsts -eq 0 ]
-then
-  echo -e "  val l1 = List(\"a\", \"b\", \"b\", \"c\", \"d\")" |  tee -a $out
-  echo -e "  val l2 = List(\"d\", \"b\", \"d\", \"b\", \"d\")" |  tee -a $out
-  echo -e "  " |  tee -a $out
-  echo -e "  prod(l1, l2) == 7 " |  tee -a $out
-  echo -e "  prod(l1, l1) == 7 " |  tee -a $out
-  echo -e "  prod(l2, l2) == 13 " |  tee -a $out
-  echo -e "  " |  tee -a $out
-  echo -e "  val l3 = List(\"1\", \"2\", \"3\", \"4\", \"5\")" |  tee -a $out
-  echo -e "  prod(l1, l3) == 0 " |  tee -a $out
-
-  if (scala_assert "docdiff.scala" "docdiff_test3.scala") 
-  then
-      echo -e "  --> success" |  tee -a $out
-      marks=$(( marks + 1.0 ))
-  else
-      echo -e "  --> ONE OF THE TESTS FAILED\n" |  tee -a $out
-  fi
-fi
-
-### docdiff overlap tests
-
-if [ $tsts -eq 0 ]
-then
-  echo -e "  val l1 = List(\"a\", \"b\", \"b\", \"c\", \"d\")" |  tee -a $out
-  echo -e "  val l2 = List(\"d\", \"b\", \"d\", \"b\", \"d\")" |  tee -a $out
-  echo -e "  " |  tee -a $out
-  echo -e "  overlap(l1, l2) == 0.5384615384615384 " |  tee -a $out
-  echo -e "  overlap(l1, l1) == 1.0 " |  tee -a $out
-  echo -e "  overlap(l2, l2) == 1.0 " |  tee -a $out
-
-  if (scala_assert "docdiff.scala" "docdiff_test4.scala") 
-  then
-      echo -e "  --> success" |  tee -a $out
-      marks=$(( marks + 0.5 ))
-  else
-      echo -e "  --> ONE OF THE TESTS FAILED\n" |  tee -a $out
-  fi
-fi
-
-
-## final marks
-echo -e "Overall mark for the Preliminary Part 2 (Scala)" | tee -a $out
-printf " %0.1f\n" $marks | tee -a $out
-
-
-#echo -e " $marks" | tee -a $out
-
--- a/pre_marking2/docdiff_test1.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-
-import CW7a._
-
-assert(clean("ab a abc") == List("ab", "a", "abc"))
-assert(clean("ab*a abc1") == List("ab", "a", "abc1"))
--- a/pre_marking2/docdiff_test2.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-
-import CW7a._
-
-assert(occurrences(List("a", "b", "b", "c", "d")) == Map("a" -> 1, "b" -> 2, "c" -> 1, "d" -> 1))
-
-assert(occurrences(List("d", "b", "d", "b", "d")) == Map("d" -> 3, "b" -> 2))
-
-assert(occurrences(List("b", "b", "b", "b", "b")) == Map("b" -> 5))
-
-assert(occurrences(Nil) == Map())
--- a/pre_marking2/docdiff_test3.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-
-import CW7a._
-
-val urban_list1 = List("a", "b", "b", "c", "d")
-val urban_list2 = List("d", "b", "d", "b", "d")
-
-assert(prod(urban_list1, urban_list2) == 7)
-assert(prod(urban_list1, urban_list1) == 7)
-assert(prod(urban_list2, urban_list2) == 13)
-
-
-val urban_listA = List("a", "b", "b", "c", "d")
-val urban_listB = List("1", "2", "3", "4", "5")
-
-assert(prod(urban_listA, urban_listB) == 0)
--- a/pre_marking2/docdiff_test4.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-
-import CW7a._
-
-val urban_list1 = List("a", "b", "b", "c", "d")
-val urban_list2 = List("d", "b", "d", "b", "d")
-
-assert(overlap(urban_list1, urban_list2) == 0.5384615384615384)
-assert(overlap(urban_list1, urban_list1) == 1.0)
-assert(overlap(urban_list2, urban_list2) == 1.0)
--- a/pre_marking2/mk	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-#!/bin/bash
-set -euo pipefail
-
-
-trap "exit" INT
-
-files=${1:-*/pre2}
-
-for sd in $files; do
-  cd $sd
-  echo $sd
-  touch .
-  cp ../../../../../pre_marking2/docdiff_test.sh .
-  cp ../../../../../pre_marking2/docdiff_test1.scala .
-  cp ../../../../../pre_marking2/docdiff_test2.scala .
-  cp ../../../../../pre_marking2/docdiff_test3.scala .
-  cp ../../../../../pre_marking2/docdiff_test4.scala .
-  ./docdiff_test.sh output
-  rm docdiff_test.sh
-  rm docdiff_test1.scala
-  rm docdiff_test2.scala
-  rm docdiff_test3.scala
-  rm docdiff_test4.scala
-  cd ..
-  cd ..
-done
-
-
--- a/pre_marking3/mk	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-#!/bin/bash
-set -euo pipefail
-
-
-trap "exit" INT
-
-files=${1:-*/pre3}
-
-for sd in $files; do
-  cd $sd
-  echo $sd
-  touch .
-  cp ../../../../../pre_marking3/postfix_test.sh .
-  cp ../../../../../pre_marking3/postfix_test1.scala .
-  cp ../../../../../pre_marking3/postfix_test2.scala .
-  cp ../../../../../pre_marking3/postfix_test3.scala .
-  cp ../../../../../pre_marking3/postfix_test4.scala .
-  ./postfix_test.sh output
-  rm postfix_test.sh
-  rm postfix_test1.scala
-  rm postfix_test2.scala
-  rm postfix_test3.scala
-  rm postfix_test4.scala
-  cd ..
-  cd ..
-done
-
-
--- a/pre_marking3/postfix.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-// Shunting Yard Algorithm
-// by Edsger Dijkstra
-// ========================
-
-object CW8a {
-
-type Toks = List[String]
-
-// the operations in the simple version
-val ops = List("+", "-", "*", "/")
-
-// the precedences of the operators
-val precs = Map("+" -> 1,
-		"-" -> 1,
-		"*" -> 2,
-		"/" -> 2)
-
-// helper function for splitting strings into tokens
-def split(s: String) : Toks = s.split(" ").toList
-
-// (6) Implement below the shunting yard algorithm. The most
-// convenient way to this in Scala is to implement a recursive 
-// function and to heavily use pattern matching. The function syard 
-// takes some input tokens as first argument. The second and third 
-// arguments represent the stack and the output of the shunting yard 
-// algorithm.
-//
-// In the marking, you can assume the function is called only with 
-// an empty stack and an empty output list. You can also assume the
-// input os  only properly formatted (infix) arithmetic expressions
-// (all parentheses will be well-nested, the input only contains 
-// operators and numbers).
-
-// You can implement any additional helper function you need. I found 
-// it helpful to implement two auxiliary functions for the pattern matching:  
-// 
- 
-def is_op(op: String) : Boolean = ops.contains(op)
-
-def prec(op1: String, op2: String) : Boolean = precs(op1) <= precs(op2)
-
-
-def syard(toks: Toks, st: Toks = Nil, out: Toks = Nil) : Toks = (toks, st, out) match {
-  case (Nil, _, _) => out.reverse ::: st
-  case (num::in, st, out) if (num.forall(_.isDigit)) => 
-    syard(in, st, num :: out)
-  case (op1::in, op2::st, out)  if (is_op(op1) && is_op(op2) && prec(op1, op2)) =>
-    syard(op1::in, st, op2 :: out) 
-  case (op1::in, st, out) if (is_op(op1)) => syard(in, op1::st, out)
-  case ("("::in, st, out) => syard(in, "("::st, out)
-  case (")"::in, op2::st, out) =>
-    if (op2 == "(") syard(in, st, out) else syard(")"::in, st, op2 :: out)
-  case (in, st, out) => {
-    println(s"in: ${in}   st: ${st}   out: ${out.reverse}")
-    Nil
-  }  
-} 
-
-
-// test cases
-//syard(split("3 + 4 * ( 2 - 1 )"))  // 3 4 2 1 - * +
-//syard(split("10 + 12 * 33"))       // 10 12 33 * +
-//syard(split("( 5 + 7 ) * 2"))      // 5 7 + 2 *
-//syard(split("5 + 7 / 2"))          // 5 7 2 / +
-//syard(split("5 * 7 / 2"))          // 5 7 * 2 /
-//syard(split("9 + 24 / ( 7 - 3 )")) // 9 24 7 3 - / +
-
-//syard(split("3 + 4 + 5"))           // 3 4 + 5 +
-//syard(split("( ( 3 + 4 ) + 5 )"))    // 3 4 + 5 +
-//syard(split("( 3 + ( 4 + 5 ) )"))    // 3 4 5 + +
-//syard(split("( ( ( 3 ) ) + ( ( 4 + ( 5 ) ) ) )")) // 3 4 5 + +
-
-// (7) Implement a compute function that evaluates an input list
-// in postfix notation. This function takes a list of tokens
-// and a stack as argumenta. The function should produce the 
-// result as an integer using the stack. You can assume 
-// this function will be only called with proper postfix 
-// expressions.    
-
-def op_comp(s: String, n1: Int, n2: Int) = s match {
-  case "+" => n2 + n1
-  case "-" => n2 - n1
-  case "*" => n2 * n1
-  case "/" => n2 / n1
-} 
-
-def compute(toks: Toks, st: List[Int] = Nil) : Int = (toks, st) match {
-  case (Nil, st) => st.head
-  case (op::in, n1::n2::st) if (is_op(op)) => compute(in, op_comp(op, n1, n2)::st)
-  case (num::in, st) => compute(in, num.toInt::st)  
-}
-
-// test cases
-// compute(syard(split("3 + 4 * ( 2 - 1 )")))  // 7
-// compute(syard(split("10 + 12 * 33")))       // 406
-// compute(syard(split("( 5 + 7 ) * 2")))      // 24
-// compute(syard(split("5 + 7 / 2")))          // 8
-// compute(syard(split("5 * 7 / 2")))          // 17
-// compute(syard(split("9 + 24 / ( 7 - 3 )"))) // 15
-
-}
-
-
--- a/pre_marking3/postfix2.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-// Shunting Yard Algorithm 
-// including Associativity for Operators 
-// =====================================
-
-object CW8b { 
-
-// type of tokens
-type Toks = List[String]
-
-// helper function for splitting strings into tokens
-def split(s: String) : Toks = s.split(" ").toList
-
-// left- and right-associativity
-abstract class Assoc
-case object LA extends Assoc
-case object RA extends Assoc
-
-// power is right-associative,
-// everything else is left-associative
-def assoc(s: String) : Assoc = s match {
-  case "^" => RA
-  case _ => LA
-}
-
-// the precedences of the operators
-val precs = Map("+" -> 1,
-  		 "-" -> 1,
-		 "*" -> 2,
-		 "/" -> 2,
-                 "^" -> 4)
-
-// the operations in the basic version of the algorithm
-val ops = List("+", "-", "*", "/", "^")
-
-// (8) Implement the extended version of the shunting yard algorithm.
-// This version should properly account for the fact that the power 
-// operation is right-associative. Apart from the extension to include
-// the power operation, you can make the same assumptions as in 
-// basic version.
-
-def is_op(op: String) : Boolean = ops.contains(op)
-
-def prec(op1: String, op2: String) : Boolean = assoc(op1) match {
-  case LA => precs(op1) <= precs(op2)
-  case RA => precs(op1) < precs(op2)
-}
-
-def syard(toks: Toks, st: Toks = Nil, out: Toks = Nil) : Toks = (toks, st, out) match {
-  case (Nil, _, _) => out.reverse ::: st
-  case (num::in, st, out) if (num.forall(_.isDigit)) => 
-    syard(in, st, num :: out)
-  case (op1::in, op2::st, out) if (is_op(op1) && is_op(op2) && prec(op1, op2)) =>
-    syard(op1::in, st, op2 :: out) 
-  case (op1::in, st, out) if (is_op(op1)) => syard(in, op1::st, out)
-  case ("("::in, st, out) => syard(in, "("::st, out)
-  case (")"::in, op2::st, out) =>
-    if (op2 == "(") syard(in, st, out) else syard(")"::in, st, op2 :: out)
-  case (in, st, out) => {
-    println(s"in: ${in}   st: ${st}   out: ${out.reverse}")
-    Nil
-  }  
-} 
-
-def op_comp(s: String, n1: Long, n2: Long) = s match {
-  case "+" => n2 + n1
-  case "-" => n2 - n1
-  case "*" => n2 * n1
-  case "/" => n2 / n1
-  case "^" => Math.pow(n2, n1).toLong
-} 
-
-def compute(toks: Toks, st: List[Long] = Nil) : Long = (toks, st) match {
-  case (Nil, st) => st.head
-  case (op::in, n1::n2::st) if (is_op(op)) => compute(in, op_comp(op, n1, n2)::st)
-  case (num::in, st) => compute(in, num.toInt::st)  
-}
-
-
-
-
-//compute(syard(split("3 + 4 * ( 2 - 1 )")))   // 7
-//compute(syard(split("10 + 12 * 33")))       // 406
-//compute(syard(split("( 5 + 7 ) * 2")))      // 24
-//compute(syard(split("5 + 7 / 2")))          // 8
-//compute(syard(split("5 * 7 / 2")))          // 17
-//compute(syard(split("9 + 24 / ( 7 - 3 )"))) // 15
-
-//compute(syard(split("4 ^ 3 ^ 2")))      // 262144
-//compute(syard(split("4 ^ ( 3 ^ 2 )")))  // 262144
-//compute(syard(split("( 4 ^ 3 ) ^ 2")))  // 4096
-//compute(syard(split("( 3 + 1 ) ^ 2 ^ 3")))   // 65536
-
-//syard(split("3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3"))  // 3 4 8 * 5 1 - 2 3 ^ ^ / +
-//compute(syard(split("3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3"))) // 3
-
-//compute(syard(split("( 3 + 1 ) ^ 2 ^ 3")))   // 65536
-
-
-
-}
--- a/pre_marking3/postfix_test.sh	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,200 +0,0 @@
-#!/bin/zsh
-set -euo pipefail
-
-
-out=${1:-output}
-
-echo -e "" > $out
-
-echo `date` >> $out
-echo -e "Below is the feedback and provisional marks for your submission" >> $out
-echo -e "of the Preliminary Part of Part 3 (Scala).  Please note all marks are provisional until" >> $out
-echo -e "ratified by the assessment board -- this is not an official" >> $out
-echo -e "results transcript." >> $out
-echo -e "" >> $out
-
-echo -e "Below is the feedback for your submission docdiff.scala" >> $out
-echo -e "" >> $out
-
-
-# marks for CW9 preliminary
-marks=$(( 0.0 ))
-
-
-# compilation tests
-
-function scala_compile {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -Xprint:parser "$1" 2> c$out 1> c$out)
-}
-
-# functional tests
-
-function scala_assert {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)
-}
-
-# purity test
-
-function scala_vars {
-   (egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' c$out 2> /dev/null 1> /dev/null)
-}
-
-# compilation test
-
-echo -e "postfix.scala runs?" | tee -a $out
-
-if (scala_compile postfix.scala)
-then
-   echo -e "  --> success" | tee -a $out
-   tsts=$(( 0 ))
-else
-   echo -e "  --> SCALA DID NOT RUN postfix.scala\n" | tee -a $out
-   tsts=$(( 1 ))
-fi
-
-
-
-# var, return, ListBuffer test
-#
-if  [ $tsts -eq 0 ]
-  then   
-  echo -e "postfix.scala does not contain VARS, RETURNS etc?" | tee -a $out
-
-  if (scala_vars postfix.scala)
-  then
-    echo -e "  --> FAIL\n" | tee -a $out  
-    tsts=$(( 1 ))
-  else
-    echo -e "  --> success" | tee -a $out  
-    tsts=$(( 0 )) 
-  fi
-else
-  tsts=$(( 1 ))  
-fi  
-
-
-
-### postfix tests
-
-if [ $tsts -eq 0 ]
-then
-  echo -e " syard(split(\"3 + 4 * ( 2 - 1 )\")) == List(\"3\", \"4\", \"2\", \"1\", \"-\", \"*\", \"+\")" | tee -a $out
-  echo -e " syard(split(\"( ( ( 3 ) ) + ( ( 4 + ( 5 ) ) ) )\")) == List(\"3\", \"4\", \"5\", \"+\", \"+\")" | tee -a $out
-  echo -e " syard(split(\"5 + 7 / 2\")) == List(\"5\", \"7\", \"2\", \"/\", \"+\")" | tee -a $out
-  echo -e " syard(split(\"5 * 7 / 2\")) == List(\"5\", \"7\", \"*\", \"2\", \"/\")" | tee -a $out
-  
-  if (scala_assert "postfix.scala" "postfix_test1.scala")
-  then
-    echo -e "  --> success" | tee -a $out
-    marks=$(( marks + 1.0 ))
-  else
-    echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
-  fi
-fi
-
-
-
-if [ $tsts -eq 0 ]
-then
-  echo -e " compute(syard(split(\"3 + 4 * ( 2 - 1 )\"))) == 7" | tee -a $out
-  echo -e " compute(syard(split(\"10 + 12 * 33\"))) == 406" | tee -a $out
-  echo -e " compute(syard(split(\"( 5 + 7 ) * 2\"))) == 24" | tee -a $out
-  echo -e " compute(syard(split(\"5 + 7 / 2\"))) == 8" | tee -a $out
-  echo -e " compute(syard(split(\"5 * 7 / 2\"))) == 17" | tee -a $out
-  echo -e " compute(syard(split(\"9 + 24 / ( 7 - 3 )\"))) == 15" | tee -a $out
-  
-  if (scala_assert "postfix.scala" "postfix_test2.scala")
-  then
-     echo -e "  --> success" | tee -a $out
-     marks=$(( marks + 1.0 ))
-  else
-     echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
-  fi
-fi
-
-
-
-### postfix2 tests
-
-echo -e "Below is the feedback for your submission postfix2.scala" >> $out
-echo -e "" >> $out
-
-# compilation test
-
-echo -e "postfix2.scala runs?" | tee -a $out
-
-if (scala_compile postfix2.scala)
-then
-   echo -e "  --> success" | tee -a $out
-   tsts=$(( 0 ))
-else
-   echo -e "  --> SCALA DID NOT RUN postfix2.scala\n" | tee -a $out
-   tsts=$(( 1 )) 
-fi
-
-
-# var, return, ListBuffer test
-#
-if  [ $tsts -eq 0 ]
-then     
-  echo -e "postfix2.scala does not contain VARS, RETURNS etc?" | tee -a $out
-
-  if (scala_vars postfix2.scala)
-  then
-    echo -e "  --> FAIL\n" | tee -a $out  
-    tsts=$(( 1 ))
-  else
-    echo -e "  --> success" | tee -a $out  
-    tsts=$(( 0 )) 
-  fi
-else
-  tsts=$(( 1 ))  
-fi
-
-
-
-
-if [ $tsts -eq 0 ]
-then
-  echo -e " syard(split(\"3 + 4 * ( 2 - 1 )\")) == List(\"3\", \"4\", \"2\", \"1\", \"-\", \"*\", \"+\")" | tee -a $out
-  echo -e " syard(split(\"( ( ( 3 ) ) + ( ( 4 + ( 5 ) ) ) )\")) == List(\"3\", \"4\", \"5\", \"+\", \"+\")" | tee -a $out
-  echo -e " syard(split(\"5 + 7 / 2\")) == List(\"5\", \"7\", \"2\", \"/\", \"+\")" | tee -a $out
-  echo -e " syard(split(\"5 * 7 / 2\")) == List(\"5\", \"7\", \"*\", \"2\", \"/\")" | tee -a $out
-  echo -e " syard(split(\"3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3\")) == " | tee -a $out
-  echo -e "         List(\"3\", \"4\", \"8\", \"*\", \"5\", \"1\", \"-\", \"2\", \"3\", \"^\", \"^\", \"/\", \"+\")" | tee -a $out
-  
-  if (scala_assert "postfix2.scala" "postfix_test3.scala")
-  then
-      echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 0.5 ))
-  else
-      echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
-  fi
-fi
-
-if [ $tsts -eq 0 ]
-then
-  echo -e " compute(syard(split(\"3 + 4 * ( 2 - 1 )\"))) == 7" | tee -a $out
-  echo -e " compute(syard(split(\"10 + 12 * 33\"))) == 406" | tee -a $out
-  echo -e " compute(syard(split(\"( 5 + 7 ) * 2\"))) == 24" | tee -a $out
-  echo -e " compute(syard(split(\"5 + 7 / 2\"))) == 8" | tee -a $out
-  echo -e " compute(syard(split(\"5 * 7 / 2\"))) == 17" | tee -a $out
-  echo -e " compute(syard(split(\"9 + 24 / ( 7 - 3 )\"))) == 15" | tee -a $out
-  echo -e " compute(syard(split(\"4 ^ 3 ^ 2\"))) == 262144" | tee -a $out
-  echo -e " compute(syard(split(\"4 ^ ( 3 ^ 2 )\"))) == 262144" | tee -a $out
-  echo -e " compute(syard(split(\"( 4 ^ 3 ) ^ 2\"))) == 4096" | tee -a $out
-  echo -e " compute(syard(split(\"( 3 + 1 ) ^ 2 ^ 3\"))) == 65536" | tee -a $out
-  
-  if (scala_assert "postfix2.scala" "postfix_test4.scala")
-  then
-      echo -e "  --> success" | tee -a $out
-      marks=$(( marks + 0.5 ))
-  else
-      echo -e "  --> ONE OF THE TESTS FAILED\n" | tee -a $out
-  fi
-fi
-
-## final marks
-echo -e "Overall mark for the Preliminary Part 3 (Scala)" | tee -a $out
-printf " %0.1f\n" $marks | tee -a $out
-
--- a/pre_marking3/postfix_test1.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-import CW8a._
-
-
-assert(syard(split("3 + 4 * ( 2 - 1 )")) == List("3", "4", "2", "1", "-", "*", "+"))
-assert(syard(split("( ( ( 3 ) ) + ( ( 4 + ( 5 ) ) ) )")) == List("3", "4", "5", "+", "+"))
-assert(syard(split("5 + 7 / 2")) == List("5", "7", "2", "/", "+"))
-assert(syard(split("5 * 7 / 2")) == List("5", "7", "*", "2", "/"))
--- a/pre_marking3/postfix_test2.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-import CW8a._
-
-assert(compute(syard(split("3 + 4 * ( 2 - 1 )"))) == 7)
-assert(compute(syard(split("10 + 12 * 33"))) == 406)
-assert(compute(syard(split("( 5 + 7 ) * 2"))) == 24)
-assert(compute(syard(split("5 + 7 / 2"))) == 8)
-assert(compute(syard(split("5 * 7 / 2"))) == 17)
-assert(compute(syard(split("9 + 24 / ( 7 - 3 )"))) == 15)
--- a/pre_marking3/postfix_test3.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-import CW8b._
-
-
-assert(syard(split("3 + 4 * ( 2 - 1 )")) == List("3", "4", "2", "1", "-", "*", "+"))
-assert(syard(split("( ( ( 3 ) ) + ( ( 4 + ( 5 ) ) ) )")) == List("3", "4", "5", "+", "+"))
-assert(syard(split("5 + 7 / 2")) == List("5", "7", "2", "/", "+"))
-assert(syard(split("5 * 7 / 2")) == List("5", "7", "*", "2", "/"))
-assert(syard(split("3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3")) == List("3", "4", "8", "*", "5", "1", "-", "2", "3", "^", "^", "/", "+"))
-
--- a/pre_marking3/postfix_test4.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-import CW8b._
-
-
-assert(compute(syard(split("3 + 4 * ( 2 - 1 )"))) == 7)
-assert(compute(syard(split("10 + 12 * 33"))) == 406)
-assert(compute(syard(split("( 5 + 7 ) * 2"))) == 24)
-assert(compute(syard(split("5 + 7 / 2"))) == 8)
-assert(compute(syard(split("5 * 7 / 2"))) == 17)
-assert(compute(syard(split("9 + 24 / ( 7 - 3 )"))) == 15)
-assert(compute(syard(split("4 ^ 3 ^ 2"))) == 262144)
-assert(compute(syard(split("4 ^ ( 3 ^ 2 )"))) == 262144)
-assert(compute(syard(split("( 4 ^ 3 ) ^ 2"))) == 4096)
-assert(compute(syard(split("( 3 + 1 ) ^ 2 ^ 3"))) == 65536)
--- a/pre_marking4/knight1_test.sh	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,218 +0,0 @@
-#!/bin/zsh
-
-# to make the script fail safely
-set -euo pipefail
-
-out=${1:-output}
-
-echo "" > $out
-
-echo `date` >> $out
-echo -e "" >> $out
-echo -e "Below is the feedback and provisional marks for your submission" >> $out
-echo -e "of the Preliminary Part of Part 4 (Scala).  Please note all marks are provisional until" >> $out
-echo -e "ratified by the assessment board -- this is not an official" >> $out
-echo -e "results transcript." >> $out
-echo -e "" >> $out
-
-echo -e "" >> $out
-echo -e "Below is the feedback for your submission knight1.scala" >> $out
-echo -e "" >> $out
-
-
-
-# marks for CW8 part 1
-marks=$(( 0.0 ))
-
-# compilation tests
-
-function scala_compile {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -Xprint:parser "$1" 2> c$out 1> c$out)
-}
-
-# functional tests
-
-function scala_assert {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)
-}
-
-function scala_assert_slow {
-  (ulimit -t 120; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)  
-}
-
-function scala_assert_thirty {
-  (ulimit -t 40; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)  
-}
-
-function scala_assert_quick {
-  (ulimit -t 30; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)    
-}
-
-function scala_assert_long {
-  (ulimit -t 60; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null)    
-}
-
-function scala_assert_elong {
-  (ulimit -t 90; JAVA_OPTS="-Xmx1g" scala -i "$1" -- "$2" -e "" 2> /dev/null 1> /dev/null) 
-}
-
-# purity test
-
-
-function scala_vars {
-   (egrep '\bvar\b|\breturn\b|\.par\.|\.par |ListBuffer|AtomicInteger|mutable|util.control|new Array' c$out 2> /dev/null 1> /dev/null)
-}
-
-
-# compilation test
-
-echo -e "knight1.scala runs?" | tee -a $out
-
-if (scala_compile knight1.scala)
-then
-    echo -e "  --> success " | tee -a $out
-    tsts=$(( 0 ))
-else
-    echo -e "  --> SCALA DID NOT RUN KNIGHT1.SCALA\n" | tee -a $out
-    tsts=$(( 1 )) 
-fi
-
-
-# knights1: purity test
-if  [ $tsts -eq 0 ]
-  then   
-  echo -e "knight1.scala does not contain VARS, RETURNS etc?" | tee -a $out
-
-  if (scala_vars knight1.scala)
-  then
-     echo -e "  --> FAIL\n" | tee -a $out
-     tsts=$(( 1 ))
-  else
-     echo -e "  --> success" | tee -a $out
-     tsts=$(( 0 )) 
-  fi
-else
-  tsts=$(( 1 ))  
-fi
-
-echo >> $out
-
-### knight1 test
-
-if [ $tsts -eq 0 ]
-then
-    echo " is_legal(8, Nil, (3, 4)) == true " | tee -a $out
-    echo " is_legal(8, List((4, 1), (1, 0)), (4, 1)) == false " | tee -a $out
-    echo " is_legal(2, Nil, (0, 0)) == true" | tee -a $out                          
-
-    if (scala_assert "knight1.scala" "knight1_test1.scala")
-    then
-        echo -e "  --> success" | tee -a $out
-	marks=$(( marks + 1.0 ))
-    else
-        echo -e "  --> \n ONE TEST FAILED\n"| tee -a $out
-    fi
-fi
-
-### knight2 test
-
-if [ $tsts -eq 0 ]
-then
-  echo " legal_moves(8, Nil, (2,2)) == List((3,4), (4,3), (4,1), (3,0), (1,0), (0,1), (0,3), (1,4))" | tee -a $out
-  echo " legal_moves(8, Nil, (7,7)) == List((6,5), (5,6))" | tee -a $out
-  echo " legal_moves(8, List((4,1), (1,0)), (2,2)) == List((3,4), (4,3), (3,0), (0,1), (0,3), (1,4))" | tee -a $out
-  echo " legal_moves(8, Nil, (0,1)) == List((1,3), (2,2), (2,0))" | tee -a $out
-  echo " legal_moves(8, List((6,6)), (7,7)) == List((6,5), (5,6))" | tee -a $out
-  echo " legal_moves(1, Nil, (0,0)) == Nil" | tee -a $out
-  echo " legal_moves(2, Nil, (0,0)) == Nil" | tee -a $out
-  echo " legal_moves(3, Nil, (0,0)) == List((1,2), (2,1))" | tee -a $out
-  
-  if (scala_assert "knight1.scala" "knight1_test2.scala")
-  then
-     echo -e "  --> success\n" | tee -a $out
-     marks=$(( marks + 1 ))
-  else
-     echo -e "  --> ONE TEST FAILED\n" | tee -a $out
-  fi
-fi
-
-
-### knight3 test
-
-if [ $tsts -eq 0 ]
-then
-  echo " count_tours from every position on the board 1 - 4 (0.5% marks)" | tee -a $out
-  echo " dim = 1: 1" | tee -a $out
-  echo "       2: 0,0,0,0" | tee -a $out
-  echo "       3: 0,0,0,0,0,0,0,0,0" | tee -a $out
-  echo "       4: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" | tee -a $out
-  START=$(date +%s)
-  
-  if (scala_assert_thirty "knight1.scala" "knight1_test3a.scala") 
-  then
-     END=$(date +%s)
-     DIFF=$(( $END - $START ))
-     #echo " This test ran for $DIFF seconds." | tee -a $out  
-     echo -e "  --> success\n" | tee -a $out
-     marks=$(( marks + 0.5 ))
-  else
-     END=$(date +%s)
-     DIFF=$(( $END - $START ))
-     echo " This test ran for $DIFF seconds." | tee -a $out 
-     echo -e "  --> ONE TEST FAILED\n" | tee -a $out
-  fi
-fi
-
-
-
-if [ $tsts -eq 0 ]
-then
-  echo " count_tours from every position on the board of dim 5 for the first 3 rows (0.5% marks)" | tee -a $out
-  echo " dim = 5: 304,0,56,0,304,0,56,0,56,0,56,0,64,0,56)" | tee -a $out
-  START=$(date +%s)
-  
-  if (scala_assert_thirty "knight1.scala" "knight1_test3b.scala") 
-  then
-     END=$(date +%s)
-     DIFF=$(( $END - $START ))
-     #echo " This test ran for $DIFF seconds." | tee -a $out  
-     echo -e "  --> success\n" | tee -a $out
-     marks=$(( marks + 0.5 ))
-  else
-     END=$(date +%s)
-     DIFF=$(( $END - $START ))
-     echo " This test ran for $DIFF seconds." | tee -a $out 
-     echo -e "  --> ONE TEST FAILED\n" | tee -a $out
-  fi
-fi
-
-
-
-if [ $tsts -eq 0 ]
-then
-  echo " enum_tours(5, List((0,2)) ) => 56 tours? and all correct?" | tee -a $out
-  echo " enum_tours(5, List((0,0)) ) => 304 tours? and all correct?" | tee -a $out
-  START=$(date +%s)
-  
-  if (scala_assert_thirty "knight1.scala" "knight1_test3c.scala") 
-  then
-     END=$(date +%s)
-     DIFF=$(( $END - $START ))
-     #echo " This test ran for $DIFF seconds." | tee -a $out 
-     echo -e "  --> success\n" | tee -a $out
-     marks=$(( marks + 1.0 ))
-  else
-     END=$(date +%s)
-     DIFF=$(( $END - $START ))
-     echo " This test ran for $DIFF seconds." | tee -a $out 
-     echo -e "  --> \n ONE TEST FAILED\n" | tee -a $out
-  fi
-fi
-
-
-## final marks
-echo -e "Overall mark for the Preliminary Part 4 (Scala)" | tee -a $out
-printf " %0.1f\n" $marks | tee -a $out
-
-
-
--- a/pre_marking4/knight1_test1.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-import CW9a._
-
-assert(is_legal(8, Nil, (3, 4)) == true)
-assert(is_legal(8, List((4, 1), (1, 0)), (4, 1)) == false)
-assert(is_legal(2, Nil, (0, 0)) == true)
-
-
-
-
--- a/pre_marking4/knight1_test2.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-import CW9a._
-
-assert(legal_moves(8, Nil, (2,2)) == 
-             List((3,4), (4,3), (4,1), (3,0), (1,0), (0,1), (0,3), (1,4)))
-assert(legal_moves(8, Nil, (7,7)) == List((6,5), (5,6)))
-assert(legal_moves(8, List((4,1), (1,0)), (2,2)) == 
-       List((3,4), (4,3), (3,0), (0,1), (0,3), (1,4)))
-assert(legal_moves(8, Nil, (0,1)) == List((1,3), (2,2), (2,0)))
-assert(legal_moves(8, List((6,6)), (7,7)) == List((6,5), (5,6)))
-assert(legal_moves(1, Nil, (0,0)) == Nil)
-assert(legal_moves(2, Nil, (0,0)) == Nil)
-assert(legal_moves(3, Nil, (0,0)) == List((1,2), (2,1)))
-
--- a/pre_marking4/knight1_test3a.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-import CW9a._
-
-def count_all_tours_urban(dim: Int) = {
-  for (i <- (0 until dim).toList; 
-       j <- (0 until dim).toList) yield count_tours(dim, List((i, j)))
-}
-
-
-assert(count_all_tours_urban(1) == List(1))
-assert(count_all_tours_urban(2) == List(0, 0, 0, 0))
-assert(count_all_tours_urban(3) == List(0, 0, 0, 0, 0, 0, 0, 0, 0))
-assert(count_all_tours_urban(4) == List(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
-
-
--- a/pre_marking4/knight1_test3b.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-import CW9a._
-//type Pos = (Int, Int)    // a position on a chessboard 
-//type Path = List[Pos]    // a path...a list of positions
-
-/*
-def count_all_tours_urban(dim: Int) = {
-  for (i <- (0 until dim).toList; 
-       j <- (0 until dim).toList) yield count_tours(dim, List((i, j)))
-}
-*/
-
-def count_all_tours_urban(dim: Int) = {
-  for (i <- (0 until 3).toList; 
-       j <- (0 until dim).toList) yield count_tours(dim, List((i, j)))
-}
-
-
-assert(count_all_tours_urban(5) == List(304, 0, 56, 0, 304, 0, 56, 0, 56, 0, 56, 0, 64, 0, 56))
-
--- a/pre_marking4/knight1_test3c.scala	Thu Jan 13 12:55:03 2022 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-import CW9a._
-
-//type Pos = (Int, Int)    // a position on a chessboard 
-//type Path = List[Pos]    // a path...a list of positions
-
-def add_pair_urban(x: Pos)(y: Pos): Pos = 
-  (x._1 + y._1, x._2 + y._2)
-
-def is_legal_urban(dim: Int, path: Path)(x: Pos): Boolean = 
-  0 <= x._1 && 0 <= x._2 && x._1 < dim && x._2 < dim && !path.contains(x)
-
-def moves_urban(x: Pos): List[Pos] = 
-  List(( 1,  2),( 2,  1),( 2, -1),( 1, -2),
-       (-1, -2),(-2, -1),(-2,  1),(-1,  2)).map(add_pair_urban(x))
-
-def legal_moves_urban(dim: Int, path: Path, x: Pos): List[Pos] = 
-  moves_urban(x).filter(is_legal_urban(dim, path))
-
-def correct_urban(dim: Int)(p: Path): Boolean = p match {
-  case Nil => true
-  case x::Nil => true
-  case x::y::p => if (legal_moves_urban(dim, p, y).contains(x)) correct_urban(dim)(y::p) else false
-}
-
-
-val ts00_urban = enum_tours(5, List((0, 0)))
-assert(ts00_urban.map(correct_urban(5)).forall(_ == true) == true)
-assert(ts00_urban.length == 304)  
-
-
-val ts_urban = enum_tours(5, List((0, 2)))
-assert(ts_urban.map(correct_urban(5)).forall(_ == true) == true)
-assert(ts_urban.length == 56)  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/progs/mandelbrot3.sc	Mon Apr 11 23:55:27 2022 +0100
@@ -0,0 +1,201 @@
+// Mandelbrot pictures
+//=====================
+//
+//   see https://en.wikipedia.org/wiki/Mandelbrot_set
+// 
+// under scala 2.13.1 needs to be called with
+// 
+// scala -cp scala-parallel-collections_2.13-0.2.0.jar mandelbrot.scala
+//
+// scala-cli run --jar scala-parallel-collections_3-1.0.4.jar mandelbrot3.sc
+
+
+import java.awt.Color
+import java.awt.Dimension
+import java.awt.Graphics
+import java.awt.Graphics2D
+import java.awt.image.BufferedImage
+import javax.swing.JFrame
+import javax.swing.JPanel
+import javax.swing.WindowConstants
+import scala.language.implicitConversions    
+import scala.collection.parallel.CollectionConverters._
+
+object Test {
+
+def main() = {
+
+// complex numbers
+case class Complex(val re: Double, val im: Double) { 
+  // represents the complex number re + im * i
+  def +(that: Complex) = Complex(this.re + that.re, this.im + that.im)
+  def -(that: Complex) = Complex(this.re - that.re, this.im - that.im)
+  def *(that: Complex) = Complex(this.re * that.re - this.im * that.im,
+                                 this.re * that.im + that.re * this.im)
+  def *(that: Double) = Complex(this.re * that, this.im * that)
+  def abs() = Math.sqrt(this.re * this.re + this.im * this.im)
+}
+
+// to allow the notation n + m * i
+object i extends Complex(0, 1)
+
+given Conversion[Double, Complex] = Complex(_, 0)
+
+
+// some customn colours for the "sliding effect"
+val colours = List(
+  new Color(66, 30, 15),    new Color(25, 7, 26),
+  new Color(9, 1, 47),      new Color(4, 4, 73),
+  new Color(0, 7, 100),     new Color(12, 44, 138),
+  new Color(24, 82, 177),   new Color(57, 125, 209),
+  new Color(134, 181, 229), new Color(211, 236, 248),
+  new Color(241, 233, 191), new Color(248, 201, 95),
+  new Color(255, 170, 0),   new Color(204, 128, 0),
+  new Color(153, 87, 0),    new Color(106, 52, 3))
+
+// the viewer panel with an image canvas
+class Viewer(width: Int, height: Int) extends JPanel {
+  val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
+  
+  override def paintComponent(g: Graphics) = 
+    g.asInstanceOf[Graphics2D].drawImage(canvas, null, null)
+  
+  override def getPreferredSize() = 
+    new Dimension(width, height)
+
+  def clearCanvas(color: Color) = {
+    for (x <- 0 to width - 1; y <- 0 to height - 1) 
+      canvas.setRGB(x, y, color.getRGB())
+    repaint()
+  }  
+}
+
+// initialising the viewer panel
+def openViewer(width: Int, height: Int) : Viewer = {
+  val frame = new JFrame("XYPlane")
+  val viewer = new Viewer(width, height)
+  frame.add(viewer)
+  frame.pack()
+  frame.setVisible(true)
+  frame.setResizable(false)
+  frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
+  viewer
+}
+
+// some hardcoded parameters
+val W = 900   // width
+val H = 800   // height
+val black = Color.black
+val viewer = openViewer(W, H)
+
+// draw a pixel on the canvas
+def pixel(x: Int, y: Int, color: Color) = 
+  viewer.canvas.setRGB(x, y, color.getRGB())
+
+
+// calculates the number of iterations using lazy lists (streams)
+//   the iteration goes on for a maximum of max steps,
+//   but might leave early when the pred is satisfied
+def iterations(c: Complex, max: Int) : Int = {
+  def next(z: Complex) = z * z + c    
+  def pred(z: Complex) = z.abs() < 2    // exit condition
+  LazyList.iterate(0.0 * i, max)(next).takeWhile(pred).size
+}
+
+// main function 
+//    start and end are the upper-left and lower-right corners, 
+//    max is the number of maximum iterations
+def mandelbrot(start: Complex, end: Complex, max: Int) : Unit = {
+  viewer.clearCanvas(black)
+  
+  // deltas for each grid step 
+  val d_x = (end.re - start.re) / W
+  val d_y = (end.im - start.im) / H
+   
+  for (y <- (0 until H).par) {
+    for (x <- (0 until W).par) {
+    
+     val c = start + 
+      (x * d_x + y * d_y * i)
+     val iters = iterations(c, max) 
+     val col = 
+       if (iters == max) black 
+       else colours(iters % 16)
+
+     pixel(x, y, col)
+    }
+    viewer.updateUI()
+  }   
+}
+
+
+// Examples
+//==========
+
+//for measuring time
+def time_needed[T](code: => T) = {
+  val start = System.nanoTime()
+  code
+  val end = System.nanoTime()
+  (end - start) / 1.0e9
+}
+
+
+
+// example 1
+val exa1 = -2.0 + -1.5 * i
+val exa2 =  1.0 +  1.5 * i
+
+println(s"${time_needed(mandelbrot(exa1, exa2, 1000))} secs")
+
+// example 2
+val exb1 = -0.37465401 + 0.659227668 * i
+val exb2 = -0.37332410 + 0.66020767 * i
+
+//time_needed(mandelbrot(exb1, exb2, 1000))
+
+// example 3
+val exc1 = 0.435396403 + 0.367981352 * i
+val exc2 = 0.451687191 + 0.380210061 * i
+
+//time_needed(mandelbrot(exc1, exc2, 1000))
+
+
+
+// some more computations with example 3
+
+val delta = (exc2 - exc1) * 0.0333
+
+println(s"${time_needed(
+  for (n <- (0 to 12)) 
+      mandelbrot(exc1 + delta * n, 
+                exc2 - delta * n, 100))} secs") 
+
+
+
+// Larry Paulson's example
+val exl1 = -0.74364990 + 0.13188170 * i
+val exl2 = -0.74291189 + 0.13261971 * i
+
+//println(s"${time_needed(mandelbrot(exl1, exl2, 1000))} secs")
+
+
+// example by Jorgen Villadsen
+val exj1 = 0.10284 - 0.63275 * i
+val exj2 = 0.11084 - 0.64075 * i
+
+//time_needed(mandelbrot(exj1, exj2, 1000))
+
+
+// another example
+val exA = 0.3439274 + 0.6516478 * i
+val exB = 0.3654477 + 0.6301795 * i
+
+//time_needed(mandelbrot(exA, exB, 1000))
+
+
+}
+
+}
+
+Test.main()