Estadística con un dado y una micro:bit. La micro:bit se pincha en la pantalla Kitronik :VIEW 128x64 y se convierte en un dado que dibuja su propio histograma. Tiene tres dados dentro: el del ordenador (pseudoaleatorio), el del mundo real (ruido físico) y uno trucado. ¿Sabrías descubrir cuál hace trampa solo mirando los datos?
Esta página lo explica todo: montaje, el programa bloque a bloque, un simulador con la pantalla, la estadística y por qué los ordenadores no saben inventar el azar.
1 · Montaje y extensión
- Pincha la micro:bit en la ranura de la pantalla Kitronik :VIEW 128x64, con la matriz de LEDs mirando hacia ti. No hacen falta cables.
- Conecta el cable USB a la micro:bit.
- En MakeCode (Chrome o Edge), proyecto nuevo → Extensiones → escribe 128 y añade la de la pantalla. Aparece la categoría 128x64 Display, con sus bloques en inglés: show, clear display, draw a rectangle, refresh display…
- Crea las variables cuenta, total, modo, dado, maximo y alto, y las funciones tirar y dibujar (Avanzado → Funciones → Crear una función). El bloque «llamada tirar» aparece en Funciones cuando la función ya existe.
2 · El programa, bloque a bloque
1 · Al iniciar: preparar la libreta
El programa necesita una libreta donde apuntar cuántas veces ha salido cada cara. Esa libreta es una lista (MakeCode la llama «matriz») de 6 números, uno por cara: la posición 0 es el 1, la posición 1 es el 2… y la posición 5 es el 6.
· fijar cuenta a matriz de 0, 0, 0, 0, 0, 0 (Avanzado → Matrices)
· fijar total a 0
· fijar modo a 1
· llamada dibujar
Lo mismo en JavaScript
cuenta = [0, 0, 0, 0, 0, 0] total = 0 modo = 1 dibujar()
2 · La función tirar: tres dados distintos
Una función es un trozo de programa con nombre que podemos usar muchas veces. tirar saca un número del 1 al 6 de tres formas distintas, según el modo:
- Modo 1 · dado del ordenador: «escoger al azar de 1 a 6». Parece azar, pero es una fórmula (lo vemos más abajo).
- Modo 2 · dado del mundo real: usa el cronómetro de la micro:bit, que cuenta microsegundos (un millón por segundo). Nadie puede agitar en un microsegundo concreto. Le sumamos la aceleración, quitamos el signo con «valor absoluto», nos quedamos con el resto de dividir entre 6 (0 a 5) y sumamos 1.
- Modo 3 · dado trucado: escoge de 1 a 8 y, si sale 7 u 8, lo convierte en 6. Así el 6 sale 3 de cada 8 veces en vez de 1 de cada 6.
Después suma 1 en la casilla de la cara que ha salido (posición dado − 1), suma 1 al total y enseña el número en la matriz de LEDs.
· si modo = 1 entonces: fijar dado a escoger al azar de 1 a 6
· si no, si modo = 2 entonces: fijar dado a ( restante de ( absoluto de ( tiempo de ejecución (micros) + aceleración (mg) x ) ) / 6 ) + 1
· si no: fijar dado a escoger al azar de 1 a 8; si dado > 6 entonces fijar dado a 6
· cuenta establecer el valor en (dado − 1) a ( cuenta obtener el valor en (dado − 1) + 1 )
· cambiar total por 1
· mostrar número dado
Lo mismo en JavaScript
function tirar () {
if (modo == 1) {
dado = randint(1, 6)
} else if (modo == 2) {
dado = Math.abs(input.runningTimeMicros() + input.acceleration(Dimension.X)) % 6 + 1
} else {
dado = randint(1, 8)
if (dado > 6) {
dado = 6
}
}
cuenta[dado - 1] = cuenta[dado - 1] + 1
total += 1
basic.showNumber(dado)
}3 · La función dibujar: el histograma
Un histograma es un gráfico de barras donde cada barra es lo que ha salido cada cara. La pantalla mide 128 × 64 píxeles: el punto (0, 0) es la esquina de arriba a la izquierda y la y crece hacia abajo.
- Primero busca la barra más alta (maximo) para que mida 50 píxeles y las demás en proporción.
- Escribe arriba el total de tiradas y el modo con show.
- Dibuja 6 rectángulos de 14 píxeles de ancho, separados 21: el de la cara índice empieza en x = índice × 21 + 2 y, para que crezca desde abajo, en y = 63 − alto.
- refresh display asegura que la pantalla se actualiza.
· clear display
· fijar maximo a 1
· para índice de 0 a 5: si (cuenta obtener el valor en índice) > maximo entonces fijar maximo a (cuenta obtener el valor en índice)
· show ( unir "T" total "Modo" modo )
· para índice de 0 a 5:
fijar alto a redondeo( (cuenta obtener el valor en índice) × 50 / maximo )
si alto > 0 entonces: draw a rectangle 14 wide alto high from position x (índice × 21 + 2) y (63 − alto)
· refresh display
Lo mismo en JavaScript
function dibujar () {
kitronik_VIEW128x64.clear()
maximo = 1
for (let índice = 0; índice <= 5; índice++) {
if (cuenta[índice] > maximo) {
maximo = cuenta[índice]
}
}
kitronik_VIEW128x64.show("T" + total + "Modo" + modo)
for (let índice2 = 0; índice2 <= 5; índice2++) {
alto = Math.round(cuenta[índice2] * 50 / maximo)
if (alto > 0) {
kitronik_VIEW128x64.drawRect(14, alto, índice2 * 21 + 2, 63 - alto)
}
}
kitronik_VIEW128x64.refresh()
}4 · Los botones
- Agitar (si agitar): una tirada y redibuja.
- B: 10 tiradas seguidas (para llegar rápido a 100 o 200) y redibuja.
- A: pasa al siguiente dado (1 → 2 → 3 → 1), borra la libreta y redibuja.
al presionarse el botón B: repetir 10 veces (llamada tirar) · llamada dibujar
al presionarse el botón A: fijar modo a modo + 1 · si modo > 3 entonces fijar modo a 1 · fijar cuenta a matriz de 0,0,0,0,0,0 · fijar total a 0 · llamada dibujar
Lo mismo en JavaScript
input.onGesture(Gesture.Shake, function () {
tirar()
dibujar()
})
input.onButtonPressed(Button.B, function () {
for (let index = 0; index < 10; index++) {
tirar()
}
dibujar()
})
input.onButtonPressed(Button.A, function () {
modo = modo + 1
if (modo > 3) {
modo = 1
}
cuenta = [0, 0, 0, 0, 0, 0]
total = 0
dibujar()
})Programa completo (pestaña JavaScript de MakeCode)
Si lo pegas en la pestaña JavaScript y vuelves a Bloques, MakeCode lo convierte en los mismos bloques (antes añade la extensión de la pantalla).
// Chisme 151 - ¿Está trucado el dado del Lince? micro:bit V2 + pantalla Kitronik :VIEW 128x64
// Necesita la extensión de la pantalla (busca "128" en Extensiones)
let alto = 0
let maximo = 0
let dado = 0
let modo = 0
let total = 0
let cuenta: number[] = []
// Tira el dado según el modo: 1 ordenador, 2 mundo real, 3 trucado
function tirar () {
if (modo == 1) {
dado = randint(1, 6)
} else if (modo == 2) {
dado = Math.abs(input.runningTimeMicros() + input.acceleration(Dimension.X)) % 6 + 1
} else {
dado = randint(1, 8)
if (dado > 6) {
dado = 6
}
}
cuenta[dado - 1] = cuenta[dado - 1] + 1
total += 1
basic.showNumber(dado)
}
// Dibuja el histograma: 6 barras, la más alta mide 50 píxeles
function dibujar () {
kitronik_VIEW128x64.clear()
maximo = 1
for (let índice = 0; índice <= 5; índice++) {
if (cuenta[índice] > maximo) {
maximo = cuenta[índice]
}
}
kitronik_VIEW128x64.show("T" + total + "Modo" + modo)
for (let índice2 = 0; índice2 <= 5; índice2++) {
alto = Math.round(cuenta[índice2] * 50 / maximo)
if (alto > 0) {
kitronik_VIEW128x64.drawRect(14, alto, índice2 * 21 + 2, 63 - alto)
}
}
kitronik_VIEW128x64.refresh()
}
input.onGesture(Gesture.Shake, function () {
tirar()
dibujar()
})
input.onButtonPressed(Button.B, function () {
for (let index = 0; index < 10; index++) {
tirar()
}
dibujar()
})
input.onButtonPressed(Button.A, function () {
modo = modo + 1
if (modo > 3) {
modo = 1
}
cuenta = [0, 0, 0, 0, 0, 0]
total = 0
dibujar()
})
cuenta = [0, 0, 0, 0, 0, 0]
total = 0
modo = 1
dibujar()
3 · Simulador
Es la misma pantalla de 128 × 64 píxeles. A cambia de dado, B tira 10 veces y Agitar tira una. Los botones grises solo existen aquí, para llegar rápido a muchas tiradas.
| Cara | Veces | % | Esperado |
|---|
¿A qué se acerca el porcentaje de seises?
La línea es el porcentaje de seises desde la primera tirada. Con pocas tiradas salta mucho; con muchas se estabiliza en 16,7 % si el dado es honrado (ley de los grandes números). Con el trucado se va a 37,5 %.
4 · La estadística: ¿cuándo podemos acusar al dado?
- Frecuencia absoluta: cuántas veces ha salido cada cara. Frecuencia relativa: esas veces divididas entre el total (en %).
- Probabilidad teórica de un dado honrado: 1/6 ≈ 16,7 % para cada cara.
- Ley de los grandes números: cuantas más tiradas, más se acerca la frecuencia relativa a la probabilidad. Con 12 tiradas es normal que una cara salga 5 veces y otra ninguna: eso no demuestra trampa.
- Prueba ji-cuadrado (χ²), para Bachillerato: compara lo observado (O) con lo esperado (E = total ÷ 6) en cada cara: χ² = Σ (O − E)² / E. Con 6 caras hay 5 grados de libertad, y si χ² pasa de 11,07 solo habría un 5 % de probabilidad de ver algo tan raro con un dado honrado: tenemos motivos para sospechar. El simulador la calcula sola a partir de 30 tiradas.
- Y lo más importante: con pocas tiradas no se puede acusar a nadie. Antes de concluir, hay que tener suficientes datos.
5 · Pseudoaleatorio: el azar del ordenador es una fórmula
Un ordenador sigue instrucciones: no puede «inventar» un número. Lo que hace «escoger al azar» es usar una fórmula que, a partir de un número inicial (la semilla), produce una secuencia que parece aleatoria. Si conoces la fórmula y la semilla, conoces todos los números que van a salir. Prueba esta fórmula sencilla (un generador congruencial lineal):
Pon la misma semilla dos veces: salen exactamente los mismos números. En ciencia eso es útil (otros pueden repetir tu simulación), pero en un juego, una lotería o una contraseña es un peligro. Por eso la micro:bit V2 elige la semilla con ruido de su propio chip al arrancar.
6 · ¿Y el azar de verdad?
- Ruido físico: el momento exacto (en microsegundos) en que alguien agita, las vibraciones del acelerómetro, el ruido del micrófono o de la luz. Es lo que usa el modo 2.
- Generadores por hardware: muchos chips, incluido el de la micro:bit V2, tienen un circuito que mide ruido eléctrico para crear números de verdad aleatorios.
- Ojo con el ruido: el ruido físico puede tener sesgos. Si las tiradas con B van muy seguidas, el tiempo entre ellas es casi regular. ¿Se nota en el histograma del modo 2? Investígalo.
- Truco de von Neumann para quitar sesgos: se miran los bits de dos en dos; «01» se convierte en 0, «10» en 1 y «00» o «11» se tiran. Aunque la moneda esté algo trucada, lo que sale está equilibrado.
Lee y predice
Tiras 12 veces el dado del ordenador y el 3 no sale nunca. ¿Está trucado?
No se puede saber con 12 tiradas: es bastante probable que una cara no salga. Tira 300 veces y mira el χ².¿Por qué en el trucado se escoge de 1 a 8?
Porque 7 y 8 se convierten en 6: el 6 tiene 3 de 8 posibilidades (37,5 %) y las demás caras 1 de 8 (12,5 %).¿Por qué se usa «dado − 1» en la libreta?
Porque las listas empiezan a contar en 0: la cara 1 se apunta en la posición 0 y la cara 6 en la 5.Micro:bit V2 y pantalla Kitronik :VIEW 128x64, programada con bloques en MakeCode.