C++ / Bitmasken

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
oli_f
Beiträge: 272
Registriert: 24.10.2003 12:27:05

C++ / Bitmasken

Beitrag von oli_f » 19.01.2005 18:20:19

Habe ein Problem. Vielleicht kann mir ja jemand helfen:

Ich habe ein Schachbrett mit 5x5 Feldern.
Als erstes habe ich mit solchen Konstrukten Steine auf dem Brett das durch ein int dargestellt wird gesetzt:

Code: Alles auswählen

int _board = 0;
_board |= 1 << x * 5 + y;
Ich möchte nun eine Dame auf 2,2 setzen und schauen ob sie einen anderen Stein bedroht:

Code: Alles auswählen

int queen = 0;
queen |= 1 << 2 * 5 + 2;
/* Algoritmus um alle bedroten Bits auf 1 zu setzen*/
if( _board & queen == 0 )
  soSomething();
Nur leider scheint das nicht zu funktionieren.
Und zwar geht wohl schon die oberste Methode um die Bits auf _board zu setzten schief.
Sieht jemand meinen das Problem?
error - divided by 0

Benutzeravatar
Joghurt
Beiträge: 5244
Registriert: 30.01.2003 15:27:31
Wohnort: Hamburg
Kontaktdaten:

Beitrag von Joghurt » 19.01.2005 22:53:13

Hat "int" bei dir auch 32 Bit? Nimm "long", um sicher zu sein. Das setzen des Bits sieht sonst OK aus.

oli_f
Beiträge: 272
Registriert: 24.10.2003 12:27:05

Beitrag von oli_f » 19.01.2005 23:45:14

hmm ich benutzte sogar long ...

ich poste mal einbisschen mehr, vielleicht hat ja jemand kurz zeit.

Der ganze Code ist unter http://rafb.net/paste/results/jqdH9d98.html zu finden

also es handelt sich um das n-queen problem (auf einem nxn grossen Feld n Damen platzieren so dass sich keine schlagen kann. gesucht anzahl lösungen)

ich speichere zuerst in einem Array für jedes mögliche feld die bedrohten Felder falls dort eine Dame stehen würde (der Algorithmus an sich funktionierte mit Arrays statt Bitmasken) :

Code: Alles auswählen

for ( int x = 0; x < _size; x++ )                                // 1.Dimension des Schachfeldes
           for ( int y  = 0; y < _size;  y++ )                   // 2  "                "     "
           {
                _queensCache[ x*_size+y ] = 0;             // Leeren

                int j = y-x;                                                 // Laufvariable für diagonale Felder
                int k = x+y;                                               // "                     "    "               "
                for ( int i = 0; i < _size; i++ )
                {
                        _queensCache[ x*_size+y ] |= ( 1 << x * _size + i );               // Horizontal         
                                                                                                  bedrohte Felder markieren
                        _queensCache[ x*_size+y ] |= ( 1 << i * _size + y );              // Vertikale

                        if ( j >= 0 && j < _size )
                                _queensCache[ x*_size+y ] |= ( 1 << i * _size + j );         // Diagonale
                        if ( k >= 0 && k < _size )
                                _queensCache[ x*_size+y ] |= ( 1 << i * _size + k );        // Diagonale

                        j++;
                        k--;
                }
           }
Danach führe ich eine Backtrack Funktion aus:

Code: Alles auswählen

   if( number == _size-1 )        //Schauen ob schon alle Damen gesetzt wurden
   {
      _solutions++;
      return;
   }

   for( int i = 0; i < _size; i++ ) 
   {
      if( _board & _queensCache[ number*_size+i ] == 0  )    // Die Spalte bleibt immer die
                                                                  selbe, nämlich die Anzahl der bereits gesetzten
                                                                  Damen, da in jede Spalte eine Dame kommt. Die 
                                                                  Zeilen werden der Reihe nach durchgetestet mit
                                                                  einer AND Verknüpfung der Bedrohten Felder 
                                                                  mit dem aktuellen _board.
       {
              _board |= ( 1 << number * _size + i );   // Die dame setzen
              solve( number+1 );                               // nächste Suchtiefe
              _board ^= ( 1 << number * _size + i );  // Dame entfernen = Backtrack
       }
   }

error - divided by 0

Benutzeravatar
jack herer
Beiträge: 94
Registriert: 28.07.2003 19:48:17

Beitrag von jack herer » 20.01.2005 19:44:31

Ich verstehe Dein Programm zwar momentan nicht, aber in dein if muß wohl noch ne Klammer, da & eine höhere Priorität hat als ==.

Code: Alles auswählen

if( ( _board & _queensCache[ number*_size+i ] ) == 0  )
]

oli_f
Beiträge: 272
Registriert: 24.10.2003 12:27:05

Beitrag von oli_f » 20.01.2005 22:18:28

genau habs gerade vorhin entdeckt und jetzt funktioniert's!

merci trozdem!

jetzt muss ich mir nur noch überlegen wie ichs bei grösseren brettern mache denn 32 bit reichen leider nur für 5x5 Felder!
error - divided by 0

Benutzeravatar
Joghurt
Beiträge: 5244
Registriert: 30.01.2003 15:27:31
Wohnort: Hamburg
Kontaktdaten:

Beitrag von Joghurt » 21.01.2005 00:54:01

Für 8x8 könntest du GCC's long long nehmen.

gms
Beiträge: 7798
Registriert: 26.11.2004 20:08:38
Lizenz eigener Beiträge: MIT Lizenz

Beitrag von gms » 21.01.2005 10:15:43

mit bitset kommst du länger aus
http://www.sgi.com/tech/stl/bitset.html

oli_f
Beiträge: 272
Registriert: 24.10.2003 12:27:05

Beitrag von oli_f » 21.01.2005 15:33:59

ja soweit war ich schon nur leider ist es mir nicht gelungen ein bitset-array zu erstellen!
ich denke das hängt damit zusammen, dass der [] Operator schon zum Auslesen von einem einzelnen Bit benutzt wird!
Wenn ich davon ein Array machen könte wäre es genial!
error - divided by 0

gms
Beiträge: 7798
Registriert: 26.11.2004 20:08:38
Lizenz eigener Beiträge: MIT Lizenz

Beitrag von gms » 21.01.2005 16:29:02

funktioniert ähnlich wie in deinem Beispiel:

Code: Alles auswählen

#define BOARDSIZE 100
std::bitset<BOARDSIZE*BOARDSIZE> mybitset();

mybitset.set(x*BOARDSIZE+y);
[edit]
std::bitset<BOARDSIZE> mybitset();
gändert auf:
std::bitset<BOARDSIZE*BOARDSIZE> mybitset();
[/edit]
Zuletzt geändert von gms am 21.01.2005 16:50:26, insgesamt 1-mal geändert.

oli_f
Beiträge: 272
Registriert: 24.10.2003 12:27:05

Beitrag von oli_f » 21.01.2005 16:43:39

ich wollte eigentlich sagen dass ich BOARDSIZE * BOARDSIZE bitsets der grösse BOARDSIZE*BOARDSIZE brauche, da ich ja am anfang für jedes feld die jeweils bedrohten Felden cachen will.

also habe ich das so probiert:

Code: Alles auswählen

const int _size = 6;

bitset<_size*_size> _queensCache[_size*_size];
aber das gibt einen Fehler beim compillieren!
error - divided by 0

gms
Beiträge: 7798
Registriert: 26.11.2004 20:08:38
Lizenz eigener Beiträge: MIT Lizenz

Beitrag von gms » 21.01.2005 16:55:24

kompiliert bei mir fehlerfrei:

Code: Alles auswählen

#include <bitset>

int main() {
  const int _size=6;
  std::bitset<_size*_size> _queenscache[_size*_size];

  return 0;
}


oli_f
Beiträge: 272
Registriert: 24.10.2003 12:27:05

Beitrag von oli_f » 21.01.2005 17:17:14

merci für deine geduld :)

ich hatte das #include <bitset> vergessen da ich irgendwie gedacht habe: ah es ist ja in der standard library und die habe ich ja schon drinn .....

jedenfalls geht das programm jetzt aber es ist immer noch etwa gleich lahm :)
werd's dann später einmal weiterschreiben.
error - divided by 0

Benutzeravatar
Joghurt
Beiträge: 5244
Registriert: 30.01.2003 15:27:31
Wohnort: Hamburg
Kontaktdaten:

Beitrag von Joghurt » 21.01.2005 19:49:45

oli_f hat geschrieben:jedenfalls geht das programm jetzt aber es ist immer noch etwa gleich lahm :)
werd's dann später einmal weiterschreiben.
Denk dran, dass du die erste Dame nur im oberen linken Quadranten platzierst, dann braucht du die rotierten Lösungen nicht einzeln rausfiltern.

oli_f
Beiträge: 272
Registriert: 24.10.2003 12:27:05

Beitrag von oli_f » 21.01.2005 23:32:58

genau so handhabe ich es mitlerweile....

aber das problem ist wohl, dass ich immer das ganze board mit der gesammten gecachten Damenbedrohungsliste (<- tolles Wort) bitwise AND verknüpfe. eigentlich müsste ich nur die zu setzende Position in den Damenbedrohungslisten der bereits gesetzten Damen zu testen.
Das gäbe ne Menge einsparungen...
error - divided by 0

Benutzeravatar
Dookie
Beiträge: 1104
Registriert: 17.02.2002 20:38:19
Wohnort: Salzburg
Kontaktdaten:

Beitrag von Dookie » 21.01.2005 23:45:38

Hi oli_f,

am einfachsten legst du ein bitfeld an, in dem du alle bedrohten damenfelder der gesetzten damen oderst, dann brauchst du nur das eine Bitfeld mit dem Bitfeld der neuen Dame anden.


Gruß

Dookie

oli_f
Beiträge: 272
Registriert: 24.10.2003 12:27:05

Beitrag von oli_f » 21.01.2005 23:52:23

nur gibt's da ein problem:
beim backtracking weiss ich nicht ob ein feld einfach oder mehrfach bedroht ist. ich kann also nicht wissen ob ich ein von der dame die ich wieder wegnehme bedrohtes Feld auch wirklich nachher nicht mehr bedroht ist!

So oder so C++ macht mir gerade ziemlich freude :)
error - divided by 0

oli_f
Beiträge: 272
Registriert: 24.10.2003 12:27:05

Beitrag von oli_f » 22.01.2005 00:29:27

hopla ganz neue Situation:

habe irgendwo per zufall gelesen man solle g++ mit dem flag -O3 aufrufen und schau an so kompilliert läuft das Program bestimmt 10x schneller!!!
Nur verstehe ich das ganze nicht! anscheinend soll dieses Flag den Kompiler dazu anhalten kleine Funktionen automatisch als inline zu behandeln. Nur habe ich in meiner solve Funktion nur einen Funktionsaufruf, nämlich ruft sie sich selber auf wenn eine neue Dame platziert werden soll. Aber diese Funktion ist nicht wirklich klein und ausserdem wird sie ja dauernd rekursiv von sich selber aufgerufen?? Verwirrt...
error - divided by 0

Benutzeravatar
Joghurt
Beiträge: 5244
Registriert: 30.01.2003 15:27:31
Wohnort: Hamburg
Kontaktdaten:

Beitrag von Joghurt » 22.01.2005 01:02:45

oli_f hat geschrieben:habe irgendwo per zufall gelesen man solle g++ mit dem flag -O3 aufrufen und schau an so kompilliert läuft das Program bestimmt 10x schneller!!!
-O3 schaltet ein Menge optimierungen ein.
Du kannst auch noch -march=pentium4 (z.B.) angeben, dann wird auch speziell für diesen Prozessor kompiliert/optimiert.

Was optimiert wird, kannst du in der info-Page nachlesen.
Online hier: http://gcc.gnu.org/onlinedocs/gcc-3.4.3 ... ze-Options

Benutzeravatar
BeS
Moderator
Beiträge: 3236
Registriert: 17.04.2002 18:30:21
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Stuttgart
Kontaktdaten:

Beitrag von BeS » 22.01.2005 01:53:55

Hallo,
warum machst du das überhaupt so umständlich?
Es reicht doch wenn du einen normalen array mit der größe einer Seitenlänge des Schachbretts nimmst, da schreibst du dann als int Wert rein an welcher Stelle der Zeile/Spalte (eines von beiden repräsentiert dein 1-dim-array) die Dame steht. Auf diese Weise kannst du durch eine einfache Formel auch überprüfen ob eine Dame in den vorherigen Feldern dich schon bedroht. Zusammen mit einem sauberen backtracking kannst du dann einfach alle Kombinationen durchspielen.

Ich habe das ganze vor einiger Zeit mal in C geschrieben, wenn es dich genauer interessiert, dann kannst du es dir auf meiner Homepage ansehen.
Deine Unterstützung für Freie Software kostet dich nur wenige Minuten: www.fsfe.org/support

Ich spreche von Freier Software!

Antworten