N
Tomahawk schrieb:
Es wäre einfach zu langsam ein Feld über Linie und Reihe zu definieren. Dann würde ich ja einen 2-dim Vektor benötigen. Nach meiner Erfahrung verkompliziert das die Berechnungen. Ganz grob: 90% aller brettrelevanten Berechnungen sind feld-spezifisch. die übrigen 10% verteilen sich auf Linien und Reihen.
Bei Annahmen über Geschwindigkeit wäre ich immer vorsichtig. Wenn du häufig Linien/Reihen und Felder ineinander umrechnen musst, kann das schliesslich auch etwas ausmachen. Du sagst ja, dass du noch nicht allzu lange programmierst, und Anfänger neigen dazu, Code wegen vermeintlicher Geschwindigkeitsgewinne umständlich zu machen (Premature Optimization). Kann aber auch gut sein, dass du Recht hast. Versuch, den Code einigermassen benutzerfreundlich und wartbar zu halten, und im Zweifelsfalle misst du eben die Zeit.
Tomahawk schrieb:
Bitoperationen benötige ich auf dem Brett eine Menge, hier ein Ausschnitt:
[...]
Auf jeden Fall wird (fast) alles in kleine inlines verpackt, das Ausdenken von aussagekräftigen Namen dauert manchmal länger als mir lieb ist.
Das ist sehr gut!
Ich dachte eben, du würdest die bitweisen Operatoren dauernd im Anwendungscode einsetzen, aber wenn du sie durch Funktionen verständlich machst, ist das kein Problem.
Tomahawk schrieb:
Wie kann ich einen Bool ganz schnell umkehren?
Gleich wie die anderen integralen Typen:
bool b = true;
b ^= true; // true statt 1 (spielt eigentlich keine Rolle)
Tomahawk schrieb:
Und ausserdem kann ich einen Bool meines Wissen nicht als Arrayindex einsetzen.
Kannst du schon, bool ist wie gesagt ein integraler Typ, der eben nur zwei Werte annehmen kann: false und true (bzw. in Zahlen ausgedrückt 0 und 1). Du könntest also höchstens ein Array mit zwei Elementen indizieren.
Tomahawk schrieb:
COLOR_WHITE und COLOR_BLACK werden auch zur Indexierung von Tabellen verwendet:
// source file
int king_sq[COLORS];
int piece_ct[COLORS][PIECES];
// header file
const int COLOR_WHITE = 0;
const int COLOR_BLACK = 1;
const int COLOR_NONE = 2;
const int COLORS = 2;
inline int opposite_color(const int color) {
return color ^ 1;
}
Eben, nimm dafür enum . Enumerator-Konstanten können auch als integrale Zahlen interpretiert werden.
enum color_t
{
WHITE, // erster Enumerator entspricht implizit dem integralen Wert 0
BLACK, // entspricht automatisch dem Vorgänger+1, also 0+1 == 1
NO_COLOR // entspricht automatisch 1+1 == 2
};
// Du kannst die Zahlen auch explizit angeben,
// das ist genau das gleiche [c]enum[/c]:
enum color_t
{
WHITE = 0,
BLACK = 1,
NO_COLOR = 2
};
const int NUM_COLORS = 2; // NUM zum Verdeutlichen, dass es sich um eine Anzahl handelt
Der Vorteil besteht darin, dass du einen eigenen Typen für Farben hast und nicht mit int hantieren musst.
color_t a = BLACK;
color_t b = 1; // Fehler
Umgang mit Arrays:
int king_sq[NUM_COLORS];
king_sq[WHITE] = ...;
king_sq[BLACK] = ...;
Umkehrfunktion ( static_cast braucht hier keine Rechenzeit, sondern dient nur zur Umgehung der Typsicherheit):
inline color_t opposite_color(color_t color)
{
return static_cast<color_t>(static_cast<int>(color) ^ 1);
}
Tomahawk schrieb:
Öfters wurde hier im Forum kommentiert, dass der const -Bezeichner in meinen Parameterlisten unsinnig sei.
Das ist in der Tat so, wie DStefan schon sagte. Du kopierst den Wert sowieso. Ob du nun die Kopie innerhalb der Funktion verändern darfst, geht die Schnittstelle nichts an. Es wird auch in der Funktion niemand daran gehindert, eine weitere Kopie zu erstellen, welche verändert werden kann. Kurz gesagt ist const bei Value-Parametern absolut sinnlos. Ausserdem tragen unnötige Schlüsselwörter dazu bei, dass relevante Dinge weniger gut erkennbar sind. Ich denke bei const in Parameterlisten z.B. immer an Zeiger oder Referenzen auf const , also dass ein Argument von der Funktion nicht direkt verändert wird. Das ist bei einer Kopie aber sowieso schon gegeben.
Glaube auch nicht, möglichst viel const führe zwangsläufig zu gutem und sicherem Code. Setze Const-Correctness ein, wo sie sinnvoll ist.