# 1. 삼각수(재귀함수)
def trinum(n):
    if n >= 1:
        return trinum(n-1) + n
    else:
        return 0

# print(trinum(1)) # 1
# print(trinum(3)) # 6
# print(trinum(6)) # 21
# print(trinum(11)) # 66
# print(trinum(0)) # 0
# print(trinum(-3)) # 0

# 삼각수(꼬리재귀함수)
def trinumT(n):
    def loop(n,r):
        if n>0:
            return loop(n-1, r+n)
        else:
            return r
    return loop(n, 0)

# print(trinumT(1)) # 1
# print(trinumT(3)) # 6
# print(trinumT(6)) # 21
# print(trinumT(11)) # 66
# print(trinumT(0)) # 0
# print(trinumT(-3)) # 0

# 삼각수(while 문 함수)
def trinumW(n):
    res = 0
    while n>0:
        res += n
        n-=1
    return res

# print(trinumW(1)) # 1
# print(trinumW(3)) # 6
# print(trinumW(6)) # 21
# print(trinumW(11)) # 66
# print(trinumW(0)) # 0
# print(trinumW(-3)) # 0

# 2. Palindrome
def is_pal(s):
    return len(s) <= 1 or (s[0]==s[-1] and is_pal(s[1:-1]))

# print(is_pal("")) # True
# print(is_pal("a")) # True
# print(is_pal("aa")) # True
# print(is_pal("aba")) # True
# print(is_pal("abba")) # True
# print(is_pal("aaba")) # False
# print(is_pal("abcba")) # True
# print(is_pal("여보 안경 안 보여")) # False
# print(is_pal("여보안경안보여")) # True

# 3-A
def is_leap_year(year):
    return year % 400 == 0 or year % 4 == 0 and year % 100 != 0

def is_valid_date(year,month,day):
    return year > 0 and 1 <= month <= 12 and \
           (month in [1,3,5,7,8,10,12] and 1 <= day <= 31 or
            month in [4,6,9,11] and 1 <= day <= 30 or
            is_leap_year(year) and 1 <= day <= 29 or
            1 <= day <= 28)

def get_valid_date_6():
    s = input('Type 6 digits: ')
    if len(s) > 6: return None

    year = int(s[0:2])
    if year < 17:
        year += 2000
    else:
        year += 1900
    month = int(s[2:4])
    day = int(s[4:])

    if is_valid_date(year,month,day):
        return (year,month,day)
    else:
        return None

print(get_valid_date_6())

# 160425 # => (2016, 4, 25)
# 160431 # => None
# 160229 # => (2016, 2, 29)
# 170229 # => None
# 450815 # => (1945, 8, 15)

# 3-B
def next_month(year, month):
    if month == 12:
        year += 1
        month = 1
    else:
        month += 1
    return (year, month)

def days_in_month(year, month):
    if month in [1,3,5,7,8,10,12]:
        return 31
    elif month in [4,6,9,11]:
        return 30
    elif month in [2]:
        if is_leap_year(year):
            return 29
        else:
            return 28
    else:
        return 0

def date_plus(year, month, day, days):
    days_left = days_in_month(year,month) - day
    if days <= days_left:
        return (year, month, day+days)
    else:
        day = days - days_left
        year, month = next_month(year, month)

        while days_in_month(year, month) < day:
            day -= days_in_month(year, month)
            year, month = next_month(year, month)

        return (year, month, day)

# print(date_plus(2017,4,20,2)) # => (2017, 4, 22)
# print(date_plus(2017,4,20,7)) # => (2017, 4, 27)
# print(date_plus(2017,4,20,10)) # => (2017, 4, 30)
# print(date_plus(2017,4,20,11)) # => (2017, 5, 1)
# print(date_plus(2017,4,20,50)) # => (2017, 6, 9)
# print(date_plus(2017,4,20,100)) # => (2017, 7, 29)
# print(date_plus(2017,4,20,200)) # => (2017, 11, 6)
# print(date_plus(2017,4,20,300)) # => (2018, 2, 14)
# print(date_plus(2017,4,20,1000)) # => (2020, 1, 15)


# 4 문자열에서 특정 문자 모두 없애기
# 재귀함수
def remove(x,xs):
    if len(xs)>0:
        if xs[0]==x:
            return remove(x, xs[1:])
        else:
            return xs[0]+remove(x, xs[1:])
    else:
        return xs

# print(remove('a','abracadabra'))
# print(remove('z','abracadabra'))

# 꼬리재귀함수
def removeT(x,xs):
    def loop(xs, s):
        if len(xs)<=0:
            return s
        else:
            if xs[0]!=x:
                return loop(xs[1:], s+xs[0])
            else:
                return loop(xs[1:], s)
    return loop(xs, "")

# print(removeT('a','abracadabra'))
# print(removeT('z','abracadabra'))

# while 문 함수
def removeW(x,xs):
    i = 0
    l = len(xs)
    res=""
    while i < l:
        if xs[i] != x: res+=xs[i]
        i+=1
    return res

# print(removeW('a','abracadabra'))
# print(removeW('z','abracadabra'))

# 5. 순열
# recur
def permutation0(n,k):
    def loop(n,k):
        if k > 0:
            return n * loop(n-1,k-1)
        else:
            return 1
    if n < k:
        return 0
    else:
        return loop(n,k)

# tailRecur
def permutation1(n,k):
    def loop(n,k,p):
        if k > 0:
            return loop(n-1,k-1,p*n)
        else:
            return p
    if n < k:
        return 0
    else:
        return loop(n,k,1)

# while
def permutation2(n,k):
    if k>0:
        res=1; i=0
        while i<k:
            res *= n-i
            i+=1
        return res
    else:
        return 1

# for
def permutation3(n,k):
    if k > 0:
        res=1
        for i in range(k):
            res *= n-i
        return res
    else:
        return 1
# print(permutation3(1,1)) # => 1
# print(permutation3(2,1)) # => 2
# print(permutation3(2,2)) # => 2
# print(permutation3(3,1)) # => 3
# print(permutation3(4,3)) # => 24
# print(permutation3(4,4)) # => 24

def sublist(s, l, r):
    if l<0 or r<0:
        return []
    return s[l:r]

### A ###
# def drop_before(s,index):
#     while s != [] and index > 0:
#         s = s[1:]
#         index -= 1
#     return s

def drop_before(s,index):
    # 예시 코드
    # if s != [] and index > 0:
    #     return drop_before(s[1:],index-1)
    # else:
    #     return s
    res=[]
    if index<0: index=0
    while index<len(s):
        res.append(s[index])
        index+=1

    return res

# s = [1,2,3,4,5]
# print("s = [1,2,3,4,5]")
# print("drop_before(s,0) =", drop_before(s,0)) # => [1,2,3,4,5]
# print("drop_before(s,1) =", drop_before(s,1)) # => [2,3,4,5]
# print("drop_before(s,-3) =", drop_before(s,-3)) # => [1,2,3,4,5]
# print("drop_before([],4) =", drop_before([],4)) # => []


### B ###
# recur
# def take_before(s,index):
#     if s == [] or index>=len(s):
#         return s
#     else:
#         return take_before(s[:index], index+1)

# def take_before(s,index):
#     if s != [] and index < len(s):
#         return take_before(s[:index], index+1)
#     else:
#         return s


# def take_before(s,index):
#     if s != [] and index > 0:
#         return [s[0]] + take_before(s[1:],index-1)
#     else:
#         return []

# tail recur
def take_before(s,index):
    def loop(s, index, res):
        if s != [] and index > 0:
            res.append(s[0])
            return loop(s[1:], index - 1, res)
        else:
            return res
    return loop(s, index, [])

# while
# def take_before(s,index):
#     if index<=0:
#         return []
#     if index>len(s):
#         return s
#     res=[]; i=0
#     while i<index:
#         res.append(s[i])
#         i+=1
#     return res
#
# s = [1,2,3,4,5]
# print("take_before(s,0) =", take_before(s,0)) # => []
# print("take_before(s,1) =", take_before(s,1)) # => [1]
# print("take_before(s,2) =", take_before(s,2)) # => [1,2]
# print("take_before(s,3) =", take_before(s,3)) # => [1,2,3]
# print("take_before(s,4) =", take_before(s,4)) # => [1,2,3,4]
# print("take_before(s,5) =", take_before(s,5)) # => [1,2,3,4,5]
# print("take_before(s,6) =", take_before(s,6)) # => [1,2,3,4,5]
# print("take_before([],4) =", take_before([],4)) # => []
# print("take_before(s,-3) =", take_before(s,-3)) # => []

### C ###
def sublist(s,low,high):
    if low < 0: low = 0
    if high < 0: high = 0
    if low <= high:
        return take_before(drop_before(s, low), high-low)
        # return drop_before(take_before(s,high), low)
    else:
        return []
# s = [1,2,3,4,5]
# print("s = [1,2,3,4,5]")
# print("sublist(s,0,0) => [] ?", sublist(s,0,0))
# print("sublist(s,0,1) => [1] ?", sublist(s,0,1))
# print("sublist(s,0,2) => [1, 2] ?", sublist(s,0,2))
# print("sublist(s,0,3) => [1, 2, 3] ?", sublist(s,0,3))
# print("sublist(s,0,4) => [1, 2, 3, 4] ?", sublist(s,0,4))
# print("sublist(s,3,6) => [4, 5] ?", sublist(s,3,6))
# print("sublist(s,5,2) => [] ?", sublist(s,5,2))
# print("sublist(s,-3,-2) => [] ?", sublist(s,-3,-2))


# 7
### A ###
def longest_streak1(s):
    contender = leader = s[0]
    streak_length = streak_record = 1
    contender_index = leader_index = 0
    index = 1
    for n in s[1:]:
        if n == contender:
            if streak_length == 1:
                contender_index = index
            streak_length += 1
        else:
            contender = n
            streak_length = 1
        if streak_length > streak_record:
            leader = contender
            streak_record = streak_length
            leader_index = contender_index

        index += 1
    return leader, streak_record, leader_index-1

# def test_longest_streak(s):
#     for n in s:
#         print(n,end="")
#     print()
#     print(longest_streak1(s))

# s0 = "06479019955907200041185008780528384811265678111671"
# test_longest_streak(s0)
# # => ('0', 3, 15)
# s1 = "49715114250863455559013207228395154984882560834674"
# test_longest_streak(s1)
# # => ('5', 4, 15)
# s2 = "79083787262159815638834042282485195270836937488097"
# test_longest_streak(s2)
# # => ('8', 2, 19)
# s3 = "36888653851748777011129000999371447120618209984726"
# test_longest_streak(s3)
# # => ('8', 3, 2)


### B ###
def longest_streak2(s):
    res = []
    contender = leader = s[0]
    streak_length = streak_record = 1
    contender_index = leader_index = 0
    index = 1
    for n in s[1:]:
        if n == contender:
            if streak_length == 1:
                contender_index = index
            streak_length += 1
        else:
            contender = n
            streak_length = 1
        if streak_length > streak_record:
            leader = contender
            streak_record = streak_length
            leader_index = contender_index-1
            res = [(leader, streak_record, leader_index)]
        elif streak_length == streak_record:
            res.append((contender, streak_length, contender_index-1))
        index += 1

    return res
# def longest_streak2(s):
#     contender = s[0]
#     streak_length = streak_record = 1
#     i=0
#     for n in s[1:]:
#         if n == contender:
#             streak_length += 1
#         else:
#             contender = n
#             streak_length = 1
#         if streak_length > streak_record:
#             streak_record = streak_length
#         i += 1
# 
#     start = 0
#     i = 0
#     res = []
#     for n in s[1:]:
#         if n == contender:
#             if streak_length == 1:
#                 start = i
#             streak_length += 1
#         else:
#             contender = n
#             streak_length = 1
#         if streak_length == streak_record:
#             res.append((contender, streak_length, start))
#         i += 1
# 
#     return res


def test_longest_streak(s):
    for n in s:
        print(n,end="")
    print()
    print(longest_streak2(s))

# s0 = "06479019955907200041185008780528384811265678111671"
# test_longest_streak(s0)
# # => [('0', 3, 15), ('1', 3, 44)]
# s1 = "49715114250863455559013207228395154984882560834674"
# test_longest_streak(s1)
# # => [('5', 4, 15)]
# s2 = "79083787262159815638834042282485195270836937488097"
# test_longest_streak(s2)
# # => [('8', 2, 19), ('2', 2, 25), ('8', 2, 45)]
# s3 = "36888653851748777011129000999371447120618209984726"
# test_longest_streak(s3)
# # => [('8', 3, 2), ('7', 3, 14), ('1', 3, 18), ('0', 3, 23), ('9', 3, 26)]
