True and False

True or False and False

False and False

print((True or False) and False)
print(True or (False and False))

print(not False)
print(not True)

"""
Explanation: Examples of Boolean operators
Think about: 

What operators exist
What these operators can be used on
The precedence of these operators
End of explanation
"""


def factorial(number):
    """
    Return the factorial of a passed number.
    e.g. if 5 is passed return: 5 * 4 * 3 * 2 * 1
    """
    if number == 0:
        return 1
    
    return number * factorial(number -1)


import math

print(factorial(5))
print(math.factorial(5))

"""
Explanation: Thinking about how results work
Look at truth tables to understand how values can be combined for these binary operators: https://en.wikipedia.org/wiki/Truth_table#Logical_conjunction_.28AND.29
Also understand the not unary operator: 
https://en.wikipedia.org/wiki/Truth_table#Logical_negation
End of explanation
"""


import random 


def dealer_will_hit(cards_value):
    """Returns true if the dealer must take a hit"""
    if cards_value <= 16:
        return True
    
    return False


def should_i_hit(dealer_showing_value, my_cards_value):
    """Returns true if you should takea  hit"""        
    # Hit because you've got the space
    if my_cards_value <= 11:
        return True
    
    if my_cards_value >= 17 and my_cards_value <= 19:
        
        # Assume the dealer will bust
        if dealer_showing_value < 5:
            return False
        
        # Assume the dealer will beat you if you don't hit
        elif dealer_showing_value >= 7:
            return True
    
    # In all other cases see how it works out.
    return False

def get_card():
    card_values = [1,2,3,4,5,6,7,8,9,10,10,10,10]
    return random.choice(card_values)

def print_who_won(dealer_cards_value, my_cards_value):
    if my_cards_value > 21:
        print("Dealer won I busted")
        
    elif dealer_cards_value > 21:
        print("I won because dealer busted")
        
    elif dealer_cards_value > my_cards_value:
        print("Dealer won with higher value cards")
        
    elif my_cards_value > dealer_cards_value:
        print("I won with higher value cards")
    
    else:
        print("We tied! No one loses.")


# Setup the game
dealer_showing_card = get_card()
dealer_card_values = dealer_showing_card + get_card()

player_cards_value = get_card() + get_card()


# Check to see if the player should hit
# Only going to hit once
if should_i_hit(dealer_showing_card, player_cards_value):
    player_cards_value += get_card()

# Same the dealer will only hit once
if dealer_will_hit(dealer_card_values):
    dealer_card_values += get_card()
    
print("Dealer ended with: ", dealer_card_values)
print("I ended with: ", player_cards_value)
print_who_won(dealer_card_values, player_cards_value)


def no_return():
    print('hi')

def has_return():
    return 'hi'

print(has_return() + ' Hello')

print(type(no_return()))
print(no_return() + ' Hello')



x = 8
if x < 15:
    print('less than 15')
    
    if x < 13:
        print('less than 13')
        
        if x < 9:
            print('less than 9')
    
    print('always printed if less than 15')
else:
    print('bye')

print('super default')

print('   hi')
print('\t\t\thi')

"""
Explanation: Black Jack
Here is a simple implementation of some black jack related functions.
End of explanation
"""


temp = [0, 1, 5, 3, 10]
some_number = 11

def contains_n(list_of_numbers, test_number):
    """
    Tests if the passed `test_number` is equal
    to a value inside `list_of_numbers`
    """
    for number in list_of_numbers:
        # executions
        #
        # number = 0 
        # number = 1
        # number = 5
        # number = 3
        # number = 10
        if number == test_number:
            return True
        
    return False

def contains_type_and_value_n(numbers, n):
    """
    Tests if the passed `test_number` is equal
    to a value inside `list_of_numbers` as well
    as the value's type.
    """
    for num in numbers:
        if num == n and type(num) == type(n):
            return True
    return False

def contains_number_of_n(numbers, n):
    count = 0
    for num in numbers:
        if num == n:
            count += 1
    return count

def contains_number_of_type_n(numbers, n):
    count = 0
    for num in numbers:
        if num == n and type(num) == type(n):
            count += 1
    return count
        
print(contains_n([5, 7, 9, 10], 6))

print(contains_type_and_value_n([5, 6.2, 5.8, 9], 5))

print(contains_number_of_n([5, 7, 9, 10, 9], 9))

print(contains_number_of_type_n([5, 7, 9, 10.0, 9], 10))

print(type(10))
print(type(10.0000))

def contains(numbers, n):
    return n in numbers

def count(numbers, n):
    return numbers.count(n)

numbers = [2, 3.0, 3, 5.0, 6.666, 4]
value = 4.0
value2 = 5.0

print(
    contains(numbers, value),
    contains(numbers, value),
    '\n',
    contains(numbers, value2),
    contains(numbers, value2)
)

# in operator: https://docs.python.org/3.4/reference/expressions.html#in

"""
Explanation: Studio: contains_n
End of explanation
"""


