diff --git a/Makefile b/Makefile
index f6c09837b350bcbd2100eb1ce4670d37a82cff45..8c86565efcf0f05d3af894f5e5dd2ccc33eec4a6 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ test: main
 	chmod +x runTests.sh; \
 	./runTests.sh
 
-main: main.c tabuleiro.o filha.o no.o 
+main: main.c tabuleiro.o filha.o lista.o no.o 
 	$(CC) $(CFLAGS) -o $@ $^
 
 clean:
diff --git a/lista.c b/lista.c
new file mode 100644
index 0000000000000000000000000000000000000000..bea275b79ebb30ee846f43c4a3caf15d28c2ff7c
--- /dev/null
+++ b/lista.c
@@ -0,0 +1,121 @@
+#include <malloc.h>
+#include "lista.h"
+#include "no.h"
+//---------------------------------------------------------------------------
+// Lista encadeada
+
+struct Lista {
+
+    unsigned int tamanho;
+    int padding; // só pra evitar warning
+    No primeiro;
+};
+//---------------------------------------------------------------------------
+// devolve o número de nós da Lista l
+
+unsigned int tamanhoLista(Lista l) { return l->tamanho; }
+
+//---------------------------------------------------------------------------
+// devolve o primeiro nó da Lista l,
+//      ou NULL, se l é vazia
+
+No primeiroNoLista(Lista l) { return l->primeiro; }
+
+//---------------------------------------------------------------------------
+// cria uma Lista vazia e a devolve
+//
+// devolve NULL em caso de falha
+
+Lista constroiLista(void) {
+
+    Lista l = malloc(sizeof(struct Lista));
+
+    if ( ! l )
+    return NULL;
+
+    l->primeiro = NULL;
+    l->tamanho = 0;
+
+    return l;
+}
+//---------------------------------------------------------------------------
+// desaloca a Lista l e todos os seus nós
+//
+// se destroi != NULL invoca
+//
+//     destroi(getConteudo(n))
+//
+// para cada nó n da Lista.
+//
+// devolve 1 em caso de sucesso,
+//      ou 0 em caso de falha
+
+int destroiLista(Lista l, int destroi(void *)) {
+
+    No p;
+    int ok=1;
+
+    while ( (p = primeiroNoLista(l)) ) {
+
+        l->primeiro = getSucessorNo(p);
+
+        if ( destroi )
+        ok &= destroi(getConteudo(p));
+
+        free(p);
+    }
+
+    free(l);
+
+    return ok;
+}
+//---------------------------------------------------------------------------
+// insere um novo nó na Lista l cujo conteúdo é p
+//
+// devolve o No recém-criado
+//      ou NULL em caso de falha
+
+No insereLista(void *conteudo, Lista l) {
+
+    No novo = criaNo();
+
+    if ( ! novo )
+    return NULL;
+
+    setConteudo(novo, conteudo);
+    setSucessorNo(novo, primeiroNoLista(l));
+    ++l->tamanho;
+
+    return l->primeiro = novo;
+}
+
+//------------------------------------------------------------------------------
+// remove o No de endereço rNo de l
+// se destroi != NULL, executa destroi(getConteudo(rNo))
+// devolve 1, em caso de sucesso
+//         0, se rNo não for um No de l
+
+int removeNo(struct Lista *l, struct No *rNo, int destroi(void *)) {
+    int r = 1;
+    if (l->primeiro == rNo) {
+        l->primeiro = getSucessorNo(rNo);
+        if (destroi != NULL) {
+            r = destroi(getConteudo(rNo));
+        }
+        free(rNo);
+        l->tamanho--;
+        return r;
+    }
+    for (No n = primeiroNoLista(l); getSucessorNo(n); n = getSucessorNo(n)) {
+        if (getSucessorNo(n) == rNo) {
+            setSucessorNo(n, getSucessorNo(rNo));
+            if (destroi != NULL) {
+                r = destroi(getConteudo(rNo));
+            }
+            free(rNo);
+            l->tamanho--;
+            return r;
+        }
+    }
+    return 0;
+}
diff --git a/lista.h b/lista.h
new file mode 100644
index 0000000000000000000000000000000000000000..2056e1a479b4a6d520db14cfb45e7fde4b0b60c6
--- /dev/null
+++ b/lista.h
@@ -0,0 +1,55 @@
+#ifndef _LISTA_
+#define _LISTA_
+#include "no.h"
+
+//-----------------------------------------------------------------------------
+// (apontador para) Lista encadeada
+
+typedef struct Lista *Lista;
+
+//------------------------------------------------------------------------------
+// devolve o número de nós da Lista l
+
+unsigned int tamanhoLista(Lista l);
+
+//------------------------------------------------------------------------------
+// devolve o primeiro nó da Lista l,
+//      ou NULL, se l é vazia
+
+No primeiroNoLista(Lista l);
+
+//------------------------------------------------------------------------------
+// insere um Novo nó na Lista l cujo conteúdo é p
+//
+// devolve o No recém-criado
+//      ou NULL em caso de falha
+
+No insereLista(void *conteudo, Lista l);
+//------------------------------------------------------------------------------
+// cria uma Lista vazia e a devolve
+//
+// devolve NULL em caso de falha
+
+Lista constroiLista(void);
+//------------------------------------------------------------------------------
+// desaloca a Lista l e todos os seus nós
+//
+// se destroi != NULL invoca
+//
+//     destroi(conteudo(n))
+//
+// para cada nó n da Lista.
+//
+// devolve 1 em caso de sucesso,
+//      ou 0 em caso de falha
+
+int destroiLista(Lista l, int destroi(void *));
+
+//------------------------------------------------------------------------------
+// remove o No de endereço rNo de l
+// se destroi != NULL, executa destroi(conteudo(rNo))
+// devolve 1, em caso de sucesso
+//         0, se rNo não for um No de l
+
+int removeNoLista(struct Lista *l, struct No *rNo, int destroi(void *));
+#endif