Page 1 of 2 12 LastLast
Results 1 to 10 of 20

Thread: Beginner's Programming Challenge 17

  1. #1
    Join Date
    Jun 2008
    Beans
    199
    Distro
    Ubuntu Development Release

    Beginner's Programming Challenge 17

    Well, I won the last programming challenge, so here is the next one. This involves parsing input with regards to tasks.

    The challenge:
    Build a program that asks for input in the format:
    Code:
    [Task Title] due [Date]
    Where [Task Title] is the title of the task, and [Date] is a string representing a date. This date string could be:
    1. An Absolute Date ("5 Nov 2010")
    2. A week day ("Tuesday"--meaning its due the next day that is a Tuesday)
    3. A Relative Date ("Tomorrow", "the day after tomorrow", "in 2 days")


    The program should return an array with the title of the task, and an absolute representation of the due date.

    Bonus:
    At the very least, the program should understand absolute dates and "tomorrow."

    Anything more counts as bonus.

    Also, if you can get the program to actually keep track of your tasks, that would be great.

    Remember, normal rules apply - the code should be all your code - try not to copy/paste other code, but read it, understand it, and type it yourself.

    Good luck

  2. #2
    Join Date
    Nov 2010
    Beans
    6

    Re: Beginner's Programming Challenge 17

    Not familiar with these challenges, are we free to code in any language for this?

  3. #3
    Join Date
    Apr 2007
    Location
    NorCal
    Beans
    1,149
    Distro
    Ubuntu 10.04 Lucid Lynx

    Re: Beginner's Programming Challenge 17

    Quote Originally Posted by austinprete View Post
    Not familiar with these challenges, are we free to code in any language for this?
    Yup, although we usually ask that you use languages with a package available from the repos (for convenience). This includes most popular languages.
    Posting code? Use the [code] or [php] tags.
    I don't care, I'm still free. You can't take the sky from me.

  4. #4
    Join Date
    Nov 2010
    Beans
    6

    Re: Beginner's Programming Challenge 17

    Alright, I wasn't going to do anything crazy with it. I'll probably either attempt it in C or Python. Just wanted to make sure it wasn't a specific language.

  5. #5
    Join Date
    Jun 2006
    Beans
    596
    Distro
    Kubuntu

    Re: Beginner's Programming Challenge 17

    My entry in ruby:
    Code:
    #!/usr/bin/env ruby
    
    require 'date'
    
    puts "Enter your task in the form:"
    puts "[Task Description] due [Date]"
    date_string,task = gets.chomp.reverse.split(" eud ",2).each{|s| s.reverse!}
    
    begin
        date = Date.parse(date_string)
    rescue ArgumentError
        date = case
               when date_string.downcase.match("day after tomorrow")
                   then Date.today + 2
               when date_string.downcase.match("tomorrow")
                   then Date.today + 1
               when days = date_string.downcase.match(/in (\d+) day/)
                   then Date.today + days[1].to_i
               else nil
               end
    end
    
    if !date
        $stderr.puts "ERROR: Unable to parse date."
        exit -1
    end
    
    puts task,date
    Features:
    • understands "tomorrow", "day after tomorrow" and "in xx day(s)", in addition to most permutations of YYYY-MM-DD.
    • correctly handles the string " due " appearing in a task description.

  6. #6

    Re: Beginner's Programming Challenge 17

    revised edition..
    Code:
    '''convert received date from stdin to datetime object with the following format, DD-month_abbreviation-YYYY
    ex. 2000 12 november -> 12 Nov 2000'''
    
    import datetime
    import re
    
    local = datetime.date.today()
    
    def get_task():
    	task_date = input('input task title and date:')
    	return [a.rstrip().lstrip() for a in task_date.split('due')]
    
    def parse_date(today):
    	days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
    	if 'in' in today:
    		diff = int(re.search('(\d+)', today).group(0))
    		reply = lang_format(diff)
    	elif 'day after tomorrow' in today:
    		diff = 2
    		reply = lang_format(diff)
    	elif today == 'tomorrow':
    		diff = 1
    		reply = lang_format(diff)
    	elif today.lower() in days:
    		reply = days_format(today, days)
    	else:
    		reply = iso_format(today)
    	if reply != None:
    		return reply
    
    def iso_format(today):
    	date_formats = ["%d %b %Y", "%d %b %y", "%Y %b %d", "%d %B %Y", "%d %B %y"]
    	for form in date_formats:
    		try:
    			iso_date = datetime.datetime.strptime(today, form)
    			return iso_date
    		except ValueError:
    			pass
    	else:
    		print("entry not valid")
    		return None
    
    def lang_format(diff=1):	
    	'''lang_format (int -> datetime object)
    	add the integer given to today's date and return 
    	ex. today = 2000-12-11, int = 3 -> 2000-12-14'''
    
    	future = datetime.datetime.toordinal(local)
    	tomorrow = future + diff
    	tomorrow = datetime.date.fromordinal(tomorrow)
    	return tomorrow
    
    def days_format(today, days):
    	'''days_format (string, list -> datetime object)
    	take the literal day as input and calculate the date that it falls on.
    	ex. today is thursday, nov. 11
    	string = friday -> nov. 12'''
    
    	now = datetime.datetime.today().strftime("%A").lower()
    	days = days * 2
    	diff = days[days.index(now):].index(today)
    	if diff == 0: #diff == 0 if the entered day is the same as today, add 7 to calculate the date that the day falls on next
    		diff = 7
    	return lang_format(diff)
    
    def main():
    	task_date = get_task()
    	future = parse_date(task_date[1])
    	print("{} due {}".format(task_date[0], future))
    
    if __name__ == "__main__":
    	main()
    understands 'tomorrow', 'the day after tomorrow', 'in xx days', any day of the week

    *fixed bug: if 'tomorrow', 'the day after tomorrow', 'in xx days', any day of the week carries over into the next month, it will crash. haven't handled it yet.

    oh the code is commented, it might make it a bit harder to read here since there's no syntax highlighting.
    Last edited by mo.reina; December 7th, 2010 at 10:47 AM.

  7. #7
    Join Date
    May 2006
    Beans
    1,790

    Re: Beginner's Programming Challenge 17

    Quote Originally Posted by mo.reina View Post
    nowhere near as short or as concise as what's above but....
    Code:
    import datetime
    
    def from_abs_date(given_date):
        '''from_abs_date( given_date ) -> absolute date
        will take an absolute date, e.g. 2000 nov 21 and return an absolute date in the format of DD-month_abbreviation-YYYY, e.g. 21 nov 2000'''
    
        try:
            return_date = datetime.datetime.strptime(given_date, "%d %b %Y")
        except ValueError:
            try:
                return_date = datetime.datetime.strptime(given_date, "%d %b %y")
            except ValueError:
                try:
                    return_date = datetime.datetime.strptime(given_date, "%Y %b %d")
                except ValueError:
                    try:
                        return_date = datetime.datetime.strptime(given_date, "%y %b %d")
                    except ValueError:
                        print("not a valid entry")
        return return_date.strftime("%d %b %Y")
    
    def from_date(given_date, days):
        '''from_date( day, list-of-days ) -> absolute date.
        will take a day of the week, e.g. 'friday', and give the absolute date of that day, e.g. the date of the next friday.'''
        
        today = datetime.datetime.today().strftime("%A").lower() # this is the current day today
        given_date = given_date.lower() # user given day
        for difference, day in enumerate(days[days.index(today):]): # checks the difference in days between today and the user given day
            if day == given_date:
                future = str(int(datetime.datetime.today().strftime("%d")) + difference)
                break
        future = future + datetime.datetime.today().strftime(" %b %Y")
        return from_abs_date(future)
    
    def from_string(days, offset):
        '''from_string( list-of-days, offset ) -> absolute date.
        tomorrow = offset of 1
        the day after tomorrow = offset of 2
        in x days = offset of x'''
        today = datetime.datetime.today().strftime("%A").lower()
        future = days[days.index(today) + offset: days.index(today) + offset + 1][0]
        return from_date(future, days)
    
    def main():
        
        days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
        days = days * 2
    
        task, given_date = input('please enter the task title and the due date: ').split('due')
        given_date = given_date.lstrip()
    
        try:
            int(given_date.split()[0])
            return_date = from_abs_date(given_date)
    
        except ValueError:
            if given_date.split()[0] in days:
                return_date = (from_date(given_date, days))
            else:
                if given_date.lower() == 'tomorrow':
                    return_date = from_string(days, 1)
                elif given_date.lower() == 'the day after tomorrow':
                    return_date = from_string(days, 2)
                else:
                    try:
                        int(given_date.split()[1])
                        return_date = from_string(days, int(given_date.split()[1]))
                    except ValueError:
                        print("i'm all out of ideas")
    
        answer = [return_date, task]
        print(answer)
    
    if __name__ == "__main__":
        main()
    understands 'tomorrow', 'the day after tomorrow', 'in xx days', any day of the week

    bug: if 'tomorrow', 'the day after tomorrow', 'in xx days', any day of the week carries over into the next month, it will crash. haven't handled it yet.

    oh the code is commented, it might make it a bit harder to read here since there's no syntax highlighting.
    The from_abs_date function can be cleaned up somewhat, which will make it easier to extend:

    Code:
    def from_abs_date(given_date):
        '''from_abs_date( given_date ) -> absolute date
        will take an absolute date, e.g. 2000 nov 21 and return an absolute date in the format of DD-month_abbreviation-YYYY, e.g. 21 nov 2000'''
    
        formats = ["%d %b %Y", "%d %b %y", "%Y %b %d", "%y %b %d"]
    
        for format in formats:
            try:
                return_date = datetime.datetime.strptime(given_date, format)
                return return_date.strftime("%d %b %Y")
            except ValueError:
                pass
    
        print("not a valid entry")
        return
    Admittedly it doesn't do exactly the same thing when no format works, but that can be fixed.

  8. #8

    Re: Beginner's Programming Challenge 17

    Quote Originally Posted by Arndt View Post
    The from_abs_date function can be cleaned up somewhat, which will make it easier to extend:

    Code:
    def from_abs_date(given_date):
        '''from_abs_date( given_date ) -> absolute date
        will take an absolute date, e.g. 2000 nov 21 and return an absolute date in the format of DD-month_abbreviation-YYYY, e.g. 21 nov 2000'''
    
        formats = ["%d %b %Y", "%d %b %y", "%Y %b %d", "%y %b %d"]
    
        for format in formats:
            try:
                return_date = datetime.datetime.strptime(given_date, format)
                return return_date.strftime("%d %b %Y")
            except ValueError:
                pass
    
        print("not a valid entry")
        return
    Admittedly it doesn't do exactly the same thing when no format works, but that can be fixed.
    thanks, that makes it much easier to read.

  9. #9
    Join Date
    Nov 2009
    Location
    The Netherlands
    Beans
    239
    Distro
    Ubuntu 12.04 Precise Pangolin

    Re: Beginner's Programming Challenge 17

    I didn't know about the python datetime module, so i have been playing with regular expressions. My solution may not be very efficient but it supports most different input formats up till now. Also, it's easily expandable.
    Here is my (Python) script:
    Code:
    #!/usr/bin/env python
    
    import re, sys, time
    
    days_long = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
    days_short = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
    months_long = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december']
    months_short = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']
    
    taskexpr = re.compile(r'(.*)\s+due\s+(.*)')
    tomorrowexpr = re.compile(r'.*?(((\d+)\s+days\s+after\s+)|(the\s+day\s+after\s+)+)?(tomorrow)')
    inxdaysexpr = re.compile(r'.*?in\s+(\d+)\s+days')
    weekdayexpr = re.compile(r'(' + '|'.join(days_long + days_short) + r')')
    dateexpr = re.compile(r'(\d\d?)\W+(([a-z]+)|(\d\d?))\W+(\d\d(\d\d)?)')
    date2expr = re.compile(r'the (\d\d?)(st|nd|th) of (' + '|'.join(months_long) + r') (\d\d(\d\d)?)')
    
    today_year    = int(time.strftime('%Y'))
    today_month   = int(time.strftime('%m'))
    today_day     = int(time.strftime('%d'))
    today_weekday = int(time.strftime('%w'))
    
    tasks = []
    
    def to_int_time(year, month, day, add_days = 0):
        date = '{0:04d} {1:02d} {2:02d}'.format(year, month, day)
        date = time.mktime(time.strptime(date, '%Y %m %d'))
        date += 86400 * add_days # 86400 seconds in a day
        return date
    
    def parse_tomorrow(match):
        days = 1
        if match.group(4): # the day after
            days += len([i for i in match.group(1).split() if i == 'after']) # just count the number of afters
        elif match.group(2): # n days after
            days += int(match.group(3))
        return to_int_time(today_year, today_month, today_day, days)
    
    def parse_inxdays(match):
        return to_int_time(today_year, today_month, today_day, int(match.group(1)))
    
    def parse_weekday(match):
        day = match.group(1)
        if day in days_long:
            day = days_long.index(day) + 1 # +1 because monday is 1 instead of 0
        if day in days_short:
            day = days_short.index(day) + 1
        day = (day - today_weekday) % 7
        if day == 0: day = 7 # make sure it is always the next xxxday, and not today
        return to_int_time(today_year, today_month, today_day, day)
    
    def parse_date(match):
        day = int(match.group(1))
        year = int(match.group(5))
        if year < 100:
            year += 2000
        if match.group(4):
            month = int(match.group(4))
        elif match.group(3):
            month = match.group(3)
            if month in months_long:
                month = months_long.index(month) + 1 # +1 because january should be 1 instead of 0
            elif month in months_short:
                month = months_short.index(month) + 1
            else:
                #invalid month
                return None
        return to_int_time(year, month, day)
    
    def parse_date2(match):
        day = int(match.group(1))
        month = months_long.index(match.group(3)) + 1
        year = int(match.group(4))
        if year < 100:
            year += 2000
        return to_int_time(year, month, day)
    
    def parse(date):
        match = tomorrowexpr.match(date)
        if match:
            return parse_tomorrow(match)
    
        match = inxdaysexpr.match(date)
        if match:
            return parse_inxdays(match)
    
        match = weekdayexpr.match(date)
        if match:
            return parse_weekday(match)
    
        match = dateexpr.match(date)
        if match:
            return parse_date(match)
    
        match = date2expr.match(date)
        if match:
            return parse_date2(match)
    
        # everything failed
        return None
    
    while True:
        input = sys.stdin.readline()
        if not input:
            break
        match = taskexpr.match(input)
        if not match:
            # print warning
            continue
        title = match.group(1)
        date = parse(match.group(2).strip().lower())
        tasks.append((date, title))
    
    tasks = [i for i in tasks if i[0] != None]
    tasks.sort()
    
    sys.stdout.write('Today is {0:s}, your tasks:\n'.format(time.strftime('%d %B %Y')))
    
    for t in tasks:
        sys.stdout.write('{0:s} due {1:s}\n'.format(t[1], time.strftime('%d %B %Y', time.localtime(t[0]))))
    and my test input:
    Code:
    t1 due tomorrow
    t2 due tuesday
    t3 due in 2 days
    t4 due 30 nov 2010
    t5 due the 14th of january 2011
    t6 due the day after the day after tomorrow
    t7 due 7 days after tomorrow
    t8 due wednesday
    t9 due 12/06/2014
    t10 due the day after the day after the day after tomorrow
    t11 due 16 february 2012
    t12 due 15-jun-2011
    I also let my program sort the tasks by their due time.

    EDIT 1:
    I just noticed that i have the same bug as mo.reina when the days go over the end of the month, working on that now.

    EDIT 2:
    fixed it.
    Last edited by ziekfiguur; November 15th, 2010 at 05:39 PM. Reason: bug fixed

  10. #10
    Join Date
    Jun 2008
    Beans
    199
    Distro
    Ubuntu Development Release

    Re: Beginner's Programming Challenge 17

    Just a reminder that this contest is still going on.

    Also, I'll probably judge entries after New Year's, so if you're working on an entry now, try to have it in before them.

    Great job for the people who already submitted entries, and good luck to all those still working!

Page 1 of 2 12 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •