4-Gewinnt Problem
-
ja klar, da k von 0 hochzählt darf ich maximal eine 4 nehmen
-
Neues Problem
Habe versucht, dass er erkennt ob die unterste zeile schon belegt ist und gegebenenfalls eine zeile weiter nach oben springt (f--).
Funktioniert aber nicht, wenn ich mit dem cursor über das feld[f][s] gehe, dann zeigt er mit nach der while-schleife eine speicheradresse an. Ich glaube hier liegt das Problem
for (i = 0; i < 5; i++){ printf("Spieler2: In welche Spalte wollen Sie ihren Spielchip setzen?\n"); scanf("%d", &s); system("cls"); int f = 4; while (feld[f][s] != 32){ f--; } feld[f][s] == 'X'; for (int i = 0; i < 5; i++){ for (int k = 0; k < 7; k++){ printf("%c", feld[i][k]); } printf("\n"); } }
-
Das Problem ist, was du in Zeile 32 geschrieben hast.
Was soll das passieren?
Was steht da und passiert wirklich.
-
meinst du weil ich da feld mit [i] ausgebe und vorher mit [f] angegeben hab?
ich weiß dass ich selber drauf kommen soll, aber stehe echt auf dem Schlauch.
Wäre dir dankbar wenn du meinen letzten code-abschnitt verbessern könntest.
-
Sorry, ich meinte Zeile 12 :
feld[f][s] == 'X';
Da ist der noch Fehler drin.
~(vielleicht hat mich die 32 in Zeile 9 verwirrt)~
-
Dulfried schrieb:
Wäre dir dankbar wenn du meinen letzten code-abschnitt verbessern könntest.
Nee, Jung. DirkB hat dir bereits geschrieben, dass du für so was kleine Funktionen schreiben sollst, die Teilaufgaben übernehmen. Eine Funktion, um den gegenwärtigen Status anzuzeigen, eine Funktion, um einen Punkt in eine Spalte zu legen (den Code hast du sogar großzügigerweise von mir bekommen). Eine Möglichkeit, um dir das Spielfeld - sogar mit Rahmen! - anzeigen zu lassen bekommst du locker in 26 Zeilen Code hin. Vielleicht ein bisschen mehr, wenn du direkt ein eindimensionales Array verwendest und mehr mit Parametern arbeitest, die Länge und Breite des gegenwärtigen Feldes mit übergeben.
Waurm verwendest du 32 statt einfach das Leerzeichen? Warum verwendest du nicht direkt
memset
?#define EMPTY ' ' const size_t rows=5; const size_t columns=7; char tiles[rows*columns]; memset(&tiles,EMPTY,sizeof(tiles));
Die Speicheradresse, die du vermutlich im Debugger gesehen hast, war ein Wert, auf den du gar nicht zugreifen solltest. Das ist so der erste Schubser in Richtung "prüft mal auf Zugriffe, die über den reservierten Speicher hinausgehen."
Prüfst du, ob der Wert in
s
in den erlaubten Grenzen liegt? Erste Sache, die man macht. Und==
ist falsch, du möchtest zuweisen, nicht vergleichen.Noch eine Sache: Unter *nix-Systemen kann man einfach:
puts("\ec");
machen, und dann wird der Bildschirm geleert. Ich glaube nicht, dass das unter Windows möglich ist, aber ausprobieren geht über studieren.
-
dachschaden schrieb:
... und dann wird der Bildschirm gelehrt. Ich glaube nicht, dass das unter Windows möglich ist, aber ausprobieren geht über studieren.
Nee, unter Windows muss man den Bildschirm schon selber lernen.
Es gibt unter Windows aber jede Menge Funktionen für die Konsole, mit deren Hilfe man sich kleine Hilfsfunktionen schreiben kann, die zB. die Konsole leeren, die Konsole in der Größe verändern, einzelne Zeichen direkt an der gewünschten Position ausgeben - so dass für so ein Spiel zB. gar nicht bei jeder Ausgabe die gesamte Konsole geleert werden muss, Zeichenpositionen eine andere Farbe geben, und und und ...
Einfach mal im etwas weiter oben angesiedelten Konsoleforum stöbern. Das ist zwar für neue Beiträge geschlossen, aber für das Hantieren mit der Konsole findet man da jede Menge nützliche Codefragmente.Oder, hier studieren und dann selbst machen:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682073(v=vs.85).aspx
-
danke für deinen hinweis, jetzt funktioniert wenigstens mal mein grundprinzip, welches ich noch erweitern werde.
-
nochmal eine kurze Frage:
Also mein programm lässt den spieler nun eine spalte auswählen, in welche der
chip bis zum letzten freien Platz durchrutsch.
Das Problem ist jetzt, dass die Gewinnabfrage horizontal nicht funktionier, ich den Fehler aber einfach nicht finde. (Die Abfrage vertikal funktioniert).Mein Programm geht in die schleifen einfach nicht rein, ich hoffe ihr seht den
Fehlerchar feld[5][7] = { { 32, 32, 32, 32, 32, 32, 32 }, { 32, 32, 32, 32, 32, 32, 32 }, { 32, 32, 32, 32, 32, 32, 32 }, { 32, 32, 32, 32, 32, 32, 32 }, { 32, 32, 32, 32, 32, 32, 32 } }; int z=0; int s = 0; int gewonnen1 = 0, gewonnen2=0; int reihe = 1; int k = 0; int i = 0; for (int i = 0; i < 5; i++){ for (int k = 0; k < 7; k++){ printf("%c", feld[i][k]); } printf("\n"); } while (gewonnen1 != 1 && gewonnen2 !=1){ if (reihe == 1){ printf("Spieler1: In welche Spalte wollen Sie ihren Spielchip setzen?\n"); scanf("%d", &s); system("cls"); int f = 4; while (feld[f][s] != 32){ f--; } feld[f][s] = 'X'; for (int i = 0; i < 5; i++){ for (int k = 0; k < 7; k++){ printf("%c", feld[i][k]); } printf("\n"); reihe = 2; } //Gewinnabfrage vertikal if (i<2 && i >=0 && k < 7 && k>=0){ if (feld[i][k] == 'X' && feld[i + 1][k] == 'X' && feld[i + 2][k] == 'X' && feld[i + 3][k] == 'X'){ gewonnen1 = 1; } if (feld[i+1][k] == 'X' && feld[i + 2][k] == 'X' && feld[i + 3][k] == 'X' && feld[i + 4][k] == 'X'){ gewonnen1 = 1; } } //Gewinnabfrage horizontal if (i<=4 && i >= 0 && k <= 3 && k >= 0){ if (feld[i][k] == 'X' && feld[i][k + 1] == 'X' && feld[i][k + 2] == 'X' && feld[i][k + 3] == 'X'){ gewonnen1 = 1; } if (feld[i][k + 1] == 'X' && feld[i][k + 2] == 'X' && feld[i][k + 3] == 'X' && feld[i][k + 4] == 'X'){ gewonnen1 = 1; } if (feld[i][k + 2] == 'X' && feld[i][k + 3] == 'X' && feld[i][k + 4] == 'X' && feld[i][k + 5] == 'X'){ gewonnen1 = 1; } if (feld[i][k + 3] == 'X' && feld[i][k + 4] == 'X' && feld[i][k + 5] == 'X' && feld[i][k + 6] == 'X'){ gewonnen1 = 1; } }
-
Dann überlege mal welchen Wert i und k nach der for-Schleife haben? Du möchtest wohl eher f und s abfragen.
PS: Ich kenne "4 gewinnt" eher mit einem 6*7 Feld. Du solltest statt der Literale daher besser Konstanten (d.h. Defines) verwenden, um das flexibler zu gestalten.
-
also die größe des spielfeldes ist durch die aufgabenstellung festgelegt.
i hat werte zwischen 0 und 4 und k nimmt werte zwischen 0 und 7 an ?!
Aber hieran kann ja kein Fehler liegen oder?
Denn die vertikale gewinnabfrage klappt.
-
Mir ist gerade aufgefallen dass bei der vertikalen abfrage auch nur der erste fall funktioniert.
Aber was ist an meiner Lösung falsch? und wie kann ich es anders machen?
-
Die Probleme fangen damit an, daß
Dulfried schrieb:
int f = 4; while (feld[f][s] != 32){ f--; } feld[f][s] == 'X';
nicht tut was du denks/willst.
-
Und ich kann DirkB und dachschaden nur zustmmen.
dachschaden schrieb:
Nee, Jung. DirkB hat dir bereits geschrieben, dass du für so was kleine Funktionen schreiben sollst, die Teilaufgaben übernehmen. [...]
Schreibe für jedes Teilproblem eine Funktion. Teste sie. Beginne mit den simplen. Zum Bleistift:
#include <assert.h> #include <stddef.h> #include <stdbool.h> #include <memory.h> #include <stdio.h> void clear( FILE * input_stream ) { assert( input_stream ); int ch; while( ( ch = fgetc( input_stream ) ) != '\n' && ch != EOF ); } typedef enum board_size_tag { BOARD_WIDTH = 16, BOARD_HEIGHT = 24 } board_size_t; typedef enum player_tag { PLAYER_NONE, PLAYER_1, PLAYER_2, } player_t; char const player_symbols[] = { ' ', 'X', 'O' }; typedef struct connect_four_tag { player_t board[ BOARD_HEIGHT * BOARD_WIDTH ]; player_t current_player; size_t num_rounds; size_t last_move_row; size_t last_move_column; } connect_four_t; void connect_four_create( connect_four_t * connect_four ) { assert( connect_four ); memset( connect_four->board, 0, sizeof connect_four->board ); connect_four->current_player = PLAYER_1; connect_four->num_rounds = 0; } void print( connect_four_t * connect_four ) { size_t y; size_t x; assert( connect_four ); printf( " " ); for( x = 0; x < BOARD_WIDTH; ++x ) printf( "%2d ", x + 1 ); putchar( '\n' ); for( y = 0; y < BOARD_HEIGHT && printf( " %2d ", BOARD_HEIGHT - y ); printf( " %2d\n", BOARD_HEIGHT - y ), ++y ) for( x = 0; x < BOARD_WIDTH; ++x ) printf( "%2c ", player_symbols[ connect_four->board[ y * BOARD_WIDTH + x ] ] ); printf( " " ); for( x = 0; x < BOARD_WIDTH; ++x ) printf( "%2d ", x + 1 ); putchar( '\n' ); } char get_player_symbol( connect_four_t * connect_four ) { assert( connect_four ); return player_symbols[ connect_four->current_player ]; } player_t get_piece_at( connect_four_t * connect_four, size_t row, size_t column ) { assert( connect_four && row < BOARD_HEIGHT && column < BOARD_WIDTH ); return connect_four->board[ row * BOARD_WIDTH + column ]; } void set_last_move( connect_four_t * connect_four, size_t row, size_t column ) { assert( row < BOARD_HEIGHT && column < BOARD_WIDTH ); connect_four->last_move_row = row; connect_four->last_move_column = column; } void set_piece_at( connect_four_t * connect_four, size_t row, size_t column ) { assert( connect_four && row < BOARD_HEIGHT && column < BOARD_WIDTH ); ++connect_four->num_rounds; connect_four->board[ row * BOARD_WIDTH + column ] = connect_four->current_player; set_last_move( connect_four, row, column ); } bool drop_piece( connect_four_t * connect_four, size_t column ) { size_t row; assert( connect_four && column < BOARD_WIDTH ); for( row = 0; row < BOARD_HEIGHT && !get_piece_at( connect_four, row, column ); ++row ); if( !row ) return false; set_piece_at( connect_four, --row, column ); return true; } void switch_players( connect_four_t * connect_four ) { assert( connect_four ); connect_four->current_player = ( connect_four->current_player == PLAYER_1 ? PLAYER_2 : PLAYER_1 ); } player_t get_winner( connect_four_t * connect_four ) { size_t row = connect_four->last_move_row; size_t column = connect_four->last_move_column; player_t winner = connect_four->current_player; size_t offset; assert( connect_four ); for( offset = 1; column >= offset && get_piece_at( connect_four, row, column - offset ) == winner || column + offset < BOARD_WIDTH && get_piece_at( connect_four, row, column + offset ) == winner; ++offset ); if( offset >= 4 ) return winner; for( offset = 1; row >= offset && get_piece_at( connect_four, row - offset, column ) == winner || row + offset < BOARD_HEIGHT && get_piece_at( connect_four, row + offset, column ) == winner; ++offset ); if( offset >= 4 ) return winner; for( offset = 1; row >= offset && column >= offset && get_piece_at( connect_four, row - offset, column - offset ) == winner || row >= offset && column + offset < BOARD_WIDTH && get_piece_at( connect_four, row - offset, column + offset ) == winner || row + offset < BOARD_HEIGHT && column >= offset && get_piece_at( connect_four, row + offset, column - offset ) == winner || row + offset < BOARD_HEIGHT && column + offset < BOARD_WIDTH && get_piece_at( connect_four, row + offset, column + offset ) == winner; ++offset ); return offset >= 4 ? winner : PLAYER_NONE; } bool move_possible( connect_four_t * connect_four ) { return connect_four->num_rounds < BOARD_WIDTH * BOARD_HEIGHT; } int main( void ) { connect_four_t connect_four; player_t winner; size_t column; connect_four_create( &connect_four ); do { switch_players( &connect_four ); print( &connect_four ); while( printf( "\nPlayer %c: Which column (1-%d) would you like to place your piece in?\nInput > ", get_player_symbol( &connect_four ), BOARD_WIDTH ), scanf( "%d", &column ) != 1 || !column || column > BOARD_WIDTH || !drop_piece( &connect_four, --column ) ) { fputs( "\nInput error. Please try again.\n\n", stderr ); clear( stdin ); } } while( !( winner = get_winner( &connect_four ) ) && move_possible( &connect_four ) ); print( &connect_four ); if( !winner ) puts( "\nThere are no further moves possible.\n" ); else printf( "\nPlayer %d (%c) won.\n\n", winner, get_player_symbol( &connect_four ) ); }
-
int f = 4; while (feld[f][s] != 32){ f--; } feld[f][s] = 'X';
Hier musst du beachten, dass ich das == verbessert habe. Also ich möchte mit dieser Funktion bewirken, dass erkannt wird ob das Feld schon belegt ist und man die Zeilen von unten nach oben durchprüft. Sobald dann ein Platz unbelegt(32) ist, soll dort das Zeichen gespeichert werden.
Was ist an dieser Überlegung falsch?
Danke für deine Mühe, kann mit deinem Code aber leider nicht viel anfangen. Weiß oft nicht ob du da fertige Funktionen benutzt oder was das überhaupt sein soll
-
Ich wäre auch dankbar wenn ihr mir sagen könntet was genau nicht bei meiner Gewinnabfrage funktioniert. Damit ich diese überarbeiten kann.
PS: Ich arbeite nacher auch noch mit funktionen, habe bisher ja die Funktion für das darstellen des Feldes und auswählen der Zeile erstellt
-
OK, ein Versuch noch dir zu helfen.
Laß dir mal die Werte von i und k vor der Gewinnabfrage ausgeben (bzw. benutze den Debugger dafür und setze einen Breakpoint dorthin).Und nochmals: du willst die beiden Variablen f und s für die Abfrage benutzen!!!
-
Dulfried1 schrieb:
int f = 4; while (feld[f][s] != 32){ f--; } feld[f][s] = 'X';
Hier musst du beachten, dass ich das == verbessert habe. [...]
Aha. Und woher soll man das riechen wenn du es weder sagst noch vollständigen Code zeigst?
Dulfried1 schrieb:
[...] kann mit deinem Code aber leider nicht viel anfangen. Weiß oft nicht ob du da fertige Funktionen benutzt oder was das überhaupt sein soll
Die einzigen "fertigen" Funktionen die ich benutzt habe sind
puts()
,fputs()
,memset()
,printf()
,putchar()
undscanf()
. Ich wollte dir nur zeigen, wie man etwas "großes" in möglichst klitzekleine Teilbrobleme zerlegt.Zeig doch mal kompletten Code ...
-
dass mit dem == hat dirkB vor ein paar antworten schon korrigiert.
Habe jetzt verstanden wieso es nicht funktioniert hat, ich muss bei der Gewinnabfrage i und k auch von 0 bis 4 bzw. 6 durchlaufen lassen. Habe es deshalb zwischen die Ausgabe des Feldes gepackt.
Ich muss jetzt nur noch die diagonale Gewinnabfrage machen und wäre nett, wenn ihr mir zeigen könntet, wie ich meine bisherigen Gewinnabfragen in eine Funktion packe und diese dann wieder aufrufe.
int main() { char feld[5][7] = { { 32, 32, 32, 32, 32, 32, 32 }, { 32, 32, 32, 32, 32, 32, 32 }, { 32, 32, 32, 32, 32, 32, 32 }, { 32, 32, 32, 32, 32, 32, 32 }, { 32, 32, 32, 32, 32, 32, 32 } }; int s = 0, i = 0, k = 0; //s=spalte int gewonnen1 = 0, gewonnen2 = 0; int reihe = 1; for (int i = 0; i < 5; i++){ for (k = 0; k < 7; k++){ printf("%c", feld[i][k]); } printf("\n"); } while (gewonnen1 != 1 && gewonnen2 != 1){ if (reihe == 1){ printf("Spieler1: In welche Spalte wollen Sie ihren Spielchip setzen?\n"); scanf("%d", &s); system("cls"); int f = 4; while (feld[f][s] != 32){ f--; } feld[f][s] = 'X'; for (int i = 0; i < 5; i++){ for (int k = 0; k < 7; k++){ //Gewinnabfrage vertikal if (i < 2 && i >= 0 && k < 7 && k >= 0){ if (feld[i][k] == 'X' && feld[i + 1][k] == 'X' && feld[i + 2][k] == 'X' && feld[i + 3][k] == 'X'){ gewonnen1 = 1; } if (feld[i + 1][k] == 'X' && feld[i + 2][k] == 'X' && feld[i + 3][k] == 'X' && feld[i + 4][k] == 'X'){ gewonnen1 = 1; } } //Gewinnabfrage horizontal if (i <= 4 && i >= 0 && k <= 3 && k >= 0){ if (feld[i][k] == 'X' && feld[i][k + 1] == 'X' && feld[i][k + 2] == 'X' && feld[i][k + 3] == 'X'){ gewonnen1 = 1; } if (feld[i][k + 1] == 'X' && feld[i][k + 2] == 'X' && feld[i][k + 3] == 'X' && feld[i][k + 4] == 'X'){ gewonnen1 = 1; } if (feld[i][k + 2] == 'X' && feld[i][k + 3] == 'X' && feld[i][k + 4] == 'X' && feld[i][k + 5] == 'X'){ gewonnen1 = 1; } if (feld[i][k + 3] == 'X' && feld[i][k + 4] == 'X' && feld[i][k + 5] == 'X' && feld[i][k + 6] == 'X'){ gewonnen1 = 1; } } printf("%c", feld[i][k]); } printf("\n"); reihe = 2; } if (gewonnen1 == 1){ printf("Spieler 1 hat gewonnen!\n"); } else{} } else{ printf("Spieler2: In welche Spalte wollen Sie ihren Spielchip setzen?\n"); scanf("%d", &s); system("cls"); int f = 4; while (feld[f][s] != 32){ f--; } feld[f][s] = 'O'; for (int i = 0; i < 5; i++){ for (int k = 0; k < 7; k++){ //Gewinnabfrage vertikal if (i < 2 && i >= 0 && k < 7 && k >= 0){ if (feld[i][k] == 'O' && feld[i + 1][k] == 'O' && feld[i + 2][k] == 'O' && feld[i + 3][k] == 'O'){ gewonnen2 = 1; } if (feld[i + 1][k] == 'O' && feld[i + 2][k] == 'O' && feld[i + 3][k] == 'O' && feld[i + 4][k] == 'O'){ gewonnen2 = 1; } } //Gewinnabfrage horizontal if (i <= 4 && i >= 0 && k <= 3 && k >= 0){ if (feld[i][k] == 'O' && feld[i][k + 1] == 'O' && feld[i][k + 2] == 'O' && feld[i][k + 3] == 'O'){ gewonnen2 = 1; } if (feld[i][k + 1] == 'O' && feld[i][k + 2] == 'O' && feld[i][k + 3] == 'O' && feld[i][k + 4] == 'O'){ gewonnen2 = 1; } if (feld[i][k + 2] == 'O' && feld[i][k + 3] == 'O' && feld[i][k + 4] == 'O' && feld[i][k + 5] == 'O'){ gewonnen2 = 1; } if (feld[i][k + 3] == 'O' && feld[i][k + 4] == 'O' && feld[i][k + 5] == 'O' && feld[i][k + 6] == 'O'){ gewonnen2 = 1; } } printf("%c", feld[i][k]); } printf("\n"); reihe = 1; } } if (gewonnen2 == 1){ printf("Spieler 2 hat gewonnen!\n"); } } system("pause"); return 0; }
-
Dulfried1 schrieb:
#include <stdio.h> // vielen dank, dasz du es mich #include <stdlib.h> // selbst hinschreiben laesst int main() { char feld[5][7] = { { 32, 32, // yay ... memset() ist was tolles. int s = 0, i = 0, k = 0; // s=spalte // <== Ja toll. Wieso nennst du es dann nicht "spalte" !? int gewonnen1 = 0, gewonnen2 = 0; // Versteh ich nicht. Gewinnen kann eh immer nur der Spieler, der an der Reihe ist!? int reihe = 1; // reihe ... reihe ... hm ... die "reihe", "row" ist doch f!? ... wait ... reihe ist der Spieler, der an der Reihe ist?? // dann ist das bloed, denn ein "Spieler" ist kein int. Ein Spieler ist ein Kon_struct_ (<- hint, hint!) dasz den Spieler beschreibt. // ist er der Anziehende oder der Nachziehende (reihe == 1 oder reihe == 2)? Welches Symbol repraesentiert ihn? for (int i = 0; i < 5; i++){ // "habe bisher ja die Funktion für das darstellen des Feldes und auswählen der Zeile erstellt" ach so? for (k = 0; k < 7; k++){ printf("%c", feld[i][k]); } printf("\n"); } // im weiteren Codeduplikation die im Prinzip zweimal dasselbe macht. Variablen, Mensch!