fix report
This commit is contained in:
1
.idea/misc.xml
generated
1
.idea/misc.xml
generated
@@ -1,4 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_20" project-jdk-name="openjdk-21" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_20" project-jdk-name="openjdk-21" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
|||||||
40
src/ChomskyChecker.java
Normal file
40
src/ChomskyChecker.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ChomskyChecker {
|
||||||
|
public static String classifyGrammar(Map<String, List<String>> grammar) {
|
||||||
|
for (Map.Entry<String, List<String>> entry : grammar.entrySet()) {
|
||||||
|
for (String listEntry : entry.getValue()) {
|
||||||
|
String prod = entry.getKey() + " -> " + listEntry;
|
||||||
|
if (isType3(prod)) {
|
||||||
|
return "Regular";
|
||||||
|
} else if (isType2(prod)) {
|
||||||
|
return "Context-free";
|
||||||
|
} else if (isType1(prod)) {
|
||||||
|
return "Context-sensitive";
|
||||||
|
} else if (isType0(prod)) {
|
||||||
|
return "Unrestricted";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isType0(String production) {
|
||||||
|
return production.matches("^[^ ]+ -> .+$");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isType1(String production) {
|
||||||
|
return production.matches("^.+ .+ .+$");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isType2(String production) {
|
||||||
|
return production.matches("^[A-Z]+ -> [^A-Z]+$");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isType3(String production) {
|
||||||
|
return production.matches("^[A-Z]+ -> [a-zA-Z]$") || production.matches("^[A-Z]+ -> [a-zA-Z][A-Z]$");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,36 +1,35 @@
|
|||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class FiniteAutomaton {
|
public class FiniteAutomaton {
|
||||||
private final Set<String> ALPHABET; // Set of symbols in the alphabet
|
private final String SS;
|
||||||
private final Map<String, Map<String, String>> P; // Transition function represented as a map of maps
|
private final Set<String> alphabet;
|
||||||
private final String SS; // Starting state
|
private final Map<String, Map<String, String>> T;
|
||||||
|
public FiniteAutomaton(String SS, Set<String> VN, Set<String> VT, Map<String, Map<String, String>> T) {
|
||||||
// Constructor to initialize the FiniteAutomaton with the alphabet, transition function, and starting state
|
this.SS = SS;
|
||||||
public FiniteAutomaton(Set<String> ALPHABET, Map<String, Map<String, String>> P, String SS) {
|
this.alphabet = VT;
|
||||||
this.ALPHABET = ALPHABET; // Initialize the alphabet
|
this.T = T;
|
||||||
this.P = P; // Initialize the transition function
|
|
||||||
this.SS = SS; // Initialize the starting state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to validate an input string against the finite automaton
|
public boolean isValid(String word) {
|
||||||
public boolean isValid(String input) {
|
String currentState = SS;
|
||||||
String currentState = SS; // Start from the initial state
|
for (char symbol : word.toCharArray()) {
|
||||||
|
String symbolStr = String.valueOf(symbol);
|
||||||
|
|
||||||
// Iterate over each symbol in the input string
|
if (!alphabet.contains(symbolStr)) return false;
|
||||||
for (char symbol : input.toCharArray()) {
|
|
||||||
String symbolStr = String.valueOf(symbol); // Convert the symbol to a string
|
|
||||||
|
|
||||||
// Check if the symbol is in the alphabet
|
if (T.containsKey(currentState) && T.get(currentState).containsKey(symbolStr))
|
||||||
if (!ALPHABET.contains(symbolStr)) return false; // If not, the input is invalid
|
currentState = T.get(currentState).get(symbolStr);
|
||||||
|
|
||||||
// Check if there is a transition defined for the current state and symbol
|
|
||||||
if (P.containsKey(currentState) && P.get(currentState).containsKey(symbolStr))
|
|
||||||
currentState = P.get(currentState).get(symbolStr); // Move to the next state
|
|
||||||
else
|
else
|
||||||
return false; // If no transition is defined, the input is invalid
|
return false;
|
||||||
}
|
}
|
||||||
// Check if the final state is the "OK" state, indicating the input is valid
|
|
||||||
return currentState.equals("OK");
|
return currentState.equals("OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Map<String, Map<String, String>> getTransitions() {
|
||||||
|
return T;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
125
src/Grammar.java
125
src/Grammar.java
@@ -1,91 +1,66 @@
|
|||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
public class Grammar {
|
public class Grammar {
|
||||||
// Instance variables to hold the grammar components
|
private final String SS;
|
||||||
private final String SS; // Starting symbol
|
private final Set<String> VN;
|
||||||
private final Set<String> VN; // Set of non-terminal symbols
|
private final Set<String> VT;
|
||||||
private final Map<String, List<String>> P; // Production rules
|
private final Map<String, List<String>> P;
|
||||||
private final FiniteAutomaton FA; // Finite Automaton representation of the grammar
|
private final FiniteAutomaton FA;
|
||||||
|
|
||||||
// Constructor to initialize the Grammar object with the provided grammar components.
|
|
||||||
public Grammar(String SS, Set<String> VN, Set<String> VT, Map<String, List<String>> P) {
|
public Grammar(String SS, Set<String> VN, Set<String> VT, Map<String, List<String>> P) {
|
||||||
this.SS = SS; // Initialize the starting symbol
|
this.SS = SS;
|
||||||
this.VN = VN; // Initialize the set of non-terminal symbols
|
this.VN = VN;
|
||||||
this.P = P; // Initialize the production rules
|
this.VT = VT;
|
||||||
// Convert the grammar to a Finite Automaton for validation.
|
this.P = P;
|
||||||
// The Finite Automaton will use the terminal symbols and transitions built from the production rules.
|
this.FA = new FiniteAutomaton(SS, VN, VT, generateTransitions(P));
|
||||||
this.FA = new FiniteAutomaton(VT, buildTransitions(P), SS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to generate and print a specified number of strings and their validity.
|
public Map<String, Map<String, String>> generateTransitions(Map<String, List<String>> P) {
|
||||||
public void generateNeededStrings(int num) {
|
|
||||||
System.out.println("Strings + Validity:");
|
|
||||||
// Loop to generate and check validity for each string
|
|
||||||
for (int i = 0; i < num; i++) {
|
|
||||||
// Generate a random string according to the grammar.
|
|
||||||
String generatedString = generateString();
|
|
||||||
// Check if the generated string is valid and print its validity.
|
|
||||||
System.out.println((i + 1) + ": " + generatedString + " " + (isValid(generatedString) ? "is valid" : "is not valid"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to check if a given word is valid according to the grammar.
|
|
||||||
public boolean isValid(String word) {
|
|
||||||
// Delegate the validation to the Finite Automaton representation of the grammar.
|
|
||||||
return FA.isValid(word);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to generate a random string according to the grammar.
|
|
||||||
public String generateString() {
|
|
||||||
// Start with the starting symbol.
|
|
||||||
String result = getRandomProduction(SS);
|
|
||||||
boolean containsNonTerminal = true;
|
|
||||||
|
|
||||||
// Continue replacing non-terminals with their productions until no more non-terminals remain.
|
|
||||||
while (containsNonTerminal) {
|
|
||||||
containsNonTerminal = false;
|
|
||||||
// Iterate over each character in the current string.
|
|
||||||
for (char entry : result.toCharArray()) {
|
|
||||||
String entryString = String.valueOf(entry);
|
|
||||||
// If the character is a non-terminal, replace it with a random production.
|
|
||||||
if (VN.contains(entryString)) {
|
|
||||||
result = result.replaceFirst(entryString, getRandomProduction(entryString));
|
|
||||||
containsNonTerminal = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to get a random production for a given non-terminal symbol.
|
|
||||||
private String getRandomProduction(String nonTerminal) {
|
|
||||||
// Get the list of productions for the given non-terminal and select one randomly.
|
|
||||||
return P.get(nonTerminal).get(ThreadLocalRandom.current().nextInt(P.get(nonTerminal).size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to build transitions for the Finite Automaton representation of the grammar.
|
|
||||||
private Map<String, Map<String, String>> buildTransitions(Map<String, List<String>> productions) {
|
|
||||||
// Initialize a map to hold the transitions for each state (non-terminal symbol).
|
|
||||||
Map<String, Map<String, String>> transitions = new HashMap<>();
|
Map<String, Map<String, String>> transitions = new HashMap<>();
|
||||||
// Iterate over each production rule.
|
for (Map.Entry<String, List<String>> entryP : P.entrySet()) {
|
||||||
for (Map.Entry<String, List<String>> entry : productions.entrySet()) {
|
String state = entryP.getKey();
|
||||||
String state = entry.getKey(); // Get the non-terminal symbol as the state.
|
List<String> productionList = entryP.getValue();
|
||||||
List<String> productionList = entry.getValue(); // Get the list of productions for the state.
|
|
||||||
Map<String, String> stateTransitions = new HashMap<>();
|
Map<String, String> stateTransitions = new HashMap<>();
|
||||||
// Iterate over each production.
|
|
||||||
for (String production : productionList) {
|
for (String production : productionList) {
|
||||||
String symbol = production.substring(0, 1); // Get the first character as the symbol.
|
String symbol = production.substring(0, 1);
|
||||||
// Get the next state as the rest of the production, or "OK" if it's empty.
|
|
||||||
String nextState = production.length() > 1 ? production.substring(1) : "OK";
|
String nextState = production.length() > 1 ? production.substring(1) : "OK";
|
||||||
stateTransitions.put(symbol, nextState); // Add the transition to the state's transitions.
|
stateTransitions.put(symbol, nextState);
|
||||||
}
|
}
|
||||||
transitions.put(state, stateTransitions); // Add the state and its transitions to the overall transitions map.
|
transitions.put(state, stateTransitions);
|
||||||
}
|
}
|
||||||
return transitions;
|
return transitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FiniteAutomaton getFA() {
|
||||||
|
return this.FA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid(String word) {
|
||||||
|
return this.FA.isValid(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateWords(int numWords) {
|
||||||
|
List<String> generatedWords = new ArrayList<>();
|
||||||
|
Random random = new Random();
|
||||||
|
|
||||||
|
for (int i = 0; i < numWords; i++) {
|
||||||
|
StringBuilder wordBuilder = new StringBuilder();
|
||||||
|
String currentState = SS;
|
||||||
|
|
||||||
|
while (!currentState.equals("OK")) {
|
||||||
|
Map<String, String> transitions = FA.getTransitions().get(currentState);
|
||||||
|
List<String> symbols = new ArrayList<>(transitions.keySet());
|
||||||
|
String symbol = symbols.get(random.nextInt(symbols.size()));
|
||||||
|
wordBuilder.append(symbol);
|
||||||
|
currentState = transitions.get(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
generatedWords.add(wordBuilder.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("===================================");
|
||||||
|
for (String word: generatedWords) {
|
||||||
|
System.out.println(word + " " + (isValid(word) ? "- Valid" : "- Not valid"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,48 @@
|
|||||||
import java.util.*;
|
import util.Pair;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
// Define the starting symbol, non-terminal symbols, terminal symbols, and production rules
|
|
||||||
public static final String SS = "S"; // Starting symbol
|
// LAB 1
|
||||||
public static final Set<String> VN = Set.of("S", "B", "C"); // Non-terminal symbols
|
public static final String SS = "S";
|
||||||
public static final Set<String> VT = Set.of("a", "b", "c"); // Terminal symbols
|
public static final Set<String> VN = Set.of("S", "B", "C");
|
||||||
public static final Map<String, List<String>> P = Map.of( // Production rules
|
public static final Set<String> VT = Set.of("a", "b", "c");
|
||||||
"S", List.of("aB"), // Production rule for S
|
public static final Map<String, List<String>> P = Map.of(
|
||||||
"B", List.of("aC", "bB"), // Production rule for B
|
"S", List.of("aB"),
|
||||||
"C", List.of("bB", "c", "aS")); // Production rule for C
|
"B", List.of("aC", "bB"),
|
||||||
|
"C", List.of("aS", "c"));
|
||||||
|
|
||||||
|
// LAB 2
|
||||||
|
public static final List<String> stateList = Arrays.asList("q0", "q1", "q2");
|
||||||
|
public static final Set<String> alphabet = Set.of("a", "b");
|
||||||
|
public static final Set<String> acceptingStates = Set.of("q2");
|
||||||
|
public static final Map<String, List<Pair>> transitions= Map.of(
|
||||||
|
"q0", List.of(new Pair("a", "q0"), new Pair("a", "q1")),
|
||||||
|
"q1", List.of(new Pair("b", "q2"), new Pair("a", "q0")),
|
||||||
|
"q2", List.of(new Pair("b", "q2"))
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
String toCheck = "aac"; // Word to check
|
String toCheck = "aac";
|
||||||
|
|
||||||
// Create a Grammar object with the defined grammar
|
|
||||||
Grammar grammar = new Grammar(SS, VN, VT, P);
|
Grammar grammar = new Grammar(SS, VN, VT, P);
|
||||||
|
grammar.generateWords(5);
|
||||||
// Generate strings needed for the validation process
|
System.out.println("===================================");
|
||||||
grammar.generateNeededStrings(5);
|
|
||||||
|
|
||||||
// Check if the given word is valid according to the grammar
|
|
||||||
System.out.println("Is " + toCheck + " valid? " + grammar.isValid(toCheck));
|
System.out.println("Is " + toCheck + " valid? " + grammar.isValid(toCheck));
|
||||||
|
System.out.println("===================================");
|
||||||
|
System.out.println(ChomskyChecker.classifyGrammar(P));
|
||||||
|
|
||||||
|
ManualFiniteAutomaton MFA = new ManualFiniteAutomaton(stateList, alphabet, acceptingStates, transitions);
|
||||||
|
System.out.println("===================================");
|
||||||
|
MFA.toGrammar();
|
||||||
|
System.out.println("===================================");
|
||||||
|
MFA.isDeterministic();
|
||||||
|
System.out.println("===================================");
|
||||||
|
MFA.toDFA();
|
||||||
|
System.out.println("===================================");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
116
src/ManualFiniteAutomaton.java
Normal file
116
src/ManualFiniteAutomaton.java
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import util.Pair;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class ManualFiniteAutomaton {
|
||||||
|
|
||||||
|
private final List<String> stateList;
|
||||||
|
private final Set<String> alphabet;
|
||||||
|
private final Set<String> acceptingStates;
|
||||||
|
private final Map<String, List<Pair>> T;
|
||||||
|
|
||||||
|
public ManualFiniteAutomaton(List<String> stateList, Set<String> alphabet, Set<String> acceptingStates, Map<String, List<Pair>> T) {
|
||||||
|
this.stateList = stateList;
|
||||||
|
this.alphabet = alphabet;
|
||||||
|
this.acceptingStates = acceptingStates;
|
||||||
|
this.T = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to map original states to equivalent single-character states
|
||||||
|
public Map<String, String> mapStates() {
|
||||||
|
Map<String, String> mappedStates = new HashMap<>(); // Creating a HashMap to store mappings
|
||||||
|
char mappedState = 'A'; // Starting mapping with character 'A'
|
||||||
|
for (String state : stateList) { // Iterating through each state in stateList
|
||||||
|
mappedStates.put(state, String.valueOf(mappedState)); // Mapping original state to a single character
|
||||||
|
mappedState++; // Moving to the next character for mapping
|
||||||
|
}
|
||||||
|
return mappedStates; // Returning the mapped states
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to check if the automaton is deterministic
|
||||||
|
public void isDeterministic() {
|
||||||
|
for (Map.Entry<String, List<Pair>> entry : T.entrySet()) { // Iterating through each transition in T
|
||||||
|
if (entry.getValue().size() > 1) { // If there are multiple transitions for a state and symbol
|
||||||
|
System.out.println("It is not deterministic!"); // Print that the automaton is not deterministic
|
||||||
|
return; // Exit the method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("It is deterministic!"); // Print that the automaton is deterministic
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to convert the NFA to DFA
|
||||||
|
public void toDFA() {
|
||||||
|
Map<Set<String>, Map<String, Set<String>>> dfaTransitions = new HashMap<>(); // Creating a map for DFA transitions
|
||||||
|
Queue<Set<String>> queue = new LinkedList<>(); // Queue to store sets of states
|
||||||
|
|
||||||
|
Set<String> initialState = new HashSet<>(stateList); // Creating initial set of states containing all states
|
||||||
|
queue.add(initialState); // Adding the initial state to the queue
|
||||||
|
|
||||||
|
while (!queue.isEmpty()) { // While there are unprocessed states in the queue
|
||||||
|
Set<String> currentState = queue.poll(); // Dequeue a state from the queue
|
||||||
|
|
||||||
|
Map<String, Set<String>> transitions = new HashMap<>(); // Map to store transitions from current state
|
||||||
|
for (String symbol : alphabet) { // For each symbol in the alphabet
|
||||||
|
Set<String> nextStates = new HashSet<>(); // Set to store next states for the symbol
|
||||||
|
for (String state : currentState) { // For each state in the current set of states
|
||||||
|
List<Pair> transitionsForState = T.get(state); // Get transitions for the current state
|
||||||
|
if (transitionsForState != null) { // If there are transitions for the state
|
||||||
|
for (Pair p : transitionsForState) { // For each transition from the state
|
||||||
|
if (p.first().equals(symbol)) { // If the transition symbol matches the current symbol
|
||||||
|
nextStates.add(p.second()); // Add the destination state to nextStates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transitions.put(symbol, nextStates); // Add transitions for the current symbol
|
||||||
|
if (!nextStates.isEmpty() && !dfaTransitions.containsKey(nextStates)) { // If nextStates is not empty and not already processed
|
||||||
|
queue.add(nextStates); // Enqueue nextStates for further processing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dfaTransitions.put(currentState, transitions); // Add transitions from current state to DFA transitions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printing DFA transitions
|
||||||
|
System.out.println("DFA Transitions:");
|
||||||
|
for (Map.Entry<Set<String>, Map<String, Set<String>>> entry : dfaTransitions.entrySet()) { // For each DFA state and its transitions
|
||||||
|
Set<String> currentState = entry.getKey(); // Get the current DFA state
|
||||||
|
Map<String, Set<String>> transitions = entry.getValue(); // Get its transitions
|
||||||
|
System.out.println("State: " + currentState); // Print the current DFA state
|
||||||
|
for (Map.Entry<String, Set<String>> transition : transitions.entrySet()) { // For each transition from the state
|
||||||
|
String inputSymbol = transition.getKey(); // Get the input symbol
|
||||||
|
Set<String> nextState = transition.getValue(); // Get the next state(s)
|
||||||
|
if (!nextState.isEmpty()) { // If there is a transition
|
||||||
|
System.out.println(" Input: " + inputSymbol + " --> " + nextState); // Print the transition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to convert the NFA to Grammar
|
||||||
|
public void toGrammar() {
|
||||||
|
Map<String, String> mappedStates = mapStates(); // Map original states to single-character states
|
||||||
|
Map<String, List<String>> grammar = new HashMap<>(); // Create a map to store the grammar rules
|
||||||
|
|
||||||
|
for(Map.Entry<String, List<Pair>> te : T.entrySet()) { // For each transition in the transition function
|
||||||
|
List<String> maps = new ArrayList<>(); // Create a list to store grammar rules for the current state
|
||||||
|
for (Pair p : te.getValue()) { // For each transition from the current state
|
||||||
|
maps.add(p.first() + mappedStates.get(p.second())); // Add a grammar rule to the list
|
||||||
|
}
|
||||||
|
grammar.put(mappedStates.get(te.getKey()), maps); // Add the grammar rules to the grammar map
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printing the grammar rules
|
||||||
|
for (Map.Entry<String, List<String>> grammarEntry : grammar.entrySet()) { // For each state and its grammar rules
|
||||||
|
System.out.print(grammarEntry.getKey() + " -> "); // Print the state
|
||||||
|
if (grammarEntry.getValue().size() > 1) { // If there are multiple rules
|
||||||
|
System.out.print(grammarEntry.getValue().get(0)); // Print the first rule
|
||||||
|
for (int i = 1; i < grammarEntry.getValue().size(); i++) { // For the remaining rules
|
||||||
|
System.out.print(" | " + grammarEntry.getValue().get(i)); // Print each rule
|
||||||
|
}
|
||||||
|
} else { // If there is only one rule
|
||||||
|
System.out.print(grammarEntry.getValue().get(0)); // Print the rule
|
||||||
|
}
|
||||||
|
System.out.println(); // Move to the next line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/reports/lab_two.pdf
Normal file
BIN
src/reports/lab_two.pdf
Normal file
Binary file not shown.
9
src/util/Pair.java
Normal file
9
src/util/Pair.java
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package util;
|
||||||
|
|
||||||
|
public record Pair(String first, String second) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "(" + first + ", " + second + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user