2

I am trying to rewrite my code without a conditional statement and loop. My code is written based on the instruction like this, but additionally without loop and conditional statement

A program that take input as start month and day to end month and day and

calculate total price.

Supposed inputs are always correct.

Input range is same year January 1 to Dec 31

January 1/1 is Monday.

Input start day is always Monday

Even month consists of 31 days , Odd month consists of 30 days

For price Weekday -> $2

Sat -> $3

Sun -> $5

If customer book over 50 days, price is going to get flat to $1


 public class test {
    int startMonth;
    int startDay;
    int endMonth;
    int endDay;
    int totalDate;

    public test (int startMonth, int startDay, int endMonth, int endDay) {
        this.endMonth = endMonth;
        this.endDay = endDay;
        this.startMonth = startMonth;
        this.startDay = startDay;
    }
    public int getPrice() {
        getTotalDate();
        int price = 0;
        int discount = totalDate > 50 ? totalDate - 50 : 0;
        System.out.println("discount " + discount);
        totalDate = totalDate > 50 ? 50 : totalDate % 50;
        System.out.println("totalData : " + totalDate);
        int sunDay = totalDate/7;
        int satDay = totalDate/7 + (totalDate%7)/6;
        int weekDay = totalDate - sunDay - satDay;
        price+= sunDay*5 + satDay*3 + weekDay*2;
        return price + discount;

    }
    public int getTotalDate() {
        int gapOfMonth = endMonth - startMonth;
        totalDate = gapOfMonth*30 + (gapOfMonth +1)/2 + (endDay - startDay);
        return totalDate;
    }

    public static void main (String[] args) {
        test t = new test(1,1,2,30);
        System.out.println("test");
        System.out.println(t.getPrice());
    }
}

  • 2
    Are you trying to count the number of days between two dates in this imaginary calendar system? Or trying to calculated the total price based on three number off weekdays/Saturdays/Sundays in that range with something happening off the number of days is over 50? – Dave Newton May 01 '20 at 23:14
  • "Start day is always Monday", what does it mean btw? New year always start with monday? Or the user will always select start day on monday, or any start day entered will be considered as monday? – Martheen May 01 '20 at 23:17
  • the input start day always has to be Monday – Happydoodle Pa May 01 '20 at 23:18
  • The no conditional and no loop thus applies to the whole logic? Both getPrice and getTotalDate can't have any conditional nor loop? – Martheen May 01 '20 at 23:23
  • No loop and no conditional statement,, is it possible? – Happydoodle Pa May 01 '20 at 23:36
  • It's possible. The constraint on start day always on Monday means it's the matter of modulo calculations – Martheen May 01 '20 at 23:38
  • I thought about modulo , but there are so many edge cases I have to handle.. how would you handle redundant works? – Happydoodle Pa May 01 '20 at 23:49
  • There are no redundant works. Start the initial variable from 0, and pass it through a succession of calculations that always works (adding, reducing, or let the value as it is) regardless of the input. Separate the calculations so you don't need ifs. – Martheen May 02 '20 at 00:00
  • I do not quite get what you mean.. but is this way without loop as well? – Happydoodle Pa May 02 '20 at 00:02
  • Yes it is without loop. By the way, is it possible to enter the same day for start and end? And will that result in totaldate of 1, or 0? I'm trying to play with in right now – Martheen May 02 '20 at 00:07
  • yes it is possible to enter same day, then it will output 0.. May I see your code – Happydoodle Pa May 02 '20 at 00:08
  • Oh and the over 50 days, does it means 51 days will result in price of 51, or does the first 50 days is still calculated normally and the rest is set to 1? – Martheen May 02 '20 at 00:09
  • It means that 51 day price will be $ 1! yes and 50 day is calculated normally – Happydoodle Pa May 02 '20 at 00:13
  • 1
    Is this a class assignment? If so, where is the code that you have written. – NomadMaker May 02 '20 at 02:17
  • Using ternary seems to be bit cheating isn't it? Because it is a conditional statement. Though I never managed to solve the over 50 without bitwise witchcraft. – Martheen May 02 '20 at 02:56
  • I think ternary is fine, but how did you use bitwise method to this problem? – Happydoodle Pa May 02 '20 at 03:01
  • Posted my answer. Mind if I ask where do you get this problem? Seems rather fun to solve other teasers like this – Martheen May 02 '20 at 03:30
  • My friend made it to challenge me.. haha but thank you so much – Happydoodle Pa May 02 '20 at 03:45
  • *"My friend made it to challenge me.. "* -- So why are you asking us? Cheat! :-) – Stephen C May 02 '20 at 04:18

4 Answers4

2

Managed to complete it without ternary

public int getPrice(int totalDay) {
    int totalPrice = 0;
    int difference = totalDay-50;
    //from https://stackoverflow.com/a/2707438/529282
    int absDifference = difference*(1-2*((3*difference)/(3*difference+1)));

    //this essentially gives the minimum value between totalDay and 50
    int before50 = (totalDay+50-absDifference)/2;

    int after50 = totalDay-before50;

    totalPrice += after50;

    //the before 50 is where the complex calculation is needed
    int before50 = totalDay - after50;

    //first, the base price for weekday
    totalPrice += before50 * 2;

    //then we add the whole week difference (sat+sun price - weekday price)
    totalPrice += (before50 / 7) * 4;

    //the we add the stray saturday if any
    totalPrice += (before50 % 7) / 6;

    return totalPrice;
}

public int getTotalDate() {
    int totalDate = 0;
    //add month difference
    totalDate += 30 * (endMonth - startMonth);

    //add day difference
    totalDate += (endDay - startDay);

    //add the extra from having 31 days every two months
    totalDate += (endMonth - startMonth) / 2;

    //if the month start from even months and the end month is different, 
    //add another day since it ends with 31
    //the trick here, if startMonth == endMonth, startMonth/endMonth = 1,
    //so 1-1 is 0, nothing get added
    //while if startMonth<endMonth, startMonth/endMont = 0, so 1-0 is 1
    totalDate += ((startMonth + 1) % 2) * (1 - startMonth / endMonth);

    return totalDate;

}
Martheen
  • 5,198
  • 4
  • 32
  • 55
1

If you don't mind Java to take care of the looping, you can make use of LocalDate and ChronoUnit.

    Long totalPrice;

    // I gave this date for example . You can convert your input to a LocalDate format
    LocalDate startDate = LocalDate.now();
    LocalDate endDate = LocalDate.now().plusDays(15);

     //+1 or +2 or 0 based on your requirement
    Long duration = DAYS.between(startDate,endDate )+1;
    if(duration>50)
        return 50;

    long saturdays = WEEKS.between(startDate.with(DayOfWeek.SATURDAY), endDate.with(DayOfWeek.SATURDAY));
    long sundays = WEEKS.between(startDate.with(DayOfWeek.SUNDAY), endDate.with(DayOfWeek.SUNDAY));

    long weekDays = duration - (saturdays+sundays);

    totalPrice = weekDays + (saturdays*3 +sundays*5);

    return totalPrice;
  • 1
    This one would not work because it is not based on given calendar system such as odd month consists of 30 days, but this system consists of real calendal – Happydoodle Pa May 02 '20 at 00:36
1

I came up with another solution using some lookup tables:

public class PriceCalc {
    private static final int FULL_WEEK_PRICE = 18;
    private static final int REGULAR_DAYS = 50;

    private static final int[] PREV_DAYS = {
        0,  31,  61,  92, 122, 153, 183, 214, 244, 275, 305, 336
    };

    // remainders between start and end dates
    private static final int[][] RESTS = {
       // S   M   T   W   T   F   S 
        { 0,  5,  7,  9, 11, 13, 16},
        {13,  0,  2,  4,  6,  8, 10},
        {11, 16,  0,  2,  4,  6,  8},
        { 9, 14, 16,  0,  2,  4,  6},
        { 7, 12, 14, 16,  0,  2,  4},
        { 5, 10, 12, 14, 16,  0,  2},
        { 3,  8, 10, 12, 14, 16,  0}
    };  

    private int startDate;
    private int startMonth;

    private int endDate;
    private int endMonth;

    public PriceCalc(int startDate, int startMonth, int endDate, int endMonth) {
        super();
        this.startDate = startDate;
        this.startMonth = startMonth;
        this.endDate = endDate;
        this.endMonth = endMonth;
    }

    private static int dayOfYear(int day, int month) {
        return day + PREV_DAYS[(month - 1) % 12];
    }

    private static int dayOfWeek(int day, int month) {
        return dayOfYear(day, month) % 7;
    }

    private static int isFlat(int duration) {
        int flat = duration / REGULAR_DAYS;
        try {
            flat /= flat;
            return flat;
        }
        catch(ArithmeticException e) {
            return 0;
        }
    }

    private int durationDays() {
        int startDOY = dayOfYear(startDate, startMonth);
        int endDOY = dayOfYear(endDate, endMonth);

        return endDOY - startDOY;
    }

    public int calcPrice() {
        int startDOW = dayOfWeek(startDate, startMonth);

        int duration = durationDays();
        int flat = isFlat(duration);

        int regularDuration = duration * (1 - flat) + REGULAR_DAYS * flat;
        int discount = flat * (duration - REGULAR_DAYS);

        int fullWeeks = regularDuration / 7;
        int rem = regularDuration % 7;
        int endDOW = (dayOfYear(startDate, startMonth) + regularDuration) % 7;
        int remainder = RESTS[startDOW][endDOW];

        int price = fullWeeks * FULL_WEEK_PRICE + remainder + discount;

        System.out.printf("Price for %3d days = %2d full weeks + %d days + %3d flat-rate days is: $%3d + $%2d + $%3d = $%3d%n",
            duration, fullWeeks, rem, discount, 
            fullWeeks * FULL_WEEK_PRICE, remainder, discount, price
        );
        return price;
    }

    public static void main(String[] args) {
        new PriceCalc(1,  1,  4, 1).calcPrice(); // $  0 + $ 6 + $  0 = $  6
        new PriceCalc(6,  1, 11, 1).calcPrice(); // $  0 + $14 + $  0 = $ 14
        new PriceCalc(1,  1,  9, 1).calcPrice(); // $ 18 + $ 2 + $  0 = $ 20
        new PriceCalc(3,  1, 17, 1).calcPrice(); // $ 36 + $ 0 + $  0 = $ 36
        new PriceCalc(4,  1, 23, 1).calcPrice(); // $ 36 + $14 + $  0 = $ 50
        new PriceCalc(27, 1,  5, 3).calcPrice(); // $ 90 + $12 + $  0 = $102
        new PriceCalc(28, 2,  1, 6).calcPrice(); // $126 + $ 2 + $ 45 = $173
    }
}
Nowhere Man
  • 19,170
  • 9
  • 17
  • 42
0

Perhaps the creator wants you to find the formula. I have based and your code:

public int getPrice() {
    getTotalDate();
    int comboDate;
    int normalDate;
    if (totalDate > 50){
        comboDate = totalDate - 50;
        normalDate = 50;
    } else {
        comboDate = 0;
        normalDate = totalDate;
    }
    int sunDay = normalDate/7;
    int satDay = normalDate/7 + (normalDate%6)/6;
    int weekDay = normalDate - satDay - sunDay;
    return comboDate*1 + sunDay*5 + satDay*3 + weekDay*2;
}
public int getTotalDate() {
    int start = startMonth*30 + (startMonth-1)/2 + startDay;
    int end = endMonth*30 + (endMonth-1)/2 + endDay;
    totalDate = end - start + 1;
    return totalDate;
}
  • This is awesome answer and I was thinking this way as well, but the question is the flat rate will be applied to $1 after 50 days after, so even if totalData is over 50 days, within 50 days, it still need to apply normal rate. any Idea how to handle? – Happydoodle Pa May 02 '20 at 01:31
  • Sorry, I didn't understand the question. I fixed the code – Lê Hoàng Dững May 02 '20 at 02:02
  • This code return 1 for January 1 to January 1, and return 31 for January 1 to February 1 while in the imaginary calendar by OP, it's the even month that have 31 days – Martheen May 02 '20 at 02:24
  • Also one of the edge case is when there are 100 days gap, it will return 0 – Happydoodle Pa May 02 '20 at 02:31
  • @HappydoodlePa As you said that you "was thinking about this as well", you'd want to update your current code to the question, so we can figure out what's wrong with it – Martheen May 02 '20 at 02:38
  • @Martheen I appreciate your time, and i just posted my progress. i think i almost got this. just need to polish now – Happydoodle Pa May 02 '20 at 02:50
  • I am stuck at how to handle when input is like 2/1 to 3/something vs 3/1 to 4/something since it even month is 31 and odd is 30 – Happydoodle Pa May 02 '20 at 02:56
  • I have set the date to be January 1. But the problem is that the if condition cannot be ignored – Lê Hoàng Dững May 02 '20 at 03:59