# Museu de Artes — Prova P2 - Algoritmos
# Requisitos: funções, listas, dicionários, ordenação (merge sort), busca (binária/linear), arquivos, exceções.
from typing import List, Dict, Any
ARQUIVO = "museu_dados.json"
# ---------------------------
# Persistência (arquivo JSON)
# ---------------------------
def carregar() -> Dict[str, Any]:
with open(ARQUIVO, "r", encoding="utf-8") as f:
# garantir chaves mínimas
if not isinstance(dados, dict):
raise ValueError("Formato inválido no arquivo.")
for k in ("obras", "artistas", "estilos", "emprestimos", "roteiros"):
except FileNotFoundError:
return {"obras": [], "artistas": [], "estilos": [], "emprestimos": [], "roteiros": []}
except json.JSONDecodeError:
print("Aviso: arquivo JSON corrompido. Iniciando base vazia.")
return {"obras": [], "artistas": [], "estilos": [], "emprestimos": [], "roteiros": []}
print("Erro ao carregar dados:", e)
return {"obras": [], "artistas": [], "estilos": [], "emprestimos": [], "roteiros": []}
def salvar(dados: Dict[str, Any]) -> None:
with open(ARQUIVO, "w", encoding="utf-8") as f:
json.dump(dados, f, ensure_ascii=False, indent=2, default=str)
print("Erro ao salvar:", e)
# ---------------------------
# Algoritmo de Ordenação: Merge Sort
# ---------------------------
def merge_sort_obras(obras: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""Ordena lista de obras pelo campo 'titulo' (case-insensitive) usando merge sort."""
left = merge_sort_obras(obras[:mid])
right = merge_sort_obras(obras[mid:])
return _merge(left, right)
def _merge(left: List[Dict[str, Any]], right: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
while i < len(left) and j < len(right):
lt = (left[i].get("titulo") or "").lower()
rt = (right[j].get("titulo") or "").lower()
result.append(left[i]); i += 1
result.append(right[j]); j += 1
# ---------------------------
# ---------------------------
def busca_linear_por_titulo(obras: List[Dict[str, Any]], termo: str) -> List[Dict[str, Any]]:
return [o for o in obras if termo in (o.get("titulo") or "").lower()]
def busca_binaria_exata(obras_ordenadas: List[Dict[str, Any]], titulo: str) -> int:
"""Retorna índice da obra com título exatamente igual (case-insensitive) ou -1 se não encontrar."""
low, high = 0, len(obras_ordenadas) - 1
mid_title = (obras_ordenadas[mid].get("titulo") or "").lower()
# ---------------------------
# Funções de domínio (CRUD mínimo)
# ---------------------------
def cadastrar_artista(dados):
nome = input("Nome do artista: ").strip()
data_nasc = input("Data de nascimento (YYYY-MM-DD) ou vazio: ").strip()
local_nasc = input("Local de nascimento: ").strip()
bio = input("Biografia (curta): ").strip()
estilos = input("Estilos associados (separar por vírgula): ").strip().split(",")
estilos = [s.strip() for s in estilos if s.strip()]
"id": f"art_{len(dados['artistas'])+1}",
"data_nasc": data_nasc or None,
"local_nasc": local_nasc,
dados["artistas"].append(artista)
print("Artista cadastrado!")
def cadastrar_estilo(dados):
denom = input("Denominação do estilo: ").strip()
periodo = input("Período de influência: ").strip()
desc = input("Descrição das características: ").strip()
escola = input("Escola principal representativa: ").strip()
"id": f"est_{len(dados['estilos'])+1}",
dados["estilos"].append(estilo)
print("Estilo cadastrado!")
def cadastrar_obra(dados):
titulo = input("Título da obra: ").strip()
data_criacao = input("Data de criação (YYYY ou YYYY-MM-DD) ou vazio: ").strip()
tema = input("Tema: ").strip()
estilo = input("Estilo artístico (nome): ").strip()
descricao = input("Descrição: ").strip()
tecnica = input("Técnica utilizada: ").strip()
autor = input("Autor (nome): ").strip()
local_sala = input("Localização na sala/exposição: ").strip()
# documentos: lista de strings representando arquivos/descrições
doc = input("Adicionar documento relacionado (enter para parar): ").strip()
# pessoa retratada (opcional)
resposta = input("Obra retrata uma figura proeminente? (s/n): ").strip().lower()
nome_pessoa = input("Nome da pessoa retratada: ").strip()
pesquisa = input("Breve pesquisa sobre a pessoa: ").strip()
retratada = {"nome": nome_pessoa, "pesquisa": pesquisa}
"id": f"obra_{len(dados['obras'])+1}",
"data_criacao": data_criacao or None,
"local_sala": local_sala,
"documentos": documentos,
"pessoa_retratada": retratada,
"historico_emprestimos": []
dados["obras"].append(obra)
print("Obra cadastrada com sucesso!")
def registrar_emprestimo(dados):
titulo = input("Título da obra a emprestar (procure exato ou use busca): ").strip()
obras_ordenadas = merge_sort_obras(dados["obras"])
idx = busca_binaria_exata(obras_ordenadas, titulo)
print("Título não encontrado exatamente. Faça uma busca parcial.")
encontrados = busca_linear_por_titulo(dados["obras"], titulo)
print("Nenhuma obra encontrada para empréstimo.")
print("Resultados parciais:")
for i, o in enumerate(encontrados, 1):
print(f"{i}. {o['titulo']} (ID: {o['id']})")
escolha = input("Escolha número ou 0 para cancelar: ").strip()
obra = encontrados[escolha - 1]
print("Escolha inválida.")
obra = obras_ordenadas[idx]
data_inicio = input("Data início empréstimo (YYYY-MM-DD): ").strip()
data_fim = input("Data fim empréstimo (YYYY-MM-DD): ").strip()
evento = input("Nome do evento: ").strip()
responsavel = input("Responsável: ").strip()
tema = input("Tema do empréstimo: ").strip()
"periodo": {"inicio": data_inicio, "fim": data_fim},
"responsavel": responsavel,
dados["emprestimos"].append(emprestimo)
# adicionar histórico na própria obra
if o["id"] == obra["id"]:
o.setdefault("historico_emprestimos", []).append(emprestimo)
print("Empréstimo registrado.")
def criar_roteiro(dados):
tema = input("Tema do roteiro: ").strip()
descricao = input("Descrição do roteiro: ").strip()
print("Adicione obras ao roteiro — digite título parcial e escolha:")
termo = input("Termo para buscar obra (enter para finalizar): ").strip()
encontrados = busca_linear_por_titulo(dados["obras"], termo)
print("Nenhuma obra encontrada com esse termo.")
for i, o in enumerate(encontrados, 1):
print(f"{i}. {o['titulo']} (ID: {o['id']})")
escolha = input("Escolha número ou 0 para cancelar: ").strip()
obras_seq.append(encontrados[escolha - 1]["id"])
print("Obra adicionada ao roteiro.")
print("Escolha inválida.")
"id": f"rot_{len(dados['roteiros'])+1}",
"obras_sequencia": obras_seq
dados["roteiros"].append(roteiro)
# ---------------------------
# ---------------------------
def listar_obras_ordenadas(dados):
obras_ordenadas = merge_sort_obras(dados["obras"])
print("Nenhuma obra cadastrada.")
print("\n--- Obras (ordenadas por título) ---")
for o in obras_ordenadas:
print(f"- {o.get('titulo')} | Autor: {o.get('autor')} | Estilo: {o.get('estilo')} | Local: {o.get('local_sala')}")
def detalhes_obra(dados):
termo = input("Buscar obra (título parcial ou exato): ").strip()
encontrados = busca_linear_por_titulo(dados["obras"], termo)
print("Nenhuma obra encontrada.")
for i, o in enumerate(encontrados, 1):
print(f"{i}. {o['titulo']} (ID: {o['id']})")
escolha = input("Escolha número para ver detalhes ou 0 para cancelar: ").strip()
o = encontrados[escolha - 1]
print("Escolha inválida.")
print("\n--- Detalhes da Obra ---")
def listar_artistas(dados):
if not dados["artistas"]:
print("Nenhum artista cadastrado.")
for a in dados["artistas"]:
print(f"- {a.get('nome')} | Nasceu: {a.get('data_nasc')} em {a.get('local_nasc')} | Estilos: {', '.join(a.get('estilos', []))}")
def listar_emprestimos(dados):
if not dados["emprestimos"]:
print("Nenhum empréstimo registrado.")
for e in dados["emprestimos"]:
print(f"- Obra ID: {e.get('obra_id')} | Evento: {e.get('evento')} | Período: {e.get('periodo')}")
def listar_roteiros(dados):
if not dados["roteiros"]:
print("Nenhum roteiro cadastrado.")
for r in dados["roteiros"]:
titles = [next((o['titulo'] for o in dados['obras'] if o['id'] == oid), oid) for oid in r.get("obras_sequencia",[])]
print(f"- {r['tema']}: {r['descricao']} | Obras: {titles}")
# ---------------------------
# ---------------------------
def menu_visitante(dados):
print("\n--- MENU VISITANTE ---")
print("1. Listar obras (ordenadas)")
print("2. Buscar obra por título (parcial)")
print("3. Ver detalhes de uma obra")
print("4. Listar roteiros de visita")
op = input("Escolha: ").strip()
listar_obras_ordenadas(dados)
termo = input("Termo para buscar: ").strip()
encontrados = busca_linear_por_titulo(dados["obras"], termo)
print(f"- {o['titulo']} ({o['autor']})")
print("Nenhuma obra encontrada.")
def menu_colaborador(dados):
print("\n--- MENU COLABORADOR ---")
print("1. Cadastrar obra")
print("2. Cadastrar artista")
print("3. Cadastrar estilo")
print("4. Registrar empréstimo")
print("5. Criar roteiro de visita")
print("6. Listar emprestimos")
print("7. Listar artistas")
op = input("Escolha: ").strip()
registrar_emprestimo(dados)
listar_emprestimos(dados)
# ---------------------------
# ---------------------------
print("Museu de Artes — Sistema P2 (Algoritmos)\n")
print("\n=== MENU PRINCIPAL ===")
print("1. Acessar como visitante")
print("2. Acessar como colaborador")
op = input("Escolha: ").strip()
print("Saindo. Dados salvos.")
if __name__ == "__main__":