
def rec_seq_downup( N ):
    if N < 0:
        return
    print( N, end = ' ' )
    rec_seq_downup( N-1 )
    print( N, end = ' ' )

def rec_binary_in( N ): # N == 4
    if N < 0:
        return
    rec_binary_in( N-1 ) # N == 3
    print( N, end = ' ' )
    rec_binary_in( N-1 ) # N == 3

def rec_binary_pre( N ):  # N == 4
    if N < 0:
        return
    print( N, end = ' ' )
    rec_binary_pre( N-1 )
    rec_binary_pre( N-1 )

def rec_binary_post( N ):  # N == 4
    if N < 0:
        return
    rec_binary_post( N-1 )
    rec_binary_post( N-1 )
    print( N, end = ' ' )

def rec_binary_tree( N, depth ):  # N == 4
    if N < 0:
        return
    rec_binary_tree( N-1, depth+1 )
    print( " "*3*depth,  N, "." *3*N  )
    rec_binary_tree( N-1, depth+1 )
'''
    _____ 3____
 __ 2__     __ 2__
 1     1    1    1
0 0   0 0  0 0  0 0
'''

def rec_binary_tree2( N, depth ): # N = 5
    if N < 0:
        return
    rec_binary_tree2( N-2, depth+1 )
    print( " "*3*depth,  N )
    rec_binary_tree2( N-1, depth+1 )

def rec_ternary_pre( N ):
    if N < 0:
        return
    print( N, end = ' ' )
    rec_ternary_pre( N-1 )
    rec_ternary_pre( N-1 )
    rec_ternary_pre( N-1 )

def rec_hello( K ):  # K == 4
    if( K == 0 ):
        return
    rec_hello( K-1 )
    rec_hello( K-1 )
    print("Hello!", "  K =", K )

'''
                        ___________________5_____________________________
            _________ 4________                                _________ 4________
      ____ 3_____         _____3_____                     ____ 3_____        _____3_____
  __ 2___     __2__    __ 2__     __2__               __ 2___     __2__   __ 2__     __2__
 _1_   _1_  _1_  _1_  1     1    1    1               1     1    1    1  1     1    1    1
0   0  0 0  0 0  0 0
'''

def rec_hello_count( K ): # K == 1
    if( K == 0 ):
        return 1  # alternate between 0 and 1
    calls1 = rec_hello_count( K-1 )  # K == 0, immediate return from recursion
    calls2 = rec_hello_count( K-1 )  # K == 0
    print("Hello!")
    return calls1 + calls2 + 1

'''
All substrings of "abcd"
A substring, in this case, is not necessarily a contiguous one

Basic recursive idea:
 "abcd" == "a" + "bcd"
       1. all substrings of "bcd":
            ["", "b", "c", "d",  "bc", "cd", "bcd"]
       2. prepend "a" to all substrings of "bcd":
            ["a", "ab", "ac", "ad",  "abc", "acd", "abcd"]
       3. join 1. and 2.
'''

def rec_allSubStrings( aString ):

    if len( aString ) == 1:
        return  [ "", aString[0:1] ]

    withoutFirst = rec_allSubStrings(aString[1:])   #  1.
    withFirst = [ aString[0] + elem for elem in withoutFirst ]  #  2.

    all = withoutFirst + withFirst   # 3.

    return all


def rec_allSums( values ):

    if len( values ) == 1:
        return  [ 0 , values[0] ]

    withoutFirst = rec_allSums( values[1:] )
    withFirst = [ values[0] + elem for elem in withoutFirst ]

    all = withoutFirst + withFirst  # join two lists

    return all


def rec_allSubsets(aSet):
    if len(aSet) == 0:
        return  [ [] ]
    withoutFirst = rec_allSubsets(aSet[1:])
    withFirst = [ ( [aSet[0]] + subset) for subset in withoutFirst]
    all = withoutFirst + withFirst
    return all
# --------------------------------------------------------
#           M  A  I  N
# --------------------------------------------------------

#'''
rec_seq_downup( 4 )
print()

rec_binary_in( 2 )
print()

print("big print 1")
rec_binary_in( 8 )
print()

print("big print 2")
rec_binary_in( 13 )
print()

print("rec_binary_pre")
rec_binary_pre( 4 )
print()

print("rec_binary_post")
rec_binary_post( 4 )
print()

print("rec_binary_tree2")
rec_binary_tree( 4, 0 )
print()

print("rec_binary_tree")
rec_binary_tree2( 5, 0 )

#print("rec_ternary_pre")
#rec_ternary_pre( 4 )
#print()

#print("rec_ternary_pre")
#rec_ternary_pre( 10 )
#print()
#'''

rec_hello( 3 )
print("---------------------------------")

calls = rec_hello_count( 3 )
print( calls )
print(".......................................")

astring = "ABCD"
all = rec_allSubStrings( astring  )
print( "all substrings of ", astring )
print( all )
print()

vals = [1, 2,  5, 10, 20, 50]  # coin values
#vals = [1, 20, 300]
allsums =  rec_allSums( vals )
print( allsums )
print()

vals = [1, 2,  5, 10, 20, 50]
allsets = rec_allSubsets( vals )
print( allsets )
print()

all2 = [ (sum(set), set) for set in allsets]
print( all2 )
print()

all2.sort(key=lambda tup: tup[0])
for item in all2:
    print( item )
print()



