HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Chocolate Distribution in a school

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
distributionschoolchocolate

Problem

Problem Statement


In a school, chocolate bars have to be distributed to children waiting
in a queue. Each Chocolate bar is rectangular in shape. Consider its
side lengths are integer values.


The distribution procedure is as follows:



  • If a bar is not square in shape, then the largest possible square piece of Chocolate is broken and given to the first child in queue.



  • If bar is square in shape, then complete bar is given to the first child in queue.





Once a child receives his share of Chocolate, he leaves the queue. The
remaining portion of the Chocolate bar is dealt in same fashion and
the whole or a portion of it is given to the next child in the queue.


School has a carton of Chocolate bars to be distributed among the
children all over the School. The Chocolate bars in the carton are of
different sizes. A bar of length i and breadth j is considered to be
different from a bar of length j and breadth i.


For every i such that M

  • next child would receive 2x2 portion (remaining 2x1 portion)



  • now the remaining portion are 2 square pieces of (1x1), which can be given to 2 more children





So the Cadbury bar with the size of 5x3 can be distributed to 4
children.


Similarly we can find out number of children for rest of the
combinations (i.e. 5x4, 6x3, 6x4) in the given range as follows:



Please let me know the corrections that I can make to improve the code.

```
public class CandidateCode {

public int distributeChocolate(int input1,int input2,int input3,int input4){
int[] chocolatelengthLimits = {input1,input2};
int[] chocolatewidthLimits = {input3,input4};
Set chocolateCarton = makeSetOfChocolatesOutOfTheLimits(chocolatelengthLimits, chocolatewidthLimits);
return getTotalNumberofChildrenThatCanBeFed(chocolateCarton);
}

private int getTotalNumberofChildrenThatCanBeFed(Set chocolateCarton){
int totalNumberOfChildrenThatCanBeFed = 0

Solution

I'd try a more top-down approach. At the moment, you make a lot of internal information of a Chocolate object available to public in order to do some calculation and decision making outside that class.

Your method numberOfChildrenThatCanBeFedFromTheChocolate for example deals with blocks of chocolate. A block of chocolate is the atomic element a chocolate bar is made from. The problem here is that the question doesn't ask for chocolate blocks. Sure, the number of blocks and how they are positioned in a grid determines how often a square can be broken off the chocolate bar, but thinking about it in terms of blocks is a bottom-up way of thinking. I as the user of your class could not care less about blocks. The problem asks for squares, not blocks. Why do I have to deal with blocks when using your class?

If you model the data/code according to the question, you get a more top-down approach, which is more abstract, but easier to digest.

You have a chocolate bar in your hand. You can break off a square piece and be left with a different sized chocolate bar or nothing. You don't really care about the size of the square broken off or the remainder. All you really care about is how often you can perform that action until there's no chocolate bar remaining. Of course you have to care about it internally somehow, but again, this is top-down thinking. Look at how your class (its objects) should be used

Another idea that you can use to your advantage is information hiding. As it turns out, the logic is often concerned with what's the longer side and what's the shorter one. Then why not store exactly that information?

Here's a version of Chocolate.java that works with the ideas mentioned above:

public class Chocolate
{
    private int min;
    private int max;

    public Chocolate(int width, int height)
    {
        min = Math.min(width, height);
        max = Math.max(width, height);
    }

    public Chocolate remainderAfterSquareBreakoff()
    {
        if ((min == 1 && max == 1) || min == max)
        {
            return null;
        }

        return new Chocolate(max - min, min);
    }

    public static void main(String[] args)
    {
        Chocolate chocolate = new Chocolate(6, 3);

        int numberOfSquares = 0;

        do
        {
            ++numberOfSquares;

            chocolate = chocolate.remainderAfterSquareBreakoff()
        }
        while (chocolate != null);

        System.out.println("# squares: " + numberOfSquares);
    }
}


The two important things are:

  • Count how often a square can be broken off until no remainder remains. This is very close to how you would break the chocolate in real life and is thus hopefully intuitive and easy to understand.



  • The size of the chocolate is stored in terms of longest and shortest side, not width and length.



You use long descriptive names for your methods, which is good. But you have so much logic outside of the Chocolate class that you need many such long descriptive names to keep track of everything. That bloats the code and reduces readability. With only a few things exposed to public, the code becomes less bloated and you need fewer identifiers.

This is clearly not providing the same functionality that your code has. Most importantly, the following doesn't hold any more:


Each Chocolate bar in carton is unique in length (i) and breath(j).

By only storing them as longest and shortest side, the orientation is lost. I'd say the orientation is not necessarily necessary to solve the task at hand. The problem only arises if a Set should be used to store the Chocolate objects, because you cannot define an equals() method to distinguish two objects only by their max and min properties. If you put them into a different data structure that does not require uniqueness like ArrayList for example, everything is fine.

If you insist on uniqueness and the use of Set, you can add another property isLandscapeFormat which can then be used to distinguish between different orientations.

public class Chocolate
{
    private int min;
    private int max;

    private boolean isLandscapeFormat;

    public Chocolate(int width, int height)
    {
        min = Math.min(width, height);
        max = Math.max(width, height);

        isLandscapeFormat = width > height;
    }


And now for something completely different.

The above assumes that you don't care about what square is broken off the bar. It also makes it necessary to reassign the return value of the method to the chocolate object.

A more common approach for this call-method-until-null-is-returned structure is an iterator.

Here's a different version of Chocolate.java that incorporates that principle.

```
public class Chocolate
{
private int min;
private int max;

public Chocolate(int width, int height)
{
setMinMax(width, height);
}

private void setMinMax(int a, int b)
{
min = Math.min(a, b);
ma

Code Snippets

public class Chocolate
{
    private int min;
    private int max;

    public Chocolate(int width, int height)
    {
        min = Math.min(width, height);
        max = Math.max(width, height);
    }

    public Chocolate remainderAfterSquareBreakoff()
    {
        if ((min == 1 && max == 1) || min == max)
        {
            return null;
        }

        return new Chocolate(max - min, min);
    }

    public static void main(String[] args)
    {
        Chocolate chocolate = new Chocolate(6, 3);

        int numberOfSquares = 0;

        do
        {
            ++numberOfSquares;

            chocolate = chocolate.remainderAfterSquareBreakoff()
        }
        while (chocolate != null);

        System.out.println("# squares: " + numberOfSquares);
    }
}
public class Chocolate
{
    private int min;
    private int max;

    private boolean isLandscapeFormat;

    public Chocolate(int width, int height)
    {
        min = Math.min(width, height);
        max = Math.max(width, height);

        isLandscapeFormat = width > height;
    }
public class Chocolate
{
    private int min;
    private int max;

    public Chocolate(int width, int height)
    {
        setMinMax(width, height);
    }

    private void setMinMax(int a, int b)
    {
        min = Math.min(a, b);
        max = Math.max(a, b);
    }

    public boolean hasNextSquare()
    {
        return min > 0 && max > 0;
    }

    public Chocolate getNextSquare()
    {
        if (!hasNextSquare())
        {
            return null;
        }

        setMinMax(max-min, min);

        return new Chocolate(min, min);
    }

    public static void main(String[] args)
    {
        Chocolate chocolate = new Chocolate(5, 3);

        int numberOfSquares = 0;

        while(chocolate.hasNextSquare())
        {
            ++numberOfSquares;

            chocolate.getNextSquare();
        }

        System.out.println("# squares: " + numberOfSquares);
    }
}
while(chocolate.hasNextSquare())
{
    ++numberOfSquares;

    chocolate.getNextSquare();
}

Context

StackExchange Code Review Q#129599, answer score: 7

Revisions (0)

No revisions yet.