Forum: PC-Programmierung Minesweeper in C


von Luis W. (brausedealer)


Lesenswert?

Hey erstmal, ich bin mir nicht sicher ob ich hier im richtigen Forum 
gelandet bin. Aber ich wollte mich sowieso mal Anmelden da war das jetzt 
der richtige Zeitpunkt.

Zu meinem Problem ich muss für ein Uni Projekt Minesweeper als Konsolen 
Variante erstellen.

Unter GCC linux

Ich habe schon angefangen und bin so auf meine Probleme gestoßen:

Das aufdecken: Ich überprüfe auf anliegende Minen, das geht. Außer ich 
bin am rand des Spielfeld.

Und das "automatische" aufdecken bis eine Mine kommt. Ich verstehe schon 
nicht ganz nach welchen System das Minesweeper macht. da kann ich es 
natürlich auch schwer umsetzen :-D

Das leeren der Konsole um das aktuelle Feld auszugeben haut auch noch 
nicht so hin.



Hier mein code bist jetzt
1
/*
2
 ============================================================================
3
 Name        : Pool3_Minesweeper_V2.c
4
============================================================================
5
 */
6
7
#include <stdio.h>
8
#include <stdlib.h>
9
#include <time.h>
10
11
#define TRUE 1
12
#define FALSE 0
13
14
int **board;
15
int n, m;
16
FILE *datei;
17
18
19
void build_board(char *argv[]);
20
void build_mines(int anzahl);
21
void write_board(char *argv[]);
22
int check_mines(int x, int y);
23
void refresh_board(char *argv[]);
24
25
int main(int argc, char *argv[]) {
26
  if(argc == 4){// Kontrolle ob die richtige anzahl an werten übergeben wurde
27
    int groese = 0, min = 0, max = 0, anzahl = 0, i, j;
28
29
    n = atoi(argv[1]); //n aus Konsolenparameter auslesen
30
    m = atoi(argv[2]); //m aus Konsolenparameter auslesen
31
32
    /*n = 20;
33
    m = 20;*/
34
    if(10 <= n && n <= 26 && 10 <= m && m <= 26){ // Kontrolle ob n und m im richtigen bereich liegen
35
36
        groese = n * m; // größe des Feldes
37
38
        //Minimale und Maximale anzahl der bomben
39
        min = (groese * 10) / 100;
40
        max = (groese * 25) / 100;
41
42
        srand (time (NULL)); //zufallszahl beginnen
43
        anzahl = (rand () % ((max + 1) - min)) + min; // Zufällige anzahl der bomben bestimmen
44
45
        //Speicherzuweißung
46
        board = (int **)malloc(n * sizeof(int *));
47
        for(i = 0; i < n; i++){
48
          board[i] = (int *)malloc(m * sizeof(int));
49
          }
50
51
        //Board mit 0 füllen, 0 ist die anzeige falls noch nicht aufgedeckt
52
        for(i = 0; i < n; i++){
53
          for(j = 0; j < m; j++){
54
            board[j][i] = 0;
55
            }
56
          }
57
          build_board(argv);
58
          build_mines(anzahl);
59
      
60
          refresh_board(argv);
61
          write_board(argv);
62
        }
63
      else{ printf("Ihre Eingabe Daten sind falsch\n");}
64
65
      }
66
67
    else{printf("Ihre Eingabe Daten sind falsch\n");}
68
69
    return EXIT_SUCCESS;
70
}
71
72
void build_board(char *argv[]){
73
  int i, j;
74
  datei = fopen(argv[3], "w+");
75
  //datei = fopen("test", "w+");
76
  for(j = 0; j < m; j++){
77
    for(i = 0; i < n; i++){
78
      fputc(48, datei);
79
      fputc(32, datei);
80
    }
81
    fputc(10, datei);
82
    }
83
84
  fclose(datei);
85
}
86
87
void build_mines(int anzahl){
88
  int i = anzahl;
89
  srand (time (NULL));
90
  while(i > 0){
91
    board[rand() % n ][rand() % m ] = 9;
92
    i -=1;
93
  }
94
95
}
96
97
int check_mines(int x, int y){
98
  int zahl = 0, i, j;
99
100
  for(i = x - 1; i < 4; i++){
101
    for(j = y - 1; j < 4; j++){
102
      if(board[i][j] == 1) zahl++;
103
      }
104
    }
105
106
  return zahl;
107
}
108
109
void write_board(char *argv[]){
110
  int temp;
111
  datei = fopen(argv[3], "r");
112
113
  //Hier sollte der bisherige Ausgabe gelöscht werden um das Aktuelle Feld auszugeben
114
  //system("clear");
115
  printf("\033[2J\033[1;1H");
116
117
  while((temp = fgetc(datei))!=EOF) {
118
    printf("%c", temp);
119
  }
120
  fclose(datei);
121
122
}
123
124
void refresh_board(char *argv[]){
125
  int i, j;
126
  datei = fopen(argv[3], "r+");
127
  for(i = 0; i < n; i++){
128
    for(j = 0; j < m; j++){
129
        if(board[j][i] == 9){
130
          fputc(48, datei);
131
          fputc(32, datei);
132
          }
133
        else{
134
          fputc(board[j][i] + 48, datei);
135
          fputc(32, datei);
136
        }
137
      }
138
      fputc(10, datei);
139
    }
140
  fclose(datei);
141
}
142
143
int uncover(int x, int y){
144
  int mine = FALSE;
145
  if(board[x][y] == 9) mine = TRUE;
146
  else{
147
    board[x][y] = check_mines(x, y);
148
  }
149
150
  return mine;
151
}



Copy paste der Aufgabe:


-ein rechteckiges Spielfeld mit n x m Feldern generieren und in einer 
Textdatei abspeichern.

Auf die Felder des Spielfelds sollen zufällig Minen verteilt werden. 
Dabei dürfen die verteilten Minen insgesamt nicht weniger als 10% und 
nicht mehr als 25% des Spielfeldes belegen.
In Feldern, auf denen keine Mine abgelegt wurde, soll die Anzahl der an 
das jeweilige Feld angrenzenden Minen angezeigt werden und zwar auch bei 
diagonaler Verbindung der Felder

Minesweeper spielen lassen, bis entweder alle minenfreien Felder 
gefunden wurden, oder bis beim Aufdecken der Felder eine Mine getroffen 
wurde.

Bei Spielbeginn sollen alle Felder verdeckt dargestellt werden (weder 
Minen noch sonstige Angaben sichtbar)
Spielzüge sollen per Tastatureingabe erfolgen. Die Auswahl eines Feldes 
erfolgt durch Angabe seiner Zeilen- und Spaltenkoordinate (z.B. G12). 
Mögliche Spielzüge sind „Feld aufdecken“ (A) oder „Feld markieren / 
Markierung entfernen“ (M). Ist ein Feld bereits markiert, dann wird die 
Markierung bei erneutem Markieren entfernt. Ein markiertes Feld darf 
nicht aufgedeckt werden.
Wird ein leeres, also ein minenfreies Feld aufgedeckt, dann sollen 
angrenzende Felder in der das aufgedeckte Feld umgebenden Fläche soweit 
aufgedeckt werden, bis entweder ein bereits markiertes Feld oder eine 
Mine gefunden werden. Das bereits markierte Feld oder die Mine werden 
nicht mehr aufgedeckt und bilden so den Rand der aufgedeckten Fläche. In 
allen Randfeldern dieser Fläche soll jeweils die Anzahl der Minen 
dargestellt werden, die auf den außen angrenzenden, also noch verdeckten 
Feldern liegen.
Die Darstellung bereits aufgedeckter Felder soll bei den weiteren 
Spielzügen nicht mehr verändert werden.
Das Spiel ist gewonnen, sobald alle minenfreien Felder aufgedeckt sind.
Das Spiel ist verloren, sobald beim Aufdecken eine Mine getroffen wurde.

am Spielende das nachfolgend definierte Spielergebnis auf dem Bildschirm 
anzeigen und an die bereits erstellte Textdatei anhängen.

Alle nicht getroffenen Minen, alle korrekt markierten Minen, sowie ggf. 
die beim Aufdecken getroffene Mine sollen zusätzlich zu den im 
bisherigen Spielverlauf dargestellten Angaben auf dem Spielfeld 
angezeigt werden.
Die Spieldauer in Minuten und die Anzahl der getätigten Spielzüge sollen 
ausgegeben werden.

von Dussel (Gast)


Lesenswert?

Luis W. schrieb:
> Das aufdecken: Ich überprüfe auf anliegende Minen,
Warum das? Zu Spielbeginn legst die Minen und berechnest danach für 
jedes Feld die Anzahl der benachbarten Minen. Beim Aufdecken wird nur 
noch abgelesen, ob auf dem Feld eine Mine, eine Zahl oder gar nichts 
ist.

Luis W. schrieb:
> Und das "automatische" aufdecken bis eine Mine kommt.
Wenn gar nichts darauf ist, wird jedes Feld benachbarte Feld aufgedeckt, 
auf dem gar nichts oder eine Zahl ist. Das für jedes dadurch aufgedeckte 
Feld wiederholen.

von Luis W. (brausedealer)


Lesenswert?

Das mit dem Check mines funktioniert ja. deswegen würde ich das auch 
beibehalten.
Und selbst wenn. wie soll ich dann den unterschied zwischen einem 
Aufgedeckten Feld und einem nicht aufgedeckten Feld erkennen. Dann sind 
ja alle von Anfang an mit zahlen voll.
Dann müsste ich das ganze Prinzip ändern.

von Dussel (Gast)


Lesenswert?

Luis W. schrieb:
> wie soll ich dann den unterschied zwischen einem
> Aufgedeckten Feld und einem nicht aufgedeckten Feld erkennen.
Über ein int-Array, bool gibt es ja in C nicht.

Luis W. schrieb:
> Dann sind ja alle von Anfang an mit zahlen voll.
Die 0 darfst du halt nicht anzeigen.

Ich muss dazu sagen, dass ich dein Programm nicht nachvollzogen habe.
Mein Ansatz wäre, ein Array für das Spielfeld zu machen, in dem die 
Anzahl der angrenzenden Minen eingetragen ist. 0 wird als leeres Feld 
angezeigt und zum Beispiel 9 steht für Mine. Je nachdem, ob Laufzeit 
oder Speicher wichtiger ist, kann man in das Array auch noch ein Flag 
für 'verdeckt', 'markiert' und 'offen' speichern, ansonsten ein 
separates Array dafür anlegen.
Wie gesagt, ich würde die Zahlen direkt bei der Erzeugung des Spielfelds 
berechnen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.