Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spotify puzzle problem

I'm trying to solve the "best before" Spotify puzzle described on this page. Basically, with an input of three integers separated by slashes (e.g. 11/3/4) you're supposed to generate an output with the earliest possible date in 2011-03-04 format. If no date is possible, it should return the original string followed by "is illegal".

The idea for my solution below was borrowed from a Python solution I found for the same problem at github. When I submit this Python code, it is accepted. Not being familiar with Python, this is my best attempt at making something similar with Java, and without using any Calendar functions as can be seen in this solution posted here at stackoverflow.

When I submit my solution, however, I get "Wrong Answer" as the response. Try as I might, I cannot find any errors with this code. I feel like I've tried every single possible combination of inputs, and all my outputs come out correctly. Anyone have any idea what I might be missing?

Since I'm relatively new to programming in general, feel free to also give advice on how the code can be improved in general if you want. I'm sure it might look noobish. Thanks!

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class DateProggy3 {

    static int var1, var2, var3;
    static int slashPosition1, slashPosition2;
    static String yearString, monthString, dayString;

    public static void main(String[] args) throws IOException {
        String dateInput = readDate();
        splitInputToInts(dateInput);
        Integer[] dateArray = {var1, var2, var3};
        Arrays.sort(dateArray);
        Integer bestDate[] = getBestDate(dateArray, dateInput);
        convertDate(bestDate);
        printDate(bestDate);
    }

    public static String readDate() throws IOException {
        BufferedReader stdin = new BufferedReader
          (new InputStreamReader(System.in));
        String dateInput; 
        dateInput = stdin.readLine();
        return dateInput;
    }

    public static void splitInputToInts(String dateInput) {
        try {
        slashPosition1 = dateInput.indexOf('/');
        slashPosition2 = dateInput.lastIndexOf('/');
        var1 = Integer.parseInt(dateInput.substring(0, slashPosition1));
        var2 = Integer.parseInt(dateInput.substring(slashPosition1+1, slashPosition2));
        var3 = Integer.parseInt(dateInput.substring(slashPosition2+1, dateInput.length()));
        }catch (StringIndexOutOfBoundsException e){
            illegal(dateInput);
        }catch (NumberFormatException e){
            illegal(dateInput);
        }
    }

    public static void illegal(String dateInput){
        System.out.println(dateInput + " is illegal");
        System.exit(0); 
    }

    public static Integer[] getBestDate(Integer[] dateArray, String dateInput){
        var1 = dateArray[0];
        var2 = dateArray[1];
        var3 = dateArray[2];
        if (testDate(var1, var2, var3)){
            Integer[] bestDate = {var1, var2, var3};
            return bestDate;
        }
        else if (testDate(var1, var3, var2)){
            Integer[] bestDate = {var1, var3, var2};
            return bestDate;
        }
        else if (testDate(var2, var1, var3)){
            Integer[] bestDate = {var2, var1, var3};
            return bestDate;
        }
        else if (testDate(var2, var3, var1)){
            Integer[] bestDate = {var2, var3, var1};
            return bestDate;
        }
        else if (testDate(var3, var1, var2)){
            Integer[] bestDate = {var3, var1, var2};
            return bestDate;
        }
        else if (testDate(var3, var2, var1)){
            Integer[] bestDate = {var3, var2, var1};
            return bestDate;
        }else{
            illegal(dateInput);
        }
        Integer[] bestDate = {var1, var2, var3};
        return bestDate;
    }

    public static boolean testDate(int year, int month, int day){
        boolean leapYear = false;
        boolean dateOK;
        if (year > 100 && year < 2000){
            return dateOK = false;
        }
        if (year < 1000){
            year+=2000;
        }
        if (year < 0){
            return dateOK = false;
        }
        if (year % 4 == 0) {
            if (year % 100 == 0 && year % 400 != 0) {
                leapYear = false; 
            }
            leapYear = true;
        }else{
            leapYear = false;
        }
        if (month > 12 || month < 1){
            return dateOK = false;
        }
        switch (month){
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                if (day > 31 || day < 1){
                    return dateOK = false;
                }
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                if (day > 30 || day < 1){
                    return dateOK = false;
                }
                break;
            case 2:
                int maxDay;
                if (leapYear){
                    maxDay = 29;
                }else{
                    maxDay = 28;
                }
                if (day > maxDay || day < 1){
                    return dateOK = false;
                }
        }
        return dateOK = true;
    }


    public static void convertDate(Integer[] dateArray){
        if (dateArray[0] < 1000){
            dateArray[0]+=2000; 
        }
        yearString = String.valueOf(dateArray[0]); 
        if (dateArray[1] < 10){ 
            monthString = "0" + dateArray[1];
        }else{
            monthString = String.valueOf(dateArray[1]);
        }
        if (dateArray[2] < 10){
            dayString = "0" + dateArray[2];
        }else{
            dayString = String.valueOf(dateArray[2]);
        }
    }

    public static void printDate(Integer[] dateArray){
        System.out.println(yearString + "-" + monthString +"-" + dayString);
    }
}

I'm the one who asked the question, but can't seem to comment and reply normally to the answers anymore since I registered to stackoverflow and lost my original cookies or something.

Anyway, thanks palacsint for your answer. I fixed the leap year problem and now my answer finally got accepted!

A question about the last two lines in the getBestDate() method. I put those there just because Eclipse IDE otherwise gives me the error "This method must return a result of type Integer[]". It doesn't seem satisfied with having all the returns in if brackets. Is there any way around this? Thanks.

like image 754
mattboy Avatar asked Nov 13 '22 17:11

mattboy


1 Answers

One bug: it accepts 2100/02/29. 2100 is not a leap year, so there is no 2011/02/29.

If I were you, I would use SimpleDateFormat for parsing and validating (hint: lenient parsing). It's much simpler, much intuitive and the code would be easier to read. (Don't Reinvent The Wheel)

Some other thoughts above.

Unnecessary assignments: return dateOK = false;

Just return with false:

return false;

(The dataOK variable is unnecessary in your case.)

public static void illegal(String dateInput){
    System.out.println(dateInput + " is illegal");
    System.exit(0); 
}

Throw exceptions instead of System.exit().

In the getBestDate() method the last two lines never run. They are dead code (since illegal() calls System.exit()):

}else{
    illegal(dateInput);
}

Integer[] bestDate = {var1, var2, var3};
return bestDate;

If it's possible avoid static methods and fields. Lastly, it's a good problem to learn how to write unit tests.

like image 168
palacsint Avatar answered Dec 15 '22 04:12

palacsint