Track
/
Elixir
Elixir
/
Esercizi
/
Dipingi con i numeri
Dipingi con i numeri

Dipingi con i numeri

Esercizio di apprendimento

Introduzione

Stringhe di bit

Lavorare con i dati binari è un concetto importante in qualsiasi linguaggio, ed Elixir fornisce una sintassi elegante per scrivere, confrontare e costruire dati binari.

In Elixir, i dati binari sono indicati come il tipo stringa di bit. Il tipo di dati binari (da non confondere con i dati binari in generale) è una forma specifica di stringa di bit, di cui parleremo in un esercizio successivo.

I letterali stringa di bit sono definiti usando la forma speciale per le stringhe di bit <<>>. Quando si definisce un letterale stringa di bit, lo si definisce in segmenti. Ogni segmento ha un valore e un tipo, separati dall'operatore ::. Il tipo specifica quanti bit verranno usati per codificare il valore. Il tipo può essere omesso completamente; in tal caso, il valore predefinito è un intero a 8 bit.

# This defines a bitstring with three segments of a single bit each
<<0::1, 1::1, 0::1>>

Specificare il tipo come ::1 è una scorciatoia per scrivere ::size(1). Devi usare la sintassi più lunga se la dimensione in bit proviene da una variabile.

Binario

Quando scriviamo letterali interi binari, possiamo scriverli direttamente nella notazione in base 2 anteponendo al letterale 0b. Tieni presente che verranno comunque visualizzati come numeri decimali quando stampati nei risultati dei test o quando si usa iex.

<<0b1011::4>> == <<11::4>>
# => true

Troncamento

Se il valore del segmento supera la capacità del tipo del segmento, verrà troncato da sinistra.

<<0b1011::3>> == <<0b0011::3>>
# => true

Anteporre e aggiungere in coda

Puoi sia anteporre che aggiungere in coda a una stringa di bit esistente usando la forma speciale. Il tipo ::bitstring deve essere usato sulla stringa di bit esistente se questa è di dimensione sconosciuta.

value = <<0b110::3, 0b001::3>>
new_value = <<0b011::3, value::bitstring, 0b000::3>>
# => <<120, 8::size(4)>>

Concatenazione

Possiamo concatenare stringhe di bit memorizzate in variabili usando la forma speciale. Il tipo ::bitstring deve essere usato quando si concatenano due stringhe di bit di dimensioni sconosciute.

first = <<0b110::3>>
second = <<0b001::3>>
concatenated = <<first::bitstring, second::bitstring>>
# => <<49::size(6)>>

Pattern matching

Il pattern matching può essere usato anche per ottenere valori dalla forma speciale. Devi conoscere il numero di bit per ogni frammento che vuoi catturare, con un'eccezione: il tipo ::bitstring può essere usato per fare pattern matching su una stringa di bit di dimensione sconosciuta, ma può essere usato solo per l'ultimo frammento.

<<value::4, rest::bitstring>> = <<0b01101001::8>>
value == 0b0110
# => true

Ispezionare le stringhe di bit

Note

Le stringhe di bit potrebbero essere stampate (dal test runner o in iex) in un formato diverso da quello usato per crearle. Questo spesso causa confusione quando si imparano le stringhe di bit.

Per impostazione predefinita, le stringhe di bit vengono visualizzate in frammenti di 8 bit (un byte), anche se le hai create con frammenti di dimensione diversa.

<<2011::11>>
# => <<251, 3::size(3)>>

Se crei una stringa di bit che rappresenta una stringa stampabile codificata in UTF-8, viene visualizzata come stringa.

<<>>
# => ""

<<65, 66, 67>>
# => "ABC"

Istruzioni

La pittura con i numeri (nota anche come colorare con i numeri) è una tecnica che usa immagini in bianco e nero pensate per essere colorate. Le diverse aree dell'immagine sono annotate con numeri diversi, e i numeri corrispondono a colori specifici in una palette di colori predefinita. L'obiettivo è riempire le aree con i colori giusti, rivelando alla fine una bellissima immagine colorata. È un'attività rilassante sia per i bambini che per gli adulti.

Il tuo compito è scrivere un'app di pittura con i numeri in Elixir. Vuoi che l'app sia in grado di importare ed esportare immagini in un formato di dati personalizzato. Hai deciso di usare i file binari per memorizzare i dati delle immagini.

Note

Questo esercizio presuppone che tu abbia familiarità con i numeri binari e che capisca i principi alla base della conversione dei numeri binari in numeri decimali e dei numeri decimali in numeri binari.

Immaginiamo di avere l'immagine di una faccina sorridente, come quella mostrata qui sotto. L'immagine ha uno sfondo bianco. La faccina ha un bordo nero e un riempimento giallo.

Questa immagine usa 3 colori. Assegniamo degli indici a questi colori:

  • 0 (binario: 0b00) per il bianco,
  • 1 (binario: 0b01) per il nero,
  • 2 (binario: 0b10) per il giallo.

Ora possiamo usare quegli indici di colore per rappresentare il colore di ogni pixel.

Faccina sorridente Faccina sorridente con gli indici di colore

1. Calcola la dimensione in bit della palette

Implementa la funzione PaintByNumber.palette_bit_size/1. Deve accettare il numero di colori della palette e restituire quanti bit sono necessari per rappresentare quel numero di indici di colore come numeri binari. Gli indici di colore iniziano sempre da 0 e sono numeri interi consecutivi in ordine crescente.

Ad esempio, per rappresentare 13 colori diversi servono 4 bit. 4 bit possono memorizzare fino a 16 indici di colore (2^4). 3 bit non basterebbero, perché 3 bit possono memorizzare solo fino a 8 indici di colore (2^3).

PaintByNumber.palette_bit_size(13)
# => 4

Nota: non esiste una funzione log2 nella libreria standard di Elixir. In seguito imparerai a usare le librerie Erlang da Elixir, dove puoi trovare questa funzione. Per ora, risolvi questo compito con la ricorsione e l'operatore di potenza **.

2. Crea un'immagine vuota

Implementa la funzione PaintByNumber.empty_picture/0. Deve restituire una bitstring vuota.

3. Crea un'immagine di test

Un'immagine di test predefinita verrà usata per il test manuale delle funzionalità di base dell'app. L'immagine di test è composta da 4 pixel con 4 colori diversi.

Implementa la funzione PaintByNumber.test_picture/0. Deve restituire una bitstring composta da 4 segmenti. Ogni segmento deve avere una dimensione in bit pari a 2. I segmenti devono avere i valori 0, 1, 2 e 3.

4. Anteponi un pixel a un'immagine

Implementa la funzione PaintByNumber.prepend_pixel/3. Deve accettare tre argomenti: una bitstring con l'immagine a cui stiamo anteponendo, il numero di colori della palette e l'indice del colore del nuovo pixel. Deve restituire una bitstring con l'immagine a cui è stato aggiunto il nuovo pixel all'inizio.

picture = <<2::4, 0::4>>
color_count = 13
pixel_color_index = 11

PaintByNumber.prepend_pixel(picture, color_count, pixel_color_index)
# => <<178, 0::size(4)>>
# (which is equal to <<11::4, 2::4, 0::4>>)

5. Ottieni il primo pixel di un'immagine

Implementa la funzione PaintByNumber.get_first_pixel/2. Deve accettare due argomenti: una bitstring con l'immagine da cui stiamo leggendo e il numero di colori della palette. Deve restituire l'indice del colore del primo pixel dell'immagine data. Se riceve un'immagine vuota, deve restituire nil.

picture = <<19::5, 2::5, 18::5>>
color_count = 20

PaintByNumber.get_first_pixel(picture, color_count)
# => 19

6. Elimina il primo pixel di un'immagine

Implementa la funzione PaintByNumber.drop_first_pixel/2. Deve accettare due argomenti: una bitstring con l'immagine da cui stiamo rimuovendo un pixel e il numero di colori della palette. Deve restituire l'immagine senza il primo pixel. Se riceve un'immagine vuota, deve restituire un'immagine vuota.

picture = <<2::3, 5::3, 5::3, 0::3>>
color_count = 6

PaintByNumber.drop_first_pixel(picture, color_count)
# => <<180, 0::size(1)>>
# (which is equal to <<5::3, 5::3, 0::3>>)

7. Concatena due immagini

Implementa la funzione PaintByNumber.concat_pictures/2. Deve accettare due argomenti, due bitstring. Deve restituire una bitstring che è il risultato dell'anteposizione del primo argomento al secondo argomento.

picture1 = <<52::6, 51::6>>
picture2 = <<0::6, 34::6, 12::6>>

PaintByNumber.concat_pictures(picture1, picture2)
# => <<211, 48, 34, 12::size(6)>>
# (which is equal to <<52::6, 51::6, 0::6, 34::6, 12::6>>)
Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
Elixir Exercism

Vuoi iniziare Dipingi con i numeri?

Iscriviti a Exercism per imparare e padroneggiare Elixir con 58 concetti168 esercizi e il mentoring di persone reali, tutto gratis.