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 aninhado — for 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 exemplo — X 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