Ich finde schon, dass man Anfängern die richtige Datenstruktur nahebringen sollte, wenn man detailliert erklärt, was warum wie ist geht das in Ordnung.
Gerade um C-style Arrays zu vermeiden sollte man std::vector oder std::array als bessere Alternativen aufzählen.
Ich würde das Spielfeld folgendermassen modellieren:
#include <cassert> // für assert()
#include <vector> // für std::vector
#include <algorithm> // für std::fill()
class Board
{
unsigned int Rows_; // Anzahl der Zeilen
unsigned int Cols_; // Anzahl der Spalten
std::vector<char> Squares; // Spielfelder
public:
Board( unsigned int Rows, unsigned int Cols ) :
Rows_( Rows ), // Anzahl der Zeilen übernehmen
Cols_( Cols ), // Anzahl der Spalten übernehmen
Squares_( Rows * Cols ) // Spielfeld initialisieren
{
}
void clear()
{
// alle Spielfelder auf o zurücksetzen
std::fill( Squares_.begin(), Squares_.end(), 0 );
}
unsigned int rows() const
{
// Anzahl der Zeilen zurückgeben
return Rows_;
}
unsigned int cols() const
{
// Anzahl der Spalten zurückgeben
return Cols_;
}
char& operator()( unsigned int Row, unsigned int Col )
{
// Zugriff auf Spielfeld
assert_bounds( Row, Col );
return Squares_[Row * cols() + Col];
}
const char& operator()( unsigned int Row, unsigned int Col ) const
{
// Zugriff auf Spielfeld
assert_bounds( Row, Col );
return Squares_[Row * cols() + Col];
}
private:
void assert_valid_bounds( unsigned int Row, unsigned int Col ) const
{
// Zeilenindex und Spaltenindex müssen gültig sein,
// ansonsten das Programm abbrechen
std::assert( Row < rows() );
std::assert( Col < cols() );
}
};
int main()
{
// Spielfeld der Größe 3x3 erzeugen
Board TicTacToeBoard( 3,3 );
// setze ein 'X' in die Mitte
TicTacToeBoard( 1,1 ) = 'X';
// setze ein 'O' in die linke obere Ecke
TicTacToeBoard( 0,0 ) = 'O';
}
Man kann jedes n-dimensionale Array als eindimensionales Arrays darstellen, man muss sich nur die Größen der einzelnen Dimensionen merken. In diesem Fall ist das Spielfeld zweidimensional, jede Dimension hat die Größe 3. Damit hat das lineare Array (hier durch einen std::vector repräsentiert) die Größe 9 und die Indizes sind folgendermassen verteilt:
`
0 | 1 | 2
---+---+---
3 | 4 | 5
---+---+---
6 | 7 | 8
`
Man kann den linearen Index aus dem 2D Index berechnen, indem man den Zeilenindex mit der Anzahl der Spalten multipliziert und dann den Spaltenindex addiert.
Der Zugriff erfolg dann über den ()-operator, der als Argumente den Zeilen- und Spaltenindex erwartet. Die Besonderheit bei den ()-Operatoren ist, dass sie Methodenaufrufe sind, aber keinen Methodennamen haben. Das lässt dann diese Notation zu:
char Mark = TicTacToeBoard( 0,0 );
Da der Operator eine Referenz auf das Spielfeldelement zuückgibt kann das Spielfeldelement durch den Zugriff verändert werden:
TicTacToeBoard( 2,1 ) = 'X';
Das Spielbrett Beispiel eignet sich hervorragend zur Einführung in die STL Container und Algorithmen, weil relativ wenig neue Funktionen/Methoden benötigt werden, aber das Spielbrett Raum für eigene Erweiterungen lässt, bis man eine eigene Klasse für n-dimensionale Arrays hat.