Source Code (Use browser search to find items of interest.)

Class Index

kreversi'Board (./kdegames/kreversi/board.h:51)

class Board : public QWidget {
  Q_OBJECT
public:

  enum { READY = 1, THINKING = 2, HINT = 3};

  Board(QWidget *parent = 0);
  ~Board();

  void newGame();
  int humanIs();
  int computerIs();
  void getScore(int&, int&);
  void setStrength(int);
  int  getStrength();
  void interrupt();
  bool interrupted();
  void doContinue();
  void undo();
  void hint();
  
  // starts all: emits some signal, so it can't be called from 
  // constructor
  void start();

  // event stuff
  void paintEvent(QPaintEvent *);
  void mousePressEvent(QMouseEvent *);
  void timerEvent(QTimerEvent *);
  QSize sizeHint() const;  

  /// stuff for zooming
  bool canZoomIn();
  bool canZoomOut();
  void zoomIn();
  void zoomOut();
  void setZoom(int);
  int  getZoom() const;

  void switchSides();
  int  getState();
  void setState(int);
  void setAnimationSpeed(int);
  int  animationSpeed();

  int  getMoveNumber();
  void loadChips(const char *);
  QString chipsName();

  void loadGame(KConfig *, bool noupdate = FALSE);
  void saveGame(KConfig *);
  bool canLoad(KConfig *);

public slots:
  void setColor(const QColor &);
  void setPixmap(QPixmap &);

protected slots:
  void slotFieldClicked(int, int);  

signals:
  void signalFieldClicked(int, int);
  void score();
  void sizeChange();
  void gameWon(int);
  void statusChange(int);
  void illegalMove();
  void turn(int);
  void strengthChanged(int);

private:  
  void gameEnded();
  void computerMakeMove();
  
  void updateBoard(bool force = FALSE);
  void drawPiece(int row, int col, bool force = FALSE);
  void drawOnePiece(int row, int col, int color);
  void loadPixmaps();
  void adjustSize();
  void animateChanged(Move m);
  void animateChangedRow(int row, int col, int dy, int dx);
  void rotateChip(int row, int col);
  bool isField(int row, int col);
  void scaleOneChip(int i);

private:
  QString chipname;
  Engine e;
  Game   g;
  int  _status;
  int _size;
  int oldsizehint;
  int _zoom;
  int human;
  int initTimerID, scaleTimerID;
  bool nopaint;
  
  QPixmap bg;

  // the chips
  QPixmap *chip[25];
  QPixmap allchips;

  int anim_speed;
};

kreversi'Board::Board() (./kdegames/kreversi/board.cpp:68)

Board::Board(QWidget *parent) : QWidget(parent) {
  setAnimationSpeed(DEFAULT_ANIMATION_DELAY);
  setUpdatesEnabled(FALSE);

  // ensure that the first time adjustsize does
  // pixmap loading
  oldsizehint = -1;

  for(int i = 0; i < CHIP_MAX; i++)
    chip[i] = 0;

  loadChips("chips.xpm");

  nopaint = FALSE;
  human = Score::BLACK;
  _size = 32;
  _zoom = 100;
  setStrength(4);

  connect(this, SIGNAL(signalFieldClicked(int, int)),
	  this, SLOT(slotFieldClicked(int, int)));
  
  scaleTimerID = -1;
}



kreversi'Board::~Board() (./kdegames/kreversi/board.cpp:94)

Board::~Board() {
  for(int i = 0; i < CHIP_MAX; i++) 
    if(chip[i])
      delete chip[i];
}


kreversi'Board::start() (./kdegames/kreversi/board.cpp:100)

void Board::start() {
  // make sure a signal is emitted  
  setStrength(e.GetStrength());
  newGame();
  adjustSize();
  setUpdatesEnabled(TRUE);
}


kreversi'Board::loadChips() (./kdegames/kreversi/board.cpp:108)

void Board::loadChips(const char *filename) {
  allchips.load(PICDATA(filename));
  chipname = filename;
  loadPixmaps();
}


kreversi'Board::chipsName() (./kdegames/kreversi/board.cpp:114)

QString Board::chipsName() {
  return chipname;
}



kreversi'Board::getMoveNumber() (./kdegames/kreversi/board.cpp:119)

int Board::getMoveNumber() {
  return g.GetMoveNumber();
}

// negative speed is allowed. if speed is negative,
// no animations are displayed

kreversi'Board::setAnimationSpeed() (./kdegames/kreversi/board.cpp:125)

void Board::setAnimationSpeed(int speed) {
  if(speed <= 10)
    anim_speed = speed;
}


kreversi'Board::animationSpeed() (./kdegames/kreversi/board.cpp:130)

int Board::animationSpeed() {
  return anim_speed;
}

// ensure that signals at the beginning are emited if
// the parent has already setup it's connecions

kreversi'Board::timerEvent() (./kdegames/kreversi/board.cpp:136)

void Board::timerEvent(QTimerEvent *t) {
  if(t->timerId() == initTimerID) {
    killTimer(t->timerId());
    initTimerID = -1;

  }

  // check if all chips are already scaled,
  // if not scale them. If all chips are
  // already scaled, kill the timer
  if(t->timerId() == scaleTimerID) {
    for(int i = 0; i < CHIP_MAX; i++)
      if(chip[i] == 0) {
	scaleOneChip(i);
	return;
      }

    killTimer(t->timerId());
    scaleTimerID = -1;
  }
}


/// takes back on move

kreversi'Board::undo() (./kdegames/kreversi/board.cpp:160)

void Board::undo() {
  if((getState() == READY) && (g.GetMoveNumber() != 0)) {
    g.TakeBackMove();
    g.TakeBackMove();
    update();
  }
}


/// interrupt thinking of game engine

kreversi'Board::interrupt() (./kdegames/kreversi/board.cpp:170)

void Board::interrupt() {
  e.SetInterrupt(TRUE);
}


kreversi'Board::interrupted() (./kdegames/kreversi/board.cpp:174)

bool Board::interrupted() {
  return ((g.GetWhoseTurn() == computerIs()) && (getState() == THINKING));
}


/// continues a move if it was prior interrupted

kreversi'Board::doContinue() (./kdegames/kreversi/board.cpp:180)

void Board::doContinue() {
  if(interrupted())
    computerMakeMove();
}


/// adjusts the size

kreversi'Board::adjustSize() (./kdegames/kreversi/board.cpp:187)

void Board::adjustSize() {
  // do only resize if size has really change to avoid a flickering display
  if(sizeHint().width() != oldsizehint) {
    loadPixmaps();
    resize(sizeHint());
    emit sizeChange();
    oldsizehint = sizeHint().width();
  }
}


/// returns which color the human plays

kreversi'Board::humanIs() (./kdegames/kreversi/board.cpp:199)

int  Board::humanIs() {
  return human;
}


/// returns which color the computer plays

kreversi'Board::computerIs() (./kdegames/kreversi/board.cpp:205)

int  Board::computerIs() {
  if(human == Score::BLACK)
    return Score::WHITE;
  else
    return Score::BLACK;
}


/// starts a new game

kreversi'Board::newGame() (./kdegames/kreversi/board.cpp:214)

void Board::newGame() {  
  //  return;
  g.Reset();
  updateBoard(TRUE);
  setState(READY);

  emit turn(Score::BLACK);
  
  // computer makes first move
  if(human == Score::WHITE)
    computerMakeMove();
}


/// handles mouse clicks

kreversi'Board::mousePressEvent() (./kdegames/kreversi/board.cpp:229)

void Board::mousePressEvent(QMouseEvent *e) {
  if(getState() == READY) {
    int px = (e->pos().x()-2) / ((_size *5 / 4) * _zoom / 100);
    int py = (e->pos().y()-2) / ((_size *5 / 4) * _zoom / 100);
    emit signalFieldClicked(py, px);
  } else if(getState() == HINT)
    setState(READY);
  else
    emit illegalMove();
}


/// handles piece settings

kreversi'Board::slotFieldClicked() (./kdegames/kreversi/board.cpp:242)

void Board::slotFieldClicked(int row, int col) {
  if(getState() == READY) {
    int color = g.GetWhoseTurn();

    /// makes a human move
    Move m(col + 1, row + 1, color);
    if(g.MoveIsLegal(m)) {
      //      playSound("click.wav");
      g.MakeMove(m);
      animateChanged(m);

      if(!g.MoveIsAtAllPossible()) {
	updateBoard();
	setState(READY);
	gameEnded();
	return;
      }

      updateBoard();

      if(color != g.GetWhoseTurn())
	computerMakeMove();
    } else 
      emit illegalMove();
  }
}


/// makes a computer move

kreversi'Board::computerMakeMove() (./kdegames/kreversi/board.cpp:271)

void Board::computerMakeMove() {
  // check if the computer can move
  int color = g.GetWhoseTurn();
  int opponent = g.GetWhoseTurnOpponent();

  emit turn(color);

  if(g.MoveIsPossible(color)) {
    setState(THINKING);
    do {
      Move m;

      if(!g.MoveIsAtAllPossible()) {
	setState(READY);
	gameEnded();
	return;
      }

      m = e.ComputeMove(g);
      if(m.GetX() == -1) {
	setState(READY);
	return;
      }

      //playSound("click.wav");
      g.MakeMove(m);
      animateChanged(m);
      updateBoard();
    } while(!g.MoveIsPossible(opponent));
    emit turn(opponent);
    setState(READY);

    if(!g.MoveIsAtAllPossible()) {
      setState(READY);
      gameEnded();
      return;
    }
  }
}


/// returns the current score

kreversi'Board::getScore() (./kdegames/kreversi/board.cpp:313)

void Board::getScore(int &black, int &white) {
  black = g.GetScore(Score::BLACK);
  white = g.GetScore(Score::WHITE);
} 


/// calculate final score

kreversi'Board::gameEnded() (./kdegames/kreversi/board.cpp:320)

void Board::gameEnded() {
  int b, w;

  getScore(b, w);
  if(b > w)
    emit gameWon(Score::BLACK);
  else if(b < w)
    emit gameWon(Score::WHITE);
  else
    emit gameWon(Score::NOBODY);
  emit turn(Score::NOBODY);
}



kreversi'Board::switchSides() (./kdegames/kreversi/board.cpp:334)

void Board::switchSides() {
  if(getState() == READY) {
    if(human == Score::WHITE)
      human = Score::BLACK;
    else
      human = Score::WHITE;
    emit score();
    computerMakeMove();
  }
}



kreversi'Board::getState() (./kdegames/kreversi/board.cpp:346)

int  Board::getState() {
  return _status;
}


kreversi'Board::setState() (./kdegames/kreversi/board.cpp:350)

void Board::setState(int nstatus) {
  _status = nstatus;
  emit statusChange(_status);
}



kreversi'Board::setStrength() (./kdegames/kreversi/board.cpp:356)

void Board::setStrength(int st) {
  if((st > 1) && (st <= 10)) {
    e.SetStrength(st);
    emit strengthChanged(e.GetStrength());
  }
}



kreversi'Board::getStrength() (./kdegames/kreversi/board.cpp:364)

int Board::getStrength() {
  return e.GetStrength();
}



kreversi'Board::hint() (./kdegames/kreversi/board.cpp:369)

void Board::hint() {
  if(getState() == READY) {
    setState(THINKING);
    Move m = e.ComputeMove(g);
    setState(HINT);
    if(m.GetX() != -1) {
      for(int flash = 0; (flash < 100) && (getState() != READY); flash++) {
	if(flash & 1)
	  drawOnePiece(m.GetY() - 1, m.GetX() - 1, Score::NOBODY);
	else
	  drawOnePiece(m.GetY() - 1, m.GetX() - 1, g.GetWhoseTurn());

	// keep GUI alive while waiting
	for(int dummy = 0; dummy < 5; dummy++) {
	  usleep(HINT_BLINKRATE/5);
	  qApp->processEvents();
	}
      }
      
      drawOnePiece(m.GetY() - 1, m.GetX() - 1, 
		   g.GetSquare(m.GetX(), m.GetY()));
    }
    setState(READY);
  }
}


// ********************************************************
// ********************************************************
//
// functions related to drawing/painting
//
// ********************************************************
// ********************************************************

// flash all pieces which are turned
// NOTE: this code is white a hack. Should make it better

kreversi'Board::animateChanged() (./kdegames/kreversi/board.cpp:406)

void Board::animateChanged(Move m) {
  if(animationSpeed() <= 0)
    return;

  // since now all chips are needed, ensure that all of them
  // are loaded
  for(int i = 0; i < CHIP_MAX; i++) 
    if(chip[i] == 0)
      scaleOneChip(i);

  // draw the new piece

  drawOnePiece(m.GetY()-1, m.GetX()-1, m.GetPlayer());
  soundSync();

  for(int dx = -1; dx < 2; dx++)
    for(int dy = -1; dy < 2; dy++)
      if((dx != 0) || (dy != 0))
	animateChangedRow(m.GetY()-1, m.GetX()-1, dy, dx);
}



kreversi'Board::isField() (./kdegames/kreversi/board.cpp:428)

bool Board::isField(int row, int col) {
  return (bool)((row > -1) && (row < 8) && (col > -1) && (col < 8));
}



kreversi'Board::animateChangedRow() (./kdegames/kreversi/board.cpp:433)

void Board::animateChangedRow(int row, int col, int dy, int dx) {
  row = row + dy;
  col = col + dx;
  while(isField(row, col)) {
    if(g.wasTurned(col+1, row+1)) {
      playSound("reversi-click.wav");
      rotateChip(row, col);
      soundSync();
   } else
      return;

    col += dx;
    row += dy;
  }
}

// NOTE: this code is S**T

kreversi'Board::rotateChip() (./kdegames/kreversi/board.cpp:450)

void Board::rotateChip(int row, int col) {
  // check which direction the chip has to be rotated
  // if the new chip is white, the chip was black first,
  // so lets begin at index 1, otherwise it was white
  int color = g.GetSquare(col+1, row+1);
  int from, end, delta;
  if(color == Score::WHITE) {
    from = CHIP_BLACK + 2;
    end  = CHIP_WHITE - 2;
    delta = 1;
  } else if(color == Score::BLACK) {
    from = CHIP_WHITE -2;
    end  = CHIP_BLACK + 2;
    delta = -1;
  } else
    return;

  int px = (col * (_size / 4) + col * _size + 3) * _zoom / 100 + 2;
  int py = (row * (_size / 4) + row * _size + 3) * _zoom / 100 + 2;
  
  // copy the background of an empty square
  drawOnePiece(row, col, Score::NOBODY);
  QPixmap saveunder;
  int p_width = (sizeHint().width())/8;
  int p_height = (sizeHint().height())/8;
  saveunder.resize(p_width, p_height);
  bitBlt(&saveunder, 0, 0, this, p_width * col, p_height * row,
	 p_width, p_height, CopyROP);

  for(int i = from; i != end; i += delta) {
    // copy the piece over a copy of the saveunder, this will reduce flicker
    QPixmap tmp = saveunder;
    bitBlt(&tmp, px % p_width, py % p_height, chip[i], 0, 0, 
	   chip[i]->width(), chip[i]->height(), CopyROP);

    QPainter p;
    p.begin(this);
    p.drawPixmap(p_width * col, p_height * row, tmp);
    //p.drawPixmap(p_width * col, p_height * row, saveunder);
    //p.drawPixmap(px, py, *chip[i]);    
    p.flush();
    p.end();
    usleep(ANIMATION_DELAY * anim_speed);
  }
  
  QPainter p;
  p.begin(this);
  p.drawPixmap(p_width * col, p_height * row, saveunder);  
  p.flush();
  p.end();
  drawOnePiece(row, col, color);
}


kreversi'Board::canZoomIn() (./kdegames/kreversi/board.cpp:503)

bool Board::canZoomIn() {
  return (bool)(width() < 640);
}



kreversi'Board::canZoomOut() (./kdegames/kreversi/board.cpp:508)

bool Board::canZoomOut() {
  return (bool)(width() > 200);
}



kreversi'Board::setZoom() (./kdegames/kreversi/board.cpp:513)

void Board::setZoom(int _new) {
  if(((_new < _zoom) && canZoomOut()) ||
     ((_new > _zoom) && canZoomIn())) {
    if(_new != _zoom) {
      _zoom = _new;
      adjustSize();
      emit sizeChange();
    }
  }
}



kreversi'Board::getZoom() (./kdegames/kreversi/board.cpp:525)

int Board::getZoom() const {
  return _zoom;
}



kreversi'Board::zoomIn() (./kdegames/kreversi/board.cpp:530)

void Board::zoomIn() {
  setZoom(_zoom + 20);
}



kreversi'Board::zoomOut() (./kdegames/kreversi/board.cpp:535)

void Board::zoomOut() {
  setZoom(_zoom - 20);
}



kreversi'Board::scaleOneChip() (./kdegames/kreversi/board.cpp:540)

void Board::scaleOneChip(int i) {
  if((i >= 0) && (i < CHIP_MAX)) {
    // free pixmap if any
    if(chip[i] != 0)
      delete chip[i];

    int w = allchips.width()/5;
    int h = allchips.height()/5;
    
    // make new pixmap
    chip[i] = new QPixmap;
    chip[i]->resize(30, 30);
    chip[i]->fill();		// thanks to Stephan Kulow
    
    // easy to understand, isn't it :-)
    bitBlt(chip[i], 0, 0, &allchips, (i % 5) * w + 10, (i / 5) * h + 10, 
	   30, 30, CopyROP);

    // scale to final size
    chip[i]->setMask(chip[i]->createHeuristicMask());
    QWMatrix wm;
    wm.scale((float)(0.01 * _zoom * _size) / 30,
 	     (float)(0.01 * _zoom * _size) / 30);
    *chip[i] = chip[i]->xForm(wm);    
  }
}



kreversi'Board::loadPixmaps() (./kdegames/kreversi/board.cpp:568)

void Board::loadPixmaps() {
  // the chips CHIP_BLACK and CHIP_WHITE
  // are needed immidiatly, so scale them. All other chips
  // are scaled in the background (timerEvent) to make the
  // program react faster to size events
  for(int i = 0; i < CHIP_MAX; i++)
    if(chip[i] != 0) {
      delete chip[i];
      chip[i] = 0;
    }
  scaleOneChip(CHIP_WHITE);
  scaleOneChip(CHIP_BLACK);  
  
  // scale background (if any)
  if(bg.width() != 0) {
    QWMatrix wm3;
    wm3.scale((float)(sizeHint().width()-4)/8.0/bg.width(),
	      (float)(sizeHint().height()-4)/8.0/bg.height());
    setBackgroundPixmap(bg.xForm(wm3));
  }

  // start the timer to begin scaling of pixmaps (if needed)
  if(scaleTimerID == -1)
    scaleTimerID = startTimer(0);
}



kreversi'Board::updateBoard() (./kdegames/kreversi/board.cpp:595)

void Board::updateBoard(bool force) {
  for(int row = 0; row < 8; row++)
    for(int col = 0; col < 8; col++) 
      drawPiece(row, col, force);

  emit score();
}



kreversi'Board::drawOnePiece() (./kdegames/kreversi/board.cpp:604)

void Board::drawOnePiece(int row, int col, int color) {
  int px = (col * (_size / 4) + col * _size + 3) * _zoom / 100 + 2;
  int py = (row * (_size / 4) + row * _size + 3) * _zoom / 100 + 2;

  // ensure that the chips are loaded
  if((chip[CHIP_BLACK] == 0) || (chip[CHIP_WHITE] == 0))
    loadPixmaps();
  
  QPainter p;
  p.begin(this);
  if(color == Score::NOBODY) {
    nopaint = TRUE;
    repaint(px, py, chip[CHIP_BLACK]->width(), chip[CHIP_BLACK]->height());
    nopaint = FALSE;
  } else if(color == Score::BLACK)
    p.drawPixmap(px, py, *chip[CHIP_BLACK]);
  else if(color == Score::WHITE)
    p.drawPixmap(px, py, *chip[CHIP_WHITE]);
  p.flush();
  p.end();  
}



kreversi'Board::drawPiece() (./kdegames/kreversi/board.cpp:627)

void Board::drawPiece(int row, int col, bool force) {
  if(g.squareModified(col+1, row+1) || force) {
    int color = g.GetSquare(col + 1, row + 1);
    drawOnePiece(row, col, color);
  }
}



kreversi'Board::paintEvent() (./kdegames/kreversi/board.cpp:635)

void Board::paintEvent(QPaintEvent *) {
  int i, w = sizeHint().width() - 2;
  
  if(!nopaint) {
    QPainter p;
    
    p.begin(this);
    p.setPen(QPen(QColor("black"), 2));
    
    // draw vertical lines
    for(i = 1; i < 8; i++) {
      int x = (i*(5 * _size / 4)) * _zoom / 100 + 2;
      p.drawLine(x, 0, x, w);
    }
    
    // draw horizontal lines
    for(i = 1; i < 8; i++) {
      int y = (i*(5 * _size / 4)) * _zoom / 100 + 2;
      p.drawLine(0, y, w, y);
    }

    p.drawRect(1, 1, w+1, w+1);
    
    p.end();
    updateBoard(TRUE);
  }
}



kreversi'Board::sizeHint() (./kdegames/kreversi/board.cpp:664)

QSize Board::sizeHint() const {
  int w = (8 * (_size/4) + 8 * _size) * _zoom / 100;
  return QSize(w+2, w+2);
}


kreversi'Board::setPixmap() (./kdegames/kreversi/board.cpp:669)

void Board::setPixmap(QPixmap &pm) {
  bg = pm;
  // scale background (if any)
  if(bg.width() != 0) {
    QWMatrix wm3;
    wm3.scale((float)(sizeHint().width()-4)/8.0/bg.width(),
	      (float)(sizeHint().height()-4)/8.0/bg.height());
    setBackgroundPixmap(bg.xForm(wm3));
  }
}


kreversi'Board::setColor() (./kdegames/kreversi/board.cpp:680)

void Board::setColor(const QColor &c) {
  setBackgroundColor(c);
  bg.resize(0, 0);
} 

// saves the game. Only one game at a time can be saved

kreversi'Board::saveGame() (./kdegames/kreversi/board.cpp:686)

void Board::saveGame(KConfig *config) {
  interrupt(); // stop thinking
  config->writeEntry("NumberOfMoves", g.GetMoveNumber());
  int nmoves = g.GetMoveNumber();
  config->writeEntry("State", getState());
  for(int i = nmoves; i > 0; i--) {    
    Move m = g.GetLastMove();
    g.TakeBackMove();
    QString s, idx;
    s.sprintf("%d %d %d", m.GetX(), m.GetY(), m.GetPlayer());
    idx.sprintf("Move_%d", i);
    config->writeEntry(idx, s);
  }
  
  // save whose turn it is
  config->writeEntry("WhoseTurn", human);

  // all moves must be redone
  loadGame(config, TRUE);
  doContinue(); // continue possible move
}

// loads the game. Only one game at a time can be saved

kreversi'Board::loadGame() (./kdegames/kreversi/board.cpp:709)

void Board::loadGame(KConfig *config, bool noupdate) {
  interrupt(); // stop thinking
  int nmoves = config->readNumEntry("NumberOfMoves", -1);
  if(nmoves > 0) {
    g.Reset();
    int movenumber = 1;
    while(nmoves--) {
      // read one move
      QString idx;
      idx.sprintf("Move_%d", movenumber++);
      QString s = config->readEntry(idx);
      
      int x, y, pl;
      sscanf(s.data(), "%d %d %d", &x, &y, &pl);
      Move m(x, y, pl);
      g.MakeMove(m);
    }

    if(noupdate)
      return;

    human = config->readNumEntry("WhoseTurn");
  
    updateBoard(TRUE);
    setState(config->readNumEntry("State"));

    if(interrupted())
      doContinue();
    else {      
      emit turn(Score::BLACK);
      // computer makes first move
      if(human == Score::WHITE)
	computerMakeMove();
    }
  }
}


kreversi'Board::canLoad() (./kdegames/kreversi/board.cpp:746)

bool Board::canLoad(KConfig *config) {
  int nmoves = config->readNumEntry("NumberOfMoves", -1);
  return (bool)(nmoves > 0);
}