Seite 1 von 1

Code von Windows zu OS X

Verfasst: Sa Feb 08, 2014 4:06 pm
von Mampf111
Guten Tag,

ich habe ein kleines Übungsprogramm geschrieben. Funktioniert alles wunderbar und genau so wie ich es mir vorgestellt habe. Allerdings habe ich das Programm unter Windows mit Code::Blocks geschrieben.
Nun wollte ich es auf meinem Mac mit xCode ebenfalls erstellen. Allerdings gab es dabei Probleme und 'Build failed'.
Ich wusste, dass ich Dinge in meinem Code verwendet habe, die nicht 1:1 auf OS X übertragbar sind. Ich hatte da allerdings mit anderen Meldungen gerechnet, mit denen ich selbst mehr anfangen kann..

Vielleicht könnt ihr mir helfen, dass mein kleines Programm auch unter OS X läuft (bzw. mit kleinen Änderungen läuft)

Programmcode:

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>

//> Unter Windows "cls", unter Unix "clear"
#define CLEAR "clear"
#define POS_MARKER '.'
#define P1_MARKER 'X'
#define P2_MARKER 'O'


//>globale Variablen
char feld[4][4];
int posX=1, posY=1, akt_spieler=1, gewinner=0;


//> setzt alle Variablen auf den Startwert zur¸ck und lˆscht die Konsole
void reset()
{
    posX=1;
    posY=1;
    akt_spieler=1;
    gewinner=0;
    
    int x,y;
    for(x=0; x<=4;x++){
        for(y=0; y<=4; y++){
            feld[x][y]=' ';
        }
    }
    
    system(CLEAR);
}

//>Schreibt das Spielfeld neu
void print_feld()
{
    int x,y;
    for(x=0; x<=4;x++){
        for(y=0; y<=4; y++){
            printf("%c\t", feld[x][y]);
        }
        printf("\n\n");
    }
}


//>Erzeugt das Spielfeld beim Start
void spielfeld_erzeugen()
{
    int x,y;
    for(x=0; x<=4;x++){
        for(y=0; y<=4; y++){
            if(x==0||x==4){
                feld[x][y]='_';
            }
            if((x==1||x==2||x==3)&&(y==1||y==2||y==3)){
                feld[x][y]=' ';
            }
            if(y==0||y==4){
                feld[x][y]='|';
            }
        }
    }
}


//>Schreibt an eine Position ein Leerzeichen, wenn die Stelle kein X oder O enthaelt
void clear_spot()
{
    if(feld[posX][posY]!=P1_MARKER && feld[posX][posY]!=P2_MARKER){
        feld[posX][posY]=' ';
    }
}


//> Schreibt an die Position ein -, wenn die Stelle kein X oder O enthaelt
void print_pos()
{
    if(feld[posX][posY]!=P1_MARKER && feld[posX][posY]!=P2_MARKER){
        feld[posX][posY]=POS_MARKER;
    }
}


//>Wartet auf Eingabe - bei w nach oben - bei s nach unten - bei a nach links - bei d nach rechts - bei enter Zeichen des spielers schreiben
void eingabe()
{
    int eing;
    
    eing=getch();
    switch(eing){
        case 'w':
            if(posX==1){
                eingabe();
            }else{
                clear_spot();
                posX--;
                print_pos();
            }
            break;
            
        case 's':
            if(posX==3){
                eingabe();
            }else{
                clear_spot();
                posX++;
                print_pos();
            }
            break;
            
        case 'a':
            if(posY==1){
                eingabe();
            }else{
                clear_spot();
                posY--;
                print_pos();
            }
            break;
            
        case 'd':
            if(posY==3){
                eingabe();
            }else{
                clear_spot();
                posY++;
                print_pos();
            }
            break;
            
        case 13:
            if(feld[posX][posY]==P1_MARKER||feld[posX][posY]==P2_MARKER){
                eingabe();
            }else{
                if(akt_spieler==1){
                    feld[posX][posY]=P1_MARKER;
                    print_feld();
                    akt_spieler++;
                }else{
                    feld[posX][posY]=P2_MARKER;
                    print_feld();
                    akt_spieler--;
                }
            }
            break;
            
        default:
            eingabe();
    }
}


//>Pr¸ft die Zeilen auf einen Gewinner, wurde ein Gewinn festgestellt return 1, sonst 0. aendert den gewinner entsprechend
int zeile()
{
    if((feld[1][1]==P1_MARKER && feld[1][2]==P1_MARKER && feld[1][3]==P1_MARKER) ||
       (feld[2][1]==P1_MARKER && feld[2][2]==P1_MARKER && feld[2][3]==P1_MARKER) ||
       (feld[3][1]==P1_MARKER && feld[3][2]==P1_MARKER && feld[3][3]==P1_MARKER))
    {
        return 1;
        gewinner = 1;
    }
    
    
    if((feld[1][1]==P2_MARKER && feld[1][2]==P2_MARKER && feld[1][3]==P2_MARKER) ||
       (feld[2][1]==P2_MARKER && feld[2][2]==P2_MARKER && feld[2][3]==P2_MARKER) ||
       (feld[3][1]==P2_MARKER && feld[3][2]==P2_MARKER && feld[3][3]==P2_MARKER))
    {
        gewinner = 2;
        return 1;
    }
    
    return 0;
}


//>Pr¸ft die Spalten auf einen Gewinner, wurde ein Gewinn festgestellt return 1, sonst 0. aendert den gewinner entsprechend
int spalte()
{
    if((feld[1][1]==P1_MARKER && feld[2][1]==P1_MARKER && feld[3][1]==P1_MARKER) ||
       (feld[1][2]==P1_MARKER && feld[2][2]==P1_MARKER && feld[3][2]==P1_MARKER) ||
       (feld[1][3]==P1_MARKER && feld[2][3]==P1_MARKER && feld[3][3]==P1_MARKER))
    {
        gewinner = 1;
        return 1;
    }
    
    
    if((feld[1][1]==P2_MARKER && feld[2][1]==P2_MARKER && feld[3][1]==P2_MARKER) ||
       (feld[1][2]==P2_MARKER && feld[2][2]==P2_MARKER && feld[3][2]==P2_MARKER) ||
       (feld[1][3]==P2_MARKER && feld[2][3]==P2_MARKER && feld[3][3]==P2_MARKER))
    {
        gewinner = 2;
        return 1;
    }
    
    return 0;
}


//>Pr¸ft die Vertiklen auf einen Gewinner, wurde ein Gewinn festgestellt return 1, sonst 0. aendert den gewinner entsprechend
int vert()
{
    if((feld[1][1]==P1_MARKER && feld[2][2]==P1_MARKER && feld[3][3]==P1_MARKER) ||
       (feld[1][3]==P1_MARKER && feld[2][2]==P1_MARKER && feld[3][1]==P1_MARKER))
    {
        gewinner = 1;
        return 1;
    }
    
    
    if((feld[1][1]==P2_MARKER && feld[2][2]==P2_MARKER && feld[3][3]==P2_MARKER) ||
       (feld[1][3]==P2_MARKER && feld[2][2]==P2_MARKER && feld[3][1]==P2_MARKER))
    {
        gewinner = 2;
        return 1;
    }
    
    return 0;
}


//>pr¸ft, ob das Spielfeld voll ist. wenn ja return 0, sonst 1
int feld_voll()
{
    if((feld[1][1]==P1_MARKER || feld[1][1]==P2_MARKER) &&
       (feld[1][2]==P1_MARKER || feld[1][2]==P2_MARKER) &&
       (feld[1][3]==P1_MARKER || feld[1][3]==P2_MARKER) &&
       (feld[2][1]==P1_MARKER || feld[2][1]==P2_MARKER) &&
       (feld[2][2]==P1_MARKER || feld[2][2]==P2_MARKER) &&
       (feld[2][3]==P1_MARKER || feld[2][3]==P2_MARKER) &&
       (feld[3][1]==P1_MARKER || feld[3][1]==P2_MARKER) &&
       (feld[3][2]==P1_MARKER || feld[3][2]==P2_MARKER) &&
       (feld[3][3]==P1_MARKER || feld[3][3]==P2_MARKER))
    {
        return 0;
    }
    
    return 1;
}


//pr¸ft, ob ein gewinner ermittelt wurde. wenn ja return 0, sonst 1
int gewinn()
{
    if(zeile()||spalte()||vert()){
        return 0;
    }
    
    return 1;
}



int main()
{
    spielfeld_erzeugen();
    print_pos();
    
    while(gewinn() && feld_voll()){
        printf("\n\tT I C \t T A C \t T O E\n\n");
        printf("\tw\tPosition nach oben\n"
               "\ta\tPosition nach links\n"
               "\ts\tPosition nach unten\n"
               "\td\tPosition nach rechts\n"
               "\tEnter\tMarker setzen\n\n");
        print_feld();
        printf("\nSpieler %i ist am Zug!\n", akt_spieler);
        eingabe();
        system(CLEAR);
    }
    
    printf("\n\t T I C \t T A C \t T O E\n\n");
    print_feld();
    
    if(gewinner==0){
        printf("\n\tEs gibt keinen Sieger!!\n");
    }else{
        printf("\n\tSPIELER %i HAT GEWONNEN!!\n", gewinner);
    }
    
    printf("\n\n\tNoch mal spielen\?(j/n)\n");
    
abfrage:
    switch (getch()){
        case 'j':
            reset();
            main();
            break;
            
        case 'n':
            printf("\n\n\tOk, Tschau!!\n");
            break;
            
        default:
            goto abfrage;
    }
    
    return 0;
}

Fehlermeldung von xCode:
Bildschirmfoto 2014-02-08 um 15.55.26.png

Re: Code von Windows zu OS X

Verfasst: Sa Feb 08, 2014 5:35 pm
von mfro
Die Fehlermeldungen bedeuten, daß der Linker die Funktionen wgetch() und stdscr() vermisst. Die sind in libcurses (oder libncurses) enthalten. Wenn Du die noch zum Build hinzufügst (im Project Navigator auf das Target klicken, dann unter "Build Phases" "Link Binary with Libraries" libcurses (oder libncurses) hinzufügen), läuft der Build durch.

Allerdings hat dein Programm noch (mindestens einen) groben Fehler, der es zum Absturz bringt (kann eigentlich schon unter Windows nicht richtig funktioniert haben).

Re: Code von Windows zu OS X

Verfasst: So Feb 09, 2014 12:53 pm
von Mampf111
Vielen Dank für deine Antwort!
mfro hat geschrieben:dann unter "Build Phases" "Link Binary with Libraries" libcurses (oder libncurses) hinzufügen
Wie komme ich dort hin?
EDIT: Habe es gefunden! Kann jetzt das Programm builden, danke!
Allerdings hängt es dann während der Eingabe und es tut sich nichts
mfro hat geschrieben:Allerdings hat dein Programm noch (mindestens einen) groben Fehler
Welche denn? Unter Windows hat das Programm so funktioniert wie ich es mit gewünscht habe. Mir ist dabei bislang nichts aufgefallen

Re: Code von Windows zu OS X

Verfasst: So Feb 09, 2014 1:20 pm
von mfro
Mampf111 hat geschrieben:Vielen Dank für deine Antwort!
mfro hat geschrieben:dann unter "Build Phases" "Link Binary with Libraries" libcurses (oder libncurses) hinzufügen
Wie komme ich dort hin?
EDIT: Habe es gefunden! Kann jetzt das Programm builden, danke!
Allerdings hängt es dann während der Eingabe und es tut sich nichts
mfro hat geschrieben:Allerdings hat dein Programm noch (mindestens einen) groben Fehler
Welche denn? Unter Windows hat das Programm so funktioniert wie ich es mit gewünscht habe. Mir ist dabei bislang nichts aufgefallen
Es sind mindestens zwei Fehler: Du initialisierst curses nicht richtig (das mag bei einer "Nachbildung" funktionieren, aber "das Echte" mag das nicht).
Du solltest darüber hinaus die printf()-Ausgaben durch printw() ersetzen. Sonst kommt curses durcheinander.

Wenn die Konsole im "no-delay" mode ist (ist sie im "richtigen" curses normalerweise), kommt ein weiterer (grober) Fehler in eingabe() zum Vorschein: anstatt die Tastatur in einer Schleife abzufragen, rufst Du - wenn die Taste nicht dabei war, auf die Du wartest - eingabe() rekursiv erneut auf.

Das führt in kürzester Zeit zu einem Stacküberlauf.

Einen ähnlichen Fehler hast Du in main() (ruft sich auch selbst auf).

Re: Code von Windows zu OS X

Verfasst: Mo Feb 10, 2014 9:57 am
von Mampf111
mfro hat geschrieben:anstatt die Tastatur in einer Schleife abzufragen
Warum ist das besser, als eine rekursive Lösung?

Re: Code von Windows zu OS X

Verfasst: Mo Feb 10, 2014 10:20 am
von cloidnerux
Warum ist das besser, als eine rekursive Lösung?
Rekursion ist zu vermeiden, wenn man sich nicht sicher sein kann, ob die Funktion nach einer gewissen maximal anzahl an aufrufen beendet werden kann.
Jeder Funktionsaufruf legt neue Daten auf den Stack und irgendwann ist dieser voll, was dazu führt, dass es eine Stack OVerflow Exception gibt und dein Programm beendet wird, mitunter Kommentarlos.
Daher ist es immer Ratsam, einen iterativen Algorithmus zu verwenden, also das Nutzen von Schleifen, anstatt Rekursion.
Zudem ist ein iterativer Algorithmus in der Regel schneller/effizienter als eine rekursive Implementation.

Re: Code von Windows zu OS X

Verfasst: Mo Feb 10, 2014 6:31 pm
von mfro
Mampf111 hat geschrieben:
mfro hat geschrieben:anstatt die Tastatur in einer Schleife abzufragen
Warum ist das besser, als eine rekursive Lösung?
Weil rekursive Lösungen nur für rekursiv zu lösende Probleme taugen 8-) .

Ernsthaft: daß sich eine Funktion, die beim ersten Aufruf nicht das gewünschte Ergebnis liefert, einfach selbst nochmal aufruft, ist keine "rekursive Lösung" sondern ein Fehler. Jedenfalls dann, wenn - wie in diesem Fall - das gewünschte Ergebnis (und damit die Existenz einer Abbruchbedingung) von Benutzereingaben abhängig ist.

Rekursive Algorithmen bieten sich dort an, wo sich "ein großes Problem" mit einer durch sich selbst definierten Funktion in eine endliche Anzahl kleinerer Probleme zerlegen und dadurch lösen läßt. Das kann z.B. eine mathematische Reihenentwicklung oder ein Sortieralgorithmus (Quicksort) sein. Ganz wichtig ist eine definierte Abbruchbedingung, sonst landet man (wie in deinem Programm) bei einem endlosen Selbstaufruf, der durch Stacküberlauf zum Absturz führt.

Das klassische Beispiel für Rekursion ist die Addition aller natürlicher Zahlen von 1 bis n (die "naive Lösung" der Gaußschen Summenformel, sum(n)). Das läßt sich auch als n + (sum(n - 1)) ausdrücken und man kommt zu dem Ergebnis

Code: Alles auswählen

int sum(int n)
{
    if (n == 1)
        return n;
    else
        return sum(n - 1) + n;
}
(daß sich das auch als sum = n * (n + 1) / 2 in einer Zeile hinschreiben läßt, ist hier natürlich didaktisch sehr ungeschickt, aber nicht zu ändern ;) ).

die iterative Lösung (die hier ganz einfach, aber längst nicht so hübsch ist) sähe so aus:

Code: Alles auswählen

int isum(int n)
{
    int i;
    int ret = 0;

    for (i = 1; i <= n; i++)
    {
        ret += i;
    }
    return ret;
}


Re: Code von Windows zu OS X

Verfasst: Di Feb 11, 2014 7:45 am
von Mampf111
Sehr schöne Erklärung! Vielen Dank dafür!

Re: Code von Windows zu OS X

Verfasst: Di Feb 11, 2014 11:29 am
von oenone
Den Aufruf von main() solltest du dir abgewöhnen. Vor Allem, wenn du irgendwann C++ machen willst, dort ist das nämlich nicht erlaubt.

Außerdem wird ein goto sehr ungern gesehen. Gerade dort, wo du es benutzt, kann es sehr leicht durch eine Schleife ersetzt werden.