Welke geheime boodschap zit er in onderstaand rooster verborgen?

boodschap
Welke geheime boodschap zit verborgen in dit rooster?

De boodschap is "East, west, home's best.". Om die boodschap te kunnen ontcijferen, wordt er een grille gebruikt: een blad papier of een stuk karton met daarop een vierkant $$n \times n$$ rooster waarin enkele openingen uitgeknipt werden. In dit geval een $$5 \times 5$$ rooster waarin zes openingen uitgeknipt worden volgens onderstaand patroon.

grille
Grille met openeningen op posities (0, 0), (1, 0), (1, 2), (1, 4), (3, 3) en (4, 2).

Als de grille op het vierkant rooster gelegd wordt, dan kan doorheen de openingen de tekst "East, " uitgelezen worden (in de leesrichting van links naar rechts, en van boven naar onder). Dit is het eerste deel van de boodschap.

grille op boodschap
Als de grille op het rooster gelegd wordt, dan kan doorheen de openingen de tekst "East, " uitgelezen worden (van links naar rechts, en van boven naar onder).

Door de grille 90° in wijzerzin te draaien, kan het tweede deel van de boodschap uitgelezen worden: "West, ". Daarna kan de grille nog tweemaal 90° in wijzerzin gedraaid worden om de twee laatste delen van de boodschap te kunnen uitlezen: "home's" en " best."

rotaties
De volledige boodschap kan uitgelezen worden via de vier mogelijk rotaties van de grille.

De oudste gekende beschrijving van deze techniek dateert van 1550 en is van de hand van de Italiaanse geleerde Girolamo Cardano1. Om die reden wordt een grille soms ook een Cardanrooster genoemd.

Opgave

Een grille met een vierkant $$n \times n$$ ($$n \in \mathbb{N}_0$$) rooster kan gebruikt worden om geheime boodschappen te ontcijferen die bestaan uit $$n^2$$ karakters. Daarvoor moet zo'n geheime boodschap opgedeeld worden in $$n$$ reeksen van $$n$$ opeenvolgende karakters. Als je die reeksen onder elkaar zet, krijg je ook een vierkant $$n \times n$$ rooster. Zo kunnen de 25 karakters van de geheime boodschap "E hWeaosbtseVtsm,e,'t.  s" als volgt omgezet worden naar het $$5 \times 5$$ rooster waarin de geheime boodschap uit de inleiding verborgen zit:

E hWe
aosbt
seVts
m,e,'
t.  s

Dat rooster moet dan zo uitgeschreven worden dat het rooster van de grille er netjes op past.

Om te kunnen verwijzen naar de cellen van een rooster (zowel voor een rooster gevormd met de karakters van een geheime boodschap als voor een rooster met de openingen van een grille) worden de rijen van boven naar onder genummerd, en de kolommen van links naar rechts, telkens vanaf nul. Hierdoor kan de positie van een cel voorgesteld worden als een reeks $$[r, k]$$ (Array), waarbij $$r \in \mathbb{N}$$ (Number) het rijnummer en $$k \in \mathbb{N}$$ (Number) het kolomnummer aanduidt.

Definieer een klasse Grille om grilles voor te stellen waarmee geheime boodschappen kunnen ontcijferd worden. Bij het aanmaken van een grille (Grille) moeten twee argumenten doorgegeven worden: i) het aantal rijen/kolommen $$n$$ (Number) van het vierkant rooster op de grille en ii) een reeks (Array) of een verzameling (Set) met de posities van de openingen in de grille. Een grille $$g$$ (Grille) moet minstens de volgende eigenschappen hebben:

Daarnaast moet je op een grille $$g$$ (Grille) minstens de volgende methoden kunnen aanroepen:

Voorbeeld

> const cijfertekst = "E hWeaosbtseVtsm,e,'t.  s"
> const grille = new Grille(5, [[0, 0], [1, 0], [1, 2], [1, 4], [3, 3], [4, 2]])
> grille.dimensie
5
> grille.openingen
new Set([[1, 2], [0, 0], [3, 3], [1, 4], [4, 2], [1, 0]])
> grille.toString()
O####
O#O#O
#####
###O#
##O##
> grille.decodeer(cijfertekst)
"East, "
> grille.roteer().openingen
new Set([[3, 1], [2, 0], [2, 3], [4, 3], [0, 4], [0, 3]])
> grille.toString()
###OO
#####
O##O#
#O###
###O#
> grille.decodeer(cijfertekst)
"West, "
> grille.roteer().openingen
new Set([[3, 2], [3, 0], [4, 4], [1, 1], [3, 4], [0, 2]])
> grille.toString()
##O##
#O###
#####
O#O#O
####O
> grille.decodeer(cijfertekst)
"home's"
> grille.roteer().openingen
new Set([[0, 1], [1, 3], [2, 1], [4, 1], [2, 4], [4, 0]])
> grille.toString()
#O###
###O#
#O##O
#####
OO###
> grille.decodeer(cijfertekst)
" best."
> grille.roteer(false).openingen
new Set([[3, 2], [3, 0], [4, 4], [1, 1], [3, 4], [0, 2]])
> grille.toString()
##O##
#O###
#####
O#O#O
####O
> grille.decodeer(cijfertekst)
"home's"

> const grille1 = new Grille(4, [[1, 3], [0, 0], [2, 3], [1, 1]])
> const grille2 = new Grille(4, new Set([[2, 0], [1, 0], [3, 3], [2, 2]]))
> const grille3 = new Grille(4, [[3, 0], [2, 3], [2, 0], [1, 1]])
> const grille4 = new Grille(5, new Set([[1, 3], [0, 0], [2, 3], [1, 1]]))
> grille1.equals(grille2)
true
> grille1.equals(grille3)
false
> grille1.equals(grille4)
false

> const grille5 = grille1.stapel(grille3)
> grille5.dimensie
4
> grille5.openingen
new Set([[2, 3], [1, 1]])
> grille5.toString()
####
#O##
###O
####
> grille1.stapel(grille4)
Error: grilles passen niet op elkaar