Aufgabe 1: Belagerung um Farnsworth Castle

 

Vorbetrachtungen

 

Jede Schablone besteht aus m2 Elementen, wobei m die Seitenlänge ist. Insgesamt sind 4 verschiedene Rotationszustände vorhanden, da 360°:90° = 4 gilt. Um einen universellen Einsatz der Schablone für alle nur denkbaren Nachrichten zu erzielen, darf jeder Buchstabe nur einmal durch ein Loch lesbar sein. Pro Rotation werden also m2:4 Buchstaben gelesen. Die Schablone hat somit auch m2:4 Löcher.

 

Eine Ausnahme von dieser Regel stellen ungerade Seitenlängen m dar. Die Mitte ist entweder ein Loch und immer lesbar oder kein Loch und nie lesbar. Die Anzahl der Löcher der Schablone beträgt also (m2-1):4.

 

Eine ordnungsgemäße Anordnung an Löchern liest jeden Buchstaben der Vorlage genau einmal. Ein Beispiel für eine einfache Schablone:

Rotiert man ein einzelnes Loch losgelöst von der gesamten Schablone, so stößt jede Drehung dieses Loches auf ein Nicht-Loch.

 

Man kann also nach folgendem Schema bei der Schablonenerstellung vorgehen:

  1. Ein Loch ausschneiden
  2. Alle gedachten Rotationen dieses Loches auf der Schablone als gesperrt markieren
  3. Eine nicht markierte Stelle suchen, die noch kein Loch ist und bei 1. weitermachen

 

Bedienung

 

Das Programm erlaubt die Eingabe einer Nachricht (unverschlüsselter Text) oder eines Ergebnisses (verschlüsselter Text). Diese Namenskonvention zieht sich auch durch die gesamte Dokumentation und den Quellcode.

 

Je nachdem, welches Eingabefeld zuletzt aktiv war, wird eine Kodierung oder Dekodierung vorgenommen. Rechts neben dem Eingabefeld wird die jeweilige Textlänge angezeigt und ihr Maximalwert, der nicht überschritten werden kann. Wird dieser Wert aber unterschritten, so bringt das Programm eine entsprechende Hinweismeldung. Alle fehlenden Stellen werden mit Leerzeichen aufgefüllt. Beim Ergebnis (oder der Nachricht, wenn dekodiert wurde) fehlende dann alle Leerzeichen hinter dem letzten Buchstaben. Allerdings ist dies mit Problemen verbunden, insbesondere bei der Darstellung der Schablone. Ich rate deshalb zu Texten mit exakt der gleichen Länge wie die Schablone Elemente umfaßt.

 

Die benutzte Schablone kann durch die Checkbutton-Anordnung beliebig verändert werden. Dabei entspricht ein Häkchen einem Loch. Ob sie den oben beschriebenen Anforderungen entspricht, kann mittels Schablone testen leicht überprüft werden.

 

Jedoch überprüft das Programm auch vor jeder Kodierung/Dekodierung die Schablone auf Korrektheit. Außerdem aktiviert bzw. deaktiviert das Programm selbständig Checkbuttons, so daß wenn nur noch markierte bzw. gesperrte Buttons vorhanden sind, die Schablone vollständig ist. Das Programm nimmt somit selbständig den 2.Schritt der Schablonenerstellung vor. Das Ergebnis der Ver-/Entschlüsselung wird direkt in das entsprechende Eingabefeld eingetragen, d.h. bei der Kodierung in das Ergebnisfeld.

 

Die Kodierung erzeigt am Schluß in einem Infofenster das Ergebnis in Schablonenform. Aufgrund der Verwendung proprotionaler Schriften von Windows stehen die Buchstaben nicht immer exakt in Spalten.

 

Beim Programmstart ist die Schablone aus der Aufgabe standardmäßig gesetzt und der Beispieltext Komm und bring Julee nach Farnsworth im Nachrichten-Eingabefeld eingetragen. Mittels Tastendruck auf Enter wird automatisch der Kodierungs-/Dekodierungsbutton aufgerufen. Das Programm verlangt keine Großschreibung, jedoch wird auch keine Umwandlung vorgenommen. Kleinbuchstaben sind im Ergebnis auch Kleinbuchstaben.

 

Der Einfachheit halber wird der verschlüsselte Text nicht in einer quadratischen Form, wie die Schablone, sondern direkt hintereinander in das Ergebniseingabefeld ausgegeben. In einem kleinen Infofenster wird bei der Verschlüsselung auch die quadratische Form angezeigt.

 

Weiterhin läßt sich interaktiv die Seitenlänge der Schablone einstellen. Dazu dient ein Schieberegler. Aus Platzgründen wurde ein Maximum von 6 gewählt. Ebenso ist eine Seitenlänge von <2 nicht sinnvoll. Leider muß bei jeder Änderung die Schablone und die Nachricht/das Ergebnis gelöscht werden.

 

In der nachfolgenden Abbildung ist die Lösung des Beispielsatzes abzulesen (das führende Leerzeichen ist zu beachten):

Somit läßt sich der Code in folgender quadratischen Form schreiben:

S J U G C

H E T T L

B E R E A A

N L D L U K

R N M N I

T E C H T

 

 

Programmdokumentation

 

Bei der Programmdokumentation beschränkte ich mich auf die Kernmethoden, die sich direkt um die Kodierung/Dekodierung kümmern. Dazu zählen:

BOOL CheckKey();

void Kodieren();

void Dekodieren();

void GetText(TFeld Key);

void SetText(TFeld Key);

void Rotiere(TFeld Alt, TFeld Neu);

Diese Methoden werde ich jetzt im einzelnen erläutern:

 

CheckKey

 

Nachdem die Schablone eingelesen wurde, wird ein spezielles Summenfeld auf 0 gesetzt. Die Idee dabei ist, die Schablone in alle 4 Positionen zu rotieren und aufzuaddieren. Da jede Position von nur einem Loch abgedeckt werden darf, müssen alle Elemente des Summenfeldes am Ende den Wert 1 haben. Liegt eine ungerade Seitenlänge vor, so wird die Mitte auch auf 1 gesetzt, da sie nicht benutzt wird und die Prüfroutine nicht stören darf. Das Ergebnis der Methode wird als boolescher Wert zurückgegeben.

 

Vor jeder Kodierung/Dekodierung wird CheckKey aufgerufen, um unsinnige Ergebnisse zu vermeiden.

 

Kodieren

 

Zuerst wird die Nachricht aus dem entsprechendem Eingabefeld ausgelesen. Um Probleme bei zu geringer Buchstabenzahl zu vermeiden, wird jedes in die Berechnung eingehende Nullzeichen durch ein Leerzeichen ersetzt. Als nächste Voraussetzung für die ordnungsgemäße Funktion wird die aktuelle Schablone gelesen, welche sich sofort einer Überprüfung unterziehen muß. Notfalls erfolgt ein Abbruch.

 

Nun folgt eine Schleife, die alle 4 Rotationen betrachtet. Dabei wird in jedem Durchlauf mittels SetText durch die Löcher der Schablone die Nachricht geschrieben. Danach wird die Schablone um 90° im Uhrzeigersinn gedreht. Am Ende der Schleife ist das Ergebnis praktisch fertig errechnet.

 

Gemäß der C-Variablendefinition für Zeichenketten wird ein Nullzeichen an das Ergebnis angehängt. Nun folgt noch die Ausgabe auf dem Bildschirm. Zusätzlich wird das Ergebnis in Schablonenform angezeigt.

 

Dekodieren

 

Die Funktionsweise ähnelt sehr stark dem Kodieren.

 

Das Ergebnis, welches in eine Nachricht umgewandelt werden soll, wird ausgelesen und von Nullen bereinigt. Die Schablone wird ebenfalls ausgelesen und überprüft. In der Schleife steht jetzt aber GetText statt SetText, d.h. jetzt wird durch die Löcher gelesen. Das Ende der Methode gleicht wieder dem Kodieren, nur die Nachricht wird in das Nachrichten-Eingabefeld geschrieben. Lediglich die Anzeige der Nachricht in Schablonenform entfällt.

 

GetText

 

Diese Methode wird nur beim Dekodieren benutzt. Sie durchläuft alle Elemente der Schablone und überprüft jeweils, ob ein Loch vorliegt. Wenn ja, dann wird an die Nachricht das durchscheinende Zeichen des Ergebnisses angehängt.

 

SetText

 

Wiederum ist ein große Ähnlichkeit zu GetText feststellbar. Alleiniger Aufrufer ist diesmal der Kodierer. Ist ein Loch gefunden, wird in die aktuelle XY-Koordinate des Ergebnisses das aktuelle Zeichen der Nachricht geschrieben.

 

Rotiere

 

Jedes Element der Schablone wird durchlaufen. Um eine Rotation um 90° im Uhrzeigersinn (mathematisch negativ) zu erzielen, müssen folgende Gleichungen gelten:

xneu = yalt

yneu = AktuelleBreite - 1 - xalt

 

Weiterführende Erläuterungen

 

Es ist einfach zu zeigen, daß sich jede Schablone aus 4 gleichen Teilen zusammensetzen läßt. Eines dieser Teile sind die Löcher, die 3 anderen die undurchsichtige Fläche (n ist eine natürliche Zahl):

m = 2n

m2 = 4 n2

m = 2n+1

m2 = (2n+1)2

m2 = 4n2 + 4n + 1

m2 = 4 (n2+n) + 1

Da jedoch die Mitte nicht anwählbar ist, sinkt die Lochanzahl um 1:

m2 -1 = 4 (n2+n)

Somit sind ist gezeigt worden, daß bei geraden Seitenlängen die Fläche ein Vielfaches von 4 ist, bei ungeraden trifft dasselbe zu, nur muß das Mittelloch frei bleiben.

 

Mit der Schablonenmethode läßt sich aber leider keine Eindeutigkeit erreichen. Dies äußert sich darin, daß je nachdem, bei welcher Rotationsposition der Schablone man anfängt, ein unterschiedliches Ergebnis entsteht. Gleichermaßen kann man bei der Dekodierung vier verschiedene Nachrichten herausbekommen. Der Unterschied ist aber nicht sehr groß, er äußert sich in einem Versatz der Buchstaben. Der Satz beginnt also irgendwo in der Mitte, geht zu Ende und fängt dann an. Durch Ausprobieren aller möglichen Versätze (um 1m, 2m oder 3m) ist es machbar, schnell den Sinn zu erfassen.

 

Als Ausweg bieten sich zwei Methoden an, die sich in der gegebenen Schablonenbreite unterscheiden: ungerade oder gerade. Danach beschreibe ich ein drittes Verfahren, welches auf alle Breiten anwendbar ist.

 

 

 

 

Bei Nachrichten mit vielen sich wiederholenden Zeichen, z.B. einer längeren Ziffernfolge, kann man für eine ganz spezielle Nachricht auch eine ganz speziellen Schablone entwerfen. Dabei macht man sich zunutze, daß ein Zeichen durch mehr als ein Loch während der 4 Rotationen gelesen wird. Damit kann der verschlüsselte Code kürzer als die Nachricht sein. Der Einsatzbereich für solche Verfahren ist aber sehr eingeschränkt, da die universelle Einsetzbarkeit verloren geht.

 

Es besteht auch die Möglichkeit, daß die Nachricht mehr Zeichen als der Schlüssel enthält und sich der eben beschriebene Trick nicht anwenden läßt. Dann muß man die Nachricht in mehrere Blöcke aufteilen, die getrennt verschlüsselt werden. Somit müssen mehrere Schablone verschickt werden. Besonders wichtig ist es, die richtige Reihenfolge zu bestimmen (siehe oben). Dies gilt sowohl für Startrotationsposition jeder Schablone als auch für die Reihenfolge der verschiedene Schablone. Diesen Weg sollte man aber nur gehen, wenn der Zugriff auf große Schablonen nicht möglich ist.

 

Beispiele

Oben wurde bereits das geforderte Beispiel mit Lösung erwähnt. Deshalb beschränke ich mich jetzt auf eigene:

 

Standardschlüssel (aus dem Beispiel):

 

Nachricht: ES GIBT AUCH NACHRICHTEN OHNE SINN !

 

 

 

Schlüssel mit Breite 2, enthält 1 Loch oben links:

Nachricht: ERBE

 

Ergebnis: ER

EB

 

Quelltext

 

EINS.H

 

#include "resource.h" // ID-Definitionen einbinden

 

 

class CEinsApp : public CWinApp // Fensterklasse

{

public:

BOOL InitInstance(); // Start für Dialogerzeugung modifizieren

};

 

 

#define MaxBreite 6 // Breite der Schablone

#define MaxInhalt MaxBreite*MaxBreite // Länge der Texte plus abschließendes Zero-Byte

#define Drehungen 4 // 360/90 Drehungen

 

#define GetSchabloneID(x,y) (ID_SCHABLONE+(x)+(y)*MaxBreite)

// Makro zur Ermittlung der ID eines Schablonenelementes

 

 

class CEinsDlg : public CDialog

{

typedef char TFeld[MaxBreite][MaxBreite];

// benötigte Typen definieren

typedef char TText[MaxInhalt+1];

 

public:

CEinsDlg(CWnd* pParent = NULL); // Konstruktor

enum { IDD = IDD_HAUPTDIALOG }; // DialogID festhalten

 

protected:

virtual BOOL OnInitDialog(); // Start modifizieren

 

afx_msg void OnClose(); // Dialog schließen

afx_msg void OnOK(); // Enter-Taste abfangen

afx_msg void OnNachricht(); // Änderung der Nachricht

afx_msg void OnErgebnis(); // Änderung des Ergebnisses

afx_msg void OnKeyItem(); // Änderung der Schablone

afx_msg void OnHScroll(int nSBCode, int nPos, CScrollBar* pScrollBar);

// auf Änderungen der Schablonenbreite reagieren

afx_msg void OnRechnen(); // Kodierung/Dekodierung einleiten

afx_msg void OnTest(); // Schablone testen

afx_msg void OnAbout(); // Programminfo

 

private:

void UpdateRechnenButton(); // Button auf Kodierung bzw. Dekodierung ändern

void UpdateBreite(); // Schablonenbreite anzeigen

void UpdateLength(int nTextID, int nLength);

// Länge der Nachricht/des Ergebnisses anzeigen

void UpdateKey(); // Schablone aktualisieren

void ShowKey(); // Ergebnis in Schablonenform anzeigen

 

BOOL CheckKey(); // Schablone überprüfen

void GetKey(); // Schablone aus Bildschirmmaske lesen

void CheckKeyItem(int X, int Y); // Schablonenelemen anpassen

void RemoveZeros(TText cText); // Nullen entfernen

 

void Kodieren(); // eigentliche Kodierung

void Dekodieren(); // eigentliche Dekodierung

void GetText(TFeld Key); // Text aus einer Schablonenposition lesen

void SetText(TFeld Key); // Text durch ein Schablonenposition schreiben

void Rotiere(TFeld Alt, TFeld Neu); // Schablone rotieren

 

int m_EditFocus; // aktuelles Edit-Fenster

TText m_Nachricht; // Nachricht

TText m_Ergebnis; // Ergebnis

int m_NachrichtZeichen; // Länge der Nachricht in Zeichen

int m_ErgebnisZeichen; // Länge des Ergebnisses in Zeichen

int m_Zeichen; // Laufvariable beim Kodieren/Dekodieren

TFeld m_Key; // Schablone

int m_Breite; // tatsächliche Schablonenbreite

int m_Inhalt; // Anzahl der Schablonenelemente

 

DECLARE_MESSAGE_MAP() // MessageHandler installieren

};

 

EINS.CPP

 

#include <afxwin.h> // MFC-Bibliothek einbinden

#include "eins.h" // Headerfile einbinden (Definitionen)

 

 

CEinsApp Eins; // eigentliches Programm

 

 

BOOL CEinsApp::InitInstance() // Start modifizieren

{

Enable3dControls(); // 3D-Stil

 

CEinsDlg MyDialog; // Dialog statisch erzeugen

 

m_pMainWnd = &MyDialog; // als Hauptfenster festlegen

return MyDialog.DoModal(); // modal ausführen

}

 

 

 

BEGIN_MESSAGE_MAP(CEinsDlg, CDialog) // alle Messages an Funktionen weiterleiten

ON_EN_SETFOCUS(ID_EDIT_NACHRICHT, OnNachricht)

ON_EN_SETFOCUS(ID_EDIT_ERGEBNIS, OnErgebnis)

ON_EN_CHANGE(ID_EDIT_NACHRICHT, OnNachricht)

ON_EN_CHANGE(ID_EDIT_ERGEBNIS, OnErgebnis)

 

ON_BN_CLICKED(ID_BUTTON_RECHNEN, OnRechnen)

ON_BN_CLICKED(ID_BUTTON_TEST, OnTest)

ON_BN_CLICKED(ID_BUTTON_ABOUT, OnAbout)

 

ON_BN_CLICKED(ID_SCHABLONE+00, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+01, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+02, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+03, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+04, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+05, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+06, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+07, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+08, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+09, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+10, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+11, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+12, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+13, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+14, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+15, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+16, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+17, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+18, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+19, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+20, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+21, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+22, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+23, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+24, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+25, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+26, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+27, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+28, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+29, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+30, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+31, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+32, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+33, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+34, OnKeyItem)

ON_BN_CLICKED(ID_SCHABLONE+35, OnKeyItem)

 

ON_WM_HSCROLL()

ON_WM_CLOSE()

END_MESSAGE_MAP()

 

 

CEinsDlg::CEinsDlg(CWnd* pParent):CDialog(IDD, pParent)

{

m_EditFocus = ID_EDIT_NACHRICHT; // Nachricht als Standard-Edit festlegen

m_Breite = 6; // Breite 6 vorgeben

m_Inhalt = m_Breite*m_Breite; // Elemente aus Breite errechnen

}

 

 

BOOL CEinsDlg::OnInitDialog() // Start modifizieren

{

CDialog::OnInitDialog(); // vererbte Methode aufrufen

 

((CScrollBar*)GetDlgItem(ID_SCROLLBAR_BREITE))->SetScrollRange(2,6,TRUE);

// Scrollbar auf Bereich 2..6 einstellen

UpdateRechnenButton(); // auf Kodierung als Vorgabe schalten

UpdateBreite(); // Breite 6 anzeigen

 

CheckDlgButton(GetSchabloneID(2,0),1); // Schablone aus Aufgabe voreinstellen

CheckDlgButton(GetSchabloneID(3,0),1);

CheckDlgButton(GetSchabloneID(4,1),1);

CheckDlgButton(GetSchabloneID(1,2),1);

CheckDlgButton(GetSchabloneID(3,2),1);

CheckDlgButton(GetSchabloneID(0,4),1);

CheckDlgButton(GetSchabloneID(3,4),1);

CheckDlgButton(GetSchabloneID(5,4),1);

CheckDlgButton(GetSchabloneID(0,5),1);

UpdateKey(); // Schablone aktualisieren

 

CEdit *pEdit2 = (CEdit*)GetDlgItem(ID_EDIT_ERGEBNIS);

CEdit *pEdit1 = (CEdit*)GetDlgItem(ID_EDIT_NACHRICHT);

pEdit2->LimitText(m_Inhalt); // Maximallänge der Texte

pEdit1->LimitText(m_Inhalt);

pEdit2->SetFocus(); // einmal aktivieren, um auf den Focus reagierende

pEdit1->SetFocus(); // Methoden aufzurufen

 

return FALSE; // Focus nicht verändern

}

 

 

void CEinsDlg::OnClose() // Dialog schließen

{

if (MessageBox("Wirklich beenden ?","Ende",MB_YESNO|MB_ICONQUESTION)==IDYES)

CDialog::OnClose(); // Sicherheitsabfrage

}

 

 

void CEinsDlg::OnOK() // Enter-Taste abfangen

{

OnRechnen(); // Kodierung/Dekodierung durchführen

}

 

 

void CEinsDlg::OnNachricht() // Änderung der Nachricht

{

CEdit *pEdit = (CEdit*)GetDlgItem(ID_EDIT_NACHRICHT);

m_NachrichtZeichen = pEdit->LineLength(); // Länge ausgeben

m_EditFocus = ID_EDIT_NACHRICHT; // EditFocus speichern

 

UpdateLength(ID_TEXT_NACHRICHT, m_NachrichtZeichen);

UpdateRechnenButton(); // Rechnenbutton anpassen

}

 

 

void CEinsDlg::OnErgebnis() // Änderung des Ergebnisses

{

CEdit *pEdit = (CEdit*)GetDlgItem(ID_EDIT_ERGEBNIS);

m_ErgebnisZeichen = pEdit->LineLength(); // Länge ausgeben

m_EditFocus = ID_EDIT_ERGEBNIS; // EditFocus speichern

 

UpdateLength(ID_TEXT_ERGEBNIS, m_ErgebnisZeichen);

UpdateRechnenButton(); // Rechnenbutton anpassen

}

 

 

void CEinsDlg::OnKeyItem() // Änderung der Schablone

{

int KeyID = GetCurrentMessage()->wParam - ID_SCHABLONE;

// BasisID abziehen

if ((KeyID>=0)&&(KeyID<MaxInhalt)) // wirklich Schablone ?

{

int X = KeyID%MaxBreite; // Koordinaten errechnen

int Y = KeyID/MaxBreite;

 

CheckKeyItem(X,Y); // CheckButton invertieren

}

}

 

 

void CEinsDlg::OnRechnen() // Kodierung/Dekodierung einleiten

{

switch(m_EditFocus) // Unterscheidung

{

case ID_EDIT_NACHRICHT:

if ((m_NachrichtZeichen==m_Inhalt)||

(MessageBox("Die Nachricht enthält weniger oder mehr Zeichen als der Schlüssel !\nTrotzdem fortfahren ?",

"Problem",MB_YESNO|MB_ICONQUESTION)==IDYES))

Kodieren(); // bei zu wenig Zeichen Sicherheitsabfrage

break;

case ID_EDIT_ERGEBNIS:

if ((m_ErgebnisZeichen==m_Inhalt)||

(MessageBox("Das Ergebnis enthält weniger oder mehr Zeichen als der Schlüssel !\nTrotzdem fortfahren ?",

"Problem",MB_YESNO|MB_ICONQUESTION)==IDYES))

Dekodieren(); // bei zu wenig Zeichen Sicherheitsabfrage

break;

}

}

 

 

void CEinsDlg::OnTest() // Schablone testen

{

GetKey(); // Schablone aus Dialog lesen

if (CheckKey()) // überprüfen (ungültig wird dort abgefangen)

MessageBox("Die Schablone ist gültig.","Schablone testen",MB_OK|MB_ICONINFORMATION);

// bei gültig Meldung

}

 

 

void CEinsDlg::OnAbout() // Programminfo

{

MessageBox("geschrieben von Stephan Brumme\nin Watcom C++ 10.6 mit MFC 3.2","Über...",MB_OK|MB_ICONINFORMATION);

}

 

 

void CEinsDlg::OnHScroll(int nSBCode, int nPos, CScrollBar* pScrollBar)

// auf Änderungen der Schablonenbreite reagieren

{

switch (nSBCode) // je nach Aktion

{

case SB_LINEDOWN: // rechts

case SB_PAGEDOWN:

if ((m_Breite>=2)&&(m_Breite<MaxBreite-2))

m_Breite += 2; // wenn im gültigen Bereich, dann erhöhen

break;

case SB_LINEUP: // links

case SB_PAGEUP:

if ((m_Breite>2)&&(m_Breite<=MaxBreite))

m_Breite -= 2; // wenn im gültigen Bereich, dann erniedrigen

break;

case SB_THUMBPOSITION:

case SB_THUMBTRACK:

m_Breite = nPos/2*2; // direkt Position bestimmen

break;

}

m_Inhalt = m_Breite*m_Breite; // neue Elementanzahl

 

SetDlgItemText(ID_EDIT_NACHRICHT, "");

SetDlgItemText(ID_EDIT_ERGEBNIS, "");

 

UpdateBreite(); // Bildschirm anpassen

UpdateKey();

}

 

 

void CEinsDlg::UpdateRechnenButton() // Button auf Kodierung bzw. Dekodierung ändern

{

char cNachricht[] = "&Verschlüsseln"; // beide Buttonbeschriftungen

char cErgebnis[] = "&Entschlüsseln";

 

switch(m_EditFocus) // je nach Editfocus Beschriftung setzen

{

case ID_EDIT_NACHRICHT:

SetDlgItemText(ID_BUTTON_RECHNEN, cNachricht);

break;

case ID_EDIT_ERGEBNIS:

SetDlgItemText(ID_BUTTON_RECHNEN, cErgebnis);

break;

}

}

 

 

void CEinsDlg::UpdateBreite() // Schablonenbreite anzeigen

{

char cBreite[2]; // Zwischenpuffer

 

sprintf(cBreite, "%i", m_Breite); // Schablonenbreite dort eintragen

SetDlgItemText(ID_TEXT_BREITE, cBreite); // und anzeigen

 

((CScrollBar*)GetDlgItem(ID_SCROLLBAR_BREITE))->SetScrollPos(m_Breite, TRUE);

// ScrollBar anpassen

 

((CEdit*)GetDlgItem(ID_EDIT_ERGEBNIS))->LimitText(m_Inhalt);

((CEdit*)GetDlgItem(ID_EDIT_NACHRICHT))->LimitText(m_Inhalt);

for (int Y=0; Y<MaxBreite; Y++) // jede Position durchlaufen

for (int X=0; X<MaxBreite; X++)

{

GetDlgItem(GetSchabloneID(X,Y))->EnableWindow((X<m_Breite)&&(Y<m_Breite));

// nur Checkbuttons innerhalb der aktuellen

// Schablonengröße anklickbar

CheckDlgButton(GetSchabloneID(X,Y),FALSE);

// bisherige Schablone löschen

}

 

OnNachricht(); // neue Breite mitteilen

OnErgebnis();

}

 

 

void CEinsDlg::UpdateLength(int nTextID, int nLength)

// Länge der Nachricht/des Ergebnisses anzeigen

{

char m_LengthBuf[20]; // Ausgabe der Länge von Nachricht bzw. Ergebnis

sprintf(m_LengthBuf, "Zeichen: %i/%i", nLength, m_Inhalt);

SetDlgItemText(nTextID, m_LengthBuf);

// Länge ausgeben

}

 

 

void CEinsDlg::UpdateKey()

{

for (int Y=0; Y<m_Breite; Y++) // jede Position durchlaufen

for (int X=0; X<m_Breite; X++)

if (IsDlgButtonChecked(GetSchabloneID(X,Y))==1)

CheckKeyItem(X,Y);

}

 

 

void CEinsDlg::ShowKey() // Ergebnis in Schablonenform anzeigen

{

char cAnzeige[200] = ""; // zur Ausgabe

 

for (int Lauf=0; Lauf<m_Inhalt; Lauf++)

{ // komplettes Ergebnis durchlaufen

if (m_Ergebnis[Lauf]==' ') // Leerzeichen ?

sprintf(cAnzeige, "%s_ ", cAnzeige);

else // durch Unterstrich symbolisieren

sprintf(cAnzeige, "%s%c ", cAnzeige, m_Ergebnis[Lauf]);

if ((Lauf%m_Breite)==m_Breite-1) // Zeilenumbruch

sprintf(cAnzeige, "%s\n", cAnzeige);

}

 

MessageBox(cAnzeige, "Ergebnis in Schablonenform", MB_OK|MB_ICONINFORMATION);

// ausgeben

}

 

 

BOOL CEinsDlg::CheckKey() // Schablone überprüfen

{

TFeld Summe, Neu, Dreh;

 

GetKey(); // Schablone holen und überprüfen

 

memset(Summe, 0, sizeof(Summe)); // Summenfeld leeren

memcpy(Neu, m_Key, sizeof(Neu)); // Originalschablone bleibt unverändert

 

for (int Lauf=0; Lauf<Drehungen; Lauf++) // alle 4 Drehungen vollziehen

{

for (int Y=0; Y<m_Breite; Y++) // jede Position durchlaufen

for (int X=0; X<m_Breite; X++)

Summe[Y][X]+=Neu[Y][X]; // Schablone aufaddieren

 

Rotiere(Neu, Dreh); // drehen

memcpy(Neu, Dreh, sizeof(Neu)); // neue Schablone speichern

}

 

for (int Y=0; Y<m_Breite; Y++) // jede Position durchlaufen

for (int X=0; X<m_Breite; X++)

if (Summe[Y][X]!=1) // falls Problem mit Lochanzahl

{

MessageBox("Ungültige Schablone !", "Problem",MB_OK|MB_ICONSTOP);

return FALSE; // Fehlermeldung, Rückmeldung an Aufrufer

}

 

return TRUE; // alles ok

}

 

 

void CEinsDlg::GetKey() // Schablone aus Bildschirmmaske lesen

{

for (int Y=0; Y<m_Breite; Y++) // jede Position durchlaufen

for (int X=0; X<m_Breite; X++)

m_Key[Y][X]=IsDlgButtonChecked(GetSchabloneID(X,Y));

// Zustand auslesen

}

 

 

void CEinsDlg::CheckKeyItem(int X, int Y) // Schablonenelemente anpassen

{

int Check = IsDlgButtonChecked(GetSchabloneID(X,Y));

// Zustand ermitteln

for (int Lauf=0; Lauf<3; Lauf++) // durch Rotation verknüpfte Elemente

{

int TempY = m_Breite-1-X; // rotieren

X = Y;

Y = TempY;

 

GetDlgItem(GetSchabloneID(X,Y))->EnableWindow(1-Check);

// Aktivierbarkeit einstellen

}

}

 

 

void CEinsDlg::RemoveZeros(TText cText) // Nullen entfernen

{

BOOL bEnde = FALSE;

for (int Lauf=0; Lauf<m_Inhalt; Lauf++) // jedes Zeichen untersuchen

if (bEnde)

cText[Lauf] = ' '; // durch Leerzeichen ersetzen

else

if (!cText[Lauf])

bEnde = TRUE;

}

 

 

void CEinsDlg::Kodieren() // eigentliche Kodierung

{

TFeld Neu, Dreh;

 

GetDlgItemText(ID_EDIT_NACHRICHT, m_Nachricht, m_Inhalt+1);

RemoveZeros(m_Nachricht);

m_Zeichen = 0; // Nachricht holen, bei Zeichen 0 anfangen

 

GetKey(); // Schablone holen und überprüfen

if (!CheckKey())

return;

 

memcpy(Neu, m_Key, sizeof(Neu)); // Originalschablone bleibt unverändert

 

for (int Lauf=0; Lauf<Drehungen; Lauf++) // alle 4 Drehungen vollziehen

{

SetText(Neu); // durch Löcher der Schablone schreiben

Rotiere(Neu, Dreh); // drehen

memcpy(Neu, Dreh, sizeof(Neu)); // neue Schablone speichern

}

 

m_Ergebnis[m_Zeichen] = 0; // abschließendes Zero-Byte

SetDlgItemText(ID_EDIT_ERGEBNIS, m_Ergebnis);

// Ergebnis ausgeben

ShowKey(); // Ergebnis in Schablonenform anzeigen

}

 

 

void CEinsDlg::Dekodieren() // eigentliche Dekodierung

{

TFeld Neu, Dreh;

 

GetDlgItemText(ID_EDIT_ERGEBNIS, m_Ergebnis, m_Inhalt+1);

RemoveZeros(m_Ergebnis);

m_Zeichen = 0; // Ergebnis holen, bei Zeichen 0 anfangen

 

GetKey(); // Schablone holen und überprüfen

if (!CheckKey())

return;

 

memcpy(Neu, m_Key, sizeof(Neu)); // Originalschablone bleibt unverändert

 

for (int Lauf=0; Lauf<Drehungen; Lauf++) // alle 4 Drehungen vollziehen

{

GetText(Neu); // aus allen Löchern der Schablone lesen

Rotiere(Neu, Dreh); // drehen

memcpy(Neu, Dreh, sizeof(Neu)); // neue Schablone speichern

}

 

m_Nachricht[m_Zeichen] = 0; // abschließendes Zero-Byte

SetDlgItemText(ID_EDIT_NACHRICHT, m_Nachricht);

// Nachricht ausgeben

}

 

 

void CEinsDlg::GetText(TFeld Key) // Text aus einer Schablonenposition lesen

{

for (int Y=0; Y<m_Breite; Y++) // jede Position durchlaufen

for (int X=0; X<m_Breite; X++)

if (Key[Y][X]) // Loch ?

m_Nachricht[m_Zeichen++]=m_Ergebnis[Y*MaxBreite+X];

// ja, Zeichen lesen

}

 

 

void CEinsDlg::SetText(TFeld Key) // Text durch ein Schablonenposition schreiben

{

for (int Y=0; Y<m_Breite; Y++) // jede Position durchlaufen

for (int X=0; X<m_Breite; X++)

if (Key[Y][X]) // Loch ?

m_Ergebnis[Y*m_Breite+X]=m_Nachricht[m_Zeichen++];

// ja, Zeichen schreiben

}

 

 

void CEinsDlg::Rotiere(TFeld Alt, TFeld Neu) // Schablone rotieren

{

for (int Y=0; Y<m_Breite; Y++) // jede Position durchlaufen

for (int X=0; X<m_Breite; X++)

Neu[Y][X] = Alt[m_Breite-1-X][Y]; // um 90 Grad im Uhrzeigersinn drehen

}

 

EINS.DLG

 

1000 DIALOG FIXED IMPURE 22, 34, 301, 170

STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | DS_CENTERMOUSE | WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU

CAPTION "Aufgabe 1"

FONT 8, "Helv"

BEGIN

CONTROL "KOMM UND BRING JULEE NACH FARNSWORTH", 1001, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 41, 3, 169, 12

CONTROL "Nachricht:", 101, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 3, 3, 36, 8

CONTROL "Ergebnis:", 102, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 3, 20, 37, 8

CONTROL "", 1002, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 41, 20, 169, 12

CONTROL "Push", 1003, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 220, 40, 75, 14

CONTROL "&Autor", 1005, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 220, 80, 75, 14

CONTROL "Edit", 103, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 220, 3, 75, 8

CONTROL "Edit", 104, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 220, 20, 75, 8

CONTROL "", 2000, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 50, 40, 11, 10

CONTROL "", 2001, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 70, 40, 13, 10

CONTROL "", 2002, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 90, 40, 15, 10

CONTROL "Schablone:", 105, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 3, 40, 44, 8

CONTROL "", 2003, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 110, 40, 11, 10

CONTROL "", 2004, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 130, 40, 15, 10

CONTROL "", 2005, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 150, 40, 15, 10

CONTROL "", 2006, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 50, 60, 13, 10

CONTROL "", 2007, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 70, 60, 13, 10

CONTROL "", 2008, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 90, 60, 12, 10

CONTROL "", 2009, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 110, 60, 13, 10

CONTROL "", 2010, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 130, 60, 12, 10

CONTROL "", 2011, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 150, 60, 16, 10

CONTROL "", 2012, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 50, 80, 13, 10

CONTROL "", 2018, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 50, 100, 13, 10

CONTROL "", 2024, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 50, 120, 12, 10

CONTROL "", 2030, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 50, 140, 15, 10

CONTROL "", 2013, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 70, 80, 11, 10

CONTROL "", 2014, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 90, 80, 12, 10

CONTROL "", 2015, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 110, 80, 13, 10

CONTROL "", 2016, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 130, 80, 11, 10

CONTROL "", 2017, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 150, 80, 16, 10

CONTROL "", 2019, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 70, 100, 11, 10

CONTROL "", 2020, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 90, 100, 12, 10

CONTROL "", 2021, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 110, 100, 15, 10

CONTROL "", 2022, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 130, 100, 12, 10

CONTROL "", 2023, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 150, 100, 13, 10

CONTROL "", 2025, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 70, 120, 13, 10

CONTROL "", 2026, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 90, 120, 11, 10

CONTROL "", 2027, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 110, 120, 12, 10

CONTROL "", 2028, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 130, 120, 11, 10

CONTROL "", 2029, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 150, 120, 12, 10

CONTROL "", 2031, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 70, 140, 11, 10

CONTROL "", 2033, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 110, 140, 12, 10

CONTROL "", 2032, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 90, 140, 13, 10

CONTROL "", 2034, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 130, 140, 12, 10

CONTROL "", 2035, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 150, 140, 12, 10

CONTROL "&Schablone testen", 1004, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 220, 60, 75, 14

CONTROL "Breite:", 106, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 180, 154, 23, 8

CONTROL "", 1006, "SCROLLBAR", SBS_HORZ | WS_CHILD | WS_VISIBLE, 58, 154, 113, 10

CONTROL "6", 107, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 204, 154, 9, 8

END

 

RESOURCE.H

 

/* Resourcen für Aufgabe 1 des BWINF 97/98

Autor: Stephan Brumme

*/

 

#define IDD_HAUPTDIALOG 1000 // ID des Dialogfensters

 

#define ID_EDIT_NACHRICHT 1001 // Dialogelemente

#define ID_EDIT_ERGEBNIS 1002

#define ID_BUTTON_RECHNEN 1003

#define ID_BUTTON_TEST 1004

#define ID_BUTTON_ABOUT 1005

#define ID_SCROLLBAR_BREITE 1006

#define ID_TEXT_NACHRICHT 103

#define ID_TEXT_ERGEBNIS 104

#define ID_TEXT_BREITE 107

 

#define ID_SCHABLONE 2000 // BasisID der Schablonen-RadioButtons

// gesamter Bereich 2000-2035