From 631623009b45cfb40f3117b47a3fd737d2d657da Mon Sep 17 00:00:00 2001 From: Daniel Bulant Date: Sat, 11 Oct 2025 18:38:36 +0200 Subject: [PATCH] add week 6 --- common/StdStats.java | 534 ++++++++++++++++++++++++++++++++++++++ main.typ | 2 +- week6/Calendar.java | 88 +++++++ week6/Card.java | 141 ++++++++++ week6/Hand.java | 95 +++++++ week6/Histogram.java | 11 + week6/HistogramTests.java | 16 ++ week6/PokerAnalysis.java | 81 ++++++ week6/common | 1 + week6/doc.typ | 55 ++++ 10 files changed, 1023 insertions(+), 1 deletion(-) create mode 100644 common/StdStats.java create mode 100644 week6/Calendar.java create mode 100644 week6/Card.java create mode 100644 week6/Hand.java create mode 100644 week6/Histogram.java create mode 100644 week6/HistogramTests.java create mode 100644 week6/PokerAnalysis.java create mode 120000 week6/common create mode 100644 week6/doc.typ diff --git a/common/StdStats.java b/common/StdStats.java new file mode 100644 index 0000000..81fd6c9 --- /dev/null +++ b/common/StdStats.java @@ -0,0 +1,534 @@ +package common; +/****************************************************************************** + * Compilation: javac StdStats.java + * Execution: java StdStats < input.txt + * Dependencies: StdOut.java + * + * Library of statistical functions. + * + * The test client reads an array of real numbers from standard + * input, and computes the minimum, mean, maximum, and + * standard deviation. + * + * The functions all throw a java.lang.IllegalArgumentException + * if the array passed in as an argument is null. + * + * The floating-point functions all return NaN if any input is NaN. + * + * Unlike Math.min() and Math.max(), the min() and max() functions + * do not differentiate between -0.0 and 0.0. + * + * % more tiny.txt + * 5 + * 3.0 1.0 2.0 5.0 4.0 + * + * % java StdStats < tiny.txt + * min 1.000 + * mean 3.000 + * max 5.000 + * std dev 1.581 + * + * Should these functions use varargs instead of array arguments? + * + ******************************************************************************/ + +/** + * The {@code StdStats} class provides static methods for computing + * statistics such as min, max, mean, sample standard deviation, and + * sample variance. + *

+ * For additional documentation, see + * Section 2.2 of + * Computer Science: An Interdisciplinary Approach + * by Robert Sedgewick and Kevin Wayne. + * + * @author Robert Sedgewick + * @author Kevin Wayne + */ +public final class StdStats { + + private StdStats() { } + + /** + * Returns the maximum value in the specified array. + * + * @param a the array + * @return the maximum value in the array {@code a[]}; + * {@code Double.NEGATIVE_INFINITY} if no such value + */ + public static double max(double[] a) { + validateNotNull(a); + + double max = Double.NEGATIVE_INFINITY; + for (int i = 0; i < a.length; i++) { + if (Double.isNaN(a[i])) return Double.NaN; + if (a[i] > max) max = a[i]; + } + return max; + } + + /** + * Returns the maximum value in the specified subarray. + * + * @param a the array + * @param lo the left endpoint of the subarray (inclusive) + * @param hi the right endpoint of the subarray (exclusive) + * @return the maximum value in the subarray {@code a[lo..hi)}; + * {@code Double.NEGATIVE_INFINITY} if no such value + * @throws IllegalArgumentException if {@code a} is {@code null} + * @throws IllegalArgumentException unless {@code (0 <= lo) && (lo < hi) && (hi <= a.length)} + */ + public static double max(double[] a, int lo, int hi) { + validateNotNull(a); + validateSubarrayIndices(lo, hi, a.length); + + double max = Double.NEGATIVE_INFINITY; + for (int i = lo; i < hi; i++) { + if (Double.isNaN(a[i])) return Double.NaN; + if (a[i] > max) max = a[i]; + } + return max; + } + + /** + * Returns the maximum value in the specified array. + * + * @param a the array + * @return the maximum value in the array {@code a[]}; + * {@code Integer.MIN_VALUE} if no such value + */ + public static int max(int[] a) { + validateNotNull(a); + + int max = Integer.MIN_VALUE; + for (int i = 0; i < a.length; i++) { + if (a[i] > max) max = a[i]; + } + return max; + } + + /** + * Returns the minimum value in the specified array. + * + * @param a the array + * @return the minimum value in the array {@code a[]}; + * {@code Double.POSITIVE_INFINITY} if no such value + */ + public static double min(double[] a) { + validateNotNull(a); + + double min = Double.POSITIVE_INFINITY; + for (int i = 0; i < a.length; i++) { + if (Double.isNaN(a[i])) return Double.NaN; + if (a[i] < min) min = a[i]; + } + return min; + } + + /** + * Returns the minimum value in the specified subarray. + * + * @param a the array + * @param lo the left endpoint of the subarray (inclusive) + * @param hi the right endpoint of the subarray (exclusive) + * @return the maximum value in the subarray {@code a[lo..hi)}; + * {@code Double.POSITIVE_INFINITY} if no such value + * @throws IllegalArgumentException if {@code a} is {@code null} + * @throws IllegalArgumentException unless {@code (0 <= lo) && (lo < hi) && (hi <= a.length)} + */ + public static double min(double[] a, int lo, int hi) { + validateNotNull(a); + validateSubarrayIndices(lo, hi, a.length); + + double min = Double.POSITIVE_INFINITY; + for (int i = lo; i < hi; i++) { + if (Double.isNaN(a[i])) return Double.NaN; + if (a[i] < min) min = a[i]; + } + return min; + } + + /** + * Returns the minimum value in the specified array. + * + * @param a the array + * @return the minimum value in the array {@code a[]}; + * {@code Integer.MAX_VALUE} if no such value + */ + public static int min(int[] a) { + validateNotNull(a); + + int min = Integer.MAX_VALUE; + for (int i = 0; i < a.length; i++) { + if (a[i] < min) min = a[i]; + } + return min; + } + + /** + * Returns the average value in the specified array. + * + * @param a the array + * @return the average value in the array {@code a[]}; + * {@code Double.NaN} if no such value + */ + public static double mean(double[] a) { + validateNotNull(a); + + if (a.length == 0) return Double.NaN; + double sum = sum(a); + return sum / a.length; + } + + /** + * Returns the average value in the specified subarray. + * + * @param a the array + * @param lo the left endpoint of the subarray (inclusive) + * @param hi the right endpoint of the subarray (exclusive) + * @return the average value in the subarray {@code a[lo..hi)}; + * {@code Double.NaN} if no such value + * @throws IllegalArgumentException if {@code a} is {@code null} + * @throws IllegalArgumentException unless {@code (0 <= lo) && (lo < hi) && (hi <= a.length)} + */ + public static double mean(double[] a, int lo, int hi) { + validateNotNull(a); + validateSubarrayIndices(lo, hi, a.length); + + int length = hi - lo; + if (length == 0) return Double.NaN; + + double sum = sum(a, lo, hi); + return sum / length; + } + + /** + * Returns the average value in the specified array. + * + * @param a the array + * @return the average value in the array {@code a[]}; + * {@code Double.NaN} if no such value + */ + public static double mean(int[] a) { + validateNotNull(a); + + if (a.length == 0) return Double.NaN; + int sum = sum(a); + return 1.0 * sum / a.length; + } + + /** + * Returns the sample variance in the specified array. + * + * @param a the array + * @return the sample variance in the array {@code a[]}; + * {@code Double.NaN} if no such value + */ + public static double var(double[] a) { + validateNotNull(a); + + if (a.length == 0) return Double.NaN; + double avg = mean(a); + double sum = 0.0; + for (int i = 0; i < a.length; i++) { + sum += (a[i] - avg) * (a[i] - avg); + } + return sum / (a.length - 1); + } + + /** + * Returns the sample variance in the specified subarray. + * + * @param a the array + * @param lo the left endpoint of the subarray (inclusive) + * @param hi the right endpoint of the subarray (exclusive) + * @return the sample variance in the subarray {@code a[lo..hi)}; + * {@code Double.NaN} if no such value + * @throws IllegalArgumentException if {@code a} is {@code null} + * @throws IllegalArgumentException unless {@code (0 <= lo) && (lo < hi) && (hi <= a.length)} + */ + public static double var(double[] a, int lo, int hi) { + validateNotNull(a); + validateSubarrayIndices(lo, hi, a.length); + + int length = hi - lo; + if (length == 0) return Double.NaN; + + double avg = mean(a, lo, hi); + double sum = 0.0; + for (int i = lo; i < hi; i++) { + sum += (a[i] - avg) * (a[i] - avg); + } + return sum / (length - 1); + } + + /** + * Returns the sample variance in the specified array. + * + * @param a the array + * @return the sample variance in the array {@code a[]}; + * {@code Double.NaN} if no such value + */ + public static double var(int[] a) { + validateNotNull(a); + if (a.length == 0) return Double.NaN; + double avg = mean(a); + double sum = 0.0; + for (int i = 0; i < a.length; i++) { + sum += (a[i] - avg) * (a[i] - avg); + } + return sum / (a.length - 1); + } + + /** + * Returns the population variance in the specified array. + * + * @param a the array + * @return the population variance in the array {@code a[]}; + * {@code Double.NaN} if no such value + */ + public static double varp(double[] a) { + validateNotNull(a); + if (a.length == 0) return Double.NaN; + double avg = mean(a); + double sum = 0.0; + for (int i = 0; i < a.length; i++) { + sum += (a[i] - avg) * (a[i] - avg); + } + return sum / a.length; + } + + /** + * Returns the population variance in the specified subarray. + * + * @param a the array + * @param lo the left endpoint of the subarray (inclusive) + * @param hi the right endpoint of the subarray (exclusive) + * @return the population variance in the subarray {@code a[lo..hi)}; + * {@code Double.NaN} if no such value + * @throws IllegalArgumentException if {@code a} is {@code null} + * @throws IllegalArgumentException unless {@code (0 <= lo) && (lo < hi) && (hi <= a.length)} + */ + public static double varp(double[] a, int lo, int hi) { + validateNotNull(a); + validateSubarrayIndices(lo, hi, a.length); + + int length = hi - lo; + if (length == 0) return Double.NaN; + + double avg = mean(a, lo, hi); + double sum = 0.0; + for (int i = lo; i < hi; i++) { + sum += (a[i] - avg) * (a[i] - avg); + } + return sum / length; + } + + /** + * Returns the sample standard deviation in the specified array. + * + * @param a the array + * @return the sample standard deviation in the array {@code a[]}; + * {@code Double.NaN} if no such value + */ + public static double stddev(double[] a) { + validateNotNull(a); + return Math.sqrt(var(a)); + } + + /** + * Returns the sample standard deviation in the specified array. + * + * @param a the array + * @return the sample standard deviation in the array {@code a[]}; + * {@code Double.NaN} if no such value + */ + public static double stddev(int[] a) { + validateNotNull(a); + return Math.sqrt(var(a)); + } + + /** + * Returns the sample standard deviation in the specified subarray. + * + * @param a the array + * @param lo the left endpoint of the subarray (inclusive) + * @param hi the right endpoint of the subarray (exclusive) + * @return the sample standard deviation in the subarray {@code a[lo..hi)}; + * {@code Double.NaN} if no such value + * @throws IllegalArgumentException if {@code a} is {@code null} + * @throws IllegalArgumentException unless {@code (0 <= lo) && (lo < hi) && (hi <= a.length)} + */ + public static double stddev(double[] a, int lo, int hi) { + validateNotNull(a); + validateSubarrayIndices(lo, hi, a.length); + + return Math.sqrt(var(a, lo, hi)); + } + + + /** + * Returns the population standard deviation in the specified array. + * + * @param a the array + * @return the population standard deviation in the array; + * {@code Double.NaN} if no such value + */ + public static double stddevp(double[] a) { + validateNotNull(a); + return Math.sqrt(varp(a)); + } + + /** + * Returns the population standard deviation in the specified subarray. + * + * @param a the array + * @param lo the left endpoint of the subarray (inclusive) + * @param hi the right endpoint of the subarray (exclusive) + * @return the population standard deviation in the subarray {@code a[lo..hi)}; + * {@code Double.NaN} if no such value + * @throws IllegalArgumentException if {@code a} is {@code null} + * @throws IllegalArgumentException unless {@code (0 <= lo) && (lo < hi) && (hi <= a.length)} + */ + public static double stddevp(double[] a, int lo, int hi) { + validateNotNull(a); + validateSubarrayIndices(lo, hi, a.length); + + return Math.sqrt(varp(a, lo, hi)); + } + + /** + * Returns the sum of all values in the specified array. + * + * @param a the array + * @return the sum of all values in the array {@code a[]}; + * {@code 0.0} if no such value + */ + private static double sum(double[] a) { + validateNotNull(a); + double sum = 0.0; + for (int i = 0; i < a.length; i++) { + sum += a[i]; + } + return sum; + } + + /** + * Returns the sum of all values in the specified subarray. + * + * @param a the array + * @param lo the left endpoint of the subarray (inclusive) + * @param hi the right endpoint of the subarray (exclusive) + * @return the sum of all values in the subarray {@code a[lo..hi)}; + * {@code 0.0} if no such value + * @throws IllegalArgumentException if {@code a} is {@code null} + * @throws IllegalArgumentException unless {@code (0 <= lo) && (lo < hi) && (hi <= a.length)} + */ + private static double sum(double[] a, int lo, int hi) { + validateNotNull(a); + validateSubarrayIndices(lo, hi, a.length); + + double sum = 0.0; + for (int i = lo; i < hi; i++) { + sum += a[i]; + } + return sum; + } + + /** + * Returns the sum of all values in the specified array. + * + * @param a the array + * @return the sum of all values in the array {@code a[]}; + * {@code 0.0} if no such value + */ + private static int sum(int[] a) { + validateNotNull(a); + int sum = 0; + for (int i = 0; i < a.length; i++) { + sum += a[i]; + } + return sum; + } + + /** + * Plots the points (0, a0), (1, a1), ..., + * (n-1, an-1) to standard draw. + * + * @param a the array of values + */ + public static void plotPoints(double[] a) { + validateNotNull(a); + int n = a.length; + StdDraw.setXscale(-1, n); + StdDraw.setPenRadius(1.0 / (3.0 * n)); + for (int i = 0; i < n; i++) { + StdDraw.point(i, a[i]); + } + } + + /** + * Plots the line segments connecting + * (i, ai) to + * (i+1, ai+1) for + * each i to standard draw. + * + * @param a the array of values + */ + public static void plotLines(double[] a) { + validateNotNull(a); + int n = a.length; + StdDraw.setXscale(-1, n); + StdDraw.setPenRadius(); + for (int i = 1; i < n; i++) { + StdDraw.line(i-1, a[i-1], i, a[i]); + } + } + + /** + * Plots bars from (0, ai) to + * (ai) for each i + * to standard draw. + * + * @param a the array of values + */ + public static void plotBars(double[] a) { + validateNotNull(a); + int n = a.length; + StdDraw.setXscale(-1, n); + for (int i = 0; i < n; i++) { + StdDraw.filledRectangle(i, a[i]/2, 0.25, a[i]/2); + } + } + + // throw an IllegalArgumentException if x is null + // (x is either of type double[] or int[]) + private static void validateNotNull(Object x) { + if (x == null) + throw new IllegalArgumentException("argument is null"); + } + + // throw an exception unless 0 <= lo <= hi <= length + private static void validateSubarrayIndices(int lo, int hi, int length) { + if (lo < 0 || hi > length || lo > hi) + throw new IllegalArgumentException("subarray indices out of bounds: [" + lo + ", " + hi + ")"); + } + + + /** + * Unit tests {@code StdStats}. + * Convert command-line arguments to array of doubles and call various methods. + * + * @param args the command-line arguments + */ + public static void main(String[] args) { + double[] a = StdArrayIO.readDouble1D(); + StdOut.printf(" min %10.3f\n", min(a)); + StdOut.printf(" mean %10.3f\n", mean(a)); + StdOut.printf(" max %10.3f\n", max(a)); + StdOut.printf(" stddev %10.3f\n", stddev(a)); + StdOut.printf(" var %10.3f\n", var(a)); + StdOut.printf(" stddevp %10.3f\n", stddevp(a)); + StdOut.printf(" varp %10.3f\n", varp(a)); + } +} diff --git a/main.typ b/main.typ index 5a107ac..48cc6cf 100644 --- a/main.typ +++ b/main.typ @@ -15,7 +15,7 @@ Collection of solutions to programming exercises as part of Introduction to Prog ) #{ - let count = 5; + let count = 6; for week in range(1, count + 1) { let a = "./week" + str(week) + "/doc.typ" include a diff --git a/week6/Calendar.java b/week6/Calendar.java new file mode 100644 index 0000000..7e71328 --- /dev/null +++ b/week6/Calendar.java @@ -0,0 +1,88 @@ +package week6; + +public class Calendar { + static final String[] months = { + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" + }; + + public static void main(String[] args) { + int month = Integer.parseInt(args[0]); + int year = Integer.parseInt(args[1]); + + System.out.printf("%s %d\n", months[month - 1], year); + System.out.println(" S M Tu W Th F S"); + int daysToSkip = dayOfWeek(year, month, 1); + int monthLength = monthLength(year, month); + for(var i = 1; i < monthLength + daysToSkip + 1; i++) { + if(i < daysToSkip && i % 7 == 0) { + System.out.println(); + continue; + } + if(i <= daysToSkip) { + System.out.print(" "); + continue; + } + System.out.printf("%2d ", i - daysToSkip); + if(i % 7 == 0) { + System.out.println(); + } + } + } + + static final int[] monthLengths = { + 31, + 28, + 31, + 30, + 31, + 30, + 31, + 31, + 30, + 31, + 30, + 31, + }; + + /** + * Length of a given month + * @param year + * @param month 1=January + * @return length of the month in days, leap year adjusted + */ + static int monthLength(int year, int month) { + return monthLengths[month - 1] + (month == 2 ? (isLeapYear(year) ? 1 : 0) : 0); + } + + static boolean isLeapYear(int year) { + boolean isLeapYear; + isLeapYear = (year % 4 == 0); + isLeapYear = isLeapYear && (year % 100 != 0); + isLeapYear = isLeapYear || (year % 400 == 0); + return isLeapYear; + } + + /** + * @param year + * @param month 1=January + * @param day + * @return day of week, 0=Sunday,6=Saturday + */ + static int dayOfWeek(int year, int month, int day) { + int y0 = year - (14 - month) / 12; + int leapAdjustedYear = y0 + y0 / 4 - y0 / 100 + y0 / 400; + int m0 = month + 12 * ((14 - month) / 12) - 2; + return (day + leapAdjustedYear + (31 * m0) / 12) % 7; + } +} diff --git a/week6/Card.java b/week6/Card.java new file mode 100644 index 0000000..e94a655 --- /dev/null +++ b/week6/Card.java @@ -0,0 +1,141 @@ +package week6; + +public class Card { + + public enum Suit { + Clubs, + Diamonds, + Hearts, + Spades; + + public static final String CLUBS = "♣"; + public static final String DIAMONDS = "♦"; + public static final String HEARTS = "♥"; + public static final String SPADES = "♠"; + + public String sprint() { + switch(this) { + case Clubs: return CLUBS; + case Diamonds: return DIAMONDS; + case Hearts: return HEARTS; + case Spades: return SPADES; + } + throw new NullPointerException(); + } + } + + public Suit suit; + public int value; + + public Card(Suit suit, int value) { + this.suit = suit; + this.value = value; + } + + // Print a single character for the value + // Only a single character is returned so that we can format + // the card output correctly and easily + public char sprintValue() { + assert this.value > 0 && this.value < 14; + if(this.value == 1) { + return 'A'; + } else if(this.value == 11) { + return 'J'; + } else if(this.value == 12) { + return 'Q'; + } else if(this.value == 13) { + return 'K'; + } else if(this.value == 10) { + // UTF-8 character that looks like a 10 + // but uses only one character width + return '⒑'; + } + // asserted 0 < x < 14, we handled 1, 10-13 + // the only valid values here are 2-9 + return Integer.toString(this.value).charAt(0); + } + + // Print the card to a string to be later processed (or printed). + // Approximates 'normal' card deck look + // Numbered cards have their suit symbol repeated based on their value. + // Face cards are empty. + public String sprintCard() { + var output = ""; + var value = this.sprintValue(); + var suit = this.suit.sprint(); + + // Generate the top (and bottom) of a card + // this will show the value of the card on each edge + var top = ""; + top += value; + if(this.value > 10) { + // face cards are empty + top += " "; + } else { + // and for numbered cards, show the suit characters + top += this.value >= 4 ? suit : " "; + top += this.value < 4 && this.value > 1 ? suit : " "; + top += this.value >= 4 ? suit : " "; + } + top += value; + top += "\n"; + + output += top; + + if(this.value > 10) { + // face cards get suits on the side, right above and under their values + // numbered cards are empty on their sides + output += suit + " " + suit + "\n"; + output += suit + " " + suit + "\n"; + } else { + // normal cards have either 3 or 4 rows of suits in 1-3 columns, + // with the middle one sometimes floating. + // we have to have a set size and can't have floating characters, + // so this is a best effort approximation + // instead of using 3 rows we have a gap in the 3rd row + output += " "; + output += this.value >= 6 ? suit : " "; + // odd or 10 have a symbol in the middle + output += this.value % 2 == 1 || this.value == 10 ? suit : " "; + output += this.value >= 6 ? suit : " "; + output += " "; + output += "\n"; + + + output += " "; + output += this.value >= 8 ? suit : " "; + output += this.value == 10 ? suit : " "; + output += this.value >= 8 ? suit : " "; + output += " "; + output += "\n"; + } + + output += top; + + return output; + } + + // Shows cards next to each other (left to right) + // for visuals, assumes that sprintCard returns the same width for each card (and each row of a card) + // for correctness, assumes that sprintCard always returns 4 rows (is asserted) + public static String sprintCards(Card[] cards) { + String[] output = { "", "", "", "" }; + + // split each card into it's 4 rows + // save the row into relevant output + for(var i = 0; i < cards.length; i++) { + var cardstr = cards[i].sprintCard().split("\n"); + assert output.length == cardstr.length; + for(var x = 0; x < cardstr.length; x++) { + output[x] += cardstr[x] + " "; + } + } + + // and join the rows together with a newline + var outputstr = ""; + for(var i = 0; i < output.length; i++) { + outputstr += output[i] + "\n"; + } + return outputstr; + } +} diff --git a/week6/Hand.java b/week6/Hand.java new file mode 100644 index 0000000..d442649 --- /dev/null +++ b/week6/Hand.java @@ -0,0 +1,95 @@ +package week6; + +import java.util.Arrays; + +public class Hand { + enum Type { + StraightFlush, + FourOfAKind, + FullHouse, + Flush, + Straight, + ThreeOfAKind, + TwoPair, + Pair, + HighCard; + } + + Card[] cards; + + public Hand(Card[] cards) { + assert cards != null; + assert cards.length == 5; + this.cards = cards; + } + + public Type type() { + var doubleHistogram = doubleHistogram(); + var hasFlush = hasFlush(); + var hasStraight = hasStraight(); + if(hasFlush && hasStraight) return Type.StraightFlush; + if(hasFlush) return Type.Flush; + if(hasStraight) return Type.Straight; + if(doubleHistogram[4] == 1) return Type.FourOfAKind; + if(doubleHistogram[3] == 1 && doubleHistogram[2] == 1) return Type.FullHouse; + if(doubleHistogram[3] == 1) return Type.ThreeOfAKind; + if(doubleHistogram[2] == 2) return Type.TwoPair; + if(doubleHistogram[2] == 1) return Type.Pair; + return Type.HighCard; + } + + int[] values() { + var values = new int[cards.length]; + for(var i = 0; i < cards.length; i++) { + values[i] = cards[i].value; + } + return values; + } + + /** + * Generates a histogram of card values. + * Each element in an array contains the number of cards with that value. + */ + int[] histogram() { + return Histogram.histogram(values(), 14); + } + /** + * Generates a histogram of the histogram of card values. + * This shows how many times did any repetitions repeat. + * For example (1,1,2,2,2,3,3) first histogram results in (0,2,3,2) + * Second histogram (what this function returns) results in (1,0,2,1). + * This tells us that there are two pairs and one three of a kind. + */ + int[] doubleHistogram() { + // if cards are dealt properly, the max is 5 (cards.length), + // as a card can't appear more than 4 times + var histogram = histogram(); + // System.out.println(Arrays.toString(histogram)); + return Histogram.histogram(histogram, cards.length + 1); + } + + boolean hasFlush() { + var suit = cards[0].suit; + for(var i = 1; i < cards.length; i++) { + if(cards[i].suit != suit) return false; + } + return true; + } + + boolean hasStraight() { + var values = values(); + Arrays.sort(values); + var isStraight = true; + for(var i = 1; i < values.length; i++) { + if(values[i] != values[i-1] + 1) { + isStraight = false; + break; + } + } + if(isStraight) return true; + return isStraight || Arrays.equals(values, new int[]{ + // A 10 J Q K is valid as well + 1, 10, 11, 12, 13 + }); + } +} diff --git a/week6/Histogram.java b/week6/Histogram.java new file mode 100644 index 0000000..ba852e3 --- /dev/null +++ b/week6/Histogram.java @@ -0,0 +1,11 @@ +package week6; + +public class Histogram { + public static int[] histogram(int[] a, int max) { + int[] output = new int[max]; + for(var x = 0; x < a.length; x++) { + output[a[x]]++; + } + return output; + } +} \ No newline at end of file diff --git a/week6/HistogramTests.java b/week6/HistogramTests.java new file mode 100644 index 0000000..e97527c --- /dev/null +++ b/week6/HistogramTests.java @@ -0,0 +1,16 @@ +package week6; + +import java.util.Arrays; + +public class HistogramTests { + public static void main(String[] args) { + assert Arrays.equals( + new int[]{ 0,1,1,1 }, + Histogram.histogram(new int[]{ 1,2,3 }, 4) + ); + assert Arrays.equals( + new int[]{ 0,3,0,0 }, + Histogram.histogram(new int[]{ 1,1,1 }, 4) + ); + } +} diff --git a/week6/PokerAnalysis.java b/week6/PokerAnalysis.java new file mode 100644 index 0000000..f9b81c5 --- /dev/null +++ b/week6/PokerAnalysis.java @@ -0,0 +1,81 @@ +package week6; + +import common.StdDraw; +import common.StdRandom; +import common.StdStats; + +public class PokerAnalysis { + /** + * Example program using PokerAnalysis + * + * Renders a plot of each type of hand + * The bars represent types in Hand.Type, in the same order + */ + public static void main(String[] args) { + var decks = 1000; + // var hands = decks * 10; + var types = analyzeShuffledDecks(decks); + var typeFloats = new double[types.length]; + var max = StdStats.max(types); + for(var i = 0; i < types.length; i++) { + // max or hands can be used here + typeFloats[i] = (double)types[i] / max; + } + + StdDraw.setPenColor(); + StdStats.plotBars(typeFloats); + } + + /** + * Gets nth (5-card) hand of a given deck. + * Up to 10 hands can be dealt from a given deck + */ + public static Hand getHand(Card[] deck, int handOffset) { + var offset = handOffset * 5; + return new Hand(new Card[]{ + deck[offset], + deck[offset+1], + deck[offset+2], + deck[offset+3], + deck[offset+4] + }); + } + + /** + * Gets the first hand of a given deck. + */ + public static Hand getHand(Card[] deck) { + return getHand(deck, 0); + } + + public static Card[] getRandomDeck() { + Card[] deck = new Card[52]; + for(var i = 0; i < 52; i++) { + var value = (i % 13) + 1; + var suit = i / 13; + deck[i] = new Card(Card.Suit.values()[suit], value); + } + StdRandom.shuffle(deck); + return deck; + } + + /** + * Shuffles n decks, draws 10 hands from each, and saves the number of hands of each type + * Returns an array mapping type (using their ordinals) to number of hands found + */ + public static int[] analyzeShuffledDecks(int decks) { + var types = new int[Hand.Type.values().length]; + for(var i = 0; i < decks; i++) { + var deck = getRandomDeck(); + for(var offset = 0; offset < 10; offset++) { + var hand = getHand(deck, offset); + types[hand.type().ordinal()]++; + } + } + return types; + } + + public static int numberOfHandsOfType(int[] analyzedShuffledDecks, Hand.Type type) { + return analyzedShuffledDecks[type.ordinal()]; + } +} diff --git a/week6/common b/week6/common new file mode 120000 index 0000000..60d3b0a --- /dev/null +++ b/week6/common @@ -0,0 +1 @@ +../common \ No newline at end of file diff --git a/week6/doc.typ b/week6/doc.typ new file mode 100644 index 0000000..5e44628 --- /dev/null +++ b/week6/doc.typ @@ -0,0 +1,55 @@ +#import "./common/common.typ" : * + +#show: template + += Week 6 + +== Exercise 2.1.19 + +Write a static method `histogram()` that takes an `int array a[]` and an +integer $m$ as arguments and returns an array of length $m$ whose $i$th element is the +number of times the integer $i$ appeared in `a[]`. Assuming the values in `a[]` are +all between $0$ and $m-1$, the sum of the values in the returned array should equal +`a.length`. + +#embedClass(name: "Histogram") + +== Exercise 2.1.30 + +_Calendar_. Write a program `Calendar` that takes two integer commandline +arguments $m$ and $y$ and prints the monthly calendar for month $m$ of year $y$, as +in this example: + +``` +% java Calendar 2 2009 +February 2009 + S M Tu W Th F S + 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 +15 16 17 18 19 20 21 +22 23 24 25 26 27 28 +``` + +#embedClass(name: "Calendar") + +== Exercise 2.2.26 + +_Poker analysis_. Write a `StdRandom` and `StdStats` client (with appropriate +static methods of its own) to estimate the probabilities of getting one pair, two pair, +three of a kind, a full house, and a flush in a five-card poker hand via simulation. + +Divide your program into appropriate static methods and defend your design decisions. +_Extra credit_ : Add straight and straight flush to the list of possibilities. + +#embedClass(name: "PokerAnalysis") + +#embedClass(name: "Hand") + +_Note that this reuses #context { + let label = ; + if query(label).len() == 0 { + [ class Card ] + } else { + ref(label) + } +} from week 4._