01 / 16
Lógica de Programação · Sem 12 · Dia 2 (Aulas 3 e 4)

Somar &
Vencer

Da planilha de notas ao tabuleiro 3×3 — extraímos médias por linha e por coluna, depois modelamos um Jogo da Velha completo em terminal.

ProfessorGuilherme Antunes CursoTécnico em Desenvolvimento de Sistemas Duração100 minutos (Aula 3 + Aula 4)
02 / 16
De onde viemos

Recap do Dia 1

  • Matriz → estrutura 2D em linhas × colunas, cada célula localizada por (i, j)
  • Indexação base 0 em Python — m[0] é a primeira linha, m[N-1] a última
  • Row-major — a memória armazena linha por linha; percorrer nessa ordem é mais rápido
  • Aliasing — use [[0]*M for _ in range(N)], nunca [[0]*M]*N
  • Laço aninhadofor i externo (linhas), for j interno (colunas)
  • Array 123 — teste a diagonal secundária antes da principal para tratar o centro de matrizes ímpares
03 / 16
Objetivos do Dia

Ao final, você será capaz de.

01

A3Calcular somas e médias por linha, por coluna e total — agregações 2D

02

A3Aplicar o truque do zip(*m) para transpor linhas em colunas em uma linha de código

03

A4Modelar um tabuleiro 3×3 em matriz e validar jogadas (intervalo, célula livre, alternância)

04

A4Implementar a verificação de vitória nas 8 trincas — linhas, colunas e duas diagonais

04 / 16
Aula 3 Ponto de partida

A planilha de notas

Você está construindo o módulo de notas do sistema escolar. A turma tem 3 alunos e 4 provas. As notas chegam numa tabela como esta:

·
P1
P2
P3
P4
Ana
8.0
7.0
9.0
8.0
Bia
6.0
7.5
5.0
8.5
Caio
9.0
8.0
7.0
10.0

Três perguntas que a coordenação faz toda reunião:

  • Qual a média de cada aluno? (soma por linha)
  • Qual a média de cada prova? (soma por coluna)
  • Qual a média geral da turma? (soma total)

Todas essas respostas são agregações: reduzir muitos valores em um valor. E todas seguem o mesmo padrão — varrer a matriz e acumular.

05 / 16
Aula 3 Construindo o conceito

Três tipos de agregação

Toda agregação responde uma pergunta simples: "como reduzir muitos valores em um?". Em matrizes, existem três eixos de redução. Cada um produz um resultado de forma diferente.

Por linha

Reduz cada linha num único número. Em uma matriz N×M, gera N resultados — um por linha. Soma da Ana, soma da Bia, soma do Caio.

resultado[i] = soma(m[i])

Por coluna

Reduz cada coluna num único número. Em N×M, gera M resultados — um por coluna. Soma da P1, soma da P2, soma da P3, soma da P4.

resultado[j] = soma da coluna j

Total

Reduz a matriz inteira num único número. Gera 1 resultado. Soma de todas as notas da turma, máximo global, mínimo global.

resultado = soma de m[i][j]
O padrão é o mesmo: varrer (com laço aninhado) + acumular (em variável). Muda só onde o acumulador zera. Por linha — zera a cada nova linha. Por coluna — um acumulador por coluna. Total — um único acumulador para tudo.
06 / 16
Aula 3 Pseudocódigo

Soma por linha · passo a passo

Comece pelo caso mais simples: a soma de cada linha. A chave é reiniciar o acumulador dentro do laço externo — assim cada linha tem seu próprio total.

// Pseudocódigo — soma por linha
para i de 0 ate n_linhas - 1 faca
    soma_linha <- 0          // ⚠ zera A CADA linha

    para j de 0 ate n_colunas - 1 faca
        soma_linha <- soma_linha + m[i][j]
    fim_para

    escrever( "Linha ", i, " = ", soma_linha )
fim_para
# Python — soma por linha
m = [[8.0, 7.0, 9.0, 8.0],
     [6.0, 7.5, 5.0, 8.5],
     [9.0, 8.0, 7.0, 10.0]]

for i in range(len(m)):
    soma_linha = 0           # zera a cada linha
    for j in range(len(m[i])):
        soma_linha += m[i][j]
    print(f"Linha {i} = {soma_linha}")
O erro mais comum: colocar soma_linha = 0 fora do laço externo. Resultado: a variável acumula tudo, e a "soma da linha 2" vira a soma de todas as linhas até a 2. Sempre que quiser somar por linha, zere dentro do for i.
07 / 16
Aula 3 Soma por coluna

Coluna a coluna — e o truque do zip(*m)

Para somar por coluna, há dois caminhos. O longo inverte os laços (j externo, i interno). O pythônico usa zip(*m), que transpõe a matriz — linhas viram colunas, e o problema cai no caso anterior.

# Caminho 1 — manual, laços invertidos
n_lin = len(m)
n_col = len(m[0])

for j in range(n_col):           # coluna externa
    soma_col = 0
    for i in range(n_lin):       # linha interna
        soma_col += m[i][j]
    print(f"Coluna {j} = {soma_col}")
# Caminho 2 — pythônico, com zip
for j, col in enumerate(zip(*m)):
    print(f"Coluna {j} = {sum(col)}")

# zip(*m) "desempilha" as linhas
# e empacota item por item:
#   linha 0: 8.0  7.0  9.0  8.0
#   linha 1: 6.0  7.5  5.0  8.5
#   linha 2: 9.0  8.0  7.0  10.0
# vira:
#   col 0: (8.0, 6.0, 9.0)
#   col 1: (7.0, 7.5, 8.0)
#   col 2: (9.0, 5.0, 7.0)
#   col 3: (8.0, 8.5, 10.0)
Como ler o *m: o asterisco desempacota a lista — em vez de passar m (uma lista de listas), passamos cada linha como argumento separado para zip. O zip então agrupa "o primeiro de cada", "o segundo de cada"… — efetivamente trocando linhas por colunas. É a transposta em uma linha.
08 / 16
Aula 3 Mini-prática

Médias de aluno e de prova

Aplique os dois padrões na planilha real. Calcule a média de cada aluno e a média de cada prova com um único bloco de código.

notas = [[8.0, 7.0, 9.0,  8.0],   # Ana
         [6.0, 7.5, 5.0,  8.5],   # Bia
         [9.0, 8.0, 7.0, 10.0]]   # Caio
alunos = ["Ana", "Bia", "Caio"]

# Médias por aluno (por linha)
for i in range(len(notas)):
    media = sum(notas[i]) / len(notas[i])
    print(f"{alunos[i]:5s}: média = {media:.2f}")

# Médias por prova (por coluna, com zip)
for j, col in enumerate(zip(*notas), start=1):
    print(f"P{j}: média = {sum(col)/len(col):.2f}")
Ana  : média = 8.00
Bia  : média = 6.75
Caio : média = 8.50

P1: média = 7.67
P2: média = 7.50
P3: média = 7.00
P4: média = 8.83

── 3 médias por aluno  (linha)
── 4 médias por prova  (coluna)
── em uma única matriz 3×4
Padrão a memorizar: sum(linha) / len(linha) dá a média de uma linha; sum(col) / len(col) com zip(*m) dá a média de uma coluna. Mesma fórmula, mudou só o eixo de iteração.
09 / 16
Aula 4 Ponte

Da planilha ao tabuleiro

Saber agregar dados de uma matriz é metade da história. A outra metade — talvez mais empolgante — é usar matrizes para modelar o mundo. Tabuleiros, mapas, grades de pixels, mapas de calor, espaços de jogos. Vamos fechar a semana construindo um Jogo da Velha completo em terminal: a matriz é o tabuleiro, e cada jogada lê, valida, atualiza e verifica vitória.

10 / 16
Aula 4 Construindo o conceito

As 8 trincas que vencem

Num tabuleiro 3×3, há exatamente oito combinações de três células que vencem o jogo: 3 linhas, 3 colunas e 2 diagonais. Visualmente:

Linha 0
Linha 1
Linha 2
Coluna 0
Coluna 1
Coluna 2
Diag. ↘
Diag. ↙
Generalização: num tabuleiro N×N, o número de trincas vencedoras é 2N + 2 — N linhas, N colunas, 2 diagonais. Para o Jogo da Velha (N=3), são 8. Para um Gomoku 15×15, seriam 32 (sem contar as trincas internas das linhas, que são outra discussão).
11 / 16
Aula 4 Antes do desafio

Passo a passo do Jogo da Velha

O desafio: programa em terminal onde dois jogadores alternam (X e O), o sistema valida cada jogada e checa vitória. Anatomia em 7 passos.

1

Modele o tabuleiro. Matriz 3×3 de '.' usando list comprehension — sem aliasing.

2

Imprima o tabuleiro. Percorra linha a linha, separando células com | ; entre linhas, mostre uma linha de -.

3

Leia a jogada. Peça linha e coluna (0 a 2). Valide: intervalo correto E célula é '.'. Se inválido, peça de novo.

4

Atualize. tab[i][j] = jogador_atual — escreve X ou O na célula validada.

5

Cheque vitória. Percorra as 8 trincas. Se alguma estiver com 3 símbolos iguais do jogador atual, ele venceu.

6

Alterne o jogador. jogador = 'O' if jogador == 'X' else 'X'.

7

Trate o empate. Se 9 jogadas se passaram sem vitória, é empate. O for/else de Python ajuda: o else só roda quando o for termina sem break.

Pegadinha da validação: testar só o intervalo 0 ≤ i, j ≤ 2 não basta — sem checar tab[i][j] == '.', o jogador O pode sobrescrever uma jogada do X. Sempre confira as duas condições.
12 / 16
Aula 4 Sua vez · Desafio · parte 1

As funções auxiliares

Antes do laço principal, prepare duas funções: imprime(), que mostra o tabuleiro, e venceu(), que retorna True se o jogador atual fechou alguma das 8 trincas.

def imprime(tab):
    for linha in tab:
        print(' | '.join(linha))
        print('-' * 9)


def venceu(tab, j):
    # 3 linhas
    for i in range(3):
        if tab[i][0] == tab[i][1] == tab[i][2] == j:
            return True

    # 3 colunas
    for c in range(3):
        if tab[0][c] == tab[1][c] == tab[2][c] == j:
            return True

    # 2 diagonais
    if tab[0][0] == tab[1][1] == tab[2][2] == j:
        return True
    if tab[0][2] == tab[1][1] == tab[2][0] == j:
        return True

    return False

Estado de exemploX venceu pela diagonal principal:

X
O
·
O
X
·
·
O
X

venceu(tab, 'X') retorna True ao testar a diagonal principal — tab[0][0] == tab[1][1] == tab[2][2] == 'X'.

O encadeamento a == b == c == d: Python avalia em cadeia — equivale a (a == b) and (b == c) and (c == d). Se qualquer par for diferente (ou se for '.'), o resultado é False e a trinca não vence. Isso já filtra automaticamente as células vazias.
13 / 16
Aula 4 Sua vez · Desafio · parte 2

O laço principal do jogo

O laço usa for jogada in range(9) — no máximo 9 jogadas até o tabuleiro lotar. O else do for trata o empate. Dentro do laço, um while True insiste até receber uma jogada válida.

tab = [['.' for _ in range(3)] for _ in range(3)]
jogador = 'X'

for jogada in range(9):
    imprime(tab)
    while True:
        i = int(input(f"{jogador} - linha (0-2): "))
        j = int(input(f"{jogador} - coluna (0-2): "))
        if 0 <= i < 3 and 0 <= j < 3 and tab[i][j] == '.':
            break
        print("Jogada inválida, tente outra.")

    tab[i][j] = jogador

    if venceu(tab, jogador):
        imprime(tab)
        print(f"{jogador} venceu!")
        break

    jogador = 'O' if jogador == 'X' else 'X'
else:
    imprime(tab)
    print("Empate!")
. | . | .
---------
. | . | .
---------
. | . | .
---------
X - linha (0-2): 1
X - linha (0-2): 1
. | . | .
---------
. | X | .
---------
. | . | .
---------
O - linha (0-2): 0
O - linha (0-2): 0
── …jogo continua…
X venceu!
Regras do desafio: use a matriz 3×3 com list comprehension (sem aliasing!). Não use numpy. A função venceu deve testar todas as 8 trincas. Se uma jogada for inválida, peça de novo — não pule a vez do jogador.
14 / 16
Pause e responda

Quantas trincas vencedoras?

Em um tabuleiro de Jogo da Velha 3×3, quantas combinações distintas de três células permitem vencer o jogo, contando linhas, colunas e diagonais?

A6 — apenas linhas e colunas
B7 — linhas, colunas e uma diagonal
C8 — três linhas, três colunas e duas diagonais
D9 — uma por célula central
Por que 8: são 3 linhas (i=0, i=1, i=2) + 3 colunas (j=0, j=1, j=2) + 2 diagonais (principal ↘ e secundária ↙). Total: 3 + 3 + 2 = 8. Generalizando para um tabuleiro N×N, são 2N + 2 trincas — o que dá 8 para N=3.
15 / 16
Então ficamos assim…

O que aprendemos hoje

  • Agregação por linha → zere o acumulador dentro do laço externo; pattern: sum(m[i])
  • Agregação por coluna → inverta os laços ou use o truque zip(*m) para transpor
  • Agregação total → um único acumulador para toda a matriz; pattern: sum(sum(linha) for linha in m)
  • Modelagem com matrizes → tabuleiros, mapas e grades cabem naturalmente em m[i][j]
  • Validação de jogada → cheque intervalo e célula livre antes de aceitar
  • 8 trincas em 3×3 → 3 linhas + 3 colunas + 2 diagonais; encadear a == b == c == j testa cada uma
  • for/else → o else só roda quando o for termina sem break; perfeito para detectar empate
Próxima semana · Sem 13

Funções e procedimentos — encapsulamento, parâmetros, retorno e escopo. Vamos transformar laços e blocos repetidos em ferramentas reutilizáveis. Fecha a unidade de estruturas de dados e abre a porta para programação modular.

16 / 16
Referências

De onde veio cada coisa

PYTHON SOFTWARE FOUNDATION. Built-in Functions — zip(). The Python Standard Library, [s.d.]. Disponível em: docs.python.org/3/library/functions.html#zip. Acesso em: 20 mai. 2026.

PYTHON SOFTWARE FOUNDATION. Compound Statements — for/else. The Python Language Reference, [s.d.]. Disponível em: docs.python.org/3/reference/compound_stmts.html. Acesso em: 20 mai. 2026.

RIBEIRO, M. Estrutura de dados — Matrizes em Python. DEV Community, 24 jun. 2023. Disponível em: dev.to/mhribeiro/matrizes-em-python-2e9j. Acesso em: 20 mai. 2026.

Base institucional: SEDUC-SP. Educação Profissional Paulista — Técnico em Desenvolvimento de Sistemas. Componente 1, Unidade 4, Semana 12 (SISANO1C1B2S12A3 e SISANO1C1B2S12A4).

Identidade visual · adaptação para apresentação HTML por Guilherme Antunes