I've tried to make the code overall more PEP-8 friendly and added more comments to make it more readable. Added some new functions and methods like ranged attack and allegiance.Play around with it. Use a to give characters more moves, s to spawn more characters, d to spawn Goblins that move randomly, f to attack and q to ranged attack. Here is the full code, tell me how I can shorten it but retain the same functionality:import randomimport mathimport pygamepygame.init()   #Starting pygame ...                                Clock = pygame.time.Clock()                   Screen = pygame.display.set_mode([650, 650])  DONE = False    #Main game loop variable                                 MAPSIZE = 25   #how many tiles in the gridTURN = 0    #incemented to keep track of turn numberTILEWIDTH  = 20    #pixel size of tiles drawn                               TILEHEIGHT = 20TILEMARGIN = 4BLACK = (0, 0, 0)                               WHITE = (255, 255, 255)GREEN = (0, 255, 0)RED = (255, 0, 0)BLUE = (0, 0, 255)BROWN = (123, 123, 0)MOVECOLOR = (150, 250, 150)KeyLookup = {    pygame.K_LEFT: W,    pygame.K_RIGHT: E,    pygame.K_DOWN: S,    pygame.K_UP: N}class MapTile(object):                       #The main class for stationary things that inhabit the grid ... grass, trees, rocks and stuff.    def __init__(self, name, internal_column, internal_row, visible):        self.name = name        self.internal_column = internal_column        self.internal_row = internal_row        self.visible = visibleclass Character(object):                    #can move around and do cool stuff    def __init__(self, name, HP, internal_column, internal_row, damage, allegiance):        self.name = name        self.HP = HP        self.internal_column = internal_column        self.internal_row = internal_row        self.damage = damage        self.allegiance = allegiance    #allegiance is either 0 or 1, 0 being friendly and 1 being enemy    visionrange = 5    moves_left = 15    direction = N    def move(self, direction):      #how characters move around        if self.collision_check(direction):            print(Collision)            return        if self.moves_left == 0:            print(No more moves left)            return        elif direction == N:                                    self.internal_row -= 1                self.direction = N        elif direction == W:                self.internal_column -= 1                self.direction = W        elif direction == E:                self.internal_column += 1                self.direction = E        elif direction == S:                self.internal_row += 1                self.direction = S        self.moves_left = self.moves_left - 1    def collision_check(self, direction): #Checks the grid square right infront of the character to see if anything is there              if direction == N:            if self.internal_row == 0:                return True            if len(Map.Grid[self.internal_column][(self.internal_row)-1]) > 1:                return True        elif direction == W:            if self.internal_column == 0:                return True            if len(Map.Grid[self.internal_column-1][(self.internal_row)]) > 1:                return True        elif direction == E:            if self.internal_column == MAPSIZE-1:                return True            if len(Map.Grid[self.internal_column+1][(self.internal_row)]) > 1:                return True        elif direction == S:            if self.internal_row == MAPSIZE-1:                return True            if len(Map.Grid[self.internal_column][(self.internal_row)+1]) > 1:                return True        return False    def attack(self, direction):    #Attacks square right infront of character        if self.collision_check(direction):            print(Attack attempt.)            if self.direction == N:              for i in range(0, len(Map.Grid[self.internal_column][self.internal_row-1])):                if Map.Grid[int(self.internal_column)][int(self.internal_row-1)][i].__class__.__name__ == Character:                    Map.Grid[self.internal_column][self.internal_row-1][i].HP -= self.damage                    print(str(self.damage) +  damage)            elif self.direction == E:                for i in range(0, len(Map.Grid[self.internal_column+1][self.internal_row])):                    if Map.Grid[self.internal_column+1][self.internal_row][i].__class__.__name__ == Character:                        Map.Grid[self.internal_column+1][self.internal_row][i].HP -= self.damage                        print(str(self.damage) +  damage)            elif self.direction == W:                for i in range(0, len(Map.Grid[self.internal_column-1][self.internal_row])):                    if Map.Grid[self.internal_column-1][self.internal_row][i].__class__.__name__ == Character:                        Map.Grid[self.internal_column-1][self.internal_row][i].HP -= self.damage                        print(str(self.damage) +  damage)            elif self.direction == S:                for i in range(0, len(Map.Grid[self.internal_column][self.internal_row+1])):                    if Map.Grid[self.internal_column][self.internal_row+1][i].__class__.__name__ == Character:                        Map.Grid[self.internal_column][self.internal_row+1][i].HP -= self.damage                        print(str(self.damage) +  damage)            self.moves_left = self.moves_left - 1    def ranged_attack(self, direction):             if self.direction == S:                for k in range(1, (MAPSIZE - self.internal_row)):                    for i in range(0, len(Map.Grid[self.internal_column][self.internal_row + k])):                        if Map.Grid[self.internal_column][self.internal_row + k][i].__class__.__name__ == Character:                            Map.Grid[self.internal_column][self.internal_row + k][i].HP -= self.damage                            print(str(self.damage) +  damage)                            self.moves_left = self.moves_left - 1             if self.direction == N:                for k in range(1, self.internal_row):                    for i in range(0, len(Map.Grid[self.internal_column][self.internal_row - k])):                        if Map.Grid[self.internal_column][self.internal_row - k][i].__class__.__name__ == Character:                            Map.Grid[self.internal_column][self.internal_row - k][i].HP -= self.damage                            print(str(self.damage) +  damage)                            self.moves_left = self.moves_left - 1            if self.direction == W:                for k in range(1, self.internal_column):                    for i in range(0, len(Map.Grid[self.internal_column - k][self.internal_row])):                        if Map.Grid[self.internal_column - k][self.internal_row][i].__class__.__name__ == Character:                            Map.Grid[self.internal_column - k][self.internal_row][i].HP -= self.damage                            print(str(self.damage) +  damage)                            self.moves_left = self.moves_left - 1            if self.direction == E:                for k in range(1, (MAPSIZE - self.internal_column)):                    for i in range(0, len(Map.Grid[self.internal_column + k][self.internal_row])):                        if Map.Grid[self.internal_column + k][self.internal_row][i].__class__.__name__ == Character:                            Map.Grid[self.internal_column + k][self.internal_row][i].HP -= self.damage                            print(str(self.damage) +  damage)                            self.moves_left = self.moves_left - 1            else:                return class Goblin(Character):    #Character that moves around randomly. Press d to summon one    def __init__(self):        Character.__init__(self, Goblin, random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1), 10, random.randint(0,1))    def random_move(self):        i = random.randint(0,3)        if i == 0:            self.move(N)        elif i == 1:            self.move(S)        elif i == 2:            self.move(W)        elif i == 3:            self.move(E)        self.moves_left = 10class Archer(Character):    def __init__(self):        Character.__init__(self, Archer, random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))class Warrior(Character):    def __init__(self):        Character.__init__(self, Warrior, random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))class Scout(Character):    def __init__(self):        Character.__init__(self, Scout, random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))class Rogue(Character):    def __init__(self):        Character.__init__(self, Rogue, random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))class Wizard(Character):    def __init__(self):        Character.__init__(self, Wizard, random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))class Map(object):              #The main class    global MAPSIZE    wild_characters = []    #Where goblins go    can_move = []   #Where characters with moves left are    no_moves = []    Grid = []    friendlies = []    enemies = []    everyone = []    visible = []    for row in range(MAPSIZE):     # Creating grid        Grid.append([])        for column in range(MAPSIZE):            Grid[row].append([])    for row in range(MAPSIZE):     #Filling grid with grass        for column in range(MAPSIZE):            TempTile = MapTile(Grass, column, row, False)            Grid[column][row].append(TempTile)    for row in range(MAPSIZE):     #Putting some rocks near the top        for column in range(MAPSIZE):            TempTile = MapTile(Rock, column, row, False)            if row == 1:                Grid[column][row].append(TempTile)    for i in range(10):         #Trees in random places        random_row = random.randint(0, MAPSIZE - 1)        random_column = random.randint(0, MAPSIZE - 1)        TempTile = MapTile(Tree, random_column, random_row, False)        Grid[random_column][random_row].append(TempTile)    def generate_hero(self):            #Generate a character and place it randomly        temp_hero = Character(Hero, 30, random.randint(0, MAPSIZE - 1), random.randint(0, MAPSIZE - 1) , 10, random.randint(0,1))        self.Grid[temp_hero.internal_column][temp_hero.internal_row].append(temp_hero)        self.can_move.append(temp_hero)        if temp_hero.allegiance == 0:            self.friendlies.append(temp_hero)        elif temp_hero.allegiance == 1:            self.enemies.append(temp_hero)    def return_distance(self, pointA, pointB):  #Gives distance between two points or characters        distance = math.sqrt((pointA.internal_column - pointB.internal_column)**2 + (pointA.internal_row - pointB.internal_row)**2)        return distance    def generate_goblin(self):            #Generate a character and place it randomly        random_row = random.randint(0, MAPSIZE - 1)        random_column = random.randint(0, MAPSIZE - 1)        temp_goblin = Goblin()        self.Grid[random_column][random_row].append(temp_goblin)        Map.wild_characters.append(temp_goblin)    def update(self):                   for column in range(MAPSIZE):                           #These nested loops go through entire grid             for row in range(MAPSIZE):                          #They check if any objects internal coordinates                for i in range(len(Map.Grid[column][row])):     #disagree with its place on the grid and update it accordingly                                                if Map.Grid[column][row][i].internal_column != column:                        TempChar = Map.Grid[column][row][i]                        Map.Grid[column][row].remove(Map.Grid[column][row][i])                        Map.Grid[int(TempChar.internal_column)][int(TempChar.internal_row)].append(TempChar)                    elif Map.Grid[column][row][i].internal_row != row:                        TempChar = Map.Grid[column][row][i]                        Map.Grid[column][row].remove(Map.Grid[column][row][i])                        Map.Grid[int(TempChar.internal_column)][int(TempChar.internal_row)].append(TempChar)        temparr = Map.no_moves[:]        for characterobject in temparr:    #This moves any characters with moves to the can move list             if len(temparr) > 0:                if characterobject.moves_left > 0:                    Map.can_move.append(characterobject)                    Map.no_moves.remove(characterobject)            if characterobject.HP <= 0:                Map.no_moves.remove(characterobject)        arr = Map.can_move[:]         for item in arr:    #This moves characters from can_move to no_moves when they run out of moves            if item.moves_left == 0:                Map.can_move.remove(item)                Map.no_moves.append(item)            if item.HP <= 0:                Map.can_move.remove(item)        for column in range(MAPSIZE):   #This checks entire grid for any dead characters and removes them                                      for row in range(MAPSIZE):                                          for i in range(len(Map.Grid[column][row])):                         if Map.Grid[column][row][i].__class__.__name__ == Character:                        if Map.Grid[column][row][i].HP <= 0:                            Map.Grid[column][row].remove(Map.Grid[column][row][i])                            print(Character died)        for column in range(MAPSIZE):   #This appends any character in the grid to Map.everyone            for row in range(MAPSIZE):                for i in range(len(Map.Grid[column][row])):                    if Map.Grid[column][row][i].__class__.__name__ == Character:                        Map.everyone.append(Map.Grid[column][row][i])        for character in Map.everyone:  #Showing visible                       for column in range(MAPSIZE):                for row in range(MAPSIZE):                    if Map.return_distance(Map.Grid[column][row][0], character ) <= character.visionrange:                        Map.Grid[column][row][0].visible = True                    else:                        Map.Grid[column][row][0].visible = False    def listofcharacters(self): #This returns the coordinates and allegiance of any characters that inhabit the grid        for column in range(MAPSIZE):            for row in range(MAPSIZE):                for i in range(len(Map.Grid[column][row])):                    if Map.Grid[column][row][i].__class__.__name__ == Character:                        print(Column: , Map.Grid[column][row][i].internal_column, , Row: , Map.Grid[column][row][i].internal_row, , Allegiance: , Map.Grid[column][row][i].allegiance)Map = Map()Map.generate_hero()while not DONE:     #Main pygame loop    for event in pygame.event.get():         #catching events        if event.type == pygame.QUIT:            DONE = True               elif event.type == pygame.MOUSEBUTTONDOWN:            Pos = pygame.mouse.get_pos()            column = Pos[0] // (TILEWIDTH + TILEMARGIN)  #Translating the position of the mouse into rows and columns            row = Pos[1] // (TILEHEIGHT + TILEMARGIN)            print(str(row) + ,  + str(column))            for i in range(len(Map.Grid[column][row])):                print(str(Map.Grid[column][row][i].name))  #print stuff that inhabits that square        elif event.type == pygame.KEYDOWN:            wild_char_arr = Map.wild_characters[:]            for wildcharacter in wild_char_arr:     #Making the goblins move randomly every time a key is pressed                if wildcharacter.name == Goblin:                    wildcharacter.random_move()             if event.key == 97:      # Keypress: a                print(New turn.)                temparr = Map.no_moves[:]                for item in temparr:                    if item.moves_left == 0:                        item.moves_left = 15                TURN = TURN + 1                print(Turn: , TURN)            elif event.key == 115:    # Keypress: s                print(Generated hero.)                Map.generate_hero()            elif event.key == 113:    # Keypress: q                     print(ranged attack)                Map.can_move[0].ranged_attack(Map.can_move[0].direction)            elif event.key == 119:    # Keypress: w                print(Generated hero.)                Map.generate_hero()            elif event.key == 101:    # Keypress: e                print(Generated hero.)                Map.generate_hero()            elif event.key == 114:    # Keypress: r                print(Generated hero.)                Map.generate_hero()            elif event.key == 116:    # Keypress: t                print(Generated hero.)                Map.generate_hero()            elif event.key == 100:  # Keypress: d                Map.generate_goblin()                print(Generated goblin.)            elif event.key == 102:  # Keypress: f                Map.can_move[0].attack(Map.can_move[0].direction)             elif len(Map.can_move) > 0: #Movement                Map.can_move[0].move(KeyLookup[event.key])            else:                print(invalid)            Map.update()    Screen.fill(BLACK)    for row in range(MAPSIZE):           # Drawing grid        for column in range(MAPSIZE):            for i in range(0, len(Map.Grid[column][row])):                Color = WHITE                if len(Map.can_move) > 0:   # Creating colored area around character showing his move range                    if (math.sqrt((Map.can_move[0].internal_column - column)**2 + (Map.can_move[0].internal_row - row)**2)) <= Map.can_move[0].moves_left:                        Color = MOVECOLOR                if len(Map.Grid[column][row]) > 1:                    Color = RED                if Map.Grid[column][row][i].name == Tree:                    Color = GREEN                if str(Map.Grid[column][row][i].__class__.__name__) == Character:                    Color = BROWN            pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN,                                             (TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN,                                             TILEWIDTH,                                             TILEHEIGHT])            if str(Map.Grid[column][row][i].__class__.__name__) == Character:     #Drawing the little red square showing character direction                if Map.Grid[column][row][i].direction == N:                        Color = RED                    pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN + 8,                                             (TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN,                                             TILEWIDTH/4,                                             TILEHEIGHT/4])            if str(Map.Grid[column][row][i].__class__.__name__) == Character: #Drawing the little red square showing character directio                if Map.Grid[column][row][i].direction == S:                    Color = RED                    pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN + 8,                                             (TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN*5 - 1 ,                                             TILEWIDTH/4,                                             TILEHEIGHT/4])            if str(Map.Grid[column][row][i].__class__.__name__) == Character: #Drawing the little red square showing character directio                if Map.Grid[column][row][i].direction == E:                    Color = RED                    pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN + 15,                                             (TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN*5 - 8,                                             TILEWIDTH/4,                                             TILEHEIGHT/4])            if str(Map.Grid[column][row][i].__class__.__name__) == Character: #Drawing the little red square showing character directio                if Map.Grid[column][row][i].direction == W:                    Color = RED                    pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN                                                     ,                                             (TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN*5 - 8 ,                                             TILEWIDTH/4,                                             TILEHEIGHT/4])    Clock.tick(60)          pygame.display.flip()     pygame.quit()
Beginner grid-based game movement engine (PART 2)
python;object oriented;game;array;python 3.x