Departamento de Ciência da Computação - IME - USP

MAC2166 Introdução à Computação

Escola Politécnica - Primeiro Semestre de 2015

Prova 2


QUESTÃO 1

Nessa quest�o, considere uma vers�o simplificada do jogo Sokoban. As constantes definidas abaixo devem ser obrigatoriamente utilizadas nessa quest�o, sem precisar redefini-las. Observe que h� apenas 4 elementos poss�veis em um mapa simplificado, e tamb�m apenas 4 movimentos poss�veis.

    # elementos poss�veis em um mapa
    CAIXA   = '$'
    JOGADOR = '@'
    PAREDE  = '#'
    VAZIO   = ' '  # espa�o indicando piso vazio
    
    # movimentos poss�veis
    BAIXO   = 'b'
    CIMA    = 'c'
    DIR     = 'd'
    ESQ     = 'e'
  
Considere tamb�m as seguintes quatro fun��es:
    def  carregaMapa():
        """(None) -> mapa

        Retorna um mapa com uma configura��o simplificada 
        de Sokoban.

        Um mapa � uma lista de listas de strings (caracteres) como no EP,
        s�o cercados por paredes e sempre possuem um �nico jogador. N�o �
        necess�rio verificar se o mapa � v�lido.
        """
        [...]

    def achaJogador(mapa):
        """(mapa) -> int, int

        Retorna a posi��o (lin,col) do jogador ou None caso n�o existir
        jogador no mapa
        """
        [...]


    def imprimeMapa(mapa):
        """(mapa) -> None

        Imprime um mapa com moldura
        """
        [...]
    
    def moveJogador(mapa, mov):
        """(mapa, str) -> bool, bool, int, int

        Recebe um mapa e um movimento mov.  Se mov � v�lido, a fun��o
        atualiza mapa e retorna os seguintes 4 valores:
        
        - 1) True indicando que mov � v�lido
        - 2) True/False indicando se uma 
        caixa foi empurrada
        - 3) nova linha do jogador.
        - 4) nova coluna do jogador.

        Caso o movimento seja inv�lido, retorna False, False, -1, -1.
        """
        [...]    
  

Nos 3 itens dessa quest�o, voc� deve escrever um programa (fun��o main() e as fun��es achaJogador() e moveJogador(). N�o � permitido modificar o prot�tipo dessas fun��es.

O programa deve simular os movimentos do jogador de acordo com uma sequ�ncia de movimentos dada. Como no EP, em um movimento v�lido, o jogador pode se mover para posi��es vazias ou empurrar uma caixa para uma posi��o vazia. Movimentos inv�lidos s�o aqueles que tentam mover o jogador para uma posi��o com parede ou com uma caixa presa, ou seja, encostada na parede ou encostada em outra caixa.

Item (a)
Escreva um programa (fun��o main()) que carrega um mapa, l� uma sequ�ncia movs de movimentos na forma de um �nico string, realiza os movimentos v�lidos atualizando o mapa e enviando mensagens exatamente como no exemplo abaixo. Ao final o programa deve imprimir as jogadas v�lidas realizadas, sendo que os movimentos que resultaram em empurr�es de caixas devem ser impressos em letras mai�sculas, como no EP.

O string com os movimentos pode conter qualquer sequ�ncia dos seguintes caracteres: 'b', 'c', 'd', 'e' ('b' = baixo, 'c' = cima, 'd''e' = esquerda). Um movimento no string s� deve ser realizado se for v�lido. Movimentos inv�lidos devem ser ignorados, e o processo deve continuar processando os movimentos seguintes, at� o final do string.

O seu programa deve utilizar, obrigatoriamente, todas as fun��es descritas anteriormente, a saber: carregaMapa(), imprimeMapa(), achaJogador() e moveJogador(), sem escrev�-las (a achaJogador() ser� escrita no item b e a moveJogador() ser� escrita no item c.

Exemplo de execu��o para a sequ�ncia de comandos (string) "bbdc" (que � digitada pelo usu�rio, ap�s o programa exibir a configura��o inicial). Lembre-se que o seu programa deve imprimir mensagens exatamente como nesse exemplo.

Configura��o inicial:
      0   1   2   3   4   5   6  
    +---+---+---+---+---+---+---+
  0 |   |   | # | # | # |   |   |
    +---+---+---+---+---+---+---+
  1 |   | # |   | @ |   | # |   |
    +---+---+---+---+---+---+---+
  2 | # |   |   | $ |   |   | # |
    +---+---+---+---+---+---+---+
  3 | # |   |   |   |   | $ | # |
    +---+---+---+---+---+---+---+
  4 | # |   |   | $ |   |   | # |
    +---+---+---+---+---+---+---+
  5 |   | # |   |   |   | # |   |
    +---+---+---+---+---+---+---+
  6 |   |   | # | # | # |   |   |
    +---+---+---+---+---+---+---+
Posi��o inicial: 1, 3

Digite seus movimentos: bbdc 

>>>> Movimento b v�lido

      0   1   2   3   4   5   6  
    +---+---+---+---+---+---+---+
  0 |   |   | # | # | # |   |   |
    +---+---+---+---+---+---+---+
  1 |   | # |   |   |   | # |   |
    +---+---+---+---+---+---+---+
  2 | # |   |   | @ |   |   | # |
    +---+---+---+---+---+---+---+
  3 | # |   |   | $ |   | $ | # |
    +---+---+---+---+---+---+---+
  4 | # |   |   | $ |   |   | # |
    +---+---+---+---+---+---+---+
  5 |   | # |   |   |   | # |   |
    +---+---+---+---+---+---+---+
  6 |   |   | # | # | # |   |   |
    +---+---+---+---+---+---+---+
O jogador moveu uma caixa
O jogador est� na posi��o: 2, 3

>>>> Movimento b inv�lido

>>>> Movimento d v�lido

      0   1   2   3   4   5   6  
    +---+---+---+---+---+---+---+
  0 |   |   | # | # | # |   |   |
    +---+---+---+---+---+---+---+
  1 |   | # |   |   |   | # |   |
    +---+---+---+---+---+---+---+
  2 | # |   |   |   | @ |   | # |
    +---+---+---+---+---+---+---+
  3 | # |   |   | $ |   | $ | # |
    +---+---+---+---+---+---+---+
  4 | # |   |   | $ |   |   | # |
    +---+---+---+---+---+---+---+
  5 |   | # |   |   |   | # |   |
    +---+---+---+---+---+---+---+
  6 |   |   | # | # | # |   |   |
    +---+---+---+---+---+---+---+
O jogador est� na posi��o: 2, 4


>>>> Movimento c v�lido

      0   1   2   3   4   5   6  
    +---+---+---+---+---+---+---+
  0 |   |   | # | # | # |   |   |
    +---+---+---+---+---+---+---+
  1 |   | # |   |   | @ | # |   |
    +---+---+---+---+---+---+---+
  2 | # |   |   |   |   |   | # |
    +---+---+---+---+---+---+---+
  3 | # |   |   | $ |   | $ | # |
    +---+---+---+---+---+---+---+
  4 | # |   |   | $ |   |   | # |
    +---+---+---+---+---+---+---+
  5 |   | # |   |   |   | # |   |
    +---+---+---+---+---+---+---+
  6 |   |   | # | # | # |   |   |
    +---+---+---+---+---+---+---+
O jogador est� na posi��o: 1, 4

Os movimentos v�lidos foram: 
Bdc

SOLU��O

def main():
    mapa = carregaMapa()

    print("Configura��o inicial:")
    imprimaMapa(mapa)
    lin, col  = achaJogador(mapa)
    print("Posi��o inicial: %d, %d\n"%(lin, col))

    movs = input("Digite seus movimentos: ")
 
    historico = '' 
    for mov in movimentoss:
        mov_valido, moveu_caixa, lin, col = moveJogador(mapa, mov)
        if mov_valido:
            print()
            print(">>>> Movimento", mov, "v�lido\n")
            imprimaMapa(mapa)

            if moveu_caixa:
                print("O jogador moveu uma caixa")
                historico += mov.upper()
            else:
                historico += mov
            print("O jogador est� na posi��o: %d, %d"%(lin, col))
            print()
        else:
            print(">>>> Movimento", mov, "inv�lido\n")
    print("Os movimentos v�lidos foram: ")
    print(historico)

Item (b)
Escreva a fun��o achaJogador().

SOLU��O

def achaJogador(mapa):
    """(mapa) -> int, int

    Retorna a posi��o do jogador ou None caso n�o existir jogador no
    mapa
    """
    for lin in range(len(mapa)):
        for col in range(len(mapa[lin])):
            if mapa[lin][col] == JOGADOR:
                return lin, col
    return None, None

Item (c)
Escreva a fun��o moveJogador(). Voc� pode usar a fun��o achaJogador(), sem escrev�-la, mesmo que n�o a tenha feito.

SOLU��O

def moveJogador(mapa, mov):
    """ (mapa, str) -> bool, bool, int, int

    Recebe um mapa e um movimento, e se o movimento � v�lido
    atualiza o mapa e retorna, 4 valores.

        - 1o valor True indicando que o movimento � v�lido
        - 2o valor True ou False indicando se uma caixa foi empurrada.
        - 3o indicando a nova linha  do jogador.
        - 4o indicando a nova coluna do jogador.
        
    Caso o movimento seja inv�lido, retorna False, False, -1, -1.
    """
    # pegue posi��o do jogador
    lin,col = achaJogador(mapa)

    # calcule o vetor deslocamente [dlin][dcol]
    if mov == BAI:
        dlin, dcol =  1,  0
    elif mov == CIM:
        dlin, dcol = -1,  0
    elif mov == DIR:
        dlin, dcol =  0,  1
    elif mov == ESQ:
        dlin, dcol =  0, -1
    else:
        # OK se assumir mov v�lido, e remover esse else.
        return False, False, -1, -1

    if mapa[lin+dlin][col+dcol] == PAREDE:
        return False, False, -1, -1
    elif mapa[lin+dlin][col+dcol] == CAIXA and \
         mapa[lin+2*dlin][col+2*dcol] != VAZIO:
        return False, False, -1, -1

    # movimento � v�lido
    if mapa[lin+dlin][col+dcol] == CAIXA:
        tem_caixa = True
        mapa[lin+2*dlin][col+2*dcol] = CAIXA
    else:
        tem_caixa = False

    # mova jogador    
    mapa[lin+dlin][col+dcol] = JOGADOR

    # apague rastro
    mapa[lin][col] = VAZIO

    return True, tem_caixa, lin+dlin, col+dcol

QUESTÃO 2

Escreva uma fun��o em Python que dada uma matriz de inteiros bin�ria (isto �, contendo valores 0 ou 1) devolve uma segunda matriz correspondendo ao menor recorte retangular da primeira, que cont�m todos elementos com valores iguais a 1 (matriz delimitadora m�nima).

OBS: Assuma que a matriz sempre tem pelo menos um elemento com valor 1.

Exemplo: Para a matriz de entrada:

matriz original

A nova matriz criada e devolvida pela fun��o ser�:

recorte

SOLUÇÃO

def recorte_retangular(matriz):
    ''' (matriz) -> submatriz

    Recebe uma matriz e crie e retorna uma matriz que 
    � o menor recorte retangular da matriz dada.
    '''
    n_lin = len(matriz)
    n_col = len(matriz[0])

    # encontra limites da matriz
    lin_ini = n_lin
    lin_fim = 0
    col_ini = n_col
    col_fim = 0
    for i in range(n_lin):
        for j in range(n_col):
            if matriz[i][j] == 1:
                if i < lin_ini:
                    lin_ini = i
                if i + 1 > lin_fim:
                    lin_fim = i + 1
                if j < col_ini:
                    col_ini = j
                if j + 1 > col_fim:
                    col_fim = j + 1

    # constroi recorte                
    submatriz = []
    for i in range(lin_ini,lin_fim):
        linha = []
        for j in range(col_ini,col_fim):
            linha.append(matriz[i][j])
        submatriz.append(linha)

    return submatriz    

 

 

 


Last modified: Wed Jun 10 08:30:25 BRT 2015