# Gan Ming Liang
# TP063338

# Amadea Lim Yi Wen (teammate)
# TP064038

# Program name: AEGIS (Asian Event General Interface Solution)

import datetime # import datetme from python library for later use

def homepage():
    print("=== Welcome to Asian Event Management Service (AEMS) ===")
    print("Please select your position:")
    print("1. Admin")
    print("2. Customer")
    print("3. Exit")
    option = int(input("Please select an option: "))
    if option == 1:
        adminHome()
    elif option == 2:
        guestOption()
    elif option == 3:
        exitPage()
    else:
        print("Please select a valid option")
        homepage()

def guestOption():
    print("\n>>> What would you like to do? \n")
    print("1. View Category")
    print("2. View Event")
    print("3. Log in as a Member")
    print("4. Register as a Member")
    print("5. Exit")
    choice = int(input("Your choice: "))
    if choice == 1:
        guestViewCategory()
    elif choice == 2:
        guestViewEvent()
    elif choice == 3:
        memberLogin()
    elif choice == 4:
        memberSignup()
    elif choice == 5:
        exitPage()
    else:
        print("option not supported, please try again")
        guestOption()

def adminHome():
    print("=== Please select an option below: ===")
    print("1. Admin Login")
    print("2. Admin Registration")
    print("3. Go Back")
    option = int(input("Your choice: "))
    if option == 1:
        adminLogin()
    elif option == 2:
        adminAuth()
    elif option == 3:
        homepage()
    else:
        print("Please select a valid option")
        adminHome()

def adminAuth():
    code = input("Please enter company referral code: ")
    if code != "AEMS0001":
        print("Incorrect referral code.")
        print("do you want to (1) Try Again, or (2) Go Back ?")
        choice = int(input("Your choice: "))
        if choice == 1:
            adminAuth()
        elif choice == 2:
            adminHome()
        else:
            print("option not supported, returning to homepage...")
            homepage()
    else:
        print("Verification successful!")
        adminSignup()

def adminSignup():
    adminHandler = open("adminList.txt", "r")
    print(">>> Welcome to AEMS admin registration page, please follow the instruction below <<<")
    username = input("Enter a username: ")
    password1 = input("Enter a password: ")
    password2 = input("Confirm your password: ")

    # database
    adminUN = []
    adminPW = []
    for i in adminHandler:
        a,b = i.split(", ")
        b = b.strip()
        adminUN.append(a)
        adminPW.append(b)

    if password1 != password2:
        print("Password does not match, please try again")
        adminSignup()
    elif len(password1) <= 8:
        print("Password must be longer than 8 characters, please try again")
        adminSignup()
    elif username in adminUN:
        print("Username already taken, please try again")
        adminSignup()
    else:
        db = open("adminList.txt", "a")
        db.write(username+", "+password1+"\n")
        print("Registration Successful!")
        db.close()
    adminHandler.close()
    adminHome()

def adminLogin():
    tempList = []
    adminHandler = open("adminList.txt", "r")
    while True:
        print(">>> Admin Login Page <<<")
        adminUN = input("Enter your username: ")
        adminPW = input("Enter your password: ")
        for i in adminHandler:
            tempList.append(i)
        if adminUN + ", " + adminPW + "\n" in tempList:
            print("Login successful!")
            print("Welcome back,", adminUN.capitalize())
            adminOption()
        else:
            print("\n >>> invalid credentials... \n")
            option = input("would you like to sign-up? \n [Y] for admin registration \n [N] to retry login \n Your choice: " )
            if option == "N":
                continue #repeat while loop
            elif option == "Y":
                adminAuth()
            else:
                print("invalid option, returning to homepage...")
                homepage()
        break
    adminHandler.close()

def adminOption():
    print("\n What would you like to do? \n")
    print("1. Add event")
    print("2. Modify event records")
    print("3. Display record details")
    print("4. Search specific record")
    print("5. Exit")
    choice = int(input("Your choice: "))
    if choice == 1:
        addEvent()
    elif choice == 2:
        modifyEvent()
    elif choice == 3:
        print("display options: \n a. Event Category \n b. All Events \n c. Registered Customers \n d. Customer Payment")
        selection = str(input("Enter your option: "))
        if selection == "a":
            adminViewCategory()
        elif selection == "b":
            adminViewEvent()
        elif selection == "c":
            adminViewCustomerList()
        elif selection == "d":
            adminViewCustomerPayment()
        else:
            print("option not supported, try again")
            adminOption()
    elif choice == 4:
        print("Please select a search option: \n a. Search Customer \n b. Search Customer's payment")
        option = str(input("Enter your option: "))
        if option == "a":
            adminSearchCustomerInfo()
        elif option == "b":
            adminSearchCustomerPayment()
        else:
            print("option not supported, try again")
            adminOption()
    elif choice == 5:
        exitPage()
    else:
        print("option not supported, try again")
        adminOption()

def addEvent():
    eventHandler = open("eventList.txt", "r")
    print(">>> Welcome to AEMS event page, please select your category of events to add <<<")
    while True: # while loop is used to display the available categories for admin if they decide to add another event later on
        print("Event Category: \n 1. Sports/Martial Arts \n 2. Musical Performance \n 3. Dance/Performing Arts \n 4. Expo/Exhibition \n 5. Competition/Tournament \n 6. Others")
        choice = int(input("Please enter your choice: "))
        if choice == 1:
            eventCat = "Sports & Martial Arts"
            break
        elif choice == 2:
            eventCat = "Musical Performance"
            break
        elif choice == 3:
            eventCat = "Dance & Performing Arts"
            break
        elif choice == 4:
            eventCat = "Expo & Exhibition"
            break
        elif choice == 5:
            eventCat = "Competition & Tournament"
            break
        elif choice == 6:
            newCat = str(input("Enter the name of your category: "))
            eventCat = newCat
            break
        else:
            print("please select a valid option")
            continue

    # to obtain user inputs
    eventName = str(input("Enter event name: "))
    eventOrg = str(input("Enter event organizer: "))
    eventDate = str(input("Enter event start date in this format > [dd/mm/yyyy]: "))
    eventTime = str(input("Enter event start time in 24-hour format [eg: 16:30]: "))
    eventDuration = str(input("Enter event duration [eg: 2 days]: "))
    eventLocation = str(input("Enter the venue of the event: "))

    eventName = eventName.title() # for neatness/presentability purposes
    eventLocation = eventLocation.title() # for neatness/presentability purposes

    while True: # looping while to ask user whether event is free or not
        eventFee = str(input("Is your event free-of-charge? [Y/N]: "))
        if eventFee == "Y":
            eventPrice = "0.00"
            break
        elif eventFee == "N":
            eventPrice = str(input("Enter event price (per person) in RM [eg: 2.00]: ")) #string because we will concatenate it later (float will cause error)
            break
        else:
            print("Error: Please insert either [Y] or [N]")
            continue

    # defining empty list
    eCat = []
    eName = []
    eOrg = []
    eDate = []
    eTime = []
    eDura = []
    eLoca = []
    eFee = []

    # appending individual items into a list
    for i in eventHandler:
        a,b,c,d,e,f,g,h = i.split(", ")
        h = h.strip()
        eCat.append(a)
        eName.append(b)
        eOrg.append(c)
        eDate.append(d)
        eTime.append(e)
        eDura.append(f)
        eLoca.append(g)
        eFee.append(h)

    # appending content of each list into the text document
    db = open("eventList.txt", "a")
    db.write(eventCat+", "+eventName+", "+eventOrg+", "+eventDate+", "+eventTime+", "+eventDuration+", "+eventLocation+", "+eventPrice+"\n")
    print("Event added Successfully!")
    db.close()
    eventHandler.close()

    while True: # option to return to homepage or add another event
        print("Do you want to [1] return to admin homepage, [2] add another event?")
        option = int(input("Your choice: "))
        if option == 1:
            print("returned")
            adminOption()
        elif option == 2:
            addEvent()
        else:
            print("please select another option")
            continue
        break

def modifyEvent():
    eventdb = open("eventList.txt", "r")
    counter = 1
    print("Which event would you like to amend?")
    for i in eventdb: # display all available events
        a,b,c,d,e,f,g,h = i.split(", ")
        print(counter,"|", b)
        counter += 1
    eventdb.close()

    selection = int(input("Your choice: ")) # obtain user choice
    selection -= 1 # important: we minus 1 to get the index value (because index starts at 0)

    modifydb = open("eventList.txt", "r")
    modList = modifydb.readlines() # readlines() let us transfer the data from files into a temporary list
    editList = [] # empty string to be used later
    newList = modList # newlist copies modlist (for later use)
    tempIndex = modList[selection] # temp index finds the index of the selected event
    modifydb.close()

    print("\n>>> Current Event Details:") # display the selected events for users to refer to when modifying content(s)
    print(tempIndex)

    while True: # feature to display available categories presets
        print("Select New Event Category: \n 1. Sports/Martial Arts \n 2. Musical Performance \n 3. Dance/Performing Arts \n 4. Expo/Exhibition \n 5. Competition/Tournament \n 6. Others")
        choice = int(input("Please enter your choice: "))
        if choice == 1:
            mod1 = "Sports & Martial Arts"
            break
        elif choice == 2:
            mod1 = "Musical Performance"
            break
        elif choice == 3:
            mod1 = "Dance & Performing Arts"
            break
        elif choice == 4:
            mod1 = "Expo & Exhibition"
            break
        elif choice == 5:
            mod1 = "Competition & Tournament"
            break
        elif choice == 6:
            modCat = input("Enter the name of your category: ")
            mod1 = modCat
            break
        else:
            print("option not supported, try again")
            continue

    # obtain new details for the modified events
    mod2 = input("New event name: ")
    mod3 = input("New event organizer: ")
    mod4 = input("New event start date [eg: dd/mm/yyyy]: ")
    mod5 = input("New event start time [eg: 16:30]: ")
    mod6 = input("New event duration [eg: 2 days]: ")
    mod7 = input("New venue of the event: ")
    mod8 = input("New event price: ")

    # replace all changes in empty list
    editList.append(mod1)
    editList.append(mod2)
    editList.append(mod3)
    editList.append(mod4)
    editList.append(mod5)
    editList.append(mod6)
    editList.append(mod7)
    editList.append(mod8+"\n")
    finalEdit = ', '.join(editList) #join function to combine all strings into one string

    # delete the old event at the specific index and replace it with a new event at the same index (modification)
    del newList[selection]
    newList.insert(selection, finalEdit)

    # save changes into the .txt file
    db = open("eventList.txt", "w")
    for x in newList:
        db.write(x)
    db.close()
    print("Modification Successful!")
    adminOption()

def adminViewCategory():
    eventdb = open("eventList.txt", "r")
    # category counters are declared here
    counterCat1 = 0
    counterCat2 = 0
    counterCat3 = 0
    counterCat4 = 0
    counterCat5 = 0
    counterCat6 = 0
    for i in eventdb: # counter that display the total event in each cateogory
        a,b,c,d,e,f,g,h = i.split(", ")
        if "Sports & Martial Arts" in a:
            counterCat1 += 1
        elif "Musical Performance" in a:
            counterCat2 += 1
        elif "Dance & Performing Arts" in a:
            counterCat3 += 1
        elif "Expo & Exhibition" in a:
            counterCat4 += 1
        elif "Competition & Tournament" in a:
            counterCat5 += 1
        else:
            counterCat6 += 1

    print("Here are all the available Categories:")
    print("\n 1. Sports & Martial Arts\n", "Number of event in this Cat =", counterCat1)
    print("\n 2. Musical Performance\n", "Number of event in this Cat =", counterCat2)
    print("\n 3. Dance & Performing Arts\n", "Number of event in this Cat =", counterCat3)
    print("\n 4. Expo & Exhibition\n", "Number of event in this Cat =", counterCat4)
    print("\n 5. Competition & Tournament\n", "Number of event in this Cat =", counterCat5)
    print("\n 6. Others\n", "Number of event in this Cat =", counterCat6)
    eventdb.close()
    adminOption()

def adminViewEvent():
    eventdb = open("eventList.txt", "r")
    counter = 1
    print("here are all the event & their details:")
    for i in eventdb: # a clean ui that presents all available event in the eventList.txt file
        a,b,c,d,e,f,g,h = i.split(", ")
        print(counter,"|", b, "\nCategory:", a, "\nOrganizer:", c, "\nDate:", d, "\nTime:", e, "\nDuration:", f, "\nVenue:", g, "\nPrice (RM):", h, "\n")
        counter += 1
    eventdb.close()
    adminOption()

def adminViewCustomerList():
    memberdb = open("memberList.txt", "r")
    counter = 1
    print("here are all the members:")
    for i in memberdb:
        a,b = i.split(", ")
        print(counter,"|", a)
        counter += 1
    memberdb.close()
    adminOption()

def adminViewCustomerPayment():
    paymentdb = open("cartList.txt", "r")
    counter = 1
    print("here are all the payment details:")
    for i in paymentdb:
        a,b,c = i.split(", ")
        print(counter,"|", "\nMember Name:", a, "\nEvent Registered:", b, "\nPayment details:", c)
        counter += 1
    paymentdb.close()
    adminOption()

def adminSearchCustomerInfo():
    search = input("Enter customer username to search: ")
    searchdb = open("memberList.txt", "r")
    searchList = searchdb.readlines()
    flag = False
    searchdb.close()
    for i in range(0, len(searchList)): # looping algorithm to find the sequence where memberName is present
        searchTemp = searchList[i].split(", ")
        if search in searchTemp:
            flag = True
        else:
            pass

    if flag:
        print(search, "is a member of Asian Event Management Service")
    else:
        print(search, "is NOT a member of Asian Event Management Service")
    adminOption()

def adminSearchCustomerPayment():
    search = input("Enter customer username to search payment details: ")
    search = search.capitalize() # all usernames are saved with capitalize in events by default
    checkIndexList = []
    a = '1' # these are used as positive flags
    b = '0' # these are used as negative flags
    print("\n=== Here are the payment details for", search, "===")
    checkdb = open("cartList.txt", "r")
    checkList = checkdb.readlines()
    checkdb.close()
    for i in range(0, len(checkList)): # looping algorithm to find the sequence where memberName is present
        tempCheck = checkList[i].split(", ")
        if search in tempCheck:
            checkIndexList.append(a)
        else:
            checkIndexList.append(b)
    for i in range(0, len(checkIndexList)):
        if '1' in checkIndexList:
            x = checkIndexList.index('1')
            print(checkList[x].replace('\n',''))
            checkIndexList[x] = '0'
        else:
            pass
    adminOption()

def guestViewEvent():
    eventdb = open("eventList.txt", "r")
    counter = 1
    print("\nhere are all the event & their details: \n")
    for i in eventdb:
        a,b,c,d,e,f,g,h = i.split(", ")
        print(counter,"|", b, "\nCategory:", a, "\nOrganizer:", c, "\nDate:", d, "\nTime:", e, "\nDuration:", f, "\nVenue:", g, "\nPrice (RM):", h, "\n")
        counter += 1
    eventdb.close()
    back = input("press <enter> to return")
    if back == "":
        guestOption()
    else:
        guestOption()

def guestViewCategory():
    print("\nhere are the available event categories: \n")
    print("1. Sports & Martial Arts")
    print("2. Musical Performance")
    print("3. Dance & Performing Arts")
    print("4. Expo & Exhibition")
    print("5. Competition & Tournament")
    print("6. Others\n")
    back = input("press <enter> to return")
    if back == "":
        guestOption()
    else:
        guestOption()

def memberSignup():
    memberHandler = open("memberList.txt", "r")
    print(">>> Welcome to AEMS member registration page, please follow the instruction below <<<")
    username = input("Enter a username: ")
    password1 = input("Enter a password: ")
    password2 = input("Confirm your password: ")

    # database
    memberUN = []
    memberPW = []
    for i in memberHandler:
        a,b = i.split(", ")
        b = b.strip()
        memberUN.append(a)
        memberPW.append(b)

    if password1 != password2:
        print("Password does not match, please try again")
        memberSignup()
    elif len(password1) <= 8:
        print("Password must be longer than 8 characters, please try again")
        memberSignup()
    elif username in memberUN:
        print("Username already taken, please try again")
        memberSignup()
    else:
        db = open("memberList.txt", "a")
        db.write(username+", "+password1+"\n")
        print("Registration Successful!")
        db.close()
    memberHandler.close()
    guestOption()

def memberLogin():
    dt_today = str(datetime.datetime.today())
    tempList = []
    memberHandler = open("memberList.txt", "r")
    while True:
        print(">>> Member Login Page <<<")
        memberUN = input("Enter your username: ")
        memberPW = input("Enter your password: ")
        for i in memberHandler: # search database for users
            tempList.append(i)
        if memberUN + ", " + memberPW + "\n" in tempList:
            print("Login successful!")
            print("Welcome back,", memberUN.capitalize())
            memberName = memberUN.capitalize() # we saved their username as memberName
            cartItems = []
            cartTotal = 0

            while True:
                # option
                print("\nwhat would you like?")
                print("1. Add events to Shopping Cart")
                print("2. View purchased events")
                print("3. Exit")
                answer = int(input("Your Choice: "))

                if answer == 1: #add + payment + write
                    while True:
                        counter = 1
                        print("Which event would you like to add?")
                        eventdb = open("eventList.txt", "r")
                        for i in eventdb:
                            a,b,c,d,e,f,g,h = i.split(", ")
                            print(counter,"|", b)
                            counter += 1
                        eventdb.close()

                        # obtain user choice
                        try:
                            selection = int(input("Your choice: "))
                            if selection in range(0, counter):
                                selection -= 1
                                pass
                            else:
                                print("\n>>> selected value out of bound, try again\n")
                                continue

                        except ValueError:
                            print("\n>>> please insert an integer value\n")
                            continue

                        # open the eventlist to extract that specific event
                        itemdb = open("eventList.txt", "r")
                        itemList = itemdb.readlines()
                        itemIndex = itemList[selection].split(", ")
                        addItem = itemIndex[1]
                        itemPrice = itemIndex[7].replace('\n','') # prevents double spacing
                        itemPrice = float(itemPrice)
                        itemdb.close()

                        cartItems.append(addItem)
                        cartTotal += itemPrice
                        choose = input("do you want to add more items? <Y/N>")
                        if choose == "Y":
                            continue
                        elif choose == "N":
                            print("proceeding to payment...")
                            break
                        else:
                            print("option not supported, proceeding to payment")
                            break # add cart

                    while True:
                        print("total amount dued: ", cartTotal)
                        try:
                            payment = float(input("please enter your payment amount: "))
                            if payment == cartTotal:
                                print("payment successful!")
                                summaryPrice = str(cartTotal)
                                balance = 0.00
                                break
                            elif payment < cartTotal:
                                print("insufficient amount, please try again")
                                continue
                            elif payment > cartTotal:
                                balance = payment - cartTotal
                                print("payment successful! RM", balance, "have been returned to your account")
                                summaryPrice = str(cartTotal)
                                break
                            else:
                                print("please insert a valid number")
                                continue # payment
                        except ValueError:
                            print("\n>>> please insert a valid amount!\n")
                            continue

                    print("\nOrder Summary:")
                    print("You bought:", cartItems)
                    print("Total cost:", cartTotal)
                    print("You paid:", payment)
                    print("Balance returned:", balance)
                    print("order completed! thank you for your support!")
                    print('')
                    eventdb.close()

                    cartdb = open("cartList.txt", "a")
                    for i in cartItems:
                        cartdb.write(memberName+", "+i+", "+"paid on "+dt_today+"\n")
                    cartdb.close()
                    continue

                elif answer == 2:
                    checkIndexList = []
                    a = '1' # these are used as positive flags
                    b = '0' # these are used as negative flags
                    print("\n=== Here are all your registered events ===")
                    checkdb = open("cartList.txt", "r")
                    checkList = checkdb.readlines()
                    checkdb.close()
                    for i in range(0, len(checkList)): # looping algorithm to find the sequence where memberName is present
                        tempCheck = checkList[i].split(", ")
                        if memberName in tempCheck:
                            checkIndexList.append(a)
                        else:
                            checkIndexList.append(b) # output is a list like this [1,0,0,1,0,1] where 1 means member is present in record

                    for i in range(0, len(checkIndexList)):
                        if '1' in checkIndexList:
                            x = checkIndexList.index('1') # with the algorithm, we can simply print the line where the corresponding memberName is present
                            print(checkList[x].replace('\n','')) # this is to remove to 'new line' feature to prevent double spacing during output
                            checkIndexList[x] = '0' # then we replace the '1' in the algorithm to '0' after printing the values
                        else:
                            pass
                    continue

                elif answer == 3:
                    exitPage()

                else:
                    print("choice not supported, try again")
                    continue

                break
        else:
            print("\n >>> invalid credentials... \n")
            option = input("would you like to sign-up? \n [Y] for membership registration \n [N] to retry login \n Your choice: " )
            if option == "N":
                continue #repeat while loop
            elif option == "Y":
                memberSignup()
            else:
                print("invalid option, returning to homepage...")
                homepage()
        break
    memberHandler.close()

def exitPage():
    print("\nYou have exited the application")
    print("Thank you for using our services!")

homepage() #initiate this upon launching AEGIS
# admin authentication referral code = AEMS0001
# total function = 20
# total lines = 717


import collections

# --- Transitional code from Python 2 to Python 3 ---
# See https://github.com/benjaminp/six/blob/master/six.py
import sys
ADDON_RUNNING_PYTHON_2 = sys.version_info[0] == 2
ADDON_RUNNING_PYTHON_3 = sys.version_info[0] == 3
if ADDON_RUNNING_PYTHON_3:
    text_type = str
    binary_type = bytes
elif ADDON_RUNNING_PYTHON_2:
    text_type = unicode
    binary_type = str
else:
    raise RuntimeError('Unknown Python runtime version')

# --- Determine interpreter running platform ---
# Cache all possible platform values in global variables for maximum speed.
# See http://stackoverflow.com/questions/446209/possible-values-from-sys-platform
cached_sys_platform = sys.platform
def _aux_is_android():
    if not cached_sys_platform.startswith('linux'): return False
    return 'ANDROID_ROOT' in os.environ or 'ANDROID_DATA' in os.environ or 'XBMC_ANDROID_APK' in os.environ

is_windows_bool = cached_sys_platform == 'win32' or cached_sys_platform == 'win64' or cached_sys_platform == 'cygwin'
is_osx_bool = cached_sys_platform.startswith('darwin')
is_android_bool = _aux_is_android()
is_linux_bool = cached_sys_platform.startswith('linux') and not is_android_bool

def is_windows(): return is_windows_bool
def is_osx(): return is_osx_bool
def is_android(): return is_android_bool
def is_linux(): return is_linux_bool

# ------------------------------------------------------------------------------------------------
# Addon options and tuneables.
# ------------------------------------------------------------------------------------------------
# Compact, smaller size, non-human readable JSON. False forces human-readable JSON for development.
# In AEL speed is not as critical so False is OK.
# In AML this must be True when releasing.
OPTION_COMPACT_JSON = False

# Use less memory when writing big JSON files, but writing is slower.
# In AEL this can be False when releasing.
# In AML it must be True when releasing.
OPTION_LOWMEM_WRITE_JSON = False

# The addon name in the GUI. Title of Kodi dialogs (yesno, progress, etc.) and used also in log functions.
ADDON_LONG_NAME = 'Advanced Emulator Launcher'
ADDON_SHORT_NAME = 'AEL'

# These parameters are used in utils_write_JSON_file() when pprint is True or
# OPTION_COMPACT_JSON is False. Otherwise non-human readable, compact JSON is written.
# pprint = True function parameter overrides option OPTION_COMPACT_JSON.
# More compact JSON files (less blanks) load faster because file size is smaller.
JSON_INDENT = 1
JSON_SEP = (', ', ': ')

# ------------------------------------------------------------------------------------------------
# CUSTOM/DEBUG/TEST settings
# ------------------------------------------------------------------------------------------------
# An integer number incremented whenever there is a change in the ROM storage format.
# This enables easy migrations, at least in theory.
AEL_STORAGE_FORMAT = 1

# ------------------------------------------------------------------------------------------------
# This is to ease printing colors in Kodi.
# ------------------------------------------------------------------------------------------------
KC_RED        = '[COLOR red]'
KC_ORANGE     = '[COLOR orange]'
KC_GREEN      = '[COLOR green]'
KC_YELLOW     = '[COLOR yellow]'
KC_VIOLET     = '[COLOR violet]'
KC_BLUEVIOLET = '[COLOR blueviolet]'
KC_END        = '[/COLOR]'

# ------------------------------------------------------------------------------------------------
# Image file constants.
# ------------------------------------------------------------------------------------------------
# Supported image files in:
# 1. misc_identify_image_id_by_contents()
# 2. misc_identify_image_id_by_ext()
IMAGE_PNG_ID     = 'PNG'
IMAGE_JPEG_ID    = 'JPEG'
IMAGE_GIF_ID     = 'GIF'
IMAGE_BMP_ID     = 'BMP'
IMAGE_TIFF_ID    = 'TIFF'
IMAGE_UKNOWN_ID  = 'Image unknown'
IMAGE_CORRUPT_ID = 'Image corrupt'

IMAGE_IDS = [
    IMAGE_PNG_ID,
    IMAGE_JPEG_ID,
    IMAGE_GIF_ID,
    IMAGE_BMP_ID,
    IMAGE_TIFF_ID,
]

IMAGE_EXTENSIONS = {
    IMAGE_PNG_ID  : ['png'],
    IMAGE_JPEG_ID : ['jpg', 'jpeg'],
    IMAGE_GIF_ID  : ['gif'],
    IMAGE_BMP_ID  : ['bmp'],
    IMAGE_TIFF_ID : ['tif', 'tiff'],
}

# Image file magic numbers. All at file offset 0.
# See https://en.wikipedia.org/wiki/List_of_file_signatures
# b prefix is a byte string in both Python 2 and 3.
IMAGE_MAGIC_DIC = {
    IMAGE_PNG_ID  : [ b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A' ],
    IMAGE_JPEG_ID : [
        b'\xFF\xD8\xFF\xDB',
        b'\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00\x01',
        b'\xFF\xD8\xFF\xEE',
        b'\xFF\xD8\xFF\xE1',
    ],
    IMAGE_GIF_ID  : [
        b'\x47\x49\x46\x38\x37\x61',
        b'\x47\x49\x46\x38\x39\x61',
    ],
    IMAGE_BMP_ID  : [ b'\x42\x4D' ],
    IMAGE_TIFF_ID : [
        b'\x49\x49\x2A\x00',
        b'\x4D\x4D\x00\x2A',
    ]
}

# ------------------------------------------------------------------------------------------------
# Addon constants
# ------------------------------------------------------------------------------------------------
# --- Misc "constants" ---
PLOT_STR_MAXSIZE = 40
RETROPLAYER_LAUNCHER_APP_NAME = 'retroplayer_launcher_app'
LNK_LAUNCHER_APP_NAME = 'lnk_launcher_app'

# Special Category/Launcher IDs.
CATEGORY_ADDONROOT_ID = 'root_category' # This is an actual category, not a virtual one.

# Launcher types.
# [TODO] Use a set of consistent labels in the addon for the different types of launchers.
#        Maybe use a database field to set the launcher type???
LAUNCHER_STANDALONE      = 'LAUNCHER_STANDALONE'
LAUNCHER_ROM_STANDARD    = 'LAUNCHER_ROM_STANDARD'
LAUNCHER_ROM_RETROPLAYER = 'LAUNCHER_ROM_RETROPLAYER'
LAUNCHER_ROM_LNK         = 'LAUNCHER_ROM_LNK'

# Favourites, Most Played and Recently Played belong to VCATEGORY_SPECIAL_ID category.
# However, having an empty category in URLs for these virtual launchers is OK.
VCATEGORY_SPECIAL_ID = 'vcategory_special'
VCATEGORY_ROM_COLLECTION_ID = 'vcategory_rom_collection'
VCATEGORY_BROWSE_BY_TITLE_ID = 'vcategory_browse_by_title'
VCATEGORY_BROWSE_BY_YEARS_ID = 'vcategory_browse_by_year'
VCATEGORY_BROWSE_BY_GENRE_ID = 'vcategory_browse_by_genre'
VCATEGORY_BROWSE_BY_DEVELOPER_ID = 'vcategory_browse_by_developer'
VCATEGORY_BROWSE_BY_NPLAYERS_ID = 'vcategory_browse_by_nplayer'
VCATEGORY_BROWSE_BY_ESRB_ID = 'vcategory_browse_by_esrb'
VCATEGORY_BROWSE_BY_RATING_ID = 'vcategory_browse_by_rating'
VCATEGORY_BROWSE_BY_CATEGORY_ID = 'vcategory_browse_by_category'
VCATEGORY_AOS_ID = 'vcategory_ael_offline_scraper'

VCATEGORY_BROWSE_BY_ID_LIST = [
    VCATEGORY_BROWSE_BY_TITLE_ID,
    VCATEGORY_BROWSE_BY_YEARS_ID,
    VCATEGORY_BROWSE_BY_GENRE_ID,
    VCATEGORY_BROWSE_BY_DEVELOPER_ID,
    VCATEGORY_BROWSE_BY_NPLAYERS_ID,
    VCATEGORY_BROWSE_BY_ESRB_ID,
    VCATEGORY_BROWSE_BY_RATING_ID,
    VCATEGORY_BROWSE_BY_CATEGORY_ID,
]

VCATEGORY_ID_LIST = [
    VCATEGORY_SPECIAL_ID,
    VCATEGORY_ROM_COLLECTION_ID,
] + VCATEGORY_BROWSE_BY_ID_LIST + [
    VCATEGORY_AOS_ID,
]

# IMPORTANT
# In many parts of the addon it is important to differentiate the type of launcher.
# Create more virtual launcher variables???
# Also, how to simplify the addon URLs?
VLAUNCHER_FAVOURITES_ID = 'vlauncher_favourites'
VLAUNCHER_RECENT_ID = 'vlauncher_recent'
VLAUNCHER_MOST_PLAYED_ID = 'vlauncher_most_played'
VLAUNCHER_ID_LIST = [
    VLAUNCHER_FAVOURITES_ID,
    VLAUNCHER_RECENT_ID,
    VLAUNCHER_MOST_PLAYED_ID,
]

# --- Content type property to be used by skins ---
AEL_CONTENT_WINDOW_ID          = 10000
AEL_CONTENT_LABEL              = 'AEL_Content'
AEL_CONTENT_VALUE_LAUNCHERS    = 'launchers'
AEL_CONTENT_VALUE_ROMS         = 'roms'
AEL_CONTENT_VALUE_CATEGORY     = 'category'
AEL_CONTENT_VALUE_STD_LAUNCHER = 'std_launcher'
AEL_CONTENT_VALUE_ROM_LAUNCHER = 'rom_launcher'
AEL_CONTENT_VALUE_ROM          = 'rom'
AEL_CONTENT_VALUE_NONE         = ''

AEL_LAUNCHER_NAME_LABEL        = 'AEL_Launch_Name'
AEL_LAUNCHER_ICON_LABEL        = 'AEL_Launch_Icon'
AEL_LAUNCHER_CLEARLOGO_LABEL   = 'AEL_Launch_Clearlogo'

# Value is the number of items inside a launcher.
AEL_NUMITEMS_LABEL             = 'AEL_NumItems'

# --- ROM flags used by skins to display status icons ---
AEL_INFAV_BOOL_LABEL                 = 'AEL_InFav'
AEL_INFAV_BOOL_VALUE_TRUE            = 'InFav_True'
AEL_INFAV_BOOL_VALUE_FALSE           = 'InFav_False'
AEL_MULTIDISC_BOOL_LABEL             = 'AEL_MultiDisc'
AEL_MULTIDISC_BOOL_VALUE_TRUE        = 'MultiDisc_True'
AEL_MULTIDISC_BOOL_VALUE_FALSE       = 'MultiDisc_False'
AEL_FAV_STAT_LABEL                   = 'AEL_Fav_stat'
AEL_FAV_STAT_VALUE_OK                = 'Fav_OK'
AEL_FAV_STAT_VALUE_UNLINKED_ROM      = 'Fav_UnlinkedROM'
AEL_FAV_STAT_VALUE_UNLINKED_LAUNCHER = 'Fav_UnlinkedLauncher'
AEL_FAV_STAT_VALUE_BROKEN            = 'Fav_Broken'
AEL_FAV_STAT_VALUE_NONE              = 'Fav_None'
AEL_NOINTRO_STAT_LABEL               = 'AEL_NoIntro_stat'
AEL_NOINTRO_STAT_VALUE_HAVE          = 'NoIntro_Have'
AEL_NOINTRO_STAT_VALUE_MISS          = 'NoIntro_Miss'
AEL_NOINTRO_STAT_VALUE_UNKNOWN       = 'NoIntro_Unknown'
AEL_NOINTRO_STAT_VALUE_EXTRA         = 'NoIntro_Extra'
AEL_NOINTRO_STAT_VALUE_NONE          = 'NoIntro_None'
AEL_PCLONE_STAT_LABEL                = 'AEL_PClone_stat'
AEL_PCLONE_STAT_VALUE_PARENT         = 'PClone_Parent'
AEL_PCLONE_STAT_VALUE_CLONE          = 'PClone_Clone'
AEL_PCLONE_STAT_VALUE_NONE           = 'PClone_None'

# --- ID of the fake ROM parent of all Unknown ROMs ---
UNKNOWN_ROMS_PARENT_ID = 'Unknown_ROMs_Parent'

# --- Audit reports ---
AUDIT_REPORT_ALL = 'AUDIT_REPORT_ALL'
AUDIT_REPORT_NOINTRO = 'AUDIT_REPORT_NOINTRO'
AUDIT_REPORT_REDUMP = 'AUDIT_REPORT_REDUMP'

# ------------------------------------------------------------------------------------------------
# Metadata
# ------------------------------------------------------------------------------------------------
# launcher['audit_state'] values default AUDIT_STATE_OFF
AUDIT_STATE_ON  = 'Audit ON'
AUDIT_STATE_OFF = 'Audit OFF'
AUDIT_STATE_LIST = [
    AUDIT_STATE_ON,
    AUDIT_STATE_OFF,
]

# launcher['audit_display_mode'] values default NOINTRO_DMODE_ALL
AUDIT_DMODE_ALL       = 'All ROMs'
AUDIT_DMODE_HAVE      = 'Have ROMs'
AUDIT_DMODE_HAVE_UNK  = 'Have or Unknown ROMs'
AUDIT_DMODE_HAVE_MISS = 'Have or Missing ROMs'
AUDIT_DMODE_MISS      = 'Missing ROMs'
AUDIT_DMODE_MISS_UNK  = 'Missing or Unknown ROMs'
AUDIT_DMODE_UNK       = 'Unknown ROMs'
AUDIT_DMODE_LIST = [
    AUDIT_DMODE_ALL,
    AUDIT_DMODE_HAVE,
    AUDIT_DMODE_HAVE_UNK,
    AUDIT_DMODE_HAVE_MISS,
    AUDIT_DMODE_MISS,
    AUDIT_DMODE_MISS_UNK,
    AUDIT_DMODE_UNK,
]

# launcher['launcher_display_mode'] values default LAUNCHER_DMODE_FLAT
LAUNCHER_DMODE_FLAT   = 'Flat mode'
LAUNCHER_DMODE_PCLONE = 'Parent/Clone mode'
LAUNCHER_DMODE_LIST = [
    LAUNCHER_DMODE_FLAT,
    LAUNCHER_DMODE_PCLONE,
]

# rom['nointro_status'] values default AUDIT_STATUS_NONE
AUDIT_STATUS_HAVE    = 'Have'
AUDIT_STATUS_MISS    = 'Miss'
AUDIT_STATUS_UNKNOWN = 'Unknown'
AUDIT_STATUS_EXTRA   = 'Extra'
AUDIT_STATUS_NONE    = 'None'
AUDIT_STATUS_LIST = [
    AUDIT_STATUS_HAVE,
    AUDIT_STATUS_MISS,
    AUDIT_STATUS_UNKNOWN,
    AUDIT_STATUS_EXTRA,
    AUDIT_STATUS_NONE,
]

# rom['pclone_status'] values default PCLONE_STATUS_NONE
PCLONE_STATUS_PARENT = 'Parent'
PCLONE_STATUS_CLONE  = 'Clone'
PCLONE_STATUS_NONE   = 'None'
PCLONE_STATUS_LIST = [
    PCLONE_STATUS_PARENT,
    PCLONE_STATUS_CLONE,
    PCLONE_STATUS_NONE,
]

# m_esrb string ESRB_LIST default ESRB_PENDING
ESRB_PENDING     = 'RP (Rating Pending)'
ESRB_EARLY       = 'EC (Early Childhood)'
ESRB_EVERYONE    = 'E (Everyone)'
ESRB_EVERYONE_10 = 'E10+ (Everyone 10+)'
ESRB_TEEN        = 'T (Teen)'
ESRB_MATURE      = 'M (Mature)'
ESRB_ADULTS_ONLY = 'AO (Adults Only)'
ESRB_LIST = [
    ESRB_PENDING,
    ESRB_EARLY,
    ESRB_EVERYONE,
    ESRB_EVERYONE_10,
    ESRB_TEEN,
    ESRB_MATURE,
    ESRB_ADULTS_ONLY,
]

# m_nplayers values default ''
NP_NOT_SET = ''
NP_1P      = '1P'
NP_2P_SIM  = '2P sim'
NP_2P_ALT  = '2P alt'
NP_3P_SIM  = '3P sim'
NP_3P_ALT  = '3P alt'
NP_4P_SIM  = '4P sim'
NP_4P_ALT  = '4P alt'
NP_6P_SIM  = '6P sim'
NP_6P_ALT  = '6P alt'
NP_8P_SIM  = '8P sim'
NP_8P_ALT  = '8P alt'
NPLAYERS_LIST = [
    NP_1P,
    NP_2P_SIM,
    NP_2P_ALT,
    NP_3P_SIM,
    NP_3P_ALT,
    NP_4P_SIM,
    NP_4P_ALT,
    NP_6P_SIM,
    NP_6P_ALT,
    NP_8P_SIM,
    NP_8P_ALT,
]

# Use unique string as IDs.
META_TITLE_ID     = 'title'
META_YEAR_ID      = 'year'
META_GENRE_ID     = 'genre'
META_DEVELOPER_ID = 'developer'
META_NPLAYERS_ID  = 'nplayers'
META_ESRB_ID      = 'esrb'
META_RATING_ID    = 'rating'
META_PLOT_ID      = 'plot'

DEFAULT_META_TITLE     = ''
DEFAULT_META_YEAR      = ''
DEFAULT_META_GENRE     = ''
DEFAULT_META_DEVELOPER = ''
DEFAULT_META_NPLAYERS  = ''
DEFAULT_META_ESRB      = ESRB_PENDING
DEFAULT_META_RATING    = ''
DEFAULT_META_PLOT      = ''

# ------------------------------------------------------------------------------------------------
# Assets
# ------------------------------------------------------------------------------------------------
# --- Object types for rendering and database storage ---
OBJECT_CATEGORY_ID   = 1
OBJECT_COLLECTION_ID = 2
OBJECT_LAUNCHER_ID   = 3
OBJECT_ROM_ID        = 4

OBJECT_LIST = [
    OBJECT_CATEGORY_ID,
    OBJECT_COLLECTION_ID,
    OBJECT_LAUNCHER_ID,
    OBJECT_ROM_ID,
]

# --- Kodi standard artwork types. Mappable to any other artwork type including itself ---
# Use unique string as IDs. Then, if asset order changes the IDs are the same.
ASSET_ICON_ID       = 'icon'
ASSET_FANART_ID     = 'fanart'
ASSET_CLEARLOGO_ID  = 'clearlogo'
ASSET_POSTER_ID     = 'poster'
ASSET_BANNER_ID     = 'banner' # Marquee in MAME
ASSET_TRAILER_ID    = 'trailer'

# --- AEL artwork types ---
# What about supporting BOXSPINE and composite box (fron, spine and back in one image).
#
# [TODO] Current artwork model uses multiplexed artwork for non-MAME and MAME platforms.
#        This was originally made to save space on the JSON databases. However, database space
#        is not so important anymore.
#        Is it better to use all artwork fields and then skinners create Arcade and non-Arcade views?
#
ASSET_TITLE_ID      = 'title'
ASSET_SNAP_ID       = 'snap'
ASSET_BOXFRONT_ID   = 'boxfront'  # Cabinet in MAME
ASSET_BOXBACK_ID    = 'boxback'   # CPanel in MAME
ASSET_3DBOX_ID      = '3dbox'     # New field in release x.y.z???
ASSET_CARTRIDGE_ID  = 'cartridge' # PCB in MAME
ASSET_FLYER_ID      = 'flyer'
ASSET_MAP_ID        = 'map'
ASSET_MANUAL_ID     = 'manual'
ASSET_CONTROLLER_ID = 'controller'

# The order of this list must match order in select dialogs in the GUI, or bad things will happen.
CATEGORY_ASSET_ID_LIST = [
    ASSET_ICON_ID,
    ASSET_FANART_ID,
    ASSET_BANNER_ID,
    ASSET_CLEARLOGO_ID,
    ASSET_POSTER_ID,
    ASSET_TRAILER_ID,
]
COLLECTION_ASSET_ID_LIST = CATEGORY_ASSET_ID_LIST

LAUNCHER_ASSET_ID_LIST = [
    ASSET_ICON_ID,
    ASSET_FANART_ID,
    ASSET_BANNER_ID,
    ASSET_CLEARLOGO_ID,
    ASSET_POSTER_ID,
    ASSET_CONTROLLER_ID,
    ASSET_TRAILER_ID,
]

ROM_ASSET_ID_LIST = [
    ASSET_FANART_ID,
    ASSET_BANNER_ID,
    ASSET_CLEARLOGO_ID,
    ASSET_TITLE_ID,
    ASSET_SNAP_ID,
    ASSET_BOXFRONT_ID,
    ASSET_BOXBACK_ID,
    ASSET_3DBOX_ID,
    ASSET_CARTRIDGE_ID,
    ASSET_FLYER_ID,
    ASSET_MAP_ID,
    ASSET_MANUAL_ID,
    ASSET_TRAILER_ID,
]

OBJECT_ASSETS = {
    OBJECT_CATEGORY_ID : CATEGORY_ASSET_ID_LIST,
    OBJECT_COLLECTION_ID : COLLECTION_ASSET_ID_LIST,
    OBJECT_LAUNCHER_ID : LAUNCHER_ASSET_ID_LIST,
    OBJECT_ROM_ID : ROM_ASSET_ID_LIST,
}

# Auxiliar constants.
DEFAULT_ODIC_ID = 'DEFAULT_ODIC_ID'
ASSET_LIST_ID   = 'ASSET_LIST_ID'

# Database fields for the defaultable assets.
DEFAULT_ASSET_DB = {
    OBJECT_CATEGORY_ID : {
        # These are the assets that can be mapped and the database fields to store the mapping.
        DEFAULT_ODIC_ID : collections.OrderedDict([
            (ASSET_ICON_ID, 'default_icon'),
            (ASSET_FANART_ID, 'default_fanart'),
            (ASSET_BANNER_ID, 'default_banner'),
            (ASSET_POSTER_ID, 'default_poster'),
            (ASSET_CLEARLOGO_ID, 'default_clearlogo'),
        ]),
        # This is the list of assets that can be choosed for the mapping.
        ASSET_LIST_ID : [
            ASSET_ICON_ID,
            ASSET_FANART_ID,
            ASSET_BANNER_ID,
            ASSET_POSTER_ID,
            ASSET_CLEARLOGO_ID,
        ],
    },
    OBJECT_COLLECTION_ID : {
        DEFAULT_ODIC_ID : collections.OrderedDict([
            (ASSET_ICON_ID, 'default_icon'),
            (ASSET_FANART_ID, 'default_fanart'),
            (ASSET_BANNER_ID, 'default_banner'),
            (ASSET_POSTER_ID, 'default_poster'),
            (ASSET_CLEARLOGO_ID, 'default_clearlogo'),
        ]),
        ASSET_LIST_ID : [
            ASSET_ICON_ID,
            ASSET_FANART_ID,
            ASSET_BANNER_ID,
            ASSET_POSTER_ID,
            ASSET_CLEARLOGO_ID,
        ],
    },
    OBJECT_LAUNCHER_ID : {
        DEFAULT_ODIC_ID : collections.OrderedDict([
            (ASSET_ICON_ID, 'default_icon'),
            (ASSET_FANART_ID, 'default_fanart'),
            (ASSET_BANNER_ID, 'default_banner'),
            (ASSET_POSTER_ID, 'default_poster'),
            (ASSET_CLEARLOGO_ID, 'default_clearlogo'),
        ]),
        ASSET_LIST_ID : [
            ASSET_ICON_ID,
            ASSET_FANART_ID,
            ASSET_BANNER_ID,
            ASSET_POSTER_ID,
            ASSET_CLEARLOGO_ID,
            ASSET_CONTROLLER_ID,
        ],
    },
    # Edition of ROMs default assets in a ROM Launcher.
    # Edition of Favourite ROM default assets.
    OBJECT_ROM_ID : {
        DEFAULT_ODIC_ID : collections.OrderedDict([
            (ASSET_ICON_ID, 'roms_default_icon'),
            (ASSET_FANART_ID, 'roms_default_fanart'),
            (ASSET_BANNER_ID, 'roms_default_banner'),
            (ASSET_POSTER_ID, 'roms_default_poster'),
            (ASSET_CLEARLOGO_ID, 'roms_default_clearlogo'),
        ]),
        ASSET_LIST_ID : [
            ASSET_TITLE_ID,
            ASSET_SNAP_ID,
            ASSET_BOXFRONT_ID,
            ASSET_BOXBACK_ID,
            ASSET_CARTRIDGE_ID,
            ASSET_FANART_ID,
            ASSET_BANNER_ID,
            ASSET_CLEARLOGO_ID,
            ASSET_FLYER_ID,
            ASSET_MAP_ID,
        ],
    },
}

# --- Addon will search these file extensions for assets ---
# Check http://kodi.wiki/view/advancedsettings.xml#videoextensions
IMAGE_EXTENSION_LIST   = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'tif', 'tiff']
MANUAL_EXTENSION_LIST  = ['pdf', 'cbz', 'cbr']
TRAILER_EXTENSION_LIST = ['mov', 'divx', 'xvid', 'wmv', 'avi', 'mpg', 'mpeg', 'mp4', 'mkv', 'avc']

# --- Scrapers -----------------------------------------------------------------------------------
# --- Options ---
# Use True only for development.
SCRAPER_CACHE_HUMAN_JSON = True

# --- Scraper IDs ---
SCRAPER_NULL_ID          = 10
SCRAPER_AEL_OFFLINE_ID   = 20
SCRAPER_THEGAMESDB_ID    = 30
SCRAPER_MOBYGAMES_ID     = 40
SCRAPER_SCREENSCRAPER_ID = 50
SCRAPER_GAMEFAQS_ID      = 60 # Disabled at the moment.
SCRAPER_ARCADEDB_ID      = 70
SCRAPER_LIBRETRO_ID      = 80 # Not coded yet.

# List of enabled scrapers. If a scraper ID is in this list then a unique scraper object
# will be instantiated and cached in the global ScraperFactory object.
# To disable an scraper just remove it from this list.
SCRAPER_LIST = [
    SCRAPER_NULL_ID,
    SCRAPER_AEL_OFFLINE_ID,
    SCRAPER_THEGAMESDB_ID,
    SCRAPER_MOBYGAMES_ID,
    SCRAPER_SCREENSCRAPER_ID,
    SCRAPER_ARCADEDB_ID,
]

# Make sure this matches the scraper list in settings.xml or bad things will happen.
SCRAP_METADATA_SETTINGS_LIST = [
    SCRAPER_AEL_OFFLINE_ID,
    SCRAPER_THEGAMESDB_ID,
    SCRAPER_SCREENSCRAPER_ID,
    SCRAPER_MOBYGAMES_ID,
]

SCRAP_ASSET_SETTINGS_LIST = [
    SCRAPER_THEGAMESDB_ID,
    SCRAPER_SCREENSCRAPER_ID,
    SCRAPER_MOBYGAMES_ID,
]

SCRAP_METADATA_MAME_SETTINGS_LIST = [
    SCRAPER_AEL_OFFLINE_ID,
    SCRAPER_ARCADEDB_ID,
    SCRAPER_THEGAMESDB_ID,
    SCRAPER_SCREENSCRAPER_ID,
    SCRAPER_MOBYGAMES_ID,
]

SCRAP_ASSET_MAME_SETTINGS_LIST = [
    SCRAPER_ARCADEDB_ID,
    SCRAPER_THEGAMESDB_ID,
    SCRAPER_SCREENSCRAPER_ID,
    SCRAPER_MOBYGAMES_ID,
]


# Computes and displays sum of given natural numbers
#===================================================

# Specify a positive number
NUM = 100

# Compute and print sum
total = NUM * (NUM + 1) / 2
print("Sum of first ", NUM, " positive numbers is ",
total)


import bisect
import math
from math import atan2

import pygame

from sprites import X, Y
import random

MAX_TERRAIN = 200
MIN_TERRAIN = 0
LINE_WIDTH = 2

class OutOfMapException(Exception):
    pass

class Terrain:
    def __init__(self, dimension, color):

        # Game details
        self._dimension = dimension

        # Terrain Generation
        self._terrain = []
        self._color = color
        self._terrain_polygon = []

        # Generate terrain
        self.generate_terrain()

    def height_at_point(self, pt):
        return self._terrain[pt]

    def grade_at_point(self, pt, width=4):
        # TODO: Do smart things with small tall peaks, use some physics maybe??

        # dist either side
        dist = int(width/2.0)

        # Get the x value for point left and right of middle point
        less_x = pt - dist if pt - dist >= 0 else 0
        high_x = pt + dist if pt + dist < self._dimension[X] else self._dimension[X] - 1

        # Get the y value for point left and right of middle point
        h_less = self._terrain[less_x]
        h_high = self._terrain[high_x]

        # Calculate and return slope - What a bitch
        slope = - (360 + ((atan2((h_less - h_high), (less_x - high_x)) * 180.0 / math.pi) - 180))
        return slope

    def generate_terrain(self):
        # previous_height = random.randint(self._dimension[Y] - MAX_TERRAIN, self._dimension[Y] - 1)
        # for x in range(0, self._dimension[X]):
        #     self._terrain.append(self._random_height(previous_height))  # Generate and save current height
        #     previous_height = self._terrain[x]  # Save off for previous in next iteration

        points = self._midpoint_displacement(start=[0, self._dimension[Y] - MAX_TERRAIN],
                                             end=[self._dimension[X]+1, self._dimension[Y] - MAX_TERRAIN],
                                             roughness=0.9,
                                             vertical_displacement=self._dimension[Y] - MAX_TERRAIN,
                                             num_of_iterations=13)

        for point in points:
            self._terrain.append(point[1] if point[1] < self._dimension[Y] else self._dimension[Y] - 1)

        # Generate the polygon for this terrain list
        self._terrain_polygon.append([0, self._dimension[Y]])  # Bottom left corner of the screen
        for x, y in enumerate(self._terrain):
            self._terrain_polygon.append([x, y])  # points along the terrain
        self._terrain_polygon.append([self._dimension[X], self._dimension[Y]])  # Bottom Right
        self._terrain_polygon.append([0, self._dimension[Y]])  # Bottom left corner of the screen again to close polygon

    def intersects_terrain(self, location, buffer_x=0, buffer_y=0):
        # TODO Add a buffer to calculation to make it easier
        if location[X] > self._dimension[X]:
            # thing is out of the map
            # print(location)
            raise OutOfMapException("Projectile out of map to the right.")
        elif location[X] < 0:
            # thing is out side of the map
            # print(location)
            # print(self._dimension)
            raise OutOfMapException("Projectile out of map to the left.")

        # print(location)

        # We made it here, the thing is still in the map
        if self._terrain[location[X]] <= location[Y]:
            # print("INTERSECT WITH GROUND: " + str(self._terrain[location[X]]) + " " + str(location[Y]))
            # Terrain is over or equal to height of projectile at this X location, we intersect
            return True
        else:
            # Otherwise we do not intersect
            return False

    def draw(self, surface):
        pygame.draw.polygon(
            surface,
            self._color,
            self._terrain_polygon,
            LINE_WIDTH
        )

    # def _random_height(self, previous_height):
    #     greater = random.randint(0, 100) > 50  # Generate a yes no
    #
    #     if greater:
    #         return random.randint(self._dimension[Y] - MAX_TERRAIN, previous_height)
    #     else:
    #         return random.randint(previous_height, self._dimension[Y] - 1)

    # Iterative midpoint vertical displacement
    def _midpoint_displacement(self, start, end, roughness, vertical_displacement=None,
                               num_of_iterations=16):
        """
        Given a straight line segment specified by a starting point and an endpoint
        in the form of [starting_point_x, starting_point_y] and [endpoint_x, endpoint_y],
        a roughness value > 0, an initial vertical displacement and a number of
        iterations > 0 applies the  midpoint algorithm to the specified segment and
        returns the obtained list of points in the form
        points = [[x_0, y_0],[x_1, y_1],...,[x_n, y_n]]

        From:
        https://bitesofcode.wordpress.com/2016/12/23/landscape-generation-using-midpoint-displacement/

        """
        # Final number of points = (2^iterations)+1
        if vertical_displacement is None:
            # if no initial displacement is specified set displacement to:
            #  (y_start+y_end)/2
            vertical_displacement = (start[1] + end[1]) / 2
        # Data structure that stores the points is a list of lists where
        # each sublist represents a point and holds its x and y coordinates:
        # points=[[x_0, y_0],[x_1, y_1],...,[x_n, y_n]]
        #              |          |              |
        #           point 0    point 1        point n
        # The points list is always kept sorted from smallest to biggest x-value
        points = [start, end]
        iteration = 1
        while iteration <= num_of_iterations:
            # Since the list of points will be dynamically updated with the new computed
            # points after each midpoint displacement it is necessary to create a copy
            # of the state at the beginning of the iteration so we can iterate over
            # the original sequence.
            # Tuple type is used for security reasons since they are immutable in Python.
            points_tup = tuple(points)
            for i in range(len(points_tup) - 1):
                # Calculate x and y midpoint coordinates:
                # [(x_i+x_(i+1))/2, (y_i+y_(i+1))/2]
                midpoint = list(map(lambda x: (points_tup[i][x] + points_tup[i + 1][x]) / 2,
                                    [0, 1]))
                # Displace midpoint y-coordinate
                midpoint[1] += random.choice([-vertical_displacement,
                                              vertical_displacement])
                # Insert the displaced midpoint in the current list of points
                bisect.insort(points, midpoint)
                # bisect allows to insert an element in a list so that its order
                # is preserved.
                # By default the maintained order is from smallest to biggest list first
                # element which is what we want.
            # Reduce displacement range
            vertical_displacement *= 2 ** (-roughness)
            # update number of iterations
            iteration += 1

        return points


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import glob
import numpy as np
import os
import tensorflow as tf

#生成TFrecord数据集格式
def make_example(key1,key2):
	example = tf.train.Example(features=tf.train.Features(
        feature={
            'data':tf.train.Feature(float_list=tf.train.FloatList(value=key1)),
            'label':tf.train.Feature(float_list=tf.train.FloatList(value=key2))
        }
    ))
	return example

def listdir_nohidden(path):
    for f in os.listdir(path):
        if not f.startswith('.') and not f.endswith('.txt'):
            yield f

def get_class_names(path):
    class_names = list(listdir_nohidden(path))
    return class_names

def process_data(inpath = './data/flower_photos/',out_path='./data/process/',validation_percentage=10):
    class_names = get_class_names(inpath)#获取flower_datd的class_name
    print (class_names)

    if not os.path.exists(out_path):
        os.mkdir(out_path)
    #建立训练测试集
    train_path = out_path+'train'
    test_path = out_path + 'test'
    if not os.path.exists(train_path):
        os.mkdir(train_path)
        os.mkdir(test_path)

    for class_index, class_name in enumerate(class_names):
        print('processing dataset is ',class_name)
        dirname = inpath + class_name+'/'
        jpg_files = list(listdir_nohidden(dirname))
        total_name = len(jpg_files)
        file_indices = tuple(range(total_name))

        tfrecordtrain = os.path.join(train_path+'/',class_name+'_train.rfrecords')#TFrecord数据集名字
        tfrecordtest = os.path.join(test_path+'/',class_name + '_test.rfrecords')
        train_writer = tf.python_io.TFRecordWriter(tfrecordtrain)
        test_writer = tf.python_io.TFRecordWriter(tfrecordtest)

        for file_index in file_indices:
            chance = np.random.randint(100)  # 随机产生100个数代表百分比train,test数据集分割
            if chance > validation_percentage:
                convert_one_file(dirname,jpg_files,class_index,train_writer,file_index)
            else:
                convert_one_file(dirname, jpg_files,class_index,test_writer,file_index)
        train_writer.close()
        test_writer.close()
        print('finished in ',class_name)

def convert_one_file(dirname,jpg_files,class_index,writer,file_index):
    file_name=dirname+jpg_files[file_index]
    image_raw_data = tf.gfile.FastGFile(file_name,'rb').read()
    label = np.zeros(5)

    with tf.Session() as sess:
        img_data = tf.image.decode_jpeg(image_raw_data)
        resized = tf.image.resize_images(images = img_data,size=[299,299])
        data = sess.run(resized)
        data = data.reshape(-1)
        label[class_index]=1
        example = make_example(data, label)
        writer.write(example.SerializeToString())
process_data()


def pivot(array, start, end):
    pivot = array[start]
    low = start + 1
    high = end

    while True:

        # Move high left
        while low <= high and array[high] >= pivot:
            high -= 1

        # Move low right
        while low <= high and array[low] <= pivot:
            low += 1

        # Check that low less than high
        if low <= high:
            # If so swap values
            array[low], array[high] = array[high], array[low]
        else:
            # Otherwise break loop
            break

    #swapping pivot with high so that pivot is at its right # #position
    array[start], array[high] = array[high], array[start]

    # Return pivot index
    return high

def quick_sort(array, start=None, end=None):
    if start == None or end == None:
        start = 0
        end = len(array) - 1
    if start >= end:
        return

    # Pivot and get pivot index
    pivot_index = pivot(array, start, end)
    # Recurse on left of pivot
    quick_sort(array, start, pivot_index-1)
    # Recurse on right of pivot
    quick_sort(array, pivot_index+1, end)


#!/bin/python3

import math
import os
import random
import re
import sys

#
# Complete the 'activityNotifications' function below.
#
# The function is expected to return an INTEGER.
# The function accepts following parameters:
#  1. INTEGER_ARRAY expenditure
#  2. INTEGER d
#

from bisect import bisect_left, insort

def get_median(ste, d):
    if d % 2 != 0:
        median = ste[d // 2]
    else:
        median = (ste[d // 2] + ste[(d // 2) - 1]) / 2
    return median

def activityNotifications(expenditure, d):
    te = expenditure[0:d]
    ste = sorted(te)
    median = get_median(ste, d)

    notification = 0
    if expenditure[d] >= 2 * median:
        notification += 1

    for i in range(d, len(expenditure) - 1):
        index = bisect_left(ste, expenditure[i - d])
        x = ste.pop(index)
        insort(ste, expenditure[i])
        median = get_median(ste, d)
        if expenditure[i + 1] >= 2 * median:
            notification += 1

    return notification

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    first_multiple_input = input().rstrip().split()

    n = int(first_multiple_input[0])

    d = int(first_multiple_input[1])

    expenditure = list(map(int, input().rstrip().split()))

    result = activityNotifications(expenditure, d)

    fptr.write(str(result) + '\n')

    fptr.close()


#!/usr/bin/env python
"""
Class :py:class:`SegGeometryJungfrauV2` describes the Jungfrau V2 sensor geometry
=================================================================================

Data array for Jungfrau 512x1024 segment is shaped as (1,512,1024),
has a matrix-like numeration for rows and columns with gaps between 2x4 ASICs
\n We assume that
\n * 1x1 ASICs has 256 rows and 256 columns,
\n * Jungfrau has a pixel size 75x75um
\n * X-Y coordinate system origin is in the sensor center,
\n * pixel (r,c)=(0,0) is in the bottom left corner, has coordinates (xmin,ymin), as shown below
\n ::

   (Xmin,Ymax)                          ^ Y                          (Xmax,Ymax)
   (511,0)                              |                             (1023,1023)
     ----------------- -----------------|----------------- -----------------
     |               | |               |||               | |               |
     |     ASIC      | |               |||               | |               |
     |    256x256    | |               |||               | |               |
     |               | |               |||               | |               |
     |               | |               |||               | |               |
     |               | |               |||               | |               |
     ----------------- -----------------|----------------- -----------------
   -------------------------------------+-------------------------------------> X
     ----------------- -----------------|----------------- -----------------
     |               | |               |||               | |               |
     |               | |               |||               | |               |
     |               | |               |||               | |               |
     |               | |               |||               | |               |
     |               | |               |||               | |               |
     |               | |               |||               | |               |
     ----------------- -----------------|----------------- -----------------
   (0,0)                                |                               (0,1023)
   (Xmin,Ymin)                                                        (Xmax,Ymin)

Usage::

    from PSCalib.SegGeometryJungfrauV2 import jungfrau_one as sg

    sg.print_seg_info(0o377)

    size_arr = sg.size()
    rows     = sg.rows()
    cols     = sg.cols()
    shape    = sg.shape()
    pix_size = pixel_scale_size()

    area     = sg.pixel_area_array()
    mask     = sg.pixel_mask_array(mbits=0o377, width=1, wcentral=1)
    # where mbits = +1-edges, +2-wide pixels

    sizeX = sg.pixel_size_array('X')
    sizeX, sizeY, sizeZ = sg.pixel_size_array()

    X     = sg.pixel_coord_array('X')
    X,Y,Z = sg.pixel_coord_array()
    print('X.shape =', X.shape)

    xmin, ymin, zmin = sg.pixel_coord_min()
    xmax, ymax, zmax = sg.pixel_coord_max()
    xmin = sg.pixel_coord_min('X')
    ymax = sg.pixel_coord_max('Y')

    # global method for rotation of numpy arrays:
    Xrot, Yrot = rotation(X, Y, C, S)
    ...

See:
 * :py:class:`GeometryObject`
 * :py:class:`SegGeometry`
 * :py:class:`SegGeometryCspad2x1V1`
 * :py:class:`SegGeometryEpix100V1`
 * :py:class:`SegGeometryJungfrauV1`
 * :py:class:`SegGeometryMatrixV1`
 * :py:class:`SegGeometryStore`

For more detail see `Detector Geometry <https://confluence.slac.stanford.edu/display/PSDM/Detector+Geometry>`_.

This software was developed for the SIT project.
If you use all or part of it, please give an appropriate acknowledgment.

Created: 2017-10-12 by Mikhail Dubrovin
2020-09-04 - converted to py3
"""

from PSCalib.SegGeometryJungfrauV1 import * # SegGeometryJungfrauV1, logging, np
logger = logging.getLogger(__name__)

class SegGeometryJungfrauV2(SegGeometryJungfrauV1):
    """Self-sufficient class for generation of Jungfrau 2x4 sensor pixel coordinate array"""

    _name = 'SegGeometryJungfrauV2'

    def __init__(sp, **kwa):
        logger.debug('SegGeometryJungfrauV2.__init__()')
        SegGeometryJungfrauV1.__init__(sp)

    def make_pixel_coord_arrs(sp):
        """Makes [512,1024] maps of x, y, and z pixel coordinates
        with origin in the center of 2x4
        """
        x_asic = np.arange(sp._casic)*sp._pixs
        x0 = np.array((-512-2.5, -256.5, 1.5, 256+3.5))*sp._pixs
        sp.x_arr_um = np.hstack([x_asic+x0[0], x_asic+x0[1], x_asic+x0[2], x_asic+x0[3]])

        y_asic = np.arange(sp._rasic)*sp._pixs
        y0 = np.array((-256.5, 1.5))*sp._pixs
        sp.y_arr_um = np.hstack([y0[0]+y_asic, y0[1]+y_asic])

        sp.x_pix_arr_um, sp.y_pix_arr_um  = np.meshgrid(sp.x_arr_um, sp.y_arr_um)
        sp.z_pix_arr_um = np.zeros((sp._rows, sp._cols))

    def get_xyz_min_um(sp):
        return sp.x_arr_um[0], sp.y_arr_um[0], 0

    def get_xyz_max_um(sp):
        return sp.x_arr_um[-1], sp.y_arr_um[-1], 0

jungfrau_front = SegGeometryJungfrauV2()

#----------- TEST -------------

if __name__ == "__main__":
  import sys
  from time import time
  import pyimgalgos.GlobalGraphics as gg # For test purpose in main only

  logging.basicConfig(format='[%(levelname).1s] L%(lineno)04d: %(message)s', level=logging.DEBUG)

  def test_xyz_min_max():
    w = jungfrau_front
    w.print_xyz_min_max_um()
    logger.info('\nYmin = ' + str(w.pixel_coord_min('Y'))\
              + '\nYmax = ' + str(w.pixel_coord_max('Y')))

  def test_xyz_maps():

    w = jungfrau_front
    w.print_maps_seg_um()

    titles = ['X map','Y map']
    #for i,arr2d in enumerate([w.x_pix_arr,w.y_pix_arr]):
    for i,arr2d in enumerate( w.get_seg_xy_maps_pix() ):
        amp_range = (arr2d.min(), arr2d.max())
        gg.plotImageLarge(arr2d, amp_range=amp_range, figsize=(10,5), title=titles[i])
        gg.move(200*i,100*i)

    gg.show()

  def test_jungfrau_img():

    t0_sec = time()
    w = jungfrau_front
    logger.info('Consumed time for coordinate arrays (sec) = %.3f' % (time()-t0_sec))

    X,Y = w.get_seg_xy_maps_pix()

    w.print_seg_info(0o377)

    logger.info('X.shape =' + str(X.shape))

    xmin, ymin, zmin = w.get_xyz_min_um()
    xmax, ymax, zmax = w.get_xyz_max_um()
    xmin /= w.pixel_scale_size()
    xmax /= w.pixel_scale_size()
    ymin /= w.pixel_scale_size()
    ymax /= w.pixel_scale_size()

    xsize = xmax - xmin + 1
    ysize = ymax - ymin + 1
    logger.info('\n  xsize = %d' % xsize\
               +'\n  ysize = %d' % ysize)

  def test_jungfrau_img_easy():
    o = jungfrau_front
    X, Y = o.get_seg_xy_maps_pix()
    xmin, xmax, ymin, ymax  = X.min(), X.max(), Y.min(), Y.max()
    Xoff, Yoff = X-xmin, ymax-Y
    iX, iY = (Xoff+0.25).astype(int), (Yoff+0.25).astype(int)
    img = gg.getImageFromIndexArrays(iY,iX,X+3*Y)
    gg.plotImageLarge(img, amp_range=(xmin+3*ymin, xmax+3*ymax), figsize=(14,6))
    gg.show()

  def test_pix_sizes():
    w = jungfrau_front
    w.print_pixel_size_arrs()
    size_arrX = w.pixel_size_array('X')
    size_arrY = w.pixel_size_array('Y')
    area_arr  = w.pixel_area_array()
    s = 'test_pix_sizes():'\
      + '\n  area_arr[348:358,378:388]:\n'  + str(area_arr[348:358,378:388])\
      + '\n  area_arr.shape:'               + str(area_arr.shape)\
      + '\n  size_arrX[348:358,378:388]:\n' + str(size_arrX[348:358,378:388])\
      + '\n  size_arrX.shape:'              + str(size_arrX.shape)\
      + '\n  size_arrY[348:358,378:388]:\n' + str(size_arrY[348:358,378:388])\
      + '\n  size_arrY.shape:'              + str(size_arrY.shape)
    logger.info(s)

  def test_jungfrau_mask(mbits=0o377, width=5, wcentral=10):
    o = jungfrau_front
    X, Y = o.get_seg_xy_maps_pix_with_offset()
    mask = o.pixel_mask_array(mbits=mbits, width=width, wcentral=wcentral)
    mask[mask==0]=4
    iX, iY = (X+0.25).astype(int), (Y+0.25).astype(int)
    img = gg.getImageFromIndexArrays(iY,iX,mask)
    gg.plotImageLarge(img, amp_range=(-1, 4), figsize=(14,6))
    gg.show()

  def usage(tname='0'):
    s = ''
    if tname in ('0',): s+='\n==== Usage: python %s <test-number>' % sys.argv[0]
    if tname in ('0','1'): s+='\n 1 - test_xyz_min_max()'
    if tname in ('0','2'): s+='\n 2 - test_xyz_maps()'
    if tname in ('0','3'): s+='\n 3 - test_jungfrau_img()'
    if tname in ('0','4'): s+='\n 4 - test_jungfrau_img_easy()'
    if tname in ('0','5'): s+='\n 5 - test_pix_sizes()'
    if tname in ('0','6'): s+='\n 6 - test_jungfrau_mask(mbits=1+2)'
    if tname in ('0','7'): s+='\n 7 - test_jungfrau_mask(mbits=1+2, width=10)'
    return s

if __name__ == "__main__":

    tname = sys.argv[1] if len(sys.argv) > 1 else '0'
    if len(sys.argv)==1: logger.info(usage())
    elif tname in ('1',): test_xyz_min_max()
    elif tname in ('2',): test_xyz_maps()
    elif tname in ('3',): test_jungfrau_img()
    elif tname in ('4',): test_jungfrau_img_easy()
    elif tname in ('5',): test_pix_sizes()
    elif tname in ('6',): test_jungfrau_mask(mbits=1+2)
    elif tname in ('7',): test_jungfrau_mask(mbits=1+2, width=10)
    else: logger.warning('NON-EXPECTED TEST NAME: %s\n\n%s' % (tname, usage()))
    if len(sys.argv)>1: logger.info(usage(tname))
    sys.exit('END OF TEST')

# EOF


# Com base nas aulas passadas vamos criar um sorteio de lista e utilizando o conceito de estrutura de
# decisão exibir qual foi a posição de ordem de inserção de dados que foi sorteada! usando o conceito
# de importação otimizada importe a função choice, logo em seguida crie quatro variáveis representadas
# por nomes n1, n2, n3, n4, essas variáveis devem ser do tipo string e devem solicitar dados. crie uma
# variável que receba como lista estas quatro variáveis. crie uma variável usando a importação otimizada
# e atribuindo a variável lista. crie uma função de impressão utilizando polimorfismo e quebra de linhas
# para definir um cabeçalho para sua aplicação console. utilizando o conceito de interpolação exiba qual
# foi o nome sorteado. utilizando o conceito de estrutura de decisão cria uma condição que exiba a ordem
# em que foi digitado o nome sorteado pela variável de sorteio da lista!

from random import choice

n1 = input("Digite um nome: ")
n2 = input("Digite um nome: ")
n3 = input("Digite um nome: ")
n4 = input("Digite um nome: ")
lista = [n1, n2, n3, n4]

sorteio = choice(lista)

print("-"*5, " NOME SORTEADO ", "-"*5)
print(f"O nome sorteado foi {sorteio} que esta na posicao {lista.index(sorteio)} ")

Aulas Iniciais - Fundamentos/Aulas Iniciais/12-09-2022/exercicio04.py


import sys
from collections import defaultdict

lines = [l.strip() for l in sys.stdin]
ans1 = 0
ans2scores = []
points = {")": 3, "]": 57, "}": 1197, ">": 25137}
points2 = {"(": 1, "[": 2, "{": 3, "<": 4}
pairs = {
    "(": ")",
    "[": "]",
    "{": "}",
    "<": ">",
}
for l in lines:
    s = []
    for c in l:
        if c in pairs.keys():
            s.append(c)
        else:
            if c == pairs[s[-1]]:
                s.pop()
            else:
                ans1 += points[c]
                break
    else:
        if s != []:
            score = 0
            for c in reversed(s):
                score *= 5
                score += points2[c]
            ans2scores.append(score)

print("ans1", ans1)

ans2scores.sort()
print("ans2", ans2scores[(len(ans2scores) // 2)])


#-*-coding:utf-8-*-
# date:2020-03-28
# Author: X.L.Eric
# function: image B G R show

import cv2 # 加载OpenCV库
import numpy as np
if __name__ == "__main__":
    img_h = 320
    img_w = 480

    img = np.zeros([img_h,img_w,3], dtype = np.float)
    img[:,:,0].fill(1.0)
    cv2.namedWindow('B', 1)
    cv2.imshow('B', img)

    img = np.zeros([img_h,img_w,3], dtype = np.float)
    img[:,:,1].fill(1.0)
    cv2.namedWindow('G', 1)
    cv2.imshow('G', img)

    img = np.zeros([img_h,img_w,3], dtype = np.float)
    img[:,:,2].fill(1.0)
    cv2.namedWindow('R', 1)
    cv2.imshow('R', img)

    cv2.waitKey(0)

    cv2.destroyAllWindows() # 销毁所有显示窗口


# --------------------------------------------------------------------------
# ------------  Metody Systemowe i Decyzyjne w Informatyce  ----------------
# --------------------------------------------------------------------------
#  Zadanie 3: Regresja logistyczna
#  autorzy: A. Gonczarek, J. Kaczmar, S. Zareba
#  2017
# --------------------------------------------------------------------------
# --------------------------------------------------------------------------
# ----------------- TEN PLIK MA POZOSTAC NIEZMODYFIKOWANY ------------------
# --------------------------------------------------------------------------

import numpy as np
from scipy.ndimage.filters import convolve

def hog(image):
    nwin_x = 5
    nwin_y = 5
    B = 7
    (L, C) = np.shape(image)
    H = np.zeros(shape=(nwin_x * nwin_y * B, 1))
    m = np.sqrt(L / 2.0)
    if C is 1:
        raise NotImplementedError
    step_x = np.floor(C / (nwin_x + 1))
    step_y = np.floor(L / (nwin_y + 1))
    cont = 0
    hx = np.array([[1, 0, -1]])
    hy = np.array([[-1], [0], [1]])
    grad_xr = convolve(image, hx, mode='constant', cval=0.0)
    grad_yu = convolve(image, hy, mode='constant', cval=0.0)
    angles = np.arctan2(grad_yu, grad_xr)
    magnit = np.sqrt((grad_yu ** 2 + grad_xr ** 2))
    for n in range(nwin_y):
        for m in range(nwin_x):
            cont += 1
            angles2 = angles[int(n * step_y):int((n + 2) * step_y), int(m * step_x):int((m + 2) * step_x)]
            magnit2 = magnit[int(n * step_y):int((n + 2) * step_y), int(m * step_x):int((m + 2) * step_x)]
            v_angles = angles2.ravel()
            v_magnit = magnit2.ravel()
            K = np.shape(v_angles)[0]
            bin = 0
            H2 = np.zeros(shape=(B, 1))
            for ang_lim in np.arange(start=-np.pi + 2 * np.pi / B, stop=np.pi + 2 * np.pi / B, step=2 * np.pi / B):
                for k in range(K):
                    if v_angles[k] < ang_lim:
                        v_angles[k] = 100
                        H2[bin] += v_magnit[k]
                bin += 1

            H2 = H2 / (np.linalg.norm(H2) + 0.01)
            H[(cont - 1) * B:cont * B] = H2
    return H


N=int(input())
li_dc=[]
for _ in range(N):
    li_dc.append(list(map(int, input().split())))

cor=[[False]*101 for _ in range(101)]
def draw(x, y, g, count, dir):
    global cor
    add_dir=[]
    print(dir)
    for i,d in enumerate(dir[::-1]):
        if d == 0:
            if i<len(dir)//2:
                x+=1
            add_dir.append(1)
        elif d==1:
            if i<len(dir)//2:
                y-=1
            add_dir.append(2)
        elif d==2:
            if i<len(dir)//2:
                x-=1
            add_dir.append(3)
        elif d==3:
            if i<len(dir)//2:
                y+=1
            add_dir.append(0)
        if 0<=x<=100 and 0<=y<=100:
            cor[y][x]=True
            print(x, y, cor[y][x], d)
    if count+1<=g:
        draw(x,y,g,count+1,dir+add_dir)
    else:
        return

for dc in li_dc:
    cor[dc[1]][dc[0]]=True
    if dc[2] ==0:
        cor[dc[1]][dc[0]+1]=True
    elif dc[2]==1:
        cor[dc[1]][dc[0]]=True
    elif dc[2]==2:
        cor[dc[1]][dc[0]]=True
        print(dc[0], dc[1], cor[dc[1]][dc[0]])
    draw(dc[0], dc[1], dc[3], 0, [dc[2]])

result=0
for i in range(101):
    for j in range(101):
        if cor[i][j]:
            if cor[i+1][j] and cor[i][j+1] and cor[i+1][j+1]:
                result+=1

print(result)


import os
import numpy as np
import torch
from torch.utils.data import Dataset
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import SimpleITK as sitk
import random
import torchvision.transforms.functional as tf
import cv2
import csv
import imageio

class ModelDataSet(Dataset):
    def __init__(self, img_path='', label_path='', train_phase='train', rand_transform=False):
        super(ModelDataSet, self).__init__()
        self.train_phase = train_phase
        # self.config = get_config('data_config')
        self.img_path = img_path
        # self.label_path = label_path
        self.ids = self.get_ids()
        self.rand_transform = rand_transform
        self.csv_name, self.csv_score = self.get_label(label_path)

    def __len__(self):
        # return 10
        return len(self.ids)

    def get_label(self, label_path):
        # global label, score
        csv_name = []
        csv_score = []
        f = csv.reader(open(os.path.join(label_path, self.train_phase + '.csv'), 'r'))
        for i in f:
            csv_name.append(i[0])
            csv_score.append(i[1])
        return csv_name, csv_score

    def __getitem__(self, index):
        id = self.ids[index]
        sample = dict()
        sample['id'] = id
        sample['data'], sample['label'] = self.get_sample_data(id)
        sample = self.data_transform(sample)
        return sample

    def get_sample_data(self, id):
        image_1 = imageio.imread(os.path.join(self.img_path, self.train_phase, id))
        if not image_1.shape[0] == 48:
            image_1 = np.r_[image_1, np.zeros([48 - image_1.shape[0], image_1.shape[1]])]
        if not image_1.shape[1] == 48:
            image_1 = np.c_[image_1, np.zeros([image_1.shape[0], 48 - image_1.shape[1]])]
        label = torch.from_numpy(np.array([float(self.csv_score[self.csv_name.index(id)])]))
        return image_1, label.type(torch.float32)

    def get_ids(self):
        arr = []
        path = os.path.join(self.img_path, self.train_phase)
        # path = os.path.join(self.img_path)
        for i in os.listdir(path):
            if os.path.splitext(i)[1] == ".png":
                arr.append(i)
        arr.sort()
        return arr

    def data_transform(self, sample):
        data_transform = transforms.Compose([
            transforms.Lambda(lambd=lambda x: torch.from_numpy((x.astype(np.float32)) / x.max() * 1.0 - 0.0)),
            transforms.Lambda(lambd=lambda x: x[np.newaxis, ...]),
        ])
        # label_transform = transforms.Compose([
        #     transforms.Lambda(lambd=lambda x: torch.from_numpy((x.astype(np.float32)) / 1.0 * 1.0 - 0.0)),
        #     transforms.Lambda(lambd=lambda x: x[np.newaxis, ...]),
        # ])

        # random augmentation
        if self.rand_transform:
            # if random.random() > 0.5:
            #     sample['data'] = cv2.flip(sample['data'], 0)
            #     sample['label'] = cv2.flip(sample['label'], 0)
            # if random.random() > 0.5:
            #     sample['data'] = cv2.flip(sample['data'], 1)
            #     sample['label'] = cv2.flip(sample['label'], 1)
            random.seed()
            rand = random.random()
            if rand > 0.25 and rand < 0.5:
                sample['data'] = cv2.rotate(sample['data'], cv2.ROTATE_90_CLOCKWISE)
                # sample['label'] = cv2.rotate(sample['label'], cv2.ROTATE_90_CLOCKWISE)
            if rand > 0.5 and rand < 0.75:
                sample['data'] = cv2.rotate(sample['data'], cv2.ROTATE_180)
                # sample['label'] = cv2.rotate(sample['label'], cv2.ROTATE_180)
            if rand > 0.75:
                sample['data'] = cv2.rotate(sample['data'], cv2.ROTATE_90_COUNTERCLOCKWISE)
                # sample['label'] = cv2.rotate(sample['label'], cv2.ROTATE_90_COUNTERCLOCKWISE)

        # normalization
        sample['data'] = data_transform(sample['data'])
        # sample['label'] = label_transform(sample['label'])
        return sample


import inspect
import collections
from pkg_resources import  iter_entry_points

from rowgenerators.exceptions import RowGeneratorError
from appurl import parse_app_url, Url

def get_generator(source, **kwargs):
    from rowgenerators import Source
    names = []

    if isinstance(source, Source):
        return source

    if isinstance(source, str):

        ref = parse_app_url(source).get_resource().get_target()
        try:
            names.append('.{}'.format(ref.target_format))
        except AttributeError:
            pass

    elif inspect.isgenerator(source):
        names.append('<generator>')
        ref = source

    elif isinstance(source, collections.Iterable):
        names.append('<iterator>')
        ref = source

    elif hasattr(source, '__iter__'):
        names.append('<iterator>')
        ref = source

    elif isinstance(source, Url):
        ref = source
        try:
            names.append('.{}'.format(ref.target_format))
        except AttributeError:
            pass

        try:
            names.append('{}+'.format(ref.scheme_extension))
        except AttributeError:
            pass

        try:
            names.append('{}:'.format(ref.scheme))
        except AttributeError:
            pass

        try:
            names.append('<{}>'.format(ref.__class__.__name__))
        except AttributeError:
            pass

    else:
        raise RowGeneratorError("Unknown arg type for source: '{}'".format(type(source)))

    classes = sorted([ep.load() for ep in iter_entry_points(group='rowgenerators') if ep.name in names],
                     key=lambda cls: cls.priority)

    if not classes:
        raise RowGeneratorError("Can't find generator for source '{}' \nproto={}, resource_format={}, target_format={} "
                                 .format(source, ref.proto, ref.resource_format, ref.target_format))

    try:
        return classes[0](ref, **kwargs)
    except Exception as e:

        raise RowGeneratorError("Failed to instantiate generator for class '{}', ref '{}'".format(classes[0], ref)) from e

class SelectiveRowGenerator(object):
    """Proxies an iterator to remove headers, comments, blank lines from the row stream.
    The header will be emitted first, and comments are avilable from properties """

    def __init__(self, seq, start=0, headers=[], comments=[], end=[], load_headers=True, **kwargs):
        """
        An iteratable wrapper that coalesces headers and skips comments

        :param seq: An iterable
        :param start: The start of data row
        :param headers: An array of row numbers that should be coalesced into the header line, which is yieled first
        :param comments: An array of comment row numbers
        :param end: The last row number for data
        :param kwargs: Ignored. Sucks up extra parameters.
        :return:
        """

        self.iter = iter(seq)
        self.start = start if (start or start is 0) else 1
        self.header_lines = headers if isinstance(headers, (tuple, list)) else [int(e) for e in headers.split(',') if e]
        self.comment_lines = comments
        self.end = end

        self.load_headers = load_headers

        self.headers = []
        self.comments = []

        int(self.start)  # Throw error if it is not an int

    @property
    def coalesce_headers(self):
        """Collects headers that are spread across multiple lines into a single row"""
        from six import text_type
        import re

        if not self.headers:
            return None

        header_lines = [list(hl) for hl in self.headers if bool(hl)]

        if len(header_lines) == 0:
            return []

        if len(header_lines) == 1:
            return header_lines[0]

        # If there are gaps in the values of a line, copy them forward, so there
        # is some value in every position
        for hl in header_lines:
            last = None
            for i in range(len(hl)):
                hli = text_type(hl[i])
                if not hli.strip():
                    hl[i] = last
                else:
                    last = hli

        headers = [' '.join(text_type(col_val).strip() if col_val else '' for col_val in col_set)
                   for col_set in zip(*header_lines)]

        headers = [re.sub(r'\s+', ' ', h.strip()) for h in headers]

        return headers

    def __iter__(self):

        for i, row in enumerate(self.iter):

            if i in self.header_lines:
                if self.load_headers:
                    self.headers.append(row)
            elif i in self.comment_lines:
                self.comments.append(row)
            elif i == self.start:
                break

        if self.headers:

            headers = self.coalesce_headers
        else:
            headers = ['col' + str(i) for i, _ in enumerate(row)]

        yield headers

        yield row

        yield from self.iter


import random

import scipy.stats

def get_bm_data(filename):
    data = {}
    with open(filename, 'r') as f:
        f.readline()
        line = f.readline()
        for k in ('name', 'gender', 'age', 'division', 'country', 'time'):
            data[k] = []
        while line != '':
            split = line.split(',')
            data['name'].append(split[0])
            data['gender'].append(split[1])
            data['age'].append(split[2])
            data['division'].append(split[3])
            data['country'].append(split[4])
            data['time'].append(float(split[5][:-1]))
            line = f.readline()
    return data

def compare_mean_marathon_data_by_country(data):
    countries_to_compare = ['BEL', 'BRA', 'FRA', 'JPN', 'ITA']

    country_times = {}
    for i in range(len(data['name'])):
        if data['country'][i] in countries_to_compare and data['gender'][i] == 'F':
            try:
                country_times[data['country'][i]].append(data['time'][i])
            except KeyError:
                country_times[data['country'][i]] = [data['time'][i]]

    for c1 in countries_to_compare:
        for c2 in countries_to_compare:
            if c1 < c2:
                p_val = scipy.stats.ttest_ind(country_times[c1], country_times[c2], equal_var=False)[1]
                if p_val < 0.05:
                    print(f'{c1} and {c2} have significantly different means\n'
                          f'p-value = {round(p_val, 4)}')

def check_multiply_hypotheses(num_hyps=50, sample_size=200):
    population = []
    for i in range(5000):
        population.append(random.gauss(0, 1))
    sample_1s, sample_2s = [], []

    # gen many pairs of small samples
    for i in range(num_hyps):
        sample_1s.append(random.sample(population, sample_size))
        sample_2s.append(random.sample(population, sample_size))
    # check pairs for statistically significant difference
    num_sig = 0
    for i in range(num_hyps):
        if scipy.stats.ttest_ind(sample_1s[i], sample_2s[i])[1] < 0.05:
            num_sig += 1
    print(f'# of statically significantly different (p < 0.05) pairs = {num_sig}')

if __name__ == '__main__':
    data = get_bm_data('bm_results2012.csv')
    compare_mean_marathon_data_by_country(data)
    check_multiply_hypotheses()

1 Intro CS/02.Intro to CS/21.Randomized Trials and Hypothesis Checking/21.6.Mulriple Hypotheses/marathon.py


# read and format input
with open('./input.txt') as f:
    inpt = [list(i.strip()) for i in f.readlines()]

# move and count
def slide(index, inp, xΔ, yΔ):
    treeCount = 0
    # start moving right
    while index['y'] < len(inp)-1:
        index['x'] += xΔ
        index['y'] += yΔ
        # make sure to loop
        index['x'] = index['x'] % len(inp[0])
        if inp[index['y']][index['x']] == '#':
            treeCount += 1
    return treeCount

## PART 2 ##
oneOne = slide({'x': 0, 'y': 0}, inpt, 1, 1)
threeOne = slide({'x': 0, 'y': 0}, inpt, 3, 1)
fiveOne = slide({'x': 0, 'y': 0}, inpt, 5, 1)
sevenOne = slide({'x': 0, 'y': 0}, inpt, 7, 1)
oneTwo = slide({'x': 0, 'y': 0}, inpt, 1, 2)

print(oneOne*threeOne*fiveOne*sevenOne*oneTwo)


# -*- encoding=utf8 -*-
__author__ = "zhongdd"

from airtest.core.api import *
from airtest.core.api import using
using("commomLogin.air")
from commomLogin import commom_login

auto_setup(__file__)
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)

stop_app("com.bosma.smarthome")
sleep(2)
start_app("com.bosma.smarthome")
sleep(5)

def commom():
    #分享控件
    poco("com.bosma.smarthome:id/iv_toolbar_sub_icon").click()
    assert_exists(Template(r"tpl1544081980683.png", record_pos=(-0.001, -0.739), resolution=(1440, 2560)),"分享控件跳转正常")
    sleep(1)
    poco("转到上一层级").click()
    sleep(10)
    #s设备设置控件
    poco("com.bosma.smarthome:id/iv_toolbar_icon").click()
    assert_exists(Template(r"tpl1544082053345.png", record_pos=(0.001, -0.745), resolution=(1440, 2560)),"设备设置控件跳转正常")
    sleep(1)
    poco("转到上一层级").click()
    sleep(10)
    #监听控件
    poco("com.bosma.smarthome:id/rb_liveview_audio_listen").click()
    assert_exists(Template(r"tpl1544083018055.png", record_pos=(-0.174, 0.755), resolution=(1440, 2560)),"监听控件打开正常")
    sleep(1)
    #自动巡航控件
    poco("com.bosma.smarthome:id/turn_screen").click()
    assert_exists(Template(r"tpl1544083776388.png", record_pos=(-0.01, 0.51), resolution=(1440, 2560)),"自动巡航控件打开正常")
    sleep(1)
    #取消巡航
    poco("com.bosma.smarthome:id/turn_screen").click()
    #对比度调整
    poco("com.bosma.smarthome:id/rb_contast").click()
    sleep(8)
    assert_exists(Template(r"tpl1544084544353.png", record_pos=(0.006, 0.007), resolution=(1440, 2560)),"对比度调整控件打开正常")
    sleep(1)
    poco("com.bosma.smarthome:id/sb_sharpness").swipe([300/1920,100/1080],[500/1920,100/1080])
    poco("com.bosma.smarthome:id/bt_image_param_cancel").click()
    assert_exists(Template(r"tpl1544084680101.png", record_pos=(-0.001, 0.46), resolution=(1440, 2560)),"调整关闭成功")

if poco(text="博冠智能").exists():
    sleep(1)
    poco("com.bosma.smarthome:id/fl_mainblock_livevideo").click()
    if exists(Template(r"tpl1541040369573.png", record_pos=(0.424, -0.619), resolution=(1080, 1920))):
        poco("com.bosma.smarthome:id/iv_liveview").click()
        sleep(10)
        if exists(Template(r"tpl1544148303628.png", record_pos=(0.013, -0.288), resolution=(1440, 2560))):
            poco("转到上一层级").click()
            assert_exists(Template(r"tpl1544148466102.png", record_pos=(-0.011, -0.747), resolution=(1440, 2560)),"设备掉线中，退出liveview页面")

        else:
            commom()
    else:
        poco("转到上一层级").click()
        assert_exists(Template(r"tpl1544148556087.png", record_pos=(0.004, -0.742), resolution=(1440, 2560)),"账号下没有设备，退出操作")

else:
    commom_login()
    poco("com.bosma.smarthome:id/fl_mainblock_livevideo").click()
    if exists(Template(r"tpl1541040369573.png", record_pos=(0.424, -0.619), resolution=(1080, 1920))):
        poco("com.bosma.smarthome:id/iv_liveview").click()
        sleep(5)
        if assert_exists(Template(r"tpl1544148303628.png", record_pos=(0.013, -0.288), resolution=(1440, 2560))):
            poco("转到上一层级").click()
            assert_exists(Template(r"tpl1544148466102.png", record_pos=(-0.011, -0.747), resolution=(1440, 2560)),"设备掉线中，退出liveview页面")

        else:
            commom()

    else:
        poco("转到上一层级").click()
        assert_exists(Template(r"tpl1544148556087.png", record_pos=(0.004, -0.742), resolution=(1440, 2560)),"账号下没有设备，退出操作")


# --------------
#Importing header files
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

#Code starts here
data = pd.read_csv(path)

#Plotting Histogram
data['Rating'].hist()
data = data[data['Rating']<=5]
data['Rating'].hist()
#Code ends here

# --------------
# code starts here

# Finding null values
total_null = data.isnull().sum()
percent_null = (total_null/data.isnull().count())*100
missing_data = pd.concat([total_null,percent_null],axis=1,keys=['Total','Perceent'])
print(missing_data)

# Removing null values
data = data.dropna()
total_null_1 = data.isnull().sum()
percent_null_1 = (total_null/data.isnull().count())*100
missing_data_1 = pd.concat([total_null_1,percent_null_1],axis=1,keys=['Total','Perceent'])
print(missing_data_1)

# code ends here

# --------------

#Code starts here

# Rating of application in each category
sns.catplot(x="Category",y="Rating",data=data, kind="box", height = 10)
plt.xticks(rotation=90)

#Code ends here

# --------------
#Importing header files
from sklearn.preprocessing import MinMaxScaler, LabelEncoder

#Code starts here

#Converting type of Installs column
data['Installs'].value_counts()
data['Installs'] = data['Installs'].str.replace('+','')
data['Installs'] = data['Installs'].str.replace(',', "")
data['Installs'] = data['Installs'].astype(int)

#Label Encoding
le = LabelEncoder()
le.fit(data['Installs'])
data['Installs'] = le.transform(data['Installs'])

#Finding correlation
plt.figure(figsize = (14,10))
a = sns.regplot(x = "Installs", y = 'Rating', data = data)
a.axes.set_title('Rating vs Installs [RegPlot]', fontsize = 20)
a.set_xlabel("Installs", fontsize = 18)
a.set_ylabel("Rating", fontsize = 18)
a.tick_params(labelsize = 8)

#Code ends here

# --------------
#Code starts here

#Converting type of price column to float
data['Price'].value_counts()
data['Price'] = data['Price'].str.replace("$","")
data['Price'] = data['Price'].astype(float)

#Checking Correlation
plt.figure(figsize = (14,10))
a = sns.regplot(x = "Price", y = 'Rating', data = data)
a.axes.set_title('Rating vs Price [RegPlot]', fontsize = 20)
a.set_xlabel("Price", fontsize = 18)
a.set_ylabel("Rating", fontsize = 18)
a.tick_params(labelsize = 8)

#Code ends here

# --------------

#Code starts here

#Checking relation in between Genres and Rating
data['Genres'].unique()
a=[]
for i in data['Genres'] :
    a.append(i.split(';')[0])

data['Genres'] = a
gr_mean = data.groupby('Genres', as_index = False)['Rating'].mean()
gr_mean.describe()

gr_mean = gr_mean.sort_values(by = 'Rating')
print(gr_mean.iloc[0], gr_mean.iloc[-1])

#Code ends here

# --------------

#Code starts here

#Comparing Rating and Last Updated
data['Last Updated']
data['Last Updated'] = pd.to_datetime(data['Last Updated'])
max_date = data['Last Updated'].max()
data['Last Updated Days'] = (max_date - data['Last Updated']).dt.days

plt.figure(figsize = (14,10))
a = sns.regplot(x = "Last Updated Days", y = 'Rating', data = data)
a.set_xlabel('Last Updated Days', fontsize = 15)
a.set_ylabel('Rating', fontsize = 15)
a.axes.set_title('Rating vs Last Updated [RegPlot]')
a.tick_params(labelsize = 13)
#Code ends here


from django.conf import settings
from django.conf.urls import patterns, include, url
from django.conf.urls.static import static
from django.contrib import admin

urlpatterns = patterns('',
    url(r'^$', 'blog.views.home', name='home'),

    url(r'^contents/$', 'blog.views.contents', name='contents'),
    url(r'^post/(\d+)/$', 'blog.views.single_post', name='post'),
    url(r'^post/(\d+)/fav/$', 'blog.views.favourite', name='mark-fav'),
    url(r'^post/(\d+)/unfav/$', 'blog.views.unfavourite', name='mark-unfav'),
    url(r'^category/(\w+)/$', 'blog.views.category', name='category'),

    url(r'^new-post/$', 'blog.views.new_post', name='new_post'),
    url(r'^feedback/$', 'blog.views.feedback', name='feedback'),

    url(r'^accounts/login/$', 'django.contrib.auth.views.login', name="login"),
    url(r'^accounts/logout/$', 'django.contrib.auth.views.logout_then_login', name="logout"),

    # url(r'^blog/', include('blog.urls')),

    url(r'^admin/', include(admin.site.urls)),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


'''
This progam asks for a user file,
then takes the number values from the file and reads its contents
to determine different values. Made for homework 10
By: Saad'''

import os
import statistics
def main():
    fileName = input("Please enter a full filename: ").strip()
    if os.path.isfile(fileName):
        inputFile = open(fileName,"r")
        s = inputFile.read()
        scores = [eval(x)for x in s.split()]
        print("The total of the file is", sum(scores))
        print("There mean of the file is:", statistics.mean(scores))
        print("There median of the file is:", statistics.median(scores))
        print("The smallest number of the file is", min(scores))
        print("The largest number of the file is", max(scores))
        inputFile.close()
    else:
        print("Failed to open a file!")

main()


class Tank:
    def __init__(self, armor, penetration, armor_type):
        self.armor = armor
        self.penetration = penetration
        self.armor_type = armor_type
        if armor_type not in ['chobham', 'composite', 'ceramic']:
            raise Exception('Invalid armor type %s' % (armor_type))
        self.tank = "Tank"

    def set_name(self, name):
        self.name = name

    def vulnerable(self, tank):
        real_armor = self.armor
        if self.armor_type == 'chobham':
            real_armor += 100
        else:
            real_armor += 50
        if real_armor <= tank.penetration:
            return True
        return False

    def swap_armor(self, othertank):
        self.armor, othertank.armor = othertank.armor, self.armor
        return othertank

    def __repr__(self):
        return self.name.lower().replace(' ', '-')

def test_tank_safe(shooter, test_vehicles=[]):
    for t in test_vehicles:
        if not t.vulnerable(shooter):
            print("A tank is safe")
            return True
    print("No tank is safe")
    return False

m1_1 = Tank(600, 670, 'chobham')
m1_2 = Tank(620, 670, 'chobham')
if m1_1.vulnerable(m1_2) is True:
    print('Vulnerable to tank m1_2')

m1_1.swap_armor(m1_2)
tanks = []
for i in range(5):
    #tanks.append(Tank(400, 400, 'steel')) # exception : steel isn't a valid armor type
    tanks.append(Tank(400, 400, 'composite'))
index = 0
for tank in tanks:
    tank.set_name('Tank' + str(index) + "_Small")
    index += 1
test = []

index = 0
while index < len(tanks):
    test.append(tanks[i].vulnerable(m1_1))
    index += 1

test_tank_safe(m1_1, tanks)