aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com.example.portfolio3/com/example/portfolio3/AbstractGraph.java52
-rw-r--r--src/main/java/com.example.portfolio3/com/example/portfolio3/AdjListGraph.java47
-rw-r--r--src/main/java/com.example.portfolio3/com/example/portfolio3/AdjMapGraph.java45
-rw-r--r--src/main/java/com.example.portfolio3/com/example/portfolio3/Edge.java37
-rw-r--r--src/main/java/com.example.portfolio3/com/example/portfolio3/EdgeGraph.java37
-rw-r--r--src/main/java/com.example.portfolio3/com/example/portfolio3/Graph.java34
-rw-r--r--src/main/java/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java331
-rw-r--r--src/main/java/com.example.portfolio3/com/example/portfolio3/Graphs.java13
-rw-r--r--src/main/java/com.example.portfolio3/com/example/portfolio3/MatrixGraph.java77
-rw-r--r--src/main/java/com.example.portfolio3/com/example/portfolio3/Vertex.java24
-rw-r--r--src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Control.java94
-rw-r--r--src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Main.java90
-rw-r--r--src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Combi.java105
-rw-r--r--src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/GUI.java62
-rw-r--r--src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Person.java18
-rw-r--r--src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/view/Window.java120
16 files changed, 1186 insertions, 0 deletions
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
new file mode 100644
index 0000000..c2cf433
--- /dev/null
+++ b/src/main/java/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/main/java/com.example.portfolio3/com/example/portfolio3/AdjListGraph.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/AdjListGraph.java
new file mode 100644
index 0000000..a677d3e
--- /dev/null
+++ b/src/main/java/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/main/java/com.example.portfolio3/com/example/portfolio3/AdjMapGraph.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/AdjMapGraph.java
new file mode 100644
index 0000000..85e5d04
--- /dev/null
+++ b/src/main/java/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/main/java/com.example.portfolio3/com/example/portfolio3/Edge.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/Edge.java
new file mode 100644
index 0000000..abc3c72
--- /dev/null
+++ b/src/main/java/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/main/java/com.example.portfolio3/com/example/portfolio3/EdgeGraph.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/EdgeGraph.java
new file mode 100644
index 0000000..ae9cbe9
--- /dev/null
+++ b/src/main/java/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/main/java/com.example.portfolio3/com/example/portfolio3/Graph.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/Graph.java
new file mode 100644
index 0000000..6e58029
--- /dev/null
+++ b/src/main/java/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/main/java/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java
new file mode 100644
index 0000000..3be7c70
--- /dev/null
+++ b/src/main/java/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/main/java/com.example.portfolio3/com/example/portfolio3/Graphs.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/Graphs.java
new file mode 100644
index 0000000..2975e44
--- /dev/null
+++ b/src/main/java/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/main/java/com.example.portfolio3/com/example/portfolio3/MatrixGraph.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/MatrixGraph.java
new file mode 100644
index 0000000..29005b7
--- /dev/null
+++ b/src/main/java/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/main/java/com.example.portfolio3/com/example/portfolio3/Vertex.java b/src/main/java/com.example.portfolio3/com/example/portfolio3/Vertex.java
new file mode 100644
index 0000000..9881159
--- /dev/null
+++ b/src/main/java/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/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Control.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Control.java
new file mode 100644
index 0000000..b53fb9f
--- /dev/null
+++ b/src/main/java/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/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Main.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/Main.java
new file mode 100644
index 0000000..2efd5b8
--- /dev/null
+++ b/src/main/java/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/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Combi.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Combi.java
new file mode 100644
index 0000000..371eb79
--- /dev/null
+++ b/src/main/java/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/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/GUI.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/GUI.java
new file mode 100644
index 0000000..ca9bd86
--- /dev/null
+++ b/src/main/java/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/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Person.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/model/Person.java
new file mode 100644
index 0000000..9edb7af
--- /dev/null
+++ b/src/main/java/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/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/view/Window.java b/src/main/java/dk.biks.bachelorizer/dk/biks/bachelorizer/view/Window.java
new file mode 100644
index 0000000..c75e290
--- /dev/null
+++ b/src/main/java/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);
+ }
+}