From 8535a9ca92539bf12ec00cac7a4e47be604f0283 Mon Sep 17 00:00:00 2001
From: Jonas Smedegaard <dr@jones.dk>
Date: Sun, 27 Apr 2025 16:43:17 +0200
Subject: simplify path structure

---
 .../com/example/portfolio3/AbstractGraph.java      |  52 ++++
 .../com/example/portfolio3/AdjListGraph.java       |  47 +++
 .../com/example/portfolio3/AdjMapGraph.java        |  45 +++
 .../com/example/portfolio3/Edge.java               |  37 +++
 .../com/example/portfolio3/EdgeGraph.java          |  37 +++
 .../com/example/portfolio3/Graph.java              |  34 +++
 .../com/example/portfolio3/GraphAlgorithms.java    | 331 +++++++++++++++++++++
 .../com/example/portfolio3/Graphs.java             |  13 +
 .../com/example/portfolio3/MatrixGraph.java        |  77 +++++
 .../com/example/portfolio3/Vertex.java             |  24 ++
 .../dk/biks/bachelorizer/Control.java              |  94 ++++++
 .../dk/biks/bachelorizer/Main.java                 |  90 ++++++
 .../dk/biks/bachelorizer/model/Combi.java          | 105 +++++++
 .../dk/biks/bachelorizer/model/GUI.java            |  62 ++++
 .../dk/biks/bachelorizer/model/Person.java         |  18 ++
 .../dk/biks/bachelorizer/view/Window.java          | 120 ++++++++
 .../com/example/portfolio3/AbstractGraph.java      |  52 ----
 .../com/example/portfolio3/AdjListGraph.java       |  47 ---
 .../com/example/portfolio3/AdjMapGraph.java        |  45 ---
 .../com/example/portfolio3/Edge.java               |  37 ---
 .../com/example/portfolio3/EdgeGraph.java          |  37 ---
 .../com/example/portfolio3/Graph.java              |  34 ---
 .../com/example/portfolio3/GraphAlgorithms.java    | 331 ---------------------
 .../com/example/portfolio3/Graphs.java             |  13 -
 .../com/example/portfolio3/MatrixGraph.java        |  77 -----
 .../com/example/portfolio3/Vertex.java             |  24 --
 .../dk/biks/bachelorizer/Control.java              |  94 ------
 .../dk/biks/bachelorizer/Main.java                 |  90 ------
 .../dk/biks/bachelorizer/model/Combi.java          | 105 -------
 .../dk/biks/bachelorizer/model/GUI.java            |  62 ----
 .../dk/biks/bachelorizer/model/Person.java         |  18 --
 .../dk/biks/bachelorizer/view/Window.java          | 120 --------
 32 files changed, 1186 insertions(+), 1186 deletions(-)
 create mode 100644 src/com.example.portfolio3/com/example/portfolio3/AbstractGraph.java
 create mode 100644 src/com.example.portfolio3/com/example/portfolio3/AdjListGraph.java
 create mode 100644 src/com.example.portfolio3/com/example/portfolio3/AdjMapGraph.java
 create mode 100644 src/com.example.portfolio3/com/example/portfolio3/Edge.java
 create mode 100644 src/com.example.portfolio3/com/example/portfolio3/EdgeGraph.java
 create mode 100644 src/com.example.portfolio3/com/example/portfolio3/Graph.java
 create mode 100644 src/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java
 create mode 100644 src/com.example.portfolio3/com/example/portfolio3/Graphs.java
 create mode 100644 src/com.example.portfolio3/com/example/portfolio3/MatrixGraph.java
 create mode 100644 src/com.example.portfolio3/com/example/portfolio3/Vertex.java
 create mode 100644 src/dk.biks.bachelorizer/dk/biks/bachelorizer/Control.java
 create mode 100644 src/dk.biks.bachelorizer/dk/biks/bachelorizer/Main.java
 create mode 100644 src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Combi.java
 create mode 100644 src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/GUI.java
 create mode 100644 src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Person.java
 create mode 100644 src/dk.biks.bachelorizer/dk/biks/bachelorizer/view/Window.java
 delete mode 100644 src/main/java/com.example.portfolio3/com/example/portfolio3/AbstractGraph.java
 delete mode 100644 src/main/java/com.example.portfolio3/com/example/portfolio3/AdjListGraph.java
 delete mode 100644 src/main/java/com.example.portfolio3/com/example/portfolio3/AdjMapGraph.java
 delete mode 100644 src/main/java/com.example.portfolio3/com/example/portfolio3/Edge.java
 delete mode 100644 src/main/java/com.example.portfolio3/com/example/portfolio3/EdgeGraph.java
 delete mode 100644 src/main/java/com.example.portfolio3/com/example/portfolio3/Graph.java
 delete mode 100644 src/main/java/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java
 delete mode 100644 src/main/java/com.example.portfolio3/com/example/portfolio3/Graphs.java
 delete mode 100644 src/main/java/com.example.portfolio3/com/example/portfolio3/MatrixGraph.java
 delete mode 100644 src/main/java/com.example.portfolio3/com/example/portfolio3/Vertex.java
 delete mode 100644 src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Control.java
 delete mode 100644 src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Main.java
 delete mode 100644 src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Combi.java
 delete mode 100644 src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/GUI.java
 delete mode 100644 src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Person.java
 delete mode 100644 src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/view/Window.java

(limited to 'src')

diff --git a/src/com.example.portfolio3/com/example/portfolio3/AbstractGraph.java b/src/com.example.portfolio3/com/example/portfolio3/AbstractGraph.java
new file mode 100644
index 0000000..c2cf433
--- /dev/null
+++ b/src/com.example.portfolio3/com/example/portfolio3/AbstractGraph.java
@@ -0,0 +1,52 @@
+package com.example.portfolio3;
+
+// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
+
+import java.util.*;
+
+/// foo
+abstract class AbstractGraph implements Graph{
+
+  /// foo
+  AbstractGraph() {}
+
+  /// foo
+  private HashMap<String,Vertex> vertexMap=new HashMap<>();
+
+  /// foo
+  private HashSet<Vertex> vertexSet=new HashSet<>();
+
+  /// foo
+  /// @param s  foo
+  /// @return Vertex
+  public Vertex vertex(String s){
+    if(vertexMap.containsKey(s))return vertexMap.get(s);
+    Vertex v=new Vertex(s);
+    vertexMap.put(s,v);
+    vertexSet.add(v);
+    return v;
+  }
+
+  /// foo
+  public void insertEdge(String v, String u, int w){
+    insertEdge(vertex(v),vertex(u),w);
+  }
+
+  /// foo
+  public Collection<Vertex> vertices() { return vertexSet;  }
+
+  /// foo
+  /// @param v1  foo
+  /// @param v2  foo
+  /// @param w   foo
+  abstract public void insertEdge(Vertex v1, Vertex v2, int w);
+
+  /// foo
+  abstract public Collection<Edge> edges();
+
+  /// foo
+  abstract public Collection<Edge> outEdge(Vertex v);
+
+  /// foo
+  abstract public Integer getWeight(Vertex v1, Vertex v2);
+}
diff --git a/src/com.example.portfolio3/com/example/portfolio3/AdjListGraph.java b/src/com.example.portfolio3/com/example/portfolio3/AdjListGraph.java
new file mode 100644
index 0000000..a677d3e
--- /dev/null
+++ b/src/com.example.portfolio3/com/example/portfolio3/AdjListGraph.java
@@ -0,0 +1,47 @@
+package com.example.portfolio3;
+
+// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
+
+import java.util.*;
+
+///  Adjecency List Graph - A map from vertices to set of outedges from the vertex
+public class AdjListGraph extends AbstractGraph {
+
+  /// foo
+  public AdjListGraph() {}
+
+  /// foo
+  private Map<Vertex,Set<Edge>> outEdge= new HashMap<>();
+
+  /// foo
+  public void insertEdge(Vertex v1,Vertex v2,int w){
+    Edge e=new Edge(v1,v2,w);
+    if(!outEdge.containsKey(e.from()))
+      outEdge.put(e.from(),new HashSet<Edge>());
+    outEdge.get(e.from()).add(e);
+  }
+
+  /// foo
+  public Collection<Edge> edges(){
+    Set<Edge> edges=new HashSet<>();
+    for(Vertex v:outEdge.keySet())edges.addAll(outEdge.get(v));
+    return edges;
+  }
+
+  /// foo
+  public Collection<Edge> outEdge(Vertex v){
+    if(!outEdge.containsKey(v))
+      return new HashSet<Edge>();
+    return outEdge.get(v);
+  }
+
+  /// foo
+  public Integer getWeight(Vertex v1,Vertex v2){
+    // linear in number of outedges from vertices
+    if(!outEdge.containsKey(v1))return null;
+    for(Edge e:outEdge.get(v1)){
+      if(e.to()==v2)return e.weight();
+    }
+    return null;
+  }
+}
diff --git a/src/com.example.portfolio3/com/example/portfolio3/AdjMapGraph.java b/src/com.example.portfolio3/com/example/portfolio3/AdjMapGraph.java
new file mode 100644
index 0000000..85e5d04
--- /dev/null
+++ b/src/com.example.portfolio3/com/example/portfolio3/AdjMapGraph.java
@@ -0,0 +1,45 @@
+package com.example.portfolio3;
+
+// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
+
+import java.util.*;
+
+///  Adjecency Map Graph - A map from vertices to map of target vertex to edge
+class AdjMapGraph extends AbstractGraph {
+
+  /// foo
+  AdjMapGraph() {}
+
+  /// foo
+  private Map<Vertex, Map<Vertex, Edge>> outEdge = new HashMap<>();
+
+  /// foo
+  public void insertEdge(Vertex v1, Vertex v2, int w) {
+    Edge e = new Edge(v1,v2, w);
+    if (!outEdge.containsKey(e.from()))
+      outEdge.put(e.from(), new HashMap<Vertex, Edge>());
+    outEdge.get(e.from()).put(e.to(), e);
+  }
+
+  /// foo
+  public Collection<Edge> edges() {
+    Set<Edge> edges = new HashSet<>();
+    for (Vertex v : outEdge.keySet())
+      for (Vertex w : outEdge.get(v).keySet())
+        edges.add(outEdge.get(v).get(w));
+    return edges;
+  }
+
+  /// foo
+  public Collection<Edge> outEdge(Vertex v) {
+    return outEdge.get(v).values();
+  }
+
+  /// foo
+  public Integer getWeight(Vertex v1, Vertex v2) {
+    // constant time operation
+    if(!outEdge.containsKey(v1))return null;
+    if(!outEdge.get(v1).containsKey(v2))return null;
+    return outEdge.get(v1).get(v2).weight();
+  }
+}
diff --git a/src/com.example.portfolio3/com/example/portfolio3/Edge.java b/src/com.example.portfolio3/com/example/portfolio3/Edge.java
new file mode 100644
index 0000000..abc3c72
--- /dev/null
+++ b/src/com.example.portfolio3/com/example/portfolio3/Edge.java
@@ -0,0 +1,37 @@
+package com.example.portfolio3;
+
+// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
+
+import java.util.*;
+
+/// foo
+class Edge{
+
+  /// foo
+  private Vertex from,to;
+
+  /// foo
+  private int weight;
+
+  /// foo
+  /// @return Vertex
+  public Vertex from(){return from;}
+
+  /// foo
+  /// @return Vertex
+  public Vertex to(){return to;}
+
+  /// foo
+  /// @return int
+  public int weight(){return weight;}
+
+  /// foo
+  /// @param from  foo
+  /// @param to    foo
+  /// @param w     foo
+  Edge(Vertex from,Vertex to,int w){this.from=from; this.to=to; weight=w;}
+
+  /// foo
+  /// @return String
+  public String toString(){return from.name()+" - "+weight+" -> "+to.name(); }
+}
diff --git a/src/com.example.portfolio3/com/example/portfolio3/EdgeGraph.java b/src/com.example.portfolio3/com/example/portfolio3/EdgeGraph.java
new file mode 100644
index 0000000..ae9cbe9
--- /dev/null
+++ b/src/com.example.portfolio3/com/example/portfolio3/EdgeGraph.java
@@ -0,0 +1,37 @@
+package com.example.portfolio3;
+
+// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
+
+/// EdgeGraph - One big set of all edges in the graph
+class EdgeGraph extends AbstractGraph {
+
+  /// foo
+  EdgeGraph() {}
+
+  /// foo
+  Set<Edge> edges=new HashSet<>();
+
+  /// foo
+  public void insertEdge(Vertex v1,Vertex v2,int w){
+    edges.add(new Edge(v1,v2,w));
+  }
+
+  /// foo
+  public Collection<Edge> edges(){return edges;}
+
+  /// foo
+  public Collection<Edge> outEdge(Vertex v){
+    ArrayList<Edge> outEdge=new ArrayList<>();
+    for(Edge e:edges)if(e.from()==v)outEdge.add(e);
+    return outEdge;
+  }
+
+  /// foo
+  public Integer getWeight(Vertex v1,Vertex v2){
+    // linear in number of edges in the graph
+    for(Edge e:edges){
+      if(e.from()==v1 && e.to()==v2)return e.weight();
+    }
+    return null;
+  }
+}
diff --git a/src/com.example.portfolio3/com/example/portfolio3/Graph.java b/src/com.example.portfolio3/com/example/portfolio3/Graph.java
new file mode 100644
index 0000000..6e58029
--- /dev/null
+++ b/src/com.example.portfolio3/com/example/portfolio3/Graph.java
@@ -0,0 +1,34 @@
+package com.example.portfolio3;
+
+// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
+
+import java.util.*;
+
+/// foo
+public interface Graph {
+
+  /// foo
+  /// @param v  foo
+  /// @param u  foo
+  /// @param w  foo
+  void insertEdge(String v, String u, int w);
+
+  /// foo
+  /// @return Collection
+  Collection<Vertex> vertices();
+
+  /// foo
+  /// @return Collection
+  Collection<Edge> edges();
+
+  /// foo
+  /// @param v  foo
+  /// @return Collection
+  Collection<Edge> outEdge(Vertex v);
+
+  /// foo
+  /// @param v1  foo
+  /// @param v2  foo
+  /// @return Integer
+  Integer getWeight(Vertex v1, Vertex v2);
+}
diff --git a/src/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java b/src/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java
new file mode 100644
index 0000000..3be7c70
--- /dev/null
+++ b/src/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java
@@ -0,0 +1,331 @@
+package com.example.portfolio3;
+
+// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
+
+import java.io.*;
+import java.util.*;
+
+/// foo
+public class GraphAlgorithms {
+
+  /// foo
+  GraphAlgorithms() {}
+
+  /// Calculates the length of a path or any other collection of edes
+  ///
+  /// does not require the edges to form a path
+  /// @param edges  foo
+  /// @return int
+  public static int pathLength(Collection<Edge> edges){
+    return edges.stream().mapToInt(e-> e.weight()).sum();
+  }
+
+  /// checks whether a list of edges form a path so that
+  ///
+  /// the to-vertex in one edge is the from-vertex of the next
+  /// @param edges  foo
+  /// @return boolean
+  public static boolean isPath(List<Edge> edges){
+    for(int i=1;i<edges.size();i++){
+      if(edges.get(i-1).to()!=edges.get(i).from())return false;
+    }
+    return true;
+  }
+
+  ///Calculates the length of a path vertices in a graph
+  ///
+  /// return null if vertices are not connected as a path
+  /// @param g     foo
+  /// @param path  foo
+  /// @return Integer
+  public static Integer pathLength(Graph g,List<Vertex> path){
+    int length=0;
+    for(int i=1;i<path.size();i++){
+      Integer w=g.getWeight(path.get(i-1),path.get(i));
+      if(w==null)return null;
+      length+=w;
+    }
+    return length;
+  }
+
+  //------------------------------------------------------------
+  //
+  //  Comparators and sorting methods
+
+  /// Comparator of edges based on weight
+  ///
+  /// can be used for sorting a list of edges
+  /// @param e1  foo
+  /// @param e2  foo
+  /// @return int
+  static int cmpEdgeWeight(Edge e1,Edge e2) {
+    int w1=e1.weight(),w2=e2.weight();
+    if(w1!=w2)return w1-w2;
+    if(e1.from()!=e2.from())return e1.from().name().compareTo(e2.from().name());
+    return e1.to().name().compareTo(e2.to().name());
+  }
+
+  /// Comparator of edges based on from-vertex
+  ///
+  /// can be used for sorting a list of edges
+  /// @param e1  foo
+  /// @param e2  foo
+  /// @return int
+  static int cmpEdgeFrom(Edge e1,Edge e2) {
+    if(e1.from()!=e2.from())return e1.from().name().compareTo(e2.from().name());
+    int w1=e1.weight(),w2=e2.weight();
+    if(w1!=w2)return w1-w2;
+    return e1.to().name().compareTo(e2.to().name());
+  }
+
+  /// Comparator of edges based on from-vertex
+  ///
+  /// can be used for sorting a list of edges
+  /// @param e1  foo
+  /// @param e2  foo
+  /// @return int
+  static int cmpEdgeTo(Edge e1,Edge e2) {
+    if(e1.to()!=e2.to())return e1.to().name().compareTo(e2.to().name());
+    if(e1.from()!=e2.from())return e1.from().name().compareTo(e2.from().name());
+    int w1=e1.weight(),w2=e2.weight();
+    return w1-w2;
+  }
+
+  /// sort a collection of edges based on their weights
+  /// @param edges  foo
+  /// @return List<Edge>
+  static List<Edge> sortEdges(Collection<Edge> edges){
+    ArrayList<Edge> list=new ArrayList<>(edges);
+    Collections.sort(list,GraphAlgorithms::cmpEdgeWeight);
+    return list;
+  }
+
+  /// sort a collection of edges based on from-vertex
+  /// @param edges  foo
+  /// @return List<Edge>
+  static List<Edge> sortEdgesFrom(Collection<Edge> edges){
+    ArrayList<Edge> list=new ArrayList<>(edges);
+    Collections.sort(list,GraphAlgorithms::cmpEdgeFrom);
+    return list;
+  }
+
+  /// sort a collection of edges based on to-vertex
+  /// @param edges  foo
+  /// @return List<Edge>
+  static List<Edge> sortEdgesTo(Collection<Edge> edges){
+    ArrayList<Edge> list=new ArrayList<>(edges);
+    Collections.sort(list,GraphAlgorithms::cmpEdgeTo);
+    return list;
+  }
+
+  /// sort a collection of vertices based on their name
+  /// @param vertices  foo
+  /// @return List<Vertex>
+  static List<Vertex> sortVertex(Collection<Vertex> vertices){
+    ArrayList<Vertex> list=new ArrayList<>(vertices);
+    Collections.sort(list,(Vertex v1,Vertex v2)-> v1.name().compareTo(v2.name()));
+    return list;
+  }
+
+  //------------------------------------------------------------
+  //
+  //  Algorithms for traverse and minimum spanning tree
+
+  /// traverse a graph depth first from a given vertex
+  /// return the set of visited vertices
+  /// @param g  foo
+  /// @param v  foo
+  /// @return Set<Vertex>
+  public static Set<Vertex> visitBreadthFirst(Graph g,Vertex v){
+    HashSet<Vertex> thisLevel=new HashSet<>();
+    HashSet<Vertex> nextLevel=new HashSet<>();
+    HashSet<Vertex> visited=new HashSet<>();
+    thisLevel.add(v);
+    while(thisLevel.size()>0){
+      System.out.println("level "+thisLevel);
+      for(Vertex w:thisLevel){
+        //System.out.println("visited "+w);
+        visited.add(w);
+        Collection<Edge> outedge=g.outEdge(w);
+        if(outedge==null)continue;
+        for(Edge e: outedge){
+          if(visited.contains(e.to()))continue;
+          if(thisLevel.contains(e.to()))continue;
+          nextLevel.add(e.to());
+        }
+      }
+      thisLevel=nextLevel;
+      nextLevel=new HashSet<Vertex>();
+    }
+    return visited;
+  }
+
+  /// traverse a graph depth first from a given vertex
+  /// return the set of visited vertices
+  /// @param g  foo
+  /// @param v  foo
+  /// @return Set<Vertex>
+  public static Set<Vertex> visitDepthFirst(Graph g,Vertex v){
+    HashSet<Vertex> visit=new HashSet<>();
+    visitDepthFirst(g, v,visit);
+    return visit;
+  }
+
+  /// foo
+  /// @param g        foo
+  /// @param v        foo
+  /// @param visited  foo
+  private static void visitDepthFirst(Graph g,Vertex v,Set<Vertex> visited){
+    if(visited.contains(v))return;
+    //System.out.println("visited "+v);
+    visited.add(v);
+    for(Edge e: g.outEdge(v))
+      visitDepthFirst(g,e.to(),visited);
+  }
+
+  /// an implementation of Prim's algorithm
+  /// naive implementation without priorityqueue
+  /// @param g  foo
+  /// @return Set<Edge>
+  public static Set<Edge> minimumSpanningTree(Graph g){
+    Collection<Edge> edges=g.edges();
+    HashSet<Edge> mst=new HashSet<>();
+    HashSet<Vertex> frontier=new HashSet<>();
+    for(Edge e:edges){frontier.add(e.from());break;}
+    while(true) {
+      Edge nearest = null;
+      for (Edge e : edges) {
+        if (!frontier.contains(e.from())) continue;
+        if (frontier.contains(e.to())) continue;
+        if (nearest == null || nearest.weight() > e.weight())
+          nearest = e;
+      }
+      if(nearest==null)break;
+      mst.add(nearest);
+      frontier.add(nearest.to());
+    }
+    return mst;
+  }
+
+  /// returns the tree of shortest paths from start to
+  /// all vertices  in the graph
+  ///
+  /// naive implementation without a prorityqueue
+  /// @param g      foo
+  /// @param start  foo
+  /// @return Set<Edge>
+  public static Set<Edge> dijkstra(Graph g, Vertex start){
+    // create table for done, prev and weight from start
+    int maxint =Integer.MAX_VALUE;
+    HashSet<Vertex> done=new HashSet<>();
+    HashMap<Vertex,Edge> prev=new HashMap<>();
+    HashMap<Vertex,Integer> weight=new HashMap<>();
+    for(Vertex w:g.vertices())weight.put(w,maxint);
+    // start node is done, distance 0 from start
+    weight.put(start,0);
+    done.add(start);
+
+    while(true){
+      // find nearest from a done vertex
+      Vertex nearest = null;
+      int neardist = maxint;
+      Edge done2near=null;
+      for(Vertex w1:done){
+        for (Edge e : g.outEdge(w1)) {
+          Vertex w2 = e.to();
+          if (done.contains(w2)) continue;
+          if ((weight.get(w1) + e.weight()) < neardist) {
+            nearest = e.to();
+            neardist = weight.get(w1) + e.weight();
+            done2near = e;
+          }
+        }
+      }
+      // System.out.println("find nearest "+done2near);
+      // if no more, then we are done
+      if (nearest == null) break;
+        // update distance from this node to other nodes
+      for (Edge e1 : g.outEdge(nearest)) {
+        Vertex w3 = e1.to();
+        int wght = e1.weight();
+        if (weight.get(w3) > (neardist + wght)) {
+          weight.put(w3, neardist + wght);
+        }
+      }
+      done.add(nearest);
+      prev.put(nearest,done2near);
+      weight.put(nearest,neardist);
+    }
+    return new HashSet<Edge>(prev.values());
+  }
+
+  //------------------------------------------------------------
+  //
+  //  IO operations
+
+  /// read a comma-separated file in the format
+  /// <vertex> , <vertex> , <weight>
+  ///
+  /// stores file as bidirectional graph
+  /// @param g     foo
+  /// @param file  foo
+  public static void readGraph(Graph g, String file) {
+    try{
+      BufferedReader in = new BufferedReader(new FileReader(file));
+      for(String line=in.readLine(); line!=null; line=in.readLine()) {
+        if(line.length()==0) continue;
+        String[] arr = line.split(",");
+        if(arr.length!=3) throw new RuntimeException("CSV file format error: "+line);
+        g.insertEdge(arr[0].trim(), arr[1].trim(), Integer.parseInt(arr[2].trim()));
+        g.insertEdge(arr[1].trim(), arr[0].trim(), Integer.parseInt(arr[2].trim()));
+      }
+      in.close();
+    }catch(IOException e){
+      throw new RuntimeException(e);
+    }
+  }
+
+  /// foo
+  /// @param g  foo
+  public static void printGraph(Graph g) {
+    for(Vertex v: sortVertex(g.vertices())) {
+      System.out.println(v.toString());
+      for(Edge e:sortEdgesTo(g.outEdge(v)))
+        System.out.println("  "+e.toString());
+    }
+  }
+
+  /// store a list of lines as a file
+  /// @param list  foo
+  /// @param f     foo
+  public static void storeStrings(List<String> list,String f){
+    try{
+      PrintWriter out=new PrintWriter(new FileWriter(f));
+      for(String s:list){
+        out.println(s);
+      }
+      out.close();
+    }catch(IOException e){
+      throw new RuntimeException(e);
+    }
+  }
+
+  /// read a file a returns a list of lines
+  /// @param f  foo
+  /// @return ArrayList
+  public static ArrayList<String> loadStrings(String f){
+    ArrayList<String> list=new ArrayList<>();
+    try{
+      BufferedReader in=new BufferedReader(new FileReader(f));
+      while(true){
+        String s=in.readLine();
+        if(s==null)break;
+        list.add(s);
+      }
+      in.close();
+    }catch(IOException e){
+      throw new RuntimeException(e);
+    }
+    return list;
+  }
+}
diff --git a/src/com.example.portfolio3/com/example/portfolio3/Graphs.java b/src/com.example.portfolio3/com/example/portfolio3/Graphs.java
new file mode 100644
index 0000000..2975e44
--- /dev/null
+++ b/src/com.example.portfolio3/com/example/portfolio3/Graphs.java
@@ -0,0 +1,13 @@
+package com.example.portfolio3;
+
+// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
+
+import java.util.*;
+
+/// foo
+public class Graphs {
+
+  /// foo
+  Graphs() {}
+
+}
diff --git a/src/com.example.portfolio3/com/example/portfolio3/MatrixGraph.java b/src/com.example.portfolio3/com/example/portfolio3/MatrixGraph.java
new file mode 100644
index 0000000..29005b7
--- /dev/null
+++ b/src/com.example.portfolio3/com/example/portfolio3/MatrixGraph.java
@@ -0,0 +1,77 @@
+package com.example.portfolio3;
+
+// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
+
+import java.util.*;
+
+///  Matrix Graph:  weights are stored in a twodimensional array
+public class MatrixGraph extends AbstractGraph {
+
+  /// foo
+  private Integer[][] matrix=null; // made in constructor
+
+  /// foo
+  // We must be able to map vertices to index in matrix and back again
+  private Vertex[] index2vertex; // made in constructor
+
+  /// foo
+  private Map<Vertex,Integer> vertex2index=new HashMap<>();
+
+  /// foo
+  private int numVertex; // maximum number of vertices
+
+  /// foo
+  /// @param numVertex  maximum number of vertices allowed
+  public MatrixGraph(int numVertex){
+    this.numVertex=numVertex;
+    matrix =new Integer[numVertex][numVertex];
+    index2vertex=new Vertex[numVertex];
+  }
+
+  /// foo
+  /// @param v  vertex
+  /// @return int
+  private int getIndex(Vertex v){
+    if(vertex2index.containsKey(v)) return vertex2index.get(v);
+    int index=vertex2index.size();
+    if(index>=index2vertex.length)throw new RuntimeException("Too many vertices in graph");
+    vertex2index.put(v,index);
+    index2vertex[index]=v;
+    return index;
+  }
+
+  /// foo
+  public void insertEdge(Vertex v1,Vertex v2,int w){
+    matrix[getIndex(v1)][getIndex(v2)] = w;
+  }
+
+  /// foo
+  public Collection<Edge> edges(){
+    HashSet<Edge> edges=new HashSet<>();
+    for(int i=0;i<numVertex;i++){
+      for(int j=0;j<numVertex;j++){
+        Integer weight=matrix[i][j]; // may be null
+        if(weight==null)continue;
+        edges.add(new Edge(index2vertex[i],index2vertex[j],weight));
+      }
+    }
+    return edges;
+  }
+
+  /// foo
+  public Collection<Edge> outEdge(Vertex v1){
+    HashSet<Edge> edges=new HashSet<>();
+    int i=vertex2index.get(v1);
+    for(int j=0;j<numVertex;j++){
+      Integer weight=matrix[i][j]; // may be null
+      if(weight==null)continue;
+      edges.add(new Edge(v1,index2vertex[j],weight));
+    }
+    return edges;
+  }
+
+  /// foo
+  public Integer getWeight(Vertex v1,Vertex v2){
+    // constant time operation
+    return matrix[vertex2index.get(v1)][vertex2index.get(v2)];}
+}
diff --git a/src/com.example.portfolio3/com/example/portfolio3/Vertex.java b/src/com.example.portfolio3/com/example/portfolio3/Vertex.java
new file mode 100644
index 0000000..9881159
--- /dev/null
+++ b/src/com.example.portfolio3/com/example/portfolio3/Vertex.java
@@ -0,0 +1,24 @@
+package com.example.portfolio3;
+
+// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
+
+import java.util.*;
+
+/// foo
+public class Vertex{
+
+  /// foo
+  private String name;
+
+  /// foo
+  /// @return String
+  public String name(){return name;}
+
+  /// foo
+  /// @param s  foo
+  public Vertex(String s){name=s;}
+
+  /// foo
+  /// @return String
+  public String toString(){return name;}
+}
diff --git a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Control.java b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Control.java
new file mode 100644
index 0000000..b53fb9f
--- /dev/null
+++ b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Control.java
@@ -0,0 +1,94 @@
+// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package dk.biks.bachelorizer;
+
+import java.util.List;
+
+import dk.biks.bachelorizer.model.GUI;
+import dk.biks.bachelorizer.view.Window;
+
+/// Bachelorizer - Controller
+public class Control{
+
+	/// Application model
+	// (declared explicitly only to silence javadoc)
+	private GUI model;
+
+	/// Application view
+	private Window view;
+
+	/// Parameters passed on command-line and in JNLP file
+	private List<String> parameters;
+
+	/// Default constructor
+	///
+	/// @param model  Application model
+	/// @param view   Application view
+	public Control(GUI model, Window view){
+		this.model = model;
+		this.view = view;
+	}
+
+	/// parse application parameters
+	///
+	/// parse parameters as GNU-style options and arguments,
+	/// i.e. treat dash-prefixed words as options
+	/// until an optional first bare "--",
+	/// taking first non-option argument as name of student
+	/// and remaining ones as activity selections
+	///
+	/// @param parameters  Application parameters
+	public void setParameters(List<String> parameters) {
+		boolean optionsDone = false;
+		boolean studentAssigned = false;
+		for (String item : parameters) {
+			if (!optionsDone && item.matches("--")) {
+				optionsDone = true;
+			} else if (!item.startsWith("-")) {
+				if (!studentAssigned) {
+					model.addStudent(item);
+					studentAssigned = true;
+					showStudent();
+				} else {
+					model.addActivity(item);
+					showActivities();
+				}
+			}
+		}
+	}
+
+	/// Enter activity
+	///
+	/// @param s  String entered
+	public void enterActivity(String s){
+		model.addActivity(s);
+		view.clearActivityEntry();
+		showActivities();
+	}
+
+	/// Display student
+	public void showStudent() {
+		view.setStudentName(model.getStudentName());
+	}
+
+	/// Display list of activity entries
+	public void showActivities() {
+		String toarea = "";
+		for (String t : model.getActivities())
+			toarea += t + "\n";
+		view.setArea(toarea);
+	}
+
+	/// drop last activity entry
+	public void delOne(){
+		model.delOneActivity();
+		showActivities();
+	}
+
+	/// drop all activity entries
+	public void delAll(){
+		model.delAllActivities();
+		showActivities();
+	}
+}
diff --git a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Main.java b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Main.java
new file mode 100644
index 0000000..2efd5b8
--- /dev/null
+++ b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Main.java
@@ -0,0 +1,90 @@
+// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package dk.biks.bachelorizer;
+
+import java.lang.UnsupportedOperationException;
+import java.util.Arrays;
+
+/* TODO
+import dk.biks.bachelorizer.view.Oneshot;
+import dk.biks.bachelorizer.view.Prompt;
+import dk.biks.bachelorizer.view.Pipe;
+import dk.biks.bachelorizer.view.Screen;
+*/
+import dk.biks.bachelorizer.view.Window;
+
+/// Bachelorizer - bachelor programme registrar
+///
+/// Tool for registering students
+/// for activities in their bachelor programme.
+///
+/// Runner class spawning an interactive or non-interactive application
+/// based on passed arguments
+///
+/// Multi-framework MVC structure inspired by project Криптоанализатор
+/// written by Александр Хмелев <akhmelev@gmail.com>.
+///
+/// * v0.0.1-draft
+///   * initial release, as part of delivery "Portfolio 1"
+///
+/// @version 0.0.1-draft
+/// @see <https://moodle.ruc.dk/mod/assign/view.php?id=523186>
+/// @see <https://github.com/demologin/CryptoAnalyzerLed>
+public class Main {
+
+	/// Default constructor
+	///
+	/// @param args  command-line arguments or default demo data
+	public Main(final String[] args) {
+
+		switch (uiFromArgs(args)) {
+			case "gui" -> { Window.main(args); }
+// TODO			case "tui" -> { Screen.main(args); }
+// TODO			case "cli" -> { Line.main(args); }
+			default -> {
+				throw new UnsupportedOperationException(
+					"Not yet implemented.");
+			}
+		}
+	}
+
+	/// JVM entry point
+	///
+	/// @param args  command-line arguments
+	public static void main(String[] args) {
+
+		// inject initial sample data unless passed as arguments
+		if ((args.length == 0)
+			|| (!Arrays.stream(args).anyMatch(
+				s -> s != null && !s.startsWith("-")))
+		) {
+			args = new String[] {
+				"Jonas Smedegaard",
+				"CS-SMC2",
+				"CS-SMC3",
+			};
+		}
+
+		new Main(args);
+	}
+
+	/// minimal argument parser to detect explicit UI choice
+	///
+	/// @param args  command-line arguments
+	/// @return      choice of UI as String
+	public static String uiFromArgs(String[] args) {
+		// TODO: make "cli" the default when implemented
+		String defaultUI = "gui";
+
+		for (String arg : args) {
+			if (arg.matches("--(gui|tui|cli)")) {
+				return (arg.length() == 2)
+					? defaultUI
+					: arg.substring(2);
+			}
+		}
+
+		return defaultUI;
+	}
+}
diff --git a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Combi.java b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Combi.java
new file mode 100644
index 0000000..371eb79
--- /dev/null
+++ b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Combi.java
@@ -0,0 +1,105 @@
+// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package dk.biks.bachelorizer.model;
+
+import java.util.Collection;
+import java.util.Set;
+
+import com.example.portfolio3.AdjListGraph;
+import com.example.portfolio3.Graph;
+import com.example.portfolio3.GraphAlgorithms;
+import com.example.portfolio3.MatrixGraph;
+import com.example.portfolio3.Vertex;
+
+/// Combi - static sample dataset of course combinations
+///
+/// Slurps and parses data from upstream-provided comma-separated file.
+///
+/// @version 0.0.1
+/// @see <https://moodle.ruc.dk/mod/assign/view.php?id=523186>
+public final class Combi {
+
+	/// data about combinations as a Graph
+	private Graph g;
+
+	/// Default constructor
+	///
+	/// @param path  path to data file
+	private Combi(final String path) {
+
+		// read into temporary graph to resolve vertice count
+		//
+		// use Adjacency List Representation:
+		//  * cheap to bootstrap (done once)
+		//  * simple to count vertices (done once): O(1)
+		Graph _g = new AdjListGraph();
+		GraphAlgorithms.readGraph(_g, path);
+		Integer _vertice_count = _g.vertices().size();
+
+		// read into final graph
+		//
+		// use Adjacency Matrix Representation:
+		//  * expensive to bootstrap (done once)
+		//    * simple to add edges but needs vertice count
+		//  * simple to get edges (done repeatedly): O(1)
+		//
+		// TODO: avoid reading and parsing file twice
+		Graph g = new MatrixGraph(_vertice_count);
+		GraphAlgorithms.readGraph(g, path);
+
+		// ensure the graph is connected
+		isConnected(g);
+
+		GraphAlgorithms.printGraph(g);
+
+		// release temporary variables for garbage collection
+		_g = null;
+		_vertice_count = null;
+	}
+
+	/// JVM entry point
+	///
+	/// @param args  command-line arguments
+	public static void main(final String[] args) {
+
+		// first argument, if provided, is the data file path;
+		// else use upstream named file in current directory.
+		String path = (args.length > 0)
+			? args[0]
+			: "combi.txt";
+
+		Combi combi = new Combi(path);
+	}
+
+	/// utility function to check that a graph is connected
+	///
+	/// If check fails, throw an unchecked exception,
+	/// since it occurs at runtime and is unrecoverable.
+	///
+	/// Time complexity of the operation is O(n²)
+	/// where n is the amount of vertices,
+	/// since visitDepthFirst() recurses out-edges of all vertices.
+	///
+	/// @param g  Graph to inspect
+	/// @throws IllegalArgumentException
+	/// https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html
+	public static void isConnected(Graph g) {
+
+		// collect all vertices in the graph
+		Collection<Vertex> c = g.vertices();
+
+		// pick a random vertice in the graph
+		Vertex v = g.vertices().iterator().next();
+
+		// collect the set of visitable vertices
+		Set<Vertex> visited = GraphAlgorithms.visitDepthFirst(
+			g, v);
+
+		// throw exception if not all vertices were visited
+		if (visited.size() != c.size()) {
+			throw new IllegalArgumentException(
+				"graph is not connected");
+		}
+	}
+}
diff --git a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/GUI.java b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/GUI.java
new file mode 100644
index 0000000..ca9bd86
--- /dev/null
+++ b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/GUI.java
@@ -0,0 +1,62 @@
+// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package dk.biks.bachelorizer.model;
+
+import java.util.ArrayList;
+
+import dk.biks.bachelorizer.model.Person;
+
+/// Bachelorizer - GUI model
+public class GUI{
+
+	/// Default constructor
+	// (declared explicitly only to silence javadoc)
+	public GUI(){
+	}
+
+	/// Activity list
+	private Person student;
+
+	/// Activity list
+	private ArrayList<String> list = new ArrayList<>();
+
+	/// Add student
+	///
+	/// @param name  Name of student
+	public void addStudent(String name){
+		student = new Person(name);
+	}
+
+	/// Get student name
+	///
+	/// @return  name of student
+	public String getStudentName(){
+		return student.name;
+	}
+
+	/// Add activity to list
+	///
+	/// @param s  Activity to add
+	public void addActivity(String s){
+		list.add(s);
+	}
+
+	/// Get list of activities
+	///
+	/// @return  activity list
+	public ArrayList<String> getActivities(){
+		return list;
+	}
+
+	/// Delete last activity from list
+	public void delOneActivity(){
+		if(list.size()>0)
+			list.remove(list.size()-1);
+	}
+
+	/// Delete all activities from list
+	public void delAllActivities(){
+		list.clear();
+	}
+}
diff --git a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Person.java b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Person.java
new file mode 100644
index 0000000..9edb7af
--- /dev/null
+++ b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Person.java
@@ -0,0 +1,18 @@
+// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package dk.biks.bachelorizer.model;
+
+/// Bachelorizer - Person model
+public class Person {
+
+	/// Person name
+	public String name;
+
+	/// Constructor
+	///
+	/// @param name  Name of person
+	public Person (String name) {
+		this.name = name;
+	}
+}
diff --git a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/view/Window.java b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/view/Window.java
new file mode 100644
index 0000000..c75e290
--- /dev/null
+++ b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/view/Window.java
@@ -0,0 +1,120 @@
+// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package dk.biks.bachelorizer.view;
+
+import java.util.List;
+import javafx.application.Application;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextArea;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+
+import dk.biks.bachelorizer.Control;
+import dk.biks.bachelorizer.model.GUI;
+
+/// Bachelorizer - JavaFX Window view
+// Class is final to forbid subclassing,
+// because object is passed to controller during instatiation
+public final class Window extends Application { // the View
+
+	/// Default constructor
+	// (declared explicitly only to silence javadoc)
+	public Window() {
+	}
+
+	/// Label styling
+	public static String LABEL_STYLE =
+		"-fx-font-weight: bold; -fx-font-size: 20;";
+
+	/// Application model
+	private GUI model = new GUI();
+
+	/// Application controller
+	private Control control = new Control(model, this);
+
+	/// Name of student
+	private TextField nameEntry = new TextField();
+
+	/// Text entry for adding an activity
+	private TextField activityEntry = new TextField();
+
+	/// Text area for activity entries
+	private TextArea area = new TextArea();
+
+	/// Button to delete one activity
+	private Button delOne = new Button("Delete one");
+
+	/// Button to delete all activities
+	private Button delAll = new Button("Delete all");
+
+	/// Application instantiation
+	///
+	/// @param args  application parameters
+	public static void main(String[] args) {
+		launch(args);
+	}
+
+	@Override
+	public void start(Stage stage) {
+
+		// pass application parameters to controller
+		control.setParameters(getParameters().getRaw());
+
+		// add listeners
+//		NameEntry.setOnAction(e -> control.enterName(
+//			activityEntry.getText()));
+		activityEntry.setOnAction(e -> control.enterActivity(
+			activityEntry.getText()));
+		delOne.setOnAction(e -> control.delOne());
+		delAll.setOnAction(e -> control.delAll());
+
+		// add buttons
+		VBox root = new VBox(10,
+			ourHBox("Student", nameEntry),
+			ourHBox("Add activity", activityEntry),
+			new HBox(10, delOne, delAll),
+			area);
+
+		// compose stage
+		Scene scene = new Scene(root, 500, 500);
+		stage.setTitle("JavaFX Demo");
+		stage.setScene(scene);
+		stage.show();
+	}
+
+	/// action to apply student name
+	///
+	/// @param s  Text to apply
+	public void setStudentName(String s) {
+		nameEntry.setText(s);
+	}
+
+	/// action to apply text to area
+	///
+	/// @param s  Text to apply
+	public void setArea(String s) {
+		area.setText(s);
+	}
+
+	/// Button action to clear field
+	public void clearActivityEntry() {
+		activityEntry.setText("");
+	}
+
+	/// Styled HBox with label and TextField
+	///
+	/// @param s  Label string
+	/// @param f  Text field
+	/// @return   HBox containing styled label and text field
+	public HBox ourHBox(String s, TextField f) {
+		Label label = new Label(s+":");
+		label.setStyle(LABEL_STYLE);
+
+		return new HBox(10, label, f);
+	}
+}
diff --git a/src/main/java/com.example.portfolio3/com/example/portfolio3/AbstractGraph.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/AbstractGraph.java
deleted file mode 100644
index c2cf433..0000000
--- a/src/main/java/com.example.portfolio3/com/example/portfolio3/AbstractGraph.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.example.portfolio3;
-
-// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
-
-import java.util.*;
-
-/// foo
-abstract class AbstractGraph implements Graph{
-
-  /// foo
-  AbstractGraph() {}
-
-  /// foo
-  private HashMap<String,Vertex> vertexMap=new HashMap<>();
-
-  /// foo
-  private HashSet<Vertex> vertexSet=new HashSet<>();
-
-  /// foo
-  /// @param s  foo
-  /// @return Vertex
-  public Vertex vertex(String s){
-    if(vertexMap.containsKey(s))return vertexMap.get(s);
-    Vertex v=new Vertex(s);
-    vertexMap.put(s,v);
-    vertexSet.add(v);
-    return v;
-  }
-
-  /// foo
-  public void insertEdge(String v, String u, int w){
-    insertEdge(vertex(v),vertex(u),w);
-  }
-
-  /// foo
-  public Collection<Vertex> vertices() { return vertexSet;  }
-
-  /// foo
-  /// @param v1  foo
-  /// @param v2  foo
-  /// @param w   foo
-  abstract public void insertEdge(Vertex v1, Vertex v2, int w);
-
-  /// foo
-  abstract public Collection<Edge> edges();
-
-  /// foo
-  abstract public Collection<Edge> outEdge(Vertex v);
-
-  /// foo
-  abstract public Integer getWeight(Vertex v1, Vertex v2);
-}
diff --git a/src/main/java/com.example.portfolio3/com/example/portfolio3/AdjListGraph.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/AdjListGraph.java
deleted file mode 100644
index a677d3e..0000000
--- a/src/main/java/com.example.portfolio3/com/example/portfolio3/AdjListGraph.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.example.portfolio3;
-
-// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
-
-import java.util.*;
-
-///  Adjecency List Graph - A map from vertices to set of outedges from the vertex
-public class AdjListGraph extends AbstractGraph {
-
-  /// foo
-  public AdjListGraph() {}
-
-  /// foo
-  private Map<Vertex,Set<Edge>> outEdge= new HashMap<>();
-
-  /// foo
-  public void insertEdge(Vertex v1,Vertex v2,int w){
-    Edge e=new Edge(v1,v2,w);
-    if(!outEdge.containsKey(e.from()))
-      outEdge.put(e.from(),new HashSet<Edge>());
-    outEdge.get(e.from()).add(e);
-  }
-
-  /// foo
-  public Collection<Edge> edges(){
-    Set<Edge> edges=new HashSet<>();
-    for(Vertex v:outEdge.keySet())edges.addAll(outEdge.get(v));
-    return edges;
-  }
-
-  /// foo
-  public Collection<Edge> outEdge(Vertex v){
-    if(!outEdge.containsKey(v))
-      return new HashSet<Edge>();
-    return outEdge.get(v);
-  }
-
-  /// foo
-  public Integer getWeight(Vertex v1,Vertex v2){
-    // linear in number of outedges from vertices
-    if(!outEdge.containsKey(v1))return null;
-    for(Edge e:outEdge.get(v1)){
-      if(e.to()==v2)return e.weight();
-    }
-    return null;
-  }
-}
diff --git a/src/main/java/com.example.portfolio3/com/example/portfolio3/AdjMapGraph.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/AdjMapGraph.java
deleted file mode 100644
index 85e5d04..0000000
--- a/src/main/java/com.example.portfolio3/com/example/portfolio3/AdjMapGraph.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.example.portfolio3;
-
-// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
-
-import java.util.*;
-
-///  Adjecency Map Graph - A map from vertices to map of target vertex to edge
-class AdjMapGraph extends AbstractGraph {
-
-  /// foo
-  AdjMapGraph() {}
-
-  /// foo
-  private Map<Vertex, Map<Vertex, Edge>> outEdge = new HashMap<>();
-
-  /// foo
-  public void insertEdge(Vertex v1, Vertex v2, int w) {
-    Edge e = new Edge(v1,v2, w);
-    if (!outEdge.containsKey(e.from()))
-      outEdge.put(e.from(), new HashMap<Vertex, Edge>());
-    outEdge.get(e.from()).put(e.to(), e);
-  }
-
-  /// foo
-  public Collection<Edge> edges() {
-    Set<Edge> edges = new HashSet<>();
-    for (Vertex v : outEdge.keySet())
-      for (Vertex w : outEdge.get(v).keySet())
-        edges.add(outEdge.get(v).get(w));
-    return edges;
-  }
-
-  /// foo
-  public Collection<Edge> outEdge(Vertex v) {
-    return outEdge.get(v).values();
-  }
-
-  /// foo
-  public Integer getWeight(Vertex v1, Vertex v2) {
-    // constant time operation
-    if(!outEdge.containsKey(v1))return null;
-    if(!outEdge.get(v1).containsKey(v2))return null;
-    return outEdge.get(v1).get(v2).weight();
-  }
-}
diff --git a/src/main/java/com.example.portfolio3/com/example/portfolio3/Edge.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/Edge.java
deleted file mode 100644
index abc3c72..0000000
--- a/src/main/java/com.example.portfolio3/com/example/portfolio3/Edge.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.example.portfolio3;
-
-// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
-
-import java.util.*;
-
-/// foo
-class Edge{
-
-  /// foo
-  private Vertex from,to;
-
-  /// foo
-  private int weight;
-
-  /// foo
-  /// @return Vertex
-  public Vertex from(){return from;}
-
-  /// foo
-  /// @return Vertex
-  public Vertex to(){return to;}
-
-  /// foo
-  /// @return int
-  public int weight(){return weight;}
-
-  /// foo
-  /// @param from  foo
-  /// @param to    foo
-  /// @param w     foo
-  Edge(Vertex from,Vertex to,int w){this.from=from; this.to=to; weight=w;}
-
-  /// foo
-  /// @return String
-  public String toString(){return from.name()+" - "+weight+" -> "+to.name(); }
-}
diff --git a/src/main/java/com.example.portfolio3/com/example/portfolio3/EdgeGraph.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/EdgeGraph.java
deleted file mode 100644
index ae9cbe9..0000000
--- a/src/main/java/com.example.portfolio3/com/example/portfolio3/EdgeGraph.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.example.portfolio3;
-
-// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
-
-/// EdgeGraph - One big set of all edges in the graph
-class EdgeGraph extends AbstractGraph {
-
-  /// foo
-  EdgeGraph() {}
-
-  /// foo
-  Set<Edge> edges=new HashSet<>();
-
-  /// foo
-  public void insertEdge(Vertex v1,Vertex v2,int w){
-    edges.add(new Edge(v1,v2,w));
-  }
-
-  /// foo
-  public Collection<Edge> edges(){return edges;}
-
-  /// foo
-  public Collection<Edge> outEdge(Vertex v){
-    ArrayList<Edge> outEdge=new ArrayList<>();
-    for(Edge e:edges)if(e.from()==v)outEdge.add(e);
-    return outEdge;
-  }
-
-  /// foo
-  public Integer getWeight(Vertex v1,Vertex v2){
-    // linear in number of edges in the graph
-    for(Edge e:edges){
-      if(e.from()==v1 && e.to()==v2)return e.weight();
-    }
-    return null;
-  }
-}
diff --git a/src/main/java/com.example.portfolio3/com/example/portfolio3/Graph.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/Graph.java
deleted file mode 100644
index 6e58029..0000000
--- a/src/main/java/com.example.portfolio3/com/example/portfolio3/Graph.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.example.portfolio3;
-
-// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
-
-import java.util.*;
-
-/// foo
-public interface Graph {
-
-  /// foo
-  /// @param v  foo
-  /// @param u  foo
-  /// @param w  foo
-  void insertEdge(String v, String u, int w);
-
-  /// foo
-  /// @return Collection
-  Collection<Vertex> vertices();
-
-  /// foo
-  /// @return Collection
-  Collection<Edge> edges();
-
-  /// foo
-  /// @param v  foo
-  /// @return Collection
-  Collection<Edge> outEdge(Vertex v);
-
-  /// foo
-  /// @param v1  foo
-  /// @param v2  foo
-  /// @return Integer
-  Integer getWeight(Vertex v1, Vertex v2);
-}
diff --git a/src/main/java/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java
deleted file mode 100644
index 3be7c70..0000000
--- a/src/main/java/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java
+++ /dev/null
@@ -1,331 +0,0 @@
-package com.example.portfolio3;
-
-// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
-
-import java.io.*;
-import java.util.*;
-
-/// foo
-public class GraphAlgorithms {
-
-  /// foo
-  GraphAlgorithms() {}
-
-  /// Calculates the length of a path or any other collection of edes
-  ///
-  /// does not require the edges to form a path
-  /// @param edges  foo
-  /// @return int
-  public static int pathLength(Collection<Edge> edges){
-    return edges.stream().mapToInt(e-> e.weight()).sum();
-  }
-
-  /// checks whether a list of edges form a path so that
-  ///
-  /// the to-vertex in one edge is the from-vertex of the next
-  /// @param edges  foo
-  /// @return boolean
-  public static boolean isPath(List<Edge> edges){
-    for(int i=1;i<edges.size();i++){
-      if(edges.get(i-1).to()!=edges.get(i).from())return false;
-    }
-    return true;
-  }
-
-  ///Calculates the length of a path vertices in a graph
-  ///
-  /// return null if vertices are not connected as a path
-  /// @param g     foo
-  /// @param path  foo
-  /// @return Integer
-  public static Integer pathLength(Graph g,List<Vertex> path){
-    int length=0;
-    for(int i=1;i<path.size();i++){
-      Integer w=g.getWeight(path.get(i-1),path.get(i));
-      if(w==null)return null;
-      length+=w;
-    }
-    return length;
-  }
-
-  //------------------------------------------------------------
-  //
-  //  Comparators and sorting methods
-
-  /// Comparator of edges based on weight
-  ///
-  /// can be used for sorting a list of edges
-  /// @param e1  foo
-  /// @param e2  foo
-  /// @return int
-  static int cmpEdgeWeight(Edge e1,Edge e2) {
-    int w1=e1.weight(),w2=e2.weight();
-    if(w1!=w2)return w1-w2;
-    if(e1.from()!=e2.from())return e1.from().name().compareTo(e2.from().name());
-    return e1.to().name().compareTo(e2.to().name());
-  }
-
-  /// Comparator of edges based on from-vertex
-  ///
-  /// can be used for sorting a list of edges
-  /// @param e1  foo
-  /// @param e2  foo
-  /// @return int
-  static int cmpEdgeFrom(Edge e1,Edge e2) {
-    if(e1.from()!=e2.from())return e1.from().name().compareTo(e2.from().name());
-    int w1=e1.weight(),w2=e2.weight();
-    if(w1!=w2)return w1-w2;
-    return e1.to().name().compareTo(e2.to().name());
-  }
-
-  /// Comparator of edges based on from-vertex
-  ///
-  /// can be used for sorting a list of edges
-  /// @param e1  foo
-  /// @param e2  foo
-  /// @return int
-  static int cmpEdgeTo(Edge e1,Edge e2) {
-    if(e1.to()!=e2.to())return e1.to().name().compareTo(e2.to().name());
-    if(e1.from()!=e2.from())return e1.from().name().compareTo(e2.from().name());
-    int w1=e1.weight(),w2=e2.weight();
-    return w1-w2;
-  }
-
-  /// sort a collection of edges based on their weights
-  /// @param edges  foo
-  /// @return List<Edge>
-  static List<Edge> sortEdges(Collection<Edge> edges){
-    ArrayList<Edge> list=new ArrayList<>(edges);
-    Collections.sort(list,GraphAlgorithms::cmpEdgeWeight);
-    return list;
-  }
-
-  /// sort a collection of edges based on from-vertex
-  /// @param edges  foo
-  /// @return List<Edge>
-  static List<Edge> sortEdgesFrom(Collection<Edge> edges){
-    ArrayList<Edge> list=new ArrayList<>(edges);
-    Collections.sort(list,GraphAlgorithms::cmpEdgeFrom);
-    return list;
-  }
-
-  /// sort a collection of edges based on to-vertex
-  /// @param edges  foo
-  /// @return List<Edge>
-  static List<Edge> sortEdgesTo(Collection<Edge> edges){
-    ArrayList<Edge> list=new ArrayList<>(edges);
-    Collections.sort(list,GraphAlgorithms::cmpEdgeTo);
-    return list;
-  }
-
-  /// sort a collection of vertices based on their name
-  /// @param vertices  foo
-  /// @return List<Vertex>
-  static List<Vertex> sortVertex(Collection<Vertex> vertices){
-    ArrayList<Vertex> list=new ArrayList<>(vertices);
-    Collections.sort(list,(Vertex v1,Vertex v2)-> v1.name().compareTo(v2.name()));
-    return list;
-  }
-
-  //------------------------------------------------------------
-  //
-  //  Algorithms for traverse and minimum spanning tree
-
-  /// traverse a graph depth first from a given vertex
-  /// return the set of visited vertices
-  /// @param g  foo
-  /// @param v  foo
-  /// @return Set<Vertex>
-  public static Set<Vertex> visitBreadthFirst(Graph g,Vertex v){
-    HashSet<Vertex> thisLevel=new HashSet<>();
-    HashSet<Vertex> nextLevel=new HashSet<>();
-    HashSet<Vertex> visited=new HashSet<>();
-    thisLevel.add(v);
-    while(thisLevel.size()>0){
-      System.out.println("level "+thisLevel);
-      for(Vertex w:thisLevel){
-        //System.out.println("visited "+w);
-        visited.add(w);
-        Collection<Edge> outedge=g.outEdge(w);
-        if(outedge==null)continue;
-        for(Edge e: outedge){
-          if(visited.contains(e.to()))continue;
-          if(thisLevel.contains(e.to()))continue;
-          nextLevel.add(e.to());
-        }
-      }
-      thisLevel=nextLevel;
-      nextLevel=new HashSet<Vertex>();
-    }
-    return visited;
-  }
-
-  /// traverse a graph depth first from a given vertex
-  /// return the set of visited vertices
-  /// @param g  foo
-  /// @param v  foo
-  /// @return Set<Vertex>
-  public static Set<Vertex> visitDepthFirst(Graph g,Vertex v){
-    HashSet<Vertex> visit=new HashSet<>();
-    visitDepthFirst(g, v,visit);
-    return visit;
-  }
-
-  /// foo
-  /// @param g        foo
-  /// @param v        foo
-  /// @param visited  foo
-  private static void visitDepthFirst(Graph g,Vertex v,Set<Vertex> visited){
-    if(visited.contains(v))return;
-    //System.out.println("visited "+v);
-    visited.add(v);
-    for(Edge e: g.outEdge(v))
-      visitDepthFirst(g,e.to(),visited);
-  }
-
-  /// an implementation of Prim's algorithm
-  /// naive implementation without priorityqueue
-  /// @param g  foo
-  /// @return Set<Edge>
-  public static Set<Edge> minimumSpanningTree(Graph g){
-    Collection<Edge> edges=g.edges();
-    HashSet<Edge> mst=new HashSet<>();
-    HashSet<Vertex> frontier=new HashSet<>();
-    for(Edge e:edges){frontier.add(e.from());break;}
-    while(true) {
-      Edge nearest = null;
-      for (Edge e : edges) {
-        if (!frontier.contains(e.from())) continue;
-        if (frontier.contains(e.to())) continue;
-        if (nearest == null || nearest.weight() > e.weight())
-          nearest = e;
-      }
-      if(nearest==null)break;
-      mst.add(nearest);
-      frontier.add(nearest.to());
-    }
-    return mst;
-  }
-
-  /// returns the tree of shortest paths from start to
-  /// all vertices  in the graph
-  ///
-  /// naive implementation without a prorityqueue
-  /// @param g      foo
-  /// @param start  foo
-  /// @return Set<Edge>
-  public static Set<Edge> dijkstra(Graph g, Vertex start){
-    // create table for done, prev and weight from start
-    int maxint =Integer.MAX_VALUE;
-    HashSet<Vertex> done=new HashSet<>();
-    HashMap<Vertex,Edge> prev=new HashMap<>();
-    HashMap<Vertex,Integer> weight=new HashMap<>();
-    for(Vertex w:g.vertices())weight.put(w,maxint);
-    // start node is done, distance 0 from start
-    weight.put(start,0);
-    done.add(start);
-
-    while(true){
-      // find nearest from a done vertex
-      Vertex nearest = null;
-      int neardist = maxint;
-      Edge done2near=null;
-      for(Vertex w1:done){
-        for (Edge e : g.outEdge(w1)) {
-          Vertex w2 = e.to();
-          if (done.contains(w2)) continue;
-          if ((weight.get(w1) + e.weight()) < neardist) {
-            nearest = e.to();
-            neardist = weight.get(w1) + e.weight();
-            done2near = e;
-          }
-        }
-      }
-      // System.out.println("find nearest "+done2near);
-      // if no more, then we are done
-      if (nearest == null) break;
-        // update distance from this node to other nodes
-      for (Edge e1 : g.outEdge(nearest)) {
-        Vertex w3 = e1.to();
-        int wght = e1.weight();
-        if (weight.get(w3) > (neardist + wght)) {
-          weight.put(w3, neardist + wght);
-        }
-      }
-      done.add(nearest);
-      prev.put(nearest,done2near);
-      weight.put(nearest,neardist);
-    }
-    return new HashSet<Edge>(prev.values());
-  }
-
-  //------------------------------------------------------------
-  //
-  //  IO operations
-
-  /// read a comma-separated file in the format
-  /// <vertex> , <vertex> , <weight>
-  ///
-  /// stores file as bidirectional graph
-  /// @param g     foo
-  /// @param file  foo
-  public static void readGraph(Graph g, String file) {
-    try{
-      BufferedReader in = new BufferedReader(new FileReader(file));
-      for(String line=in.readLine(); line!=null; line=in.readLine()) {
-        if(line.length()==0) continue;
-        String[] arr = line.split(",");
-        if(arr.length!=3) throw new RuntimeException("CSV file format error: "+line);
-        g.insertEdge(arr[0].trim(), arr[1].trim(), Integer.parseInt(arr[2].trim()));
-        g.insertEdge(arr[1].trim(), arr[0].trim(), Integer.parseInt(arr[2].trim()));
-      }
-      in.close();
-    }catch(IOException e){
-      throw new RuntimeException(e);
-    }
-  }
-
-  /// foo
-  /// @param g  foo
-  public static void printGraph(Graph g) {
-    for(Vertex v: sortVertex(g.vertices())) {
-      System.out.println(v.toString());
-      for(Edge e:sortEdgesTo(g.outEdge(v)))
-        System.out.println("  "+e.toString());
-    }
-  }
-
-  /// store a list of lines as a file
-  /// @param list  foo
-  /// @param f     foo
-  public static void storeStrings(List<String> list,String f){
-    try{
-      PrintWriter out=new PrintWriter(new FileWriter(f));
-      for(String s:list){
-        out.println(s);
-      }
-      out.close();
-    }catch(IOException e){
-      throw new RuntimeException(e);
-    }
-  }
-
-  /// read a file a returns a list of lines
-  /// @param f  foo
-  /// @return ArrayList
-  public static ArrayList<String> loadStrings(String f){
-    ArrayList<String> list=new ArrayList<>();
-    try{
-      BufferedReader in=new BufferedReader(new FileReader(f));
-      while(true){
-        String s=in.readLine();
-        if(s==null)break;
-        list.add(s);
-      }
-      in.close();
-    }catch(IOException e){
-      throw new RuntimeException(e);
-    }
-    return list;
-  }
-}
diff --git a/src/main/java/com.example.portfolio3/com/example/portfolio3/Graphs.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/Graphs.java
deleted file mode 100644
index 2975e44..0000000
--- a/src/main/java/com.example.portfolio3/com/example/portfolio3/Graphs.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.example.portfolio3;
-
-// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
-
-import java.util.*;
-
-/// foo
-public class Graphs {
-
-  /// foo
-  Graphs() {}
-
-}
diff --git a/src/main/java/com.example.portfolio3/com/example/portfolio3/MatrixGraph.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/MatrixGraph.java
deleted file mode 100644
index 29005b7..0000000
--- a/src/main/java/com.example.portfolio3/com/example/portfolio3/MatrixGraph.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.example.portfolio3;
-
-// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
-
-import java.util.*;
-
-///  Matrix Graph:  weights are stored in a twodimensional array
-public class MatrixGraph extends AbstractGraph {
-
-  /// foo
-  private Integer[][] matrix=null; // made in constructor
-
-  /// foo
-  // We must be able to map vertices to index in matrix and back again
-  private Vertex[] index2vertex; // made in constructor
-
-  /// foo
-  private Map<Vertex,Integer> vertex2index=new HashMap<>();
-
-  /// foo
-  private int numVertex; // maximum number of vertices
-
-  /// foo
-  /// @param numVertex  maximum number of vertices allowed
-  public MatrixGraph(int numVertex){
-    this.numVertex=numVertex;
-    matrix =new Integer[numVertex][numVertex];
-    index2vertex=new Vertex[numVertex];
-  }
-
-  /// foo
-  /// @param v  vertex
-  /// @return int
-  private int getIndex(Vertex v){
-    if(vertex2index.containsKey(v)) return vertex2index.get(v);
-    int index=vertex2index.size();
-    if(index>=index2vertex.length)throw new RuntimeException("Too many vertices in graph");
-    vertex2index.put(v,index);
-    index2vertex[index]=v;
-    return index;
-  }
-
-  /// foo
-  public void insertEdge(Vertex v1,Vertex v2,int w){
-    matrix[getIndex(v1)][getIndex(v2)] = w;
-  }
-
-  /// foo
-  public Collection<Edge> edges(){
-    HashSet<Edge> edges=new HashSet<>();
-    for(int i=0;i<numVertex;i++){
-      for(int j=0;j<numVertex;j++){
-        Integer weight=matrix[i][j]; // may be null
-        if(weight==null)continue;
-        edges.add(new Edge(index2vertex[i],index2vertex[j],weight));
-      }
-    }
-    return edges;
-  }
-
-  /// foo
-  public Collection<Edge> outEdge(Vertex v1){
-    HashSet<Edge> edges=new HashSet<>();
-    int i=vertex2index.get(v1);
-    for(int j=0;j<numVertex;j++){
-      Integer weight=matrix[i][j]; // may be null
-      if(weight==null)continue;
-      edges.add(new Edge(v1,index2vertex[j],weight));
-    }
-    return edges;
-  }
-
-  /// foo
-  public Integer getWeight(Vertex v1,Vertex v2){
-    // constant time operation
-    return matrix[vertex2index.get(v1)][vertex2index.get(v2)];}
-}
diff --git a/src/main/java/com.example.portfolio3/com/example/portfolio3/Vertex.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/Vertex.java
deleted file mode 100644
index 9881159..0000000
--- a/src/main/java/com.example.portfolio3/com/example/portfolio3/Vertex.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.example.portfolio3;
-
-// origin: <https://moodle.ruc.dk/course/section.php?id=211877>
-
-import java.util.*;
-
-/// foo
-public class Vertex{
-
-  /// foo
-  private String name;
-
-  /// foo
-  /// @return String
-  public String name(){return name;}
-
-  /// foo
-  /// @param s  foo
-  public Vertex(String s){name=s;}
-
-  /// foo
-  /// @return String
-  public String toString(){return name;}
-}
diff --git a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Control.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Control.java
deleted file mode 100644
index b53fb9f..0000000
--- a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Control.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package dk.biks.bachelorizer;
-
-import java.util.List;
-
-import dk.biks.bachelorizer.model.GUI;
-import dk.biks.bachelorizer.view.Window;
-
-/// Bachelorizer - Controller
-public class Control{
-
-	/// Application model
-	// (declared explicitly only to silence javadoc)
-	private GUI model;
-
-	/// Application view
-	private Window view;
-
-	/// Parameters passed on command-line and in JNLP file
-	private List<String> parameters;
-
-	/// Default constructor
-	///
-	/// @param model  Application model
-	/// @param view   Application view
-	public Control(GUI model, Window view){
-		this.model = model;
-		this.view = view;
-	}
-
-	/// parse application parameters
-	///
-	/// parse parameters as GNU-style options and arguments,
-	/// i.e. treat dash-prefixed words as options
-	/// until an optional first bare "--",
-	/// taking first non-option argument as name of student
-	/// and remaining ones as activity selections
-	///
-	/// @param parameters  Application parameters
-	public void setParameters(List<String> parameters) {
-		boolean optionsDone = false;
-		boolean studentAssigned = false;
-		for (String item : parameters) {
-			if (!optionsDone && item.matches("--")) {
-				optionsDone = true;
-			} else if (!item.startsWith("-")) {
-				if (!studentAssigned) {
-					model.addStudent(item);
-					studentAssigned = true;
-					showStudent();
-				} else {
-					model.addActivity(item);
-					showActivities();
-				}
-			}
-		}
-	}
-
-	/// Enter activity
-	///
-	/// @param s  String entered
-	public void enterActivity(String s){
-		model.addActivity(s);
-		view.clearActivityEntry();
-		showActivities();
-	}
-
-	/// Display student
-	public void showStudent() {
-		view.setStudentName(model.getStudentName());
-	}
-
-	/// Display list of activity entries
-	public void showActivities() {
-		String toarea = "";
-		for (String t : model.getActivities())
-			toarea += t + "\n";
-		view.setArea(toarea);
-	}
-
-	/// drop last activity entry
-	public void delOne(){
-		model.delOneActivity();
-		showActivities();
-	}
-
-	/// drop all activity entries
-	public void delAll(){
-		model.delAllActivities();
-		showActivities();
-	}
-}
diff --git a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Main.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Main.java
deleted file mode 100644
index 2efd5b8..0000000
--- a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Main.java
+++ /dev/null
@@ -1,90 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package dk.biks.bachelorizer;
-
-import java.lang.UnsupportedOperationException;
-import java.util.Arrays;
-
-/* TODO
-import dk.biks.bachelorizer.view.Oneshot;
-import dk.biks.bachelorizer.view.Prompt;
-import dk.biks.bachelorizer.view.Pipe;
-import dk.biks.bachelorizer.view.Screen;
-*/
-import dk.biks.bachelorizer.view.Window;
-
-/// Bachelorizer - bachelor programme registrar
-///
-/// Tool for registering students
-/// for activities in their bachelor programme.
-///
-/// Runner class spawning an interactive or non-interactive application
-/// based on passed arguments
-///
-/// Multi-framework MVC structure inspired by project Криптоанализатор
-/// written by Александр Хмелев <akhmelev@gmail.com>.
-///
-/// * v0.0.1-draft
-///   * initial release, as part of delivery "Portfolio 1"
-///
-/// @version 0.0.1-draft
-/// @see <https://moodle.ruc.dk/mod/assign/view.php?id=523186>
-/// @see <https://github.com/demologin/CryptoAnalyzerLed>
-public class Main {
-
-	/// Default constructor
-	///
-	/// @param args  command-line arguments or default demo data
-	public Main(final String[] args) {
-
-		switch (uiFromArgs(args)) {
-			case "gui" -> { Window.main(args); }
-// TODO			case "tui" -> { Screen.main(args); }
-// TODO			case "cli" -> { Line.main(args); }
-			default -> {
-				throw new UnsupportedOperationException(
-					"Not yet implemented.");
-			}
-		}
-	}
-
-	/// JVM entry point
-	///
-	/// @param args  command-line arguments
-	public static void main(String[] args) {
-
-		// inject initial sample data unless passed as arguments
-		if ((args.length == 0)
-			|| (!Arrays.stream(args).anyMatch(
-				s -> s != null && !s.startsWith("-")))
-		) {
-			args = new String[] {
-				"Jonas Smedegaard",
-				"CS-SMC2",
-				"CS-SMC3",
-			};
-		}
-
-		new Main(args);
-	}
-
-	/// minimal argument parser to detect explicit UI choice
-	///
-	/// @param args  command-line arguments
-	/// @return      choice of UI as String
-	public static String uiFromArgs(String[] args) {
-		// TODO: make "cli" the default when implemented
-		String defaultUI = "gui";
-
-		for (String arg : args) {
-			if (arg.matches("--(gui|tui|cli)")) {
-				return (arg.length() == 2)
-					? defaultUI
-					: arg.substring(2);
-			}
-		}
-
-		return defaultUI;
-	}
-}
diff --git a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Combi.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Combi.java
deleted file mode 100644
index 371eb79..0000000
--- a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Combi.java
+++ /dev/null
@@ -1,105 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package dk.biks.bachelorizer.model;
-
-import java.util.Collection;
-import java.util.Set;
-
-import com.example.portfolio3.AdjListGraph;
-import com.example.portfolio3.Graph;
-import com.example.portfolio3.GraphAlgorithms;
-import com.example.portfolio3.MatrixGraph;
-import com.example.portfolio3.Vertex;
-
-/// Combi - static sample dataset of course combinations
-///
-/// Slurps and parses data from upstream-provided comma-separated file.
-///
-/// @version 0.0.1
-/// @see <https://moodle.ruc.dk/mod/assign/view.php?id=523186>
-public final class Combi {
-
-	/// data about combinations as a Graph
-	private Graph g;
-
-	/// Default constructor
-	///
-	/// @param path  path to data file
-	private Combi(final String path) {
-
-		// read into temporary graph to resolve vertice count
-		//
-		// use Adjacency List Representation:
-		//  * cheap to bootstrap (done once)
-		//  * simple to count vertices (done once): O(1)
-		Graph _g = new AdjListGraph();
-		GraphAlgorithms.readGraph(_g, path);
-		Integer _vertice_count = _g.vertices().size();
-
-		// read into final graph
-		//
-		// use Adjacency Matrix Representation:
-		//  * expensive to bootstrap (done once)
-		//    * simple to add edges but needs vertice count
-		//  * simple to get edges (done repeatedly): O(1)
-		//
-		// TODO: avoid reading and parsing file twice
-		Graph g = new MatrixGraph(_vertice_count);
-		GraphAlgorithms.readGraph(g, path);
-
-		// ensure the graph is connected
-		isConnected(g);
-
-		GraphAlgorithms.printGraph(g);
-
-		// release temporary variables for garbage collection
-		_g = null;
-		_vertice_count = null;
-	}
-
-	/// JVM entry point
-	///
-	/// @param args  command-line arguments
-	public static void main(final String[] args) {
-
-		// first argument, if provided, is the data file path;
-		// else use upstream named file in current directory.
-		String path = (args.length > 0)
-			? args[0]
-			: "combi.txt";
-
-		Combi combi = new Combi(path);
-	}
-
-	/// utility function to check that a graph is connected
-	///
-	/// If check fails, throw an unchecked exception,
-	/// since it occurs at runtime and is unrecoverable.
-	///
-	/// Time complexity of the operation is O(n²)
-	/// where n is the amount of vertices,
-	/// since visitDepthFirst() recurses out-edges of all vertices.
-	///
-	/// @param g  Graph to inspect
-	/// @throws IllegalArgumentException
-	/// https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html
-	public static void isConnected(Graph g) {
-
-		// collect all vertices in the graph
-		Collection<Vertex> c = g.vertices();
-
-		// pick a random vertice in the graph
-		Vertex v = g.vertices().iterator().next();
-
-		// collect the set of visitable vertices
-		Set<Vertex> visited = GraphAlgorithms.visitDepthFirst(
-			g, v);
-
-		// throw exception if not all vertices were visited
-		if (visited.size() != c.size()) {
-			throw new IllegalArgumentException(
-				"graph is not connected");
-		}
-	}
-}
diff --git a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/GUI.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/GUI.java
deleted file mode 100644
index ca9bd86..0000000
--- a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/GUI.java
+++ /dev/null
@@ -1,62 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package dk.biks.bachelorizer.model;
-
-import java.util.ArrayList;
-
-import dk.biks.bachelorizer.model.Person;
-
-/// Bachelorizer - GUI model
-public class GUI{
-
-	/// Default constructor
-	// (declared explicitly only to silence javadoc)
-	public GUI(){
-	}
-
-	/// Activity list
-	private Person student;
-
-	/// Activity list
-	private ArrayList<String> list = new ArrayList<>();
-
-	/// Add student
-	///
-	/// @param name  Name of student
-	public void addStudent(String name){
-		student = new Person(name);
-	}
-
-	/// Get student name
-	///
-	/// @return  name of student
-	public String getStudentName(){
-		return student.name;
-	}
-
-	/// Add activity to list
-	///
-	/// @param s  Activity to add
-	public void addActivity(String s){
-		list.add(s);
-	}
-
-	/// Get list of activities
-	///
-	/// @return  activity list
-	public ArrayList<String> getActivities(){
-		return list;
-	}
-
-	/// Delete last activity from list
-	public void delOneActivity(){
-		if(list.size()>0)
-			list.remove(list.size()-1);
-	}
-
-	/// Delete all activities from list
-	public void delAllActivities(){
-		list.clear();
-	}
-}
diff --git a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Person.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Person.java
deleted file mode 100644
index 9edb7af..0000000
--- a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Person.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package dk.biks.bachelorizer.model;
-
-/// Bachelorizer - Person model
-public class Person {
-
-	/// Person name
-	public String name;
-
-	/// Constructor
-	///
-	/// @param name  Name of person
-	public Person (String name) {
-		this.name = name;
-	}
-}
diff --git a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/view/Window.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/view/Window.java
deleted file mode 100644
index c75e290..0000000
--- a/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/view/Window.java
+++ /dev/null
@@ -1,120 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package dk.biks.bachelorizer.view;
-
-import java.util.List;
-import javafx.application.Application;
-import javafx.scene.control.Button;
-import javafx.scene.control.Label;
-import javafx.scene.control.TextArea;
-import javafx.scene.control.TextField;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.VBox;
-import javafx.scene.Scene;
-import javafx.stage.Stage;
-
-import dk.biks.bachelorizer.Control;
-import dk.biks.bachelorizer.model.GUI;
-
-/// Bachelorizer - JavaFX Window view
-// Class is final to forbid subclassing,
-// because object is passed to controller during instatiation
-public final class Window extends Application { // the View
-
-	/// Default constructor
-	// (declared explicitly only to silence javadoc)
-	public Window() {
-	}
-
-	/// Label styling
-	public static String LABEL_STYLE =
-		"-fx-font-weight: bold; -fx-font-size: 20;";
-
-	/// Application model
-	private GUI model = new GUI();
-
-	/// Application controller
-	private Control control = new Control(model, this);
-
-	/// Name of student
-	private TextField nameEntry = new TextField();
-
-	/// Text entry for adding an activity
-	private TextField activityEntry = new TextField();
-
-	/// Text area for activity entries
-	private TextArea area = new TextArea();
-
-	/// Button to delete one activity
-	private Button delOne = new Button("Delete one");
-
-	/// Button to delete all activities
-	private Button delAll = new Button("Delete all");
-
-	/// Application instantiation
-	///
-	/// @param args  application parameters
-	public static void main(String[] args) {
-		launch(args);
-	}
-
-	@Override
-	public void start(Stage stage) {
-
-		// pass application parameters to controller
-		control.setParameters(getParameters().getRaw());
-
-		// add listeners
-//		NameEntry.setOnAction(e -> control.enterName(
-//			activityEntry.getText()));
-		activityEntry.setOnAction(e -> control.enterActivity(
-			activityEntry.getText()));
-		delOne.setOnAction(e -> control.delOne());
-		delAll.setOnAction(e -> control.delAll());
-
-		// add buttons
-		VBox root = new VBox(10,
-			ourHBox("Student", nameEntry),
-			ourHBox("Add activity", activityEntry),
-			new HBox(10, delOne, delAll),
-			area);
-
-		// compose stage
-		Scene scene = new Scene(root, 500, 500);
-		stage.setTitle("JavaFX Demo");
-		stage.setScene(scene);
-		stage.show();
-	}
-
-	/// action to apply student name
-	///
-	/// @param s  Text to apply
-	public void setStudentName(String s) {
-		nameEntry.setText(s);
-	}
-
-	/// action to apply text to area
-	///
-	/// @param s  Text to apply
-	public void setArea(String s) {
-		area.setText(s);
-	}
-
-	/// Button action to clear field
-	public void clearActivityEntry() {
-		activityEntry.setText("");
-	}
-
-	/// Styled HBox with label and TextField
-	///
-	/// @param s  Label string
-	/// @param f  Text field
-	/// @return   HBox containing styled label and text field
-	public HBox ourHBox(String s, TextField f) {
-		Label label = new Label(s+":");
-		label.setStyle(LABEL_STYLE);
-
-		return new HBox(10, label, f);
-	}
-}
-- 
cgit v1.2.3