Tracks
/
Factor
Factor
/
Ejercicios
/
Cuaderno de bitácora del faro
Cuaderno de bitácora del faro

Cuaderno de bitácora del faro

Ejercicio de aprendizaje

Introducción

Los hash-sets son colecciones mutables y desordenadas que almacenan cada valor como máximo una vez. La búsqueda, la inserción y la eliminación son todas O(1) en promedio. Viven en hash-sets e implementan el protocolo de sets.

Literales de hash-set

HS{ "NS-1024" "WB-203" } .
! => HS{ "NS-1024" "WB-203" }

HS{ } es el literal vacío. Como otros literales de Factor, es un objeto compartido: cada referencia a HS{ } en el código fuente apunta al mismo conjunto. HS{ } clone te da una copia nueva e independiente en cada llamada.

Desde una secuencia

>hash-set ( seq -- set )    ! build a fresh set from a sequence

Cuando ya tienes los valores en una secuencia, >hash-set los convierte en un solo paso y descarta los duplicados.

USING: hash-sets prettyprint ;

{ "NS-1024" "WB-203" "NS-1024" } >hash-set .
! => HS{ "NS-1024" "WB-203" }

Agregar y eliminar

adjoin     ( elt set -- )    ! insert in place; no-op if already present
adjoin-all ( seq set -- )    ! insert every element of seq in place
delete     ( elt set -- )    ! remove in place; no-op if absent

Los tres modifican el conjunto; ninguno devuelve nada en la pila.

USING: hash-sets kernel sets ;

HS{ } clone
"NS-1024" over adjoin
"WB-203"  over adjoin
"NS-1024" over adjoin    ! duplicate — no effect
.                        ! => HS{ "NS-1024" "WB-203" }

adjoin-all es la forma masiva: agrega cada elemento de una secuencia y omite los duplicados, igual que adjoin lo hace uno a la vez.

USING: hash-sets kernel sets ;

HS{ "NS-1024" } clone
{ "WB-203" "NS-1024" "QR-7" } over adjoin-all
.                        ! => HS{ "QR-7" "NS-1024" "WB-203" }  (order not guaranteed)

Consultar el conjunto

in?         ( elt set -- ? )   ! is elt in the set?
null?       ( set -- ? )       ! is the set empty?
cardinality ( set -- n )       ! number of elements
members     ( set -- seq )     ! enumerate as a sequence

in? es la prueba de pertenencia del protocolo de conjuntos. Es distinto de member? (de sequences), que hace un recorrido lineal sobre una secuencia. Para un hash-set, in? es una búsqueda hash, O(1) en promedio, que es el punto central de usar un hash-set.

null? informa si el conjunto no tiene elementos: la forma directa de preguntar «¿está vacío?» en lugar de comparar cardinality con cero.

: my-log ( -- set ) HS{ "NS-1024" "WB-203" } ;

"NS-1024" my-log in? .   ! => t
"X-99"    my-log in? .   ! => f
my-log null? .           ! => f
HS{ } clone null? .      ! => t
my-log cardinality .     ! => 2

Combinar conjuntos

union     ( set1 set2 -- set )
intersect ( set1 set2 -- set )
diff      ( set1 set2 -- set )
set-like  ( set exemplar -- set' )

union es «todos los elementos de cualquiera de los dos»; intersect es «elementos en ambos»; diff es «en set1 pero no en set2». Cada uno devuelve un conjunto nuevo sin modificar los conjuntos originales.

set-like convierte set al tipo de exemplar. Las implementaciones predeterminadas de union/intersect/diff lo usan para que el resultado coincida con el tipo del receptor: <my-set> <hash-set> union devuelve un my-set, no un hash-set.

Por qué esto importa

Los hash-sets se combinan de forma natural con las tablas hash para el recorrido de grafos: una tabla hash asigna cada nodo a sus vecinos, y un hash-set registra qué nodos ya se visitaron para que la búsqueda no entre en bucle ni repita trabajo. El recorrido es entonces una cola más las dos estructuras, que se modifican en el lugar a medida que avanzas hacia afuera.

Instrucciones

Eres el farero del faro de Cape Crozier. Desde la sala de la linterna registras cada embarcación que pasa (cada una se identifica con una señal de llamada única) y además coordinas las retransmisiones de señales con los demás faros a lo largo de la costa.

1. Una bitácora nueva

Define empty-log para que devuelva un conjunto hash nuevo y vacío, listo para ir acumulando señales de llamada.

empty-log .
! => HS{ }

2. Registra un avistamiento

Define sight para que reciba una bitácora y una señal de llamada, y registre el avistamiento en el lugar. No devuelve nada.

empty-log dup "NS-1024" sight .
! => HS{ "NS-1024" }

3. ¿Ya vimos esta?

Define seen? para que reciba una bitácora y una señal de llamada, y devuelva t si la señal de llamada ya está registrada y f en caso contrario.

HS{ "NS-1024" "WB-203" } "NS-1024" seen? .   ! => t
HS{ "NS-1024" "WB-203" } "X-99"    seen? .   ! => f

4. Olvida un avistamiento

Define forget-sighting para que reciba una bitácora y una señal de llamada, y elimine la señal de llamada de la bitácora en el lugar. No devuelve nada. Si la señal de llamada no está, no hagas nada.

HS{ "NS-1024" "WB-203" } clone dup "WB-203" forget-sighting .
! => HS{ "NS-1024" }

5. ¿Cuántas embarcaciones distintas?

Define unique-count para que devuelva la cantidad de señales de llamada distintas que hay en la bitácora.

HS{ "NS-1024" "WB-203" "AC-77" } unique-count .   ! => 3
empty-log unique-count .                          ! => 0

6. Faros alcanzables

La guardia costera mantiene un relay-map: una tabla hash cuyas claves son nombres de faros, y cada valor es un array con los faros a los que el faro de la clave puede retransmitir directamente.

Define reachable para que reciba un faro start y un relay-map, y devuelva un conjunto hash con todos los faros a los que se puede llegar desde start (incluido el propio start) mediante retransmisiones sucesivas.

H{
    { "Crozier"  { "Beacon"  "Hadley"  } }
    { "Beacon"   { "Crozier" "Spiral"  } }
    { "Hadley"   { "Crozier"           } }
    { "Spiral"   { "Beacon"  "Outpost" } }
    { "Outpost"  { "Spiral"            } }
    { "Far-Isle" { "Lonely"            } }
    { "Lonely"   { "Far-Isle"          } }
}
"Crozier" swap reachable .
! => HS{ "Crozier" "Beacon" "Hadley" "Spiral" "Outpost" }

El par Far-Isle/Lonely forma su propia componente conexa, así que ninguno de los dos aparece en el resultado.

Editar en GitHub El enlace se abre en una ventana o una pestaña nuevas
Factor Exercism

¿Todo listo para empezar Cuaderno de bitácora del faro?

Regístrate en Exercism para aprender y dominar Factor con 47 conceptos163 ejercicios y mentoría humana real, todo gratis.