├── ArrayDemo.java ├── ArraySearchDemo.java ├── Barnyard.java ├── BigComplex.java ├── BigHamming.java ├── BigPrimes.java ├── BloomFilter.java ├── CCPS 209 Course Notes.pdf ├── CCPS 209 Modules.pdf ├── CardExamples.java ├── ChatClient.java ├── ChatServer.java ├── CollectionsDemo.java ├── ConcurrencyDemo.java ├── ConditionsAndLoops.java ├── ContinuedFraction.java ├── Counter.java ├── DLA.java ├── DataDemo.java ├── DissociatedPress.java ├── ElementaryCellular.java ├── EnumDemo.java ├── ExceptionDemo.java ├── FJMergeSort.java ├── FirstBatch.java ├── FloydSteinberg.java ├── Fraction.java ├── GZip.java ├── GameOfLife.java ├── GenericsDemo.java ├── Greeter.java ├── HammingTriple.java ├── ImageDemo.java ├── ImageLoops.java ├── ImageOpsDemo.java ├── InheritanceDemo.java ├── Java5Demo.java ├── LICENSE ├── Length.java ├── LinePrinter.java ├── Mandelbrot.java ├── MapReduceDemo.java ├── Minesweeper.java ├── MoreLoopExamples.java ├── MySemaphore.java ├── NatSet.java ├── NestedDemo.java ├── Overload.java ├── Pair.java ├── ParameterDemo.java ├── PythonToJava.java ├── README.md ├── Recursion.java ├── ReflectionDemo.java ├── Reverserver.java ├── SecondBatch.java ├── ShapePanel.java ├── Shlemiel.java ├── ShortHamming.java ├── Sierpinski.java ├── Sliders.java ├── SomeUnixCommands.java ├── SpaceFiller.java ├── StringExamples.java ├── TakeUntil.java ├── WordFrequency.java ├── WordTransform.java ├── coffee.jpg ├── flappy.png └── package.bluej /ArraySearchDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Demonstrate the basic array searching algorithms. 3 | * @author Ilkka Kokkarinen 4 | */ 5 | 6 | public class ArraySearchDemo { 7 | 8 | /** 9 | * Unoptimized linear search. 10 | * @param a The array to search the value in. 11 | * @param x The element to search for. 12 | * @return The first index in which the element is found, 13 | * or -1 if that element does not exist in the array. 14 | */ 15 | public int linearSearch(int[] a, int x) { 16 | int i = 0; 17 | while(i < a.length && a[i] != x) { i++; } 18 | return i < a.length ? i : -1; 19 | } 20 | 21 | /** 22 | * Sentinel search optimizes away one comparison per array element. 23 | * @param a The array to search the value in. 24 | * @param x The element to search for. 25 | * @return The first index in which the element is found, 26 | * or -1 if that element does not exist in the array. 27 | */ 28 | public int sentinelSearch(int[] a, int x) { 29 | int last = a[a.length - 1]; 30 | a[a.length - 1] = x; 31 | int i = 0; 32 | while(a[i] != x) { i++; } 33 | a[a.length - 1] = last; 34 | return (i < a.length - 1 || last == x) ? i : -1; 35 | } 36 | 37 | /** 38 | * Unrolled search to halve the number of bounds checks. 39 | * @param a The array to search the value in. 40 | * @param x The element to search for. 41 | * @return The first index in which the element is found, 42 | * or -1 if that element does not exist in the array. 43 | */ 44 | public int unrolledSearch(int[] a, int x) { 45 | int i = 0; 46 | if(a.length % 2 == 1) { // odd man out 47 | if(a[i++] == x) { return 0; } 48 | } 49 | while(i < a.length) { 50 | if(a[i++] == x) { return i - 1; } 51 | if(a[i++] == x) { return i - 1; } 52 | } 53 | return -1; 54 | } 55 | 56 | /** 57 | * The classic binary search for sorted arrays. 58 | * @param a The array to search the value in. 59 | * @param x The element to search for. 60 | * @return The first index in which the element is found. If the element 61 | * {@code x} is not found, returns the index where that element would go 62 | * to keep array in sorted order. If {@code x} is larger than the current 63 | * largest element of the array, returns {@code a.length} as special case. 64 | */ 65 | // Binary search for sorted arrays. 66 | public int binarySearch(int[] a, int x) { 67 | int i = 0, j = a.length - 1; 68 | if(a[j] < x) { return a.length; } // special case 69 | while(i < j) { 70 | int mid = (i+j) / 2; 71 | if(a[mid] < x) { i = mid + 1; } 72 | else { j = mid; } 73 | } 74 | return i; 75 | } 76 | } -------------------------------------------------------------------------------- /Barnyard.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.Random; 3 | 4 | public class Barnyard { 5 | 6 | // The cliched first example of inheritance, akin to factorial for recursion or 7 | // that "output a rectangle of asterisks" for loops. But there is a reason why 8 | // every cliche became a cliche in the first place. For convenience, all classes 9 | // are given here as static nested classes, but they might as well be separate 10 | // top level classes. 11 | 12 | // An abstract superclass that defines the common behaviour of each animal. 13 | // Cannot be used to create objects, but serves as abstract parameter type for 14 | // polymorphic methods that works for all animals. 15 | 16 | public abstract static class Animal { 17 | private static int count = 0; // counter shared by all animals 18 | public static int getCount() { return count; } 19 | 20 | public Animal() { 21 | System.out.println("Default constructor of Animal"); // for educational purposes 22 | count++; 23 | } 24 | 25 | // Methods we wish to impose on all future subclasses, but cannot at this level 26 | // be given a meaningful implementation, are declared abstract. 27 | public abstract String getSound(); 28 | public abstract String getSpecies(); 29 | 30 | // All species of animals have same implementation of toString. 31 | @Override final public String toString() { 32 | return this.getSpecies() + " that says " + this.getSound(); 33 | } 34 | } 35 | 36 | // A concrete subclass of the previous abstract superclass. 37 | public static class Cat extends Animal { 38 | private static final Random rng = new Random(); 39 | public Cat() { 40 | System.out.println("Default constructor of Cat"); 41 | } 42 | 43 | @Override public String getSound() { 44 | return rng.nextInt(100) < 50? "meow": "purrrr"; 45 | } 46 | @Override public String getSpecies() { 47 | return "cat"; 48 | } 49 | } 50 | 51 | // A subclass can also be itself abstract. 52 | public abstract static class Bird extends Animal { 53 | public Bird() { 54 | System.out.println("Default constructor of Bird"); 55 | } 56 | 57 | // Define new subclass methods that don't exist in the superclass. 58 | public abstract void fly(); 59 | } 60 | 61 | // Two concrete subclasses of Bird. 62 | public static class Chicken extends Bird { 63 | public Chicken() { 64 | System.out.println("Default constructor of Chicken"); 65 | } 66 | @Override public String getSound() { return "cluck"; } 67 | @Override public String getSpecies() { return "chicken"; } 68 | @Override public void fly() { 69 | System.out.println("The chicken flaps its wings without much success."); 70 | } 71 | } 72 | 73 | public static class Goose extends Bird { 74 | public Goose() { 75 | System.out.println("Default constructor of Goose"); 76 | } 77 | @Override public String getSound() { return "honk"; } 78 | @Override public String getSpecies() { return "goose"; } 79 | @Override public void fly() { 80 | System.out.println("The goose soars majestically to the skies."); 81 | } 82 | } 83 | 84 | // The power of inheritance hierarchies comes from the ability to write 85 | // polymorphic methods in accordance to the DRY principle. The same method, 86 | // written once, works for any subtype of its parameter type in the future. 87 | 88 | public static void flyMultipleTimes(Bird b, int n) { 89 | for(int i = 0; i < n; i++) { 90 | b.fly(); // dynamically bound method call 91 | } 92 | } 93 | 94 | public static void outputSounds(Animal[] as) { 95 | for(Animal a: as) { 96 | System.out.println(a.getSound()); 97 | } 98 | } 99 | 100 | // A decorator subclass of Animal. Every decorator object contains a private 101 | // reference to the underlying client object, and defines all its methods to 102 | // first consult the client and then modify the answer returned. 103 | 104 | public static class LoudAnimal extends Animal { 105 | private final Animal client; 106 | public LoudAnimal(Animal client) { 107 | this.client = client; 108 | System.out.println("Constructor of LoudAnimal with " + client); 109 | } 110 | @Override public String getSound() { 111 | return client.getSound().toUpperCase(); 112 | } 113 | @Override public String getSpecies() { 114 | return "loud " + client.getSpecies(); 115 | } 116 | } 117 | 118 | // Another decorator subclass with the same idea. 119 | public static class MirroredAnimal extends Animal { 120 | private final Animal client; 121 | public MirroredAnimal(Animal client) { 122 | this.client = client; 123 | System.out.println("Constructor of MirroredAnimal with " + client); 124 | } 125 | @Override public String getSound() { 126 | // Canonical way to reverse a String in Java is through a StringBuilder. 127 | return new StringBuilder(client.getSound()).reverse().toString(); 128 | } 129 | @Override public String getSpecies() { 130 | return "mirrored " + client.getSpecies(); 131 | } 132 | } 133 | 134 | // Once more, with a feeling. 135 | public static class AngryAnimal extends Animal { 136 | private final Animal client; 137 | public AngryAnimal(Animal client) { 138 | this.client = client; 139 | System.out.println("Constructor of AngryAnimal with " + client); 140 | } 141 | @Override public String getSound() { 142 | return "grrr " + client.getSound() + " hisss!"; 143 | } 144 | @Override public String getSpecies() { 145 | return "angry " + client.getSpecies(); 146 | } 147 | } 148 | 149 | // To avoid code duplication in decorators, it might be a good idea to define an 150 | // abstract superclass AnimalDecorator to take care of this boilerplate. The 151 | // subclasses would then override precisely those methods for which that type 152 | // of decorator provides some additional service. 153 | 154 | // A main method for demonstration and educational purposes. 155 | public static void main(String[] args) { 156 | Animal a1 = new Goose(); 157 | System.out.println("Our first animal is " + a1 + "."); 158 | // a1.fly() would not compile, make sure you understand why 159 | flyMultipleTimes(new Chicken(), 3); // calling the polymorphic method 160 | flyMultipleTimes(new Goose(), 2); // calling the polymorphic method 161 | 162 | Animal[] as = { 163 | new MirroredAnimal(new Goose()), 164 | new MirroredAnimal(new LoudAnimal(new Chicken())), 165 | // The order of otherwise same decorators may affect the behaviour. 166 | new AngryAnimal(new LoudAnimal(new Cat())), 167 | new LoudAnimal(new AngryAnimal(new Cat())) 168 | }; 169 | System.out.println(Arrays.toString(as)); 170 | System.out.println("Let's hear the sounds that these creatures make: "); 171 | outputSounds(as); 172 | } 173 | } -------------------------------------------------------------------------------- /BigComplex.java: -------------------------------------------------------------------------------- 1 | import java.math.BigDecimal; 2 | import java.math.MathContext; 3 | 4 | // Complex number arithmetic using BigDecimal components for real and imaginary 5 | // parts of the number. 6 | 7 | public class BigComplex { 8 | 9 | private static final int INITPRECISION = 10; 10 | public static MathContext mc = new MathContext(INITPRECISION); 11 | public static final BigComplex ZERO = new BigComplex(0, 0); 12 | public static final BigComplex ONE = new BigComplex(1, 0); 13 | public static final BigComplex I = new BigComplex(0, 1); 14 | 15 | // A complex number consists of real and imaginary parts. 16 | private final BigDecimal re; 17 | private final BigDecimal im; 18 | 19 | public BigComplex(double re, double im) { 20 | this.re = new BigDecimal(re, mc); 21 | this.im = new BigDecimal(im, mc); 22 | } 23 | 24 | public BigComplex(BigDecimal re, BigDecimal im) { 25 | this.re = re; this.im = im; 26 | } 27 | 28 | public BigDecimal getRe() { return re; } 29 | public BigDecimal getIm() { return im; } 30 | 31 | public BigComplex add(BigComplex other) { 32 | return new BigComplex(this.re.add(other.re, mc), this.im.add(other.im, mc)); 33 | } 34 | 35 | public BigComplex subtract(BigComplex other) { 36 | return new BigComplex(this.re.subtract(other.re, mc), this.im.subtract(other.im, mc)); 37 | } 38 | 39 | public BigComplex multiply(BigComplex other) { 40 | BigDecimal r1 = this.re.multiply(other.re, mc); 41 | BigDecimal r2 = this.im.multiply(other.im, mc); 42 | BigDecimal i1 = this.im.multiply(other.re, mc); 43 | BigDecimal i2 = other.im.multiply(this.re, mc); 44 | return new BigComplex(r1.subtract(r2, mc), i1.add(i2, mc)); 45 | } 46 | 47 | public BigDecimal getAbsSq() { 48 | return this.re.multiply(this.re, mc).add(this.im.multiply(this.im, mc), mc); 49 | } 50 | 51 | public String toString() { 52 | if(this.im.compareTo(BigDecimal.ZERO) >= 0) { 53 | return "(" + this.re + "+" + this.im + "i)"; 54 | } 55 | else { 56 | return "(" + this.re + "" + this.im + "i)"; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /BigHamming.java: -------------------------------------------------------------------------------- 1 | import java.math.BigInteger; 2 | import java.util.HashSet; 3 | import java.util.PriorityQueue; 4 | 5 | /** 6 | * Compute the {code n}:th Hamming number by generating Hamming numbers in a priority queue. 7 | * @author Ilkka Kokkarinen 8 | */ 9 | 10 | public class BigHamming { 11 | 12 | private static final BigInteger[] muls = { 13 | BigInteger.valueOf(2), BigInteger.valueOf(3), BigInteger.valueOf(5) 14 | }; 15 | 16 | /** 17 | * Compute the {@code n}:th Hamming number, with quiet operation. 18 | * @param n The index of the Hammin number to compute. 19 | */ 20 | public BigInteger computeHamming(int n) { 21 | return computeHamming(n, false); 22 | } 23 | 24 | /** 25 | * Compute the {@code n}:th Hamming number. 26 | * @param n The index of the Hamming number to compute. 27 | * @param verbose Whether the method should output the number and timing statistics. 28 | * @return The {code n}:th Hamming number. 29 | */ 30 | public static BigInteger computeHamming(int n, boolean verbose) { 31 | long startTime = System.currentTimeMillis(); 32 | // The elements of the search frontier 33 | PriorityQueue frontierQ = new PriorityQueue<>(); 34 | HashSet frontierS = new HashSet<>(); 35 | 36 | // Initialize the frontier 37 | frontierQ.offer(BigInteger.ONE); 38 | frontierS.add(BigInteger.ONE); 39 | 40 | // Invariant: we have generated all Hamming numbers up to the smallest 41 | // element in the frontier. 42 | while(true) { 43 | // Pop out the next Hamming number from the frontier 44 | BigInteger curr = frontierQ.poll(); 45 | frontierS.remove(curr); 46 | //System.out.println(curr); 47 | if(--n == 0) { 48 | if(verbose) { 49 | System.out.println("Time: " + (System.currentTimeMillis() - startTime) + " ms"); 50 | System.out.println("Result: " + curr); 51 | } 52 | return curr; 53 | } 54 | // Generate the next three numbers to the search frontier 55 | for(BigInteger e : muls) { 56 | assert curr != null; 57 | BigInteger newB = curr.multiply(e); 58 | if(!frontierS.contains(newB)) { 59 | frontierQ.offer(newB); 60 | frontierS.add(newB); 61 | } 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /BloomFilter.java: -------------------------------------------------------------------------------- 1 | import java.util.HashSet; 2 | import java.util.Random; 3 | import java.util.Set; 4 | import java.util.function.Function; 5 | 6 | // A probabilistic monotonic set that is extremely space efficient even for large n, 7 | // but allows for a small chance of false positives. False negatives are impossible. 8 | // This is good enough for many practical applications of such a space-efficient set. 9 | 10 | public class BloomFilter { 11 | 12 | // Needed to randomly initialize the parameters as and bs. 13 | private static final Random rng = new Random(); 14 | 15 | // Family of multiplicative hash functions h(x) = (a*x + b) % M 16 | private final int[] as; 17 | private final int[] bs; 18 | private final boolean[] bits; 19 | 20 | // Function to convert element into an integer. If null, the result of 21 | // calling the method hashCode() is used instead. 22 | private final Function conv; 23 | 24 | /** 25 | * Constructor to initialize the Bloom filter. 26 | * @param k The number of hash functions to use. 27 | * @param m The number of bits to use to store the element hashes. 28 | * @param conv The function to convert each element into an integer. 29 | */ 30 | public BloomFilter(int k, int m, Function conv) { 31 | this.conv = conv; 32 | bits = new boolean[m]; 33 | as = new int[k]; 34 | bs = new int[k]; 35 | for(int i = 0; i < k; i++) { 36 | as[i] = rng.nextInt(); 37 | bs[i] = rng.nextInt(); 38 | } 39 | } 40 | 41 | public BloomFilter(int k, int m) { this(k, m, null); } 42 | 43 | /** 44 | * Add the given element to this Bloom filter. 45 | * @param elem The new element to be added. 46 | */ 47 | public void add(E elem) { 48 | int h = conv == null ? elem.hashCode() : conv.apply(elem); 49 | for(int i = 0; i < as.length; i++) { 50 | bits[Math.abs(as[i] * h + bs[i]) % bits.length] = true; 51 | } 52 | } 53 | 54 | /** 55 | * Check if the given element has been added to this Bloom filter. 56 | * @param elem The element to search for. 57 | * @return Whether the element is currently in this Bloom filter. 58 | */ 59 | public boolean probablyContains(E elem) { 60 | int h = conv == null ? elem.hashCode() : conv.apply(elem); 61 | for(int i = 0; i < as.length; i++) { 62 | if(!bits[Math.abs(as[i] * h + bs[i]) % bits.length]) { 63 | return false; // negative answer is guaranteed correct 64 | } 65 | } 66 | return true; // true with high probability 67 | } 68 | 69 | // A utility method needed for the demonstration done in the main method. 70 | private static String createWord(Set already) { 71 | StringBuilder word; 72 | do { 73 | word = new StringBuilder(); 74 | int len = rng.nextInt(10) + 2; 75 | for(int j = 0; j < len; j++) { 76 | word.append((char) ('a' + rng.nextInt(26))); 77 | } 78 | } while(already.contains(word.toString())); 79 | return word.toString(); 80 | } 81 | 82 | // For amusement and demonstration purposes. 83 | public static void main(String[] args) { 84 | // Our Bloom filter uses 128 kilobytes (plus some spare change) to store 85 | // the bits, the size of element type E makes no difference to anything. 86 | // Also try out how changing k and m affects the false positive percentage. 87 | BloomFilter wordBloom = new BloomFilter<>(20, 128 * 1024 * 8); 88 | // The hash set will take a lot more memory than 128 kb to store the same 89 | // strings in the 100% accurately retrievable and exact fashion. 90 | HashSet wordHash = new HashSet<>(); 91 | 92 | // Populate both collections with the same set of randomly created "words". 93 | for(int i = 0; i < 50000; i++) { 94 | String word = createWord(wordHash); 95 | wordBloom.add(word); 96 | wordHash.add(word); 97 | } 98 | // Just to make sure that our filter works, check that it says yes to all added words. 99 | for(String word: wordHash) { 100 | if(!wordBloom.probablyContains(word)) { 101 | System.out.println("Bloom filter implementation is broken!"); 102 | return; 103 | } 104 | } 105 | 106 | // Create one million random "words" that are different from our earlier words, and 107 | // count for how many of those new words our Bloom filter returns a false positive. 108 | int falsePosCount = 0; 109 | for(int i = 0; i < 1000000; i++) { 110 | String word = createWord(wordHash); 111 | if(wordBloom.probablyContains(word)) { falsePosCount++; } 112 | } 113 | double falsePosProb = falsePosCount / 1000000.0; 114 | System.out.printf("Got %d false positives out of one million words, so P(posAns | neg) = %.6f.\n", 115 | falsePosCount, falsePosProb); 116 | } 117 | } -------------------------------------------------------------------------------- /CCPS 209 Course Notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikokkari/JavaExamples/4f53574d0c3515c2468a87933ee058b364191b87/CCPS 209 Course Notes.pdf -------------------------------------------------------------------------------- /CCPS 209 Modules.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikokkari/JavaExamples/4f53574d0c3515c2468a87933ee058b364191b87/CCPS 209 Modules.pdf -------------------------------------------------------------------------------- /CardExamples.java: -------------------------------------------------------------------------------- 1 | import java.util.Random; 2 | 3 | public class CardExamples { 4 | 5 | // A private utility method to convert a card character to its numerical value. 6 | // Could have also been written longer as an if-else ladder, which would be 7 | // better if the parameter were not guaranteed to be a legal rank. 8 | private static int getRank(char c) { 9 | return 2 + "23456789TJQKA".indexOf(c); // clever String method to use 10 | } 11 | 12 | /** 13 | * Compute and return the numerical rank of the highest card in the hand. 14 | * @param hand The hand of cards to analyze. 15 | * @return The numerical rank of the highest card in the hand. 16 | */ 17 | public static int highestRank(String hand) { 18 | int highest = 0; 19 | for(int i = 0; i < hand.length(); i += 2) { 20 | int rank = getRank(hand.charAt(i)); 21 | if(rank > highest) { highest = rank; } 22 | } 23 | return highest; 24 | } 25 | 26 | /** 27 | * Create a random hand of cards so that no card can be repeated. Useful for 28 | * JUnit tester methods to try out other card methods with random hands. 29 | * @param rng The random number generator to use. 30 | * @param len Number of cards in the hand to create. 31 | * @return The hand of cards as string. 32 | */ 33 | private static String createHand(Random rng, int len) { 34 | StringBuilder result = new StringBuilder(); 35 | for(int i = 0; i < len; i++) { 36 | String card; 37 | outer: 38 | while(true) { 39 | // Create a random card. 40 | card = "" + "23456789TJQKA".charAt(rng.nextInt(13)); 41 | card += "cdhs".charAt(rng.nextInt(4)); 42 | // Verify that the result does not contain that card already. 43 | for(int j = 0; j < result.length(); j += 2) { 44 | if(result.substring(j, j + 2).equals(card)) { continue outer; } 45 | } 46 | break; 47 | } 48 | result.append(card); 49 | } 50 | return result.toString(); 51 | } 52 | 53 | // A private utility method to convert a card character to its blackjack value. 54 | private static int blackjackValue(char c) { 55 | int idx = getRank(c); 56 | if(idx > 10 && idx < 14) { idx = 10; } // all faces are counted as 10 57 | if(idx == 14) { idx = 11; } // aces are 11's in blackjack for now 58 | return idx; 59 | } 60 | 61 | /** 62 | * Given a blackjack hand as a string (as in the labs), compute its 63 | * value and return it as a string. If the value is greater than 21, 64 | * return "bust" regardless of value. If the first two cards are 65 | * equal to 21, return "blackjack". Otherwise, return the value as 66 | * number preceded by either "soft" or "hard" depending on whether 67 | * the hand has an ace that was counted as 11 instead of 1. 68 | * @param hand The blackjack hand to analyze. 69 | * @return The value of the hand. 70 | */ 71 | public static String blackjackCount(String hand) { 72 | int count = 0; 73 | int soft = 0; // how many soft aces there are in the hand 74 | for(int i = 0; i < hand.length(); i += 2) { // suits don't matter 75 | int p = blackjackValue(hand.charAt(i)); // numerical value of this card 76 | count += p; 77 | if(p == 11) { soft++; } 78 | if(count > 21) { 79 | if(soft > 0) { // saved from the bust by the soft ace 80 | soft--; count -= 10; 81 | } 82 | else { return "bust"; } 83 | } 84 | } 85 | if(hand.length() == 4 && count == 21) { return "blackjack"; } 86 | return (soft > 0 ? "soft " : "hard ") + count; 87 | } 88 | 89 | /** 90 | * Given a five-card poker hand as string, determine if it contains a 91 | * straight, that is, five cards of consecutive ranks. Also, an ace can 92 | * be either low or high, for the possible straights A2345 and TJQKA. 93 | * For simplicity, we ignore the possibility of straight flushes. 94 | * @param hand The poker hand given as a string. 95 | * @return Whether the poker hand is a straight. 96 | */ 97 | public static boolean hasStraight(String hand) { 98 | int min = 20, max = 0; 99 | int aceCount = 0; 100 | // Find the highest and lower ranks of cards in this hand separately 101 | // from aces, and also count the number of aces along the way. 102 | for(int i = 0; i < 10; i += 2) { 103 | int rank = getRank(hand.charAt(i)); 104 | if(rank == 14) { aceCount++; } 105 | if(rank < 14 && rank < min) { min = rank; } 106 | if(rank < 14 && rank > max) { max = rank; } 107 | } 108 | // Quick rejection of many cases that cannot be a straight. 109 | if(aceCount > 1) { return false; } 110 | if(aceCount == 0 && max - min != 4) { return false; } 111 | if(aceCount == 1) { 112 | if(max == 5) { min = 2; } 113 | else if(min == 10) { max = 13; } 114 | else { return false; } 115 | } 116 | // Verify that hand contains each rank between min and max. 117 | for(int r = min; r <= max; r++) { 118 | boolean containsRank = false; 119 | for(int i = 0; i < 10; i += 2) { 120 | char c = hand.charAt(i); 121 | if(getRank(c) == r) { containsRank = true; break; } 122 | } 123 | if(!containsRank) { return false; } 124 | } 125 | return true; 126 | } 127 | } -------------------------------------------------------------------------------- /ChatClient.java: -------------------------------------------------------------------------------- 1 | import javax.swing.JButton; 2 | import javax.swing.JFrame; 3 | import javax.swing.JPanel; 4 | import javax.swing.JScrollPane; 5 | import javax.swing.JTextArea; 6 | import javax.swing.JTextField; 7 | import java.awt.BorderLayout; 8 | import java.awt.Dimension; 9 | import java.awt.event.WindowAdapter; 10 | import java.awt.event.WindowEvent; 11 | import java.io.IOException; 12 | import java.net.DatagramPacket; 13 | import java.net.DatagramSocket; 14 | import java.net.InetAddress; 15 | import java.net.SocketTimeoutException; 16 | import java.util.concurrent.ExecutorService; 17 | import java.util.concurrent.Executors; 18 | 19 | public class ChatClient extends JFrame { 20 | 21 | private static final int PACKET_SIZE = 512; 22 | private DatagramPacket receivedPacket; 23 | private DatagramPacket sentPacket; 24 | private DatagramSocket clientSocket; 25 | private volatile boolean running = true; 26 | private ExecutorService executorService = Executors.newFixedThreadPool(1); 27 | 28 | // The method to send a message to the server. 29 | private void sendMessage(String message) { 30 | try { 31 | byte[] bytes = message.getBytes(); 32 | sentPacket.setData(bytes); 33 | sentPacket.setLength(bytes.length); 34 | clientSocket.send(sentPacket); 35 | } catch(IOException e) { System.out.println("ChatClient error: " + e); } 36 | } 37 | 38 | public ChatClient(InetAddress serverAddress, int serverPort, final String nick) { 39 | // First, set up the desired Swing interface. 40 | JPanel topPanel = new JPanel(); 41 | JButton quit = new JButton("Quit"); 42 | topPanel.add(quit); 43 | final JTextField input = new JTextField(40); 44 | topPanel.add(input); 45 | this.add(topPanel, BorderLayout.NORTH); 46 | final JTextArea output = new JTextArea(); 47 | JScrollPane sb = new JScrollPane(output); 48 | sb.setPreferredSize(new Dimension(500,300)); 49 | this.add(sb, BorderLayout.CENTER); 50 | this.setTitle("Chat for " + nick); 51 | this.pack(); 52 | this.setVisible(true); 53 | 54 | // Next, the client itself. 55 | try { 56 | clientSocket = new DatagramSocket(); 57 | clientSocket.setSoTimeout(1000); 58 | receivedPacket = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE); 59 | sentPacket = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE, serverAddress, serverPort); 60 | } catch(Exception e) { 61 | System.out.println("ChatClient error: " + e); 62 | return; 63 | } 64 | 65 | sendMessage("@JOIN" + nick); 66 | 67 | input.addActionListener(ae -> { 68 | sendMessage(nick + ":" + input.getText()); 69 | input.setText(""); 70 | }); 71 | 72 | quit.addActionListener(ae -> { 73 | sendMessage("@QUIT"); 74 | ChatClient.this.terminate(); 75 | }); 76 | 77 | this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 78 | this.addWindowListener(new WindowAdapter() { 79 | public void windowClosing(WindowEvent we) { 80 | sendMessage("@QUIT"); 81 | ChatClient.this.terminate(); 82 | } 83 | }); 84 | 85 | /* A background thread to listen to the messages coming from the Server. */ 86 | executorService.submit(() -> { 87 | try { 88 | while(running) { 89 | try { 90 | // Wait for the next incoming datagram. 91 | clientSocket.receive(receivedPacket); 92 | // Extract the message from the datagram. 93 | byte[] bytes = receivedPacket.getData(); 94 | bytes = java.util.Arrays.copyOfRange(bytes, 0, receivedPacket.getLength()); 95 | String message = new String(bytes); 96 | output.append(message + "\n"); 97 | } 98 | catch(SocketTimeoutException e) { /* No message this time */ } 99 | } 100 | } 101 | catch(IOException e) { 102 | System.out.println("ChatClient error: " + e); 103 | } 104 | finally { 105 | clientSocket.close(); 106 | System.out.println("ChatClient terminated"); 107 | } 108 | }); 109 | } 110 | 111 | public void terminate() { 112 | running = false; 113 | executorService.shutdownNow(); 114 | this.dispose(); 115 | } 116 | 117 | // For demonstration purposes. 118 | public static void launch(InetAddress serverAddress, int serverPort, String nick) { 119 | new ChatClient(serverAddress, serverPort, nick); 120 | } 121 | public static void launch(int serverPort, String nick) throws Exception { 122 | launch(InetAddress.getLocalHost(), serverPort, nick); 123 | } 124 | 125 | public static void main(String[] args) throws Exception { 126 | if(args.length != 2) { 127 | System.out.println("Usage: ChatClient port nick"); 128 | } 129 | else { 130 | launch(Integer.parseInt(args[0]), args[1]); 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /ChatServer.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | import java.net.DatagramPacket; 3 | import java.net.DatagramSocket; 4 | import java.net.SocketTimeoutException; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | import java.util.concurrent.ExecutorService; 9 | import java.util.concurrent.Executors; 10 | 11 | public class ChatServer { 12 | 13 | private static final int PACKET_SIZE = 512; 14 | private final List clients = new ArrayList<>(); 15 | private volatile boolean running = true; 16 | private DatagramSocket serverSocket; 17 | private DatagramPacket receivedPacket; 18 | private final ExecutorService executorService = Executors.newFixedThreadPool(1); 19 | 20 | // Objects of the inner class Client represent the registered clients in the chat. 21 | private class Client { 22 | public String nick; // Client's chosen nickname 23 | private final DatagramPacket clientPacket; // Client contact info 24 | 25 | public void sendMessage(String message) throws IOException { 26 | byte[] bytes = message.getBytes(); 27 | clientPacket.setData(bytes); 28 | clientPacket.setLength(bytes.length); 29 | serverSocket.send(clientPacket); 30 | } 31 | 32 | public Client(DatagramPacket initialPacket, String nick) { 33 | this.nick = nick; 34 | this.clientPacket = new DatagramPacket( 35 | new byte[PACKET_SIZE], PACKET_SIZE, 36 | initialPacket.getAddress(), initialPacket.getPort() 37 | ); 38 | } 39 | } 40 | 41 | public ChatServer(int serverPort) { 42 | try { 43 | serverSocket = new DatagramSocket(serverPort); 44 | serverSocket.setSoTimeout(60000); 45 | } 46 | catch(Exception e) { 47 | System.out.println("Error: Can't open ChatServer socket"); return; 48 | } 49 | receivedPacket = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE); 50 | executorService.submit(new LogicThread()); 51 | } 52 | 53 | public void sendMessageToAll(String message) throws IOException { 54 | for(Client client: clients) { client.sendMessage(message); } 55 | } 56 | 57 | // The background thread to implement the chat server's mainloop. 58 | private class LogicThread implements Runnable { 59 | public void run() { 60 | try { 61 | while(running) { 62 | // Wait for the next incoming datagram. 63 | serverSocket.receive(receivedPacket); 64 | // Extract the message from the datagram. 65 | byte[] bytes = receivedPacket.getData(); 66 | bytes = Arrays.copyOfRange(bytes, 0, receivedPacket.getLength()); 67 | String message = new String(bytes); 68 | // Do what the message tells us to do. 69 | if(message.startsWith("@JOIN")) { 70 | Client client = new Client(receivedPacket, message.substring(5)); 71 | clients.add(client); 72 | sendMessageToAll("New client " + client.nick + " has joined the chat"); 73 | } 74 | else if(message.equals("@QUIT")) { 75 | for(Client client: clients) { // who wants to quit? 76 | if(client.clientPacket.getAddress().equals(receivedPacket.getAddress()) && 77 | client.clientPacket.getPort() == receivedPacket.getPort()) { 78 | clients.remove(client); 79 | sendMessageToAll(client.nick + " has quit the chat"); 80 | break; // Can't continue iterating collection after mutation 81 | } 82 | } 83 | } 84 | else { sendMessageToAll(message); } 85 | } 86 | } 87 | catch(SocketTimeoutException e) { 88 | System.out.println("Socket timeout, closing server"); 89 | } 90 | catch(IOException e) { 91 | System.out.println("ChatServer error: " + e ); 92 | } 93 | finally { 94 | serverSocket.close(); 95 | System.out.println("ChatServer terminated, good night"); 96 | terminate(); 97 | } 98 | } 99 | } 100 | 101 | private void terminate() { 102 | running = false; 103 | executorService.shutdownNow(); 104 | } 105 | 106 | public static void main(String[] args) { 107 | if(args.length != 1) { 108 | System.out.println("USAGE: ChatServer port"); 109 | } 110 | else { 111 | new ChatServer(Integer.parseInt(args[0])); 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /ConcurrencyDemo.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.ExecutorService; 2 | import java.util.concurrent.Executors; 3 | import java.util.concurrent.ThreadLocalRandom; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | public class ConcurrencyDemo { 7 | 8 | // An inner class for a Runnable task used in this example. 9 | 10 | private static class SimpleWaiter implements Runnable { 11 | private static final AtomicInteger TICKET_MACHINE = new AtomicInteger(0); 12 | private final int id; 13 | public SimpleWaiter() { 14 | this.id = TICKET_MACHINE.incrementAndGet(); // Guaranteed atomic 15 | } 16 | @Override public void run() { 17 | System.out.println("Starting waiter #" + id + "."); 18 | try { 19 | // Make this thread sleep for a random time between 2 and 4 seconds. 20 | Thread.sleep(ThreadLocalRandom.current().nextInt(2000) + 2000); 21 | } 22 | // Not allowed to let exceptions fly out, we are forced use this classic antipattern. 23 | catch(InterruptedException ignored) { } 24 | System.out.println("Finishing waiter #" + id + "."); 25 | } 26 | } 27 | 28 | // Demonstrate how to create and launch new threads. Each SimpleWaiter task is 29 | // executed in its own separate thread. 30 | public static void simpleThreadDemo(int n) { 31 | for(int i = 0; i < n; i++) { 32 | Thread t = new Thread(new SimpleWaiter()); 33 | // Some settings could be changed here before starting the thread. 34 | // We don't, but someone could. 35 | t.start(); 36 | } 37 | System.out.println("All waiters created, returning from method."); 38 | } 39 | 40 | // The previous example implemented using an ExecutorService instead of explicitly 41 | // creating threads. See what happens if you set this up with different argument. 42 | private static final ExecutorService taskHandler = Executors.newFixedThreadPool(3); 43 | 44 | public static void simpleExecutorDemo(int n) { // Try n = 2, 5, 10. 45 | for(int i = 0; i < n; i++) { 46 | taskHandler.submit(new SimpleWaiter()); 47 | } 48 | System.out.println("All waiters submitted, returning from method."); 49 | } 50 | 51 | public static void main(String[] args) { 52 | simpleThreadDemo(20); 53 | // simpleExecutorDemo(20); 54 | 55 | // Make sure that the ExecutorService that we use here releases its threads 56 | // once all tasks submitted to it have been completed. 57 | taskHandler.shutdown(); 58 | } 59 | } -------------------------------------------------------------------------------- /ContinuedFraction.java: -------------------------------------------------------------------------------- 1 | import java.math.BigDecimal; 2 | import java.math.BigInteger; 3 | import java.math.RoundingMode; 4 | import java.util.Iterator; 5 | 6 | // https://en.wikipedia.org/wiki/Continued_fraction 7 | 8 | // A decorator that takes an existing Iterator and treats the 9 | // values it produces as coefficients of a continuing fraction, and 10 | // produces the sequence of exact integer Fractions defined by these 11 | // coefficients so far. 12 | 13 | public class ContinuedFraction implements Iterator { 14 | 15 | // The continued fraction so far simplified to its lowest form. 16 | private Fraction state = new Fraction(1); 17 | // The iterator that produces the terms of this continued fraction. 18 | private final Iterator it; 19 | 20 | public ContinuedFraction(Iterator it) { this.it = it; } 21 | 22 | public boolean hasNext() { 23 | return it.hasNext(); 24 | } 25 | 26 | public Fraction next() { 27 | int v = it.next(); 28 | // If the current state is a/b, next state is given by 1/(v + a/b)... 29 | BigInteger a = state.getNum(); 30 | BigInteger b = state.getDen(); 31 | // ...which simplifies to 1/((bv+a)/b), which equals b/(bv+a) 32 | state = new Fraction(b, b.multiply(new BigInteger(""+v)).add(a)); 33 | return state; 34 | } 35 | 36 | /* 37 | * Output the first 1000 digits after the decimal point of the Golden ratio. 38 | * Of all irrational numbers, the Golden ratio has the simplest possible 39 | * representation as a continued fraction, with each term of the infinite 40 | * series being equal to 1. Unfortunately, other famous irrationals such as 41 | * pi and e tend to have more complicated continued fraction forms. However, 42 | * this same idea generalizes to more powerful representations as sequences 43 | * of integers that allows us to compute even those irrationals out up to 44 | * any finite precision we wish. 45 | */ 46 | 47 | public static void computeGoldenRatioDemo() { 48 | final int PREC = 1000; // How many decimal places the result is computed to. 49 | final int PERLINE = 50; // How many digits are printed per line. 50 | final int N = 2300; // How many terms of continuing fractions are generated. 51 | 52 | // I found the value of N for the result to converge by trial and error. With 53 | // some other numbers, you need some more sophisticated stopping criteria. 54 | 55 | // An iterator that produces a series of count copies of value v. 56 | class Repeat implements Iterator { 57 | private int count; 58 | private final int val; 59 | public Repeat(int val, int count) { 60 | this.val = val; 61 | this.count = count; 62 | } 63 | public boolean hasNext() { 64 | return count > 0; 65 | } 66 | public Integer next() { 67 | count--; return val; 68 | } 69 | } 70 | 71 | // Iterator that produces ever more accurate approximations of Golden ratio. 72 | Iterator goldenApprox = new ContinuedFraction(new Repeat(1, N)); 73 | // (Try what happens if your sequence repeats some other constant than one.) 74 | 75 | // Generate the approximation by evaluating the continuing fraction. 76 | Fraction gf = new Fraction(1); 77 | while(goldenApprox.hasNext()) { 78 | gf = goldenApprox.next(); 79 | } 80 | 81 | // Create BigDecimal objects from BigInteger objects we have. 82 | BigDecimal num = new BigDecimal(gf.getNum()); 83 | BigDecimal den = new BigDecimal(gf.getDen()); 84 | // Since BigDecimal divisions are generally non-terminating, you 85 | // need to specify how many decimal places your want, and how you 86 | // want the truncated decimal after the last one to be handled. 87 | BigDecimal golden = num.divide(den, PREC, RoundingMode.FLOOR); 88 | // Extract the decimals and print them on console. 89 | String decimals = golden.toString(); 90 | int pos = decimals.indexOf('.') + 1; 91 | System.out.println("After decimal point, first " + PREC + " decimals of Golden ratio:\n"); 92 | while(pos < decimals.length()) { 93 | System.out.println(decimals.substring(pos, Math.min(pos + PERLINE, decimals.length()))); 94 | pos += PERLINE; 95 | } 96 | 97 | // (The built-in double type has 51 bits (about 17 decimal digits) 98 | // of precision that must handle both the integer and the real part 99 | // of that number. Separate 12 bits of scale determine which bits 100 | // represent which powers of the base two. Therefore, the double 101 | // type cannot tell apart the numbers x and x+y whenever y is 18+ 102 | // orders of magnitude smaller than x, and x == x+y evaluates to true.) 103 | } 104 | 105 | public static void main(String[] args) { 106 | computeGoldenRatioDemo(); 107 | } 108 | } -------------------------------------------------------------------------------- /Counter.java: -------------------------------------------------------------------------------- 1 | import java.awt.Color; 2 | import java.awt.Dimension; 3 | import java.awt.Font; 4 | import java.awt.GridLayout; 5 | import java.awt.event.ActionEvent; 6 | import java.awt.event.ActionListener; 7 | import javax.swing.BorderFactory; 8 | import javax.swing.BoxLayout; 9 | import javax.swing.JButton; 10 | import javax.swing.JFrame; 11 | import javax.swing.JLabel; 12 | import javax.swing.JPanel; 13 | import javax.swing.JTextField; 14 | import javax.swing.border.BevelBorder; 15 | 16 | public class Counter extends JPanel { 17 | 18 | private static final Font BUTTON_FONT = new Font("Arial", Font.PLAIN, 28); 19 | private static final Font LABEL_FONT = new Font("Courier", Font.BOLD, 50); 20 | private int count = 0; 21 | 22 | public Counter() { 23 | this.setPreferredSize(new Dimension(250, 80)); 24 | // Every Swing component can have an arbitrarily festive and decorative border. 25 | this.setBorder(BorderFactory.createLoweredSoftBevelBorder()); 26 | 27 | // Instead of the default FlowLayout layout manager, let's try something more fancy. 28 | this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); 29 | // When a local variable is accessed from a local nested class, that variable has 30 | // to be effectively final; that is, either declared final, or never assigned to 31 | // after initialization. 32 | JLabel myLabel = new JLabel("0"); 33 | myLabel.setBorder(BorderFactory.createEtchedBorder()); 34 | myLabel.setFont(LABEL_FONT); 35 | this.add(myLabel); 36 | 37 | JButton myButton = new JButton("Press me"); 38 | myButton.setFont(BUTTON_FONT); 39 | myButton.setToolTipText("Click to increase the count"); 40 | this.add(myButton); 41 | 42 | // A local class defined and used only inside this method. 43 | class MyActionListener implements ActionListener { 44 | // The action listener nested class must have this exact method. 45 | public void actionPerformed(ActionEvent ae) { 46 | // This code of this method gets executed each time the button is pressed. 47 | // As you see, nested class methods can modify the fields of the outer 48 | // class object directly without any special syntax... 49 | count++; 50 | // ... and access all effectively final local variables of the method. 51 | myLabel.setText(Integer.toString(count)); 52 | } 53 | } 54 | myButton.addActionListener(new MyActionListener()); 55 | } 56 | 57 | public static void main(String[] args) { 58 | JFrame f = new JFrame("Counter demo"); 59 | f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 60 | 61 | // Let's add sixteen separate Counter instances, just to show what happens. 62 | int n = 4; 63 | f.setLayout(new GridLayout(n, n)); 64 | for(int i = 0; i < n*n-1; i++) { f.add(new Counter()); } 65 | // Just to make a point about GridLayout, make bottom right component different. 66 | JTextField myTextField = new JTextField(); 67 | myTextField.setText("Look at me, I am a text field"); 68 | f.add(myTextField); 69 | f.pack(); 70 | f.setVisible(true); 71 | } 72 | } -------------------------------------------------------------------------------- /DLA.java: -------------------------------------------------------------------------------- 1 | import javax.swing.JFrame; 2 | import javax.swing.JPanel; 3 | import java.awt.BasicStroke; 4 | import java.awt.Color; 5 | import java.awt.Dimension; 6 | import java.awt.FlowLayout; 7 | import java.awt.Graphics; 8 | import java.awt.Graphics2D; 9 | import java.awt.RenderingHints; 10 | import java.awt.geom.CubicCurve2D; 11 | import java.util.ArrayList; 12 | import java.util.Random; 13 | 14 | // Diffusion limited aggregation, adapted from http://paulbourke.net/fractals/dla/ 15 | 16 | // In this example, particles move around randomly until they come close enough to 17 | // some particle that is already frozen. At that time, that particle also becomes 18 | // frozen, and the particle it connected with becomes its parent. 19 | 20 | public class DLA { 21 | 22 | private static final Random rng = new Random(); 23 | private static final double STEP = 0.03; 24 | 25 | // A nested class to represent an individual particle. 26 | private static class Particle { 27 | public double x, y; // Coordinates of this particle, in [0,1] * [0,1]; 28 | public Particle parent; // The parent of this particle once it is frozen. 29 | 30 | public Particle() { 31 | x = rng.nextDouble(); 32 | y = rng.nextDouble(); 33 | parent = null; 34 | } 35 | 36 | public double distSq(Particle other) { 37 | double dx = this.x - other.x; 38 | double dy = this.y - other.y; 39 | return dx*dx + dy*dy; 40 | } 41 | 42 | public void move() { 43 | x += rng.nextGaussian() * STEP; 44 | y += rng.nextGaussian() * STEP; 45 | // Bounce from the edges. 46 | if(x < 0) { x = -x; } 47 | else if(x > 1) { x = 2 - x; } 48 | if(y < 0) { y = -y; } 49 | else if(y > 1) { y = 2 - y; } 50 | } 51 | } 52 | 53 | private static final double SNAP = 0.7; 54 | 55 | public static ArrayList computeDLA(int n, int m, int points, double d) { 56 | // Seed the particles randomly. At all times, we have n + m particles so that 57 | // first n particles are frozen, and the rest are still moving. 58 | ArrayList particles = new ArrayList<>(); 59 | for(int i = 0; i < n + m; i++) { 60 | particles.add(new Particle()); 61 | } 62 | 63 | // Simulate until enough points are frozen. 64 | while(n < points) { 65 | // Move each still moving particle a random amount. 66 | for(int pi = n; pi < particles.size(); pi++) { 67 | particles.get(pi).move(); 68 | } 69 | // Loop through moving particles to see if they are close enough to 70 | // some frozen particles, and if so, make that particle also frozen. 71 | for(int pi = n; pi < particles.size(); pi++) { 72 | Particle p = particles.get(pi); 73 | for(int fi = 0; fi < n; fi++) { 74 | if(particles.get(fi).distSq(p) < d) { 75 | p.parent = particles.get(fi); 76 | // Snap a bit closer 77 | p.x = SNAP * p.x + (1-SNAP) * p.parent.x; 78 | p.y = SNAP * p.y + (1-SNAP) * p.parent.y; 79 | break; 80 | } 81 | } 82 | } 83 | // Loop through moving particles and swap those that froze to the 84 | // area that contains the frozen particles, growing that area by one. 85 | for(int pi = n; pi < particles.size(); pi++) { 86 | if(particles.get(pi).parent != null) { 87 | Particle tmp = particles.get(n); 88 | particles.set(n++, particles.get(pi)); 89 | particles.set(pi, tmp); 90 | } 91 | } 92 | // Finally, create more moving particles to replace those frozen. 93 | while(particles.size() - n < m) { 94 | particles.add(new Particle()); 95 | } 96 | } 97 | 98 | // Return the frozen particles as a separate sublist. 99 | ArrayList result = new ArrayList<>(n); 100 | for(int i = 0; i < n; i++) { 101 | result.add(particles.get(i)); 102 | } 103 | return result; 104 | } 105 | 106 | // A utility method to create a JPanel that displays the result. 107 | public static JPanel createPanel(final int w, int n, int m, int points, double d) { 108 | final ArrayList particles = computeDLA(n, m, points, d); 109 | 110 | class DLAPanel extends JPanel { 111 | public DLAPanel() { 112 | this.setPreferredSize(new Dimension(w, w)); 113 | this.setBackground(Color.WHITE); 114 | } 115 | public void paintComponent(Graphics g) { 116 | super.paintComponent(g); 117 | Graphics2D g2 = (Graphics2D)g; 118 | g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 119 | RenderingHints.VALUE_ANTIALIAS_ON); 120 | 121 | g2.setPaint(new Color(30, 25, 20)); 122 | g2.setStroke(new BasicStroke(4.0f)); 123 | for(Particle p: particles) { 124 | Particle pa = p.parent; 125 | if(pa != null) { 126 | Particle ppa = pa.parent; 127 | if(ppa != null) { 128 | g2.draw(new CubicCurve2D.Double( 129 | w*p.x, w*p.y, w*pa.x, w*pa.y, w*pa.x, w*pa.y, w*ppa.x, w*ppa.y 130 | )); 131 | } 132 | } 133 | } 134 | } 135 | } 136 | 137 | return new DLAPanel(); 138 | } 139 | 140 | public static void main(String[] args) { 141 | JFrame f = new JFrame("DLA"); 142 | f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 143 | f.setLayout(new FlowLayout()); 144 | f.add(createPanel(800, 10, 20, 2000, 0.002)); 145 | f.pack(); 146 | f.setVisible(true); 147 | } 148 | } -------------------------------------------------------------------------------- /DissociatedPress.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | import java.io.IOException; 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Random; 6 | import java.util.Scanner; 7 | 8 | public class DissociatedPress { 9 | 10 | // To run this program, replace FILENAME with some text file that you have. 11 | private static final String FILENAME = "warandpeace.txt"; 12 | 13 | private static final Random rng = new Random(); 14 | 15 | private final Map followMap = new HashMap<>(); 16 | private final int maxPat; 17 | private final int maxFollow; 18 | private String pattern; 19 | 20 | public DissociatedPress() { this(" ", 7, 200); } 21 | 22 | /** 23 | * The constructor for DissociatedPress. 24 | * @param pattern The initial pattern. 25 | * @param maxPat The maximum length for the current pattern. 26 | * @param maxFollow The maximum length for the follow string for any pattern. 27 | */ 28 | public DissociatedPress(String pattern, int maxPat, int maxFollow) { 29 | this.pattern = pattern; 30 | this.maxPat = maxPat; 31 | this.maxFollow = maxFollow; 32 | } 33 | 34 | /** 35 | * Process the next character of the input text and update the followmap for all 36 | * the suffixes of the current pattern. 37 | * @param next The next character of input to process. 38 | */ 39 | public void processChar(char next) { 40 | // Add the next character to follow strings of every suffix of current pattern. 41 | for(int i = 0; i < pattern.length(); i++) { 42 | String partPat = pattern.substring(i); 43 | String follow = followMap.getOrDefault(partPat, ""); 44 | if(follow.length() < maxFollow) { 45 | followMap.put(partPat, follow + next); 46 | } 47 | } 48 | pattern += next; 49 | if(pattern.length() > maxPat) { 50 | pattern = pattern.substring(1); 51 | } 52 | } 53 | 54 | /** 55 | * Use the Dissociated Press pattern map to emit a random character based on the 56 | * current pattern, and update the pattern accordingly. 57 | * @param maxEmitPat The maximum pattern length to use in emission, regardless of the 58 | * patterns stored in the followmap. 59 | * @return A randomly chosen character from the follow string of the current pattern. 60 | */ 61 | public char nextChar(int maxEmitPat) { 62 | while(pattern.length() > maxEmitPat) { 63 | pattern = pattern.substring(1); 64 | } 65 | while(pattern.length() > 0) { 66 | String follow = followMap.getOrDefault(pattern, ""); 67 | if(follow.length() > 0) { 68 | char next = follow.charAt(rng.nextInt(follow.length())); 69 | pattern += next; 70 | if(pattern.length() > maxPat) { pattern = pattern.substring(1); } 71 | return next; 72 | } 73 | pattern = pattern.substring(1); 74 | } 75 | return '$'; 76 | } 77 | 78 | public void outputInfo() { 79 | StringBuilder characters = new StringBuilder(); 80 | int[] patCount = new int[maxPat + 1]; 81 | int[] followCount = new int[maxPat + 1]; 82 | int[] saturated = new int[maxPat + 1]; 83 | for(String pat: followMap.keySet()) { 84 | patCount[pat.length()]++; 85 | int fl = followMap.get(pat).length(); 86 | followCount[pat.length()] += fl; 87 | if(fl == maxFollow) { saturated[pat.length()]++; } 88 | if(pat.length() == 1) { characters.append(pat); } 89 | } 90 | System.out.println("Characters found in data are:\n" + characters); 91 | System.out.println("\nLength\tTotal\tSaturated\tAverage"); 92 | for(int patLen = 1; patLen <= maxPat; patLen++) { 93 | System.out.printf("%d\t%d\t%d\t\t%.3f\n", patLen, patCount[patLen], 94 | saturated[patLen], followCount[patLen] / (double)patCount[patLen]); 95 | } 96 | System.out.println("\n"); 97 | } 98 | 99 | /** 100 | * For demonstration purposes, read in the text file "War and Peace" to be used to 101 | * build up the followmap. Demonstrate the behaviour of the Dissociated Press 102 | * technique to produce sample random test for pattern lengths from 1 to 7. 103 | */ 104 | public static void main(String[] args) throws IOException { 105 | Scanner wap = new Scanner(new File(FILENAME)); 106 | DissociatedPress dp = new DissociatedPress(); 107 | while(wap.hasNextLine()) { 108 | String line = wap.nextLine(); // nextLine() strips away newline character 109 | for(int i = 0; i < line.length(); i++) { 110 | dp.processChar(line.charAt(i)); 111 | } 112 | dp.processChar(' '); // newline works as whitespace for this analysis 113 | } 114 | wap.close(); 115 | dp.outputInfo(); 116 | for(int maxEmitPat = 1; maxEmitPat < 8; maxEmitPat++) { 117 | if(maxEmitPat > 1) { System.out.println("\n---\n"); } 118 | System.out.println("Emit pattern length " + maxEmitPat + "."); 119 | int currLineLen = 0, linesRemain = 10; 120 | char prev = ' '; 121 | while(linesRemain > 0) { 122 | char next = dp.nextChar(maxEmitPat); 123 | if(!(Character.isWhitespace(next) && Character.isWhitespace(prev))) { 124 | if(currLineLen++ > 60 && Character.isWhitespace(next)) { 125 | next = '\n'; currLineLen = 0; linesRemain--; 126 | } 127 | System.out.print(next); 128 | } 129 | prev = next; 130 | } 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /ElementaryCellular.java: -------------------------------------------------------------------------------- 1 | import javax.swing.JCheckBox; 2 | import javax.swing.JFrame; 3 | import javax.swing.JLabel; 4 | import javax.swing.JPanel; 5 | import javax.swing.JSlider; 6 | import javax.swing.event.ChangeEvent; 7 | import javax.swing.event.ChangeListener; 8 | import java.awt.Dimension; 9 | import java.awt.FlowLayout; 10 | import java.awt.Graphics; 11 | import java.awt.event.ItemEvent; 12 | import java.awt.event.ItemListener; 13 | import java.awt.image.BufferedImage; 14 | 15 | /** 16 | * A Swing component to display one-dimensional cellular automata, with 17 | * time flowing in the vertical direction, as is customary in this genre. 18 | * @author Ilkka Kokkarinen 19 | */ 20 | 21 | public class ElementaryCellular extends JPanel { 22 | 23 | private static final int TOP = 35; 24 | private final boolean[][] state; 25 | 26 | // All sorts of Swing components with different listeners. 27 | private final JSlider ruleSlider; 28 | private final JCheckBox fredkinBox; 29 | private final JLabel ruleLabel; 30 | 31 | private int rule = 110; 32 | private final BufferedImage img; 33 | 34 | // Compute the value of the cell (x,y) based on its ancestors. 35 | private boolean evaluateCell(int x, int y, boolean fredkin) { 36 | int v = 0; 37 | int len = state.length; 38 | v += state[(x + len - 1) % len][y-1] ? 4: 0; 39 | v += state[x][y-1] ? 2: 0; 40 | v += state[(x + 1) % len][y-1] ? 1: 0; 41 | boolean v1 = (rule & (1 << v)) != 0; 42 | if(fredkin) { // Fredkin rule 43 | boolean v2 = (y > 1 && state[x][y-2]); 44 | return (v1 || v2) && !(v1 && v2); // xor 45 | } 46 | else { // Wolfram rule 47 | return v1; 48 | } 49 | } 50 | 51 | /** 52 | * Compute the state of the entire board, given the first row. 53 | */ 54 | public void evaluateBoard() { 55 | boolean fredkin = fredkinBox.isSelected(); 56 | for(int y = 0; y < state[0].length; y++) { 57 | for(int x = 0; x < state.length; x++) { 58 | state[x][y] = y > 0 ? evaluateCell(x, y, fredkin) : state[x][y]; 59 | int col = state[x][y] ? 0 : 0x00FFFFFF; 60 | int xx = 2 * x, yy = 2 * y; 61 | img.setRGB(xx, yy, col); 62 | img.setRGB(xx + 1, yy, col); 63 | img.setRGB(xx, yy + 1, col); 64 | img.setRGB(xx + 1, yy + 1, col); 65 | } 66 | } 67 | repaint(); 68 | } 69 | 70 | /** 71 | * The constructor for desired width and height. 72 | * @param width The width of the computed image, in pixels. 73 | * @param height, The height of the computed image, in pixels. 74 | */ 75 | public ElementaryCellular(int width, int height) { 76 | this.setPreferredSize(new Dimension(2 * width, 2 * height + TOP)); 77 | img = new BufferedImage(2 * width, 2 * height, BufferedImage.TYPE_INT_BGR); 78 | 79 | fredkinBox = new JCheckBox("Fredkin"); 80 | this.add(fredkinBox); 81 | fredkinBox.addItemListener(new MyFredkinListener()); 82 | this.add(new JLabel("Rule:")); 83 | ruleLabel = new JLabel(rule + ""); 84 | this.add(ruleLabel); 85 | ruleSlider = new JSlider(0, 255); 86 | this.add(ruleSlider); 87 | ruleSlider.addChangeListener(new MySliderListener()); 88 | 89 | state = new boolean[width][height]; 90 | state[width / 2][0] = true; 91 | evaluateBoard(); 92 | } 93 | 94 | /** 95 | * Render this component as it currently looks like. 96 | * @param g The {@code Graphics} object provided by Swing for us to draw on. 97 | */ 98 | public void paintComponent(Graphics g) { 99 | super.paintComponent(g); 100 | g.drawImage(img, 0, TOP, this); 101 | } 102 | 103 | private class MySliderListener implements ChangeListener { 104 | public void stateChanged(ChangeEvent ce) { 105 | rule = ruleSlider.getValue(); 106 | ruleLabel.setText(rule + ""); 107 | evaluateBoard(); 108 | } 109 | } 110 | 111 | private class MyFredkinListener implements ItemListener { 112 | public void itemStateChanged(ItemEvent ie) { 113 | evaluateBoard(); 114 | } 115 | } 116 | 117 | 118 | public static void main(String[] args) { 119 | JFrame f = new JFrame("Elementary Cellular Automata"); 120 | f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 121 | f.setLayout(new FlowLayout()); 122 | f.add(new ElementaryCellular(500, 500)); 123 | f.pack(); 124 | f.setVisible(true); 125 | } 126 | } -------------------------------------------------------------------------------- /EnumDemo.java: -------------------------------------------------------------------------------- 1 | import java.util.EnumMap; 2 | import java.util.EnumSet; 3 | 4 | public class EnumDemo { 5 | 6 | private enum Day { 7 | // possible values of this particular enum type 8 | SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY; 9 | 10 | // enum types can have fields and methods just like classes 11 | public boolean isWeekday() { 12 | return (this != SATURDAY && this != SUNDAY); 13 | } 14 | } 15 | 16 | public static void main(String[] args) { 17 | for(Day d: Day.values()) { 18 | System.out.println(d.ordinal() + ":" + d.name() + 19 | (d.isWeekday() ? " is" : " is not") + " a weekday"); 20 | } 21 | 22 | // Enums can also be used in switches (like int or char) 23 | System.out.println("Listing weekdays with a switch"); 24 | for(Day d: Day.values()) { 25 | System.out.print(d + " is "); 26 | switch (d) { 27 | case SATURDAY: 28 | case SUNDAY: { System.out.println("not a weekday"); break; } 29 | default: System.out.println("a weekday"); 30 | } 31 | } 32 | 33 | // EnumSet is the efficient Set implementation for Enums 34 | EnumSet weekdays = EnumSet.range(Day.MONDAY, Day.FRIDAY); 35 | System.out.println("Listing weekdays with an EnumSet"); 36 | for(Day d: weekdays) { System.out.println(d); } 37 | 38 | // EnumMap is the efficient Map implementation for Enums 39 | EnumMap weekdayMap = new EnumMap<>(Day.class); 40 | for(Day d: Day.values()) { weekdayMap.put(d, d.isWeekday()); } 41 | System.out.println("Listing weekdays with an EnumMap"); 42 | for(Day d: Day.values()) { 43 | if(weekdayMap.get(d)) { System.out.println(d); } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /ExceptionDemo.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | 3 | public class ExceptionDemo { 4 | 5 | // This method can fail and throw an IOException. 6 | private static Object failOne() throws IOException { 7 | System.out.println("Entered method failOne."); 8 | if(true) { // fool the compiler to think that the last line is reachable 9 | throw new IOException("testing"); 10 | } 11 | System.out.println("Execution does not get here."); 12 | return new IOException("testing"); 13 | } 14 | 15 | // Calls failOne but does not handle the exception that it can throw. 16 | // Therefore, this method must declare that it may throw IOExceptions. 17 | private static void failTwo() throws IOException { 18 | try { 19 | System.out.println("Calling method failOne from failTwo."); 20 | failOne(); // fails 21 | System.out.println("Execution does not get here."); 22 | } 23 | finally { // this code will be executed no matter what 24 | System.out.println("But the execution does get here."); 25 | } 26 | } 27 | 28 | // The demo method catches and handles the exception that was thrown 29 | // from two levels below it in the method stack. 30 | public static void demo() { 31 | try { 32 | failTwo(); // fails by calling something that fails 33 | } 34 | catch(IOException e) { 35 | System.out.println("Caught an exception " + e); 36 | System.out.println("Printing the stack trace: "); 37 | StackTraceElement[] trace = e.getStackTrace(); 38 | for (StackTraceElement stackTraceElement : trace) { 39 | System.out.print(stackTraceElement.getClassName() + " "); 40 | System.out.print(stackTraceElement.getMethodName() + " "); 41 | System.out.println(stackTraceElement.getLineNumber() + " "); 42 | } 43 | } 44 | finally { 45 | System.out.println("And we are finally done!"); 46 | } 47 | } 48 | 49 | // Will this method return 0 or 1 when called? What do you think? 50 | public static int returnDemo() { 51 | try { 52 | return 42; 53 | } 54 | finally { 55 | return 99; 56 | } 57 | } 58 | 59 | // What does this method throw? First place your bets, then see! 60 | public static void throwDemo() throws IOException { 61 | try { 62 | // throw "Hello world"; // Also can't do this, String is not Throwable 63 | throw new IllegalStateException("first"); //unchecked 64 | } 65 | finally { 66 | try { 67 | throw new IOException("second"); // checked 68 | } 69 | catch(IOException ignored) { } // go away 70 | } 71 | } 72 | 73 | // Does this method terminate, or is it an infinite loop? Who will win 74 | // this game of tug-of-war between these two opposing forces? What will 75 | // happen if you swap the statements continue and break? 76 | public static void whileDemo() { 77 | while(true) { 78 | try { 79 | break; 80 | } 81 | finally { 82 | continue; 83 | } 84 | } 85 | } 86 | 87 | public static void main(String[] args) { 88 | demo(); 89 | System.out.println(returnDemo()); 90 | try { 91 | throwDemo(); 92 | } 93 | catch(Exception e) { 94 | System.out.println("Caught exception: " + e); 95 | } 96 | // whileDemo(); // uncomment to see 97 | } 98 | } -------------------------------------------------------------------------------- /FJMergeSort.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.RecursiveAction; 2 | 3 | /* Sort the given array using merge sort with recursive calls 4 | * executed in parallel, to demonstrate Java 7 ForkJoinTask. */ 5 | 6 | public class FJMergeSort extends RecursiveAction { 7 | 8 | private static final int PARCUTOFF = 300; // adjust to taste 9 | private static final int MSCUTOFF = 50; 10 | private final int low; 11 | private final int high; 12 | private final int[] a; 13 | private final int[] b; 14 | 15 | // Sort the subarray (low..high) of array a, using another array 16 | // b of the same length as the temporary workspace. 17 | public FJMergeSort(int[] a, int[] b, int low, int high) { 18 | this.a = a; this.b = b; this.low = low; this.high = high; 19 | } 20 | 21 | // The important method of every ForkJoinTask. 22 | @Override public void compute() { 23 | mergeSort(low, high); 24 | } 25 | 26 | // Recursive mergesort with the left half sorted in a new task 27 | // in parallel while the right half is sorted in this same task. 28 | private void mergeSort(int low, int high) { 29 | if(high - low > MSCUTOFF) { 30 | int mid = (low + high) / 2; 31 | if(mid - low > PARCUTOFF) { // split to parallel task 32 | FJMergeSort left = new FJMergeSort(a, b, low, mid); 33 | left.fork(); // starts a new task in parallel 34 | mergeSort(mid + 1, high); 35 | left.join(); // waits for that task to finish 36 | } 37 | else { // too small for the parallelism overhead to pay off 38 | mergeSort(low, mid); 39 | mergeSort(mid + 1, high); 40 | } 41 | // either way, merge the sorted subarrays 42 | merge(low, mid, high); 43 | } 44 | else { // too small for mergesort overhead to pay off 45 | insertionSort(low, high); 46 | } 47 | } 48 | 49 | // Merge the sorted subarrays (low..mid) and (mid+1..high). 50 | private void merge(int low, int mid, int high) { 51 | int i = low, j = mid + 1, loc = low; 52 | while(i <= mid && j <= high) { 53 | if(a[i] <= a[j]) { b[loc++] = a[i++]; } 54 | else { b[loc++] = a[j++]; } 55 | } 56 | while(i <= mid) { b[loc++] = a[i++]; } 57 | while(j <= high) { b[loc++] = a[j++]; } 58 | System.arraycopy(b, low, a, low, high - low + 1); 59 | } 60 | 61 | // Small subarrays are best sorted with simple insertion sort. 62 | private void insertionSort(int low, int high) { 63 | for(int i = low + 1; i <= high; i++) { 64 | int x = a[i]; 65 | int j = i; 66 | while(j > low && a[j-1] > x) { 67 | a[j] = a[j-1]; 68 | j--; 69 | } 70 | a[j] = x; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /FirstBatch.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | 3 | public class FirstBatch { 4 | 5 | // So that the code will compile, an example implementation of isFunny. 6 | public static boolean isFunny(int n) { 7 | return n % 3 == 0; 8 | } 9 | 10 | public static int countFunnies(int[] a) { 11 | int count = 0; 12 | for(int e: a) { // We care about the elements only, not their indices. 13 | if(isFunny(e)) { count++; } 14 | } 15 | return count; 16 | } 17 | 18 | public static int[] collectFunnies(int[] a) { 19 | int count = countFunnies(a); 20 | int[] b = new int[count]; 21 | int loc = 0; // The index where the next funny element goes. 22 | for(int e: a) { 23 | if(isFunny(e)) { 24 | b[loc++] = e; 25 | } 26 | } 27 | return b; 28 | } 29 | 30 | // A utility method needed in the later selection sort method. 31 | public static int locationOfSmallest(int[] a, int start, int end) { 32 | int m = start; 33 | for(int i = start + 1; i <= end; i++) { 34 | if(a[i] < a[m]) { m = i; } 35 | } 36 | return m; 37 | } 38 | 39 | // Our first (and worst) sorting algorithm in the course. 40 | public static void selectionSort(int[] a) { 41 | for(int i = 0; i < a.length - 1; i++) { 42 | int j = locationOfSmallest(a, i, a.length - 1); 43 | int tmp = a[i]; 44 | a[i] = a[j]; 45 | a[j] = tmp; 46 | } 47 | } 48 | 49 | // Three methods of similar spirit and style coming up. 50 | public static int[] zip(int[] a, int[] b) { 51 | int i = 0, loc = 0; 52 | int[] c = new int[a.length + b.length]; 53 | while(i < a.length && i < b.length) { 54 | c[loc++] = a[i]; 55 | c[loc++] = b[i++]; 56 | } 57 | while(i < a.length) { c[loc++] = a[i++]; } 58 | while(i < b.length) { c[loc++] = b[i++]; } 59 | return c; 60 | } 61 | 62 | public static int[] merge(int[] a, int[] b) { 63 | int i = 0, j = 0, loc = 0; 64 | int[] c = new int[a.length + b.length]; 65 | while(i < a.length && j < b.length) { 66 | if(a[i] <= b[j]) { c[loc++] = a[i++]; } 67 | else { c[loc++] = b[j++]; } 68 | } 69 | while(i < a.length) { c[loc++] = a[i++]; } 70 | while(j < b.length) { c[loc++] = b[j++]; } 71 | return c; 72 | } 73 | 74 | public static int[] intersection(int[] a, int[] b) { 75 | ArrayList result = new ArrayList(); 76 | int i = 0, j = 0; 77 | while(i < a.length && j < b.length) { 78 | if(a[i] < b[j]) { i++; } 79 | else if(a[i] > b[j]) { j++; } 80 | else { 81 | result.add(a[i]); 82 | i++; j++; 83 | } 84 | } 85 | // Even though Java converts int to Integer automatically, 86 | // this conversion is only for scalars, not for arrays. 87 | int[] c = new int[result.size()]; 88 | for(i = 0; i < c.length; i++) { c[i] = result.get(i); } 89 | return c; 90 | } 91 | 92 | public static int[] removeDuplicates(int[] a) { 93 | if(a.length == 0) { return a; } 94 | int count = 1; 95 | for(int i = 1; i < a.length; i++) { 96 | if(a[i] != a[i-1]) { count++; } 97 | } 98 | int[] b = new int[count]; 99 | int loc = 1; 100 | b[0] = a[0]; 101 | for(int i = 1; i < a.length; i++) { 102 | if(a[i] != a[i-1]) { b[loc++] = a[i]; } 103 | } 104 | return b; 105 | } 106 | 107 | // This problem demonstrates how to write one-pass methods through array 108 | // using state variables that are updated in each step. 109 | public static int longestAscending(int[] a) { 110 | int curr = 1; // The length of the current ascension. 111 | int max = 1; // The longest ascension that we have seen so far. 112 | for(int i = 1; i < a.length; i++) { // Start from second element 113 | if(a[i] > a[i-1]) { 114 | curr++; 115 | if(curr > max) { max = curr; } 116 | } 117 | else { 118 | curr = 1; 119 | } 120 | } 121 | return max; 122 | } 123 | 124 | // Adapted (and stylistically much improved) from Rosetta Code. 125 | 126 | private static final String[] symbolArr = { 127 | "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" 128 | }; 129 | 130 | private static final int[] valueArr = { 131 | 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 132 | }; 133 | 134 | public static String romanEncode(int n) { 135 | if(n < 1) { throw new IllegalArgumentException("Cannot convert " + n + " to Roman"); } 136 | StringBuilder result = new StringBuilder(); 137 | int idx = 0; 138 | while(n > 0) { 139 | while(n >= valueArr[idx]) { 140 | result.append(symbolArr[idx]); 141 | n -= valueArr[idx]; 142 | } 143 | idx++; 144 | } 145 | return result.toString(); 146 | } 147 | 148 | private static final String symbols = "MDCLXVI"; 149 | private static final int[] values = { 1000, 500, 100, 50, 10, 5, 1 }; 150 | 151 | public static int romanDecode(String roman) { 152 | int result = 0; 153 | int prev = 0; 154 | roman = roman.toUpperCase(); // Canonical form 155 | for(int idx = roman.length() - 1; idx >= 0; idx--) { 156 | int curr = symbols.indexOf(roman.charAt(idx)); 157 | if(curr == -1) { 158 | throw new IllegalArgumentException("Illegal character " + roman.charAt(idx)); 159 | } 160 | curr = values[curr]; 161 | result += curr < prev ? -curr : +curr; // IX vs. XI distinction 162 | prev = curr; 163 | } 164 | return result; 165 | } 166 | 167 | public static void testRomanConversions() { 168 | for(int n = 1; n < 5000; n++) { 169 | assert n == romanDecode(romanEncode(n)); 170 | } 171 | } 172 | 173 | 174 | } -------------------------------------------------------------------------------- /Fraction.java: -------------------------------------------------------------------------------- 1 | import java.math.BigInteger; 2 | 3 | /** 4 | * The class Fraction implements the integer fractions and some 5 | * of their arithmetic and comparison operations. The fractions 6 | * are internally implemented using Java's BigInteger class for 7 | * arbitrarily large integer values. 8 | * @author Ilkka Kokkarinen 9 | */ 10 | 11 | public class Fraction implements Comparable { 12 | 13 | // A fraction is internally encoded as numerator and denominator, both BigIntegers. 14 | 15 | private BigInteger num; // the numerator 16 | private BigInteger den; // the denominator, should always be > 0 17 | 18 | // The getter methods. Note that we don't have setter methods, since the Fraction 19 | // class is immutable, which means that an object, once created, cannot change its 20 | // state. (Immutability has various advantages that aren't intuitive quite yet.) 21 | 22 | /** 23 | * Return the numerator of this fraction. 24 | * @return The numerator of this fraction. 25 | */ 26 | public BigInteger getNum() { return num; } 27 | 28 | /** 29 | * Return the denominator of this fraction. 30 | * @return The denominator of this fraction. 31 | */ 32 | public BigInteger getDen() { return den; } 33 | 34 | /** 35 | * Construct a fraction from given numerator and denominator, as ints. 36 | * @param num The numerator of the fraction. 37 | * @param den The denominator of the fraction. 38 | */ 39 | public Fraction(int num, int den) { 40 | this(new BigInteger("" + num), new BigInteger("" + den)); 41 | } 42 | 43 | /** 44 | * Construct a fraction from given numerator and denominator, as BigIntegers. 45 | * @param num The numerator of the fraction. 46 | * @param den The denominator of the fraction. 47 | */ 48 | public Fraction(BigInteger num, BigInteger den) { 49 | this.num = num; 50 | this.den = den; 51 | simplify(); 52 | } 53 | 54 | /** 55 | * Construct a fraction that is an integer, from an int. 56 | * @param num The integer part of this fraction. 57 | */ 58 | public Fraction(int num) { 59 | this(new BigInteger("" + num)); 60 | } 61 | 62 | /** 63 | * Construct a fraction that is an integer, from a BigInteger. 64 | * @param num The integer part of this fraction. 65 | */ 66 | public Fraction(BigInteger num) { 67 | this.num = num; 68 | this.den = BigInteger.ONE; 69 | // no need to simplify, fraction is already in lowest terms 70 | } 71 | 72 | // Addition of fractions. Note that to add two fractions, call this method for one of them, 73 | // and pass the second one as parameter. This method doesn't modify either fraction, but 74 | // creates and returns a new fraction that contains the result. 75 | 76 | /** 77 | * Create a new fraction that is the sum of this fraction and the {@code other} fraction. 78 | * @param other The other fraction to add. 79 | * @return A fraction that contains the sum of the two fractions. 80 | */ 81 | public Fraction add(Fraction other) { 82 | return new Fraction(this.num.multiply(other.den).add(this.den.multiply(other.num)), this.den.multiply(other.den)); 83 | } 84 | 85 | /** 86 | * Create a new fraction that is the product of this fraction and the {@code other} fraction. 87 | * @param other The other fraction to multiply. 88 | * @return A fraction that contains the product of the two fractions. 89 | */ 90 | public Fraction multiply(Fraction other) { 91 | return new Fraction(this.num.multiply(other.num), this.den.multiply(other.den)); 92 | } 93 | 94 | /** 95 | * Create a new fraction that is the difference of this fraction and the {@code other} fraction. 96 | * @param other The other fraction to subtract. 97 | * @return A fraction that contains the difference of the two fractions. 98 | */ 99 | public Fraction subtract(Fraction other) { 100 | return new Fraction(this.num.multiply(other.den).subtract(this.den.multiply(other.num)), this.den.multiply(other.den)); 101 | } 102 | 103 | /** 104 | * Create a new fraction that is the quotient of this fraction and the {@code other} fraction. 105 | * @param other The other fraction to divide. 106 | * @return A fraction that contains the quotient of the two fractions. 107 | */ 108 | public Fraction divide(Fraction other) { 109 | return new Fraction(this.num.multiply(other.den), this.den.multiply(other.num)); 110 | } 111 | 112 | /** 113 | * Check the equality of this fraction and the {@code other} fraction. 114 | * @param o The other fraction of the equality comparison. 115 | * @return {@code true} if the fractions are equal, {@code false} otherwise. 116 | */ 117 | @Override public boolean equals(Object o) { 118 | if(o instanceof Fraction) { 119 | // downcast to correct subtype 120 | Fraction other = (Fraction)o; 121 | return (this.num.equals(other.num) && this.den.equals(other.den)); 122 | } 123 | else { 124 | return false; 125 | } 126 | } 127 | 128 | /** 129 | * Compute the hash code for this object. We combine the hash code from 130 | * the hash codes of the numerator and denominator. The bytes of the 131 | * denominator's hash code are swapped before combining results with 132 | * "exclusive or" operator ^, which you note does not mean the power 133 | * function in Java. Java does not have an integer power function at all. 134 | * Python's power function is **, with ^ in the same "xor" role as here. 135 | * @return The hash code of this Fraction. 136 | */ 137 | @Override public int hashCode() { 138 | int hd = den.hashCode(); 139 | int hn = num.hashCode(); 140 | // As not to hash a/b and b/a to the same value, do some bitwise 141 | // arithmetic to one of their hash codes to break the symmetry. 142 | hd = (hd >> 16) ^ ~(hd << 16); 143 | // Hash codes are best combined from pieces with bitwise xor. 144 | return hn ^ hd; // ^ is bitwise xor, not exponentiation. 145 | } 146 | 147 | /** 148 | * The ordering comparison of fractions. 149 | * @param other The other fraction of the order comparison. 150 | * @return -1, 0 or +1 depending on the result of the comparison. 151 | */ 152 | @Override public int compareTo(Fraction other) { 153 | // We just subtract the fractions and return the sign of result. 154 | Fraction diff = this.subtract(other); 155 | return diff.getNum().signum(); 156 | } 157 | 158 | /** 159 | * Construct the {@code String} representation of this fraction. 160 | */ 161 | public String toString() { 162 | if(den.equals(BigInteger.ONE)) { return num.toString(); } 163 | else { return num + "/" + den; } 164 | } 165 | 166 | // A private method for simplifying the initial value to the lowest terms. 167 | private void simplify() { 168 | if(den.signum() == -1) { // we want the denominator to always be positive 169 | den = den.negate(); num = num.negate(); 170 | } 171 | 172 | BigInteger gcd = num.gcd(den); // handy! 173 | num = num.divide(gcd); // to simplify a fraction num/den, divide both num 174 | den = den.divide(gcd); // and den by their greatest common divisor 175 | } 176 | 177 | // For demonstration purposes. 178 | public static void main(String[] args) { 179 | Fraction a = new Fraction(3, 7); // 3/7 180 | Fraction b = new Fraction(-2, 18); // -1/9 181 | Fraction c = a.add(b); // c = a + b 182 | c = c.multiply(a.subtract(b)); // c = c * (a-b) 183 | System.out.println("a is now " + a); 184 | System.out.println("b is now " + b); 185 | System.out.println("c is now " + c); 186 | } 187 | } -------------------------------------------------------------------------------- /GZip.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | import java.io.FileInputStream; 3 | import java.io.FileOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | import java.util.zip.GZIPInputStream; 8 | import java.util.zip.GZIPOutputStream; 9 | 10 | public class GZip { 11 | 12 | private static void gzipFile(String filename) throws IOException { 13 | // Create the compressed version of the original file. 14 | File original = new File(filename); 15 | // The policy to name the resulting compressed version of the file. 16 | String resultFileName = filename + ".gz"; 17 | 18 | try (InputStream source = new FileInputStream(original)) { 19 | try (OutputStream target = new GZIPOutputStream(new FileOutputStream(resultFileName))) { 20 | int b = source.read(); 21 | while (b != -1) { 22 | target.write(b); // Read and write bytes in lockstep 23 | b = source.read(); 24 | } 25 | } 26 | } 27 | // try-with-resources silently generates the finally-blocks to close both streams. 28 | 29 | // Before deleting the original, let's at least ensure that compression was successful. 30 | File compressedFile = new File(resultFileName); 31 | if(!(compressedFile.exists() && compressedFile.length() > 0)) { 32 | throw new IOException("Unable to create compressed file"); 33 | } 34 | try (InputStream originalStream = new FileInputStream(original)) { 35 | try (InputStream compressedStream = new GZIPInputStream(new FileInputStream(compressedFile))) { 36 | int b1, b2; 37 | do { 38 | b1 = originalStream.read(); 39 | b2 = compressedStream.read(); 40 | if (b1 != b2) { 41 | compressedFile.delete(); 42 | throw new IOException("Compression result not equal to original"); 43 | } 44 | } while(b1 > -1); 45 | // Having come this far, we are willing to put our head on the chopping block. 46 | original.delete(); 47 | } 48 | } 49 | } 50 | 51 | public static void main(String[] args) throws IOException { 52 | for(String filename: args) { 53 | gzipFile(filename); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /GameOfLife.java: -------------------------------------------------------------------------------- 1 | import java.awt.Color; 2 | import java.awt.Dimension; 3 | import java.awt.Graphics; 4 | import javax.swing.BorderFactory; 5 | import javax.swing.JFrame; 6 | import javax.swing.JPanel; 7 | import javax.swing.Timer; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | import java.awt.event.WindowAdapter; 11 | import java.awt.event.WindowEvent; 12 | import java.awt.image.BufferedImage; 13 | import java.util.Random; 14 | 15 | /** 16 | * Animate and display variations of Conway's Game of Life. The game starts running as soon 17 | * as the object is constructed, and keeps running one step per second until the method 18 | * {@code terminate} is called to stop the animation timer. 19 | * @author Ilkka Kokkarinen 20 | */ 21 | 22 | public class GameOfLife extends JPanel { 23 | 24 | private static final int PIXSIZE = 3; 25 | private static final int MARGIN = 40; 26 | private static final Random rng = new Random(); 27 | 28 | private boolean[][] board, newBoard; 29 | private final int size; // size of square grid as tiles 30 | private final String birth; // rules for birth and survival 31 | private final String survival; 32 | private final Timer t; // animation timer 33 | private final BufferedImage img; // draw directly to BufferedImage for speed 34 | private final int aliveColour = Color.BLACK.getRGB(); // colour to draw living cells 35 | private final int deadColour = Color.WHITE.getRGB(); // colour to draw dead cells 36 | 37 | /** 38 | * Constructor using the original Conway's Game of Life ruleset. 39 | * @param size The size of the automaton, measured in cells. 40 | */ 41 | public GameOfLife(int size) { this(size, "3", "23", 0.30); } 42 | 43 | /** 44 | * Constructor for generalized variants of Conway's Game of Life. 45 | * @param size The size of the automaton, measured in cells. 46 | * @param birth The string containing the values for which a cell comes alive, e.g. "3". 47 | * @param survival The string containing the values for which a cell survives, e.g. "23". 48 | * @param prob Probability that a cell is initially alive. 49 | */ 50 | public GameOfLife(int size, String birth, String survival, double prob) { 51 | this.size = size; 52 | this.birth = birth; 53 | this.survival = survival; 54 | int pix = size * PIXSIZE; 55 | this.img = new BufferedImage(pix, pix, BufferedImage.TYPE_INT_RGB); 56 | this.setPreferredSize(new Dimension(pix, pix)); 57 | this.setBorder(BorderFactory.createRaisedBevelBorder()); 58 | board = new boolean[size][size]; // initialize the board arrays 59 | newBoard = new boolean[size][size]; 60 | for(int x = MARGIN; x < size - MARGIN; ++x) { 61 | for(int y = MARGIN; y < size - MARGIN; ++y) { 62 | board[x][y] = rng.nextDouble() < prob; 63 | } 64 | } 65 | this.setBackground(new Color(deadColour)); 66 | 67 | // Tick every 500 milliseconds, generating an action event 68 | t = new Timer(500, new MyActionListener()); 69 | t.setInitialDelay(rng.nextInt(500)); // try to avoid lockstep with multiple games 70 | t.start(); 71 | } 72 | 73 | /** 74 | * Terminate the internal animation timer of the component so that the JVM can terminate. 75 | */ 76 | public void terminate() { 77 | t.stop(); // stop the timer in the end 78 | System.out.println("Game of Life timer terminated"); 79 | } 80 | 81 | private class MyActionListener implements ActionListener { 82 | public void actionPerformed(ActionEvent ae) { 83 | for(int x = 0; x < size; ++x) { 84 | for(int y = 0; y < size; ++y) { 85 | int sum = 0; // count the number of live variables into variable sum 86 | if(x > 0) { // look at the three cells above the cell (x,y) 87 | if(y > 0 && board[x-1][y-1]) ++sum; 88 | if(board[x-1][y]) ++sum; 89 | if(y < size-1 && board[x-1][y+1]) ++sum; 90 | } 91 | if(x < size-1) { // look at the three cells below the cell (x,y) 92 | if(y > 0 && board[x+1][y-1]) ++sum; 93 | if(board[x+1][y]) ++sum; 94 | if(y < size-1 && board[x+1][y+1]) ++sum; 95 | } 96 | if(y > 0 && board[x][y-1]) ++sum; // look at the cell to the left 97 | if(y < size-1 && board[x][y+1]) ++sum; // look at the cell to the right 98 | 99 | // the cell (x,y) is alive at next board if either 100 | // (1) it is alive now, and its neighbour count is among the survivals 101 | // (2) is is dead now, and its neighbour count is among the births 102 | newBoard[x][y] = 103 | (board[x][y] && survival.indexOf('0' + sum) > -1) || 104 | (!board[x][y] && birth.indexOf('0' + sum) > -1); 105 | 106 | // set the pixel of the image according to the new state of cell 107 | for(int px = 0; px < PIXSIZE; px++) { 108 | for(int py = 0; py < PIXSIZE; py++) { 109 | img.setRGB(x * PIXSIZE + px, y * PIXSIZE + py, 110 | newBoard[x][y] ? aliveColour: deadColour); 111 | } 112 | } 113 | 114 | } 115 | } 116 | boolean[][] tmp = board; // swap the references to the two board arrays 117 | board = newBoard; 118 | newBoard = tmp; 119 | repaint(); 120 | } 121 | } 122 | 123 | /** 124 | * Render this component as it currently looks like. 125 | * @param g The {@code Graphics} object provided by Swing for us to draw on. 126 | */ 127 | public void paintComponent(Graphics g) { 128 | super.paintComponent(g); 129 | g.drawImage(img, 0, 0, this); 130 | } 131 | 132 | private static final int SIZE = 150; 133 | private static int idx = 0; 134 | 135 | /** 136 | * A utility method to create a {@code JFrame} instance to display the game. 137 | * @param title The title of the frame. 138 | * @param g The {@code GameOfLife} instance to display in this frame. 139 | */ 140 | public static void createFrame(String title, final GameOfLife g, int x, int y) { 141 | final JFrame f = new JFrame(title); 142 | f.add(g); 143 | f.addWindowListener(new WindowAdapter() { 144 | public void windowClosing(WindowEvent we) { 145 | g.terminate(); // first kill the timer of the GameOfLife component 146 | f.dispose(); // and now we can safely dispose of the frame 147 | } 148 | }); 149 | f.pack(); 150 | int p = PIXSIZE * SIZE - 100; 151 | f.setLocation(x, y); 152 | ++idx; 153 | f.setVisible(true); 154 | } 155 | 156 | public static void main(String[] args) { 157 | // "Three or more, use a for!" 158 | createFrame("Conway's Game of Life", new GameOfLife(SIZE, "3", "23", 0.20), 100, 100); 159 | createFrame("Day & Night", new GameOfLife(SIZE, "3678", "34678", 0.40), 100, 600); 160 | createFrame("Mazectric", new GameOfLife(SIZE, "3", "1234", 0.05), 600, 100); 161 | // The survival of diamoeba depends greatly on initial filling probability. 162 | createFrame("Diamoeba", new GameOfLife(SIZE, "35678", "5678", 0.50), 600, 600); 163 | createFrame("Serviettes", new GameOfLife(SIZE, "234", "", 0.03), 1100, 100); 164 | createFrame("Gnarl", new GameOfLife(SIZE, "1", "1", 0.01), 1100, 600); 165 | // Plenty more available at http://www.mirekw.com/ca/rullex_life.html 166 | } 167 | } -------------------------------------------------------------------------------- /GenericsDemo.java: -------------------------------------------------------------------------------- 1 | import java.math.BigInteger; 2 | import java.util.ArrayList; 3 | import java.util.Arrays; 4 | import java.util.Collection; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | public class GenericsDemo { 10 | 11 | // From Java 5 on, the Collection classes are generic. Let's see if we can do something 12 | // there. Here is a method that checks for any kind of List if its elements are unique, 13 | // that is, there are no two duplicate elements anywhere in the list. 14 | public static boolean allUnique(List list) { 15 | for(int i = 0; i < list.size() - 1; i++) { 16 | for(int j = i+1; j < list.size(); j++) { 17 | if(list.get(i).equals(list.get(j))) return false; 18 | } 19 | } 20 | return true; 21 | } 22 | 23 | // Type parameter upper and lower bounds are occasionally handy. When a method takes 24 | // named typed parameters not already declared in the class, we need to declare them 25 | // in front of the method type. 26 | public static void addAll(Collection src, Collection tgt) { 27 | // Collections have addAll method already, but just as a practice. 28 | for(T elem: src) { tgt.add(elem); } 29 | } 30 | 31 | // The next method can be used to check if the list of type List is sorted, but only 32 | // if T is some type that implements the interface Comparable. 33 | public static > boolean isSorted(List list) { 34 | for(int i = 1; i < list.size(); i++) { 35 | if(list.get(i).compareTo(list.get(i-1)) < 0) return false; 36 | } 37 | return true; 38 | } 39 | 40 | // Even though ArrayList is a subtype of List, and Fraction is a subtype of 41 | // Object, it does not follow that ArrayList would be a subtype of 42 | // List. It cannot be, since the latter allows you to add a String 43 | // or whatever else kind of objects you want inside the list, whereas the 44 | // former can only take in Fraction objects! 45 | 46 | public static int noNines(List items) { 47 | int count = 0; 48 | for(Object item: items) { 49 | if(item.toString().indexOf('9') == -1) { 50 | count++; 51 | } 52 | } 53 | // For demonstration purposes, a little side effect. 54 | items.add("Hello world!"); 55 | // An instance of List would not be able to do that. 56 | return count; 57 | } 58 | 59 | // Knowing that every item is a Fraction, we can be more specific 60 | // about what we expect these items are able to do. 61 | public static int noNinesInDenominator(List items) { 62 | int count = 0; 63 | for(Fraction f: items) { 64 | BigInteger den = f.getDen(); 65 | if(den.toString().indexOf('9') == -1) { 66 | count++; 67 | } 68 | } 69 | return count; 70 | } 71 | 72 | // Demonstration how generics and type wildcards work. 73 | public static void main(String[] args) { 74 | Pair p1 = new Pair<>("Hello", 42); 75 | Pair p2 = new Pair<>("Hello", 42); 76 | Pair p3 = new Pair<>("World", 17); 77 | Pair> p4 = new Pair<>(1.234, p1); 78 | 79 | System.out.println("Pair count is now " + Pair.getCount()); // 4 80 | System.out.println("p1 equals p2? " + p1.equals(p2)); // true 81 | System.out.println("p1 equals p3? " + p1.equals(p3)); // false 82 | System.out.println("p1 same type as p4? " + (p1.getClass() == p4.getClass())); // true 83 | 84 | // A collection using type wildcards to allow heterogeneous content. 85 | ArrayList> pairs = new ArrayList<>(); 86 | pairs.add(p1); 87 | pairs.add(p2); 88 | pairs.add(p3); 89 | pairs.add(p4); 90 | System.out.println(pairs); // entire collection 91 | System.out.println("All unique? " + allUnique(pairs)); // false 92 | Pair elem = pairs.get(2); // one element 93 | System.out.println("We pulled out the element " + elem); 94 | // We can't assume anything about types of first and second here. 95 | // They just are some kind of objects, but that's all the type 96 | // system knows for the purposes of runtime type safety. 97 | 98 | // A more specifically typed collection, which then allows us to 99 | // assume more about its element types. 100 | Set> pairSet = new HashSet<>(); 101 | pairSet.add(p1); 102 | pairSet.add(p2); // already there 103 | pairSet.add(p3); 104 | int tally = 0; 105 | for(Pair p: pairSet) { 106 | // We know that getSecond() will return an integer. 107 | tally += p.getSecond(); // So this is legal. 108 | } 109 | System.out.println("Final tally is " + tally); 110 | 111 | // Another list, this time containing elements that are Comparable. 112 | List a = Arrays.asList(1, 2, 3, 5, 4); // a vararg utility method 113 | System.out.println("All unique? " + allUnique(a)); // true 114 | System.out.println("Is sorted? " + isSorted(a)); // false 115 | List b = new ArrayList<>(); // a list of arbitrary elements 116 | b.add("Hello world"); 117 | addAll(a,b); // in a call to generic method, compiler infers type parameters 118 | System.out.println("The list is now " + b); // [Hello World, 1, 2, 3, 4, 5]; 119 | 120 | List fs = Arrays.asList( 121 | new Fraction(3, 19), 122 | new Fraction(7, 18), 123 | new Fraction(-1, 99), 124 | new Fraction(12345, 54321) 125 | ); 126 | int noNinesDen = noNinesInDenominator(fs); 127 | System.out.println("The list contains " + noNinesDen + 128 | " fractions without a nine in denominator."); 129 | // This call would not compile, uncomment to convince yourself. 130 | // int noNines = noNines(fs); 131 | } 132 | } -------------------------------------------------------------------------------- /Greeter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The first example class for CCPS 109. An object constructed from this 3 | * class has two capabilities, the ability to output a greeting, and the 4 | * ability to output a bye message. The objects contain no data fields or 5 | * other internal state. 6 | * @author Ilkka Kokkarinen 7 | */ 8 | 9 | public class Greeter { 10 | 11 | /** 12 | * Outputs a simple greeting to the console. 13 | */ 14 | public void greet() { 15 | System.out.println("Hello, world!"); 16 | } 17 | 18 | /** 19 | * Outputs a simple goodbye message to the console. 20 | */ 21 | public void bye() { 22 | System.out.println("See you later!"); 23 | } 24 | 25 | /** 26 | * Having the main method allows this class to execute as a 27 | * standalone application. When using BlueJ, you don't need 28 | * a main method in your class to try out its objects and 29 | * their methods interactively. Most classes are not intended 30 | * to be standalone applications, but to be used as parts of 31 | * some larger program. 32 | */ 33 | public static void main(String[] args) { 34 | // Declare and create a new Greeter object. 35 | Greeter g = new Greeter(); 36 | // Now we can call its methods. 37 | g.greet(); 38 | g.bye(); 39 | g.greet(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /HammingTriple.java: -------------------------------------------------------------------------------- 1 | import java.math.BigInteger; 2 | import java.util.PriorityQueue; 3 | 4 | public class HammingTriple implements Comparable { 5 | 6 | // Precompute a couple of constants that we need all the time 7 | private static final BigInteger two = BigInteger.valueOf(2); 8 | private static final BigInteger three = BigInteger.valueOf(3); 9 | private static final BigInteger five = BigInteger.valueOf(5); 10 | private static final double logOf2 = Math.log(2); 11 | private static final double logOf3 = Math.log(3); 12 | private static final double logOf5 = Math.log(5); 13 | 14 | // The powers of this triple 15 | private int a; 16 | private final int b; 17 | private final int c; 18 | 19 | public HammingTriple(int a, int b, int c) { 20 | this.a = a; this.b = b; this.c = c; 21 | } 22 | 23 | public String toString() { 24 | return "[" + a + ", " + b + ", " + c + "]"; 25 | } 26 | 27 | public BigInteger getValue() { 28 | return two.pow(a).multiply(three.pow(b)).multiply(five.pow(c)); 29 | } 30 | 31 | public boolean equals(Object other) { 32 | if(other instanceof HammingTriple) { 33 | HammingTriple h = (HammingTriple) other; 34 | return this.a == h.a && this.b == h.b && this.c == h.c; 35 | } 36 | else { return false; } 37 | } 38 | 39 | // Return 0 if this == other, +1 if this > other, and -1 if this < other 40 | public int compareTo(HammingTriple other) { 41 | // equality 42 | if(this.a == other.a && this.b == other.b && this.c == other.c) { 43 | return 0; 44 | } 45 | // this dominates 46 | if(this.a >= other.a && this.b >= other.b && this.c >= other.c) { 47 | return +1; 48 | } 49 | // other dominates 50 | if(this.a <= other.a && this.b <= other.b && this.c <= other.c) { 51 | return -1; 52 | } 53 | 54 | // take the logarithms for comparison 55 | double log1 = this.a * logOf2 + this.b * logOf3 + this.c * logOf5; 56 | double log2 = other.a * logOf2 + other.b * logOf3 + other.c * logOf5; 57 | 58 | // are these different enough to be reliable? 59 | if(Math.abs(log1 - log2) > 0.0000001) { 60 | return (log1 < log2) ? -1: +1; 61 | } 62 | 63 | // oh well, looks like we have to do this the hard way 64 | return this.getValue().compareTo(other.getValue()); 65 | // (getting this far should be pretty rare, though) 66 | } 67 | 68 | public static BigInteger computeHamming(int n, boolean verbose) { 69 | if(verbose) { 70 | System.out.println("Hamming number #" + n); 71 | } 72 | long startTime = System.currentTimeMillis(); 73 | 74 | // The elements of the search frontier 75 | PriorityQueue frontierQ = new PriorityQueue<>(); 76 | int maxFrontierSize = 1; 77 | 78 | // Initialize the frontier 79 | frontierQ.offer(new HammingTriple(0, 0, 0)); // 1 80 | 81 | while(true) { 82 | if(frontierQ.size() > maxFrontierSize) { 83 | maxFrontierSize = frontierQ.size(); 84 | } 85 | // Pop out the next Hamming number from the frontier 86 | HammingTriple curr = frontierQ.poll(); 87 | 88 | if(--n == 0) { 89 | if(verbose) { 90 | System.out.println("Time: " + (System.currentTimeMillis() - startTime) + " ms"); 91 | System.out.println("Frontier max size: " + maxFrontierSize); 92 | assert curr != null; 93 | System.out.println("As powers: " + curr); 94 | System.out.println("As value: " + curr.getValue()); 95 | } 96 | assert curr != null; 97 | return curr.getValue(); 98 | } 99 | 100 | // Current times five, if at origin in (a,b) plane 101 | assert curr != null; 102 | if(curr.a == 0 && curr.b == 0) { 103 | frontierQ.offer(new HammingTriple(curr.a, curr.b, curr.c + 1)); 104 | } 105 | // Current times three, if at line a == 0 106 | if(curr.a == 0) { 107 | frontierQ.offer(new HammingTriple(curr.a, curr.b + 1, curr.c)); 108 | } 109 | // Current times two, unconditionally 110 | curr.a++; 111 | frontierQ.offer(curr); // reuse the current HammingTriple object 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /ImageDemo.java: -------------------------------------------------------------------------------- 1 | import java.awt.BasicStroke; 2 | import java.awt.Color; 3 | import java.awt.Dimension; 4 | import java.awt.FlowLayout; 5 | import java.awt.Graphics; 6 | import java.awt.Graphics2D; 7 | import java.awt.Image; 8 | import java.awt.RenderingHints; 9 | import java.awt.event.ActionEvent; 10 | import java.awt.event.ActionListener; 11 | import java.awt.geom.Ellipse2D; 12 | import java.awt.image.BufferedImage; 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.util.Random; 16 | import javax.imageio.ImageIO; 17 | import javax.swing.ImageIcon; 18 | import javax.swing.JButton; 19 | import javax.swing.JFrame; 20 | import javax.swing.JPanel; 21 | 22 | /** 23 | * A Swing example class that demonstrate how to download, render and modify images. 24 | * @author Ilkka Kokkarinen 25 | */ 26 | 27 | public class ImageDemo extends JPanel { 28 | private Image coffee; 29 | private Image flappy; 30 | private final BufferedImage bimg1; 31 | private final BufferedImage bimg2; 32 | private final Random rng = new Random(); 33 | 34 | // Utility method to pack three RGB components into bytes of single int. 35 | private int convertToRGB(int r, int g, int b) { 36 | return (r & 0xff) << 16 | (g & 0xff) << 8 | (b & 0xff); 37 | } 38 | 39 | public ImageDemo() throws IOException { 40 | // We can read an image from gif, jpeg, png file... 41 | coffee = ImageIO.read(new File("coffee.jpg")); 42 | flappy = ImageIO.read(new File("flappy.png")); 43 | // Take a wild guess which ImageIO method would then write an image to a file. 44 | 45 | // Images can be easily scaled to desired size. 46 | coffee = coffee.getScaledInstance(800, 600, Image.SCALE_AREA_AVERAGING); 47 | Image lilcoffee = coffee.getScaledInstance(50, 50, Image.SCALE_AREA_AVERAGING); 48 | flappy = flappy.getScaledInstance(25, 25, Image.SCALE_AREA_AVERAGING); 49 | 50 | // We can also create our own BufferedImage and draw stuff in it the 51 | // same way as you draw in paintComponent method, or read and write 52 | // the individual pixels directly. 53 | bimg1 = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); 54 | bimg2 = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); 55 | for(int x = 0; x < 256; x++) { 56 | for(int y = 0; y < 256; y++) { 57 | bimg1.setRGB(x, y, convertToRGB(x, 256 - y, (x + y) % 256)); 58 | bimg2.setRGB(x, y, convertToRGB((2*x+y) % 256, (x + y) % 256, y)); 59 | } 60 | } 61 | // You can ask any image for a Graphics object to draw into that image. 62 | Graphics2D g2 = (Graphics2D)bimg1.getGraphics(); 63 | g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 64 | RenderingHints.VALUE_ANTIALIAS_ON); 65 | g2.setStroke(new BasicStroke(5.0f)); 66 | g2.setPaint(Color.BLACK); 67 | g2.draw(new Ellipse2D.Double(64, 64, 128, 128)); 68 | 69 | // An image can also be used as ImageIcon shown inside JLabel, JButton or similar. 70 | this.setLayout(new FlowLayout()); 71 | JButton button = new JButton(new ImageIcon(lilcoffee)); 72 | this.add(button); 73 | button.addActionListener(new ButtonListener()); 74 | this.setPreferredSize( 75 | new Dimension(coffee.getWidth(this) + 256, coffee.getHeight(this)) 76 | ); 77 | } 78 | 79 | private class ButtonListener implements ActionListener { 80 | public void actionPerformed(ActionEvent ae) { repaint(); } 81 | } 82 | 83 | /** 84 | * Render this component as it currently looks like. 85 | * @param g The {@code Graphics} object provided by Swing for us to draw on. 86 | */ 87 | public void paintComponent(Graphics g) { 88 | super.paintComponent(g); 89 | Graphics2D g2 = (Graphics2D)g; 90 | g2.drawImage(coffee, 0, 0, this); 91 | g2.drawImage(bimg1, coffee.getWidth(this), 0, this); 92 | g2.drawImage(bimg2, coffee.getWidth(this), 256, this); 93 | for(int i = 0; i < 20; i++) { 94 | // With PNG images, the transparency information is stored alongside the colours. 95 | g2.drawImage(flappy, rng.nextInt(this.getWidth()), rng.nextInt(this.getHeight()), this); 96 | } 97 | } 98 | 99 | public static void main(String[] args) throws IOException { 100 | JFrame f = new JFrame("Imagedemo"); 101 | f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 102 | f.setLayout(new FlowLayout()); 103 | f.add(new ImageDemo()); 104 | f.pack(); 105 | f.setVisible(true); 106 | } 107 | } -------------------------------------------------------------------------------- /ImageLoops.java: -------------------------------------------------------------------------------- 1 | import javax.swing.JFrame; 2 | import javax.swing.JPanel; 3 | import java.awt.Color; 4 | import java.awt.Dimension; 5 | import java.awt.FlowLayout; 6 | import java.awt.Graphics; 7 | import java.awt.image.BufferedImage; 8 | import java.util.function.BiPredicate; 9 | 10 | // First demonstration of lambdas in Java 8. 11 | 12 | public class ImageLoops { 13 | 14 | // Objects of class Color represent individual colours. However, for low-level 15 | // drawing, the colours are represented and encoded as four-byte integers. 16 | private static final int WHITE = Color.WHITE.getRGB(); 17 | 18 | // Define the size and padding as named constants. 19 | private static final int SIZE = 400; 20 | private static final int PAD = 40; 21 | private static final int BOX = 25; 22 | 23 | // Render the pixels (x, y) that satisfy the predicate given as parameter. 24 | public static BufferedImage computeImage(int w, int h, BiPredicate pred) { 25 | BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); 26 | for(int x = 0; x < w; x++) { 27 | for(int y = 0; y < h; y++) { 28 | if(pred.test(x, y)) { 29 | img.setRGB(x, y, WHITE); 30 | } 31 | } 32 | } 33 | return img; 34 | } 35 | 36 | // A main method to display the images inside a panel inside a JFrame window. 37 | public static void main(String[] args) { 38 | JFrame f = new JFrame("Some images made with lambda expressions"); 39 | f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 40 | f.setLayout(new FlowLayout()); 41 | 42 | class ImagePanel extends JPanel { 43 | private final BufferedImage[] imgs = new BufferedImage[6]; 44 | public ImagePanel() { 45 | this.setPreferredSize(new Dimension(3*SIZE + 4*PAD, 2*SIZE + 3*PAD)); 46 | this.setBackground(new Color(30, 30, 60)); 47 | imgs[0] = computeImage(SIZE, SIZE, 48 | (x, y) -> (x / BOX) % 2 != (y / BOX) % 2 49 | ); 50 | imgs[1] = computeImage(SIZE, SIZE, 51 | (x, y) -> (5*x + 3*y) / (BOX * 3) % 2 == 0 52 | ); 53 | imgs[2] = computeImage(SIZE, SIZE, 54 | (x, y) -> (x / BOX) % 2 == 0 && ((y + 3*x/BOX) / BOX) % 2 == 0 55 | ); 56 | imgs[3] = computeImage(SIZE, SIZE, (x, y) -> 57 | (x + y) / BOX % 2 == 0 && 58 | (x >= y ? (x - y) / BOX % 2 == 0 : (y - x) / BOX % 2 == 1) 59 | ); 60 | // From TAOCP 7.1.3, via yurichev.com 61 | imgs[4] = computeImage(SIZE, SIZE, (x, y) -> ((y*y*x >> 11) & 1) > 0); 62 | imgs[5] = computeImage(SIZE, SIZE, (x, y) -> { 63 | int c = x*x-2*(x&y)+y|x + (x^y); 64 | c = c % 256; 65 | return c < -55 || c > 106; 66 | }); 67 | } 68 | 69 | public void paintComponent(Graphics g) { 70 | super.paintComponent(g); 71 | for(int i = 0; i < imgs.length; i++) { 72 | if(imgs[i] != null) { 73 | int row = i / 3; 74 | int col = i % 3; 75 | g.drawImage(imgs[i], PAD + (PAD + SIZE) * col, PAD + (PAD + SIZE) * row, this); 76 | } 77 | } 78 | } 79 | } 80 | 81 | f.add(new ImagePanel()); 82 | f.pack(); 83 | f.setVisible(true); 84 | } 85 | } -------------------------------------------------------------------------------- /ImageOpsDemo.java: -------------------------------------------------------------------------------- 1 | import java.awt.Dimension; 2 | import java.awt.FlowLayout; 3 | import java.awt.Graphics; 4 | import java.awt.Image; 5 | import java.awt.MediaTracker; 6 | import java.awt.Toolkit; 7 | import java.awt.geom.AffineTransform; 8 | import java.awt.image.AffineTransformOp; 9 | import java.awt.image.BufferedImageFilter; 10 | import java.awt.image.BufferedImageOp; 11 | import java.awt.image.ConvolveOp; 12 | import java.awt.image.CropImageFilter; 13 | import java.awt.image.FilteredImageSource; 14 | import java.awt.image.ImageFilter; 15 | import java.awt.image.ImageProducer; 16 | import java.awt.image.Kernel; 17 | import java.awt.image.RGBImageFilter; 18 | import java.io.File; 19 | import java.io.IOException; 20 | import java.util.Arrays; 21 | import javax.imageio.ImageIO; 22 | import javax.swing.BorderFactory; 23 | import javax.swing.JFrame; 24 | import javax.swing.JPanel; 25 | 26 | // Demonstration of Image processing using ImageFilter subtypes to perform image 27 | // operations such as colour conversion, cropping and rotation on images. 28 | 29 | public class ImageOpsDemo { 30 | 31 | // An example of filtering an image with a subtype of RGBImageFilter. 32 | public static Image scrambleRGB(Image img, final int xs, final int ys) { 33 | class Scramble extends RGBImageFilter { 34 | @Override public int filterRGB(int x, int y, int rgb) { 35 | // Extract the individual rgb values from the packed int. 36 | int a = (rgb >> 24) & 0xFF; 37 | int r = (rgb >> 16) & 0xFF; 38 | int g = (rgb >> 8) & 0xFF; 39 | int b = rgb & 0xFF; 40 | int tmp; 41 | // Scramble the colours depending on parity of scaled x and y. 42 | switch((x/xs + y/ys) % 4) { 43 | case 0: tmp = r; r = g; g = tmp; break; 44 | case 1: tmp = r; r = b; b = tmp; break; 45 | case 2: tmp = b; b = g; g = tmp; break; 46 | default: 47 | } 48 | // Pack three rgb bytes into a single int. 49 | return (a << 24) | (r << 16) | (g << 8) | b; 50 | } 51 | } 52 | 53 | // The magic incantations to apply an ImageFilter to an image. 54 | ImageFilter filter = new Scramble(); 55 | ImageProducer producer = new FilteredImageSource(img.getSource(), filter); 56 | return Toolkit.getDefaultToolkit().createImage(producer); 57 | } 58 | 59 | public static Image rotate(Image img, int steps) { 60 | // Rotations are special case of affine transforms. 61 | AffineTransform rot90 = AffineTransform.getRotateInstance( 62 | steps * Math.PI / 2.0, img.getWidth(null) / 2.0, img.getHeight(null) / 2.0 63 | ); 64 | // Create a BufferedImageOp from that transformation. 65 | BufferedImageOp aop = new AffineTransformOp(rot90, AffineTransformOp.TYPE_BICUBIC); 66 | // Build a filter around that image operation, and proceed as before. 67 | ImageFilter filter = new BufferedImageFilter(aop); 68 | 69 | ImageProducer producer = new FilteredImageSource(img.getSource(), filter); 70 | Image result = Toolkit.getDefaultToolkit().createImage(producer); 71 | MediaTracker m = new MediaTracker(new JPanel()); 72 | m.addImage(result, 0); 73 | try { m.waitForAll(); } catch(InterruptedException ignored) { } 74 | return result; 75 | } 76 | 77 | // Many image processing operations can be rephrased as image convolutions 78 | // where different kernels achieve different ends. See the Wikipedia page 79 | // https://en.wikipedia.org/wiki/Kernel_(image_processing) for a taste. Too 80 | // bad the Java graphics library does not also have "deconvolution" like Wolfram... 81 | 82 | public static Image boxBlur(Image img, int r) { 83 | r = 2*r + 1; // (Kernel sizes are usually odd, but they don't have to be.) 84 | int rr = r * r; 85 | float n = 1.0f / rr; 86 | float[] a = new float[rr]; 87 | Arrays.fill(a, n); 88 | // The kernel of convolution is a rectangle of weights. 89 | Kernel kernel = new Kernel(r, r, a); 90 | // A convolution is determined by its kernel. 91 | BufferedImageOp edge = new ConvolveOp(kernel); 92 | ImageFilter filter = new BufferedImageFilter(edge); 93 | 94 | ImageProducer producer = new FilteredImageSource(img.getSource(), filter); 95 | Image result = Toolkit.getDefaultToolkit().createImage(producer); 96 | MediaTracker m = new MediaTracker(new JPanel()); 97 | m.addImage(result, 0); 98 | try { m.waitForAll(); } catch(InterruptedException ignored) { } 99 | return result; 100 | } 101 | 102 | // A little utility class to display images as Swing components. 103 | private static class ImagePanel extends JPanel { 104 | private final Image img; 105 | public ImagePanel(Image img, String toolTip) { 106 | this.img = img; 107 | this.setToolTipText(toolTip); 108 | this.setPreferredSize(new Dimension(img.getWidth(this), img.getHeight(this))); 109 | this.setBorder(BorderFactory.createEtchedBorder()); 110 | } 111 | public void paintComponent(Graphics g) { 112 | g.drawImage(img, 0, 0, this); 113 | } 114 | } 115 | 116 | public static void main(String[] args) throws IOException { 117 | // Read the image from the file. 118 | Image coffee = ImageIO.read(new File("coffee.jpg")); 119 | // Create a smaller version of the image. 120 | coffee = coffee.getScaledInstance(800, 600, Image.SCALE_SMOOTH); 121 | // Crop into a square area. 122 | ImageFilter cf = new CropImageFilter(100, 0, 600, 600); 123 | ImageProducer producer = new FilteredImageSource(coffee.getSource(), cf); 124 | coffee = Toolkit.getDefaultToolkit().createImage(producer); 125 | 126 | JFrame f = new JFrame("Image Operations Demo"); 127 | f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 128 | f.setLayout(new FlowLayout()); 129 | f.add(new ImagePanel(scrambleRGB(coffee, 7, 13), "Scramble")); 130 | f.add(new ImagePanel(rotate(coffee, 1), "Rotate 90 degrees right")); 131 | f.add(new ImagePanel(boxBlur(coffee, 5), "Box blur")); 132 | f.pack(); 133 | f.setVisible(true); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /InheritanceDemo.java: -------------------------------------------------------------------------------- 1 | // This doesn't do anything useful yet, just demonstrates the language. 2 | 3 | public class InheritanceDemo { 4 | 5 | // When a nested class is declared static, objects of that class can 6 | // exist on their own, without an outer class context object. 7 | 8 | private static class A { // superclass 9 | public int x; // can be accessed everywhere 10 | private int y; // can be accessed in same class only 11 | protected int z; // can be accessed by same class and subclasses 12 | 13 | public A() { 14 | System.out.println("Executing constructor of A"); 15 | x = 17; y = 42; z = 99; 16 | } 17 | 18 | public void outputValues() { 19 | System.out.println("x is " + x); 20 | System.out.println("y is " + y); 21 | System.out.println("z is " + z); 22 | } 23 | 24 | public void greet() { 25 | System.out.println("Hello"); 26 | } 27 | } 28 | 29 | private static class B extends A { // subclass 30 | public int w; // adding new fields 31 | public int x; // (yes, even this is possible, but bad) 32 | 33 | public B() { // Constructors are executed as chain down the line. 34 | System.out.println("Executing constructor of B"); 35 | w = -123; x = -999; 36 | } 37 | 38 | @Override 39 | public void outputValues() { // overriding an inherited method 40 | super.outputValues(); // we first call the superclass version of method 41 | System.out.println("w is " + w); // then output the new field 42 | System.out.println("x defined in B is " + x); 43 | System.out.println("x inherited from A is " + super.x); 44 | } 45 | 46 | @Override 47 | public void greet() { // overriding an inherited method 48 | System.out.println("Hi there"); 49 | // Note that in this method, we don't call the superclass version. 50 | } 51 | 52 | public void bye() { // defining whole new methods in the subclass 53 | System.out.println("Bye"); 54 | } 55 | } 56 | 57 | public static void main(String[] args) { 58 | A first = new A(); 59 | A second = new B(); 60 | B third = new B(); 61 | 62 | first.greet(); // Hello 63 | second.greet(); // Hi there 64 | third.greet(); // Hi there 65 | 66 | System.out.println("Output the values of first object:"); 67 | first.outputValues(); 68 | System.out.println("Output the values of second object:"); 69 | second.outputValues(); 70 | System.out.println("Output the values of third object:"); 71 | third.outputValues(); 72 | 73 | // first.bye(); wouldn't compile 74 | // second.bye(); wouldn't compile either 75 | third.bye(); // compiles and runs 76 | } 77 | } -------------------------------------------------------------------------------- /Java5Demo.java: -------------------------------------------------------------------------------- 1 | // Ordinary imports 2 | import java.lang.annotation.Annotation; 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | import java.lang.reflect.Field; 8 | import java.util.PriorityQueue; 9 | import java.util.Queue; 10 | 11 | // Static imports 12 | import static java.lang.Math.sqrt; 13 | import static java.lang.System.out; 14 | 15 | // Java 5 came out in 2005. Its features are no longer new, but established part of the 16 | // language. Pretty soon I will have students who are younger than Java 5. 17 | 18 | public class Java5Demo { 19 | 20 | // Annotations. To define your annotation type, use @interface. 21 | // Annotations can themselves be annotated with meta-annotations, 22 | // especially to define their retention policy and target. 23 | @Retention(RetentionPolicy.RUNTIME) // keep for runtime 24 | @Target(ElementType.TYPE) // May be applied to classes and other types 25 | @interface Author { 26 | String name(); 27 | int year() default 2014; // How the time goes by... 28 | } 29 | 30 | // Let us use our new annotation type on a little class. 31 | @Author(name = "Ilkka Kokkarinen") 32 | private static class AnnotationDemo { /* whatevs */ } 33 | 34 | // And then use reflection to examine it at the runtime. If the 35 | // Author annotation were not retained until runtime, but discarded 36 | // after compilation, it would not show up in the following output. 37 | public static void annotationDemo() { 38 | System.out.println("Starting annotationDemo."); 39 | AnnotationDemo at = new AnnotationDemo(); 40 | Class c = at.getClass(); 41 | for(Annotation ant: c.getAnnotations()) { 42 | System.out.println("Found annotation: " + ant); 43 | } 44 | System.out.println("Finished annotationDemo.\n"); 45 | } 46 | 47 | // Boxing and unboxing demonstrated. IntelliJ IDEA will mark many of these redundant. 48 | public static void boxingDemo() { 49 | System.out.println("Starting boxingDemo."); 50 | Integer a = 42; // Boxing primitive to wrapper, small enough to be in cache. 51 | Integer b = 42; // Boxing primitive to wrapper, reuses 42 from cache. 52 | int c = 42; // Primitive int value. 53 | assert a == c; // Primitive vs. wrapper, unbox and compare values. 54 | assert a == b; // Wrapper vs. wrapper, memory address comparison. 55 | assert a.equals(b); // Wrapper vs. wrapper, object content comparison. 56 | 57 | Integer d = 84; // Boxing primitive to wrapper, small enough to be in cache. 58 | Integer e = new Integer(84); // new always creates a new object, no matter what 59 | assert d != e; // Memory address comparison, guaranteed unequal here. 60 | assert d.equals(e); // Wrapper vs. wrapper, object content comparison. 61 | assert a + b == e; // Arithmetic automatically unboxes before the operation. 62 | assert 2 * a == e; 63 | assert e / 2 == b; 64 | assert a < e; // As do the order comparisons. 65 | 66 | Integer f = 9999; // Boxing primitive to wrapper, outside the cache range. 67 | Integer g = 9999; // Boxing primitive to wrapper, outside the cache range. 68 | assert f != g; // Memory address comparison, guaranteed different here. 69 | assert f.equals(g); // Wrapper vs. wrapper, object content comparison. 70 | 71 | System.out.println("Sleep well. Integers still work the way they are supposed to."); 72 | System.out.println("Finished boxingDemo.\n"); 73 | } 74 | 75 | // Varargs 76 | public static String concatenate(Object... rest) { 77 | StringBuilder result = new StringBuilder(); 78 | for(Object o: rest) { result.append(o).append(" "); } 79 | return result.toString(); 80 | } 81 | 82 | // C-style printf 83 | public static void printfDemo() { 84 | System.out.println("Starting printfDemo."); 85 | int a = 99; char b = 'x'; String c = "Hello"; 86 | out.printf("Now a = %d, b = %c and c = %s\n", a, b, c); 87 | double d = 1234.56789; 88 | out.printf("To two decimal places, sqrt(d) = %.2f\n", sqrt(d)); 89 | System.out.println("Finished printfDemo.\n"); 90 | } 91 | 92 | // Adapted from a thread in Stack Overflow. Truly evil. 93 | public static void orwellianDemo() throws Exception { 94 | System.out.println("Starting orwellianDemo."); 95 | Class cacheType = Integer.class.getDeclaredClasses()[0]; 96 | Field c = cacheType.getDeclaredField("cache"); 97 | c.setAccessible(true); // Tell reflection not to care about field c being private. 98 | Integer[] cachedIntegers = (Integer[]) c.get(cacheType); 99 | cachedIntegers[132] = cachedIntegers[133]; // 4 is at position 132, 5 is at 133 100 | // Two plus two is whatever The Party says it is, Winston. 101 | System.out.printf("Two plus two equals %d.\n", 2+2); // 5 102 | // Even the basic laws of arithmetic must yield to doublethink. 103 | System.out.println("Finished orwellianDemo.\n"); 104 | } 105 | 106 | // Queue collections: an absurdity in terms. Saying that a Queue is-a 107 | // Collection is just like saying that a Car is-an Engine. 108 | public static void queueDemo() { 109 | System.out.println("Starting queueDemo."); 110 | Queue aq = new PriorityQueue<>(); 111 | aq.add(7); aq.offer(2); aq.offer(3); 112 | out.println("head element: " + aq.peek()); // 2 113 | out.println("popped element: " + aq.remove()); // 2 114 | out.println("head element: " + aq.peek()); // 3 115 | out.println("popped element: " + aq.remove()); // 3 116 | out.println("popped element: " + aq.remove()); // 7 117 | System.out.println("Finished queueDemo.\n"); 118 | } 119 | 120 | // That said, PriorityQueue often comes handy in clever algorithms. 121 | // Just don't pretend that it is also some kind of Collection. (Or a 122 | // floor wax. Or a dessert topping.) 123 | 124 | public static void main(String[] args) { 125 | annotationDemo(); 126 | boxingDemo(); 127 | printfDemo(); 128 | queueDemo(); 129 | try { 130 | orwellianDemo(); 131 | } catch(Exception e) { 132 | System.out.println("Caught exception " + e + " from orwellianDemo."); 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /Length.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The first proper class in this course is a class whose instances represent 3 | * lengths. The same length can be expressed in both centimeters and inches. 4 | * (It is still the same physical quantity, even if the units that we use to 5 | * talk about it are different.) 6 | * 7 | * "All services offered by a module should be available through a uniform 8 | * notation, which does not betray whether they are implemented through storage 9 | * or through computation." -- Bertrand Meyer 10 | * 11 | * https://martinfowler.com/bliki/UniformAccessPrinciple.html 12 | * 13 | * @author Ilkka Kokkarinen 14 | */ 15 | 16 | public class Length { 17 | 18 | // We choose to store the length in centimeters. We could have just as well 19 | // chosen to store the length in inches, in which case the following methods 20 | // would have been written as mirror images. 21 | private double cm; 22 | 23 | /** 24 | * Setter method for centimeters. 25 | * @param newCM The new length in centimeters. 26 | */ 27 | public void setCentimeters(double newCM) { 28 | cm = newCM; // Assign parameter value to the data field inside the object. 29 | } 30 | 31 | /** 32 | * Getter method for centimeters. 33 | * @return The current length in centimeters. 34 | */ 35 | public double getCentimeters() { 36 | return cm; // Return the value from data field inside the object. 37 | } 38 | 39 | // First the conversion factor: to declare a field static means that it is 40 | // shared between all objects of this class, and to also declare it final 41 | // means that it is a "named constant" whose value cannot be changed later. 42 | // You should prefer named constants to "magic numbers" hardwired in code. 43 | private static final double CM_PER_INCH = 2.54; 44 | 45 | /** 46 | * Setter method for inches. 47 | * @param inches The new length in inches. 48 | */ 49 | public void setInches(double inches) { 50 | cm = inches * CM_PER_INCH; // Convert inches to cm for storage. 51 | } 52 | 53 | /** 54 | * Getter method for inches. 55 | * @return The current length in inches. 56 | */ 57 | public double getInches() { 58 | return cm / CM_PER_INCH; // Convert stored cm to inches. 59 | } 60 | 61 | // As an exercise, try modifying this class to allow the length to be accessed in 62 | // some more exotic units such as furlongs or light seconds. The idea is the same 63 | // as with inches, you just need to look up or compute the appropriate conversion 64 | // factor to be defined as a similar named constant as CM_PER_INCH. 65 | 66 | /** 67 | * Constructor for this class. 68 | * @param newCM The length in centimeters. 69 | */ 70 | public Length(double newCM) { 71 | // We can call existing methods in the class, instead of duplicating their code. 72 | // This does not make a big difference here, but might in a different class where 73 | // the field initialization requires some more complex computations and checks. 74 | setCentimeters(newCM); 75 | } 76 | 77 | /** 78 | * Compute and return the String representation of this Length object. 79 | * @return The length stored in this object in centimeters. 80 | */ 81 | public String toString() { 82 | return "Length of " + this.cm + " cm."; // String representation of this object. 83 | } 84 | 85 | /** 86 | * A main method for demonstration purposes. This class is not really intended 87 | * as a standalone application, but is to be used as a part of a larger system. 88 | */ 89 | public static void main(String[] args) { 90 | Length a = new Length(20); // Create a new object with the operator new. 91 | System.out.println(a); // A length of 20 cm. 92 | Length b = new Length(20); // Another new object. 93 | System.out.println("a in centimeters is " + a.getCentimeters()); // 20 94 | System.out.println("a in inches is " + a.getInches()); // 7.874015748031496 95 | System.out.println("b in centimeters is " + b.getCentimeters()); // 20 96 | System.out.println("b in inches is " + b.getInches()); // 7.874015748031496 97 | a.setInches(20); 98 | System.out.println("a in centimeters is " + a.getCentimeters()); // 50.8 99 | System.out.println("a in inches is " + a.getInches()); // 20.0 100 | System.out.println("b in centimeters is " + b.getCentimeters()); // 20 101 | System.out.println("b in inches is " + b.getInches()); // 7.874015748031496 102 | // See the DataDemo example to find out how to print decimal numbers up 103 | // to some more reasonable precision. 104 | } 105 | } -------------------------------------------------------------------------------- /LinePrinter.java: -------------------------------------------------------------------------------- 1 | import java.io.PrintWriter; 2 | 3 | public class LinePrinter { 4 | private final int lineMaxLength; // Maximum desired length of a line. 5 | private int lineLen; // Length of the current line. 6 | private final PrintWriter target; // Where to direct the printed characters. 7 | private boolean firstInLine = true; // Is the current word first in this line? 8 | 9 | public LinePrinter(PrintWriter target, int lineMaxLength) { 10 | this.target = target; 11 | this.lineMaxLength = lineMaxLength; 12 | } 13 | 14 | public void printWord(String word) { 15 | // If adding the current word would make the line too long, start a new line. 16 | if(lineLen + (firstInLine? 0: 1) + word.length() > lineMaxLength) { 17 | lineBreak(); 18 | } 19 | // Print a space before the current word, unless it's the first word in line. 20 | if(!firstInLine) { 21 | target.print(" "); 22 | lineLen++; 23 | } 24 | // Print the actual word. 25 | target.print(word); 26 | firstInLine = false; 27 | lineLen += word.length(); 28 | } 29 | 30 | public void lineBreak() { 31 | target.println(""); 32 | target.flush(); // Emulate the behaviour flushing at line breaks. 33 | lineLen = 0; 34 | firstInLine = true; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /MapReduceDemo.java: -------------------------------------------------------------------------------- 1 | import java.math.BigInteger; 2 | import java.util.Arrays; 3 | import java.util.List; 4 | import java.util.Random; 5 | import java.util.function.IntPredicate; 6 | import java.util.function.Predicate; 7 | import java.util.function.Supplier; 8 | import java.util.stream.Collectors; 9 | import java.util.stream.IntStream; 10 | import java.util.stream.Stream; 11 | 12 | public class MapReduceDemo { 13 | 14 | // IntPredicate object defined as a lambda: the compiler expands 15 | // all that anonymous subclass boilerplate rigmarole automatically. 16 | // This predicate is stateless, so it can be used in a parallel 17 | // stream of integers as well as sequential stream. 18 | private static final IntPredicate PRIME_TESTER = n -> { 19 | if(n < 2) { return false; } 20 | if(n == 2) { return true; } 21 | if(n % 2 == 0) { return false; } 22 | for(int i = 3; i * i <= n; i += 2) { 23 | if(n % i == 0) { return false; } 24 | } 25 | return true; 26 | }; 27 | 28 | public static void main(String[] args) { 29 | // Compute the sum of squares of 100 smallest distinct prime numbers 30 | // generated from the floors of the decimal numbers generated from 31 | // the given rng, but excluding the first ten. 32 | System.out.println("The sum of asked squares is " + 33 | new Random(12345).doubles() 34 | .map(x -> Math.sqrt(x * 1_000_000 + 3)) 35 | .mapToInt(x -> (int)x) 36 | .filter(PRIME_TESTER) // longer way: .filter(x -> PRIME_TESTER.test(x)) 37 | .skip(10) // skip the first 10 38 | .limit(90) // and take the first 90 of the rest 39 | .map(e -> e * e) // square the numbers 40 | .reduce(0, (state, elem) -> state + elem) // and add them up 41 | ); 42 | 43 | // Many other standard classes in Java are retrofitted to generate streams. 44 | List nums = Arrays.asList(16, 15, 22, 9, 7, 82, 17); 45 | System.out.println("The first prime number in the list is " + nums.stream() 46 | .mapToInt(Integer::intValue) // method reference with :: operator 47 | .filter(PRIME_TESTER) 48 | .findFirst() // An OptionalInt, as stream could be empty (this one isn't) 49 | .orElse(-1) // This is an OptionalInt method, not a Collector 50 | ); 51 | 52 | nums = Arrays.asList(4, 8, 15); // Let's try the same thing with no primes. 53 | System.out.println("The first prime number in the list is " + nums.stream() 54 | .mapToInt(x -> x) 55 | .filter(PRIME_TESTER) 56 | .findFirst() 57 | .orElse(-1)); 58 | 59 | System.out.println("Lazy evaluation with long, even infinite streams"); 60 | Stream.generate( () -> 42 ) // A stateless infinite stream 42, 42, 42, ... 61 | .limit(10) // that we cap to the maximum length of 10 62 | .forEach(System.out::println); // to print out the elements 63 | 64 | // A huge stream 0, 1, 2, ... , 1,000,000,000. No problem, since Java 8 65 | // streams are evaluated in a lazy fashion. 66 | IntStream is = IntStream.rangeClosed(0, 1_000_000_000) 67 | .filter(PRIME_TESTER.negate()); // Predicates have a default method negate() 68 | 69 | // Notice how the stream has been defined, but no computation takes place 70 | // yet. The stream itself is an object, just sitting there in the memory, 71 | // and it can be assigned to a variable, passed to a method, or returned 72 | // as a result. Attaching some collector to the end of the stream will then 73 | // actually launch the evaluation by requesting elements from the stream. 74 | 75 | System.out.println("\nThe first 20 non-primes are " + 76 | is.limit(20) 77 | .boxed() 78 | .collect(Collectors.toList()) 79 | ); 80 | 81 | // Infinite stream of random numbers. Again, lazy evaluation prevents this 82 | // computation from falling into an infinite loop. 83 | System.out.println("Here are some filtered random numbers."); 84 | Random rng = new Random(); 85 | System.out.println( 86 | Stream.generate(rng::nextDouble) 87 | .filter(x -> x < 0.5) 88 | .limit(10) 89 | .map(Object::toString) 90 | .collect(Collectors.joining(", ", "<< ", " >>")) // French style quote marks 91 | ); 92 | 93 | // The interface Supplier can be used the same way as generators of other languages. 94 | // Suppliers can then be turned into infinite streams. Here is a supplier of Fibonacci 95 | // numbers. Since Fibonacci numbers grow exponentially, use BigInteger representation. 96 | class FibSupplier implements Supplier { 97 | BigInteger a = BigInteger.ZERO; // Internal state of the supplier. 98 | BigInteger b = BigInteger.ONE; 99 | public BigInteger get() { // The method called to supply the next element. 100 | BigInteger result = a; 101 | BigInteger c = a.add(b); 102 | a = b; 103 | b = c; 104 | return result; 105 | } 106 | } 107 | 108 | // Stateful predicates with fields cannot be implemented as lambdas. But they are 109 | // still classes, so we can write them explicitly as such. Also, the result of 110 | // the predicate can depend on things other than the element, although such a 111 | // stateful predicate would be nondeterministic if used in a parallel stream. 112 | class CountPredicate implements Predicate { 113 | private final int limit; 114 | private int count; 115 | public CountPredicate(int limit) { 116 | this.limit = limit; 117 | } 118 | public boolean test(T value) { 119 | count = (count + 1) % limit; 120 | return count == 0; 121 | } 122 | } 123 | 124 | // Combine the previous two classes to create a stream of skipped Fibonacci numbers. 125 | System.out.println("Here is every fifth Fibonacci number:"); 126 | Stream.generate(new FibSupplier()) 127 | //.parallel() // uncomment this line for some goofy nondeterminism 128 | .filter(new CountPredicate<>(5)) 129 | .limit(100) 130 | .forEach(System.out::println); 131 | 132 | // flatMap is a handy stream operator to expand individual elements to many elements. 133 | System.out.println("Prefix of the \"pyramid series\" generated with flatMap: "); 134 | // Generate the stream 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, ... 135 | IntStream.rangeClosed(1, 1_000_000_000) // enough 136 | .flatMap(e -> IntStream.rangeClosed(1, e).map(x -> e)) 137 | .limit(50) 138 | .forEach(x -> System.out.print(x + " ")); 139 | } 140 | } -------------------------------------------------------------------------------- /Minesweeper.java: -------------------------------------------------------------------------------- 1 | import javax.swing.JFrame; 2 | import javax.swing.JPanel; 3 | import java.awt.BasicStroke; 4 | import java.awt.Color; 5 | import java.awt.Dimension; 6 | import java.awt.FlowLayout; 7 | import java.awt.Font; 8 | import java.awt.Graphics; 9 | import java.awt.Graphics2D; 10 | import java.awt.RenderingHints; 11 | import java.awt.event.MouseAdapter; 12 | import java.awt.event.MouseEvent; 13 | import java.awt.geom.RoundRectangle2D; 14 | import java.util.Random; 15 | 16 | /** 17 | * A Java implementation of the classic Minesweeper game of Microsoft Windows. 18 | * @author Ilkka Kokkarinen 19 | */ 20 | 21 | public class Minesweeper extends JPanel { 22 | 23 | private final int gridWidth; 24 | private final int gridHeight; // Game board width and height in tiles 25 | private final double prob; // Probability that a tile becomes a mine 26 | private boolean gameOn; // Is the game on? 27 | private boolean first; // Is the player opening the first tile? 28 | private boolean[][] isMine, isOpen, isMarked; // State of the gameboard 29 | private int[][] value; // Precomputed numerical values to show 30 | private final Random rng = new Random(); 31 | 32 | private static final int TILESIZE = 30; 33 | private static final int XOFFSET = 10; 34 | private static final int YOFFSET = 10; 35 | private static final int NOFF = TILESIZE / 2 - 4; 36 | private static final Font font = new Font("Code2000", Font.BOLD, 12); 37 | 38 | /** 39 | * Construct a new Minesweeper panel of given size. 40 | * @param w The width of the gamefield, measured in tiles. 41 | * @param h The height of the gamefields, measured in tiles. 42 | * @param prob The probability of a tile initially containing a mine, from range 0 to 100. 43 | */ 44 | public Minesweeper(int w, int h, double prob) { 45 | this.setBackground(Color.GRAY); 46 | this.setPreferredSize(new Dimension(2 * XOFFSET + w * TILESIZE, 2 * YOFFSET + h * TILESIZE)); 47 | this.gridWidth = w; 48 | this.gridHeight = h; 49 | this.prob = prob; 50 | this.addMouseListener(new MineListener()); 51 | startNewGame(); 52 | } 53 | 54 | // Count how many neighbours of tile (x, y) are true in the data array. 55 | private int countNeighbours(boolean[][] data, int x, int y) { 56 | int sum = 0; 57 | if(x > 0) { 58 | if(y > 0 && data[x-1][y-1]) ++sum; 59 | if(data[x-1][y]) ++sum; 60 | if(y < gridHeight-1 && data[x-1][y+1]) ++sum; 61 | } 62 | if(x < gridWidth-1) { 63 | if(y > 0 && data[x+1][y-1]) ++sum; 64 | if(data[x+1][y]) ++sum; 65 | if(y < gridHeight-1 && data[x+1][y+1]) ++sum; 66 | } 67 | if(y > 0 && data[x][y-1]) ++sum; 68 | if(y < gridHeight-1 && data[x][y+1]) ++sum; 69 | return sum; 70 | } 71 | 72 | /** 73 | * Initialize a new game with each tile initially closed. The mines will not be 74 | * planted on the field until the first tile opening click done by the player. 75 | */ 76 | private void startNewGame() { 77 | gameOn = true; 78 | first = true; 79 | isMine = new boolean[gridWidth][gridHeight]; 80 | isOpen = new boolean[gridWidth][gridHeight]; 81 | isMarked = new boolean[gridWidth][gridHeight]; 82 | value = new int[gridWidth][gridHeight]; 83 | this.repaint(); 84 | } 85 | 86 | // Each tile becomes a mine with the given probability, independent of other tiles. 87 | private void seedMines(int sx, int sy) { 88 | for(int x = 0; x < gridWidth; x++) { 89 | for(int y = 0; y < gridHeight; y++) { 90 | isMine[x][y] = ((Math.abs(x-sx) + Math.abs(y-sy) > 2) && rng.nextDouble() < prob); 91 | } 92 | } 93 | for(int x = 0; x < gridWidth; x++) { 94 | for(int y = 0; y < gridHeight; y++) { 95 | value[x][y] = countNeighbours(isMine, x, y); 96 | } 97 | } 98 | } 99 | 100 | /** 101 | * Render this component as it currently looks like. 102 | * @param g The {@code Graphics} object provided by Swing for us to draw on. 103 | */ 104 | public void paintComponent(Graphics g) { 105 | super.paintComponent(g); 106 | Graphics2D g2 = (Graphics2D)g; // convert to better Graphics2D 107 | g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 108 | RenderingHints.VALUE_ANTIALIAS_ON); // looks nicer 109 | 110 | g2.setFont(font); 111 | g2.setStroke(new BasicStroke(2.0f)); 112 | for(int x = 0; x < gridWidth; x++) { 113 | for(int y = 0; y < gridHeight; y++) { 114 | int bx = XOFFSET + TILESIZE * x; 115 | int by = YOFFSET + TILESIZE * (y + 1); 116 | if(isOpen[x][y]) { 117 | if(isMine[x][y]) { 118 | g2.drawString("M", bx + NOFF, by - NOFF); 119 | } 120 | else if(value[x][y] > 0) { 121 | g2.drawString("" + value[x][y], bx + NOFF, by - NOFF); 122 | } 123 | } 124 | else { 125 | RoundRectangle2D.Double rect = new RoundRectangle2D.Double( 126 | bx + 2, by - TILESIZE + 2, TILESIZE - 4, TILESIZE - 4, 5, 5 127 | ); 128 | g2.setPaint(isMarked[x][y]? Color.RED: Color.GREEN); 129 | g2.fill(rect); 130 | g2.setPaint(Color.BLACK); 131 | g2.draw(rect); 132 | } 133 | } 134 | } 135 | } 136 | 137 | private class MineListener extends MouseAdapter { 138 | @Override public void mousePressed(MouseEvent me) { 139 | if(!gameOn) { startNewGame(); return; } 140 | int x = (me.getX() - XOFFSET) / TILESIZE; 141 | int y = (me.getY() - YOFFSET) / TILESIZE; 142 | if(me.getButton() == MouseEvent.BUTTON1) { 143 | if(openTile(x, y, false)) { 144 | hitMine(); 145 | } 146 | } 147 | else { 148 | if(!isOpen[x][y]) { isMarked[x][y] = !isMarked[x][y]; } 149 | } 150 | for(x = 0; x < gridWidth; x++) { 151 | for(y = 0; y < gridHeight; y++) { 152 | if(isOpen[x][y] && value[x][y] == countNeighbours(isMarked, x, y)) { 153 | if(openTile(x, y, true)) { hitMine(); } 154 | } 155 | } 156 | } 157 | repaint(); 158 | } 159 | // The other four MouseListener methods are inherited from MouseAdapter. 160 | } 161 | 162 | // Open the tile (x, y). If neighbours is true, do not open but check whether 163 | // some tiles can be safely opened. Returns true if hit a mine, false if not. 164 | private boolean openTile(int x, int y, boolean neighbours) { 165 | if(x < 0 || x >= gridWidth || y < 0 || y >= gridHeight) { 166 | return false; // out of bounds, do nothing 167 | } 168 | if(!neighbours) { 169 | if(isOpen[x][y] || isMarked[x][y]) { return false; } 170 | if(first) { 171 | first = false; 172 | seedMines(x, y); 173 | } 174 | isOpen[x][y] = true; 175 | if(isMine[x][y]) { return true; } 176 | } 177 | // Generalization of the zero cell opening makes the game more fun 178 | boolean result = false; 179 | if(value[x][y] == countNeighbours(isMarked, x, y)) { 180 | result = openTile(x - 1, y - 1, false); 181 | result |= openTile(x-1, y, false); 182 | result |= openTile(x-1, y+1, false); 183 | result |= openTile(x+1, y-1, false); 184 | result |= openTile(x+1, y, false); 185 | result |= openTile(x+1, y+1, false); 186 | result |= openTile(x, y-1, false); 187 | result |= openTile(x, y+1, false); 188 | } 189 | return result; 190 | } 191 | 192 | private void hitMine() { 193 | gameOn = false; 194 | for(int x = 0; x < gridWidth; x++) { 195 | for(int y = 0; y < gridHeight; y++) { 196 | isOpen[x][y] = true; 197 | } 198 | } 199 | repaint(); 200 | } 201 | 202 | public static void main(String[] args) { 203 | JFrame f = new JFrame("Minesweeper"); 204 | f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 205 | f.setLayout(new FlowLayout()); 206 | f.add(new Minesweeper(35, 20, .23)); 207 | f.pack(); 208 | f.setVisible(true); 209 | } 210 | } -------------------------------------------------------------------------------- /MoreLoopExamples.java: -------------------------------------------------------------------------------- 1 | import java.security.SecureRandom; 2 | import java.util.Random; 3 | 4 | /** 5 | * Additional examples of conditions and loops for the course CCPS 109. 6 | * @author Ilkka Kokkarinen 7 | */ 8 | 9 | public class MoreLoopExamples { 10 | 11 | /** 12 | * Given an integer {@code n}, count how many digits its representation contains. 13 | * @param n The integer whose digits are to be counted. 14 | * @return How many digits there are in the parameter {@code n}. 15 | */ 16 | public static int countDigits(int n) { 17 | if(n < 0) { n = -n; } // flip a negative number to positive 18 | int count = 1; 19 | while(n > 9) { 20 | n = n / 10; 21 | count++; 22 | } 23 | return count; 24 | } 25 | 26 | /** 27 | * Given an integer {@code n}, compute the number given by writing the 28 | * digits of {@code n} twice. For example, for argument 1234, the method 29 | * would return 12341234. 30 | * @param n The integer whose digits are to be duplicated. 31 | * @return The result of duplicating the digits. 32 | */ 33 | public static long duplicateDigits(long n) { 34 | if(n < 0) { return -duplicateDigits(-n); } 35 | int d = 1; 36 | long n2 = n; // We should not modify n, so we modify n2 instead. 37 | // Compute the power of 10 that has same number of digits as n. 38 | // Use integer arithmetic instead of Math.pow to guarantee precision. 39 | while(n2 > 0) { 40 | d = d * 10; n2 = n2 / 10; 41 | } 42 | return (d+1) * n; // We need the original value of n in this formula. 43 | } 44 | 45 | // Another classic randomness problem. Let us solve it by numerical simulation. 46 | // On average, how many random numbers from the uniform interval [0, 1) do you 47 | // need to generate for their sum to exceed one? 48 | 49 | /** 50 | * A single trial of generating random numbers until their sum exceeds one. 51 | * @return The count of random numbers needed to reach one in this trial. 52 | */ 53 | public static int rollUntilAddToOne() { 54 | double total = 0; 55 | int rolls = 0; 56 | do { 57 | total += rng.nextDouble(); 58 | rolls++; 59 | } while(total < 1); 60 | return rolls; 61 | } 62 | 63 | /** 64 | * Perform given number of {@code trials} of generating random numbers until 65 | * their sum exceeds one. 66 | * @param trials The numbers of trials to perform. 67 | * @return The average result of the random trials. 68 | */ 69 | public static double howManyUntilOne(int trials) { 70 | int count = 0; 71 | for(int i = 0; i < trials; i++) { 72 | count += rollUntilAddToOne(); 73 | } 74 | return (double)count / trials; 75 | } 76 | 77 | /** 78 | * Calculate the square root of {@code x} with Heron's method, iterating an 79 | * initial guess until the double value no longer changes. Another blast from 80 | * the ancient age of swords and sandals back when, like it says in the song, 81 | * "the ships were made of wood and men were made of iron". 82 | * @param x The number whose square root we want to numerically compute. 83 | * @param verbose Whether the method should output its progress. 84 | * @return The square root of {@code x}, within given tolerance of {@code tol}. 85 | */ 86 | public static double heronRoot(double x, boolean verbose) { 87 | double guess = x / 2; // we have to start from somewhere 88 | double prev = 0; 89 | while(guess != prev) { 90 | if(verbose) { System.out.println("Current guess is " + guess); } 91 | // current guess becomes the previous guess 92 | prev = guess; 93 | // calculate a new, more accurate guess 94 | guess = (guess + x / guess) / 2; 95 | } 96 | if(verbose) { System.out.println("Returning result " + guess); } 97 | return guess; 98 | 99 | // The idea generalizes to arbitrary roots, not just the square root. 100 | // Heron's algorithm is a special case of the much later and more famous 101 | // "Newton's method" to solve roots of arbitrary continuous functions 102 | // whose differentials are known. Plugging the square root into Newton's 103 | // method gives Heron root iteration. 104 | } 105 | 106 | // Monte Carlo estimation for area of some complicated shape: generate 107 | // random points from some easy area that is known to fully contain the 108 | // area that we want to measure, and count how many of these points fall 109 | // under that area. Use this percentage of the larger area as an estimate 110 | // for the smaller area. 111 | 112 | private static final String seed = 113 | "Serious long simulations require a serious random number generator " + 114 | "that has sufficient entropy to generate reliable results."; 115 | private static final Random rng = new SecureRandom(seed.getBytes()); 116 | 117 | /** 118 | * Estimate the area of the unit circle with Monte Carlo estimation. 119 | * @param n Number of random samples to generate for the estimation. 120 | * @return The estimated area of the unit circle. 121 | */ 122 | public static double estimateUnitCircleArea(int n) { 123 | int count = 0; 124 | for(int i = 0; i < n; i++) { 125 | // random point in origin-centered 2*2 square 126 | double x = rng.nextDouble() * 2 - 1; 127 | double y = rng.nextDouble() * 2 - 1; 128 | // if inside the circle, increment count 129 | if(x*x + y*y <= 1) { count++; } 130 | } 131 | return 4 * (double) count / n; 132 | } 133 | 134 | /** 135 | * Measure the error of Monte Carlo estimation for unit circle area, 136 | * for various values of the sample size {@code n}. 137 | */ 138 | public static void checkAreaConvergence() { 139 | int n = 10; 140 | for(int i = 0; i < 7; i++) { 141 | double area = estimateUnitCircleArea(n); 142 | double error = Math.abs(Math.PI - area); 143 | System.out.printf("Using n = %d, error is %.7f\n", n, error); 144 | n = 10 * n; 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /MySemaphore.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.locks.Condition; 2 | import java.util.concurrent.locks.Lock; 3 | import java.util.concurrent.locks.ReentrantLock; 4 | 5 | // A standard exercise of Concurrency Intro is to prove that Semaphores are 6 | // equivalent to Locks and Condition variables in power, shown by implementing 7 | // each one with the other. Here, a simple Semaphore implementation. 8 | 9 | public class MySemaphore { 10 | private int permits; 11 | private final Lock mutex; 12 | private final Condition permitAvailable; 13 | 14 | public MySemaphore(int permits, boolean fair) { 15 | this.permits = permits; 16 | this.mutex = new ReentrantLock(fair); 17 | this.permitAvailable = mutex.newCondition(); 18 | } 19 | 20 | public void acquire() throws InterruptedException { 21 | mutex.lock(); 22 | try { 23 | while(permits < 1) { 24 | // Wait for one permit to become available. 25 | permitAvailable.await(); 26 | } 27 | permits--; 28 | } 29 | // Ensure that mutex is unlocked even if an exception is thrown. 30 | finally { mutex.unlock(); } 31 | } 32 | 33 | public void release() { 34 | mutex.lock(); 35 | permits++; 36 | // One waiting thread can now acquire a permit. 37 | if(permits > 0) { permitAvailable.signal(); } 38 | mutex.unlock(); 39 | } 40 | } 41 | 42 | // Puzzle: assuming that the Lock mutex is FIFO, is this Semaphore also FIFO in that 43 | // the threads that call acquire are always guaranteed to get the permit in the order 44 | // in which they made these calls? 45 | 46 | // Another puzzle: what would happen if you commented out the mutex operations from 47 | // the release method? Devise a scenario where the semaphore would no longer work 48 | // correctly. -------------------------------------------------------------------------------- /NatSet.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | // A monotonic set of natural numbers ideal for situations where these 4 | // numbers tend to be encountered in roughly ascending order, but not 5 | // strictly so. Many recursive sequences work this way. 6 | 7 | public class NatSet { 8 | 9 | // Initial size of the boolean[] used to store membership info. 10 | private static final int PAGE = 1000; 11 | // For statistics of how often these optimizations help us. 12 | private long shiftCount = 0; 13 | public long getShiftCount() { return shiftCount; } 14 | 15 | // The set contains all natural numbers that are less than start. 16 | private long start = 0; 17 | // Array to keep track of set membership for elements i that satisfy 18 | // start <= i < start + n, where n is the current length of the data array. 19 | private boolean[] data; 20 | // Inside the data array, every position < pos contains the value true. 21 | private int pos = 0; 22 | // We might as well allow the outside code become aware of this fact. 23 | public long allTrueUpTo() { return start + pos; } 24 | 25 | public NatSet() { 26 | data = new boolean[PAGE]; 27 | } 28 | 29 | public void add(long n) { 30 | if(n >= start) { 31 | // Determine the need for expanding the data array. 32 | int newSize = data.length; 33 | while(n >= start + newSize) { 34 | // Grow the data array exponentially, but modestly. 35 | newSize += data.length / 4; 36 | } 37 | // If n is past the end of data array, expand data array. 38 | if(newSize > data.length) { 39 | data = Arrays.copyOf(data, newSize); 40 | } 41 | // Update the element in the data array. 42 | data[(int)(n - start)] = true; 43 | // Update the pos counter sweeping through the data array. 44 | while(pos < data.length && data[pos]) { pos++; } 45 | // Once the first quarter of elements are true, shift the sliding window. 46 | if(pos > data.length / 4) { 47 | // Update the shifting statistics. 48 | shiftCount += pos; 49 | // Copy the rest of the array to start from the beginning. 50 | if (data.length - pos >= 0) { 51 | System.arraycopy(data, pos, data, 0, data.length - pos); 52 | } 53 | // Update the position of the sliding window. 54 | start += pos; 55 | // Fill the portion of data array with false values again. 56 | Arrays.fill(data, data.length - pos, data.length, false); 57 | // And start sweeping the data array from the beginning again. 58 | pos = 0; 59 | } 60 | } 61 | // No else here, since adding an element < start changes nothing. 62 | } 63 | 64 | public boolean contains(long n) { 65 | // Everything to the left of the sliding window is member. 66 | if(n < start) { return true; } 67 | // Everything to the right of the sliding window is a nonmember. 68 | if(n >= start + data.length) { return false; } 69 | // Inside the sliding window, consult the data array to get the answer. 70 | return data[(int)(n - start)]; 71 | } 72 | 73 | public static void demo() { 74 | // Demonstration of the principle of "tortoise and hare" where two 75 | // position indices advance the exact same path, except that hare makes 76 | // two moves for every one move of tortoise. Two identical RNG's are 77 | // used to generate the same steps for both. The hare adds the elements 78 | // it steps to into the set, whereas tortoise adds every element to 79 | // the set as it verifies that only those elements that hare also jumped 80 | // into were members of the set. 81 | NatSet s = new NatSet(); 82 | // Use two identical RNG's to generate the steps for tortoise and hare. 83 | Random rng1 = new Random(123); 84 | Random rng2 = new Random(123); 85 | int t = 0, h = 0; // Positions of tortoise and hare. 86 | // You can try on your computer how high you can make i go before 87 | // running out of heap memory needed by the data array. 88 | for(int i = 0; i < 100_000_000; i++) { 89 | // Hare moves in every round. 90 | h += rng1.nextInt(10) + 1; 91 | s.add(h); 92 | // Tortoise moves in every other round. 93 | if(i % 2 == 1) { 94 | int next = t + rng2.nextInt(10) + 1; 95 | t++; 96 | while(t < next) { 97 | assert !s.contains(t) : t + " should not be in the set"; 98 | s.add(t); 99 | t++; 100 | } 101 | assert s.contains(t) : t + " should be in the set"; 102 | } 103 | } 104 | System.out.println("Ended with hare at " + h + " and tortoise at " + t); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /NestedDemo.java: -------------------------------------------------------------------------------- 1 | public class NestedDemo { 2 | 3 | // Private variables, both static and instance, cannot be accessed from the 4 | // outside. However, the murderer is already inside the house... 5 | private static int count = 0; 6 | private final int x; 7 | 8 | public NestedDemo(int x) { 9 | // Local variable z is effectively final without us having to actually 10 | // declare that with the modifier final, since the compiler can see that 11 | // the variable is never again assigned to. 12 | int z = x*x*x; // final int z = x*x*x; 13 | 14 | // A local class is an inner class defined inside the only method that 15 | // ever uses it. Inner and local classes are used to separate some part 16 | // of the behaviour of the outer class into a separate entity that is 17 | // not shown to the outside world. 18 | class Local { 19 | private final int x; 20 | public Local() { 21 | x = count++; // Methods can access all members of the outer class. 22 | } 23 | public void report(int x) { 24 | // Note also how to disambiguate between three different variables named x. 25 | System.out.println("Parameter x equals " + x); 26 | System.out.println("Field x in the inner object equals " + this.x); 27 | System.out.println("Field x in the context object equals " + NestedDemo.this.x); 28 | System.out.println("Local variable z of surrounding method equals " + z); 29 | } 30 | } 31 | 32 | System.out.println("Creating a new NestedDemo object."); 33 | this.x = x; 34 | Local i1 = new Local(); 35 | Local i2 = new Local(); 36 | i1.report(17); 37 | i2.report(99); 38 | System.out.println("Finished creating the NestedDemo object.\n"); 39 | } 40 | 41 | public static void main(String[] args) { 42 | new NestedDemo(42); 43 | new NestedDemo(99); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Overload.java: -------------------------------------------------------------------------------- 1 | public class Overload { 2 | 3 | /* 4 | * Overloading is resolved at the compile time, based on declared parameter types. 5 | * Overriding is resolved at runtime, based on the type of the object "this". 6 | * This example class demonstrates this crucial difference between these two. 7 | */ 8 | 9 | // Just that we have an inheritance hierarchy to use as a parameter type. 10 | private static class Bird {} 11 | private static class Hawk extends Bird {} 12 | private static class Sparrow extends Bird {} 13 | 14 | // Then the classes that we use to demonstrate overloading and overriding. 15 | private static class A { 16 | public int get(Bird b) { return 1; } // #1 17 | public int get(Hawk h) { return 2; } // #2 18 | } 19 | 20 | private static class B extends A { 21 | @Override public int get(Bird b) { return 3; } // #3 22 | public int get(Sparrow s) { return 4; } // #4 23 | } 24 | 25 | // The demonstration itself. 26 | public static void main(String[] args) { 27 | // Our setup for this problem. 28 | A x = new A(); 29 | A y = new B(); 30 | Bird heckle = new Hawk(); 31 | Sparrow jeckle = new Sparrow(); 32 | 33 | // Now, what does each method call output? 34 | System.out.println(x.get(heckle)); // #1 35 | System.out.println(x.get(jeckle)); // #1 36 | System.out.println(y.get(heckle)); // #3 37 | System.out.println(y.get(jeckle)); // #3 38 | 39 | // Without defining any new variables, how could you call #2 and #4 ? 40 | // By downcasting these references to have their correct runtime type 41 | // already at the compile time. 42 | System.out.println(x.get((Hawk)heckle)); // #2 43 | System.out.println(((B)y).get(jeckle)); // #4 44 | 45 | // Some languages have "dynamic dispatching" in which the overloading 46 | // is resolved at runtime based on the argument object types. Java 47 | // resolves overloading at compile time when objects do not exist. 48 | } 49 | } -------------------------------------------------------------------------------- /Pair.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | import java.io.IOException; 3 | import java.util.Scanner; 4 | import java.util.HashSet; 5 | 6 | // An immensely useful class that for some reason is missing from 7 | // the Java standard library. (Google "why java has no pair class") 8 | 9 | public final class Pair { 10 | 11 | // A generic class can have static members, but they can't 12 | // use the type arguments in any way (because of erasure). 13 | private static int count = 0; 14 | public static int getCount() { return count; } 15 | 16 | // Type arguments can be used in instance fields and methods 17 | // as placeholders for actual type arguments given later by 18 | // the users of this class. 19 | private T first; 20 | private U second; 21 | 22 | public Pair(T first, U second) { 23 | count++; 24 | this.first = first; 25 | this.second = second; 26 | } 27 | 28 | public T getFirst() { return first; } 29 | public U getSecond() { return second; } 30 | 31 | // Uncomment these two lines if you prefer a mutable pair. 32 | // public void setFirst(T first) { this.first = first; } 33 | // public void setSecond(U second) { this.second = second; } 34 | 35 | @Override public String toString() { 36 | return "[" + getFirst() + ", " + getSecond() + "]"; 37 | } 38 | 39 | @Override public boolean equals(Object other) { 40 | if(other instanceof Pair) { // The most we can check at runtime. 41 | Pair otherPair = (Pair) other; // Downcast to Pair to access its getFirst and getSecond. 42 | return this.getFirst().equals(otherPair.getFirst()) && 43 | this.getSecond().equals(otherPair.getSecond()); 44 | } 45 | else { return false; } 46 | } 47 | 48 | @Override public int hashCode() { 49 | // When creating hash functions, bit shifts and xor are your helpful friends. 50 | // Hash code of object is computed based on precisely those fields that can 51 | // affect the equality comparison of those objects under the equals method. 52 | int h1 = getFirst().hashCode(); 53 | int h2 = getSecond().hashCode(); 54 | // Swap top and bottom halves of h1 so that pairs (a, b) and (b, a) will hash 55 | // differently. (This part is optional, but can't really hurt us either.) 56 | h1 = (h1 >> 16) | ((h1 & 0xFFFF) << 16); 57 | // Combine the hash codes of these fields with the exclusive or operator ^. 58 | int result = h1 ^ h2; 59 | // Last, use the bitwise and to ensure that the highest (sign) bit is zero. 60 | return result & 0x7FFFFFFF; 61 | } 62 | 63 | // Read all words from War and Peace and count how many hash codes we get for 64 | // the (word, idx) pairs generated from that data. The higher that number is, 65 | // the better your hash function works in practice with hash sets and maps. 66 | public static void main(String[] args) throws IOException { 67 | HashSet seen = new HashSet<>(); 68 | int wordNo = 0; 69 | try(Scanner sc = new Scanner(new File("warandpeace.txt"))) { 70 | while(sc.hasNextLine()) { 71 | for(String word: sc.nextLine().split(" ")) { 72 | seen.add(new Pair<>(word, wordNo++).hashCode()); 73 | } 74 | } 75 | } 76 | System.out.println("We got " + seen.size() + " different hash codes for " + wordNo + " words."); 77 | } 78 | } -------------------------------------------------------------------------------- /ParameterDemo.java: -------------------------------------------------------------------------------- 1 | // Demonstrate the difference in Java parameter passing when applied to primitive 2 | // types versus object references. The same discipline of call-by-value used in 3 | // all of Java parameter passing produces very different results for each kind. 4 | 5 | public class ParameterDemo { 6 | 7 | private static void fooPrimitive(int x) { 8 | x++; 9 | System.out.println("Inside method foo, x is now " + x + "."); // 6 10 | } 11 | 12 | public static void demoPrimitive() { 13 | int a = 5; 14 | System.out.println("To start, a is " + a + "."); // 5 15 | fooPrimitive(a); 16 | System.out.println("After call, a is " + a + "."); // 5 17 | } 18 | 19 | private static void fooArray(int[] x) { 20 | x[42]++; 21 | System.out.println("Inside method foo, x[42] is now " + x[42] + "."); 22 | } 23 | 24 | public static void demoArray() { 25 | int[] a = new int[100]; 26 | a[42] = 5; 27 | System.out.println("To start, a[42] is " + a[42] + "."); // 5 28 | fooArray(a); 29 | System.out.println("After call, a[42] is " + a[42] + "."); // 6 30 | } 31 | 32 | public static void main(String[] args) { 33 | demoPrimitive(); 34 | demoArray(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CCPS 209 Computer Science II 2 | 3 | Course outline, lecture material and example code for *CCPS 209 Computer Science II*, as it is taught by [Ilkka Kokkarinen](http://scs.ryerson.ca/~ikokkari) for the Chang School of Continuing Education, Toronto Metropolitan University, Canada. For the present implementation of this course, consult the instructor for the grading and other current policies. 4 | 5 | The outline for the course is in the document [Modules.pdf](https://github.com/ikokkari/JavaExamples/blob/master/CCPS%20209%20Modules.pdf), and the lecture notes are in the document [CCPS 209 Course Notes.pdf](https://github.com/ikokkari/JavaExamples/blob/master/CCPS%20209%20Course%20Notes.pdf). 6 | 7 | The YouTube playlist [CCPS 209 Computer Science II, Java](https://www.youtube.com/playlist?list=PLm1Sd7Iw1hHsRtM6KX5-XKGmOOvcDPBiB) collects the author's video lectures of this material. 8 | 9 | All source code is released under GNU General Public License v3. All computer science instructors are free to use and adapt these examples in their courses as they see fit. The author welcomes feedback from all such learners and instructors at `ilkka.kokkarinen@gmail.com`. The image file `coffee.jpg` taken by Ilkka Kokkarinen is released in public domain. 10 | -------------------------------------------------------------------------------- /ReflectionDemo.java: -------------------------------------------------------------------------------- 1 | import java.lang.reflect.Array; 2 | import java.lang.reflect.Field; 3 | import java.util.ArrayList; 4 | import java.util.IdentityHashMap; 5 | import java.util.LinkedList; 6 | import java.util.Queue; 7 | import java.util.Set; 8 | 9 | // As in http://tutorials.jenkov.com/java-reflection/index.html 10 | 11 | public class ReflectionDemo { 12 | 13 | // Utility method needed to simplify the findNeighbours method below. 14 | private static void processElement( 15 | Object next, 16 | IdentityHashMap discovered, 18 | Queue frontier, 19 | int depth 20 | ) { 21 | if(next != null && !discovered.containsKey(next)) { 22 | frontier.offer(next); 23 | discovered.put(next, depth + 1); 24 | } 25 | } 26 | 27 | /** 28 | * Uses reflection to discover all objects reachable from the given object by 29 | * following the reference fields, up to the distance limit. This method does 30 | * the search in breadth first order by using a FIFO queue as the frontier. 31 | * @param start The object from which to start the search. 32 | * @param limit The limit of how many levels to search. 33 | * @param verbose If true, the method prints out the objects that it finds. 34 | * @return A set of objects that are reachable from the start object. 35 | */ 36 | public static Set findNeighbours(Object start, int limit, boolean verbose) { 37 | // The objects discovered during the search, using memory address equality 38 | // as the equivalence criterion. 39 | IdentityHashMap discovered = new IdentityHashMap<>(); 40 | discovered.put(start, 0); 41 | // The search frontier of objects discovered and waiting to be processed. 42 | Queue frontier = new LinkedList(); 43 | frontier.offer(start); 44 | // Repeatedly pop an object from the frontier, and add its undiscovered 45 | // neighbours into the frontier. 46 | while(frontier.size() > 0) { 47 | Object current = frontier.poll(); 48 | if(verbose) { 49 | System.out.println("PROCESSING <" + current + "> AT DEPTH " + discovered.get(current)); 50 | } 51 | int depth = discovered.get(current); 52 | if(depth < limit) { 53 | Class c = current.getClass(); 54 | for(Field f: c.getDeclaredFields()) { 55 | Class ft = f.getType(); 56 | if(ft.isArray()) { // Arrays must be handled with special care. 57 | if(verbose) { System.out.println("Following field " + f.getName() + ":"); } 58 | f.setAccessible(true); // Follow even private fields. 59 | try { 60 | Object elems = f.get(current); 61 | if(elems == null) { continue; } 62 | int len = Array.getLength(elems); 63 | for(int i = 0; i < len; i++) { 64 | Object elem = Array.get(elems, i); 65 | if(elem != null) { 66 | processElement(elem, discovered, frontier, depth); 67 | } 68 | } 69 | } catch(IllegalAccessException e) { 70 | if(verbose) { System.out.println("Error: " + e); } 71 | } 72 | } 73 | else if(!ft.isPrimitive()) { // Follow a reference field. 74 | if(verbose) { System.out.println("Following field " + f.getName() + ":"); } 75 | f.setAccessible(true); // Follow even private fields. 76 | try { 77 | processElement(f.get(current), discovered, frontier, depth); 78 | } catch(IllegalAccessException e) { 79 | if(verbose) { System.out.println("Error: " + e); } 80 | } 81 | } 82 | } 83 | } 84 | } 85 | return discovered.keySet(); 86 | } 87 | 88 | public static void main(String[] args) { 89 | ArrayList a = new ArrayList<>(); 90 | a.add("Hello"); 91 | a.add(42); 92 | a.add(a); 93 | System.out.println("Demonstrating the discovery of object neighbourhood."); 94 | System.out.println(findNeighbours(a, 2, true).size()); 95 | } 96 | } -------------------------------------------------------------------------------- /Reverserver.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.io.OutputStreamWriter; 5 | import java.io.PrintWriter; 6 | import java.net.InetAddress; 7 | import java.net.ServerSocket; 8 | import java.net.Socket; 9 | import java.net.SocketTimeoutException; 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Executors; 12 | 13 | public class Reverserver { 14 | private ServerSocket serverSocket; 15 | private volatile boolean running = true; 16 | private ExecutorService executorService = Executors.newFixedThreadPool(5); 17 | public Reverserver(int serverPort) throws IOException{ 18 | serverSocket = new ServerSocket(serverPort); 19 | serverSocket.setSoTimeout(5000); // finish up, if no new clients come in 5 seconds 20 | executorService.submit(() -> { 21 | try { 22 | while(running) { 23 | Socket socket = serverSocket.accept(); 24 | // Generally we should launch a new thread the serve the client, so that 25 | // other clients can come in while we are serving this one. 26 | executorService.submit(() -> { 27 | // Java try-with-resources 28 | try (BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); 29 | PrintWriter output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream())) 30 | ) { 31 | String line = input.readLine(); 32 | while(line != null && line.length() > 0) { 33 | output.println(new StringBuilder(line).reverse()); 34 | output.flush(); 35 | line = input.readLine(); 36 | } 37 | } 38 | catch(IOException ignored) { } 39 | // finally-block is automatically synthesized with try-with-resources 40 | }); 41 | } 42 | } 43 | catch(SocketTimeoutException e) { System.out.println("Server timeout, closing up the shop"); } 44 | catch(IOException e) { System.out.println("Reverserver error: " + e); } 45 | finally { // after exiting the while loop 46 | Reverserver.this.terminate(); 47 | System.out.println("Reverserver closed, good night"); 48 | } 49 | }); 50 | } 51 | 52 | public void terminate() { 53 | try { 54 | running = false; 55 | serverSocket.close(); 56 | executorService.shutdownNow(); 57 | System.out.println("Reverserver terminated"); 58 | } catch(IOException ignored) {} 59 | } 60 | 61 | // A main method for demonstration purposes. 62 | public static void main(String[] args) { 63 | try { 64 | final int serverPort = 7777; 65 | new Reverserver(serverPort); 66 | Socket s = new Socket(InetAddress.getLocalHost(), serverPort); 67 | PrintWriter output = new PrintWriter(new OutputStreamWriter(s.getOutputStream())); 68 | BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream())); 69 | output.println("Reverse this!"); 70 | output.flush(); 71 | System.out.println(input.readLine()); 72 | output.println("Here's another line for you to reverse"); 73 | output.flush(); 74 | System.out.println(input.readLine()); 75 | output.println(""); // Tell the reverserver to close the connection with this client 76 | s.close(); 77 | } catch(Exception ignored) {} 78 | } 79 | } -------------------------------------------------------------------------------- /SecondBatch.java: -------------------------------------------------------------------------------- 1 | import java.util.Random; 2 | 3 | public class SecondBatch { 4 | 5 | // In Lake Wobegon, all students are above average. 6 | public static int aboveAverage(double[] a) { 7 | if(a.length == 0) { return 0; } 8 | double sum = 0; 9 | for(double e: a) { sum += e; } 10 | double avg = sum / a.length; 11 | int count = 0; 12 | for(double e: a) { 13 | if(e > avg) { count++; } 14 | } 15 | return count; 16 | } 17 | 18 | // Simple counting problem. 19 | public static int hammingDistance(boolean[] a, boolean[] b) { 20 | int count = 0; 21 | for(int i = 0; i < a.length; i++) { 22 | if(a[i] != b[i]) { count++; } 23 | } 24 | return count; 25 | } 26 | 27 | // An important statistical quantity is surprisingly easy to compute. 28 | public static double variance(double[] a) { 29 | if(a.length == 0) { return 0; } 30 | double sum = 0, sqSum = 0; 31 | for(double e: a) { 32 | sum += e; 33 | sqSum += e*e; 34 | } 35 | double avg = sum / a.length; 36 | double sqAvg = sqSum / a.length; 37 | return sqAvg - avg * avg; // square root of this is standard deviation 38 | } 39 | 40 | // Evaluate the terms one by one. 41 | public static double eval(double[] coeff, double x) { 42 | double sum = 0; 43 | double pow = 1; 44 | // Two multiplications and one add per coefficient. 45 | for(double e: coeff) { 46 | sum += e * pow; 47 | pow = pow * x; 48 | } 49 | return sum; 50 | } 51 | 52 | // Horner's rule from inside out saves one multiplication per round. 53 | public static double evalHornerRule(double[] coeff, double x) { 54 | double sum = coeff[coeff.length - 1]; 55 | // One multiplication and one add per coefficient. 56 | for(int i = coeff.length - 2; i >= 0; i--) { 57 | sum = sum * x + coeff[i]; 58 | } 59 | // Also more numerically stable using floating point. 60 | return sum; 61 | } 62 | 63 | // Random sampling without replacement with the aid of boolean array. 64 | public static double[] sample(double[] a, int k, Random rng) { 65 | // Keep track of which elements have already been taken in. 66 | boolean[] alreadyTaken = new boolean[a.length]; 67 | double[] b = new double[k]; 68 | for(int i = 0; i < k; i++) { 69 | int j; 70 | do { 71 | j = rng.nextInt(a.length); 72 | } while(alreadyTaken[j]); 73 | alreadyTaken[j] = true; 74 | b[i] = a[j]; 75 | } 76 | return b; 77 | } 78 | 79 | // Reservoir sampling, an online algorithm. Assumes k <= a.length. 80 | public static double[] reservoirSampling(double[] a, int k, Random rng) { 81 | double[] b = new double[k]; 82 | // Establish the reservoir of first k elements. 83 | System.arraycopy(a, 0, b, 0, k); 84 | // Other elements may be swapped into the reservoir. 85 | for(int i = k; i < a.length; i++) { 86 | int j = rng.nextInt(i+1); 87 | if(j < k) { 88 | b[j] = a[i]; 89 | } 90 | } 91 | return b; 92 | } 93 | 94 | // Showcases the idea of numerically simulating some process to 95 | // find out its average, when we don't know the analytical solution. 96 | public static double couponCollector(int n, int trials, Random rng) { 97 | int total = 0; 98 | for(int i = 0; i < trials; i++) { 99 | boolean[] coupons = new boolean[n]; 100 | int remain = n; 101 | while(remain > 0) { 102 | int c = rng.nextInt(n); 103 | if(!coupons[c]) { coupons[c] = true; remain--; } 104 | total++; 105 | } 106 | } 107 | return total / (double)trials; 108 | } 109 | } -------------------------------------------------------------------------------- /ShapePanel.java: -------------------------------------------------------------------------------- 1 | import java.awt.BasicStroke; 2 | import java.awt.Color; 3 | import java.awt.Dimension; 4 | import java.awt.FlowLayout; 5 | import java.awt.Font; 6 | import java.awt.GradientPaint; 7 | import java.awt.Graphics; 8 | import java.awt.Graphics2D; 9 | import java.awt.RenderingHints; 10 | import java.awt.geom.AffineTransform; 11 | import java.awt.geom.Area; 12 | import java.awt.geom.Ellipse2D; 13 | import java.awt.geom.Path2D; 14 | import java.awt.geom.Rectangle2D; 15 | import java.awt.geom.RoundRectangle2D; 16 | import javax.swing.BorderFactory; 17 | import javax.swing.JFrame; 18 | import javax.swing.JPanel; 19 | import javax.swing.border.BevelBorder; 20 | 21 | /** 22 | * An example Swing component that has no interaction, but displays an 23 | * assortment of geometric shapes rendered in various ways. 24 | * @author Ilkka Kokkarinen 25 | */ 26 | 27 | public class ShapePanel extends JPanel { 28 | 29 | private final boolean antiAlias; 30 | 31 | /** 32 | * Constructor for the class. 33 | * @param antiAlias Whether the rendering should be done using anti-aliasing. 34 | */ 35 | public ShapePanel(boolean antiAlias) { 36 | // Subclasses can always define additional fields and behaviour. 37 | this.antiAlias = antiAlias; 38 | // The one setting you must provide for your custom Swing component. 39 | this.setPreferredSize(new Dimension(500, 300)); 40 | // Many other settings and options can also be given. 41 | this.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); 42 | this.setToolTipText("Antialiasing is " + (antiAlias? "on": "off")); 43 | } 44 | 45 | /** 46 | * Render this component as it currently looks like. 47 | * @param g The {@code Graphics} object provided by Swing for us to draw on. 48 | */ 49 | @Override public void paintComponent(Graphics g) { 50 | super.paintComponent(g); // Erase the previous contents of the component. 51 | Graphics2D g2 = (Graphics2D)g; // Downcast the reference to modern Graphics2D. 52 | if(antiAlias) { 53 | g2.setRenderingHint( 54 | RenderingHints.KEY_ANTIALIASING, 55 | RenderingHints.VALUE_ANTIALIAS_ON 56 | ); // looks nicer 57 | } 58 | 59 | // To render shapes, you need to define the stroke and the paint strategies used. 60 | // This is just a fancy way to say that you need to choose the pen and the colour. 61 | g2.setStroke(new BasicStroke(3.0f)); 62 | g2.setPaint(Color.RED); // Solid uniform colour 63 | for(int r = 0; r < 150; r += 10) { 64 | // If nothing else, let's admire the existence of the method "draw" 65 | // that can draw the outline of any Shape that anybody will ever think up. 66 | g2.draw(new Rectangle2D.Double(100 - r / 2.0,100 - r / 2.0, r, r)); 67 | } 68 | 69 | // A rectangle with round corners. 70 | g2.setStroke(new BasicStroke(8.0f)); 71 | g2.setPaint(new GradientPaint(210, 60, Color.YELLOW, 290, 140, Color.BLUE)); 72 | RoundRectangle2D.Double rect = new RoundRectangle2D.Double(200, 50, 100, 100, 30, 45); 73 | g2.fill(rect); // Insides of the shape 74 | g2.setPaint(Color.ORANGE); 75 | g2.draw(rect); // Outline 76 | 77 | // An ellipse shape is defined using an invisible bounding rectangle. Decorating any 78 | // Shape with Area unlocks the power of affine transforms and computational geometry. 79 | Area elli = new Area(new Ellipse2D.Double(350, 50, 70, 140)); 80 | // AffineTransform has factory methods to create all kinds of transforms. Note that 81 | // the rotation angle is radians in [0, 2*Math.PI] instead of angles in [0, 360]. 82 | AffineTransform trans = AffineTransform.getRotateInstance(Math.toRadians(13), 385, 120); 83 | elli = elli.createTransformedArea(trans); 84 | // Constructive solid geometry operations add, subtract, intersect and exclusiveOr 85 | // can create complex shapes by combining simpler shapes together. 86 | elli.subtract(new Area(new Ellipse2D.Double(400, 100, 50, 50))); 87 | 88 | // Now we get to admire the results. 89 | g2.setPaint(new GradientPaint(370, 60, Color.BLACK, 360, 150, Color.WHITE)); 90 | // Polymorphic draw and fill methods deal with our new custom Area no problemo. 91 | // These methods expect some kind of Shape, and every Area is a Shape. That's 92 | // all there is to it with polymorphic methods, really. 93 | g2.fill(elli); 94 | // When rendering piecewise shapes, make sure to use nice cap and join settings. 95 | g2.setStroke(new BasicStroke(5.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND)); 96 | g2.setPaint(Color.BLUE); 97 | g2.draw(elli); 98 | 99 | // A more complex polygon shape that is partially outside the component bounds. The 100 | // rendering engine will automatically clip each shape into the visible "peephole" 101 | // defined by the component bounds. 102 | final int CENTER_X = 150, CENTER_Y = 250; 103 | Path2D.Double path = new Path2D.Double(); // outline path of the shape 104 | int points = 10; // Try out different values to see how these formulas work. 105 | int n = 2 * points; // As a polygon, a ten-point star has twenty corner points. 106 | for(int i = 0; i < n; i++) { 107 | double a = i * 2 * Math.toRadians(360) / n; // Angles are given in radians. 108 | double r = (i % 2 == 0) ? 100 : 50; // Tip or groove? 109 | if(i == 0) { // Starting point of the polygon starts the path. 110 | path.moveTo(CENTER_X + r * Math.cos(a), CENTER_Y + r * Math.sin(a)); 111 | } 112 | else { // Consecutive line segment edges. 113 | path.lineTo(CENTER_X + r * Math.cos(a), CENTER_Y + r * Math.sin(a)); 114 | } 115 | } 116 | 117 | // A closed path into can be turned into an Area that it encloses. 118 | Area area = new Area(path); 119 | g2.setStroke(new BasicStroke(5.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND)); 120 | g2.setPaint(Color.WHITE); 121 | g2.fill(area); 122 | g2.setPaint(Color.BLACK); 123 | g2.draw(area); 124 | 125 | // Finally, here is how you can render some text. The glyphs defined in each font 126 | // are just curves and line segments, and their rendering is fundamentally no 127 | // different from the rendering of the above shapes. 128 | g2.setColor(Color.BLACK); 129 | g2.setFont(new Font("Times", Font.ITALIC, 28)); // hook to the fonts in your system 130 | g2.drawString("Hello, wyrld!", 300, 250); // letter y reaches below baseline 131 | } 132 | 133 | /** 134 | * Create a JFrame, a free-moving window component, and put a ShapePanel inside it. 135 | */ 136 | public static void main(String[] args) { 137 | // A JPanel cannot exist alone on the screen, and must be place inside some 138 | // top-level container, which in all our examples will be JFrame. 139 | JFrame f = new JFrame("ShapePanel demo"); 140 | // Tell the frame to obey the close button. 141 | f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 142 | // Default layout manager of JFrame is BorderLayout, which is too fancy here. 143 | f.setLayout(new FlowLayout()); 144 | // Let's add two separate ShapePanel instances, just to see how it works. 145 | f.add(new ShapePanel(true)); // one with antialiasing 146 | f.add(new ShapePanel(false)); // one without antialiasing 147 | f.pack(); 148 | f.setVisible(true); 149 | } 150 | } -------------------------------------------------------------------------------- /ShortHamming.java: -------------------------------------------------------------------------------- 1 | import java.math.BigInteger; 2 | 3 | public class ShortHamming { 4 | 5 | private static final int HEAPSIZE = 10000000; 6 | 7 | private static final short[] heap = new short[HEAPSIZE * 3]; 8 | private static int size = 0; 9 | private static int expensiveCount = 0; 10 | 11 | private static final BigInteger two = BigInteger.valueOf(2); 12 | private static final BigInteger three = BigInteger.valueOf(3); 13 | private static final BigInteger five = BigInteger.valueOf(5); 14 | 15 | private static final double logOf2 = Math.log(2); 16 | private static final double logOf3 = Math.log(3); 17 | private static final double logOf5 = Math.log(5); 18 | 19 | private static BigInteger getValue(int pos) { 20 | return two.pow(heap[pos]).multiply(three.pow(heap[pos+1])).multiply(five.pow(heap[pos+2])); 21 | } 22 | 23 | private static boolean lessThan(int pos1, int pos2) { 24 | assert pos1 != pos2; 25 | if(heap[pos1] == heap[pos2] && heap[pos1+1] == heap[pos2+1] && heap[pos1+2] == heap[pos2+2]) { 26 | return false; 27 | } 28 | if(heap[pos1] <= heap[pos2] && heap[pos1+1] <= heap[pos2+1] && heap[pos1+2] <= heap[pos2+2]) { 29 | return true; 30 | } 31 | if(heap[pos1] >= heap[pos2] && heap[pos1+1] >= heap[pos2+1] && heap[pos1+2] >= heap[pos2+2]) { 32 | return false; 33 | } 34 | double log1 = heap[pos1] * logOf2 + heap[pos1+1] * logOf3 + heap[pos1+2] * logOf5; 35 | double log2 = heap[pos2] * logOf2 + heap[pos2+1] * logOf3 + heap[pos2+2] * logOf5; 36 | if(Math.abs(log1 - log2) > 0.000000001) { 37 | return log1 < log2; 38 | } 39 | expensiveCount++; 40 | return getValue(pos1).compareTo(getValue(pos2)) < 0; 41 | } 42 | 43 | private static void push(short a, short b, short c) { 44 | int idx1 = ++size; 45 | int pos = 3 * size; 46 | heap[pos] = a; heap[pos + 1] = b; heap[pos + 2] = c; 47 | while(idx1 > 1) { 48 | int idx2 = idx1 / 2; 49 | int pos1 = 3 * idx1; 50 | int pos2 = 3 * idx2; 51 | if(lessThan(pos1, pos2)) { 52 | short tmp = heap[pos1]; heap[pos1] = heap[pos2]; heap[pos2] = tmp; 53 | tmp = heap[pos1+1]; heap[pos1+1] = heap[pos2+1]; heap[pos2+1] = tmp; 54 | tmp = heap[pos1+2]; heap[pos1+2] = heap[pos2+2]; heap[pos2+2] = tmp; 55 | idx1 = idx2; 56 | } 57 | else { return; } 58 | } 59 | } 60 | 61 | private static void extractMin() { 62 | int pos = 3 * size--; 63 | heap[3] = heap[pos]; heap[4] = heap[pos+1]; heap[5] = heap[pos+2]; 64 | int idx = 1; 65 | while(2 * idx <= size) { 66 | pos = 3 * idx; 67 | int largest = 2 * idx; 68 | int posl = 3 * largest; 69 | int posr = 3 * (largest + 1); 70 | if(largest + 1 <= size) { 71 | if(lessThan(posr, posl)) { posl = posr; largest++; } 72 | } 73 | if(lessThan(posl, pos)) { 74 | short tmp = heap[pos]; heap[pos] = heap[posl]; heap[posl] = tmp; 75 | tmp = heap[pos + 1]; heap[pos + 1] = heap[posl + 1]; heap[posl + 1] = tmp; 76 | tmp = heap[pos + 2]; heap[pos + 2] = heap[posl + 2]; heap[posl + 2] = tmp; 77 | idx = largest; 78 | } 79 | else { return; } 80 | } 81 | } 82 | 83 | public static BigInteger hamming(long n) { 84 | int maxSize; 85 | size = maxSize = expensiveCount = 0; 86 | short a, b, c; 87 | long startTime = System.currentTimeMillis(); 88 | push((short)0, (short)0, (short)0); 89 | for(long i = 1; i < n; i++) { 90 | a = heap[3]; b = heap[4]; c = heap[5]; 91 | if(i % 100000000 == 0) { 92 | System.out.println(i + ": (" + a + ", " + b + ", " + c + ")"); 93 | } 94 | extractMin(); 95 | if(a == 0 && b == 0) { 96 | push(a, b, (short)(c + 1)); 97 | } 98 | if(a == 0) { 99 | push(a, (short)(b + 1), c); 100 | } 101 | push((short)(a + 1), b, c); 102 | if(size > maxSize) { maxSize = size; } 103 | } 104 | long endTime = System.currentTimeMillis(); 105 | System.out.println("Solution found in " + (endTime - startTime) + " millis."); 106 | System.out.println("Maximum heap size was " + maxSize + " using " + expensiveCount + " explicit comparisons."); 107 | System.out.println(getValue(3) + " (" + heap[3] + ", " + heap[4] + ", " + heap[5] + ")"); 108 | return getValue(3); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Sierpinski.java: -------------------------------------------------------------------------------- 1 | import javax.swing.JFrame; 2 | import javax.swing.JPanel; 3 | import java.awt.BasicStroke; 4 | import java.awt.Color; 5 | import java.awt.Dimension; 6 | import java.awt.FlowLayout; 7 | import java.awt.Graphics; 8 | import java.awt.Graphics2D; 9 | import java.awt.RenderingHints; 10 | import java.awt.event.MouseAdapter; 11 | import java.awt.event.MouseEvent; 12 | import java.awt.geom.Line2D; 13 | import java.util.Random; 14 | 15 | // See http://www.oftenpaper.net/sierpinski.htm for all about this classic fractal. 16 | 17 | /** 18 | * Renders the Sierpinski triangle inside a {@code JPanel}. 19 | */ 20 | public class Sierpinski extends JPanel { 21 | 22 | private boolean drawAll = true; 23 | private final Random rng = new Random(); 24 | 25 | /** 26 | * Default constructor for suitably chosen component dimensions. 27 | */ 28 | public Sierpinski() { 29 | this.setPreferredSize(new Dimension(600,600)); 30 | this.setBackground(Color.WHITE); 31 | this.addMouseListener(new MouseAdapter() { 32 | public void mousePressed(MouseEvent me) { 33 | drawAll = !drawAll; repaint(); 34 | } 35 | }); 36 | } 37 | 38 | /** 39 | * Render this component as it currently looks like. 40 | * @param g The {@code Graphics} object provided by Swing for us to draw on. 41 | */ 42 | public void paintComponent(Graphics g) { 43 | super.paintComponent(g); 44 | final Graphics2D g2 = (Graphics2D)g; 45 | g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 46 | RenderingHints.VALUE_ANTIALIAS_ON); 47 | g2.setStroke(new BasicStroke(0.2f)); 48 | g2.setColor(Color.BLACK); 49 | sierpinski(g2, 5, 5, getWidth() - 10, getHeight() - 10); 50 | } 51 | 52 | private void sierpinski(Graphics2D g, double x, double y, double w, double h) { 53 | if(w < 10 && h < 10) { // base case when shape is small enough 54 | if(drawAll || rng.nextBoolean()) g.draw(new Line2D.Double(x,y,x+w,y)); 55 | if(drawAll || rng.nextBoolean()) g.draw(new Line2D.Double(x,y,x+w/2,y+h)); 56 | if(drawAll || rng.nextBoolean()) g.draw(new Line2D.Double(x+w/2,y+h,x+w,y)); 57 | } 58 | else { // otherwise draw three smaller Sierpinski triangles 59 | sierpinski(g,x,y,w/2,h/2); 60 | sierpinski(g,x+w/2,y,w/2,h/2); 61 | sierpinski(g,x+w/4,y+h/2,w/2,h/2); 62 | } 63 | } 64 | 65 | public static void main(String[] args) { 66 | JFrame f = new JFrame(); 67 | f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 68 | f.setLayout(new FlowLayout()); 69 | f.add(new Sierpinski()); 70 | f.pack(); 71 | f.setVisible(true); 72 | } 73 | } -------------------------------------------------------------------------------- /SomeUnixCommands.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.FileInputStream; 3 | import java.io.IOException; 4 | import java.io.InputStreamReader; 5 | import java.io.OutputStreamWriter; 6 | import java.io.PrintWriter; 7 | import java.io.Reader; 8 | import java.io.Writer; 9 | import java.nio.charset.StandardCharsets; 10 | 11 | public class SomeUnixCommands { 12 | 13 | // Output lines that are not equal to the previous line. 14 | public static void uniq(Reader in, Writer out) throws IOException { 15 | BufferedReader br = new BufferedReader(in); 16 | PrintWriter pw = new PrintWriter(out); 17 | String prev = null; 18 | String line; 19 | while((line = br.readLine()) != null) { 20 | if(!line.equals(prev)) { 21 | pw.println(line); 22 | } 23 | prev = line; 24 | } 25 | pw.flush(); // Do not close(), otherwise System.out also closes (very bad!) 26 | } 27 | 28 | // Output each line reversed. 29 | public static void rev(Reader in, Writer out) throws IOException { 30 | BufferedReader br = new BufferedReader(in); 31 | PrintWriter pw = new PrintWriter(out); 32 | String line; 33 | while((line = br.readLine()) != null) { 34 | pw.println(new StringBuilder(line).reverse()); 35 | } 36 | pw.flush(); 37 | } 38 | 39 | // Output only the given fields ("words") in each line. 40 | public static void cut(Reader in, Writer out, String sep, int[] fields) throws IOException { 41 | BufferedReader br = new BufferedReader(in); 42 | PrintWriter pw = new PrintWriter(out); 43 | String line; 44 | while((line = br.readLine()) != null) { 45 | if(line.length() == 0) { continue; } 46 | String[] split = line.split(sep); 47 | for(int i = 0; i < fields.length; i++) { 48 | if(fields[i] >= split.length) { continue; } 49 | if(i > 0) { pw.print(" "); } 50 | pw.print(split[fields[i]]); 51 | } 52 | pw.println(""); 53 | } 54 | pw.flush(); 55 | } 56 | 57 | // For demonstration purposes. 58 | public static void main(String[] args) throws IOException { 59 | 60 | System.out.println("Lorem ipsum:"); 61 | Reader r = new InputStreamReader(new FileInputStream("lorem.txt"), StandardCharsets.UTF_8); 62 | uniq(r, new OutputStreamWriter(System.out)); 63 | r.close(); 64 | 65 | System.out.println("Lorem ipsum reversed:"); 66 | r = new InputStreamReader(new FileInputStream("lorem.txt"), StandardCharsets.UTF_8); 67 | rev(r, new OutputStreamWriter(System.out)); 68 | r.close(); 69 | 70 | int[] fields = {1, 3, 6}; 71 | System.out.println("Second, fourth and seventh word of each line of Lorem ipsum:"); 72 | r = new InputStreamReader(new FileInputStream("lorem.txt"), StandardCharsets.UTF_8); 73 | cut(r, new OutputStreamWriter(System.out), " ", fields); 74 | r.close(); 75 | } 76 | } -------------------------------------------------------------------------------- /TakeUntil.java: -------------------------------------------------------------------------------- 1 | import java.util.Iterator; 2 | import java.util.NoSuchElementException; 3 | import java.util.Spliterator; 4 | import java.util.Spliterators; 5 | import java.util.function.Predicate; 6 | import java.util.stream.IntStream; 7 | import java.util.stream.Stream; 8 | import java.util.stream.StreamSupport; 9 | 10 | /* Adapted from Saint Hill's answer in Stack Overflow. Create a class 11 | that can be used to convert any stream, finite or infinite, into 12 | another stream that stops at the first element that satisfies the 13 | given predicate. */ 14 | 15 | public class TakeUntil implements Iterator { 16 | 17 | private final Iterator it; // The iterator used to access the stream elements. 18 | private final Predicate pr; // The predicate used as stopping criterion. 19 | private volatile T next; // The next element of the stream, cached inside this object. 20 | private volatile boolean terminated = false; // Has the stopping criterion has been reached? 21 | 22 | // Constructor for the class. 23 | public TakeUntil(Stream s, Predicate pr) { 24 | this.it = s.iterator(); 25 | this.pr = pr; 26 | this.next = null; 27 | } 28 | 29 | // Is there at least one more element coming? 30 | public boolean hasNext() { 31 | // Has the stopping criterion been reached? 32 | if(terminated) { return false; } 33 | // Is there a cached element? 34 | if(next != null) { return true; } 35 | // Otherwise, ask the element from the iterator... 36 | if(it.hasNext()) { 37 | next = it.next(); 38 | // Answer depends on whether next element satisfies stopping criterion. 39 | return !pr.test(next); 40 | } 41 | return false; 42 | } 43 | 44 | // Return the next element of the stream. 45 | public T next() { 46 | if(!hasNext()) { 47 | throw new NoSuchElementException(); 48 | } 49 | T result = next; 50 | next = null; 51 | return result; 52 | } 53 | 54 | // Utility method to use this class to convert any Stream into another Stream 55 | // that terminates at the first element that satisfies the given predicate. 56 | public static Stream stream(Stream s, Predicate pred) { 57 | TakeUntil tu = new TakeUntil<>(s, pred); 58 | Spliterator split = Spliterators.spliterator(tu, Integer.MAX_VALUE, Spliterator.ORDERED); 59 | return StreamSupport.stream(split, false); 60 | } 61 | 62 | // For demonstration purposes, take numbers from the stream of consecutive positive 63 | // integers until you get to one that is greater than 10. 64 | public static void demo() { 65 | TakeUntil.stream(IntStream.range(1, 1_000_000_000).boxed(), x -> x > 10) 66 | .forEach(System.out::println); 67 | } 68 | } -------------------------------------------------------------------------------- /WordFrequency.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | import java.io.IOException; 3 | import java.io.PrintWriter; 4 | import java.util.ArrayList; 5 | import java.util.Comparator; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.Scanner; 9 | 10 | public class WordFrequency { 11 | 12 | // To run this program, change the FILENAME to some text file that you have. 13 | private static final String FILENAME = "warandpeace.txt"; 14 | 15 | private static final String[][] replacements = { 16 | {"doesn't", "does not"}, 17 | {"don't", "do not"}, 18 | {"you're", "you are"}, 19 | {"i'm", "i am"}, 20 | {"we're", "we are"}, 21 | {"they're", "they are"}, 22 | {"won't", "will not"}, 23 | {"can't", "can not"}, 24 | {"shan't", "shall not"}, 25 | {"shouldn't", "should not"}, 26 | {"mustn't", "must not"}, 27 | {"aren't", "are not"} 28 | }; 29 | 30 | public static Map wordFrequencies(Scanner s) { 31 | Map frequencies = new HashMap<>(); 32 | while(s.hasNextLine()) { 33 | String line = s.nextLine().trim().toLowerCase(); 34 | for(String[] replacement: replacements) { 35 | line = line.replaceAll(replacement[0], replacement[1]); 36 | } 37 | line = line.replaceAll("'s\\b", ""); // \b is regex word boundary 38 | line = line.replaceAll("'ll\\b", " will"); 39 | line = line.replaceAll("'t\\b", ""); 40 | String wordSeparators = "[^a-z]+"; 41 | for(String word: line.split(wordSeparators)) { 42 | // Lines that start with the quote character will end up having an 43 | // empty word at the front of the split line array. Thus, this check. 44 | if(word.length() != 0) { 45 | frequencies.put(word, frequencies.getOrDefault(word, 0) + 1); 46 | } 47 | } 48 | } 49 | return frequencies; 50 | } 51 | 52 | // For demonstration purposes, some word frequencies from "War and Peace". 53 | public static void main(String[] args) throws IOException { 54 | Map frequencies = wordFrequencies(new Scanner(new File(FILENAME))); 55 | System.out.println("Found " + frequencies.size() + " distinct words.\n"); 56 | System.out.println("Some occurrence counts are: "); 57 | String[] words = { 58 | "chicken", "prince", "Russia", "train", "I", "supercalifragilisticexpialidocius" 59 | }; 60 | for(String word: words) { 61 | word = word.toLowerCase(); 62 | System.out.println(word + ": " + (frequencies.getOrDefault(word, 0))); 63 | } 64 | 65 | // Custom comparator to compare strings by their frequency in the map, resolving cases 66 | // for equal frequency using the ordinary string comparison as secondary criterion. 67 | class FreqComparator implements Comparator { 68 | public int compare(String word1, String word2) { 69 | int f1 = frequencies.get(word1); 70 | int f2 = frequencies.get(word2); 71 | return f2 != f1 ? (f1 < f2 ? +1 : -1) : word2.compareTo(word1); 72 | } 73 | } 74 | 75 | // Create an arraylist of words so that we can sort these words by frequency. 76 | ArrayList wordList = new ArrayList<>(frequencies.keySet()); 77 | // Sort the arraylist using our frequency comparator. 78 | wordList.sort(new FreqComparator()); 79 | 80 | // Let's print out the results. 81 | System.out.println("\nThe three hundred most frequent words of 'War and Peace' are:\n"); 82 | LinePrinter lp = new LinePrinter(new PrintWriter(System.out), 80); 83 | for(int i = 0; i < 300; i++) { 84 | String word = wordList.get(i); 85 | lp.printWord(word + " (" + frequencies.get(word) + ")"); 86 | } 87 | lp.lineBreak(); 88 | System.out.println("\nHere are the words that occur only once in 'War and Peace':\n"); 89 | int i = wordList.size()-1; 90 | String word = wordList.get(i--); 91 | while(frequencies.get(word) == 1) { 92 | lp.printWord(word); 93 | word = wordList.get(i--); 94 | } 95 | lp.lineBreak(); 96 | } 97 | } -------------------------------------------------------------------------------- /WordTransform.java: -------------------------------------------------------------------------------- 1 | public class WordTransform { 2 | 3 | // Something that transforms a word into some other word. 4 | private interface Transform { 5 | String transform(String word); 6 | } 7 | 8 | // Reverse the given word, maintaining case. 9 | private static class Reverse implements Transform { 10 | public String transform(String word) { 11 | StringBuilder result = new StringBuilder(); 12 | boolean cap = Character.isUpperCase(word.charAt(0)); 13 | for(int i = word.length() - 1; i >= 0; i--) { 14 | char c = word.charAt(i); 15 | if(i == word.length() - 1) { 16 | result.append(cap ? Character.toUpperCase(c) : c); 17 | } 18 | else { 19 | result.append(Character.toLowerCase(c)); 20 | } 21 | } 22 | return result.toString(); 23 | } 24 | } 25 | 26 | // Convert the word to pig latin, maintaining case. 27 | private static class PigLatin implements Transform { 28 | public String transform(String word) { 29 | boolean cap = Character.isUpperCase(word.charAt(0)); 30 | int idx = 0; 31 | while(idx < word.length() && "AEIOUYaeiouy".indexOf(word.charAt(idx)) == -1) { 32 | idx++; 33 | } 34 | if(idx == 0) { 35 | return word + "way"; 36 | } 37 | else { 38 | String head; 39 | if(cap) { 40 | head = Character.toUpperCase(word.charAt(idx)) + word.substring(idx + 1); 41 | } 42 | else { 43 | head = word.substring(idx); 44 | } 45 | return head + word.substring(0, idx).toLowerCase() + "ay"; 46 | } 47 | } 48 | } 49 | 50 | // Convert the word to ubbi dubbi, maintaining case. 51 | private static class UbbiDubbi implements Transform { 52 | public String transform(String word) { 53 | StringBuilder result = new StringBuilder(); 54 | for(int i = 0; i < word.length(); i++) { 55 | char c = word.charAt(i); 56 | if("AEIOUYaeiouy".indexOf(c) == -1) { 57 | result.append(c); 58 | } 59 | else { 60 | if(Character.isUpperCase(c)) { 61 | result.append("Ub").append(Character.toLowerCase(c)); 62 | } 63 | else { 64 | result.append("ub").append(c); 65 | } 66 | } 67 | } 68 | return result.toString(); 69 | } 70 | } 71 | 72 | // The main algorithm that transforms all the words in the given text, using 73 | // the Transform given to it as strategy object. 74 | public static String transformSentence(String phrase, Transform transformer) { 75 | int start = 0; 76 | boolean inWord = false; 77 | StringBuilder result = new StringBuilder(); 78 | for(int i = 0; i <= phrase.length(); i++) { 79 | if(i == phrase.length() || !Character.isLetter(phrase.charAt(i))) { 80 | if(inWord) { 81 | inWord = false; 82 | String trans = transformer.transform(phrase.substring(start, i)); 83 | result.append( trans); 84 | } 85 | if(i < phrase.length()) { result.append(phrase.charAt(i)); } 86 | } 87 | else { 88 | if(!inWord) { start = i; } 89 | inWord = true; 90 | } 91 | } 92 | return result.toString(); 93 | } 94 | 95 | public static void main(String[] args) { 96 | String s = "What does this become? We shall see!"; 97 | System.out.println("Reverse: " + transformSentence(s, new Reverse())); 98 | System.out.println("Pig latin: " + transformSentence(s, new PigLatin())); 99 | System.out.println("Ubbi dubbi: " + transformSentence(s, new UbbiDubbi())); 100 | } 101 | } -------------------------------------------------------------------------------- /coffee.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikokkari/JavaExamples/4f53574d0c3515c2468a87933ee058b364191b87/coffee.jpg -------------------------------------------------------------------------------- /flappy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikokkari/JavaExamples/4f53574d0c3515c2468a87933ee058b364191b87/flappy.png --------------------------------------------------------------------------------