Decrementing Carousel
is a container, accepting int elements. DecrementingCarousel
has a maximum capacity, specified via the constructor. When created, DecrementingCarousel is in accumulating state: you may add elements via the addElement
method and can produce a CarouselRun
object via the run
method. Once the run
method is called, DecrementingCarousel
is in running state: it refuses adding more elements.
The CarouselRun
allows to iterate over elements of the carousel decrementing them one by one with the next
method. The next
returns the value of the current element.
The CarouselRun
iterates over elements in the order of their insertion.
When an element is decreased to zero, the CarouselRun
will skip it in further iterations. When there are no more elements available for decrementing, the CarouselRun
returns -1.
The CarouselRun
also has the isFinished
method, which indicates, if the carousel has run out of the lements to decrement.
Specification Details
boolean addElement(int element)
- adds an element. If element is negative or zero, do not add the element. If container is full, do not add the element. If the run method was called to create a CarouselRun
, do not add the element. If element is added successfully, return true
. Return false
otherwise.
CarouselRun run()
- returns a CarouselRun to iterate over the elements. If the run method has already been called earlier, it must return null
: DecrementingCarousel
may generate only one CarouselRun
object.
CarouselRun
has two public methods:
int next()
- returns the current value of the current element, then decreases the current element by one and switches to the next element in insertion order. Skips zero elements. When there is no more elements to decrease, returns -1.
boolean isFinished()
- when there is no more elements to decrease, returns true
. Otherwise, returns false
.
The code:
public class DecrementingCarousel {
private final int capacity;
static int[] carousel;
int index;
boolean isRun;
{
index = 0;
isRun = false;
}
public DecrementingCarousel(int capacity) {
this.capacity = capacity;
carousel = new int[capacity];
}
public boolean addElement(int element){
if (element > 0 && index < capacity && !isRun) {
carousel[index ] = element;
return true;
}
return false;
}
public CarouselRun run() {
if (!isRun) {
isRun = true;
return new CarouselRun();
}
return null;
}
}
Methods in CarouselRun:
public class CarouselRun {
protected final int[] array = DecrementingCarousel.carousel.clone();
protected int position = 0;
public int next() {
if (isFinished())
return -1;
else {
while (array[position %= array.length] <= 0) {
position ;
}
}
return array[position ]--;
}
public boolean isFinished() {
for (int el : array)
if (el > 0)
return false;
return true;
}
}
So this subclass must decrement elements by gradually increasing decrement. When you need to decrement an element for the first time, decrease it by 1. Next time you need to decrement the same element, decrease it by 2. Next time decrease by 3, then by 4 and so on.
public class GraduallyDecreasingCarousel extends DecrementingCarousel{
public GraduallyDecreasingCarousel(final int capacity) {
super(capacity);
}
@Override
public CarouselRun run() {
if (!isRun) {
isRun = true;
return new GraduallyDecreasingCarouselRun();
}
return null;
}
}
public class GraduallyDecreasingCarouselRun extends CarouselRun {
int decrement = 1;
@Override
public int next() {
int beforeDecreasing;
if (isFinished())
return -1;
else {
while (array[position %= array.length] <= 0) {
position ;
if (position == array.length) {
decrement ;
}
}
}
beforeDecreasing = array[position];
array[position ] -= decrement;
return beforeDecreasing;
}
The main method:
public class Main {
public static void main(String[] args) {
DecrementingCarousel carousel = new GraduallyDecreasingCarousel(7);
carousel.addElement(20);
carousel.addElement(30);
carousel.addElement(10);
CarouselRun run = carousel.run();
System.out.println(run.isFinished()); //false
System.out.println(run.next()); //20
System.out.println(run.next()); //30
System.out.println(run.next()); //10
System.out.println(">>>>>>>>>>");
System.out.println(run.next()); //19
System.out.println(run.next()); //29
System.out.println(run.next()); //9
System.out.println(">>>>>>>>>>");
System.out.println(run.next()); //17
System.out.println(run.next()); //27
System.out.println(run.next()); //7
System.out.println(">>>>>>>>>>");
System.out.println(run.next()); //14
System.out.println(run.next()); //24
System.out.println(run.next()); //4
System.out.println(">>>>>>>>>>");
System.out.println(run.next()); //10
System.out.println(run.next()); //20
System.out.println(">>>>>>>>>>");
System.out.println(run.next()); //5
System.out.println(run.next()); //15
System.out.println(">>>>>>>>>>");
System.out.println(run.next()); //9
System.out.println(">>>>>>>>>>");
System.out.println(run.next()); //2
System.out.println(run.isFinished()); //true
System.out.println(run.next()); //-1
}
}
it works fine in main but wont pass the tests IDK how to change next method in GraduallyDecreasingCarouselRun
tried counting next calls and reset the counter when its greater than amount of elements to decrease but when theres one element left its wasnt working correctly
CodePudding user response:
Wow. Needed a really long time to fully understand the problem. The problem occurs when you fill the capacity of your array completely.
In that case your check for incrementing the value of decrease
inside the while loop can fail, because the modulo assignment will "reset" the position to 0 without going inside the loop and therefore skipping the increment of decrease
.
The solution to make the code understandable easier would be to decouple the modulo assignment from the while condition. This is slower and uses more code, but makes it easier to understand and also handles position
as the "next" position like stated in the specification. Optimizations are possible, but I just post the unoptimized code here:
public int next() {
int beforeDecreasing;
if (isFinished())
return -1;
else {
beforeDecreasing = array[position];
array[position] -= decrement;
do {
position ;
if (position == array.length) {
decrement ;
position = 0;
}
} while ((array[position] <= 0) && !isFinished());
}
return beforeDecreasing;
}
CodePudding user response:
For a "quick win" I would suggest another solution: change the place and check for the increment of decrease
: (only snippet from inside the else
branch)
int oldPosition = position;
while (array[position %= array.length] <= 0) {
position ;
}
if (oldPosition > position) {
decrement ;
}