init commit
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class App {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
File boardTiles = new File("boardTiles.txt");
|
||||||
|
if(boardTiles == null) {
|
||||||
|
System.out.println("Could not find boardTiles.txt!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ArrayList<Player> players = new ArrayList<>();
|
||||||
|
players.add(new Player());
|
||||||
|
|
||||||
|
Board b1000 = new Board(boardTiles, 1000, players);
|
||||||
|
Board b10000 = new Board(boardTiles, 10000, players);
|
||||||
|
Board b100000 = new Board(boardTiles, 100000, players);
|
||||||
|
Board b1000000 = new Board(boardTiles, 1000000, players);
|
||||||
|
|
||||||
|
System.out.println("\n\n1000 turns: ");
|
||||||
|
b1000.printBoard();
|
||||||
|
|
||||||
|
System.out.println("\n\n10000 turns: ");
|
||||||
|
b10000.printBoard();
|
||||||
|
|
||||||
|
System.out.println("\n\n100000 turns: ");
|
||||||
|
b100000.printBoard();
|
||||||
|
|
||||||
|
System.out.println("\n\n1000000 turns: ");
|
||||||
|
b1000000.printBoard();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class Board {
|
||||||
|
private Tile head;
|
||||||
|
private Tile tail;
|
||||||
|
private Tile jail;
|
||||||
|
private int n;
|
||||||
|
|
||||||
|
public Board(File board, int turns, ArrayList<Player> players) {
|
||||||
|
n = 0;
|
||||||
|
|
||||||
|
try (Scanner scan = new Scanner(board)) {
|
||||||
|
while(scan.hasNextLine()) {
|
||||||
|
add(scan.nextLine());
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Could not open boardTiles.txt!");
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentTurn = 0;
|
||||||
|
|
||||||
|
while(currentTurn < turns) {
|
||||||
|
move(players.get(0).roll());
|
||||||
|
currentTurn++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printBoard() {
|
||||||
|
Tile current = head;
|
||||||
|
|
||||||
|
while(current != null) {
|
||||||
|
System.out.println(current.tileName + ", " + current.timesLanded);
|
||||||
|
current = current.next;
|
||||||
|
|
||||||
|
if(current.tileName.equals(head.tileName)) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void move(int spaces) {
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
Tile current = head;
|
||||||
|
while(counter < spaces) {
|
||||||
|
current = current.next;
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
head = current;
|
||||||
|
tail = current.prev;
|
||||||
|
|
||||||
|
head.landed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveTo(String tileName) {
|
||||||
|
/*
|
||||||
|
if(tileName.equals("Jail")) {
|
||||||
|
head = jail;
|
||||||
|
tail = jail.prev;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Tile current = head;
|
||||||
|
|
||||||
|
while(!current.tileName.equals(tileName)) {
|
||||||
|
current = current.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
head = current;
|
||||||
|
tail = current.prev;
|
||||||
|
|
||||||
|
head.landed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void add(String tileName) {
|
||||||
|
if(n == 0) {
|
||||||
|
head = new Tile(tileName);
|
||||||
|
n++;
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else if(n == 1) {
|
||||||
|
tail = new Tile(tileName);
|
||||||
|
head.next = tail;
|
||||||
|
tail.prev = head;
|
||||||
|
n++;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tail.next = new Tile(tileName);
|
||||||
|
tail.next.prev = tail;
|
||||||
|
tail = tail.next;
|
||||||
|
|
||||||
|
tail.next = head;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Deck {
|
||||||
|
ArrayList<Card> cards;
|
||||||
|
|
||||||
|
public Deck(String filename) {
|
||||||
|
// Create the deck by reading in the file.
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shuffle() {
|
||||||
|
// Shuffle the deck
|
||||||
|
}
|
||||||
|
|
||||||
|
public String drawChance() {
|
||||||
|
return ""; // TODO: Return the action of the card drawn
|
||||||
|
}
|
||||||
|
|
||||||
|
public String drawCommunity() {
|
||||||
|
return ""; // TODO: Return the action of the card drawn
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Card {
|
||||||
|
String action;
|
||||||
|
|
||||||
|
public Card(String action) {
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
public class Deck {
|
||||||
|
ArrayList<Card> cards;
|
||||||
|
|
||||||
|
public Deck(String filename) {
|
||||||
|
// Create the deck by reading in the file.
|
||||||
|
cards = new ArrayList<Card>();
|
||||||
|
try {
|
||||||
|
|
||||||
|
Scanner scanner = new Scanner(new File(filename));
|
||||||
|
while (scanner.hasNextLine()) {
|
||||||
|
String action = scanner.nextLine();
|
||||||
|
Card newCard = new Card(action);
|
||||||
|
cards.add(newCard);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Can't find comCard.txt!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Deck [cards=" + cards + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shuffle() {
|
||||||
|
Collections.shuffle(cards);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String drawChance() {
|
||||||
|
|
||||||
|
return ""; // TODO: Return the action of the card drawn
|
||||||
|
}
|
||||||
|
|
||||||
|
public String drawCommunity() {
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
int randomNumber = random.nextInt(16);
|
||||||
|
return getCardAction(randomNumber); // TODO: Return the action of the card drawn
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCardAction(int index) {
|
||||||
|
if (index >= 0 && index < cards.size()) {
|
||||||
|
return cards.get(index).action;
|
||||||
|
} else {
|
||||||
|
return "Invalid index";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfCards() {
|
||||||
|
return cards.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Card {
|
||||||
|
String action;
|
||||||
|
|
||||||
|
public Card(String action) {
|
||||||
|
this.action = action;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Create a Deck object by providing the filename
|
||||||
|
Deck deck = new Deck("src/comCard.txt");
|
||||||
|
String action = deck.drawCommunity();
|
||||||
|
System.out.println(action);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class Player {
|
||||||
|
private int doubleDiceRoll;
|
||||||
|
private int getOutOfJail;
|
||||||
|
|
||||||
|
public Player() {
|
||||||
|
doubleDiceRoll = 0;
|
||||||
|
getOutOfJail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addGetOutOfJailCard() {
|
||||||
|
getOutOfJail++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useGetOutOfJailCard() {
|
||||||
|
getOutOfJail--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasGetOutOfJailCard() {
|
||||||
|
return getOutOfJail > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int roll() {
|
||||||
|
Random r = new Random();
|
||||||
|
int rollA = r.nextInt(7) + 1;
|
||||||
|
int rollB = r.nextInt(7) + 1;
|
||||||
|
|
||||||
|
if(rollA == rollB) doubleDiceRoll++;
|
||||||
|
|
||||||
|
return rollA + rollB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDoubleDiceRoll() {
|
||||||
|
return doubleDiceRoll;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
public class Tile {
|
||||||
|
public String tileName;
|
||||||
|
public int timesLanded;
|
||||||
|
public Tile next;
|
||||||
|
public Tile prev;
|
||||||
|
|
||||||
|
public Tile(String tileName) { this.tileName = tileName; }
|
||||||
|
|
||||||
|
public void landed() {
|
||||||
|
timesLanded++;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
Go
|
||||||
|
Mediterranean Avenue
|
||||||
|
Community Chest
|
||||||
|
Baltic Avenue
|
||||||
|
Income Tax
|
||||||
|
Reading Railroad
|
||||||
|
Oriental Avenue
|
||||||
|
Chance
|
||||||
|
Vermont Avenue
|
||||||
|
Connecticut Avenue
|
||||||
|
Jail / Just Visiting
|
||||||
|
St. Charles Place
|
||||||
|
Electric Company
|
||||||
|
States Avenue
|
||||||
|
Virginia Avenue
|
||||||
|
Pennsylvania Railroad
|
||||||
|
St. James Place
|
||||||
|
Community Chest
|
||||||
|
Tennessee Avenue
|
||||||
|
New York Avenue
|
||||||
|
Free Parking
|
||||||
|
Kentucky Avenue
|
||||||
|
Chance
|
||||||
|
Indiana Avenue
|
||||||
|
Illinois Avenue
|
||||||
|
B. & O. Railroad
|
||||||
|
Atlantic Avenue
|
||||||
|
Ventnor Avenue
|
||||||
|
Water Works
|
||||||
|
Marvin Gardens
|
||||||
|
Go To Jail
|
||||||
|
Pacific Avenue
|
||||||
|
North Carolina Avenue
|
||||||
|
Community Chest
|
||||||
|
Pennsylvania Avenue
|
||||||
|
Short Line
|
||||||
|
Chance
|
||||||
|
Park Place
|
||||||
|
Luxury Tax
|
||||||
|
Boardwalk
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/zsh
|
||||||
|
|
||||||
|
javac *.java
|
||||||
|
java App
|
||||||
|
|
||||||
|
rm *.class
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
|
<classpathentry kind="src" path=""/>
|
||||||
|
<classpathentry kind="output" path=""/>
|
||||||
|
</classpath>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/CompareSortingAlgorithms.class
|
||||||
|
/Driver.class
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="openjdk-20" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/cs2430-project1.iml" filepath="$PROJECT_DIR$/cs2430-project1.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>cs2430-project1</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
<filteredResources>
|
||||||
|
<filter>
|
||||||
|
<id>1695833596179</id>
|
||||||
|
<name></name>
|
||||||
|
<type>30</type>
|
||||||
|
<matcher>
|
||||||
|
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
||||||
|
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
||||||
|
</matcher>
|
||||||
|
</filter>
|
||||||
|
</filteredResources>
|
||||||
|
</projectDescription>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
To run:
|
||||||
|
Compilation: in the root folder (cs2430-project1), run `javac src/TestDriver.java src/algorithms/*.java src/utils/*.java`
|
||||||
|
Execute: in the root folder (cs2430-project1), run `java src/TestDriver`
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/results" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
package src;
|
||||||
|
|
||||||
|
import src.algorithms.*;
|
||||||
|
|
||||||
|
import src.utils.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares various sorting algorithms based upon the number of comparisons each algorithm completes.
|
||||||
|
* Generates and sorts every permutation of numbers from 0 (inclusive) to n (exclusive).
|
||||||
|
* Current implementation only tests the HeapSort algorithm, but it can be extended to other algorithms.
|
||||||
|
*
|
||||||
|
* @author Josh Ashton, Lexus Lindeman, Sean White, Abbas, Culton
|
||||||
|
*/
|
||||||
|
public class TestDriver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main driver method to test the sorting algorithms.
|
||||||
|
* Generates all possible permutations for each test size, then sorts each permutation using a new HeapSort instance.
|
||||||
|
* After sorting, results (including the number of comparisons) are stored.
|
||||||
|
* The results are then processed to print out the best, worst, and average cases based on the number of comparisons.
|
||||||
|
* Results are also saved to a text file in the "results" directory.
|
||||||
|
*
|
||||||
|
* @param args Command-line arguments (not used).
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
int[] testSizes = {4, 6, 8}; // Sizes for which the sorting algorithms will be tested
|
||||||
|
|
||||||
|
// Write results to a file in the "results" directory
|
||||||
|
try {
|
||||||
|
FileOutputUtil.writeToFile("heapsort.txt", testAlgo(testSizes,0));
|
||||||
|
System.out.println("Results written to results/heapsort.txt");
|
||||||
|
|
||||||
|
FileOutputUtil.writeToFile("mergesort.txt", testAlgo(testSizes,1));
|
||||||
|
System.out.println("Results written to results/mergesort.txt");
|
||||||
|
|
||||||
|
FileOutputUtil.writeToFile("quicksort.txt", testAlgo(testSizes,2));
|
||||||
|
System.out.println("Results written to results/quicksort.txt");
|
||||||
|
|
||||||
|
FileOutputUtil.writeToFile("shakersort.txt", testAlgo(testSizes,3));
|
||||||
|
System.out.println("Results written to results/shakersort.txt");
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Error writing to file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String testAlgo(int[] testSizes, int algo) {
|
||||||
|
StringBuilder output = new StringBuilder(); // To collect the output for the file
|
||||||
|
|
||||||
|
for (int n : testSizes) {
|
||||||
|
int[][] permutations = PermutationsGenerator.generate(n);
|
||||||
|
int totalComparisons = 0;
|
||||||
|
List<Result> results = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int[] permutation : permutations) {
|
||||||
|
int[] copy = Arrays.copyOf(permutation, permutation.length);
|
||||||
|
int comparisons = 0;
|
||||||
|
switch (algo) {
|
||||||
|
case 0:
|
||||||
|
HeapSort heapSort = new HeapSort(); // Create a new HeapSort instance for each permutation
|
||||||
|
heapSort.sort(copy);
|
||||||
|
comparisons = heapSort.getComparisonCount();
|
||||||
|
totalComparisons += comparisons;
|
||||||
|
results.add(new Result(permutation, copy, comparisons));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
MergeSort mergeSort = new MergeSort();
|
||||||
|
mergeSort.sort(copy);
|
||||||
|
comparisons = mergeSort.getComparisonCount();
|
||||||
|
totalComparisons += comparisons;
|
||||||
|
results.add(new Result(permutation, copy, comparisons));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
QuickSort quickSort = new QuickSort();
|
||||||
|
quickSort.sort(copy);
|
||||||
|
comparisons = quickSort.getComparisonCount();
|
||||||
|
totalComparisons += comparisons;
|
||||||
|
results.add(new Result(permutation, copy, comparisons));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
ShakerSort shakerSort = new ShakerSort();
|
||||||
|
shakerSort.sort(copy);
|
||||||
|
comparisons = shakerSort.getComparisonCount();
|
||||||
|
totalComparisons += comparisons;
|
||||||
|
results.add(new Result(permutation, copy, comparisons));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
results.sort(Comparator.comparingInt(Result::comparisons));
|
||||||
|
|
||||||
|
// Append results to the output StringBuilder
|
||||||
|
output.append("\n========================================\n");
|
||||||
|
output.append("RESULTS FOR N = ").append(n).append("\n");
|
||||||
|
output.append("========================================\n\n");
|
||||||
|
|
||||||
|
output.append("Best 10 cases:\n");
|
||||||
|
output.append("--------------------\n");
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
output.append("Original: ").append(Arrays.toString(results.get(i).originalArray()))
|
||||||
|
.append("\nSorted: ").append(Arrays.toString(results.get(i).sortedArray()))
|
||||||
|
.append("\nComparisons: ").append(results.get(i).comparisons()).append("\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
output.append("\nWorst 10 cases:\n");
|
||||||
|
output.append("--------------------\n");
|
||||||
|
for (int i = results.size() - 10; i < results.size(); i++) {
|
||||||
|
output.append("Original: ").append(Arrays.toString(results.get(i).originalArray()))
|
||||||
|
.append("\nSorted: ").append(Arrays.toString(results.get(i).sortedArray()))
|
||||||
|
.append("\nComparisons: ").append(results.get(i).comparisons()).append("\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the average comparisons for this test size with two decimal places
|
||||||
|
output.append("\nAverage comparisons: ").append(String.format("%.2f", totalComparisons / (double) permutations.length)).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package src.algorithms;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `HeapSort` class provides an implementation of the heapsort algorithm.
|
||||||
|
* Heapsort is a comparison-based sorting algorithm that builds a binary heap
|
||||||
|
* and then repeatedly extracts the maximum element from the heap to build the
|
||||||
|
* sorted array.
|
||||||
|
*
|
||||||
|
* @author Sean White
|
||||||
|
*
|
||||||
|
*<p>
|
||||||
|
* Usage example:
|
||||||
|
*<p>
|
||||||
|
* HeapSort sorter = new HeapSort();
|
||||||
|
* int[] arr = {4, 10, 3, 5, 1};
|
||||||
|
* sorter.sort(arr);
|
||||||
|
* int comparisons = sorter.getComparisonCount();
|
||||||
|
*/
|
||||||
|
public class HeapSort {
|
||||||
|
|
||||||
|
private int comparisons = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts an array of integers in ascending order using the HeapSort algorithm.
|
||||||
|
*
|
||||||
|
* @param arr The array to be sorted.
|
||||||
|
*/
|
||||||
|
public void sort(int[] arr) {
|
||||||
|
int n = arr.length;
|
||||||
|
|
||||||
|
// Build heap (rearrange array)
|
||||||
|
for (int i = n / 2 - 1; i >= 0; i--) {
|
||||||
|
comparisons++;
|
||||||
|
heapify(arr, n, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// One by one extract an element from heap
|
||||||
|
for (int i = n - 1; i > 0; i--) {
|
||||||
|
comparisons++;
|
||||||
|
// Swap current root with end
|
||||||
|
swap(arr, 0, i);
|
||||||
|
// Call max heapify on the reduced heap
|
||||||
|
heapify(arr, i, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the heapify operation on a subtree rooted at a specified index.
|
||||||
|
*
|
||||||
|
* @param arr The array in which the heapify operation is performed.
|
||||||
|
* @param n The size of the heap/subtree.
|
||||||
|
* @param i The index at which the heapify operation starts.
|
||||||
|
*/
|
||||||
|
private void heapify(int[] arr, int n, int i) {
|
||||||
|
int largest = i;
|
||||||
|
int left = 2 * i + 1;
|
||||||
|
int right = 2 * i + 2;
|
||||||
|
|
||||||
|
// Check if left child exists and is greater than the root
|
||||||
|
if (left < n) {
|
||||||
|
comparisons++; // Incrementing the counter for comparison with largest
|
||||||
|
if (arr[left] > arr[largest]) {
|
||||||
|
comparisons++;
|
||||||
|
largest = left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if right child exists and is greater than the largest value determined so far
|
||||||
|
if (right < n) {
|
||||||
|
comparisons++; // Incrementing the counter for comparison with largest
|
||||||
|
if (arr[right] > arr[largest]) {
|
||||||
|
comparisons++;
|
||||||
|
largest = right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the largest is not root
|
||||||
|
if (largest != i) {
|
||||||
|
comparisons++;
|
||||||
|
swap(arr, i, largest);
|
||||||
|
// Recursively heapify the affected sub-tree
|
||||||
|
heapify(arr, n, largest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps two elements in the array.
|
||||||
|
*
|
||||||
|
* @param arr The array in which elements are swapped.
|
||||||
|
* @param i The index of the first element to be swapped.
|
||||||
|
* @param j The index of the second element to be swapped.
|
||||||
|
*/
|
||||||
|
private void swap(int[] arr, int i, int j) {
|
||||||
|
int temp = arr[i];
|
||||||
|
arr[i] = arr[j];
|
||||||
|
arr[j] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the count of comparisons made during the sorting process.
|
||||||
|
*
|
||||||
|
* @return The number of comparisons made during sorting.
|
||||||
|
*/
|
||||||
|
public int getComparisonCount() {
|
||||||
|
return comparisons;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package src.algorithms;
|
||||||
|
|
||||||
|
public class MergeSort {
|
||||||
|
|
||||||
|
private int comparisons = 0;
|
||||||
|
|
||||||
|
public void sort(int arr[]) {
|
||||||
|
sort(arr, 0, arr.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sort(int arr[], int l, int r) {
|
||||||
|
if (l < r) {
|
||||||
|
comparisons++;
|
||||||
|
// Find the middle point
|
||||||
|
int m = l + (r - l) / 2;
|
||||||
|
|
||||||
|
// Sort first and second halves
|
||||||
|
sort(arr, l, m);
|
||||||
|
sort(arr, m + 1, r);
|
||||||
|
|
||||||
|
// Merge the sorted halves
|
||||||
|
merge(arr, l, m, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void merge(int arr[], int l, int m, int r) {
|
||||||
|
// Find sizes of two subarrays to be merged
|
||||||
|
int n1 = m - l + 1;
|
||||||
|
int n2 = r - m;
|
||||||
|
|
||||||
|
// Create temp arrays
|
||||||
|
int L[] = new int[n1];
|
||||||
|
int R[] = new int[n2];
|
||||||
|
|
||||||
|
// Copy data to temp arrays
|
||||||
|
for (int i = 0; i < n1; ++i) {
|
||||||
|
comparisons++;
|
||||||
|
L[i] = arr[l + i];
|
||||||
|
}
|
||||||
|
for (int j = 0; j < n2; ++j) {
|
||||||
|
comparisons++;
|
||||||
|
R[j] = arr[m + 1 + j];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge the temp arrays
|
||||||
|
|
||||||
|
// Initial indices of first and second subarrays
|
||||||
|
int i = 0, j = 0;
|
||||||
|
|
||||||
|
// Initial index of merged subarray array
|
||||||
|
int k = l;
|
||||||
|
while (i < n1 && j < n2) {
|
||||||
|
if (L[i] <= R[j]) {
|
||||||
|
comparisons++;
|
||||||
|
arr[k] = L[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
comparisons++;
|
||||||
|
arr[k] = R[j];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy remaining elements of L[] if any
|
||||||
|
while (i < n1) {
|
||||||
|
comparisons++;
|
||||||
|
arr[k] = L[i];
|
||||||
|
i++;
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy remaining elements of R[] if any
|
||||||
|
while (j < n2) {
|
||||||
|
comparisons++;
|
||||||
|
arr[k] = R[j];
|
||||||
|
j++;
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the count of comparisons made during the sorting process.
|
||||||
|
*
|
||||||
|
* @return The number of comparisons made during sorting.
|
||||||
|
*/
|
||||||
|
public int getComparisonCount() {
|
||||||
|
return comparisons;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package src.algorithms;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class QuickSort {
|
||||||
|
|
||||||
|
private int comparisons = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public method for the user to use quick sort.
|
||||||
|
*
|
||||||
|
* @param int[] arr, an array containing a permutation.
|
||||||
|
* @return sorted array
|
||||||
|
*/
|
||||||
|
public void sort(int[] arr) {
|
||||||
|
quickSort(arr, 0, arr.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method for quickSort
|
||||||
|
*
|
||||||
|
* @param arr
|
||||||
|
* @param low
|
||||||
|
* @param high
|
||||||
|
*/
|
||||||
|
private void quickSort(int[] arr, int low, int high) {
|
||||||
|
if (low < high + 1) {
|
||||||
|
comparisons++;
|
||||||
|
int p = partition(arr, low, high);
|
||||||
|
quickSort(arr, low, p - 1);
|
||||||
|
quickSort(arr, p + 1, high);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps two indices of an array
|
||||||
|
*
|
||||||
|
* @param arr
|
||||||
|
* @param index1
|
||||||
|
* @param index2
|
||||||
|
*/
|
||||||
|
private void swap(int[] arr, int index1, int index2) {
|
||||||
|
int temp = arr[index1];
|
||||||
|
arr[index1] = arr[index2];
|
||||||
|
arr[index2] = temp;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns random pivot index between low and high.
|
||||||
|
*
|
||||||
|
* @param low
|
||||||
|
* @param high
|
||||||
|
* @return random pivot
|
||||||
|
*/
|
||||||
|
private int getPivot(int low, int high) {
|
||||||
|
Random rand = new Random();
|
||||||
|
return rand.nextInt((high - low) + 1) + low;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves all n < pivot to the left of pivot and all n > pivot
|
||||||
|
* to the right of pivot, then returns the pivot index.
|
||||||
|
*
|
||||||
|
* @param arr
|
||||||
|
* @param low
|
||||||
|
* @param high
|
||||||
|
* @return pivot index
|
||||||
|
*/
|
||||||
|
private int partition(int[] arr, int low, int high) {
|
||||||
|
swap(arr, low, getPivot(low, high));
|
||||||
|
int border = low + 1;
|
||||||
|
for (int i = border; i <= high; i++) {
|
||||||
|
comparisons++;
|
||||||
|
if (arr[i] < arr[low]) {
|
||||||
|
comparisons++;
|
||||||
|
swap(arr, i, border++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
swap(arr, low, border - 1);
|
||||||
|
return border - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the count of comparisons made during the sorting process.
|
||||||
|
*
|
||||||
|
* @return The number of comparisons made during sorting.
|
||||||
|
*/
|
||||||
|
public int getComparisonCount() {
|
||||||
|
return comparisons;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package src.algorithms;
|
||||||
|
|
||||||
|
public class ShakerSort {
|
||||||
|
private int comparisons = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int[] arr, an array containing a permutation.
|
||||||
|
* @return the number of comparisons
|
||||||
|
*/
|
||||||
|
public void sort(int[] array) {
|
||||||
|
for (int i = 0; i < array.length / 2; i++) {
|
||||||
|
comparisons++;
|
||||||
|
boolean swapped = false;
|
||||||
|
for (int j = i; j < array.length - i - 1; j++) {
|
||||||
|
comparisons++;
|
||||||
|
if (array[j] > array[j + 1]) {
|
||||||
|
comparisons++;
|
||||||
|
int tmp = array[j];
|
||||||
|
array[j] = array[j + 1];
|
||||||
|
array[j + 1] = tmp;
|
||||||
|
swapped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j = array.length - 2 - i; j > i; j--) {
|
||||||
|
comparisons++;
|
||||||
|
if (array[j] < array[j - 1]) {
|
||||||
|
comparisons++;
|
||||||
|
int tmp = array[j];
|
||||||
|
array[j] = array[j - 1];
|
||||||
|
array[j - 1] = tmp;
|
||||||
|
swapped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!swapped)
|
||||||
|
comparisons++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the count of comparisons made during the sorting process.
|
||||||
|
*
|
||||||
|
* @return The number of comparisons made during sorting.
|
||||||
|
*/
|
||||||
|
public int getComparisonCount() {
|
||||||
|
return comparisons;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package src.utils;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `FileOutputUtil` class provides utility methods for writing content to files.
|
||||||
|
* @author Sean White
|
||||||
|
*/
|
||||||
|
public class FileOutputUtil {
|
||||||
|
/**
|
||||||
|
* Writes the provided content to a specified file inside the "results" directory.
|
||||||
|
*
|
||||||
|
* @param filename The name of the file to which the content will be written.
|
||||||
|
* @param content The content to write to the file.
|
||||||
|
* @throws IOException If any I/O error occurs.
|
||||||
|
*/
|
||||||
|
public static void writeToFile(String filename, String content) throws IOException {
|
||||||
|
// Ensure the "results" directory exists
|
||||||
|
File directory = new File("results");
|
||||||
|
if (!directory.exists()) {
|
||||||
|
directory.mkdir();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the file inside the "results" directory
|
||||||
|
File file = new File(directory, filename);
|
||||||
|
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||||
|
writer.write(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package src.utils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides functionality to generate all permutations of n integers in lexicographic (dictionary) order.
|
||||||
|
* The integers in each permutation range from 0 to n-1.
|
||||||
|
*
|
||||||
|
* @author Sean White
|
||||||
|
*
|
||||||
|
* <p><strong>Usage Example:</strong></p>
|
||||||
|
* <pre>
|
||||||
|
* {@code
|
||||||
|
* PermutationsGenerator generator = new PermutationsGenerator();
|
||||||
|
* int[][] permutationsFor3 = generator.generate(3);
|
||||||
|
* for (int[] permutation : permutationsFor3) {
|
||||||
|
* System.out.println(Arrays.toString(permutation));
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* The above code will generate and print all permutations for n=3 in lexicographic order:
|
||||||
|
* <pre>
|
||||||
|
* [0, 1, 2]
|
||||||
|
* [0, 2, 1]
|
||||||
|
* [1, 0, 2]
|
||||||
|
* [1, 2, 0]
|
||||||
|
* [2, 0, 1]
|
||||||
|
* [2, 1, 0]
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class PermutationsGenerator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates all permutations of n integers in lexicographic order.
|
||||||
|
*
|
||||||
|
* @param n The number of integers in each permutation.
|
||||||
|
* @return A 2D array where each row represents a permutation.
|
||||||
|
*/
|
||||||
|
public static int[][] generate(int n) {
|
||||||
|
List<int[]> results = new ArrayList<>();
|
||||||
|
|
||||||
|
// Initialize with the smallest permutation (i.e., [0, 1, 2, ..., n-1])
|
||||||
|
int[] current = new int[n];
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
current[i] = i;
|
||||||
|
}
|
||||||
|
results.add(current.clone());
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Identify the rightmost pair (i, i+1) where current[i] < current[i+1]
|
||||||
|
int i;
|
||||||
|
for (i = n - 2; i >= 0; i--) {
|
||||||
|
if (current[i] < current[i + 1]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If no such pair exists, we have generated all permutations
|
||||||
|
if (i == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identify the largest index j > i such that current[i] < current[j]
|
||||||
|
int j;
|
||||||
|
for (j = n - 1; j > i; j--) {
|
||||||
|
if (current[i] < current[j]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap elements at indices i and j
|
||||||
|
int temp = current[i];
|
||||||
|
current[i] = current[j];
|
||||||
|
current[j] = temp;
|
||||||
|
|
||||||
|
// Reverse the elements after index i to get the next permutation in lexicographic order
|
||||||
|
int start = i + 1, end = n - 1;
|
||||||
|
while (start < end) {
|
||||||
|
temp = current[start];
|
||||||
|
current[start] = current[end];
|
||||||
|
current[end] = temp;
|
||||||
|
start++;
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the new permutation
|
||||||
|
results.add(current.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the list of permutations to a 2D array for the final result
|
||||||
|
return results.toArray(new int[0][0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package src.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the result of sorting a permutation using an algorithm.
|
||||||
|
* This class encapsulates the original permutation (before sorting),
|
||||||
|
* the sorted permutation, and the number of comparisons made during sorting.
|
||||||
|
*
|
||||||
|
* <p><strong>Usage Example:</strong></p>
|
||||||
|
* <pre>
|
||||||
|
* {@code
|
||||||
|
* int[] original = {3, 1, 2};
|
||||||
|
* int[] sorted = {1, 2, 3};
|
||||||
|
* int comparisons = 2; // Typically obtained from the sorting algorithm
|
||||||
|
*
|
||||||
|
* Result result = new Result(original, sorted, comparisons);
|
||||||
|
* System.out.println("Original Array: " + Arrays.toString(result.getOriginalArray()));
|
||||||
|
* System.out.println("Sorted Array: " + Arrays.toString(result.getSortedArray()));
|
||||||
|
* System.out.println("Comparisons Made: " + result.getComparisons());
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* The above code will create a Result object and print:
|
||||||
|
* <pre>
|
||||||
|
* Original Array: [3, 1, 2]
|
||||||
|
* Sorted Array: [1, 2, 3]
|
||||||
|
* Comparisons Made: 2
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param originalArray The original permutation before sorting
|
||||||
|
* @param sortedArray The permutation after sorting
|
||||||
|
* @param comparisons The number of comparisons made during sorting
|
||||||
|
* @author Sean White
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Result {
|
||||||
|
|
||||||
|
int[] originalArray;
|
||||||
|
int[] sortedArray;
|
||||||
|
int comparisons;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an immutable Result object with the provided parameters.
|
||||||
|
*
|
||||||
|
* @param originalArray The original permutation before sorting
|
||||||
|
* @param sortedArray The permutation after sorting
|
||||||
|
* @param comparisons The number of comparisons made during sorting
|
||||||
|
*/
|
||||||
|
public Result(int[] originalArray, int[] sortedArray, int comparisons) {
|
||||||
|
this.originalArray = originalArray.clone(); // Create a defensive copy
|
||||||
|
this.sortedArray = sortedArray.clone(); // Create a defensive copy
|
||||||
|
this.comparisons = comparisons;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the original permutation before sorting.
|
||||||
|
*
|
||||||
|
* @return The original permutation
|
||||||
|
*/
|
||||||
|
public int[] originalArray() {
|
||||||
|
return originalArray.clone(); // Return a defensive copy
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the permutation after sorting.
|
||||||
|
*
|
||||||
|
* @return The sorted permutation
|
||||||
|
*/
|
||||||
|
public int[] sortedArray() {
|
||||||
|
return sortedArray.clone(); // Return a defensive copy
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the number of comparisons made during sorting.
|
||||||
|
*
|
||||||
|
* @return The number of comparisons
|
||||||
|
*/
|
||||||
|
public int comparisons() {
|
||||||
|
return comparisons;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
target
|
||||||
Generated
+75
@@ -0,0 +1,75 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cs2430-project2"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.149"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "cs2430-project2"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rand = "0.8.5"
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
### 1. Modules and Imports
|
||||||
|
|
||||||
|
```rust
|
||||||
|
mod multiset_operations;
|
||||||
|
mod set_operations;
|
||||||
|
|
||||||
|
use multiset_operations::MultiSet;
|
||||||
|
use set_operations::Set;
|
||||||
|
```
|
||||||
|
|
||||||
|
- `mod`: Declares a module. The actual code for the modules `multiset_operations` and `set_operations` is not shown, but they should be either in the same file or in `multiset_operations.rs` and `set_operations.rs` files respectively.
|
||||||
|
- `use`: Imports types or functions from a module into the current scope. Here, `MultiSet` and `Set` are imported.
|
||||||
|
|
||||||
|
### 2. Main Function
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `fn`: Keyword to define a new function.
|
||||||
|
- `main`: The entry point of a Rust program.
|
||||||
|
|
||||||
|
### 3. Variable Declaration and Initialization
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let a = Set::from_vec(vec![true, false, true, false, true, false, true, false, true, false]);
|
||||||
|
```
|
||||||
|
|
||||||
|
- `let`: Used for variable declaration.
|
||||||
|
- `Set::from_vec`: Calls a associated function (similar to a static method in other languages) named `from_vec` of the `Set` struct.
|
||||||
|
|
||||||
|
### 4. Mutable Variable Declaration
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut a_mult = MultiSet::from_vec(vec![3, 2, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
|
```
|
||||||
|
|
||||||
|
- `mut`: Indicates that the variable is mutable, i.e., its value can be changed.
|
||||||
|
|
||||||
|
### 5. Array/Vector Indexing
|
||||||
|
|
||||||
|
```rust
|
||||||
|
a_mult.elements[0] = 3;
|
||||||
|
```
|
||||||
|
|
||||||
|
- Elements in a vector/array can be accessed using the index.
|
||||||
|
|
||||||
|
### 6. Printing to Console
|
||||||
|
|
||||||
|
```rust
|
||||||
|
println!("Set A:");
|
||||||
|
```
|
||||||
|
|
||||||
|
- `println!`: A macro (not a function) to print to the console with a newline at the end.
|
||||||
|
|
||||||
|
### 7. Method Calls on Structs
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let not_a = a.complement();
|
||||||
|
```
|
||||||
|
|
||||||
|
- Methods are called on instances of structs using the dot notation.
|
||||||
|
|
||||||
|
### 8. Public Struct Declaration
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub struct Set {
|
||||||
|
pub elements: Vec<bool>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `pub`: A visibility modifier that makes the struct and its fields public.
|
||||||
|
- `struct`: Keyword to define a new structure.
|
||||||
|
- `Vec<bool>`: A vector of boolean values.
|
||||||
|
|
||||||
|
### 9. Implementing Methods for a Struct
|
||||||
|
|
||||||
|
```rust
|
||||||
|
impl Set {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `impl`: Begins an implementation block for methods of a struct.
|
||||||
|
|
||||||
|
### 10. Function Definitions with Parameters
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub fn union(&self, other: &Set) -> Set {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `&self`: A reference to the current instance of the struct (similar to `this` in other languages).
|
||||||
|
- `other: &Set`: A reference to another `Set` instance.
|
||||||
|
- `-> Set`: Indicates the return type of the function.
|
||||||
|
|
||||||
|
### 11. Iterating Over Collections
|
||||||
|
|
||||||
|
```rust
|
||||||
|
for &element in &self.elements {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `for`: Begins a for loop.
|
||||||
|
- `&element`: Pattern matching to destructure and get the value from the reference.
|
||||||
|
|
||||||
|
### 12. Printing with Format Specifiers
|
||||||
|
|
||||||
|
```rust
|
||||||
|
println!("Sum of elements in A: {}", a_mult.sum());
|
||||||
|
```
|
||||||
|
|
||||||
|
- `{}`: A placeholder that will be replaced by the value specified after the format string.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
mod multiset_operations;
|
||||||
|
mod set_operations;
|
||||||
|
|
||||||
|
use multiset_operations::MultiSet;
|
||||||
|
use set_operations::Set;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a = Set::from_vec(vec![
|
||||||
|
true, false, true, false, true, false, true, false, true, false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
let b = Set::from_vec(vec![
|
||||||
|
false, true, false, true, false, true, false, true, false, true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Multisets, where each element (ie. element 0, 1, 2) has a count
|
||||||
|
let a_mult = MultiSet::from_vec(vec![3, 2, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
|
let b_mult = MultiSet::from_vec(vec![0, 1, 4, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
|
|
||||||
|
println!("Set A:");
|
||||||
|
a.display();
|
||||||
|
println!("Set B:");
|
||||||
|
b.display();
|
||||||
|
|
||||||
|
// A and B sets together
|
||||||
|
let a_union_b = a.union(&b);
|
||||||
|
println!("A union B:");
|
||||||
|
a_union_b.display();
|
||||||
|
|
||||||
|
// The common elements between sets A and B.
|
||||||
|
let a_intersection_b = a.intersection(&b);
|
||||||
|
println!("A intersection B:");
|
||||||
|
a_intersection_b.display();
|
||||||
|
|
||||||
|
// Elements that are a part of set B are no longer a part of set A.
|
||||||
|
let a_difference_b = a.difference(&b);
|
||||||
|
println!("A difference B:");
|
||||||
|
a_difference_b.display();
|
||||||
|
|
||||||
|
// Remove the common elements from set A and B.
|
||||||
|
let a_symmetric_difference_b = a.symmetric_difference(&b);
|
||||||
|
println!("A symmetric difference B:");
|
||||||
|
a_symmetric_difference_b.display();
|
||||||
|
|
||||||
|
println!("MultiSet A:");
|
||||||
|
a_mult.display();
|
||||||
|
println!("MultiSet B:");
|
||||||
|
b_mult.display();
|
||||||
|
|
||||||
|
// Union of both multisets A and B
|
||||||
|
let a_union_b = a_mult.union(&b_mult);
|
||||||
|
println!("A union B:");
|
||||||
|
a_union_b.display();
|
||||||
|
|
||||||
|
// Common elements between multisets A and B
|
||||||
|
let a_intersection_b = a_mult.intersection(&b_mult);
|
||||||
|
println!("A intersection B:");
|
||||||
|
a_intersection_b.display();
|
||||||
|
|
||||||
|
// Removing any common elements of set B from set A
|
||||||
|
let a_difference_b = a_mult.difference(&b_mult);
|
||||||
|
println!("A difference B:");
|
||||||
|
a_difference_b.display();
|
||||||
|
|
||||||
|
println!("Sum of elements in A: {}", a_mult.sum());
|
||||||
|
println!("Sum of elements in B: {}", b_mult.sum());
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
pub struct MultiSet {
|
||||||
|
pub elements: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MultiSet {
|
||||||
|
pub fn from_vec(vec: Vec<usize>) -> Self {
|
||||||
|
MultiSet { elements: vec }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the combination of values between the two multisets.
|
||||||
|
pub fn union(&self, other: &MultiSet) -> MultiSet {
|
||||||
|
MultiSet {
|
||||||
|
elements: self
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.zip(&other.elements)
|
||||||
|
.map(|(&x, &y)| x + y)
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the minimum count of an element between two multisets.
|
||||||
|
pub fn intersection(&self, other: &MultiSet) -> MultiSet {
|
||||||
|
MultiSet {
|
||||||
|
elements: self
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.zip(&other.elements)
|
||||||
|
.map(|(&x, &y)| usize::min(x, y))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract the count of the element in multiset B from multiset A.
|
||||||
|
pub fn difference(&self, other: &MultiSet) -> MultiSet {
|
||||||
|
MultiSet {
|
||||||
|
elements: self
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.zip(&other.elements)
|
||||||
|
.map(|(&x, &y)| if x > y { x - y } else { 0 })
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the count of the elements between two multisets
|
||||||
|
pub fn sum(&self) -> usize {
|
||||||
|
self.elements.iter().sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
// List each element value and the count of that element.
|
||||||
|
pub fn display(&self) {
|
||||||
|
for (index, &count) in self.elements.iter().enumerate() {
|
||||||
|
println!("Element {index}: Count {count}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
pub struct Set {
|
||||||
|
pub elements: Vec<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Set {
|
||||||
|
pub fn from_vec(vec: Vec<bool>) -> Self {
|
||||||
|
Self { elements: vec }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine sets A and B.
|
||||||
|
pub fn union(&self, other: &Set) -> Set {
|
||||||
|
Set {
|
||||||
|
elements: self
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.zip(&other.elements)
|
||||||
|
.map(|(&x, &y)| x || y)
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the shared values between sets A and B.
|
||||||
|
pub fn intersection(&self, other: &Set) -> Set {
|
||||||
|
Set {
|
||||||
|
elements: self
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.zip(&other.elements)
|
||||||
|
.map(|(&x, &y)| x && y)
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the set where set A has no ocommon elements with set B.
|
||||||
|
pub fn difference(&self, other: &Set) -> Set {
|
||||||
|
Set {
|
||||||
|
elements: self
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.zip(&other.elements)
|
||||||
|
.map(|(&x, &y)| x && !y)
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the union of A diff B and B diff A between two sets.
|
||||||
|
pub fn symmetric_difference(&self, other: &Set) -> Set {
|
||||||
|
let a_minus_b = self.difference(other);
|
||||||
|
let b_minus_a = other.difference(self);
|
||||||
|
a_minus_b.union(&b_minus_a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format and display the set.
|
||||||
|
pub fn display(&self) {
|
||||||
|
for &element in &self.elements {
|
||||||
|
print!("{}", if element { 1 } else { 0 })
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class App {
|
||||||
|
private static int W = 700;
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Experiment[] e = {
|
||||||
|
new Experiment(1, "Cloud Patterns", 36, 5),
|
||||||
|
new Experiment(2, "Solar Flares", 264, 9),
|
||||||
|
new Experiment(3, "Solar Power", 188, 6),
|
||||||
|
new Experiment(4, "Binary Stars", 203, 8),
|
||||||
|
new Experiment(5, "Relativity", 104, 8),
|
||||||
|
new Experiment(6, "Seed Viability", 7, 4),
|
||||||
|
new Experiment(7, "Sun Spots", 90, 2),
|
||||||
|
new Experiment(8, "Mice Tumors", 65, 8),
|
||||||
|
new Experiment(9, "Microgravity Plant Growth", 75, 5),
|
||||||
|
new Experiment(10, "Micrometeorites", 170, 9),
|
||||||
|
new Experiment(11, "Cosmic Rays", 80, 7),
|
||||||
|
new Experiment(12, "Yeast Fermentation", 27, 4)
|
||||||
|
};
|
||||||
|
|
||||||
|
System.out.println("\n\nSorted by weight:");
|
||||||
|
sortByWeight(e, e.length);
|
||||||
|
printArr(e);
|
||||||
|
sortById(e, e.length);
|
||||||
|
|
||||||
|
System.out.println("\n\nSorted by rating:");
|
||||||
|
sortByRating(e, e.length);
|
||||||
|
printArr(e);
|
||||||
|
sortById(e, e.length);
|
||||||
|
|
||||||
|
System.out.println("\n\nSorted by ratio:");
|
||||||
|
sortByRatio(e, e.length);
|
||||||
|
printArr(e);
|
||||||
|
sortById(e, e.length);
|
||||||
|
|
||||||
|
System.out.println("\n\nDynamic programming approach: ");
|
||||||
|
int n = e.length;
|
||||||
|
int[][] combinations = new int[n + 1][W + 1];
|
||||||
|
boolean[][] included = new boolean[n + 1][W + 1];
|
||||||
|
|
||||||
|
// fill the combinations table
|
||||||
|
for (int i = 1; i <= n; i++) {
|
||||||
|
for (int j = 1; j <= W; j++) {
|
||||||
|
if (e[i - 1].getWeight() > j) {
|
||||||
|
combinations[i][j] = combinations[i - 1][j];
|
||||||
|
} else {
|
||||||
|
int withoutI = combinations[i - 1][j];
|
||||||
|
int withI = e[i - 1].getRating() + combinations[i - 1][j - e[i - 1].getWeight()];
|
||||||
|
if (withI > withoutI) {
|
||||||
|
combinations[i][j] = withI;
|
||||||
|
included[i][j] = true;
|
||||||
|
} else {
|
||||||
|
combinations[i][j] = withoutI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the items included in the optimal solution
|
||||||
|
List<Integer> indices = new ArrayList<>();
|
||||||
|
int remainingW = W;
|
||||||
|
for (int i = n; i >= 1; i--) {
|
||||||
|
if (included[i][remainingW]) {
|
||||||
|
indices.add(i - 1);
|
||||||
|
remainingW -= e[i - 1].getWeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.reverse(indices);
|
||||||
|
|
||||||
|
// print out the results
|
||||||
|
System.out.println("max rating: " + combinations[n][W]);
|
||||||
|
System.out.println("items included: ");
|
||||||
|
|
||||||
|
int weight = 0;
|
||||||
|
int rating = 0;
|
||||||
|
for (int i: indices) {
|
||||||
|
System.out.println(e[i]);
|
||||||
|
weight += e[i].getWeight();
|
||||||
|
rating += e[i].getRating();
|
||||||
|
}
|
||||||
|
System.out.println("Total rating: " + rating + ", total weight: " + weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printArr(Experiment[] arr) {
|
||||||
|
int weight = 0;
|
||||||
|
int rating = 0;
|
||||||
|
for (Experiment e : arr) {
|
||||||
|
if(!(weight + e.getWeight() > W)) {
|
||||||
|
System.out.println(e);
|
||||||
|
weight += e.getWeight();
|
||||||
|
rating += e.getRating();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Total rating: " + rating + ", total weight: " + weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sortByWeight(Experiment[] arr, int n) {
|
||||||
|
// base case
|
||||||
|
if (n == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// one pass through the array to move the largest unsorted element to the end
|
||||||
|
for (int i = 0; i < n - 1; i++) {
|
||||||
|
if (arr[i].getWeight() > arr[i + 1].getWeight()) {
|
||||||
|
// swap arr[i] and arr[i+1]
|
||||||
|
Experiment temp = arr[i];
|
||||||
|
arr[i] = arr[i + 1];
|
||||||
|
arr[i + 1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursive call with n-1
|
||||||
|
sortByWeight(arr, n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sortByRating(Experiment[] arr, int n) {
|
||||||
|
// base case
|
||||||
|
if (n == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// one pass through the array to move the largest unsorted element to the end
|
||||||
|
for (int i = 0; i < n - 1; i++) {
|
||||||
|
if (arr[i].getRating() > arr[i + 1].getRating()) {
|
||||||
|
// swap arr[i] and arr[i+1]
|
||||||
|
Experiment temp = arr[i];
|
||||||
|
arr[i] = arr[i + 1];
|
||||||
|
arr[i + 1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursive call with n-1
|
||||||
|
sortByRating(arr, n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sortByRatio(Experiment[] arr, int n) {
|
||||||
|
// base case
|
||||||
|
if (n == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// one pass through the array to move the largest unsorted element to the end
|
||||||
|
for (int i = 0; i < n - 1; i++) {
|
||||||
|
if (arr[i].getRatio() > arr[i + 1].getRatio()) {
|
||||||
|
// swap arr[i] and arr[i+1]
|
||||||
|
Experiment temp = arr[i];
|
||||||
|
arr[i] = arr[i + 1];
|
||||||
|
arr[i + 1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursive call with n-1
|
||||||
|
sortByRatio(arr, n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sortById(Experiment[] arr, int n) {
|
||||||
|
// base case
|
||||||
|
if (n == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// one pass through the array to move the largest unsorted element to the end
|
||||||
|
for (int i = 0; i < n - 1; i++) {
|
||||||
|
if (arr[i].getId() > arr[i + 1].getId()) {
|
||||||
|
// swap arr[i] and arr[i+1]
|
||||||
|
Experiment temp = arr[i];
|
||||||
|
arr[i] = arr[i + 1];
|
||||||
|
arr[i + 1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursive call with n-1
|
||||||
|
sortById(arr, n - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
public class Experiment {
|
||||||
|
private int id;
|
||||||
|
private String name;
|
||||||
|
private int weight;
|
||||||
|
private int rating;
|
||||||
|
private double ratio;
|
||||||
|
|
||||||
|
public Experiment(int id, String name, int weight, int rating) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.weight = weight;
|
||||||
|
this.rating = rating;
|
||||||
|
this.ratio = weight / rating;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWeight() {
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRating() {
|
||||||
|
return rating;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getRatio() {
|
||||||
|
return ratio; // TODO: need to calculate ratio.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("[%d, %s, %dkg, %d]", id, name, weight, rating);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user