/mobile Handheld Friendly website
Ubuntu : Intel® Q6600® one core |
Each table row shows performance measurements for this C++ g++ program with a particular command-line input value N.
| N | CPU secs | Elapsed secs | Memory KB | Code B | ≈ CPU Load |
|---|---|---|---|---|---|
| 2,098 | 0.25 | 0.25 | 516 | 4080 | 0% 4% 8% 100% |
Read the ↓ make, command line, and program output logs to see how this program was run.
Read meteor-contest benchmark to see what this program should do.
gcc (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3
// The Computer Language Benchmarks Game // http://benchmarksgame.alioth.debian.org/ // contributed by Ben St. John #include <cstdio> #include <cstdlib> #include <iostream> #include <vector> #include <string> #include <memory.h> using namespace std; #define FREE(p) {free(p); p = NULL;} enum {X, Y, N_DIM}; enum {EVEN, ODD, N_PARITY}; typedef unsigned int TUInt32; typedef unsigned long long TUInt64; typedef signed char TInt8; typedef TUInt64 BitVec; namespace Meteor { static const int N_COL = 5; static const int N_ROW = 10; static const int N_CELL = N_COL * N_ROW; class Piece; //------------------------------------ class Solution { public: static const int NO_PIECE = -1; void addPiece(const BitVec & vec, int iPiece); void removeLastPiece(void); void setCells(void); bool lessThan(Solution & r); ///< I don't feel like operator overloading string toString(void) const; void fill(int val); bool isEmpty(void) {return (m_pieces.size() == 0);} void spin(Solution & spun); Solution(int fillVal); Solution() {m_synched = false;} private: struct SPiece { BitVec vec; TUInt32 iPiece; }; vector<SPiece> m_pieces; TInt8 m_cells[N_ROW][N_COL]; bool m_synched; }; //------------------------------------ class Board { public: static const BitVec L_EDGE_MASK = (1LL << 0) | (1LL << 5) | (1LL << 10) | (1LL << 15) | (1LL << 20) | (1LL << 25) | (1LL << 30) | (1LL << 35) | (1LL << 40) | (1LL << 45) | (1LL << 50) | (1LL << 55); static const BitVec R_EDGE_MASK = L_EDGE_MASK << 4; static const BitVec TOP_ROW = 0x1fLL; static const BitVec ROW_0_MASK = ( TOP_ROW | (TOP_ROW << 10) | (TOP_ROW << 20) | (TOP_ROW << 30) | (TOP_ROW << 40) | (TOP_ROW << 50)); static const BitVec ROW_1_MASK = ROW_0_MASK << 5; static const BitVec BOARD_MASK = (1LL << N_CELL) - 1; Board(); static TUInt32 getIndex(TUInt32 x, TUInt32 y) { return y * N_COL + x; } static bool hasBadFirstRegion(BitVec & toFill); static bool hasBadIslands(const BitVec & boardVec); void genAllSolutions(BitVec boardVec, TUInt32 placedPieces, TUInt32 iNextFill, const BitVec & maskNextFill); void recordSolution(Solution & s); Solution m_curSolution; Solution m_minSolution; Solution m_maxSolution; TUInt32 m_nSolutionFound; }; //------------------------------------ class Piece { public: struct Instance { BitVec m_vec; BitVec m_allowed; TUInt32 m_offset; TUInt32 m_w; TUInt32 m_h; }; static const int N_ELEM = 5; static const int N_ORIENT = 12; static const int N_TYPE = 10; static const int ALL_PIECE_MASK = (1 << N_TYPE) - 1; static const TUInt32 SKIP_PIECE = 5; // it's magic! typedef int TCoordList[N_ELEM][N_DIM]; static const BitVec BaseDefinitions[N_TYPE]; static Piece s_basePiece[N_TYPE][N_ORIENT]; static const Instance & getPiece(TUInt32 iPiece, TUInt32 iOrient, TUInt32 iParity); static bool checkBaseDefinitions(void); static BitVec toBitVector(const TCoordList & coords); static void genOrientation(const BitVec & vec, TUInt32 iOrient, Piece & target); static void setCoordList(const BitVec & vec, TCoordList & coords); static void shiftUpLines(TCoordList & coords, int shift); static void shiftToX0(TCoordList & coords, Instance & instance, int offsetRow); static void setAllowedPositions(Instance & p); static void genAllOrientations(void); Instance m_instance[N_PARITY]; }; //------------------------------------ Solution::Solution(int fillVal) { fill(fillVal); m_pieces.reserve(Piece::N_TYPE); } void Solution::fill(int val) { m_synched = false; memset(&m_cells[0][0], val, N_CELL); } string Solution::toString(void) const { string result; result.reserve(N_CELL * 2); for (int y = 0; y < N_ROW; y++) { for (int x = 0; x < N_COL; x++) { int val = m_cells[y][x]; result += ((val == NO_PIECE) ? '.' : char('0' + val)); result += ' '; } result += '\n'; // indent every second line if (y % 2 == 0) result += " "; } return result; // copies result. Oh well } void Solution::setCells(void) { if (m_synched) return; fill(NO_PIECE); // could be more efficient for (TUInt32 iPiece = 0; iPiece < m_pieces.size(); iPiece++) { const BitVec & vec = m_pieces[iPiece].vec; int pID = m_pieces[iPiece].iPiece; BitVec mask = 1LL; int nNewCells = 0; for (int y = 0; y < N_ROW; y++) { for (int x = 0; x < N_COL; x++) { if (mask & vec) { m_cells[y][x] = (TInt8)pID; nNewCells++; } mask <<= 1; } if (nNewCells == Piece::N_ELEM) break; } } m_synched = true; } void Solution::addPiece(const BitVec & vec, int iPiece) { SPiece p = {vec, iPiece}; m_pieces.push_back(p); } void Solution::removeLastPiece(void) { m_pieces.pop_back(); m_synched = false; } bool Solution::lessThan(Solution & r) { if (m_pieces[0].iPiece != r.m_pieces[0].iPiece) { return m_pieces[0].iPiece < r.m_pieces[0].iPiece; } setCells(); r.setCells(); int y; for (y = 0; y < N_ROW; y++) { for (int x = 0; x < N_COL; x++) { int lval = m_cells[y][x]; int rval = r.m_cells[y][x]; if (lval != rval) return (lval < rval); } } return false; // solutions are equal } void Solution::spin(Solution & spun) { setCells(); // swap cells for (int y = 0; y < N_ROW; y++) { for (int x = 0; x < N_COL; x++) { TInt8 flipped = m_cells[N_ROW - y - 1][N_COL - x - 1]; spun.m_cells[y][x] = flipped; } } // swap first and last pieces (the rest aren't used) spun.m_pieces.push_back(m_pieces[Piece::N_TYPE - 1]); spun.m_synched = true; } //------------------------------------ Piece Piece::s_basePiece[N_TYPE][N_ORIENT]; const BitVec Piece::BaseDefinitions[] = { 0x010f, 0x00cb, 0x1087, 0x0427, 0x0465, 0x00c7, 0x08423, 0x00a7, 0x0187, 0x008f }; int floor(int top, int bot) { int toZero = top / bot; // negative numbers should be rounded down, not towards zero if ((toZero * bot != top) && ((top < 0) != (bot <= 0))) toZero--; return toZero; } TUInt32 getFirstOne(const BitVec & v, TUInt32 startPos = 0) { if (v == (BitVec)0) return 0; static const TUInt32 firstOne[16] = { 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, }; TUInt32 iPos = startPos; BitVec mask = 0xffLL << startPos; while ((mask & v) == 0) { mask <<= 8; iPos += 8; } TUInt32 result = TUInt32((mask & v) >> iPos); TUInt32 resultLow = result & 0x0f; if (resultLow != 0) iPos += firstOne[resultLow]; else iPos += 4 + firstOne[result >> 4]; return iPos; } TUInt32 countOnes(BitVec v) { TUInt32 n = 0; while (v) { n++; v = v & (v - 1); } return n; } void Piece::genAllOrientations(void) { for (int iPiece = 0; iPiece < N_TYPE; iPiece++) { const BitVec & refPiece = BaseDefinitions[iPiece]; for (int iOrient = 0; iOrient < N_ORIENT; iOrient++) genOrientation(refPiece, iOrient, s_basePiece[iPiece][iOrient]); } } void Piece::setCoordList(const BitVec & vec, TCoordList & coords) { int iCoord = 0; BitVec mask = 1LL; for (int y = 0; y < N_ROW; y++) { for (int x = 0; x < N_COL; x++) { if (mask & vec) { coords[iCoord][X] = x; coords[iCoord][Y] = y; iCoord++; } mask <<= 1; } } } BitVec Piece::toBitVector(const TCoordList & coords) { int y, x; BitVec result = 0; for (int iCoord = 0; iCoord < N_ELEM; iCoord++) { x = coords[iCoord][X]; y = coords[iCoord][Y]; int pos = Board::getIndex(x, y); result |= (1LL << pos); // to generate a 64 bit representation of 1 } return result; } void Piece::shiftUpLines(TCoordList & coords, int shift) { // apply shifts are not so simple in the vertical direction for (int iCoord = 0; iCoord < N_ELEM; iCoord++) { int & rx = coords[iCoord][X]; int & ry = coords[iCoord][Y]; if (ry & shift & 0x1) rx++; ry -= shift; } } void Piece::shiftToX0(TCoordList & coords, Piece::Instance & instance, int offsetRow) { // .. determine shift int x, y; int xMin = coords[0][X]; int xMax = xMin; int iCoord; for (iCoord = 1; iCoord < N_ELEM; iCoord++) { x = coords[iCoord][X]; y = coords[iCoord][Y]; if (x < xMin) xMin = x; else if (x > xMax) xMax = x; } // I'm dying for a 'foreach' here int offset = N_ELEM; for (iCoord = 0; iCoord < N_ELEM; iCoord++) { int & rx = coords[iCoord][X]; int & ry = coords[iCoord][Y]; rx -= xMin; // check offset -- leftmost cell on top line if ((ry == offsetRow) && (rx < offset)) offset = rx; } instance.m_w = xMax - xMin; instance.m_offset = offset; instance.m_vec = toBitVector(coords); } void Piece::setAllowedPositions(Piece::Instance & p) { BitVec & allowed = p.m_allowed = 0; BitVec posMask = 1LL; TUInt32 iPos = 0; for (int y = 0; y < N_ROW; y++) { for (int x = 0; x < N_COL; x++, iPos++, posMask <<= 1){ // check if the new position is on the board int xPos = x - p.m_offset; if ((xPos < 0) || (y + p.m_h >= N_ROW) || (xPos + p.m_w >= N_COL)) continue; // move it to the desired location BitVec pieceVec = p.m_vec << (iPos - p.m_offset); if (Board::hasBadIslands(pieceVec)) continue; // position is allowed allowed |= posMask; } } } void Piece::genOrientation(const BitVec & vec, TUInt32 iOrient, Piece & target) { // get (x,y) coordinates TCoordList coords; setCoordList(vec, coords); int y, x; int iCoord = 0; int rot = iOrient % 6; int flip = iOrient >= 6; if (flip) { for (iCoord = 0; iCoord < N_ELEM; iCoord++) coords[iCoord][Y] = -coords[iCoord][Y]; } // rotate (if necessary) while (rot--) { for (iCoord = 0; iCoord < N_ELEM; iCoord++) { x = coords[iCoord][X]; y = coords[iCoord][Y]; // I just worked this out by hand. Took a while. int xNew = floor((2 * x - 3 * y + 1), 4); int yNew = floor((2 * x + y + 1), 2); coords[iCoord][X] = xNew; coords[iCoord][Y] = yNew; } } // shift vertically // .. determine shift int yMin = coords[0][Y]; int yMax = yMin; for (iCoord = 1; iCoord < N_ELEM; iCoord++) { y = coords[iCoord][Y]; if (y < yMin) yMin = y; else if (y > yMax) yMax = y; } TUInt32 h = yMax - yMin; target.m_instance[EVEN].m_h = h; target.m_instance[ODD].m_h = h; shiftUpLines(coords, yMin); shiftToX0(coords, target.m_instance[EVEN], 0); setAllowedPositions(target.m_instance[EVEN]); // shift down one line shiftUpLines(coords, -1); shiftToX0(coords, target.m_instance[ODD], 1); // shift the bitmask back one line target.m_instance[ODD].m_vec >>= N_COL; setAllowedPositions(target.m_instance[ODD]); } const Piece::Instance & Piece::getPiece(TUInt32 iPiece, TUInt32 iOrient, TUInt32 iParity) { return s_basePiece[iPiece][iOrient].m_instance[iParity]; } // ------------------------------------ Board::Board() : m_curSolution(Solution::NO_PIECE), m_minSolution(Piece::N_TYPE), m_maxSolution(Solution::NO_PIECE), m_nSolutionFound(0) { } bool Board::hasBadFirstRegion(BitVec & toFill) { int iPos = getFirstOne(toFill); // grow empty region, until it doesn't change any more BitVec region; BitVec rNew = 1LL << iPos; do { region = rNew; // grow right/left rNew |= (region & ~L_EDGE_MASK) >> 1; rNew |= (region & ~R_EDGE_MASK) << 1; // simple grow up/down rNew |= (region >> N_COL); rNew |= (region << N_COL); // tricky growth BitVec evenRegion = region & (ROW_0_MASK & ~L_EDGE_MASK); rNew |= evenRegion >> (N_COL + 1); rNew |= evenRegion << (N_COL - 1); BitVec oddRegion = region & (ROW_1_MASK & ~R_EDGE_MASK); rNew |= oddRegion >> (N_COL - 1); rNew |= oddRegion << (N_COL + 1); // clamp against existing pieces rNew &= toFill; } while ((rNew != toFill) && (rNew != region)); // subtract empty region from board toFill ^= rNew; TUInt32 nEmptyCells = countOnes(toFill); if (nEmptyCells % 5 != 0) return true; return false; } bool Board::hasBadIslands(const BitVec & boardVec) { BitVec toFill = ~boardVec & BOARD_MASK; // a little pre-work to speed things up BitVec row = (Board::TOP_ROW << ((N_ROW - 1) * N_COL)); bool filled = ((row & toFill) == row); while ((row & toFill) == row) { toFill ^= row; row >>= N_COL; } // undo the last row, so regions stay connected if (filled) { row <<= N_COL; toFill |= row; } while (toFill) { if (hasBadFirstRegion(toFill)) return true; } return false; } // recursive vs iterative? void Board::genAllSolutions(BitVec boardVec, TUInt32 placedPieces, TUInt32 iNextFill, const BitVec & maskNextFill) { BitVec pieceVec; int pieceMask = 1; int y = iNextFill / N_COL; int isOddLine = y & 1; for (int iPlacedPiece = 0; iPlacedPiece < Piece::N_TYPE; iPlacedPiece++, pieceMask <<= 1) { TUInt32 iPiece = iPlacedPiece; // leftover from when I remapped it // skip if we've already used this piece if (pieceMask & placedPieces) continue; // try to fit piece bool skipFlippedOdd = (iPiece == Piece::SKIP_PIECE); for (int iOrient = 0; iOrient < Piece::N_ORIENT; iOrient++) { if (skipFlippedOdd && ((iOrient / 3) & 1)) continue; // get the particular piece in the particular orientation const Piece::Instance & p = Piece::getPiece(iPiece, iOrient, isOddLine); // check if the new position is allowed on the board if (!(p.m_allowed & maskNextFill)) continue; // move it to the desired location, if possible and pieceVec = p.m_vec << (iNextFill - p.m_offset); // check if piece conflicts with other pieces if (pieceVec & boardVec) continue; // add the piece to the board boardVec |= pieceVec; if ((boardVec != pieceVec) && hasBadIslands(boardVec)) { // remove the piece from the board vector boardVec ^= pieceVec; continue; } // mark piece as placed placedPieces |= pieceMask; m_curSolution.addPiece(pieceVec, iPiece); // recur if not done if (placedPieces != Piece::ALL_PIECE_MASK) { // need to find the next unfilled cell TUInt32 iCell = getFirstOne(~boardVec, iNextFill + 1); BitVec mNextFill = (maskNextFill << (iCell - iNextFill)); genAllSolutions(boardVec, placedPieces, iCell, mNextFill); } else { // done, record piece/solution and end recursion recordSolution(m_curSolution); } // remove the piece before continuing with a new piece boardVec ^= pieceVec; m_curSolution.removeLastPiece(); } placedPieces &= ~pieceMask; } } void Board::recordSolution(Solution & s) { m_nSolutionFound += 2; // we add the solution and its rotation if (m_minSolution.isEmpty()) { m_minSolution = m_maxSolution = s; return; } if (s.lessThan(m_minSolution)) m_minSolution = s; else if (m_maxSolution.lessThan(s)) m_maxSolution = s; Solution spun; s.spin(spun); if (spun.lessThan(m_minSolution)) m_minSolution = spun; else if (m_maxSolution.lessThan(s)) m_maxSolution = spun; } } // namespace using namespace Meteor; int main(int argc, char * argv []) { const int N_SOLUTION = 2098; TUInt32 nSolMax = N_SOLUTION; if (argc > 2) return 1; // spec says this is an error else if (argc == 2) nSolMax = *((TUInt32 *)argv[1]); Board board; Piece::genAllOrientations(); board.genAllSolutions(0, 0, 0, 1LL); cout << board.m_nSolutionFound << " solutions found\n\n"; cout << board.m_minSolution.toString() << '\n'; cout << board.m_maxSolution.toString() << endl; // if (nSolMax != N_SOLUTION) // return 1; return 0; }
Tue, 30 Apr 2013 05:33:49 GMT
MAKE:
/usr/bin/g++ -c -pipe -O3 -fomit-frame-pointer -march=native meteor.gpp-2.c++ -o meteor.gpp-2.c++.o && \
/usr/bin/g++ meteor.gpp-2.c++.o -o meteor.gpp-2.gpp_run
rm meteor.gpp-2.c++
10.40s to complete and log all make actions
COMMAND LINE:
./meteor.gpp-2.gpp_run 2098
PROGRAM OUTPUT:
2098 solutions found
0 0 0 0 1
2 2 2 0 1
2 6 6 1 1
2 6 1 5 5
8 6 5 5 5
8 6 3 3 3
4 8 8 9 3
4 4 8 9 3
4 7 4 7 9
7 7 7 9 9
9 9 9 9 8
9 6 6 8 5
6 6 8 8 5
6 8 2 5 5
7 7 7 2 5
7 4 7 2 0
1 4 2 2 0
1 4 4 0 3
1 4 0 0 3
1 1 3 3 3