General FizzBuzz/jFizzBuzz: Difference between revisions
Content added Content deleted
(Changed type of {@link UserSuppliedArguments.buzzerEntries} to {@link java.util.Map}; added package statement.) |
No edit summary |
||
(5 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
<syntaxhighlight lang="java"> |
|||
/** |
|||
{{works with|Java|1.8.x}} |
|||
* @file GeneralFizzBuzz.java |
|||
User-supplied values must be passed as command-line arguments. |
|||
<lang Java>/** |
|||
* |
|||
* FizzBuzz Enterprise Edition (c) 2016 |
|||
* |
|||
* |
|||
* TODO: Add End-User License Agreement |
|||
* TODO: Add JavaDoc Comments |
|||
* TODO: Add Unit Tests |
|||
* TODO: Add Dependency Injection (FizzBuzzProvider, BuzzerProvider, etc.) |
|||
* |
|||
* |
|||
*/ |
*/ |
||
import java.io.InputStream; |
|||
package com.fizzbuzzinc.jfizzbuzz; |
|||
import java.io.OutputStream; |
|||
import java.io.PrintWriter; |
|||
import java.util.ArrayList; |
|||
import java.util.HashMap; |
|||
import java.util.Iterator; |
|||
import java.util.List; |
import java.util.List; |
||
import java.util.ArrayList; |
|||
import java.util.LinkedHashMap; |
|||
import java.util.Map; |
import java.util.Map; |
||
import java.util. |
import java.util.NoSuchElementException; |
||
import java.util.Scanner; |
|||
/** |
|||
class BuzzException extends Exception |
|||
* This class follows the "God class" pattern. |
|||
* See {@link #main(String[])} for example usage. |
|||
*/ |
|||
class FizzBuzzer |
|||
implements |
|||
Iterable<FizzBuzzer.Entry>, |
|||
Iterator<FizzBuzzer.Entry> |
|||
{ |
{ |
||
private static final long DEFAULT_START_NUM = 1; |
|||
public BuzzException( |
|||
private static final long DEFAULT_MAX_NUM = Long.MAX_VALUE; |
|||
String textualRepresentation |
|||
) |
|||
{ |
|||
super(textualRepresentation); |
|||
} |
|||
} |
|||
public class Entry { |
|||
public final long num; |
|||
interface IBuzzer |
|||
public final List<String> names; |
|||
{ |
|||
void buzz( |
|||
Integer numericValue |
|||
) |
|||
throws BuzzException; |
|||
} |
|||
private Entry(Long num, List<String> names) { |
|||
this.num = num; |
|||
this.names = names; |
|||
} |
|||
} |
|||
private Map<Integer, String> modToName = new HashMap<>(); |
|||
interface IFizzBuzz |
|||
{ |
|||
Boolean addBuzzer( |
|||
IBuzzer buzzerToAddToTheListOfBuzzers |
|||
); |
|||
private long currNum = DEFAULT_START_NUM; |
|||
String doExecute(); |
|||
private long maxNum = DEFAULT_MAX_NUM; |
|||
} |
|||
private Map<Long, List<Integer>> schedule = new HashMap<>(); |
|||
public long getCurrNum() { return currNum; } |
|||
public void setCurrNum(long currNum) { this.currNum = currNum; } |
|||
public long getMaxNum() { return maxNum; } |
|||
public void setMaxNum(long maxNum) { this.maxNum = maxNum; } |
|||
class Buzzer implements IBuzzer |
|||
{ |
|||
protected final Integer numericValue; |
|||
protected final String textualRepresentation; |
|||
private List<Integer> scheduledAt(long num) { |
|||
public Buzzer( |
|||
return schedule.computeIfAbsent(num, num_ -> new ArrayList<>()); |
|||
Integer numericValue, |
|||
String textualRepresentation |
|||
) |
|||
{ |
|||
this.numericValue = numericValue; |
|||
this.textualRepresentation = textualRepresentation; |
|||
} |
} |
||
private void scheduleNearest(Integer mod) { |
|||
Integer numericValue |
|||
) |
|||
throws BuzzException |
|||
{ |
|||
Integer moduloOfNumericValues = new Integer(numericValue % this.getNumericValue()); |
|||
long nearestNum = currNum + (mod - currNum % mod); |
|||
if (moduloOfNumericValues.equals(new Integer(0))) |
|||
{ |
|||
throw new BuzzException(this.getTextualRepresentation()); |
|||
} |
|||
scheduledAt(nearestNum).add(mod); |
|||
} |
} |
||
public boolean add(Integer mod, String name) { |
|||
Integer getNumericValue() |
|||
{ |
|||
return this.numericValue; |
|||
} |
|||
if (modToName.containsKey(mod)) { |
|||
String getTextualRepresentation() |
|||
return false; |
|||
{ |
|||
} |
|||
return this.textualRepresentation; |
|||
} |
|||
} |
|||
modToName.put(mod, name); |
|||
scheduleNearest(mod); |
|||
return true; |
|||
/** |
|||
* |
|||
* Thread-safe implementation of {@link IFizzBuzz}. |
|||
* |
|||
*/ |
|||
class FizzBuzz implements IFizzBuzz |
|||
{ |
|||
protected final Integer numericvalueOfUpperLimit; |
|||
protected final List<IBuzzer> listOfBuzzers; |
|||
public FizzBuzz( |
|||
Integer numericvalueOfUpperLimit |
|||
) |
|||
{ |
|||
this.numericvalueOfUpperLimit = numericvalueOfUpperLimit; |
|||
this.listOfBuzzers = new ArrayList<IBuzzer>(); |
|||
} |
} |
||
public void addAll(Map<Integer, String> modToName) { |
|||
public synchronized Boolean addBuzzer( |
|||
IBuzzer buzzerToAddToTheListOfBuzzers |
|||
for (Map.Entry<Integer, String> modAndName : modToName.entrySet()) { |
|||
) |
|||
add(modAndName.getKey(), modAndName.getValue()); |
|||
{ |
|||
} |
|||
return new Boolean(this.listOfBuzzers.add(buzzerToAddToTheListOfBuzzers)); |
|||
} |
} |
||
public synchronized String doExecute() |
|||
{ |
|||
StringBuilder textualRepresentationOfFizzBuzzProgramOutput = new StringBuilder(); |
|||
@Override |
|||
public Entry next() { |
|||
Integer loopIndex = new Integer(1); |
|||
loopIndex <= this.numericvalueOfUpperLimit; |
|||
loopIndex += new Integer(1) |
|||
) |
|||
{ |
|||
Boolean atLeastOneBuzzerBuzzed = new Boolean(false); |
|||
List<Integer> currMods = scheduledAt(currNum); |
|||
Integer buzzerIndex = new Integer(0); |
|||
buzzerIndex < new Integer(this.listOfBuzzers.size()); |
|||
buzzerIndex += new Integer(1) |
|||
) |
|||
{ |
|||
IBuzzer buzzer = this.listOfBuzzers.get(buzzerIndex); |
|||
try |
|||
{ |
|||
buzzer.buzz(loopIndex); |
|||
} |
|||
catch (BuzzException buzzException) |
|||
{ |
|||
textualRepresentationOfFizzBuzzProgramOutput.append(buzzException.getMessage()); |
|||
atLeastOneBuzzerBuzzed = new Boolean(true); |
|||
} |
|||
} |
|||
List<String> currNames = new ArrayList<>(); |
|||
if (atLeastOneBuzzerBuzzed.equals(new Boolean(false))) |
|||
{ |
|||
textualRepresentationOfFizzBuzzProgramOutput.append(loopIndex.toString()); |
|||
} |
|||
for (Integer m : currMods) { |
|||
textualRepresentationOfFizzBuzzProgramOutput.append(new String("\n")); |
|||
} |
|||
String name = modToName.get(m); |
|||
return textualRepresentationOfFizzBuzzProgramOutput.toString(); |
|||
currNames.add(name); |
|||
long newNum = currNum + m; |
|||
} |
|||
scheduledAt(newNum).add(m); |
|||
} |
|||
class FizzBuzzEnterpriseDemo |
|||
{ |
|||
public static void main( |
|||
String[] programArgumentsAsProvidedByTheEndUser |
|||
) |
|||
{ |
|||
final UserSuppliedArguments userSuppliedArguments; |
|||
try |
|||
{ |
|||
userSuppliedArguments = new UserSuppliedArguments(programArgumentsAsProvidedByTheEndUser); |
|||
} |
|||
catch (IllegalArgumentException illegalArgumentException) |
|||
{ |
|||
System.err.println(illegalArgumentException.getMessage()); |
|||
System.exit(1); |
|||
return; |
|||
} |
} |
||
Entry result = new Entry(currNum, currNames); |
|||
final FizzBuzz fizzBuzz = new FizzBuzz(userSuppliedArguments.numericValueOfUpperLimit); |
|||
currNum++; |
|||
Iterator buzzerEntriesIterator = userSuppliedArguments.buzzerEntries.entrySet().iterator(); |
|||
return result; |
|||
while (buzzerEntriesIterator.hasNext()) |
|||
} |
|||
Map.Entry numericValueTextualRepresentationPair = (Map.Entry) buzzerEntriesIterator.next(); |
|||
@Override |
|||
fizzBuzz.addBuzzer(new Buzzer( |
|||
public void remove() { |
|||
(Integer) numericValueTextualRepresentationPair.getKey(), |
|||
schedule.remove(currNum - 1); |
|||
(String) numericValueTextualRepresentationPair.getValue() |
|||
} |
|||
} |
|||
@Override |
|||
System.out.println(fizzBuzz.doExecute()); |
|||
public boolean hasNext() { |
|||
return (maxNum < 0) || (currNum <= maxNum); |
|||
} |
|||
@Override |
|||
public Iterator<Entry> iterator() { |
|||
return this; |
|||
} |
} |
||
public static FizzBuzzer readFrom(InputStream in) { |
|||
{ |
|||
public final Integer numericValueOfUpperLimit; |
|||
public final Map<Integer,String> buzzerEntries; |
|||
FizzBuzzer fizzBuzzer = new FizzBuzzer(); |
|||
String[] sourceArguments |
|||
) |
|||
throws IllegalArgumentException |
|||
{ |
|||
Integer requiredAmountOfUserSuppliedArguments = new Integer(7); |
|||
Integer actualAmountOfUserSuppliedArguments = new Integer(sourceArguments.length); |
|||
try (Scanner scanner = new Scanner(in)) { |
|||
if (actualAmountOfUserSuppliedArguments < requiredAmountOfUserSuppliedArguments) |
|||
{ |
|||
throw new IllegalArgumentException(String.format( |
|||
"End user did not provide sufficient amount of command-line program arguments.\n"+ |
|||
"Required amount of arguments: %d\n"+ |
|||
"Amount of arguments supplied by the end used: %d\n", |
|||
requiredAmountOfUserSuppliedArguments, actualAmountOfUserSuppliedArguments |
|||
)); |
|||
} |
|||
long maxNum = scanner.nextLong(); |
|||
fizzBuzzer.setMaxNum(maxNum); |
|||
while (scanner.hasNext()) { |
|||
Integer mod = scanner.nextInt(); |
|||
scanner.skip("[\t ]*"); |
|||
String name = scanner.nextLine(); |
|||
fizzBuzzer.add(mod, name); |
|||
{ |
|||
numericValueOfUpperLimit = new Integer(textualValueOfUpperLimit); |
|||
if (numericValueOfUpperLimit < new Integer(0)) |
|||
{ |
|||
throw new IllegalArgumentException(); |
|||
} |
|||
} |
|||
catch (IllegalArgumentException illegalArgumentException) |
|||
{ |
|||
throw new IllegalArgumentException(String.format( |
|||
"End user supplied invalid value for upper limit for the FizzBuzz execution.\n"+ |
|||
"Required non-negative integer value.\n"+ |
|||
"Value supplied by the end user: %s\n", |
|||
textualValueOfUpperLimit |
|||
)); |
|||
} |
} |
||
} |
|||
return fizzBuzzer; |
|||
this.numericValueOfUpperLimit = numericValueOfUpperLimit; |
|||
} |
|||
public void printTo(OutputStream out) { |
|||
try (PrintWriter writer = new PrintWriter(out)) { |
|||
Integer loopIndex = new Integer(0); |
|||
loopIndex < new Integer(3); |
|||
loopIndex += new Integer(1) |
|||
) |
|||
{ |
|||
Integer numericValueArgumentIndex = new Integer(1) + loopIndex * new Integer(2); |
|||
Integer textualRepresentationArgumentIndex = numericValueArgumentIndex + new Integer(1); |
|||
for (FizzBuzzer.Entry e : this) { |
|||
String buzzerTextualValue; |
|||
String buzzerTextualRepresentation; |
|||
String strNames = String.join(" ", e.names); |
|||
buzzerTextualRepresentation = sourceArguments[textualRepresentationArgumentIndex]; |
|||
String line = String.format("%d %s", e.num, strNames); |
|||
buzzerTextualValue = sourceArguments[numericValueArgumentIndex]; |
|||
writer.println(line); |
|||
writer.flush(); |
|||
buzzerNumericValue = new Integer(buzzerTextualValue); |
|||
if (buzzerNumericValue <= new Integer(0)) |
|||
{ |
|||
throw new IllegalArgumentException(); |
|||
} |
|||
} |
|||
catch (IllegalArgumentException illegalArgumentException) |
|||
{ |
|||
throw new IllegalArgumentException(String.format( |
|||
"End user supplied invalid numeric value for buzzer.\n"+ |
|||
"Required positive integer value.\n"+ |
|||
"Value supplied by the end user: %s\n", |
|||
buzzerTextualValue |
|||
)); |
|||
} |
|||
remove(); |
|||
} |
} |
||
} |
} |
||
} |
|||
@Override |
|||
public String toString() { |
|||
return String.format("%s; current %d; max %d", |
|||
modToName, currNum, maxNum); |
|||
} |
} |
||
} |
} |
||
class GeneralFizzBuzz { |
|||
</lang> |
|||
public static void main(String[] args) { |
|||
try { |
|||
FizzBuzzer.readFrom(System.in).printTo(System.out); |
|||
} |
|||
catch (NoSuchElementException | IllegalStateException e) { |
|||
System.err.format("Error: %s\n", e.toString()); |
|||
System.exit(1); |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
Latest revision as of 09:50, 15 June 2023
/**
* @file GeneralFizzBuzz.java
*/
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Scanner;
/**
* This class follows the "God class" pattern.
* See {@link #main(String[])} for example usage.
*/
class FizzBuzzer
implements
Iterable<FizzBuzzer.Entry>,
Iterator<FizzBuzzer.Entry>
{
private static final long DEFAULT_START_NUM = 1;
private static final long DEFAULT_MAX_NUM = Long.MAX_VALUE;
public class Entry {
public final long num;
public final List<String> names;
private Entry(Long num, List<String> names) {
this.num = num;
this.names = names;
}
}
private Map<Integer, String> modToName = new HashMap<>();
private long currNum = DEFAULT_START_NUM;
private long maxNum = DEFAULT_MAX_NUM;
private Map<Long, List<Integer>> schedule = new HashMap<>();
public long getCurrNum() { return currNum; }
public void setCurrNum(long currNum) { this.currNum = currNum; }
public long getMaxNum() { return maxNum; }
public void setMaxNum(long maxNum) { this.maxNum = maxNum; }
private List<Integer> scheduledAt(long num) {
return schedule.computeIfAbsent(num, num_ -> new ArrayList<>());
}
private void scheduleNearest(Integer mod) {
long nearestNum = currNum + (mod - currNum % mod);
scheduledAt(nearestNum).add(mod);
}
public boolean add(Integer mod, String name) {
if (modToName.containsKey(mod)) {
return false;
}
modToName.put(mod, name);
scheduleNearest(mod);
return true;
}
public void addAll(Map<Integer, String> modToName) {
for (Map.Entry<Integer, String> modAndName : modToName.entrySet()) {
add(modAndName.getKey(), modAndName.getValue());
}
}
@Override
public Entry next() {
List<Integer> currMods = scheduledAt(currNum);
List<String> currNames = new ArrayList<>();
for (Integer m : currMods) {
String name = modToName.get(m);
currNames.add(name);
long newNum = currNum + m;
scheduledAt(newNum).add(m);
}
Entry result = new Entry(currNum, currNames);
currNum++;
return result;
}
@Override
public void remove() {
schedule.remove(currNum - 1);
}
@Override
public boolean hasNext() {
return (maxNum < 0) || (currNum <= maxNum);
}
@Override
public Iterator<Entry> iterator() {
return this;
}
public static FizzBuzzer readFrom(InputStream in) {
FizzBuzzer fizzBuzzer = new FizzBuzzer();
try (Scanner scanner = new Scanner(in)) {
long maxNum = scanner.nextLong();
fizzBuzzer.setMaxNum(maxNum);
while (scanner.hasNext()) {
Integer mod = scanner.nextInt();
scanner.skip("[\t ]*");
String name = scanner.nextLine();
fizzBuzzer.add(mod, name);
}
}
return fizzBuzzer;
}
public void printTo(OutputStream out) {
try (PrintWriter writer = new PrintWriter(out)) {
for (FizzBuzzer.Entry e : this) {
String strNames = String.join(" ", e.names);
String line = String.format("%d %s", e.num, strNames);
writer.println(line);
writer.flush();
remove();
}
}
}
@Override
public String toString() {
return String.format("%s; current %d; max %d",
modToName, currNum, maxNum);
}
}
class GeneralFizzBuzz {
public static void main(String[] args) {
try {
FizzBuzzer.readFrom(System.in).printTo(System.out);
}
catch (NoSuchElementException | IllegalStateException e) {
System.err.format("Error: %s\n", e.toString());
System.exit(1);
}
}
}