Aufgabe 5: Nach der Party

 

Vorüberlegungen

 

Eigentlich braucht das Programm nur bei jeder bei neuen Festlegung einer Bekanntschaft zu überprüfen, ob ein Partner Kenntnis von Katrins Fest besitzt. Ist dies der Fall, so kennt ab sofort auch der andere Partner das Fest. Das einzige Problem besteht darin, Robert als Partner abzufangen, da er niemandem weitererzählen wird.

 

Auch muß Wissen weitergetragen werden, so daß alle Freunde dieser Bekanntschaften in eventuelle Änderungen bezüglich des Fest involviert werden.

 

Bedienung

 

In der oberen linken Ecke gibt man einen neuen Namen ein, der durch den Button rechts daneben zu den beiden oberen Listen hinzugefügt wird.

 

Um eine Bekanntschaft festzulegen, klickt man die Namen der beiden an, einen in der linken, den anderen in der rechten Liste. Abschließend drückt man den kennt-Button. Jede Bekanntschaft ist in der unteren linken Liste nachzulesen.

 

In der unteren rechten Liste werden alle Freunde der zuletzt selektierten Person angezeigt.

 

Zur einfachen Bestimmung, wer alles Katrins Fest kennt, erhält jeder Wissende ein kleines Kreuz zum Namen hinzu. Allerdings gilt dies nur für die untere rechte Liste.

 

In der Dialogmitte schließlich steht, wie oft Robert von dem Fest hört.

 

Bei Programmstart sind die Namen Katrin und Robert bereits eingetragen, wobei Katrin natürlich Kenntnis von ihrem Fest besitzt.

 

Jeder Gast ist als Freund Katrins einzugeben und die Anzahl aller Personen auf 100 (siehe MaxPersonen) zu beschränken. Es werden keinerlei wiederholte Eingaben mit gleichem Inhalt abgefangen, z.B. doppelte Eingabe des Namens Hans. Dies trifft sowohl auf die Namen (inkl. Robert und Katrin), als auch auf die Bekanntschaftsbeziehungen zu.

 

Dokumentation

 

Bei diesem Programm teilen sich zwei Methoden die Hauptarbeit. Da sie auch Aufgaben zur Bildschirmkommunikation erfüllen, beschreibe ich jetzt nur die zur Aufgabenlösung wesentlichen Bestandteile folgender Funktionen:

void OnKnows();

void UpdateAlleBekanntschaften();

 

OnKnows

 

Diese Methode wird jedesmal aufgerufen, wenn eine neue Bekanntschaft definiert wird

 

Zuerst werden die numerischen Werte des Selektionen in der linken und der rechten oberen Liste bestimmt. Dabei werden zwei Sonderfälle ausgeschlossen:

  1. die Person kennt sich selbst
  2. Robert kennt Katrin (und umgekehrt)

Letzterer Punkt ist zwar inhaltlich nicht richtig, beschreibt aber, daß Katrin Robert nie von dem Fest erzählen würde.

 

Nachdem die Bekanntschaft in der unteren linken Liste eingetragen wurde, erhält das Bekannschaften-Feld einen Eintrag. Sofort wird UpdateAlleBekanntschaften aufgerufen, um mögliches Wissen über das Fest zu verbreiten. Am Schluß wird noch die Liste der Einzelbekanntschaften aktualisiert.

 

UpdateAlleBekanntschaften

 

Diese Methode ist alleinig für das Verknüpfen unterschiedlicher Freundschaften und des entsprechenden Wissens über das Fest zuständig.

 

Dazu wird gleich zu Beginn eine boolesche Variable deklariert, welche jede, noch so geringe, Änderung an einem der beiden Felder Bekanntschaften und KenntFest feststellt. Solange sie wahr ist, wird die Schleife immer wieder durchlaufen. Damit ein vollständiges Bearbeiten abgesichert.

 

Jeder Durchlauf überprüft, ob ein Bekanntschaftsverhältnis zu einer anderen Person vorliegt. Ist dies nicht der Fall, so wird das Verhältnis der umgekehrten Richtung übernommen. Grund dafür ist, das die Kombination (a;b) als sich fremd deklariert sein kann, dagegen (b;a) sich kennt.

 

Danach erfolgt der Test, ob das Fest bekannt ist. Bei Verneinung wird das Wissen des Freundes übernommen. Allerdings muß Robert als Freund ausgeschlossen werden, da er niemandem von Katrins Fest erzählt.

 

Zuletzt erfolgt eine Aktualisierung des Bildschirms.

 

Beispiele

  1. Beispiel:
  2. Für das vorgegebene Beispiel ergibt sich, daß Robert von 7 Personen erfährt, wie toll das Fest war. Dazu gehören: Jochen, Muriel, Cornelia, Peter, Michael, Herbert und Janine.

     

  3. Beispiel:

Robert erfährt somit 1mal von dem Fest. Interessant an dieser Konstellation ist die Reihenfolge. Gibt man erst die Bekanntschaft Christian-Robert, danach Christian-Stephan und zuletzt Stephan-Katrin, so muß das Programm sich rückwärts von Katrin über Stephan und Christian zu Robert vorarbeiten.

 

  1. Beispiel:

Robert erfährt 3mal von dem Fest.

 

Besonders das erste und das dritte Beispiel zeigen, daß Robert nicht von jedem seiner Freunde erzählt bekommt, was für ein tolles Fest Katrin organisiert hat. Dadurch konnte ich auch schnell das Problem erkennen, daß Robert als einziger niemanden sein Wissen weitererzählen darf.

 

Quelltext

 

FUENF.H

 

#include "resource.h"

 

 

class CFuenfApp : public CWinApp // Basisklasse

{

public:

virtual BOOL InitInstance(); // Start überladen

};

 

 

#define KatrinIndex 0 // Katrins Index

#define RobertIndex 1 // Roberts Index

#define MaxPersonen 100

 

class CFuenfDlg : public CDialog // Dialogklasse

{

public:

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

 

enum { IDD = ID_DIALOG }; // ID aus der Resource

 

protected:

virtual BOOL OnInitDialog(); // Dialoginitialisierung

 

afx_msg void OnOK(); // Entertaste

afx_msg void OnAdd(); // Namen hinzufügen

afx_msg void OnKnows(); // kennt-Button

afx_msg void OnLinks(); // Focus auf linke Liste

afx_msg void OnRechts(); // Focus auf rechte Liste

afx_msg void OnAbout(); // Programminfo

afx_msg void OnClose(); // Programm beenden

 

private:

void UpdateEinzelneBekanntschaften(); // einzelne Bekanntschaften anzeigen

void UpdateAlleBekanntschaften(); // alle Bekanntschaften verknüpfen

void UpdateRobert(); // wie oft Robert vom Fest erfährt

void AddToListBoxLinksRechts(LPCSTR cName, BOOL bFest);

// Namen zu beiden oberen Listen hinzufügen

void GetName(int nIndex, char* cName); // Namen holen

void GetMarkedName(int nIndex, char* cName);

// wie GetName, nur mit Markierung

int nFocus; // zuletzt markierter Name

int nPersonen; // Anzahl Personen

 

BOOL Bekanntschaften[MaxPersonen][MaxPersonen];

// alle Bekanntschaften

BOOL KenntFest[MaxPersonen]; // vom Fest Wissende

DECLARE_MESSAGE_MAP() // Messagehandler installieren

};

 

FUENF.CPP

 

#include "afxwin.h" // MFC-Definitionen

#include "fuenf.h" // Headerfile einbinden

 

 

CFuenfApp FuenfApp; // Programm statisch erzeugen

 

 

virtual BOOL CFuenfApp::InitInstance() // Start überladen

{

Enable3dControls(); // 3D-Stil

 

CFuenfDlg dlg; // Dialog statisch erzeugen

m_pMainWnd = &dlg; // Zeiger darauf eintragen

dlg.DoModal(); // modal ausführen

 

return FALSE; // fehlerfrei

}

 

 

 

BEGIN_MESSAGE_MAP(CFuenfDlg, CDialog) // Messages weiterleiten

ON_BN_CLICKED(ID_BUTTON_HINZU, OnAdd)

ON_BN_CLICKED(ID_BUTTON_KENNT, OnKnows)

ON_BN_CLICKED(ID_BUTTON_ABOUT, OnAbout)

 

ON_LBN_SELCHANGE(ID_LISTBOX_KENNT_LINKS, OnLinks)

ON_LBN_SELCHANGE(ID_LISTBOX_KENNT_RECHTS, OnRechts)

ON_WM_CLOSE()

END_MESSAGE_MAP()

 

 

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

// Konstruktor

{

nFocus = ID_LISTBOX_KENNT_LINKS; // Focus auf linke Liste

nPersonen = 0;

memset(Bekanntschaften, FALSE, sizeof(Bekanntschaften));

memset(KenntFest, FALSE, sizeof(KenntFest));

}

 

 

BOOL CFuenfDlg::OnInitDialog() // Dialoginitialisierung

{

CDialog::OnInitDialog(); // an Grundklasse weiterleiten

 

AddToListBoxLinksRechts("Katrin", TRUE); // Katrin einfügen, kennt Fest

AddToListBoxLinksRechts("Robert", FALSE); // Robert einfügen, kennt Fest nicht

 

((CListBox*)GetDlgItem(ID_LISTBOX_KENNT_LINKS))->SetCurSel(KatrinIndex);

((CListBox*)GetDlgItem(ID_LISTBOX_KENNT_RECHTS))->SetCurSel(KatrinIndex);

// Katrin selektieren

UpdateAlleBekanntschaften();

UpdateEinzelneBekanntschaften(); // Katrins Freunde anzeigen

 

return TRUE;

}

 

 

void CFuenfDlg::OnOK() // Entertaste

{

OnAdd(); // Name zu den Listen hinzufügen

}

 

 

void CFuenfDlg::OnAdd() // Namen hinzufügen

{

char cName[50]; // temporär Namen speichern

 

GetDlgItemText(ID_EDIT_NAMEN, cName, 49); // Namen auslesen

if (cName[0]==0) // falls keiner eingegeben

{

MessageBeep(0); // Piepton, Methode beenden

return;

}

SetDlgItemText(ID_EDIT_NAMEN, ""); // Eingabefeld löschen

 

AddToListBoxLinksRechts(cName,FALSE); // Name zu Listen hinzufügen

}

 

 

void CFuenfDlg::OnKnows() // kennt-Button

{

CListBox* pBoxLinks = (CListBox*)GetDlgItem(ID_LISTBOX_KENNT_LINKS);

CListBox* pBoxRechts = (CListBox*)GetDlgItem(ID_LISTBOX_KENNT_RECHTS);

 

int nLinks = pBoxLinks->GetCurSel(); // aktuelle Selektion holen

int nRechts = pBoxRechts->GetCurSel();

 

if ((nLinks==LB_ERR)||(nRechts==LB_ERR)||(nLinks==nRechts))

{ // ungültige Auswahl oder gleicher Name

MessageBeep(0); // Piepton, Methode beenden

return;

}

 

if (((nLinks==KatrinIndex)&&(nRechts==RobertIndex))||

((nLinks==RobertIndex)&&(nRechts==KatrinIndex)))

{ // Kombination Robert-Katrin ausschließen

MessageBox("Robert und Katrin sprechen nicht miteinander über das Fest.","Problem",MB_OK|MB_ICONSTOP);

return;

}

 

char cLinks[50], cRechts[50]; // Namen temporär speichern

GetName(nLinks,cLinks); // linker Name

GetName(nRechts,cRechts); // rechter Name

char cWerKenntWen[110]; // Kombination beider Namen

sprintf(cWerKenntWen, "%s kennt %s", cLinks, cRechts);

CListBox* pBox = (CListBox*)GetDlgItem(ID_LISTBOX_ALLE_BEKANNTSCHAFTEN);

pBox->InsertString(-1,cWerKenntWen); // Kombination ans Ende anhängen

 

Bekanntschaften[nLinks][nRechts] = TRUE;

UpdateAlleBekanntschaften();

 

UpdateEinzelneBekanntschaften(); // Bildschirmanzeige anpassen

}

 

 

void CFuenfDlg::OnLinks() // Focus auf linke Liste

{

nFocus = ID_LISTBOX_KENNT_LINKS; // Focus speichern

UpdateEinzelneBekanntschaften(); // Bildschirmanzeige anpassen

}

 

 

void CFuenfDlg::OnRechts() // Focus auf linke Liste

{

nFocus = ID_LISTBOX_KENNT_RECHTS; // Focus speichern

UpdateEinzelneBekanntschaften(); // Bildschirmanzeige anpassen

}

 

 

void CFuenfDlg::OnAbout() // Programminfo

{

MessageBox("programmiert von Stephan Brumme\nin Watcom C++ 10.6 mit MFC 3.2",

"Über...", MB_OK|MB_ICONINFORMATION);

}

 

 

void CFuenfDlg::OnClose() // Programm beenden

{

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

// Sicherheitsabfrage

CDialog::OnClose();

}

 

 

void CFuenfDlg::UpdateEinzelneBekanntschaften() // einzelne Bekanntschaften anzeigen

{

CListBox* pBoxLinksRechts = (CListBox*)GetDlgItem(nFocus);

CListBox* pBoxAlle = (CListBox*)GetDlgItem(ID_LISTBOX_ALLE_BEKANNTSCHAFTEN);

CListBox* pBoxEinzeln = (CListBox*)GetDlgItem(ID_LISTBOX_EINZELNE_BEKANNTSCHAFTEN);

 

char cName[50], cText[60];

int nName = pBoxLinksRechts->GetCurSel(); // selektiertes Element holen

 

GetMarkedName(nName, cName); // Namen mit Markierung identifizieren

sprintf(cText, "%s kennt:", cName);

SetDlgItemText(ID_TEXT_EINZELNE_BEKANNTSCHAFTEN, cText);

// Überschrift der Einzelbekanntschaften

// anpassen

pBoxEinzeln->ResetContent(); // Liste löschen

 

if (pBoxAlle->GetCount()>0) // nur falls bereits Bekanntschaften

for(int Lauf=0; Lauf<MaxPersonen; Lauf++)// alle Bekanntschaften durchlaufen

if (Bekanntschaften[nName][Lauf]) // nur wenn Einzelperson gemeint

{

char cFreund[50];

GetMarkedName(Lauf, cFreund);

// Freund mit Markierung erkennen

pBoxEinzeln->InsertString(-1,cFreund);

// Freund in Liste eintragen

}

}

 

 

void CFuenfDlg::UpdateAlleBekanntschaften() // alle Bekanntschaften verknüpfen

{

BOOL bNeu = TRUE; // wahr, wenn neue Bekanntschaften verabeitet

while (bNeu)

{

bNeu = FALSE; // von bearbeitetem Feld ausgehen

for (int X=0; X<nPersonen; X++) // alle Personen durchlaufen

for (int Y=0; Y<nPersonen; Y++) // alle möglichen Freunde

if (X!=Y) // sich selbst ausschließen

{

if (!Bekanntschaften[X][Y]) // noch keine Bekanntschaft ?

if ((Bekanntschaften[X][Y]=Bekanntschaften[Y][X])==TRUE)

bNeu = TRUE; // fast doch, eintragen & neues Feld

if ((Y!=RobertIndex)&&Bekanntschaften[X][Y]&&!KenntFest[X])

// falls nicht Robert der Freund und

// das Fest nicht bekannt

if ((KenntFest[X]=KenntFest[Y])==TRUE)

bNeu = TRUE; // wenn Fest bekannt neues Feld

}

}

 

UpdateRobert(); // Bildschirmanzeige ändern

}

 

 

void CFuenfDlg::UpdateRobert() // wie oft Robert vom Fest erfährt

{

int nRobertWirdErzaehlt = 0; // erstmal Fest unbekannt

for (int Lauf=0; Lauf<nPersonen; Lauf++) // alle Personen

if (Bekanntschaften[RobertIndex][Lauf]&&KenntFest[Lauf])

// wenn Freund und Fest bekannt

nRobertWirdErzaehlt++; // Anzahl Erzählender erhöhen

 

char cText[50];

 

sprintf(cText, "Robert wird %imal von dem Fest erzählt.", nRobertWirdErzaehlt);

SetDlgItemText(ID_TEXT_ROBERT, cText); // Anzahl in Bildmitte anzeigen

}

 

 

void CFuenfDlg::AddToListBoxLinksRechts(LPCSTR cName, BOOL bFest)

{ // Namen zu beiden oberen Listen hinzufügen

nPersonen++;

((CListBox*)GetDlgItem(ID_LISTBOX_KENNT_LINKS))->InsertString(-1, cName);

((CListBox*)GetDlgItem(ID_LISTBOX_KENNT_RECHTS))->InsertString(-1, cName);

// beide Listen ändern

int nIndex = ((CListBox*)GetDlgItem(ID_LISTBOX_KENNT_LINKS))->GetCount()-1;

KenntFest[nIndex] = bFest; // Festkenntnis speichern

UpdateAlleBekanntschaften();

}

 

 

void CFuenfDlg::GetName(int nIndex, char* cName)// Namen holen

{

((CListBox*)GetDlgItem(ID_LISTBOX_KENNT_LINKS))->GetText(nIndex, cName);

}

 

 

void CFuenfDlg::GetMarkedName(int nIndex, char* cName)

{ // wie GetName, nur mit Markierung

CListBox* pBox = (CListBox*)GetDlgItem(ID_LISTBOX_KENNT_LINKS);

 

pBox->GetText(nIndex, cName);

if (KenntFest[nIndex])

sprintf(cName, "%s*", cName); // bei Festkenntnis Stern anhängen

}

 

FUENF.DLG

 

100 DIALOG FIXED IMPURE 27, 14, 231, 175

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

CAPTION "Aufgabe 5"

FONT 8, "Helv"

BEGIN

CONTROL "", 101, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 10, 10, 75, 12

CONTROL "&Hinzu", 102, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 95, 10, 40, 14

CONTROL "", 103, "LISTBOX", LBS_STANDARD | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP, 10, 30, 75, 66

CONTROL "", 105, "LISTBOX", LBS_STANDARD | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP, 145, 30, 75, 66

CONTROL "&kennt", 104, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 95, 40, 40, 14

CONTROL "", 106, "LISTBOX", LBS_STANDARD | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP, 10, 110, 120, 66

CONTROL "", 107, "LISTBOX", LBS_STANDARD | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP, 145, 110, 75, 66

CONTROL "Alle Bekanntschaften:", 111, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 10, 100, 72, 8

CONTROL "Text", 108, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 145, 100, 83, 8

CONTROL "&Autor", 110, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 180, 10, 40, 14

CONTROL "Robert wird 4mal von dem Fest erzählt.", 109, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 95, 65, 40, 33

END

 

RESOURCE.H

 

#define ID_DIALOG 100

 

#define ID_EDIT_NAMEN 101

#define ID_BUTTON_HINZU 102

#define ID_LISTBOX_KENNT_LINKS 103

#define ID_BUTTON_KENNT 104

#define ID_LISTBOX_KENNT_RECHTS 105

#define ID_LISTBOX_ALLE_BEKANNTSCHAFTEN 106

#define ID_LISTBOX_EINZELNE_BEKANNTSCHAFTEN 107

#define ID_TEXT_EINZELNE_BEKANNTSCHAFTEN 108

#define ID_TEXT_ROBERT 109

#define ID_BUTTON_ABOUT 110