# Semana 12: árboles rojinegros. Se usa dentro del entorno del curso.
#
#   make               compila los programas de la clase en build/
#   make lab           compila el laboratorio en build/lab/
#   make test          corre las pruebas de los ejemplos y de los apuntes
#   make test-base     comprueba el mapa de partida, que no depende de los colores
#   make test-rotations  prueba las rotaciones de la semana 11 (paso 1)
#   make test-check    prueba check_invariants con árboles sanos y rotos (paso 2)
#   make test-insert   prueba la inserción, contra std::map (paso 3)
#   make test-measure  prueba time_inserts y time_finds (paso 5)
#   make test-lab      prueba todo su laboratorio; falla hasta que lo terminen
#   make bench-counts  cuenta rotaciones y recoloreos, con -O2 y sin sanitizers (paso 4)
#   make bench-times   mide AVL, rojinegro y std::map, con -O2 y sin sanitizers (paso 5)
#   make bench-words   lo mismo con palabras.txt, en su orden y barajado (paso 5)
#   make clean         borra lo generado
#
# Los programas de errors/ tienen errores a propósito. No se compilan con make:
# los compilan las pruebas, y ustedes, con los comandos de los apuntes.

CXX = g++
CXXFLAGS = -Wall -Wextra -std=c++20 -g -fsanitize=address,undefined
BENCHFLAGS = -Wall -Wextra -std=c++20 -O2
DATA ?= ../../data
LAB_DIR ?= lab
BUILD = build
PROGRAMS = rb_trace tree_234_trace btree_levels height_bound test_structures
BENCHES = all_orders all_shapes collapse_check height_table count_table recursive_cost
COMMON_HEADERS = rb_set.h tree_234.h avl_set.h bench.h
LAB_HEADERS = $(LAB_DIR)/red_black_map.h $(LAB_DIR)/measure.h lab/not_implemented.h rb_set.h

.PHONY: all lab test test-base test-rotations test-check test-insert test-measure test-lab bench-counts bench-times bench-words clean

all: $(PROGRAMS:%=$(BUILD)/%) $(BENCHES:%=$(BUILD)/%)

$(PROGRAMS:%=$(BUILD)/%): $(BUILD)/%: %.cpp $(COMMON_HEADERS) | $(BUILD)
	$(CXX) $(CXXFLAGS) $< -o $@

# Las mediciones y las búsquedas exhaustivas van con -O2 y sin sanitizers.
$(BENCHES:%=$(BUILD)/%): $(BUILD)/%: %.cpp $(COMMON_HEADERS) | $(BUILD)
	$(CXX) $(BENCHFLAGS) $< -o $@

# LAB_DIR va primero: así las pruebas toman el mapa de esa carpeta.
$(BUILD)/$(LAB_DIR)/map_tests: lab/tests/map_tests.cpp $(LAB_HEADERS) | $(BUILD)/$(LAB_DIR)
	$(CXX) $(CXXFLAGS) -I$(LAB_DIR) -Ilab -I. $< -o $@

$(BUILD)/$(LAB_DIR)/bench_counts: lab/tests/bench_counts.cpp $(LAB_HEADERS) lab/avl_map.h | $(BUILD)/$(LAB_DIR)
	$(CXX) $(BENCHFLAGS) -I$(LAB_DIR) -Ilab -I. $< -o $@

$(BUILD)/$(LAB_DIR)/bench_times: lab/tests/bench_times.cpp $(LAB_HEADERS) lab/avl_map.h bench.h | $(BUILD)/$(LAB_DIR)
	$(CXX) $(BENCHFLAGS) -I$(LAB_DIR) -Ilab -I. $< -o $@

$(BUILD)/$(LAB_DIR)/bench_words: lab/tests/bench_words.cpp $(LAB_HEADERS) lab/avl_map.h bench.h | $(BUILD)/$(LAB_DIR)
	$(CXX) $(BENCHFLAGS) -I$(LAB_DIR) -Ilab -I. $< -o $@

$(BUILD) $(BUILD)/$(LAB_DIR):
	mkdir -p $@

lab/avl_map.h:
	@echo "Falta lab/avl_map.h: copien aquí el avl_map.h que terminaron en la semana 11."
	@exit 1

lab: $(BUILD)/$(LAB_DIR)/map_tests $(BUILD)/$(LAB_DIR)/bench_counts $(BUILD)/$(LAB_DIR)/bench_times $(BUILD)/$(LAB_DIR)/bench_words

# Si existe solution/, también se comprueba la solución del laboratorio.
test: all
	@if [ -d solution ]; then $(MAKE) --no-print-directory LAB_DIR=solution lab; fi
	DATA=$(DATA) python3 -m unittest discover -p 'test_*.py'

test-base: all lab
	LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab.TestBase

test-rotations: all lab
	LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab.TestRotations

test-check: all lab
	LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab.TestCheck

test-insert: all lab
	LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab.TestInsert

test-measure: all lab
	LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab.TestMeasure

test-lab: all lab
	LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab

bench-counts: $(BUILD)/$(LAB_DIR)/bench_counts
	$<

bench-times: $(BUILD)/$(LAB_DIR)/bench_times
	@for map in avl rn std; do \
		echo $$map; \
		printf '%9s%10s%10s%10s%10s\n' n ins.orden bus.orden ins.azar bus.azar; \
		for n in 16000 64000 256000 1024000; do $< $$map $$n || exit 1; done; \
	done

bench-words: $(BUILD)/$(LAB_DIR)/bench_words
	@for map in avl rn std; do $< $(DATA)/palabras.txt $$map || exit 1; done

clean:
	rm -rf $(BUILD) __pycache__
