summaryrefslogtreecommitdiffstats
path: root/kreversi
diff options
context:
space:
mode:
Diffstat (limited to 'kreversi')
-rw-r--r--kreversi/AUTHORS2
-rw-r--r--kreversi/ChangeLog553
-rw-r--r--kreversi/DESIGN121
-rw-r--r--kreversi/Engine.cpp787
-rw-r--r--kreversi/Engine.h245
-rw-r--r--kreversi/Game.cpp265
-rw-r--r--kreversi/Game.h143
-rw-r--r--kreversi/Makefile.am101
-rw-r--r--kreversi/Move.cpp118
-rw-r--r--kreversi/Move.h124
-rw-r--r--kreversi/NEWS20
-rw-r--r--kreversi/Position.cpp366
-rw-r--r--kreversi/Position.h98
-rw-r--r--kreversi/Score.cpp70
-rw-r--r--kreversi/Score.h78
-rw-r--r--kreversi/SuperEngine.cpp133
-rw-r--r--kreversi/SuperEngine.h142
-rw-r--r--kreversi/TODO87
-rw-r--r--kreversi/board.cpp576
-rw-r--r--kreversi/board.h150
-rw-r--r--kreversi/highscores.cpp104
-rw-r--r--kreversi/highscores.h50
-rw-r--r--kreversi/icons/Makefile.am1
-rw-r--r--kreversi/icons/cr16-action-lastmoves.pngbin0 -> 593 bytes
-rw-r--r--kreversi/icons/cr16-action-legalmoves.pngbin0 -> 573 bytes
-rw-r--r--kreversi/icons/cr22-action-lastmoves.pngbin0 -> 780 bytes
-rw-r--r--kreversi/icons/cr22-action-legalmoves.pngbin0 -> 772 bytes
-rw-r--r--kreversi/icons/cr32-action-lastmoves.pngbin0 -> 1117 bytes
-rw-r--r--kreversi/icons/cr32-action-legalmoves.pngbin0 -> 1080 bytes
-rw-r--r--kreversi/icons/cr48-action-lastmoves.pngbin0 -> 1592 bytes
-rw-r--r--kreversi/icons/cr48-action-legalmoves.pngbin0 -> 1576 bytes
-rw-r--r--kreversi/icons/crsc-action-lastmoves.svgzbin0 -> 2303 bytes
-rw-r--r--kreversi/icons/crsc-action-legalmoves.svgzbin0 -> 2457 bytes
-rw-r--r--kreversi/icons/hi128-app-kreversi.pngbin0 -> 12369 bytes
-rw-r--r--kreversi/icons/hi16-app-kreversi.pngbin0 -> 865 bytes
-rw-r--r--kreversi/icons/hi22-app-kreversi.pngbin0 -> 3931 bytes
-rw-r--r--kreversi/icons/hi32-app-kreversi.pngbin0 -> 2265 bytes
-rw-r--r--kreversi/icons/hi48-app-kreversi.pngbin0 -> 3484 bytes
-rw-r--r--kreversi/icons/hi64-app-kreversi.pngbin0 -> 4754 bytes
-rw-r--r--kreversi/kreversi.cpp841
-rw-r--r--kreversi/kreversi.desktop74
-rw-r--r--kreversi/kreversi.h178
-rw-r--r--kreversi/kreversi.kcfg66
-rw-r--r--kreversi/kreversiui.rc45
-rw-r--r--kreversi/kzoommainwindow.cpp135
-rw-r--r--kreversi/kzoommainwindow.h138
-rw-r--r--kreversi/main.cpp87
-rw-r--r--kreversi/pics/Makefile.am8
-rw-r--r--kreversi/pics/background/Dark_Wood.pngbin0 -> 1330 bytes
-rw-r--r--kreversi/pics/background/Earth.pngbin0 -> 23427 bytes
-rw-r--r--kreversi/pics/background/Granite.pngbin0 -> 11228 bytes
-rw-r--r--kreversi/pics/background/Hexagon.pngbin0 -> 334 bytes
-rw-r--r--kreversi/pics/background/Light_Wood.pngbin0 -> 2072 bytes
-rw-r--r--kreversi/pics/background/Makefile.am8
-rw-r--r--kreversi/pics/background/Mystique.pngbin0 -> 13323 bytes
-rw-r--r--kreversi/pics/background/Ocean.pngbin0 -> 12421 bytes
-rw-r--r--kreversi/pics/background/Pipes.pngbin0 -> 14716 bytes
-rw-r--r--kreversi/pics/background/Puzzle.pngbin0 -> 11478 bytes
-rw-r--r--kreversi/pics/background/Stones.pngbin0 -> 29782 bytes
-rw-r--r--kreversi/pics/chips.pngbin0 -> 26778 bytes
-rw-r--r--kreversi/pics/chips_mono.pngbin0 -> 24796 bytes
-rw-r--r--kreversi/prefs.kcfgc7
-rw-r--r--kreversi/qreversigame.cpp93
-rw-r--r--kreversi/qreversigame.h101
-rw-r--r--kreversi/qreversigameview.cpp299
-rw-r--r--kreversi/qreversigameview.h160
-rw-r--r--kreversi/settings.ui329
-rw-r--r--kreversi/sounds/Makefile.am7
-rw-r--r--kreversi/sounds/eventsrc566
-rw-r--r--kreversi/sounds/reversi-click.wavbin0 -> 2474 bytes
-rw-r--r--kreversi/sounds/reversi-won.wavbin0 -> 40200 bytes
-rw-r--r--kreversi/version.h1
72 files changed, 7477 insertions, 0 deletions
diff --git a/kreversi/AUTHORS b/kreversi/AUTHORS
new file mode 100644
index 00000000..3964c051
--- /dev/null
+++ b/kreversi/AUTHORS
@@ -0,0 +1,2 @@
+Mario Weilguni <[email protected]> Initial coding
+Inge Wallin <[email protected]> Cleanups, lots of enhancements
diff --git a/kreversi/ChangeLog b/kreversi/ChangeLog
new file mode 100644
index 00000000..ad743814
--- /dev/null
+++ b/kreversi/ChangeLog
@@ -0,0 +1,553 @@
+2006-07-03 Inge Wallin <[email protected]>
+
+ * kreversi.cpp (slotGameOver): Set state back to Ready after the
+ game is finished, and before showing highscore.
+
+2006-07-03 Inge Wallin <[email protected]>
+
+ * version.h (KREVERSI_VERSION): Update version to 1.7.1 for KDE
+ 3.5.4.
+
+2006-07-03 Inge Wallin <[email protected]>
+
+ * Position.cpp (undoMove): Keep track of score when undoing a
+ move.
+
+ * qreversigameview.h (removeMove): show game status after removing
+ a move.
+
+2006-07-02 Inge Wallin <[email protected]>
+
+ * qreversigameview.cpp (moveMade): Print color Red/Blue in
+ addition to White/Black into the game view if non-BW color is
+ chosen in the preferences.
+
+
+ ----------------------------------------------------------------
+ New start of ChangeLogging
+ ----------------------------------------------------------------
+
+
+2005-09-15 Inge Wallin <[email protected]>
+
+ Bump version number for the release of KDE 3.5
+ * version.h: Bump version from 1.6 to 1.7
+
+2005-04-04 Inge Wallin <[email protected]>
+
+ Fix bug where hint and 'show legal moves' didn't work together.
+ * board.cpp (showHint): call drawSmallCircle if showLegalMoves is true.
+ (drawSmallCircle): new private method
+ New feature: show last move.
+ * board.cpp (setShowLastMove): new method
+
+
+ Refactoring: make showing of legal moves simpler
+ * board.cpp (showLegalMoves): Take bool for on/off instead of Movelist
+ (quitShowLegalMoves): removed
+ (m_legalMovesShowing): new bool member instead of m_legalMoves
+ * kreversi.cpp (misc): don't call showLegalMoves were not necessary
+ Fix a bug with 'show legal moves': old ones were never erased.
+ * board.cpp (showLegalMoves): new method broken out of updateBoard
+
+ Some code cleaning and documentation
+ * DESIGN: Made documentation up-to-date
+ * qreversigame.{h,cpp} (updateBoard,turn): removed signals
+ * qreversigameview.{cpp} (slotNewGame): renamed into newGame
+ (updateBoard): new method
+ (updateMovelist): new method (empty yet)
+ (misc proxy methods): simplified.
+
+ Move over more view stuff to the gameview.
+ * kreversi.cpp (showMove): Renamed into handleMove, most of it
+ moved to the view
+ (slotStateChange): removed slot
+ (turn(Color), score, stateChange): removed signals
+ (setState): Do the job of slotStateChange.
+ * qreversigameview.cpp (moveMade): do the job of showMove
+
+ More control of the view by signals
+ * kreversi.cpp (showTurn): now catches sig_newGame and sig_update
+ from the game
+ (showTurn): new slot
+
+ Let the game view be updated by signals from the game instead of
+ by explicit calls.
+ * kreversi.cpp (misc): Don't call updateboard et al.
+ (showColor): Removed
+ * qreversigame.cpp (sig_score): Removed.
+ * qreversigameview.{h,cpp} (slotNewGame, moveMade): new slots
+
+2005-04-03 Inge Wallin <[email protected]>
+
+ Clean up the signals from the game and change some explicit calls
+ to update the view into signal/slots instead.
+ * kreversi.{h, cpp} (showScore): removed
+ * qreversigame.{h,cpp} (sig_newGame, sig_update): new signals
+ (gameOver): signal renamed into sig_gameOver
+ * qreversigameview.{h,cpp} (StatusWidget::setText): new method
+ (createView): New private method.
+ (updateView): new slot
+ (updateStatus): new slot
+ (setHumanColor): new method.
+
+
+ Move the status info from the toolbar to the gameview.
+ * kreversi.{h,cpp} (StatusWidget): Removed class
+ (createStatusBar): Removed.
+ (m_krgame): renamed into m_game
+ * qreversigameview.{h,cpp} (StatusWidget): Added class
+
+ Move the movelist to the gameview.
+
+ Refactor: Create a new class QReversiGameView that will comprise
+ the entire view.
+ * Unfortunately the details of the change got lost in some stupid
+ mistake of mine.
+
+2005-04-02 Inge Wallin <[email protected]>
+
+ Fix bug 102890: The result is not put into the higscore if not all
+ squares are filled at the end of the game
+ * kreversi.cpp (KReversi): call slotNewGame
+
+2005-04-01 Inge Wallin <[email protected]>
+
+ Fix bug 102297: I am playing in KReversi as "expert" but it saves
+ statistics to the "beginner" records
+ * kreversi.h (m_lowestStrength): Should be uint instead of bool.
+
+2005-03-31 Inge Wallin <[email protected]>
+
+ Implement wish 102813: Should be able to show last move
+ * board.{h,cpp} (m_showLastMove, lastMoveShown): new members
+ (setShowLastMove, showLastMove): new methods
+ (updateBoard): show last move.
+ * kreversi.{h,cpp} (showLastMoveAction): new toggleaction
+ (slotShowLastMove): new slot
+ * kreversiui.rc (show_last_move): new action
+
+ Some consecutive small, but important changes (latest at the top).
+ * Position::undoMove(): new method.
+ * Remove m_lastPosition from class Game.
+ * Rename makeMove() to doMove() and takeBackMove() to undoMove().
+
+ Big changes in the lower levels of the program. Mostly
+ simplifications.
+ * Move.h, Move.cpp (SimpleMove): renamed from Move
+ (Move): new class with undo information
+ * Position.h, Position.cpp: allow Move and SimpleMove in various
+ places.
+ * Game.h, Game.cpp: allow Move and SimpleMove in various places
+
+2005-03-30 Inge Wallin <[email protected]>
+
+ Continue on wish 82900
+ * kreversiui.rc (viewToolBar): new toolbar for the views.
+ * kreversi.{h,cpp} (showLegalMovesAction): new toggleaction
+ (slotShowLegalMOves): new slot
+ (misc): check status of toggle action before showing legal moves
+ NOTE: This change adds a new toolbar. Before testing you must
+ make install.
+
+ ----------------------------------------------------------------
+
+ Start on wish 82900: Show possible moves in the current position
+ * Move.{h,cpp} (Move): new copy constructor
+ * Move.h (MoveList): new type
+ * qreversigame.h (position): new method.
+ * Position.{h,cpp} (generateMoves): new method
+ * board.{h,cc} (showLegalMoves, quitShowLegalMoves): new methods
+ (setMarks): Show also legal moves.
+ * kreversi.cpp: call showLegalMoves() in various places.
+
+ ----------------------------------------------------------------
+
+ Implement wish 82517: show moves of the game in a view
+ * Game.h (Game): Make members protected.
+ (asString): new method
+ * qreversigame.cpp (makeMove): emit new signal sig_move .
+ * kreversi.{h,cpp} (m_movesView): new member
+ (showMove): new slot
+
+2005-03-29 Inge Wallin <[email protected]>
+
+ Implement wish 82519: Label the board with A-H, 1-8
+ * board.cpp (OFFSET): new macro
+ (m_marksShowing): new member
+ (setMarks): new method
+ (mousePressEvent): take into account offset.
+ (updateBoard): draw markings if m_marksShowing is true
+ (drawOnePiece): take into account offset.
+ (adjustSize): take into account markings
+
+ Some cleaning
+
+ ----------------------------------------------------------------
+
+ Move KReversiGame out to its own file, and remove it.
+ * qreversigame.{h,cpp}: new files.
+ (class): Inherit from Game instead of containing it.
+ (signal score): Rename into sig_score().
+ * Makefile.am: include new files.
+ * board.cpp: Remove class KReversiGame
+ (all methods): Rename to QReversiGame
+
+ Code cleaning
+ * Game.{h,cpp} (~Game): new method
+
+2005-03-28 Inge Wallin <[email protected]>
+
+ * kreversi.cpp (KReversi): Fix faulty connect().
+
+
+================================================================
+ KDE 3.4 released
+================================================================
+
+
+2005-02-18 Inge Wallin <[email protected]>
+
+ * version.h (KREVERSI_VERSION): Bumped version to 1.6
+
+2004-10-31 Inge Wallin <[email protected]>
+
+ Better fix for bug 91055.
+ * kreversi.cpp (slotNewGame): Reimplement dialog using
+ KMessageBox::warningYesNo(). This solves the FIXME in the header.
+
+2004-10-15 Inge Wallin <[email protected]>
+
+ Fix bug 90472: KReversi: When you interrupt the computers move and
+ then switch sides, the program gets confused
+ * kreversi.cpp (slotSwitchSides): Don't allow the user to switch
+ sides if the computers move is interrupted.
+
+2004-10-11 Inge Wallin <[email protected]>
+
+ Code cleaning
+ * kreversi.{h,cpp}: Make all members follow the m_ convention.
+ Also added some comments.
+
+ ----------------- CVS commit on stuff below --------------------
+
+ Fix bug 91055 - KReversi: If you start a new game when a game is
+ playing, the user is never asked for confirmation.
+ * kreversi.cpp (slotNewGame): Show a dialog that asks for
+ confirmation from the user.
+
+2004-10-09 Inge Wallin <[email protected]>
+
+ Fix bug 90203: KReversi: It should be visible when the user
+ interrupts the computers thinking.
+ * kreversi.cpp (slotInterrupt): call showTurn().
+ (showTurn): Show "(interrupted)" if it is.
+ NOTE: This fix can't be backported easily since there is a string
+ freeze for BRANCH_3_3.
+
+ ----------------- CVS commit on stuff below --------------------
+
+ Fix a bug that made the score unset at startup.
+ * kreversi.cpp (KReversi): show the score at startup.
+
+ ----------------- CVS commit on stuff below --------------------
+
+ Finally make KReversi a proper Model/View program (step I.4 and
+ I.5 from the plan in the TODO file).
+ * board.{h,cpp} (KReversiGame): new class
+ * board.{h,cpp} (Board): new name KReversiBoardView
+ * Lots of minor cleanup
+ * DESIGN: (class diagram): new info
+
+ ----------------- CVS commit on stuff below --------------------
+
+ Some minor cleanup.
+
+2004-10-03 Inge Wallin <[email protected]>
+
+ * DESIGN: New document
+
+ ----------------- CVS commit on stuff below --------------------
+
+ Simplify saving of the game
+ * Game.{h,cpp} (move(uint)): New method.
+ * kreversi.cpp (saveGame): Use the new method, and don't call
+ loadGame to restore the Game object.
+
+2004-09-29 Inge Wallin <[email protected]>
+
+ Continue to make KReversi a proper model/view program:
+ Step I.1 of the plan (see TODO): Fix the class Game
+ * Game.h (Game): Convert to store moves instead of positions.
+ * Game.cpp (Game): Code cleanup and convert as above.
+ * Game.{h,cpp}: Follow naming conventions from the rest of the
+ program.
+ * Position.{h,cpp}: Follow naming conventions from the rest of the
+ program.
+ * Position.{h,cpp} (Position::operator=): new method.
+ (Position::makeMove): new method.
+
+ Added myself in the credits in the about window.
+ (Will add myself to the real authors when we have KGame and
+ network play ready. :-) )
+
+2004-09-27 Inge Wallin <[email protected]>
+
+ Continue to make KReversi a proper model/view program:
+ * Transfer ownership of Game and Engine to kreversi from Board.
+ board.h, board.cpp, kreversi.h, kreversi.cpp: lots of changes.
+
+ Some other cleanup:
+ * SuperEngine.h (interrupt): renamed to interrupted()
+
+2004-09-26 Inge Wallin <[email protected]>
+
+ Fix bug 90195: KReversi: Changing the skill level late in a game
+ doesn't count as cheating:
+ * board.h (Board::m_lowestStrength): new member
+ * board.cpp (Board::newGame): set m_lowestStrength
+ * board.cpp (Board::setStrength): update m_lowestStrength and
+ update highscore type.
+
+ Fix Bug 90190: KReversi: Switch sides and then Undo gets the
+ program out of sync.
+ * board.cpp (doUndo): If it is the computers turn to move after an
+ undo, call computerMakeMove().
+ (doUndo): Fix repainting so that it looks nice.
+
+2004-09-25 Inge Wallin <[email protected]>
+
+ Transfer the rest of the slots for KActions to kreversi.cpp
+ * Board::interrupt() -> KReversi::slotInterrupt()
+ * Board::doContinue() -> KReversi::slotContinue()
+
+ Rename some slots for clarity
+ * KReversi::switchSides() -> KReversi::slotSwitchSides()
+ * KReversi::showSettings() -> KReversi::slotEditSettings()
+
+ Make a trivial function inline:
+ * Board::interrupt()
+
+2004-09-24 Inge Wallin <[email protected]>
+
+ Start the work to port KReversi to KGame/Kplayer:
+
+ Transfer the slots for most KActions to kreversi.cpp
+ * Board::undo() -> KReversi::slotUndo()
+ (Board::doUndo()): Do the real work of undoing.
+ * Board->hint() -> KReversi::slotHint()
+ (Board::showHint): do the actual work of showing the hint.
+
+ Rename some slots for clarity
+ * KReversi::newGame -> KReversi::slotNewGame
+ * KReversi::openGame -> KReversi::slotOpenGame
+ * KReversi::save -> KReversi::slotSave
+
+ Make some trivial functions inline:
+ * Board::whoseTurn()
+ * Board::moveNumber()
+ * Board::score(Color)
+ * Board::interrupted()
+ * Board::strength()
+
+2004-09-23 Anne-Marie Mahfouf <[email protected]>
+
+ Cleaned some previously left lines of code in board.cpp
+ Change CustomAdditions=false back in prefs.kcfg to fix compilation
+ Tested Inges fix and found it works well.
+
+2004-09-22 Inge Wallin <[email protected]>
+
+ Fix bug 89829: "KReversi: When you save a game, the color for
+ Human and Computer is not saved" again. See the discussion on the
+ KDE bugzilla for details
+ (http://bugs.kde.org/show_bug.cgi?id=89829).
+ * board.cpp (Board::saveGame): Save m_humanColor as HumanColor.
+ * Remove saving of the side to move since this is implicit
+ anyway.
+ * (Board::loadGame): Fix loading of m_humanColor and
+ m_competitiveGame
+ * Fix emit of signal turn, and the condition to call
+ computerMakeMove().
+ * prefs_addons.h: Removed
+
+
+2004-09-18 Anne-Marie Mahfouf (ChangeLog entry by Inge Wallin)
+
+ Fix bug 89829. (See above, though)
+ * prefs_addons.h: New file
+ * board.cpp (saveGame): Some changes
+
+2004-09-18 Inge Wallin <[email protected]>
+
+ Some cleaning: remove unused members, add m_ to members and some
+ comments.
+ * Engine.h (Engine::lastYield): removed
+ * Board.h (Board::nopaint): removed
+ * kreversi.{h,cpp} (KReversi::board): renamed into m_board.
+
+2004-09-17 Inge Wallin <[email protected]>
+
+ Some further cleanup:
+ * board.{h,cpp} (game, engine, human): renamed into m_game,
+ m_engine and m_humanColor.
+
+2004-09-16 Inge Wallin <[email protected]>
+
+ Support Casual and Competitive play:
+ * SuperEngine.cpp (SuperEngine::computeMove()): new parameter
+ 'competitive'
+ * Engine.cpp (Engine::computeMove()): new parameter 'competitive'
+ * board.cpp (m_competitiveGame): new member
+ (saveGame, loadGame): Save competitive in config file.
+ * kreversi.cpp (slotGameEnded): Only store result in highscore
+ file if the game was competitive all the time.
+ * kreversi.kcfg (CompetitiveGameChoice): new setting
+ * settings.ui: redesigned
+
+
+2004-08-17 Inge Wallin <[email protected]>
+
+ Finish the big code cleanup:
+ * board.h, board.cpp: cleaned up
+ * highscores.h, highscores.cpp,
+ * kzoommainwindow.h, kzoommainwindow.cpp:
+ Converted to same coding style as rest of kreversi.
+
+
+2004-08-16 Inge Wallin <[email protected]>
+
+ Continue the big code cleanup:
+ * Engine.h, Engine.cpp
+ * kreversi.h kreversi.cpp
+
+
+2004-08-15 Inge Wallin <[email protected]>
+
+ Continue the big code cleanup:
+ * SuperEngine.h, SuperEngine.cpp
+ * Game.h Game.cpp
+
+2004-08-14 Inge Wallin <[email protected]>
+
+ Start of the big code cleanup:
+ * Move.h, Move.cpp
+ * Score.h, Score.cpp
+ * main.cpp
+ * Position.h, Position.cpp
+
+ Step 2 in the plan to use KGame from libkdegames:
+ * Code cleaning: Add some comments, reduce complexity, improve
+ indentation
+ * Add m_to_move to class Position.
+
+
+ Step 1 in the plan to use KGame from libkdegames:
+ * Code cleaning: Change "enum Player" into "enum Color", since that
+ is really what it describes.
+
+2004-06-29 (1.5) Nicolas Hadacek <[email protected]>
+ * use KZoomMainWindow
+
+2004-05-29 (1.4) Nicolas Hadacek <[email protected]>
+ * fix statusbar + cleanup code
+ * use notify framework for sounds
+
+1999-06-20 Mario Weilguni <[email protected]>
+ * fixed bugs with those damned KStdDirs
+ * removed the private wallpapers and use the KDE ones instead
+ * use kimgio
+ * fixed locating toolbar icons
+ * compiles now with --enable-final
+
+1999-06-16 Mario Weilguni <[email protected]>
+ * adapted to the upcoming KDE-2
+
+1999-02-01 Mario Weilguni <[email protected]>
+ * fixed a warning (egcs)
+
+1.0
+ * I finally decided that it�s stable enough. This is the final
+ version (if no further bugs are detected and I do not have a
+ good idea what to improve)
+
+ * ChangeLog reversed
+
+0.6.6
+ * [Robert Williams] Changed Reversi.kdelnk to kreversi.kdelnk
+ * [Robert Williams] Add -caption "%c" to kreversi.kdelnk
+ * [Robert Williams] Added kapp->getCaption()
+ * [Robert Williams] getHelpMenu(true, 0) -> Uses own About dialog
+
+0.6.5 Support for non GNUC++ compilers.
+
+0.6.4 fixed that get-hit-and-then-doubleclick bug
+
+ fixed a bug that caused the computer to switch sides if no
+ computer move is possible instead of getting another human move
+
+0.6.3 sound fix: when the animation is finished, the correct piece gets
+ redrawn before doing a sound-sync (how could I ever believe 0.6.2
+ would be the last change :-)
+
+0.6.2 animation fixed (hope this will be the last change)
+
+0.6.1 fixed that newly introduced highscore bug
+ computer continues now if a game was saved while thinking
+
+0.6: better integration into new FSSTND
+ fixes for new kdecore
+ layout management for all dialogs
+ mini-icon and icon
+ locale-strings changed - partial translation required for
+ other languages than english and german
+ removed both the kfixedtopwidget and ktablistbox
+ drawing a border around the reversi board
+ session-management - what an overkill for kreversi :-))
+ you can save (and load) exactly ONE game
+
+
+0.5: added klocale to support translation
+ added german translation
+ fixed a few bugs
+ tried to remove absolute widget placing/sizing
+ removed the date field from the HOF
+ grayscale support
+ fixed those CPU busy bug
+ removed the -finline-functions optimize flag (not portable)
+ ported to new KDE file system standards (well, mostly)
+ fixed segfaulting on exit
+
+0.4: interims release - no changelog
+
+0.3: Sound support (using libmediatool)
+ When switching sides, the Quit -> the computer made on move. FIXED
+ Fixed a few typos
+ Cursor changes when thinking
+
+0.2.1: times(NULL) does not work with FreeBSD (fixed)
+ fixed a bug (reported by Stephan Kulow) where pixmaps of pieces
+ are not initialized properly (could't reproduce the bug with
+ my system)
+ New "About" dialog showing all (well, most) of the contributors
+ All xpm's have now 8 bits per color component instead of 16.
+ 16 bits seems to confuse the XPM loader of Qt.
+
+0.2: better pieces
+ animations
+ fixed a small bug: when someone made it in the hall of fame,
+ he was'nt notified of this
+ some improvements in the Hall Of Fame
+
+0.1.2: background color selectable via dialog
+ background pixmaps implemented, selectable via menu
+ background pixmaps are scaled to fit size
+ pieces are drawn at runtime instead of pixmaps
+ some accelerators added
+ toolbar buttons for help and hint added
+
+0.1.1: now pixmaps are installed
+ a kdelnk file is installed
+ version numbering changed
+
+0.1 : First release
diff --git a/kreversi/DESIGN b/kreversi/DESIGN
new file mode 100644
index 00000000..d2a13202
--- /dev/null
+++ b/kreversi/DESIGN
@@ -0,0 +1,121 @@
+This file describes the overall design of KReversi. Some of the
+classes have different names at this point, but that is indicated by a
+(now: XXX) tag. These names will be changed when the KDE project has
+converted from CVS to Subversion since Subversion has so much better
+support for renaming files and directories.
+
+Almost all of the classes hold more members than are mentioned here,
+but those are implementation details and would only obscure the
+overall picture. This file is only to give a helicopter view of the
+program, not to serve as detailed documentation.
+
+
+Classes
+=======
+
+Class Diagram (See details below)
+-------------
+
+KReversi----------------------------------------------+
+ | | +--------------------------------+ |
+ | +-----------------+ | |
+ | | | |
+ | v v v
+ | QReversiGameView Engine StatusBar
+ | | | | (shows whose turn it is)
+ | +- - - - - - - + | +----------+
+ | | v v
+ | +- - - -QReversiBoardView Other widgets
+ | | | (movelist, score)
+ v v v
+QReversiGame
+ X
+ v
+ Game
+ I +=========+
+ I I
+ v v
+Position Move[]
+
+
+Legend:
+XXXXXXXX> Inherits
+========> Contains
+--------> Ownership pointer
+- - - - > Reference pointer
+
+
+Details
+-------
+
+ReversiPosition (now: Position)
+ Holds a Reversi position. This is the object that implements the
+ Reversi rules.
+
+
+ReversiMove (now: Move)
+ A move in a Reversi game.
+
+
+ReversiGame (now: Game)
+ Holds all the moves of the game being played.
+ Contains: ReversiPosition Holds the current position.
+ Move[60]
+ FIXME: Remove the ReversiPosition and let it be implicit?
+ FIXME: Implement variations (later)
+
+
+Engine
+ Can generate a move, given a ReversiPosition.
+
+
+QReversiGame
+ The "document" for KReversi.
+ Handles a game being played and sends signals to all its views
+ when something changes. Basically, the only difference between
+ this class and the more basic ReversiGame is that it sends signals
+ to the views.
+ Inherits: ReversiGame The actual game being played
+
+
+QReversiGameView (status: PLANNED)
+
+ Shows a view of a complete game. Currently this comprises a board
+ view, a listbox with a list of the moves, two status widgets
+ showing the current score.
+
+ Contains: *QReversiBoardView
+ *QListBox
+ *StatusWidget (two of them)
+
+
+QReversiBoardView
+
+ A view for a Reversi board. The rest of the game view is
+ implemented in the class QReversiGameView.
+
+ Inherits: QWidget.
+ Contains: *QReversiGame (not owner)
+
+ FIXME: Enhance the view with timing information, clock, etc.
+
+
+KReversi
+ The main class for the KReversi program
+ Contains: KActions
+ *QReversiGame (owner)
+ *KReversiGameView (owner)
+ *Engine (owner)
+ Statusbar
+
+ FIXME: Let the class also own two players.
+
+
+EngineView (status: PLANNED)
+ View of the internal thought processes of an Engine (trace, etc).
+
+
+Some notes
+----------
+
+* KReversi follows the Model/View principle strictly.
diff --git a/kreversi/Engine.cpp b/kreversi/Engine.cpp
new file mode 100644
index 00000000..da7750ce
--- /dev/null
+++ b/kreversi/Engine.cpp
@@ -0,0 +1,787 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+// The class Engine produces moves from a Game object through calls to the
+// function ComputeMove().
+//
+// First of all: this is meant to be a simple example of a game playing
+// program. Not everything is done in the most clever way, particularly not
+// the way the moves are searched, but it is hopefully made in a way that makes
+// it easy to understand. The function ComputeMove2() that does all the work
+// is actually not much more than a hundred lines. Much could be done to
+// make the search faster though, I'm perfectly aware of that. Feel free
+// to experiment.
+//
+// The method used to generate the moves is called minimax tree search with
+// alpha-beta pruning to a fixed depth. In short this means that all possible
+// moves a predefined number of moves ahead are either searched or refuted
+// with a method called alpha-beta pruning. A more thorough explanation of
+// this method could be found at the world wide web at http:
+// //yoda.cis.temple.edu:8080/UGAIWWW/lectures96/search/minimax/alpha-beta.html
+// at the time this was written. Searching for "minimax" would also point
+// you to information on this subject. It is probably possible to understand
+// this method by reading the source code though, it is not that complicated.
+//
+// At every leaf node at the search tree, the resulting position is evaluated.
+// Two things are considered when evaluating a position: the number of pieces
+// of each color and at which squares the pieces are located. Pieces at the
+// corners are valuable and give a high value, and having pieces at squares
+// next to a corner is not very good and they give a lower value. In the
+// beginning of a game it is more important to have pieces on "good" squares,
+// but towards the end the total number of pieces of each color is given a
+// higher weight. Other things, like how many legal moves that can be made in a
+// position, and the number of pieces that can never be turned would probably
+// make the program stronger if they were considered in evaluating a position,
+// but that would make things more complicated (this was meant to be very
+// simple example) and would also slow down computation (considerably?).
+//
+// The member m_board[10][10]) holds the current position during the
+// computation. It is initiated at the start of ComputeMove() and
+// every move that is made during the search is made on this board. It should
+// be noted that 1 to 8 is used for the actual board, but 0 and 9 can be
+// used too (they are always empty). This is practical when turning pieces
+// when moves are made on the board. Every piece that is put on the board
+// or turned is saved in the stack m_squarestack (see class SquareStack) so
+// every move can easily be reversed after the search in a node is completed.
+//
+// The member m_bc_board[][] holds board control values for each square
+// and is initiated by a call to the function private void SetupBcBoard()
+// from Engines constructor. It is used in evaluation of positions except
+// when the game tree is searched all the way to the end of the game.
+//
+// The two members m_coord_bit[9][9] and m_neighbor_bits[9][9] are used to
+// speed up the tree search. This goes against the principle of keeping things
+// simple, but to understand the program you do not need to understand them
+// at all. They are there to make it possible to throw away moves where
+// the piece that is played is not adjacent to a piece of opposite color
+// at an early stage (because they could never be legal). It should be
+// pointed out that not all moves that pass this test are legal, there will
+// just be fewer moves that have to be tested in a more time consuming way.
+//
+// There are also two other members that should be mentioned: Score m_score
+// and Score m_bc_score. They hold the number of pieces of each color and
+// the sum of the board control values for each color during the search
+// (this is faster than counting at every leaf node).
+//
+
+// The classes SquareStackEntry and SquareStack implement a
+// stack that is used by Engine to store pieces that are turned during
+// searching (see ComputeMove()).
+//
+// The class MoveAndValue is used by Engine to store all possible moves
+// at the first level and the values that were calculated for them.
+// This makes it possible to select a random move among those with equal
+// or nearly equal value after the search is completed.
+
+
+#include <qapplication.h>
+
+#include "Engine.h"
+
+
+// ================================================================
+// Class ULONG64
+
+
+#if !defined(__GNUC__)
+
+
+ULONG64::ULONG64() : QBitArray(64)
+{
+ fill(0);
+}
+
+
+// Initialize an ULONG64 from a 32 bit value.
+//
+
+ULONG64::ULONG64( unsigned int value ) : QBitArray(64)
+{
+ fill(0);
+ for(int i = 0; i < 32; i++) {
+ setBit(i, (bool)(value & 1));
+ value >>= 1;
+ }
+}
+
+
+// Shift an ULONG64 left one bit.
+//
+
+void ULONG64::shl()
+{
+ for(int i = 63; i > 0; i--)
+ setBit(i, testBit(i - 1));
+ setBit(0, 0);
+}
+
+#endif
+
+
+// ================================================================
+// Classes SquareStackEntry and SquareStack
+
+
+// A SquareStack is used to store changes to the squares on the board
+// during search.
+
+
+inline void SquareStackEntry::setXY(int x, int y) {
+ m_x = x;
+ m_y = y;
+}
+
+
+SquareStackEntry::SquareStackEntry()
+{
+ setXY(0,0);
+}
+
+
+// ----------------------------------------------------------------
+
+
+SquareStack::SquareStack() {
+ init(0);
+}
+
+
+SquareStack::SquareStack(int size) {
+ init(size);
+}
+
+
+void SquareStack::resize(int size)
+{
+ m_squarestack.resize(size);
+}
+
+
+// (Re)initialize the stack so that is empty, and at the same time
+// resize it to 'size'.
+//
+
+void SquareStack::init(int size)
+{
+ resize(size);
+
+ m_top = 0;
+ for (int i = 0; i < size; i++)
+ m_squarestack[i].setXY(0,0);
+}
+
+
+
+inline SquareStackEntry SquareStack::Pop()
+{
+ return m_squarestack[--m_top];
+}
+
+
+inline void SquareStack::Push(int x, int y)
+{
+ m_squarestack[m_top].m_x = x;
+ m_squarestack[m_top++].m_y = y;
+}
+
+
+// ================================================================
+// Class MoveAndValue
+
+
+// Class MoveAndValue aggregates a move with its value.
+//
+
+
+inline void MoveAndValue::setXYV(int x, int y, int value)
+{
+ m_x = x;
+ m_y = y;
+ m_value = value;
+}
+
+
+MoveAndValue::MoveAndValue()
+{
+ setXYV(0,0,0);
+}
+
+
+MoveAndValue::MoveAndValue(int x, int y, int value)
+{
+ setXYV(x, y, value);
+}
+
+
+// ================================================================
+// The Engine itself
+
+
+// Some special values used in the search.
+const int Engine::LARGEINT = 99999;
+const int Engine::ILLEGAL_VALUE = 8888888;
+const int Engine::BC_WEIGHT = 3;
+
+
+Engine::Engine(int st, int sd) : SuperEngine(st, sd)
+{
+ SetupBcBoard();
+ SetupBits();
+}
+
+
+Engine::Engine(int st) : SuperEngine(st)
+{
+ SetupBcBoard();
+ SetupBits();
+}
+
+
+Engine::Engine() : SuperEngine(1)
+{
+ SetupBcBoard();
+ SetupBits();
+}
+
+
+// keep GUI alive
+void Engine::yield()
+{
+ qApp->processEvents();
+}
+
+
+// Calculate the best move from the current position, and return it.
+
+Move Engine::computeMove(Game *game, bool competitive)
+{
+ Color color;
+
+ // A competitive game is one where we try our damnedest to make the
+ // best move. The opposite is a casual game where the engine might
+ // make "a mistake". The idea behind this is not to scare away
+ // newbies. The member m_competitive is used during search for this
+ // very move.
+ m_competitive = competitive;
+
+ // Suppose that we should give a heuristic evaluation. If we are
+ // close to the end of the game we can make an exhaustive search,
+ // but that case is determined further down.
+ m_exhaustive = false;
+
+ // Get the color to calculate the move for.
+ color = game->toMove();
+ if (color == Nobody)
+ return Move(Nobody, -1, -1);
+
+ // Figure out the current score
+ m_score.set(White, game->score(White));
+ m_score.set(Black, game->score(Black));
+
+ // Treat the first move as a special case (we can basically just
+ // pick a move at random).
+ if (m_score.score(White) + m_score.score(Black) == 4)
+ return ComputeFirstMove(game);
+
+ // Let there be room for 3000 changes during the recursive search.
+ // This is more than will ever be needed.
+ m_squarestack.init(3000);
+
+ // Get the search depth. If we are close to the end of the game,
+ // the number of possible moves goes down, so we can search deeper
+ // without using more time.
+ m_depth = m_strength;
+ if (m_score.score(White) + m_score.score(Black) + m_depth + 3 >= 64)
+ m_depth = 64 - m_score.score(White) - m_score.score(Black);
+ else if (m_score.score(White) + m_score.score(Black) + m_depth + 4 >= 64)
+ m_depth += 2;
+ else if (m_score.score(White) + m_score.score(Black) + m_depth + 5 >= 64)
+ m_depth++;
+
+ // If we are very close to the end, we can even make the search
+ // exhaustive.
+ if (m_score.score(White) + m_score.score(Black) + m_depth >= 64)
+ m_exhaustive = true;
+
+ // The evaluation is a linear combination of the score (number of
+ // pieces) and the sum of the scores for the squares (given by
+ // m_bc_score). The earlier in the game, the more we use the square
+ // values and the later in the game the more we use the number of
+ // pieces.
+ m_coeff = 100 - (100*
+ (m_score.score(White) + m_score.score(Black)
+ + m_depth - 4)) / 60;
+
+ // Initialize the board that we use for the search.
+ for (uint x = 0; x < 10; x++)
+ for (uint y = 0; y < 10; y++) {
+ if (1 <= x && x <= 8
+ && 1 <= y && y <= 8)
+ m_board[x][y] = game->color(x, y);
+ else
+ m_board[x][y] = Nobody;
+ }
+
+ // Initialize a lot of stuff that we will use in the search.
+
+ // Initialize m_bc_score to the current bc score. This is kept
+ // up-to-date incrementally so that way we won't have to calculate
+ // it from scratch for each evaluation.
+ m_bc_score.set(White, CalcBcScore(White));
+ m_bc_score.set(Black, CalcBcScore(Black));
+
+ ULONG64 colorbits = ComputeOccupiedBits(color);
+ ULONG64 opponentbits = ComputeOccupiedBits(opponent(color));
+
+ int maxval = -LARGEINT;
+ int max_x = 0;
+ int max_y = 0;
+
+ MoveAndValue moves[60];
+ int number_of_moves = 0;
+ int number_of_maxval = 0;
+
+ setInterrupt(false);
+
+ ULONG64 null_bits;
+ null_bits = 0;
+
+ // The main search loop. Step through all possible moves and keep
+ // track of the most valuable one. This move is stored in
+ // (max_x, max_y) and the value is stored in maxval.
+ m_nodes_searched = 0;
+ for (int x = 1; x < 9; x++) {
+ for (int y = 1; y < 9; y++) {
+ // Don't bother with non-empty squares and squares that aren't
+ // neighbors to opponent pieces.
+ if (m_board[x][y] != Nobody
+ || (m_neighbor_bits[x][y] & opponentbits) == null_bits)
+ continue;
+
+
+ int val = ComputeMove2(x, y, color, 1, maxval,
+ colorbits, opponentbits);
+
+ if (val != ILLEGAL_VALUE) {
+ moves[number_of_moves++].setXYV(x, y, val);
+
+ // If the move is better than all previous moves, then record
+ // this fact...
+ if (val > maxval) {
+
+ // ...except that we want to make the computer miss some
+ // good moves so that beginners can play against the program
+ // and not always lose. However, we only do this if the
+ // user wants a casual game, which is set in the settings
+ // dialog.
+ int randi = m_random.getLong(7);
+ if (maxval == -LARGEINT
+ || m_competitive
+ || randi < (int) m_strength) {
+ maxval = val;
+ max_x = x;
+ max_y = y;
+
+ number_of_maxval = 1;
+ }
+ }
+ else if (val == maxval)
+ number_of_maxval++;
+ }
+
+ // Jump out prematurely if interrupt is set.
+ if (interrupted())
+ break;
+ }
+ }
+
+ // long endtime = times(&tmsdummy);
+
+ // If there are more than one best move, the pick one randomly.
+ if (number_of_maxval > 1) {
+ int r = m_random.getLong(number_of_maxval) + 1;
+ int i;
+
+ for (i = 0; i < number_of_moves; i++) {
+ if (moves[i].m_value == maxval && --r <= 0)
+ break;
+ }
+
+ max_x = moves[i].m_x;
+ max_y = moves[i].m_y;
+ }
+
+ // Return a suitable move.
+ if (interrupted())
+ return Move(Nobody, -1, -1);
+ else if (maxval != -LARGEINT)
+ return Move(color, max_x, max_y);
+ else
+ return Move(Nobody, -1, -1);
+}
+
+
+// Get the first move. We can pick any move at random.
+//
+
+Move Engine::ComputeFirstMove(Game *game)
+{
+ int r;
+ Color color = game->toMove();
+
+ r = m_random.getLong(4) + 1;
+
+ if (color == White) {
+ if (r == 1) return Move(color, 3, 5);
+ else if (r == 2) return Move(color, 4, 6);
+ else if (r == 3) return Move(color, 5, 3);
+ else return Move(color, 6, 4);
+ }
+ else {
+ if (r == 1) return Move(color, 3, 4);
+ else if (r == 2) return Move(color, 5, 6);
+ else if (r == 3) return Move(color, 4, 3);
+ else return Move(color, 6, 5);
+ }
+}
+
+
+// Play a move at (xplay, yplay) and generate a value for it. If we
+// are at the maximum search depth, we get the value by calling
+// EvaluatePosition(), otherwise we get it by performing an alphabeta
+// search.
+//
+
+int Engine::ComputeMove2(int xplay, int yplay, Color color, int level,
+ int cutoffval, ULONG64 colorbits,
+ ULONG64 opponentbits)
+{
+ int number_of_turned = 0;
+ SquareStackEntry mse;
+ Color opponent = ::opponent(color);
+
+ m_nodes_searched++;
+
+ // Put the piece on the board and incrementally update scores and bitmaps.
+ m_board[xplay][yplay] = color;
+ colorbits |= m_coord_bit[xplay][yplay];
+ m_score.inc(color);
+ m_bc_score.add(color, m_bc_board[xplay][yplay]);
+
+ // Loop through all 8 directions and turn the pieces that can be turned.
+ for (int xinc = -1; xinc <= 1; xinc++)
+ for (int yinc = -1; yinc <= 1; yinc++) {
+ if (xinc == 0 && yinc == 0)
+ continue;
+
+ int x, y;
+
+ for (x = xplay + xinc, y = yplay + yinc; m_board[x][y] == opponent;
+ x += xinc, y += yinc)
+ ;
+
+ // If we found the end of a turnable row, then go back and turn
+ // all pieces on the way back. Also push the squares with
+ // turned pieces on the squarestack so that we can undo the move
+ // later.
+ if (m_board[x][y] == color)
+ for (x -= xinc, y -= yinc; x != xplay || y != yplay;
+ x -= xinc, y -= yinc) {
+ m_board[x][y] = color;
+ colorbits |= m_coord_bit[x][y];
+ opponentbits &= ~m_coord_bit[x][y];
+
+ m_squarestack.Push(x, y);
+
+ m_bc_score.add(color, m_bc_board[x][y]);
+ m_bc_score.sub(opponent, m_bc_board[x][y]);
+ number_of_turned++;
+ }
+ }
+
+ int retval = -LARGEINT;
+
+ // If we managed to turn at least one piece, then (xplay, yplay) was
+ // a legal move. Now find out the value of the move.
+ if (number_of_turned > 0) {
+
+ // First adjust the number of pieces for each side.
+ m_score.add(color, number_of_turned);
+ m_score.sub(opponent, number_of_turned);
+
+ // If we are at the bottom of the search, get the evaluation.
+ if (level >= m_depth)
+ retval = EvaluatePosition(color); // Terminal node
+ else {
+ int maxval = TryAllMoves(opponent, level, cutoffval, opponentbits,
+ colorbits);
+
+ if (maxval != -LARGEINT)
+ retval = -maxval;
+ else {
+
+ // No possible move for the opponent, it is colors turn again:
+ retval = TryAllMoves(color, level, -LARGEINT, colorbits, opponentbits);
+
+ if (retval == -LARGEINT) {
+
+ // No possible move for anybody => end of game:
+ int finalscore = m_score.score(color) - m_score.score(opponent);
+
+ if (m_exhaustive)
+ retval = finalscore;
+ else {
+ // Take a sure win and avoid a sure loss (may not be optimal):
+
+ if (finalscore > 0)
+ retval = LARGEINT - 65 + finalscore;
+ else if (finalscore < 0)
+ retval = -(LARGEINT - 65 + finalscore);
+ else
+ retval = 0;
+ }
+ }
+ }
+ }
+
+ m_score.add(opponent, number_of_turned);
+ m_score.sub(color, number_of_turned);
+ }
+
+ // Undo the move. Start by unturning the turned pieces.
+ for (int i = number_of_turned; i > 0; i--) {
+ mse = m_squarestack.Pop();
+ m_bc_score.add(opponent, m_bc_board[mse.m_x][mse.m_y]);
+ m_bc_score.sub(color, m_bc_board[mse.m_x][mse.m_y]);
+ m_board[mse.m_x][mse.m_y] = opponent;
+ }
+
+ // Now remove the new piece that we put down.
+ m_board[xplay][yplay] = Nobody;
+ m_score.sub(color, 1);
+ m_bc_score.sub(color, m_bc_board[xplay][yplay]);
+
+ // Return a suitable value.
+ if (number_of_turned < 1 || interrupted())
+ return ILLEGAL_VALUE;
+ else
+ return retval;
+}
+
+
+// Generate all legal moves from the current position, and do a search
+// to see the value of them. This function returns the value of the
+// most valuable move, but not the move itself.
+//
+
+int Engine::TryAllMoves(Color opponent, int level, int cutoffval,
+ ULONG64 opponentbits, ULONG64 colorbits)
+{
+ int maxval = -LARGEINT;
+
+ // Keep GUI alive by calling the event loop.
+ yield();
+
+ ULONG64 null_bits;
+ null_bits = 0;
+
+ for (int x = 1; x < 9; x++) {
+ for (int y = 1; y < 9; y++) {
+ if (m_board[x][y] == Nobody
+ && (m_neighbor_bits[x][y] & colorbits) != null_bits) {
+ int val = ComputeMove2(x, y, opponent, level+1, maxval, opponentbits,
+ colorbits);
+
+ if (val != ILLEGAL_VALUE && val > maxval) {
+ maxval = val;
+ if (maxval > -cutoffval || interrupted())
+ break;
+ }
+ }
+ }
+
+ if (maxval > -cutoffval || interrupted())
+ break;
+ }
+
+ if (interrupted())
+ return -LARGEINT;
+
+ return maxval;
+}
+
+
+// Calculate a heuristic value for the current position. If we are at
+// the end of the game, do this by counting the pieces. Otherwise do
+// it by combining the score using the number of pieces, and the score
+// using the board control values.
+//
+
+int Engine::EvaluatePosition(Color color)
+{
+ int retval;
+
+ Color opponent = ::opponent(color);
+
+ int score_color = m_score.score(color);
+ int score_opponent = m_score.score(opponent);
+
+ if (m_exhaustive)
+ retval = score_color - score_opponent;
+ else {
+ retval = (100-m_coeff) *
+ (m_score.score(color) - m_score.score(opponent))
+ + m_coeff * BC_WEIGHT * (m_bc_score.score(color)
+ - m_bc_score.score(opponent));
+ }
+
+ return retval;
+}
+
+
+// Calculate bitmaps for each square, and also for neighbors of each
+// square.
+//
+
+void Engine::SetupBits()
+{
+ //m_coord_bit = new long[9][9];
+ //m_neighbor_bits = new long[9][9];
+
+ ULONG64 bits = 1;
+
+ // Store a 64 bit unsigned it with the corresponding bit set for
+ // each square.
+ for (int i=1; i < 9; i++)
+ for (int j=1; j < 9; j++) {
+ m_coord_bit[i][j] = bits;
+#if !defined(__GNUC__)
+ bits.shl();
+#else
+ bits *= 2;
+#endif
+ }
+
+ // Store a bitmap consisting of all neighbors for each square.
+ for (int i=1; i < 9; i++)
+ for (int j=1; j < 9; j++) {
+ m_neighbor_bits[i][j] = 0;
+
+ for (int xinc=-1; xinc<=1; xinc++)
+ for (int yinc=-1; yinc<=1; yinc++) {
+ if (xinc != 0 || yinc != 0)
+ if (i + xinc > 0 && i + xinc < 9 && j + yinc > 0 && j + yinc < 9)
+ m_neighbor_bits[i][j] |= m_coord_bit[i + xinc][j + yinc];
+ }
+ }
+}
+
+
+// Set up the board control values that will be used in evaluation of
+// the position.
+//
+
+void Engine::SetupBcBoard()
+{
+ // JAVA m_bc_board = new int[9][9];
+
+ for (int i=1; i < 9; i++)
+ for (int j=1; j < 9; j++) {
+ if (i == 2 || i == 7)
+ m_bc_board[i][j] = -1;
+ else
+ m_bc_board[i][j] = 0;
+
+ if (j == 2 || j == 7)
+ m_bc_board[i][j] -= 1;
+ }
+
+ m_bc_board[1][1] = 2;
+ m_bc_board[8][1] = 2;
+ m_bc_board[1][8] = 2;
+ m_bc_board[8][8] = 2;
+
+ m_bc_board[1][2] = -1;
+ m_bc_board[2][1] = -1;
+ m_bc_board[1][7] = -1;
+ m_bc_board[7][1] = -1;
+ m_bc_board[8][2] = -1;
+ m_bc_board[2][8] = -1;
+ m_bc_board[8][7] = -1;
+ m_bc_board[7][8] = -1;
+}
+
+
+// Calculate the board control score.
+//
+
+int Engine::CalcBcScore(Color color)
+{
+ int sum = 0;
+
+ for (int i=1; i < 9; i++)
+ for (int j=1; j < 9; j++)
+ if (m_board[i][j] == color)
+ sum += m_bc_board[i][j];
+
+ return sum;
+}
+
+
+// Calculate a bitmap of the occupied squares for a certain color.
+//
+
+ULONG64 Engine::ComputeOccupiedBits(Color color)
+{
+ ULONG64 retval = 0;
+
+ for (int i=1; i < 9; i++)
+ for (int j=1; j < 9; j++)
+ if (m_board[i][j] == color) retval |= m_coord_bit[i][j];
+
+ return retval;
+}
+
diff --git a/kreversi/Engine.h b/kreversi/Engine.h
new file mode 100644
index 00000000..a84be895
--- /dev/null
+++ b/kreversi/Engine.h
@@ -0,0 +1,245 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+// The class Engine produces moves from a Game object through calls to the
+// function ComputeMove().
+//
+// First of all: this is meant to be a simple example of a game playing
+// program. Not everything is done in the most clever way, particularly not
+// the way the moves are searched, but it is hopefully made in a way that makes
+// it easy to understand. The function ComputeMove2() that does all the work
+// is actually not much more than a hundred lines. Much could be done to
+// make the search faster though, I'm perfectly aware of that. Feel free
+// to experiment.
+//
+// The method used to generate the moves is called minimax tree search with
+// alpha-beta pruning to a fixed depth. In short this means that all possible
+// moves a predefined number of moves ahead are either searched or refuted
+// with a method called alpha-beta pruning. A more thorough explanation of
+// this method could be found at the world wide web at http:
+// //yoda.cis.temple.edu:8080/UGAIWWW/lectures96/search/minimax/alpha-beta.html
+// at the time this was written. Searching for "minimax" would also point
+// you to information on this subject. It is probably possible to understand
+// this method by reading the source code though, it is not that complicated.
+//
+// At every leaf node at the search tree, the resulting position is evaluated.
+// Two things are considered when evaluating a position: the number of pieces
+// of each color and at which squares the pieces are located. Pieces at the
+// corners are valuable and give a high value, and having pieces at squares
+// next to a corner is not very good and they give a lower value. In the
+// beginning of a game it is more important to have pieces on "good" squares,
+// but towards the end the total number of pieces of each color is given a
+// higher weight. Other things, like how many legal moves that can be made in a
+// position, and the number of pieces that can never be turned would probably
+// make the program stronger if they were considered in evaluating a position,
+// but that would make things more complicated (this was meant to be very
+// simple example) and would also slow down computation (considerably?).
+//
+// The member m_board[10][10]) holds the current position during the
+// computation. It is initiated at the start of ComputeMove() and
+// every move that is made during the search is made on this board. It should
+// be noted that 1 to 8 is used for the actual board, but 0 and 9 can be
+// used too (they are always empty). This is practical when turning pieces
+// when moves are made on the board. Every piece that is put on the board
+// or turned is saved in the stack m_squarestack (see class SquareStack) so
+// every move can easily be reversed after the search in a node is completed.
+//
+// The member m_bc_board[][] holds board control values for each square
+// and is initiated by a call to the function private void SetupBcBoard()
+// from Engines constructor. It is used in evaluation of positions except
+// when the game tree is searched all the way to the end of the game.
+//
+// The two members m_coord_bit[9][9] and m_neighbor_bits[9][9] are used to
+// speed up the tree search. This goes against the principle of keeping things
+// simple, but to understand the program you do not need to understand them
+// at all. They are there to make it possible to throw away moves where
+// the piece that is played is not adjacent to a piece of opposite color
+// at an early stage (because they could never be legal). It should be
+// pointed out that not all moves that pass this test are legal, there will
+// just be fewer moves that have to be tested in a more time consuming way.
+//
+// There are also two other members that should be mentioned: Score m_score
+// and Score m_bc_score. They hold the number of pieces of each color and
+// the sum of the board control values for each color during the search
+// (this is faster than counting at every leaf node).
+//
+
+// The classes SquareStackEntry and SquareStack implement a
+// stack that is used by Engine to store pieces that are turned during
+// searching (see ComputeMove()).
+//
+// The class MoveAndValue is used by Engine to store all possible moves
+// at the first level and the values that were calculated for them.
+// This makes it possible to select a random move among those with equal
+// or nearly equal value after the search is completed.
+
+#ifndef __ENGINE__H__
+#define __ENGINE__H__
+
+#include "SuperEngine.h"
+#include "Position.h"
+#include "Game.h"
+#include "Move.h"
+#include "Score.h"
+#include <qmemarray.h>
+#include <sys/times.h>
+#include <qbitarray.h>
+
+
+// Class ULONG64 is used as a bitmap for the squares.
+
+#if defined(__GNUC__)
+#define ULONG64 unsigned long long int
+#else
+class ULONG64 : public QBitArray {
+public:
+ ULONG64();
+ ULONG64( unsigned int );
+ void shl();
+};
+#endif
+
+
+// SquareStackEntry and SquareStack are used during search to keep
+// track of turned pieces.
+
+class SquareStackEntry
+{
+public:
+ SquareStackEntry();
+
+ void setXY(int x, int y);
+
+public:
+ int m_x;
+ int m_y;
+};
+
+
+class SquareStack
+{
+public:
+ SquareStack();
+ SquareStack(int size);
+
+ void resize(int size);
+ void init(int size);
+ SquareStackEntry Pop();
+ void Push(int x, int y);
+
+private:
+ QMemArray<SquareStackEntry> m_squarestack;
+ int m_top;
+};
+
+
+// Connect a move with its value.
+
+class MoveAndValue
+{
+public:
+ MoveAndValue();
+ MoveAndValue(int x, int y, int value);
+
+ void setXYV(int x, int y, int value);
+
+public:
+ int m_x;
+ int m_y;
+ int m_value;
+};
+
+
+// The real beef of this program: the engine that finds good moves for
+// the computer player.
+//
+class Engine : public SuperEngine {
+public:
+ Engine(int st, int sd);
+ Engine(int st);
+ Engine();
+
+ Move computeMove(Game *game, bool competitive);
+
+private:
+ Move ComputeFirstMove(Game *game);
+ int ComputeMove2(int xplay, int yplay, Color color, int level,
+ int cutoffval,
+ ULONG64 colorbits, ULONG64 opponentbits);
+
+ int TryAllMoves(Color opponent, int level, int cutoffval,
+ ULONG64 opponentbits, ULONG64 colorbits);
+
+ int EvaluatePosition(Color color);
+ void SetupBcBoard();
+ void SetupBits();
+ int CalcBcScore(Color color);
+ ULONG64 ComputeOccupiedBits(Color color);
+
+ void yield();
+
+private:
+ static const int LARGEINT;
+ static const int ILLEGAL_VALUE;
+ static const int BC_WEIGHT;
+
+ Color m_board[10][10];
+ int m_bc_board[9][9];
+ Score m_score;
+ Score m_bc_score;
+ SquareStack m_squarestack;
+
+ int m_depth;
+ int m_coeff;
+ int m_nodes_searched;
+ bool m_exhaustive;
+ bool m_competitive;
+
+ ULONG64 m_coord_bit[9][9];
+ ULONG64 m_neighbor_bits[9][9];
+};
+
+#endif
diff --git a/kreversi/Game.cpp b/kreversi/Game.cpp
new file mode 100644
index 00000000..e389fdd3
--- /dev/null
+++ b/kreversi/Game.cpp
@@ -0,0 +1,265 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+// The class Game represents a complete or incomplete Othello game. It uses
+// the classes Score and Move (and internally Position).
+// You can make moves, take back one move at a time, reset to initial position
+// and get certain data on the current position.
+
+// Public functions:
+
+// public Game()
+// Creates a game with the initial position.
+
+// public void Reset()
+// Resets to the initial position.
+
+// public boolean makeMove(Move &move)
+// Makes the move m. Returns false if the move is not legal or when called
+// with a move where the player is Score.NOBODY.
+
+// public boolean TakeBackMove()
+// Takes back a move. Returns true if not at the initial position.
+
+// public int GetSquare(int x, int y)
+// Returns the piece at (x, y). Returns Score.NOBODY if the square is not
+// occupied.
+
+// public int GetScore(int player)
+// Returns the score for player.
+
+// public Move GetLastMove()
+// Returns the last move. Returns null if at the initial position.
+
+// public boolean MoveIsLegal(Move m)
+// Checks if move m is legal.
+
+// public boolean MoveIsPossible(int player)
+// Checks if there is a legal move for player.
+
+// public boolean MoveIsAtAllPossible()
+// Checks if there are any legal moves at all.
+
+// public int GetMoveNumber()
+// Returns move number.
+
+// public int GetWhoseTurn()
+// Returns the player in turn to play (if there are no legal moves
+// Score.NOBODY is returned).
+
+// public Move[] TurnedByLastMove()
+// Returns a vector of the squares that were changed by the last move.
+// The move that was actually played is at index 0. At the initial
+// position the length of the vector returned is zero. (Could be used
+// for faster updates of a graphical board).
+
+
+#include <assert.h>
+
+#include "Game.h"
+
+
+
+Game::Game()
+{
+ newGame();
+}
+
+Game::~Game()
+{
+}
+
+
+// Start a new game and reset the position to before the first move.
+//
+
+void Game::newGame()
+{
+ m_position.setupStartPosition();
+ m_moveNumber = 0;
+}
+
+
+// Return the last move made in the game.
+//
+
+Move Game::lastMove() const
+{
+ // If no moves where made, return a NULL move.
+ if (m_moveNumber == 0)
+ return Move();
+
+ return m_moves[m_moveNumber - 1];
+}
+
+
+Move
+Game::move(uint moveNo) const
+{
+ assert(moveNo < m_moveNumber);
+
+ return m_moves[moveNo];
+}
+
+
+
+// Return true if the move is legal in the current position.
+//
+
+bool Game::moveIsLegal(SimpleMove &move) const
+{
+ return m_position.moveIsLegal(move);
+}
+
+
+// Return true if the color can make a move in the current position.
+
+bool Game::moveIsPossible(Color color) const
+{
+ return m_position.moveIsPossible(color);
+}
+
+
+// Return true if any side can make a move in the current position.
+//
+
+bool Game::moveIsAtAllPossible() const
+{
+ return m_position.moveIsAtAllPossible();
+}
+
+
+// Make a move in the game, resulting in a new position.
+//
+// If everything went well, return true. Otherwise return false and
+// do nothing.
+
+bool Game::doMove(Move &move)
+{
+ Position lastPos = m_position;
+
+ // Some sanity checks.
+ if (move.color() == Nobody)
+ return false;
+
+ if (toMove() != move.color())
+ return false;
+
+ // Make the move in the position and store it. Don't allow illegal moves.
+ if (!m_position.doMove(move))
+ return false;
+
+ m_moves[m_moveNumber++] = move;
+
+ return true;
+}
+
+
+bool Game::doMove(SimpleMove &smove)
+{
+ Move move(smove);
+
+ return doMove(move);
+}
+
+
+// Take back the last move.
+//
+// Note: The removed move is not remembered, so a redo is not possible.
+//
+
+bool Game::undoMove()
+{
+ if (m_moveNumber == 0)
+ return false;
+
+#if 0
+ m_position.setupStartPosition();
+ m_moveNumber--;
+ for (uint i = 0; i < m_moveNumber; i++)
+ m_position.doMove(m_moves[i]);
+#else
+ m_position.undoMove(m_moves[--m_moveNumber]);
+#endif
+
+ return true;
+}
+
+
+// ----------------------------------------------------------------
+// Reversi specific methods
+
+
+// Return true if the square at (x, y) was changed during the last move.
+//
+
+bool Game::squareModified(uint x, uint y) const
+{
+ // If the move number is zero, we want to redraw all squares.
+ // That's why we return true here.
+ if (m_moveNumber == 0)
+ return true;
+
+ return m_moves[m_moveNumber - 1].squareModified(x, y);
+}
+
+
+// Return true if the piece at square (x, y) was turned during the last move.
+//
+
+bool Game::wasTurned(uint x, uint y) const
+{
+ // Nothing turned before the first move.
+ if (m_moveNumber == 0)
+ return false;
+
+ Color color = m_position.color(x, y);
+
+ if (color == Nobody)
+ return false;
+
+ return m_moves[m_moveNumber - 1].wasTurned(x, y);
+}
diff --git a/kreversi/Game.h b/kreversi/Game.h
new file mode 100644
index 00000000..c33a2096
--- /dev/null
+++ b/kreversi/Game.h
@@ -0,0 +1,143 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+// The class Game represents a complete or incomplete Othello game. It uses
+// the classes Score and Move (and internally Position).
+// You can make moves, take back one move at a time, reset to initial position
+// and get certain data on the current position.
+
+// Public functions:
+
+// public Game()
+// Creates a game with the initial position.
+
+// public void Reset()
+// Resets to the initial position.
+
+// public boolean MakeMove(Move m)
+// Makes the move m. Returns false if the move is not legal or when called
+// with a move where the player is Score.NOBODY.
+
+// public boolean TakeBackMove()
+// Takes back a move. Returns true if not at the initial position.
+
+// public int GetSquare(int x, int y)
+// Returns the piece at (x, y). Returns Score.NOBODY if the square is not
+// occupied.
+
+// public int GetScore(int player)
+// Returns the score for player.
+
+// public Move GetLastMove()
+// Returns the last move. Returns null if at the initial position.
+
+// public boolean MoveIsLegal(Move m)
+// Checks if move m is legal.
+
+// public boolean MoveIsPossible(int player)
+// Checks if there is a legal move for player.
+
+// public boolean MoveIsAtAllPossible()
+// Checks if there are any legal moves at all.
+
+// public int GetMoveNumber()
+// Returns move number.
+
+// public int GetWhoseTurn()
+// Returns the player in turn to play (if there are no legal moves
+// Score.NOBODY is returned).
+
+// public Move[] TurnedByLastMove()
+// Returns a vector of the squares that were changed by the last move.
+// The move that was actually played is at index 0. At the initial
+// position the length of the vector returned is zero. (Could be used
+// for faster updates of a graphical board).
+
+
+#ifndef __GAME__H__
+#define __GAME__H__
+
+
+#include "Score.h"
+#include "Move.h"
+#include "Position.h"
+
+
+class Game {
+public:
+ Game();
+ ~Game();
+
+ void newGame();
+
+ Color color(uint x, uint y) const { return m_position.color(x, y); }
+ uint score(Color color) const { return m_position.score(color); }
+ Move lastMove() const;
+ Move move(uint moveNo) const;
+
+ bool moveIsLegal(SimpleMove &move) const;
+ bool moveIsPossible(Color color) const;
+ bool moveIsAtAllPossible() const;
+ bool doMove(Move &move);
+ bool doMove(SimpleMove &move);
+ bool undoMove();
+
+ const Position &position() const { return m_position; }
+ uint moveNumber() const { return m_moveNumber; }
+ Color toMove() const { return m_position.toMove(); }
+
+ // Reversi specific methods
+ bool squareModified(uint x, uint y) const;
+ bool wasTurned(uint x, uint y) const;
+
+protected:
+ Move m_moves[60];
+ Position m_position; // The current position in the game
+ uint m_moveNumber;
+};
+
+
+#endif
diff --git a/kreversi/Makefile.am b/kreversi/Makefile.am
new file mode 100644
index 00000000..ca13e36f
--- /dev/null
+++ b/kreversi/Makefile.am
@@ -0,0 +1,101 @@
+INCLUDES = -I$(top_srcdir)/libkdegames -I$(top_srcdir)/libkdegames/highscore $(all_includes)
+
+bin_PROGRAMS = kreversi
+
+kreversi_SOURCES = \
+ kzoommainwindow.cpp \
+ Score.cpp \
+ Move.cpp \
+ Position.cpp \
+ Game.cpp \
+ qreversigame.cpp \
+ qreversigameview.cpp \
+ SuperEngine.cpp \
+ Engine.cpp \
+ board.cpp \
+ settings.ui \
+ highscores.cpp \
+ kreversi.cpp \
+ main.cpp \
+ prefs.kcfgc
+kreversi_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kreversi_LDADD = $(LIB_KDEGAMES) $(LIB_KIO)
+kreversi_DEPENDENCIES = $(LIB_KDEGAMES_DEP)
+
+METASOURCES = AUTO
+
+rcdir = $(kde_datadir)/kreversi
+rc_DATA = kreversiui.rc
+
+noinst_HEADERS = \
+ kzoommainwindow.h \
+ Engine.h \
+ Game.h \
+ qreversigame.h \
+ qreversigameview.h \
+ kreversi.h \
+ Move.h \
+ board.h \
+ Position.h \
+ Score.h \
+ version.h \
+ SuperEngine.h \
+ highscores.h
+
+SUBDIRS = . pics sounds icons
+
+xdg_apps_DATA = kreversi.desktop
+kde_kcfg_DATA = kreversi.kcfg
+
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kreversi.pot
+
+# for system-wide highscore file
+DESTBIN = $(DESTDIR)$(bindir)/$(bin_PROGRAMS)
+DESTHIGHSCORES = $(DESTDIR)$(HIGHSCORE_DIRECTORY)
+DESTSCORES = $(DESTDIR)$(HIGHSCORE_DIRECTORY)/$(bin_PROGRAMS).scores
+
+install-data-local:
+ @if test x$(HIGHSCORE_DIRECTORY) != x; then \
+ echo "********************************************************" ;\
+ echo "" ;\
+ echo "This game is installed sgid \"games\" to use the" ;\
+ echo "system-wide highscore file (in "$(HIGHSCORE_DIRECTORY)")." ;\
+ echo "" ;\
+ echo "If the system-wide highscore file does not exist, it is" ;\
+ echo "created with the correct ownership and permissions. See the" ;\
+ echo "INSTALL file in \"kdegames/libkdegames/highscore\" for details." ;\
+ echo "" ;\
+ echo "********************************************************" ;\
+ fi
+
+install-exec-hook:
+ @if test x$(HIGHSCORE_DIRECTORY) != x; then \
+ chown $(highscore_user):$(highscore_group) $(DESTBIN) \
+ || echo "Error: Could not install the game with correct permissions !!" ;\
+ fi
+
+ @if test x$(HIGHSCORE_DIRECTORY) != x; then \
+ mkdir -p $(DESTHIGHSCORES) && \
+ chown $(highscore_user):$(highscore_group) $(DESTHIGHSCORES) \
+ && chmod 750 $(DESTHIGHSCORES) \
+ || echo "Error: Could not create the highscore directory with correct permissions !!" ;\
+ fi
+
+ @if test x$(HIGHSCORE_DIRECTORY) != x; then \
+ chown $(highscore_user):$(highscore_group) $(DESTBIN) \
+ || echo "Error: Could not install the game with correct permissions !!" ;\
+ fi
+
+ @if test ${setgid} = true; then \
+ chmod 2755 $(DESTBIN) \
+ || echo "Error: Could not install the game with correct permissions !!" ;\
+ fi
+
+ @if test x$(HIGHSCORE_DIRECTORY) != x; then \
+ touch $(DESTSCORES) && chown $(highscore_user):$(highscore_group) $(DESTSCORES) \
+ && chmod 0660 $(DESTSCORES) \
+ || echo "Error: Could not create system-wide highscore file with correct permissions !!" ;\
+ fi
+
diff --git a/kreversi/Move.cpp b/kreversi/Move.cpp
new file mode 100644
index 00000000..3a616647
--- /dev/null
+++ b/kreversi/Move.cpp
@@ -0,0 +1,118 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+#include "Move.h"
+
+
+SimpleMove::SimpleMove(Color color, int x, int y)
+{
+ m_color = color;
+ m_x = x;
+ m_y = y;
+}
+
+
+SimpleMove::SimpleMove(const SimpleMove &move)
+{
+ *this = move;
+}
+
+
+QString SimpleMove::asString() const
+{
+ if (m_x == -1)
+ return QString("pass");
+ else
+ return QString("%1%2").arg(" ABCDEFGH"[m_x]).arg(" 12345678"[m_y]);
+}
+
+
+// ================================================================
+
+
+Move::Move()
+ : SimpleMove()
+{
+ m_turnedPieces.clear();
+}
+
+
+Move::Move(Color color, int x, int y)
+ : SimpleMove(color, x, y)
+{
+ m_turnedPieces.clear();
+}
+
+
+Move::Move(const Move &move)
+ : SimpleMove((SimpleMove&) move)
+{
+ m_turnedPieces.clear();
+}
+
+
+Move::Move(const SimpleMove &move)
+ : SimpleMove(move)
+{
+ m_turnedPieces.clear();
+}
+
+
+// ----------------------------------------------------------------
+
+
+bool Move::squareModified(uint x, uint y) const
+{
+ return (m_x == (int) x && m_y == (int) y) || wasTurned(x, y);
+}
+
+
+bool Move::wasTurned(uint x, uint y) const
+{
+ // findIndex returns the first index where the item is found, or -1
+ // if not found.
+ return (m_turnedPieces.findIndex(10 * x + y) != -1);
+}
diff --git a/kreversi/Move.h b/kreversi/Move.h
new file mode 100644
index 00000000..e205f279
--- /dev/null
+++ b/kreversi/Move.h
@@ -0,0 +1,124 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+// This file defines the two classes SimpleMove and Move.
+//
+// The class Move is used to represent an Othello move with a player value
+// (see class Score) and a pair of coordinates on an 8x8 Othello board.
+// Each coordinate can have values between 1 and 8, inclusive.
+//
+// The difference between a Move and a SimpleMove is that a SimpleMove
+// can be done (performed) in a Position, but a Move can be both done
+// and undone. In addition to the info in SimpleMove, the class Move
+// stores information that is used in undoing the move and visualizing
+// it.
+//
+// The reason for the class SimpleMove is that it saves memory. The
+// class Game stores an array of Moves, since the BoardView needs
+// information about which pieces were turned by the move.
+//
+
+
+#ifndef __MOVE__H__
+#define __MOVE__H__
+
+
+#include "qvaluelist.h"
+#include "qstring.h"
+
+#include "Score.h"
+
+
+class Position;
+
+
+class SimpleMove
+{
+public:
+ SimpleMove() { m_color = Nobody; m_x = -1; m_y = -1; }
+ SimpleMove(Color color, int x, int y);
+ SimpleMove(const SimpleMove &move);
+
+ //Move &operator=(Move &move);
+
+ Color color() const { return m_color; }
+ int x() const { return m_x; }
+ int y() const { return m_y; }
+
+ QString asString() const;
+
+protected:
+ Color m_color;
+ int m_x;
+ int m_y;
+};
+
+
+// Note: This class is not memory optimized. The list of turned
+// pieces can surely be made much smaller.
+
+class Move : public SimpleMove
+{
+ friend class Position;
+
+public:
+ Move();
+ Move(Color color, int x, int y);
+ Move(const Move &move);
+ Move(const SimpleMove &move);
+
+ bool squareModified(uint x, uint y) const;
+ bool wasTurned(uint x, uint y) const;
+
+private:
+ QValueList<char> m_turnedPieces;
+};
+
+
+typedef QValueList<Move> MoveList;
+
+
+#endif
diff --git a/kreversi/NEWS b/kreversi/NEWS
new file mode 100644
index 00000000..8e815ffa
--- /dev/null
+++ b/kreversi/NEWS
@@ -0,0 +1,20 @@
+v0.1pl168: Initial release
+
+06/14/97 released version 0.1.2
+
+06/16/97 released version 0.2
+
+06/25/97 released version 0.2.1
+
+07/30/97 released version 0.3
+
+???????? released version 0.4 (unware about date)
+
+07/10/97 released version 0.5
+
+10/09/97 released 0.6
+
+10/12/97 released 0.6.1 (bugfix release)
+
+see ChangeLog for details
+
diff --git a/kreversi/Position.cpp b/kreversi/Position.cpp
new file mode 100644
index 00000000..22ffb3cf
--- /dev/null
+++ b/kreversi/Position.cpp
@@ -0,0 +1,366 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+// The class Position is used to represent an Othello position as white and
+// black pieces and empty squares (see class Score) on an 8x8 Othello board.
+
+
+#include "kdebug.h"
+
+#include "Position.h"
+#include <stdlib.h>
+
+
+Position::Position()
+{
+ setupStartPosition();
+}
+
+
+Position::Position(Position &pos, SimpleMove &move)
+{
+ constrCopy(pos, move);
+}
+
+
+Position &Position::operator=(Position &pos)
+{
+ // Copy the position itself.
+ for (uint row = 0; row < 10; row++)
+ for (uint col = 0; col < 10; col++)
+ m_board[row][col] = pos.m_board[row][col];
+ m_toMove = pos.m_toMove;
+
+ m_score = pos.m_score;
+
+ return *this;
+}
+
+
+// ----------------------------------------------------------------
+// Helpers to the constructors
+
+
+// Construct a Position by copying another one and then make a move.
+//
+
+void Position::constrCopy(Position &pos, SimpleMove &move)
+{
+ *this = pos;
+ doMove(move);
+}
+
+
+// Setup the Position by setting it to the initial Reversi position.
+
+void Position::setupStartPosition()
+{
+ // Initialize the real board
+ for (uint i = 0; i < 10; i++)
+ for (uint j = 0; j < 10; j++)
+ m_board[i][j] = Nobody;
+
+ // The initial position
+ m_board[4][4] = White;
+ m_board[5][5] = White;
+ m_board[5][4] = Black;
+ m_board[4][5] = Black;
+
+ // Black always starts the game in Reversi.
+ m_toMove = Black;
+
+ // Each side starts out with two pieces.
+ m_score.set(White, 2);
+ m_score.set(Black, 2);
+}
+
+
+// ----------------------------------------------------------------
+// Access methods
+
+
+Color Position::color(uint x, uint y) const
+{
+ if (x < 1 || x > 8 || y < 1 || y > 8)
+ return Nobody;
+
+ return m_board[x][y];
+}
+
+
+// ----------------------------------------------------------------
+// Moves in the position
+
+
+// Return true if the move is legal.
+//
+// NOTE: This function does *NOT* test wether the move is done
+// by the color to move. That must be checked separately.
+//
+
+bool Position::moveIsLegal(SimpleMove &move) const
+{
+ if (m_board[move.x()][move.y()] != Nobody)
+ return false;
+
+ Color color = move.color();
+ Color opponent = ::opponent(color);
+
+ // Check in all directions and see if there is a turnable row of
+ // opponent pieces. If there is at least one such row, then the
+ // move is legal.
+ for (int xinc = -1; xinc <= 1; xinc++) {
+ for (int yinc = -1; yinc <= 1; yinc++) {
+ int x, y;
+
+ if (xinc == 0 && yinc == 0)
+ continue;
+
+ // Find the end of such a row of pieces.
+ for (x = move.x()+xinc, y = move.y()+yinc; m_board[x][y] == opponent;
+ x += xinc, y += yinc)
+ ;
+
+ // If the row ends with a piece of our own and there was at
+ // least one opponent piece between it and the move point, then
+ // we have found a turnable row.
+ if (m_board[x][y] == color
+ && (x - xinc != move.x() || y - yinc != move.y()))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+// See if 'color' can make a move in the current position. This is
+// independent of wether it is 'color's turn to move or not.
+
+bool Position::moveIsPossible(Color color) const
+{
+ // Make it simple: Step through all squares and see if it is a legal move.
+ for (uint i = 1; i < 9; i++)
+ for (uint j = 1; j < 9; j++) {
+ SimpleMove move(color, i, j);
+
+ if (moveIsLegal(move))
+ return true;
+ }
+
+ return false;
+}
+
+
+// Return true if any side can move. (If not, the game is over.)
+
+bool Position::moveIsAtAllPossible() const
+{
+ return (moveIsPossible(White) || moveIsPossible(Black));
+}
+
+
+// Make a move in the position.
+//
+// Return true if the move was legal, otherwise return false.
+//
+bool Position::doMove(SimpleMove &move, QValueList<char> *turned)
+{
+ if (move.color() == Nobody)
+ return false;
+
+ Color color = move.color();
+ Color opponent = ::opponent(color);
+
+ // Put the piece on the board
+ m_board[move.x()][move.y()] = color;
+ m_score.inc(color);
+
+ // Turn pieces.
+ uint scoreBefore = m_score.score(color);
+ for (int xinc = -1; xinc <= 1; xinc++) {
+ for (int yinc = -1; yinc <= 1; yinc++) {
+ int x, y;
+
+ // Skip the case where both xinc and yinc == 0, since then we
+ // won't move in any direction at all.
+ if (xinc == 0 && yinc == 0)
+ continue;
+
+ // Find the end point (x, y) of a possible row of turnable pieces.
+ for (x = move.x()+xinc, y = move.y()+yinc; m_board[x][y] == opponent;
+ x += xinc, y += yinc)
+ ;
+
+ // If the row was indeed turnable, then do it.
+ if (m_board[x][y] == color) {
+ for (x -= xinc, y -= yinc; x != move.x() || y != move.y();
+ x -= xinc, y -= yinc) {
+ // Turn the piece.
+ m_board[x][y] = color;
+ if (turned)
+ turned->append(10 * x + y);
+
+ // Make the piece count correct again.
+ m_score.inc(color);
+ m_score.dec(opponent);
+ }
+ }
+ }
+ }
+
+ // If nothing was turned, the move wasn't legal.
+ if (m_score.score(color) == scoreBefore) {
+ m_board[move.x()][move.y()] = Nobody;
+ m_score.dec(color);
+
+ return false;
+ }
+
+ // Set the next color to move.
+ if (moveIsPossible(opponent))
+ m_toMove = opponent;
+ else if (moveIsPossible(color))
+ m_toMove = color;
+ else
+ m_toMove = Nobody;
+
+ return true;
+}
+
+
+bool Position::doMove(Move &move)
+{
+ move.m_turnedPieces.clear();
+ return doMove((SimpleMove &) move, &move.m_turnedPieces);
+}
+
+
+bool Position::undoMove(Move &move)
+{
+ Color color = move.color();
+ Color other = opponent(color);
+
+ // Sanity checks
+ // 1. The move must be on the board and be of the right color.
+ if (color != m_board[move.x()][move.y()]) {
+ //kdDebug() << "move on the board is wrong color: " << (int) color << "["
+ // << move.x() << "," << move.y() << "]" << endl;
+ return false;
+ }
+
+ // 2. All turned pieces must be on the board anb be of the right color.
+ QValueList<char>::iterator it;
+ for (it = move.m_turnedPieces.begin();
+ it != move.m_turnedPieces.end();
+ ++it) {
+ int sq = *it;
+
+ if (m_board[sq / 10][sq % 10] != color) {
+ //kdDebug() << "turned piece the board is wrong color: ["
+ // << sq / 10 << "," << sq % 10 << "]" << endl;
+ return false;
+ }
+ }
+
+ // Ok, everything seems allright. Let's do it!
+ // 1. Unturn all the turned pieces.
+ for (it = move.m_turnedPieces.begin();
+ it != move.m_turnedPieces.end();
+ ++it) {
+ int sq = *it;
+
+ m_board[sq / 10][sq % 10] = other;
+ m_score.dec(color);
+ m_score.inc(other);
+ }
+
+ // 2. Remove the move itself.
+ m_score.dec(color);
+ m_board[move.x()][move.y()] = Nobody;
+
+
+ return true;
+}
+
+
+MoveList Position::generateMoves(Color color) const
+{
+ MoveList moves;
+
+ // Make it simple: Step through all squares and see if it is a legal move.
+ for (uint i = 1; i < 9; i++) {
+ for (uint j = 1; j < 9; j++) {
+ Move move(color, i, j);
+
+ if (moveIsLegal(move))
+ moves.append(move);
+ }
+ }
+
+ return moves;
+}
+
+
+QString Position::asString() const
+{
+ QString result;
+
+ for (uint y = 1; y < 9; ++y) {
+ for (uint x = 1; x < 9; ++x) {
+ switch (m_board[x][y]) {
+ case Nobody: result.append(' '); break;
+ case Black: result.append('*'); break;
+ case White: result.append('o'); break;
+ default: result.append('?'); break;
+ }
+ }
+
+ result.append('\n');
+ }
+
+ return result;
+}
diff --git a/kreversi/Position.h b/kreversi/Position.h
new file mode 100644
index 00000000..7269c2e6
--- /dev/null
+++ b/kreversi/Position.h
@@ -0,0 +1,98 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+// The class Position is used to represent an Othello position as white and
+// black pieces and empty squares (see class Score) on an 8x8 Othello board.
+
+#ifndef __POSITION__H__
+#define __POSITION__H__
+
+
+#include "Move.h"
+#include "Score.h"
+
+
+class Position
+{
+public:
+ Position();
+ Position(Position &pos, SimpleMove &move);
+ Position(Position &pos, Move &move);
+
+ Position &operator=(Position &pos);
+
+ void constrCopy(Position &pos, SimpleMove &move);
+
+ void setupStartPosition();
+
+ // Access methods
+ Color toMove() const { return m_toMove; }
+ Color color(uint x, uint y) const;
+ uint score(Color color) const { return m_score.score(color); }
+
+ // Moves in the current position.
+ bool moveIsPossible(Color color) const;
+ bool moveIsAtAllPossible() const;
+ bool moveIsLegal(SimpleMove &move) const;
+ bool doMove(SimpleMove &move, QValueList<char> *turned = 0);
+ bool doMove(Move &move);
+ bool undoMove(Move &move);
+
+ MoveList generateMoves(Color color) const;
+
+ QString asString() const;
+
+private:
+ // The actual position itself. Use the simplest representation possible.
+ Color m_board[10][10];
+ Color m_toMove;
+
+ // Some extra data
+ Score m_score; // The number of pieces for each side.
+};
+
+
+#endif
diff --git a/kreversi/Score.cpp b/kreversi/Score.cpp
new file mode 100644
index 00000000..f508152b
--- /dev/null
+++ b/kreversi/Score.cpp
@@ -0,0 +1,70 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+
+#include "Score.h"
+
+
+Score::Score()
+{
+ m_score[White] = 0;
+ m_score[Black] = 0;
+}
+
+
+/* Return the opponent color for 'color'.
+ */
+
+Color opponent(Color color)
+{
+ switch (color) {
+ case White: return Black;
+ case Black: return White;
+ case Nobody: break;
+ }
+
+ return Nobody;
+}
diff --git a/kreversi/Score.h b/kreversi/Score.h
new file mode 100644
index 00000000..947272dc
--- /dev/null
+++ b/kreversi/Score.h
@@ -0,0 +1,78 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+#ifndef __SCORE__H__
+#define __SCORE__H__
+
+#include <qglobal.h>
+
+enum Color { White = 0, Black = 1, NbColors = 2, Nobody = NbColors };
+
+Color opponent(Color color);
+
+
+/* This class keeps track of the score for both colors. Such a score
+ * could be either the number of pieces, the score from the evaluation
+ * function or anything similar.
+ */
+
+class Score {
+public:
+ Score();
+
+ uint score(Color color) const { return m_score[color]; }
+
+ void set(Color color, uint score) { m_score[color] = score; }
+ void inc(Color color) { m_score[color]++; }
+ void dec(Color color) { m_score[color]--; }
+ void add(Color color, uint s) { m_score[color] += s; }
+ void sub(Color color, uint s) { m_score[color] -= s; }
+
+private:
+ uint m_score[NbColors];
+};
+
+#endif
diff --git a/kreversi/SuperEngine.cpp b/kreversi/SuperEngine.cpp
new file mode 100644
index 00000000..3da7326f
--- /dev/null
+++ b/kreversi/SuperEngine.cpp
@@ -0,0 +1,133 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+// The class SuperEngine is a super class for engines that produce moves.
+// It implements functionality that move engines have in common, which is
+// useful if you want to use several different engines in the same program
+// (for instance when you are test playing different strategies against each
+// other).
+//
+// SuperEngine implements:
+//
+// Random number handling (engines should not play exactly the same games
+// repeatedly).
+//
+// Setting playing strength level.
+//
+// Functionality for telling the engine to interrupt calculation.
+//
+
+// Public and protected functions:
+
+// public SuperEngine(int st)
+// Creates an engine playing at level st. All integers greater than 0
+// should be possible levels. There need not be any actual difference in
+// playing strength between levels, but if there is, higher number should
+// mean greater playing strength.
+
+// public SuperEngine(int st, int sd)
+// The same as above, but uses sd as the seed for the random generator.
+// This means that the engine always behaves in exactly the same way
+// (practical when testing).
+
+// public synchronized final void SetInterrupt(boolean intr)
+// This function could be called when ComputeMove() (see below) is
+// executing. It tells the engine to interrupt calculation as
+// soon as possible and return null from ComputeMove().
+
+// protected synchronized final boolean GetInterrupt()
+// Returns true when SetInterrupt() has been called. Should be called
+// with short intervals from ComputeMove().
+
+// public void SetStrength(int st)
+// Sets playing strength level.
+
+// public int GetStrength()
+// Gets playing strength level.
+
+// public void SetSeed(int sd)
+// Changes the random seed.
+
+// public abstract Move ComputeMove(Game g)
+// This function should produce a move. If SetInterrupt() is called
+// during its execution it should return null as soon as possible.
+
+// Protected members:
+
+// protected int m_strength
+// Is set and read by SetStrength() and GetStrength().
+
+// protected Random m_random
+// Could (and should in a good engine) be used to prevent the engine from
+// repeating itself, always playing the same moves in the same positions.
+// If this is not done, winning once would make it possible to play the
+// same moves and win every time against the program.
+
+
+#include "SuperEngine.h"
+
+
+SuperEngine::SuperEngine(int st)
+{
+ m_strength = st;
+ m_random.setSeed(0);
+ m_interrupt = false;
+}
+
+
+SuperEngine::SuperEngine(int st, int sd)
+{
+ m_strength = st;
+ m_random.setSeed(sd);
+ m_interrupt = false;
+}
+
+
+void SuperEngine::setSeed(int sd)
+{
+ m_random.setSeed(sd);
+}
+
diff --git a/kreversi/SuperEngine.h b/kreversi/SuperEngine.h
new file mode 100644
index 00000000..d3faf6a9
--- /dev/null
+++ b/kreversi/SuperEngine.h
@@ -0,0 +1,142 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * Created 1997 by Mario Weilguni <[email protected]>. This file
+ * is ported from Mats Luthman's <[email protected]> JAVA applet.
+ * Many thanks to Mr. Luthman who has allowed me to put this port
+ * under the GNU GPL. Without his wonderful game engine kreversi
+ * would be just another of those Reversi programs a five year old
+ * child could beat easily. But with it it's a worthy opponent!
+ *
+ * If you are interested on the JAVA applet of Mr. Luthman take a
+ * look at http://www.sylog.se/~mats/
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+// The class SuperEngine is a super class for engines that produce moves.
+// It implements functionality that move engines have in common, which is
+// useful if you want to use several different engines in the same program
+// (for instance when you are test playing different strategies against each
+// other).
+//
+// SuperEngine implements:
+//
+// Random number handling (engines should not play exactly the same games
+// repeatedly).
+//
+// Setting playing strength level.
+//
+// Functionality for telling the engine to interrupt calculation.
+//
+
+// Public and protected functions:
+
+// public SuperEngine(int st)
+// Creates an engine playing at level st. All integers greater than 0
+// should be possible levels. There need not be any actual difference in
+// playing strength between levels, but if there is, higher number should
+// mean greater playing strength.
+
+// public SuperEngine(int st, int sd)
+// The same as above, but uses sd as the seed for the random generator.
+// This means that the engine always behaves in exactly the same way
+// (practical when testing).
+
+// public synchronized final void SetInterrupt(boolean intr)
+// This function could be called when ComputeMove() (see below) is
+// executing. It tells the engine to interrupt calculation as
+// soon as possible and return null from ComputeMove().
+
+// protected synchronized final boolean GetInterrupt()
+// Returns true when SetInterrupt() has been called. Should be called
+// with short intervals from ComputeMove().
+
+// public void SetStrength(int st)
+// Sets playing strength level.
+
+// public int GetStrength()
+// Gets playing strength level.
+
+// public void SetSeed(int sd)
+// Changes the random seed.
+
+// public abstract Move ComputeMove(Game g)
+// This function should produce a move. If SetInterrupt() is called
+// during its execution it should return null as soon as possible.
+
+// Protected members:
+
+// protected int m_strength
+// Is set and read by SetStrength() and GetStrength().
+
+// protected Random m_random
+// Could (and should in a good engine) be used to prevent the engine from
+// repeating itself, always playing the same moves in the same positions.
+// If this is not done, winning once would make it possible to play the
+// same moves and win every time against the program.
+
+#ifndef __SUPERENGINE__H__
+#define __SUPERENGINE__H__
+
+#include "Game.h"
+
+#include <krandomsequence.h>
+
+class SuperEngine {
+public:
+ SuperEngine(int st);
+ SuperEngine(int st, int sd);
+ virtual ~SuperEngine() {}
+
+ void setInterrupt(bool intr) { m_interrupt = intr; }
+ bool interrupted() const { return m_interrupt; }
+
+ enum Strength { MinStrength = 1, MaxStrength = 7,
+ NbStrengths = MaxStrength };
+ void setStrength(uint st) { m_strength = st; }
+ uint strength() const { return m_strength; }
+
+ void setSeed(int sd);
+
+ virtual Move computeMove(Game *game, bool competitive) = 0;
+
+protected:
+ uint m_strength;
+ KRandomSequence m_random;
+
+private:
+ bool m_interrupt;
+};
+
+#endif
diff --git a/kreversi/TODO b/kreversi/TODO
new file mode 100644
index 00000000..4e81f5d1
--- /dev/null
+++ b/kreversi/TODO
@@ -0,0 +1,87 @@
+TODO-list for KREVERSI
+======================
+
+Next
+----
+
+*
+
+
+================================================================
+
+
+* Implement the plans in DESIGN
+ + Implement the QReversiGameView class DONE
+ - Move board view to it done
+ - Move movelist to it done
+ - Move status widgets to it done
+ + Move all showing of legal moves into the BoardView class DONE
+ + Implement the QEngineView class ----
+
+* More cleaning / refactoring
+ + class KReversi is still a bit of a mess. Separate it more DONE
+
+* Enhancements to the view
+ + Letters A-H and figures 1-8 on the board view. DONE
+
+ + Show possible moves in the current position DONE
+ - Actually show them on the board done
+ - Create a toggle action to toggle it on/off done
+ - Make an icon for the toggle action --
+ - Bug: legal moves don't get updated if one side has to pass done
+ - Bug: legal moves don't work together with hint. done
+ + Show moves made during the game DONE
+
+ + Navigate in the list of moves ----
+
+ + Wish 102813: Should be able to show last move DONE
+ - Make an icon for the toggle action --
+ - Bug: When turned on, should show last move immediately done
+ - Bug: When turned off, should unshow last move immediately done
+
+ + Save settings of toggleactions in config file. ----
+
+* Convert KReversi to use KGame / KPlayer
+ I. Convert KReversi to a proper Model/View program.
+ 1. Fix a ReversiGame (formerly known as Game) DONE
+ - Clean it up. (Only store the moves).
+ - Add a few necessary methods.
+ 2. Move all the slots for KActions to kreversi.cpp DONE
+ 3. Move the ownership of the engine and the game to kreversi. DONE
+ 4. Create a new class QReversiGame, that inherits ReversiGame DONE
+ and sends a lot of signals.
+ - Split out a lot of methods from the current class Board. done
+ 5. Create QReversiBoardView from the rest of the current Board DONE
+ - Clean it done
+
+ II. Introduce a class ReversiPlayer
+
+ III. Convert everything to KGame
+ 1. Let KReversiGame inherit from KGame
+ 2. Let ReversiPlayer inherit from KPlayer.
+
+ IV. ...
+
+ V. Profit!
+
+
+
+
+Old TODO items, partially done/not done
+=======================================
+
+* undo/redo
+ undo works, but I'll probably do not make a redo function
+
+* Sound support:
+ I'm not happy with
+ the sound files I have so if
+ you have better sounds, mail them to me
+ (uuencoded). I need sounds for the following actions:
+ - game won
+ - game lost
+ - game drawn
+ - turning a piece
+ - putting a piece
+ - something for the hall of fame (trumpets???)
+
diff --git a/kreversi/board.cpp b/kreversi/board.cpp
new file mode 100644
index 00000000..9d367a38
--- /dev/null
+++ b/kreversi/board.cpp
@@ -0,0 +1,576 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * created 1997 by Mario Weilguni <[email protected]>
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+
+#include <unistd.h>
+
+#include <qpainter.h>
+#include <qfont.h>
+
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+#include <knotifyclient.h>
+#include <klocale.h>
+#include <kexthighscore.h>
+#include <kdebug.h>
+
+#include "board.h"
+#include "prefs.h"
+#include "Engine.h"
+#include "qreversigame.h"
+
+
+#ifndef PICDATA
+#define PICDATA(x) KGlobal::dirs()->findResource("appdata", QString("pics/")+ x)
+#endif
+
+const uint HINT_BLINKRATE = 250000;
+const uint ANIMATION_DELAY = 3000;
+const uint CHIP_OFFSET[NbColors] = { 24, 1 };
+const uint CHIP_SIZE = 36;
+
+#define OFFSET() (zoomedSize() * 3 / 4)
+
+
+// ================================================================
+// class KReversiBoardView
+
+
+QReversiBoardView::QReversiBoardView(QWidget *parent, QReversiGame *krgame)
+ : QWidget(parent, "board"),
+ chiptype(Unloaded)
+{
+ m_krgame = krgame;
+
+ m_marksShowing = true;
+ m_legalMovesShowing = false;
+ m_legalMoves.clear();
+
+ m_showLastMove = false;
+ m_lastMoveShown = SimpleMove();
+}
+
+
+QReversiBoardView::~QReversiBoardView()
+{
+}
+
+
+// ----------------------------------------------------------------
+
+
+// Start it all up.
+//
+
+void QReversiBoardView::start()
+{
+ updateBoard(true);
+ adjustSize();
+}
+
+
+void QReversiBoardView::loadChips(ChipType type)
+{
+ QString name("pics/");
+ name += (type==Colored ? "chips.png" : "chips_mono.png");
+
+ QString s = KGlobal::dirs()->findResource("appdata", name);
+ bool ok = allchips.load(s);
+
+ Q_ASSERT( ok && allchips.width()==CHIP_SIZE*5
+ && allchips.height()==CHIP_SIZE*5 );
+ chiptype = type;
+ update();
+}
+
+
+// Negative speed is allowed. If speed is negative,
+// no animations are displayed.
+//
+
+void QReversiBoardView::setAnimationSpeed(uint speed)
+{
+ if (speed <= 10)
+ anim_speed = speed;
+}
+
+
+// Handle mouse clicks.
+//
+
+void QReversiBoardView::mousePressEvent(QMouseEvent *e)
+{
+ // Only handle left button. No context menu.
+ if ( e->button() != LeftButton ) {
+ e->ignore();
+ return;
+ }
+
+ int offset = m_marksShowing ? OFFSET() : 0;
+ int px = e->pos().x()- 1 - offset;
+ int py = e->pos().y()- 1 - offset;
+
+ if (px < 0 || px >= 8 * (int) zoomedSize()
+ || py < 0 || py >= 8 * (int) zoomedSize()) {
+ e->ignore();
+ return;
+ }
+
+ emit signalSquareClicked(py / zoomedSize(), px / zoomedSize());
+}
+
+
+void QReversiBoardView::showHint(Move move)
+{
+ // Only show a hint if there is a move to show.
+ if (move.x() == -1)
+ return;
+
+ // Blink with a piece at the location where the hint move points.
+ //
+ // The isVisible condition has been added so that when the player
+ // was viewing a hint and quits the game window, the game doesn't
+ // still have to do all this looping and directly ends.
+ QPainter p(this);
+ p.setPen(black);
+ m_hintShowing = true;
+ for (int flash = 0;
+ flash < 100 && m_hintShowing && isVisible();
+ flash++)
+ {
+ if (flash & 1) {
+ // FIXME: Draw small circle if showLegalMoves is turned on.
+ drawPiece(move.y() - 1, move.x() - 1, Nobody);
+ if (m_legalMovesShowing)
+ drawSmallCircle(move.x(), move.y(), p);
+ }
+ else
+ drawPiece(move.y() - 1, move.x() - 1, m_krgame->toMove());
+
+ // keep GUI alive while waiting
+ for (int dummy = 0; dummy < 5; dummy++) {
+ usleep(HINT_BLINKRATE / 5);
+ qApp->processEvents();
+ }
+ }
+ m_hintShowing = false;
+
+ // Draw the empty square again.
+ drawPiece(move.y() - 1, move.x() - 1, m_krgame->color(move.x(), move.y()));
+ if (m_legalMovesShowing)
+ drawSmallCircle(move.x(), move.y(), p);
+}
+
+
+// Set the member m_hintShowing to false. This will make showHint()
+// end, if it is running.
+//
+
+void QReversiBoardView::quitHint()
+{
+ m_hintShowing = false;
+}
+
+
+void QReversiBoardView::setShowLegalMoves(bool show)
+{
+ m_legalMovesShowing = show;
+ updateBoard(true);
+}
+
+void QReversiBoardView::setShowMarks(bool show)
+{
+ m_marksShowing = show;
+ updateBoard(true);
+}
+
+
+void QReversiBoardView::setShowLastMove(bool show)
+{
+ m_showLastMove = show;
+ updateBoard(true);
+}
+
+
+// ================================================================
+// Functions related to drawing/painting
+
+
+// Flash all pieces which are turned.
+//
+// NOTE: This code is quite a hack. Should make it better.
+//
+
+void QReversiBoardView::animateChanged(Move move)
+{
+ if (anim_speed == 0)
+ return;
+
+ // Draw the new piece.
+ drawPiece(move.y() - 1, move.x() - 1, move.color());
+
+ // Animate row by row in all directions.
+ for (int dx = -1; dx < 2; dx++)
+ for (int dy = -1; dy < 2; dy++)
+ if ((dx != 0) || (dy != 0))
+ animateChangedRow(move.y() - 1, move.x() - 1, dy, dx);
+}
+
+
+bool QReversiBoardView::isField(int row, int col) const
+{
+ return ((0 <= row) && (row < 8) && (0 <= col) && (col < 8));
+}
+
+
+void QReversiBoardView::animateChangedRow(int row, int col, int dy, int dx)
+{
+ row = row + dy;
+ col = col + dx;
+ while (isField(row, col)) {
+ if (m_krgame->wasTurned(col+1, row+1)) {
+ KNotifyClient::event(winId(), "click", i18n("Click"));
+ rotateChip(row, col);
+ } else
+ return;
+
+ col += dx;
+ row += dy;
+ }
+}
+
+
+void QReversiBoardView::rotateChip(uint row, uint 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.
+ Color color = m_krgame->color(col+1, row+1);
+ uint from = CHIP_OFFSET[opponent(color)];
+ uint end = CHIP_OFFSET[color];
+ int delta = (color==White ? 1 : -1);
+
+ from += delta;
+ end -= delta;
+
+ for (uint i = from; i != end; i += delta) {
+ drawOnePiece(row, col, i);
+ kapp->flushX(); // FIXME: use QCanvas to avoid flicker...
+ usleep(ANIMATION_DELAY * anim_speed);
+ }
+}
+
+
+// Redraw the board. If 'force' is true, redraw everything, otherwise
+// only redraw those squares that have changed (marked by
+// m_krgame->squareModified(col, row)).
+//
+
+void QReversiBoardView::updateBoard (bool force)
+{
+ QPainter p(this);
+ p.setPen(black);
+
+ // If we are showing legal moves, we have to erase the old ones
+ // before we can show the new ones. The easiest way to do that is
+ // to repaint everything.
+ //
+ // FIXME: A better way, perhaps, is to do the repainting in
+ // drawPiece (which should be renamed drawSquare).
+ if (m_legalMovesShowing)
+ force = true;
+
+ // Draw the squares of the board.
+ for (uint row = 0; row < 8; row++)
+ for (uint col = 0; col < 8; col++)
+ if ( force || m_krgame->squareModified(col + 1, row + 1) ) {
+ Color color = m_krgame->color(col + 1, row + 1);
+ drawPiece(row, col, color);
+ }
+
+ // Draw a border around the board.
+ int offset = m_marksShowing ? OFFSET() : 0;
+ p.drawRect(0 + offset, 0 + offset,
+ 8 * zoomedSize() + 2, 8 * zoomedSize() + 2);
+
+ // Draw letters and numbers if appropriate.
+ if (m_marksShowing) {
+ QFont font("Sans Serif", zoomedSize() / 2 - 6);
+ font.setWeight(QFont::DemiBold);
+ QFontMetrics metrics(font);
+
+ p.setFont(font);
+ uint charHeight = metrics.ascent();
+ for (uint i = 0; i < 8; i++) {
+ QChar letter = "ABCDEFGH"[i];
+ QChar number = "12345678"[i];
+ uint charWidth = metrics.charWidth("ABCDEFGH", i);
+
+ // The horizontal letters
+ p.drawText(offset + i * zoomedSize() + (zoomedSize() - charWidth) / 2,
+ offset - charHeight / 2 + 2,
+ QString(letter));
+ p.drawText(offset + i * zoomedSize() + (zoomedSize() - charWidth) / 2,
+ offset + 8 * zoomedSize() + offset - charHeight / 2 + 2,
+ QString(letter));
+
+ // The vertical numbers
+ p.drawText((offset - charWidth) / 2 + 2,
+ offset + (i + 1) * zoomedSize() - charHeight / 2 + 2,
+ QString(number));
+ p.drawText(offset + 8 * zoomedSize() + (offset - charWidth) / 2 + 2,
+ offset + (i + 1) * zoomedSize() - charHeight / 2 + 2,
+ QString(number));
+ }
+ }
+
+ // Show legal moves.
+ if (m_legalMovesShowing)
+ showLegalMoves();
+
+ // Show last move
+ int ellipseSize = zoomedSize() / 3;
+ SimpleMove lastMove = m_krgame->lastMove();
+ if (m_showLastMove && lastMove.x() != -1) {
+ // Remove the last shown last move.
+ int col = m_lastMoveShown.x();
+ int row = m_lastMoveShown.y();
+ if (col != -1 && row != -1) {
+ if (lastMove.x() != col || lastMove.y() != row) {
+ //kdDebug() << "Redrawing piece at [" << col << "," << row
+ // << "] with color " << m_krgame->color(col, row)
+ // << endl;
+ drawPiece(row - 1, col - 1, m_krgame->color(col, row));
+ }
+ }
+
+ p.setPen(yellow);
+ p.setBackgroundColor(yellow);
+ p.setBrush(SolidPattern);
+
+ //kdDebug() << "Marking last move at ["
+ // << lastMove.x() << "," << lastMove.y() << "]"
+ // << endl;
+ int px = offset + (lastMove.x() - 1) * zoomedSize() + zoomedSize() / 2;
+ int py = offset + (lastMove.y() - 1) * zoomedSize() + zoomedSize() / 2;
+ p.drawEllipse(px - ellipseSize / 2 + 1, py - ellipseSize / 2 + 1,
+ ellipseSize - 1, ellipseSize - 1);
+
+ m_lastMoveShown = lastMove;
+
+ p.setPen(black);
+ p.setBackgroundColor(black);
+ p.setBrush(NoBrush);
+ }
+}
+
+
+// Show legal moves on the board.
+
+void QReversiBoardView::showLegalMoves()
+{
+ QPainter p(this);
+ p.setPen(black);
+
+ // Get the legal moves in the current position.
+ Color toMove = m_krgame->toMove();
+ MoveList moves = m_krgame->position().generateMoves(toMove);
+
+ // Show the moves on the board.
+ MoveList::iterator it;
+ for (it = moves.begin(); it != moves.end(); ++it)
+ drawSmallCircle((*it).x(), (*it).y(), p);
+}
+
+
+void QReversiBoardView::drawSmallCircle(int x, int y, QPainter &p)
+{
+ int offset = m_marksShowing ? OFFSET() : 0;
+ int ellipseSize = zoomedSize() / 3;
+
+ int px = offset + (x - 1) * zoomedSize() + zoomedSize() / 2;
+ int py = offset + (y - 1) * zoomedSize() + zoomedSize() / 2;
+
+ p.drawEllipse(px - ellipseSize / 2, py - ellipseSize / 2,
+ ellipseSize, ellipseSize);
+}
+
+
+
+QPixmap QReversiBoardView::chipPixmap(Color color, uint size) const
+{
+ return chipPixmap(CHIP_OFFSET[color], size);
+}
+
+
+// Get a pixmap for the chip 'i' at size 'size'.
+//
+
+QPixmap QReversiBoardView::chipPixmap(uint i, uint size) const
+{
+ // Get the part of the 'allchips' pixmap that contains exactly that
+ // chip that we want to use.
+ QPixmap pix(CHIP_SIZE, CHIP_SIZE);
+ copyBlt(&pix, 0, 0, &allchips, (i%5) * CHIP_SIZE, (i/5) * CHIP_SIZE,
+ CHIP_SIZE, CHIP_SIZE);
+
+ // Resize (scale) the pixmap to the desired size.
+ QWMatrix wm3;
+ wm3.scale(float(size)/CHIP_SIZE, float(size)/CHIP_SIZE);
+
+ return pix.xForm(wm3);
+}
+
+
+uint QReversiBoardView::zoomedSize() const
+{
+ return qRound(float(CHIP_SIZE) * Prefs::zoom() / 100);
+}
+
+
+void QReversiBoardView::drawPiece(uint row, uint col, Color color)
+{
+ int i = (color == Nobody ? -1 : int(CHIP_OFFSET[color]));
+ drawOnePiece(row, col, i);
+}
+
+
+void QReversiBoardView::drawOnePiece(uint row, uint col, int i)
+{
+ int px = col * zoomedSize() + 1;
+ int py = row * zoomedSize() + 1;
+ QPainter p(this);
+
+ // Draw either a background pixmap or a background color to the square.
+ int offset = m_marksShowing ? OFFSET() : 0;
+ if (bg.width())
+ p.drawTiledPixmap(px + offset, py + offset,
+ zoomedSize(), zoomedSize(), bg, px, py);
+ else
+ p.fillRect(px + offset, py + offset,
+ zoomedSize(), zoomedSize(), bgColor);
+
+ // Draw a black border around the square.
+ p.setPen(black);
+ p.drawRect(px + offset, py + offset, zoomedSize(), zoomedSize());
+
+ // If no piece on the square, i.e. only the background, then return here...
+ if ( i == -1 )
+ return;
+
+ // ...otherwise finally draw the piece on the square.
+ p.drawPixmap(px + offset, py + offset, chipPixmap(i, zoomedSize()));
+}
+
+
+// We got a repaint event. We make it easy for us and redraw the
+// entire board.
+//
+
+void QReversiBoardView::paintEvent(QPaintEvent *)
+{
+ updateBoard(true);
+}
+
+
+void QReversiBoardView::adjustSize()
+{
+ int w = 8 * zoomedSize();
+
+ if (m_marksShowing)
+ w += 2 * OFFSET();
+
+ setFixedSize(w + 2, w + 2);
+}
+
+
+void QReversiBoardView::setPixmap(QPixmap &pm)
+{
+ if ( pm.width() == 0 )
+ return;
+
+ bg = pm;
+ update();
+ setErasePixmap(pm);
+}
+
+
+void QReversiBoardView::setColor(const QColor &c)
+{
+ bgColor = c;
+ bg = QPixmap();
+ update();
+ setEraseColor(c);
+}
+
+
+// Load all settings that have to do with the board view, such as
+// piece colors, background, animation speed, an so on.
+
+void QReversiBoardView::loadSettings()
+{
+ // Colors of the pieces (red/blue or black/white)
+ if ( Prefs::grayscale() ) {
+ if (chiptype != Grayscale)
+ loadChips(Grayscale);
+ }
+ else {
+ if (chiptype != Colored)
+ loadChips(Colored);
+ }
+
+ // Animation speed.
+ if ( !Prefs::animation() )
+ setAnimationSpeed(0);
+ else
+ setAnimationSpeed(10 - Prefs::animationSpeed());
+
+ // Background
+ if ( Prefs::backgroundImageChoice() ) {
+ QPixmap pm( Prefs::backgroundImage() );
+ if (!pm.isNull())
+ setPixmap(pm);
+ } else {
+ setColor( Prefs::backgroundColor() );
+ }
+}
+
+
+#include "board.moc"
+
diff --git a/kreversi/board.h b/kreversi/board.h
new file mode 100644
index 00000000..4f9d1603
--- /dev/null
+++ b/kreversi/board.h
@@ -0,0 +1,150 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * created 1997 by Mario Weilguni <[email protected]>
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+#ifndef __BOARD__H__
+#define __BOARD__H__
+
+#include <qwidget.h>
+#include <qpixmap.h>
+
+#include "Position.h"
+//#include "Game.h"
+#include "Move.h"
+
+
+class KConfig;
+
+class QReversiGame;
+
+// The class Board is the visible Reversi Board widget.
+//
+
+class QReversiBoardView : public QWidget {
+ Q_OBJECT
+
+public:
+
+ QReversiBoardView(QWidget *parent, QReversiGame *game);
+ ~QReversiBoardView();
+
+ // starts all: emits some signal, so it can't be called from
+ // constructor
+ void start();
+
+ // Used by the outer KZoomMainWindow class.
+ void adjustSize();
+
+ // Show a hint to the user.
+ void showHint(Move move);
+ void quitHint();
+
+ // Turn on or off some special features.
+ void setShowLegalMoves(bool show);
+ void setShowMarks(bool show);
+ void setShowLastMove(bool show);
+
+ // View methods called from the outside.
+ void updateBoard(bool force = FALSE);
+ void animateChanged(Move move);
+ void setAnimationSpeed(uint);
+
+ void loadSettings();
+
+ // To get the pixmap for the status view
+ QPixmap chipPixmap(Color color, uint size) const;
+
+
+signals:
+ void signalSquareClicked(int, int);
+
+
+protected:
+
+ // event stuff
+ void paintEvent(QPaintEvent *);
+ void mousePressEvent(QMouseEvent *);
+
+
+private:
+ uint zoomedSize() const;
+ void drawPiece(uint row, uint col, Color);
+ void drawOnePiece(uint row, uint col, int i);
+ void animateChangedRow(int row, int col, int dy, int dx);
+ void rotateChip(uint row, uint col);
+ bool isField(int row, int col) const;
+
+ void setColor(const QColor &);
+ QColor color() const { return bgColor; }
+ void setPixmap(QPixmap &);
+
+ // Methods for handling images of pieces.
+ enum ChipType { Unloaded, Colored, Grayscale };
+ void loadChips(ChipType);
+ ChipType chipType() const { return chiptype; }
+ QPixmap chipPixmap(uint i, uint size) const;
+
+ // Private drawing methods.
+ void showLegalMoves();
+ void drawSmallCircle(int x, int y, QPainter &p);
+
+
+private:
+ QReversiGame *m_krgame; // Pointer to the game object (not owner).
+
+ // The background of the board - a color and a pixmap.
+ QColor bgColor;
+ QPixmap bg;
+
+ // the pieces
+ ChipType chiptype;
+ QPixmap allchips;
+ uint anim_speed;
+
+ // Special stuff used only in smaller areas.
+ bool m_hintShowing;
+ MoveList m_legalMoves;
+ bool m_legalMovesShowing;
+ bool m_marksShowing;
+
+ bool m_showLastMove;
+ SimpleMove m_lastMoveShown;
+};
+
+
+#endif
+
diff --git a/kreversi/highscores.cpp b/kreversi/highscores.cpp
new file mode 100644
index 00000000..88317a87
--- /dev/null
+++ b/kreversi/highscores.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2004 Nicolas HADACEK ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "highscores.h"
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kapplication.h>
+
+
+namespace KExtHighscore
+{
+
+const ExtManager::Data ExtManager::DATA[SuperEngine::NbStrengths] = {
+ { I18N_NOOP("1 (Beginner)"), "beginner" },
+ { I18N_NOOP("2"), 0 },
+ { I18N_NOOP("3"), 0 },
+ { I18N_NOOP("4 (Average)"), "average" },
+ { I18N_NOOP("5"), 0 },
+ { I18N_NOOP("6"), 0 },
+ { I18N_NOOP("7 (Expert)"), "expert" }
+};
+
+
+ExtManager::ExtManager()
+ : Manager(SuperEngine::NbStrengths)
+{
+ setShowStatistics(true);
+ setShowDrawGamesStatistic(true);
+
+ const uint RANGE[6] = { 0, 32, 40, 48, 56, 64 };
+ QMemArray<uint> s;
+ s.duplicate(RANGE, 6);
+ setScoreHistogram(s, ScoreBound);
+}
+
+
+QString ExtManager::gameTypeLabel(uint gameType, LabelType type) const
+{
+ const Data &data = DATA[gameType];
+ switch (type) {
+ case Icon: return data.icon;
+ case Standard: return QString::number(gameType);
+ case I18N: return i18n(data.label);
+ case WW: break;
+ }
+
+ return QString::null;
+}
+
+
+void ExtManager::convertLegacy(uint gameType)
+{
+ // Since there is no information about the skill level
+ // in the legacy highscore list, consider they are
+ // for beginner skill ...
+ qDebug("convert legacy %i", gameType);
+
+ if ( gameType!=0 )
+ return;
+
+ KConfigGroupSaver cg(kapp->config(), "High Score");
+
+ for (uint i = 1; i <= 10; i++) {
+ QString key = "Pos" + QString::number(i);
+ QString name = cg.config()->readEntry(key + "Name", QString::null);
+
+ if ( name.isEmpty() )
+ name = i18n("anonymous");
+
+ uint score = cg.config()->readUnsignedNumEntry(key + "NumChips", 0);
+ if ( score==0 )
+ continue;
+
+ QString sdate = cg.config()->readEntry(key + "Date", QString::null);
+ QDateTime date = QDateTime::fromString(sdate);
+ Score s(Won);
+
+ s.setScore(score);
+ s.setData("name", name);
+ if ( date.isValid() )
+ s.setData("date", date);
+ submitLegacyScore(s);
+ }
+}
+
+
+} // Namespace
diff --git a/kreversi/highscores.h b/kreversi/highscores.h
new file mode 100644
index 00000000..a599d12d
--- /dev/null
+++ b/kreversi/highscores.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2004 Nicolas HADACEK ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef HIGHSCORES_H
+#define HIGHSCORES_H
+
+
+#include <kexthighscore.h>
+#include <kdemacros.h>
+#include "SuperEngine.h"
+
+
+namespace KExtHighscore
+{
+
+class KDE_EXPORT ExtManager : public Manager
+{
+ public:
+ ExtManager();
+
+ private:
+ QString gameTypeLabel(uint gameTye, LabelType) const;
+ void convertLegacy(uint gameType);
+
+ struct Data {
+ const char *label;
+ const char *icon;
+ };
+ static const Data DATA[SuperEngine::NbStrengths];
+};
+
+}
+
+#endif
diff --git a/kreversi/icons/Makefile.am b/kreversi/icons/Makefile.am
new file mode 100644
index 00000000..da1319dc
--- /dev/null
+++ b/kreversi/icons/Makefile.am
@@ -0,0 +1 @@
+KDE_ICON = AUTO \ No newline at end of file
diff --git a/kreversi/icons/cr16-action-lastmoves.png b/kreversi/icons/cr16-action-lastmoves.png
new file mode 100644
index 00000000..5543a104
--- /dev/null
+++ b/kreversi/icons/cr16-action-lastmoves.png
Binary files differ
diff --git a/kreversi/icons/cr16-action-legalmoves.png b/kreversi/icons/cr16-action-legalmoves.png
new file mode 100644
index 00000000..5ef60f95
--- /dev/null
+++ b/kreversi/icons/cr16-action-legalmoves.png
Binary files differ
diff --git a/kreversi/icons/cr22-action-lastmoves.png b/kreversi/icons/cr22-action-lastmoves.png
new file mode 100644
index 00000000..29d0f962
--- /dev/null
+++ b/kreversi/icons/cr22-action-lastmoves.png
Binary files differ
diff --git a/kreversi/icons/cr22-action-legalmoves.png b/kreversi/icons/cr22-action-legalmoves.png
new file mode 100644
index 00000000..3158b678
--- /dev/null
+++ b/kreversi/icons/cr22-action-legalmoves.png
Binary files differ
diff --git a/kreversi/icons/cr32-action-lastmoves.png b/kreversi/icons/cr32-action-lastmoves.png
new file mode 100644
index 00000000..47166dd7
--- /dev/null
+++ b/kreversi/icons/cr32-action-lastmoves.png
Binary files differ
diff --git a/kreversi/icons/cr32-action-legalmoves.png b/kreversi/icons/cr32-action-legalmoves.png
new file mode 100644
index 00000000..c5a0e304
--- /dev/null
+++ b/kreversi/icons/cr32-action-legalmoves.png
Binary files differ
diff --git a/kreversi/icons/cr48-action-lastmoves.png b/kreversi/icons/cr48-action-lastmoves.png
new file mode 100644
index 00000000..47a3e0da
--- /dev/null
+++ b/kreversi/icons/cr48-action-lastmoves.png
Binary files differ
diff --git a/kreversi/icons/cr48-action-legalmoves.png b/kreversi/icons/cr48-action-legalmoves.png
new file mode 100644
index 00000000..5742a01d
--- /dev/null
+++ b/kreversi/icons/cr48-action-legalmoves.png
Binary files differ
diff --git a/kreversi/icons/crsc-action-lastmoves.svgz b/kreversi/icons/crsc-action-lastmoves.svgz
new file mode 100644
index 00000000..c2b1c4bb
--- /dev/null
+++ b/kreversi/icons/crsc-action-lastmoves.svgz
Binary files differ
diff --git a/kreversi/icons/crsc-action-legalmoves.svgz b/kreversi/icons/crsc-action-legalmoves.svgz
new file mode 100644
index 00000000..db2acad9
--- /dev/null
+++ b/kreversi/icons/crsc-action-legalmoves.svgz
Binary files differ
diff --git a/kreversi/icons/hi128-app-kreversi.png b/kreversi/icons/hi128-app-kreversi.png
new file mode 100644
index 00000000..26c22bc8
--- /dev/null
+++ b/kreversi/icons/hi128-app-kreversi.png
Binary files differ
diff --git a/kreversi/icons/hi16-app-kreversi.png b/kreversi/icons/hi16-app-kreversi.png
new file mode 100644
index 00000000..9dda53b2
--- /dev/null
+++ b/kreversi/icons/hi16-app-kreversi.png
Binary files differ
diff --git a/kreversi/icons/hi22-app-kreversi.png b/kreversi/icons/hi22-app-kreversi.png
new file mode 100644
index 00000000..6f77f5a9
--- /dev/null
+++ b/kreversi/icons/hi22-app-kreversi.png
Binary files differ
diff --git a/kreversi/icons/hi32-app-kreversi.png b/kreversi/icons/hi32-app-kreversi.png
new file mode 100644
index 00000000..360f1bda
--- /dev/null
+++ b/kreversi/icons/hi32-app-kreversi.png
Binary files differ
diff --git a/kreversi/icons/hi48-app-kreversi.png b/kreversi/icons/hi48-app-kreversi.png
new file mode 100644
index 00000000..b310d52f
--- /dev/null
+++ b/kreversi/icons/hi48-app-kreversi.png
Binary files differ
diff --git a/kreversi/icons/hi64-app-kreversi.png b/kreversi/icons/hi64-app-kreversi.png
new file mode 100644
index 00000000..5ca5cb5d
--- /dev/null
+++ b/kreversi/icons/hi64-app-kreversi.png
Binary files differ
diff --git a/kreversi/kreversi.cpp b/kreversi/kreversi.cpp
new file mode 100644
index 00000000..b0a5ddc8
--- /dev/null
+++ b/kreversi/kreversi.cpp
@@ -0,0 +1,841 @@
+/* Yo Emacs, this is -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * created 1997 by Mario Weilguni <[email protected]>
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+
+#include <unistd.h>
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlistbox.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kstatusbar.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kaction.h>
+#include <kstdgameaction.h>
+#include <kkeydialog.h>
+#include <kconfigdialog.h>
+#include <knotifyclient.h>
+#include <knotifydialog.h>
+#include <kexthighscore.h>
+
+#include "Score.h"
+#include "kreversi.h"
+
+// Automatically generated headers
+#include "prefs.h"
+#include "settings.h"
+
+#include "kreversi.moc"
+
+
+// ================================================================
+// class KReversi
+
+
+#ifndef PICDATA
+#define PICDATA(x) \
+ KGlobal::dirs()->findResource("appdata", QString("pics/") + x)
+#endif
+
+
+KReversi::KReversi()
+ : KZoomMainWindow(10, 300, 5, "kreversi"),
+ m_gameOver(false)
+{
+ QWidget *w;
+ QGridLayout *top;
+
+ KNotifyClient::startDaemon();
+
+ // The game.
+ m_game = new QReversiGame();
+ m_cheating = false;
+ m_gameOver = false;
+ m_humanColor = Black;
+
+ // The Engine
+ m_engine = new Engine();
+ setStrength(1);
+
+ // The visual stuff
+ w = new QWidget(this);
+ setCentralWidget(w);
+
+ top = new QGridLayout(w, 2, 2);
+
+ // The reversi game view.
+ m_gameView = new QReversiGameView(w, m_game);
+ top->addMultiCellWidget(m_gameView, 0, 1, 0, 0);
+
+ // Populate the GUI.
+ createKActions();
+ addWidget(m_gameView);
+
+ // Connect the signals from the game with slots of the view
+ //
+ // The only part of the view that is left in this class is the
+ // indicator of whose turn it is in the status bar. The rest is
+ // in the game view.
+ connect(m_game, SIGNAL(sig_newGame()), this, SLOT(showTurn()));
+ connect(m_game, SIGNAL(sig_move(uint, Move&)),
+ this, SLOT(handleMove(uint, Move&))); // Calls showTurn().
+ connect(m_game, SIGNAL(sig_update()), this, SLOT(showTurn()));
+ connect(m_game, SIGNAL(sig_gameOver()), this, SLOT(slotGameOver()));
+
+ // Signal that is sent when the user clicks on the board.
+ connect(m_gameView, SIGNAL(signalSquareClicked(int, int)),
+ this, SLOT(slotSquareClicked(int, int)));
+
+ loadSettings();
+
+ setupGUI();
+ init("popup");
+ m_gameView->start();
+
+ slotNewGame();
+}
+
+
+KReversi::~KReversi()
+{
+ delete m_game;
+ delete m_engine;
+}
+
+
+
+// Create all KActions used in KReversi.
+//
+
+void KReversi::createKActions()
+{
+ // Standard Game Actions.
+ KStdGameAction::gameNew(this, SLOT(slotNewGame()), actionCollection(),
+ "game_new");
+ KStdGameAction::load(this, SLOT(slotOpenGame()), actionCollection());
+ KStdGameAction::save(this, SLOT(slotSave()), actionCollection());
+ KStdGameAction::quit(this, SLOT(close()), actionCollection());
+ KStdGameAction::hint(this, SLOT(slotHint()), actionCollection(),
+ "game_hint");
+ KStdGameAction::undo(this, SLOT(slotUndo()), actionCollection(),
+ "game_undo");
+
+ // Non-standard Game Actions: Stop, Continue, Switch sides
+ stopAction = new KAction(i18n("&Stop Thinking"), "game_stop", Qt::Key_Escape,
+ this, SLOT(slotInterrupt()), actionCollection(),
+ "game_stop");
+ continueAction = new KAction(i18n("&Continue Thinking"), "reload", 0,
+ this, SLOT(slotContinue()), actionCollection(),
+ "game_continue");
+ new KAction(i18n("S&witch Sides"), 0, 0,
+ this, SLOT(slotSwitchSides()), actionCollection(),
+ "game_switch_sides");
+
+ // Some more standard game actions: Highscores, Settings.
+ KStdGameAction::highscores(this, SLOT(showHighScoreDialog()), actionCollection());
+ KStdAction::preferences(this, SLOT(slotEditSettings()), actionCollection());
+
+ // Actions for the view(s).
+ showLastMoveAction = new KToggleAction(i18n("Show Last Move"), "lastmoves", 0,
+ this, SLOT(slotShowLastMove()),
+ actionCollection(),
+ "show_last_move");
+ showLegalMovesAction = new KToggleAction(i18n("Show Legal Moves"), "legalmoves", 0,
+ this, SLOT(slotShowLegalMoves()),
+ actionCollection(),
+ "show_legal_moves");
+}
+
+
+// ----------------------------------------------------------------
+// Methods for the engine
+
+
+// Set the strength for the engine. We keep track of the lowest
+// strength that was used during a game and if the user wins, this is
+// the strength that we will store in the highscore file.
+
+void KReversi::setStrength(uint strength)
+{
+ // FIXME: 7 should be MAXSTRENGTH or something similar.
+ Q_ASSERT( 1 <= strength && strength <= 7 );
+
+ strength = QMAX(QMIN(strength, 7), 1);
+ m_engine->setStrength(strength);
+ if (m_lowestStrength < strength)
+ m_lowestStrength = strength;
+ KExtHighscore::setGameType(m_lowestStrength-1);
+}
+
+
+// ----------------------------------------------------------------
+// Slots for KActions
+
+
+// A slot that is called when the user wants a new game.
+//
+
+void KReversi::slotNewGame()
+{
+ // If already playing, ask the player if he wants to abort the old game.
+ if ( isPlaying() ) {
+ if (KMessageBox
+ ::warningYesNo(0,
+ i18n("You are already running an unfinished game. "
+ "If you abort the old game to start a new one, "
+ "the old game will be registered as a loss in "
+ "the highscore file.\n"
+ "What do you want to do?"),
+ i18n("Abort Current Game?"),
+ i18n("Abort Old Game"),
+ i18n("Continue Old Game")) == KMessageBox::No)
+ return;
+
+ KExtHighscore::submitScore(KExtHighscore::Lost, this);
+ }
+
+ m_gameOver = false;
+ m_cheating = false;
+
+ m_game->newGame();
+ m_competitiveGame = Prefs::competitiveGameChoice();
+ m_lowestStrength = strength();
+ //kdDebug() << "Competitive: " << m_competitiveGame << endl;
+
+ // Set the state to waiting for the humans move.
+ setState(Ready);
+
+ // Black always makes first move.
+ if (m_humanColor == White)
+ computerMakeMove();
+}
+
+
+// Open an earlier saved game from the config file.
+//
+// FIXME: Should give a choice to load from an ordinary file (SGF?)
+//
+
+void KReversi::slotOpenGame()
+{
+ KConfig *config = kapp->config();
+ config->setGroup("Savegame");
+
+ if (loadGame(config))
+ Prefs::setSkill(m_engine->strength());
+ m_gameView->setHumanColor(humanColor());
+}
+
+
+// Save a game to the config file.
+//
+// FIXME: Should give a choice to save as an ordinary file (SGF?)
+//
+
+void KReversi::slotSave()
+{
+ KConfig *config = kapp->config();
+ config->setGroup("Savegame");
+ saveGame(config);
+
+ KMessageBox::information(this, i18n("Game saved."));
+}
+
+
+void KReversi::slotHint()
+{
+ Move move;
+
+ if (state() != Ready)
+ return;
+
+ setState(Thinking);
+ move = m_engine->computeMove(m_game, m_competitiveGame);
+
+ setState(Hint);
+ m_gameView->showHint(move);
+
+ setState(Ready);
+}
+
+
+// Takes back last set of moves
+//
+
+void KReversi::slotUndo()
+{
+ if (state() != Ready)
+ return;
+
+ // Can't undo anything if no moves are made.
+ if (m_game->moveNumber() == 0)
+ return;
+
+ // Undo all moves of the same color as the last one.
+ Color last_color = m_game->lastMove().color();
+ while (m_game->moveNumber() != 0
+ && last_color == m_game->lastMove().color()) {
+ m_game->undoMove();
+ m_gameView->removeMove(m_game->moveNumber());
+ }
+
+ // Take back one more move.
+ if (m_game->moveNumber() > 0) {
+ m_game->undoMove();
+ m_gameView->removeMove(m_game->moveNumber());
+
+ // FIXME: Call some method in m_gameView.
+ m_gameView->setCurrentMove(m_game->moveNumber() - 1);
+ }
+
+ if (m_game->toMove() == computerColor()) {
+ // Must repaint so that the new move is not shown before the old
+ // one is removed on the screen.
+ m_gameView->repaint();
+ computerMakeMove();
+ }
+ else
+ m_gameView->update();
+}
+
+
+// Interrupt thinking of game engine.
+//
+
+void KReversi::slotInterrupt()
+{
+ m_engine->setInterrupt(TRUE);
+
+ // Indicate that the computer was interrupted.
+ showTurn();
+}
+
+
+// Continues a move if it was interrupted earlier.
+//
+
+void KReversi::slotContinue()
+{
+ if (interrupted())
+ computerMakeMove();
+}
+
+
+// Turn on or off showing of legal moves in the board view.
+
+void KReversi::slotShowLastMove()
+{
+ m_gameView->setShowLastMove(showLastMoveAction->isChecked());
+}
+
+
+// Turn on or off showing of legal moves in the board view.
+
+void KReversi::slotShowLegalMoves()
+{
+ m_gameView->setShowLegalMoves(showLegalMovesAction->isChecked());
+}
+
+
+void KReversi::slotSwitchSides()
+{
+ if (state() != Ready)
+ return;
+
+ if (interrupted()) {
+ KMessageBox::information(this, i18n("You cannot switch sides in the middle of the computer's move."),
+ i18n("Notice"));
+ return;
+ }
+
+ // It's ok to change sides before the first move.
+ if (m_game->moveNumber() != 0) {
+ int res = KMessageBox::warningContinueCancel(this,
+ i18n("If you switch side, your score will not be added to the highscores."),
+ QString::null, QString::null, "switch_side_warning");
+ if ( res==KMessageBox::Cancel )
+ return;
+
+ m_cheating = true;
+ }
+
+ m_humanColor = opponent(m_humanColor);
+
+ // Update the human color in the window.
+ m_gameView->setHumanColor(m_humanColor);
+
+ kapp->processEvents();
+ computerMakeMove();
+}
+
+
+// ----------------------------------------------------------------
+// Slots for the game IO
+
+
+// Handle mouse clicks.
+//
+
+void KReversi::slotSquareClicked(int row, int col)
+{
+ // Can't move when it is the computers turn.
+ if ( interrupted() ) {
+ illegalMove();
+ return;
+ }
+
+ if (state() == Ready)
+ humanMakeMove(row, col);
+ else if (state() == Hint) {
+ m_gameView->quitHint();
+ setState(Ready);
+ }
+ else
+ illegalMove();
+}
+
+
+// ----------------------------------------------------------------
+// Slots for the game view
+
+
+// Show the move in the move view.
+// FIXME: Move this to the gameview.
+
+void KReversi::handleMove(uint /*moveno*/, Move& /*move*/)
+{
+ showTurn();
+}
+
+
+// A slot that is called when it is time to show whose turn it is.
+//
+
+void KReversi::showTurn()
+{
+ showTurn(m_game->toMove());
+}
+
+void KReversi::showTurn(Color color)
+{
+ // If we are not playing, do nothing.
+ if (m_gameOver)
+ return;
+
+ if (color == humanColor())
+ statusBar()->message(i18n("Your turn"));
+ else if (color == computerColor()) {
+ QString message = i18n("Computer's turn");
+
+ // We can't use the interrupted() test here since we might be in a
+ // middle state when called from slotInterrupt().
+ if (m_state == Thinking)
+ message += i18n(" (interrupted)");
+ statusBar()->message(message);
+ }
+ else
+ statusBar()->clear();
+}
+
+
+// A slot that is called when the game ends.
+//
+
+void KReversi::slotGameOver()
+{
+ uint black = m_game->score(Black);
+ uint white = m_game->score(White);
+
+ setState(Ready);
+
+ if (black > white)
+ showGameOver(Black);
+ else if (black < white)
+ showGameOver(White);
+ else
+ showGameOver(Nobody);
+
+ showTurn(Nobody);
+}
+
+
+// ----------------------------------------------------------------
+// Private methods
+
+
+// Handle the humans move.
+//
+
+void KReversi::humanMakeMove(int row, int col)
+{
+ if (state() != Ready)
+ return;
+
+ Color color = m_game->toMove();
+
+ // Create a move from the mouse click and see if it is legal.
+ // If it is, then make a human move.
+ Move move(color, col + 1, row + 1);
+ if (m_game->moveIsLegal(move)) {
+ // Do the move. The view is automatically updated.
+ m_game->doMove(move);
+
+ if (!m_game->moveIsAtAllPossible()) {
+ setState(Ready);
+ slotGameOver();
+ return;
+ }
+
+ if (color != m_game->toMove())
+ computerMakeMove();
+ } else
+ illegalMove();
+}
+
+
+// Make a computer move.
+//
+
+void KReversi::computerMakeMove()
+{
+ MoveList moves;
+
+ // Check if the computer can move.
+ Color color = m_game->toMove();
+ Color opponent = ::opponent(color);
+
+ if (!m_game->moveIsPossible(color))
+ return;
+
+ // Make computer moves until the human can play or until the game is over.
+ setState(Thinking);
+ do {
+ Move move;
+
+ if (!m_game->moveIsAtAllPossible()) {
+ setState(Ready);
+ slotGameOver();
+ return;
+ }
+
+ move = m_engine->computeMove(m_game, m_competitiveGame);
+ if (move.x() == -1) {
+ setState(Ready);
+ return;
+ }
+ usleep(300000); // Pretend we have to think hard.
+
+ // Do the move on the board. The view is automatically updated.
+ //playSound("click.wav");
+ m_game->doMove(move);
+ } while (!m_game->moveIsPossible(opponent));
+
+ setState(Ready);
+
+ if (!m_game->moveIsAtAllPossible()) {
+ slotGameOver();
+ return;
+ }
+}
+
+
+// Handle an attempt to make an illegal move by the human.
+
+void KReversi::illegalMove()
+{
+ KNotifyClient::event(winId(), "illegal_move", i18n("Illegal move"));
+}
+
+
+// Show things when the game is over.
+//
+
+void KReversi::showGameOver(Color color)
+{
+ // If the game already was over, do nothing.
+ if (m_gameOver)
+ return;
+
+ statusBar()->message(i18n("End of game"));
+
+ // Get the scores.
+ uint human = m_game->score(humanColor());
+ uint computer = m_game->score(computerColor());
+
+ KExtHighscore::Score score;
+ score.setScore(m_game->score(humanColor()));
+
+ // Show the winner in a messagebox.
+ if ( color == Nobody ) {
+ KNotifyClient::event(winId(), "draw", i18n("Draw!"));
+ QString s = i18n("Game is drawn!\n\nYou : %1\nComputer: %2")
+ .arg(human).arg(computer);
+ KMessageBox::information(this, s, i18n("Game Ended"));
+ score.setType(KExtHighscore::Draw);
+ }
+ else if ( humanColor() == color ) {
+ KNotifyClient::event(winId(), "won", i18n("Game won!"));
+ QString s = i18n("Congratulations, you have won!\n\nYou : %1\nComputer: %2")
+ .arg(human).arg(computer);
+ KMessageBox::information(this, s, i18n("Game Ended"));
+ score.setType(KExtHighscore::Won);
+ }
+ else {
+ KNotifyClient::event(winId(), "lost", i18n("Game lost!"));
+ QString s = i18n("You have lost the game!\n\nYou : %1\nComputer: %2")
+ .arg(human).arg(computer);
+ KMessageBox::information(this, s, i18n("Game Ended"));
+ score.setType(KExtHighscore::Lost);
+ }
+
+ // Store the result in the highscore file if no cheating was done,
+ // and only if the game was competitive.
+ if (!m_cheating && m_competitiveGame) {
+ KExtHighscore::submitScore(score, this);
+ }
+
+ m_gameOver = true;
+}
+
+
+// Saves the game in the config file.
+//
+// Only one game at a time can be saved.
+//
+
+void KReversi::saveGame(KConfig *config)
+{
+ // Stop thinking.
+ slotInterrupt();
+
+ // Write the data to the config file.
+ config->writeEntry("State", state());
+ config->writeEntry("Strength", strength());
+ config->writeEntry("Competitive", (int) m_competitiveGame);
+ config->writeEntry("HumanColor", (int) m_humanColor);
+
+ // Write the moves of the game to the config object. This object
+ // saves itself all at once so we don't have to write the moves
+ // to the file ourselves.
+ config->writeEntry("NumberOfMoves", m_game->moveNumber());
+ for (uint i = 0; i < m_game->moveNumber(); i++) {
+ Move move = m_game->move(i);
+
+ QString moveString;
+ QString idx;
+
+ moveString.sprintf("%d %d %d", move.x(), move.y(), (int) move.color());
+ idx.sprintf("Move_%d", i + 1);
+ config->writeEntry(idx, moveString);
+ }
+
+ // Actually write the data to file.
+ config->sync();
+
+ // Continue with the move if applicable.
+ slotContinue();
+}
+
+
+// Loads the game. Only one game at a time can be saved.
+
+bool KReversi::loadGame(KConfig *config)
+{
+ slotInterrupt(); // stop thinking
+
+ uint nmoves = config->readNumEntry("NumberOfMoves", 0);
+ if (nmoves==0)
+ return false;
+
+ m_game->newGame();
+ uint movenumber = 1;
+ while (nmoves--) {
+ // Read one move.
+ QString idx;
+ idx.sprintf("Move_%d", movenumber++);
+
+ QStringList s = config->readListEntry(idx, ' ');
+ uint x = (*s.at(0)).toUInt();
+ uint y = (*s.at(1)).toUInt();
+ Color color = (Color)(*s.at(2)).toInt();
+
+ Move move(color, x, y);
+ m_game->doMove(move);
+ }
+
+ m_humanColor = (Color) config->readNumEntry("HumanColor");
+ m_competitiveGame = (bool) config->readNumEntry("Competitive");
+
+ m_gameView->updateBoard(TRUE);
+ setState(State(config->readNumEntry("State")));
+ setStrength(config->readNumEntry("Strength", 1));
+
+ if (interrupted())
+ slotContinue();
+ else {
+ // Computer makes first move.
+ if (m_humanColor != m_game->toMove())
+ computerMakeMove();
+ }
+
+ return true;
+}
+
+
+// ----------------------------------------------------------------
+
+
+void KReversi::saveProperties(KConfig *c)
+{
+ saveGame(c);
+}
+
+
+void KReversi::readProperties(KConfig *config) {
+ loadGame(config);
+ m_gameOver = false;
+ m_cheating = false; // FIXME: Is this true? It isn't saved.
+}
+
+
+void KReversi::showHighScoreDialog()
+{
+ KExtHighscore::show(this);
+}
+
+
+void KReversi::slotEditSettings()
+{
+ // If we are already editing the settings, then do nothing.
+ if (KConfigDialog::showDialog("settings"))
+ return;
+
+ KConfigDialog *dialog = new KConfigDialog(this, "settings", Prefs::self(),
+ KDialogBase::Swallow);
+ Settings *general = new Settings(0, "General");
+
+ dialog->addPage(general, i18n("General"), "package_settings");
+ connect(dialog, SIGNAL(settingsChanged()), this, SLOT(loadSettings()));
+ dialog->show();
+}
+
+
+void KReversi::configureNotifications()
+{
+ KNotifyDialog::configure(this);
+}
+
+
+void KReversi::loadSettings()
+{
+ m_humanColor = (Color) Prefs::humanColor();
+ setStrength(Prefs::skill());
+
+ // m_competitiveGame is set at the start of a game and can only be
+ // downgraded during the game, never upgraded.
+ if ( !Prefs::competitiveGameChoice() )
+ m_competitiveGame = false;
+
+ m_gameView->loadSettings();
+
+ // Update the color of the human and the computer.
+ m_gameView->setHumanColor(humanColor());
+}
+
+
+bool KReversi::isPlaying() const
+{
+ return ( m_game->moveNumber() != 0 && !m_gameOver );
+}
+
+
+void KReversi::setState(State newState)
+{
+ m_state = newState;
+
+ if (m_state == Thinking){
+ kapp->setOverrideCursor(waitCursor);
+ stopAction->setEnabled(true);
+ }
+ else {
+ kapp->restoreOverrideCursor();
+ stopAction->setEnabled(false);
+ }
+
+ continueAction->setEnabled(interrupted());
+}
+
+
+bool KReversi::queryExit()
+{
+ if ( isPlaying() )
+ KExtHighscore::submitScore(KExtHighscore::Lost, this);
+
+ return KZoomMainWindow::queryExit();
+}
+
+
+void KReversi::writeZoomSetting(uint zoom)
+{
+ Prefs::setZoom(zoom);
+ Prefs::writeConfig();
+}
+
+
+uint KReversi::readZoomSetting() const
+{
+ return Prefs::zoom();
+}
+
+
+void KReversi::writeMenubarVisibleSetting(bool visible)
+{
+ Prefs::setMenubarVisible(visible);
+ Prefs::writeConfig();
+}
+
+
+bool KReversi::menubarVisibleSetting() const
+{
+ return Prefs::menubarVisible();
+}
diff --git a/kreversi/kreversi.desktop b/kreversi/kreversi.desktop
new file mode 100644
index 00000000..e32a3bc4
--- /dev/null
+++ b/kreversi/kreversi.desktop
@@ -0,0 +1,74 @@
+[Desktop Entry]
+Exec=kreversi %i %m -caption "%c"
+Name=KReversi
+Name[af]=Kreversi
+Name[be]=Рэверсі
+Name[bn]=কে-রিভার্সি
+Name[ca]=Reversi
+Name[eo]=Renverso
+Name[hi]=के-रिवर्सी
+Name[is]=Viðsnúningur
+Name[ne]=केडीई रिभर्सी
+Name[pa]=ਕੇ-ਰੀਵਰਸੀ
+Name[pl]=Reversi
+Name[sv]=Kreversi
+Name[ta]=Kரிவர்ஸி
+Name[tg]=KРеверси
+Name[th]=หมากหนีบ - K
+Name[zh_TW]=KReversi 黑白棋
+Type=Application
+DocPath=kreversi/index.html
+GenericName=Reversi Board Game
+GenericName[be]=Настольная гульня ў рэверсі
+GenericName[bg]=Игра на дъска
+GenericName[bn]=ছককেন্দ্রিক খেলা রিভার্সি
+GenericName[br]=Ur c'hoari taolenn Reversi
+GenericName[bs]=Igra s pločom
+GenericName[ca]=Joc de taula Reversi
+GenericName[cs]=Desková hra Reversi
+GenericName[cy]=Gêm Fwrdd Reversi
+GenericName[da]=Reversi brætspil
+GenericName[de]=Reversi Brettspiel
+GenericName[el]=Επιτραπέζιο παιχνίδι Reversi
+GenericName[eo]="Renverso"-Tabuloludo
+GenericName[es]=Juego de tablero Reversi
+GenericName[et]=Lauamäng Reversi
+GenericName[eu]=Reversi mahai-jokoa
+GenericName[fa]=بازی Reversi Board
+GenericName[fi]=Othello
+GenericName[fr]=Jeu de plateau Reversi
+GenericName[he]=רברסי, משחק לוח
+GenericName[hr]=Reversi igra na ploči
+GenericName[hu]=Reversi
+GenericName[is]=Reversi borðleikur
+GenericName[it]=Reversi, gioco da tavolo
+GenericName[ja]=リバーシゲーム
+GenericName[km]=ល្បែង​ក្ដារ Reversi
+GenericName[ko]=리버시 보드 게임
+GenericName[lt]=Reversi stalo žaidimas
+GenericName[lv]=Reversā galda spēle
+GenericName[mk]=Игра на табла Reversi
+GenericName[nb]=Brettspillet reversi
+GenericName[nds]=Reversi-Brettspeel
+GenericName[ne]=रिभर्सी बोर्ड खेल
+GenericName[nl]=Reversi-bordspel
+GenericName[nn]=Brettspelet reversi
+GenericName[pl]=Gra planszowa Reversi
+GenericName[pt]=Jogo de Tabuleiro Reversi
+GenericName[pt_BR]=Jogo de tabuleiro como Reversi
+GenericName[ru]=Реверси
+GenericName[se]=Duolbbášspeallu reversi
+GenericName[sk]=Stolová hra Reversi
+GenericName[sl]=Namizna igra Reversi
+GenericName[sr]=Игра на табли Reversi
+GenericName[sr@Latn]=Igra na tabli Reversi
+GenericName[sv]=Othello brädspel
+GenericName[ta]=ரிவர்சி பலகை விளையாட்டு
+GenericName[uk]=Гра на дошці (реверсі)
+GenericName[wa]=Djeu d' platea Reversi
+GenericName[zh_TW]=黑白棋棋盤遊戲
+Terminal=false
+Icon=kreversi
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Game;BoardGame;
diff --git a/kreversi/kreversi.h b/kreversi/kreversi.h
new file mode 100644
index 00000000..17599fa2
--- /dev/null
+++ b/kreversi/kreversi.h
@@ -0,0 +1,178 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * created 1997 by Mario Weilguni <[email protected]>
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+
+#ifndef KREVERSI_H
+#define KREVERSI_H
+
+
+#include "kzoommainwindow.h"
+
+#include "Score.h"
+#include "Game.h"
+#include "Engine.h"
+//#include "board.h"
+#include "qreversigame.h"
+#include "qreversigameview.h"
+
+
+class QLabel;
+
+class KAction;
+
+
+class KReversi : public KZoomMainWindow
+{
+ Q_OBJECT
+
+public:
+
+ enum State { Ready, Thinking, Hint};
+
+ KReversi();
+ ~KReversi();
+
+ bool isPlaying() const;
+
+ // Methods that deal with the game
+ Color toMove() const { return m_game->toMove(); }
+ Color humanColor() const { return m_humanColor; }
+ Color computerColor() const { return opponent(m_humanColor); }
+
+ // Methods that deal with the engine.
+ void setStrength(uint);
+ uint strength() const { return m_engine->strength(); }
+ void interrupt() { m_engine->setInterrupt(TRUE); }
+ bool interrupted() const { return (m_game->toMove() == computerColor()
+ && m_state == Ready); }
+
+ // State of the program (Hint, Ready, Thinking, etc).
+ void setState(State);
+ State state() const { return m_state; }
+
+private:
+ // Initialisation
+ void createKActions();
+
+ // View functions.
+ QString getPlayerName();
+
+ virtual void writeZoomSetting(uint zoom);
+ virtual uint readZoomSetting() const;
+ virtual void writeMenubarVisibleSetting(bool visible);
+ virtual bool menubarVisibleSetting() const;
+
+ virtual void saveProperties(KConfig *);
+ virtual void readProperties(KConfig *);
+ virtual bool queryExit();
+
+
+private slots:
+
+ // Slots for KActions.
+ void slotNewGame();
+ void slotOpenGame();
+ void slotSave();
+ void slotHint();
+ void slotUndo();
+ void slotSwitchSides();
+
+ // Interrupt and continue the engines thinking (also KActions).
+ void slotInterrupt();
+ void slotContinue();
+ void slotShowLastMove();
+ void slotShowLegalMoves();
+
+ // Slots for game IO
+ void slotSquareClicked(int, int);
+
+ // Misc slots.
+ void configureNotifications();
+
+ // Some dialogs and other misc stuff.
+ void showHighScoreDialog();
+ void slotEditSettings();
+ void loadSettings();
+
+ public slots:
+ // Slots for the view.
+ void handleMove(uint moveno, Move &move);
+ void showTurn();
+ void showTurn(Color color);
+ void slotGameOver();
+
+private:
+
+ // Private methods
+ void humanMakeMove(int row, int col);
+ void computerMakeMove();
+ void illegalMove();
+ void showGameOver(Color);
+
+ void saveGame(KConfig *);
+ bool loadGame(KConfig *);
+
+
+private:
+ // Some Actions that need to be manipulated.
+ KAction *stopAction;
+ KAction *continueAction;
+
+ KToggleAction *showLastMoveAction;
+ KToggleAction *showLegalMovesAction;
+
+ // The game itself and game properties
+ QReversiGame *m_game; // The main document - the game
+
+ Color m_humanColor; // The Color of the human player.
+ bool m_gameOver; // True if the game is over
+ bool m_cheating; // True if the user has changed sides
+ uint m_lowestStrength; // Lowest strength during the game.
+ bool m_competitiveGame;// True if the game has been
+ // competitive during all moves so far.
+
+ State m_state; // Ready, Thinking, Hint
+ Engine *m_engine; // The AI that creates the computers moves.
+
+ // Widgets
+ QReversiGameView *m_gameView; // The board widget.
+};
+
+
+#endif
+
diff --git a/kreversi/kreversi.kcfg b/kreversi/kreversi.kcfg
new file mode 100644
index 00000000..c1dc6e52
--- /dev/null
+++ b/kreversi/kreversi.kcfg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <include>kstandarddirs.h</include>
+ <include>kglobal.h</include>
+ <kcfgfile name="kreversirc"/>
+ <group name="Game">
+ <entry name="Grayscale" type="Bool">
+ <label>Whether to use a grayscale board instead of colored.</label>
+ <default>false</default>
+ </entry>
+ <entry name="HumanColor" type="Int">
+ <label>The human color.</label>
+ <default>1</default>
+ </entry>
+ <entry name="ComputerColor" type="Int">
+ <label>The computer color.</label>
+ <default>0</default>
+ </entry>
+ <entry name="Animation" type="Bool">
+ <label>Whether to use animations.</label>
+ <default>true</default>
+ </entry>
+ <entry name="AnimationSpeed" type="Int">
+ <label>The speed of the animations.</label>
+ <default>4</default>
+ <min>1</min>
+ <max>10</max>
+ </entry>
+ <entry name="Zoom" type="Int">
+ <label>The zoom factor of the board.</label>
+ <default>100</default>
+ <min>10</min>
+ <max>300</max>
+ </entry>
+ <entry name="CompetitiveGameChoice" type="Bool">
+ <label>Whether to play competitively in contrast to casually.</label>
+ <default>true</default>
+ </entry>
+ <entry name="skill" type="Int">
+ <label>The strength of the computer player.</label>
+ <default>1</default>
+ <min>1</min>
+ <max>7</max>
+ </entry>
+ <entry name="BackgroundImageChoice" type="Bool">
+ <label>Whether to use a background image.</label>
+ <default>true</default>
+ </entry>
+ <entry name="BackgroundColor" type="Color">
+ <label>The background color to use.</label>
+ <default>#ffffff</default>
+ </entry>
+ <entry name="BackgroundImage" type="Path">
+ <label>Image to use as background.</label>
+ <code>#define PICDATA(x) KGlobal::dirs()->findResource("appdata", QString("pics/")+ x)</code>
+ <default code="true">PICDATA("background/Light_Wood.png")</default>
+ </entry>
+ <entry name="MenubarVisible" type="Bool" key="menubar visible">
+ <label>Whether the menubar is visible.</label>
+ <default>true</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kreversi/kreversiui.rc b/kreversi/kreversiui.rc
new file mode 100644
index 00000000..304b87b2
--- /dev/null
+++ b/kreversi/kreversiui.rc
@@ -0,0 +1,45 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kreversi" version="2">
+
+<ActionProperties>
+ <Action name="game_stop" icon="stop"/>
+</ActionProperties>
+
+<MenuBar>
+ <Menu name="game"><text>&amp;Game</text>
+ <Action name="game_sound"/>
+ </Menu>
+ <Menu name="move"><text>&amp;Move</text>
+ <Action name="game_undo"/>
+ <Action name="game_hint"/>
+ <Action name="game_switch_sides"/>
+ <Separator/>
+ <Action name="game_stop"/>
+ <Action name="game_continue"/>
+ </Menu>
+
+</MenuBar>
+
+<ToolBar name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="game_new"/>
+ <Action name="game_stop"/>
+ <Action name="game_continue"/>
+ <Action name="game_undo"/>
+ <Action name="options_show_menubar"/>
+</ToolBar>
+<ToolBar name="viewToolBar"><text>View Toolbar</text>
+ <Action name="game_hint"/>
+ <Action name="show_last_move"/>
+ <Action name="show_legal_moves"/>
+</ToolBar>
+
+<Menu name="popup">
+ <Action name="options_show_menubar"/>
+ <Separator/>
+ <Action name="game_new"/>
+ <Action name="game_highscores"/>
+ <Separator/>
+ <Action name="game_quit"/>
+</Menu>
+
+</kpartgui>
diff --git a/kreversi/kzoommainwindow.cpp b/kreversi/kzoommainwindow.cpp
new file mode 100644
index 00000000..4da50935
--- /dev/null
+++ b/kreversi/kzoommainwindow.cpp
@@ -0,0 +1,135 @@
+/*
+ This file is part of the KDE games library
+ Copyright (C) 2004 Nicolas Hadacek ([email protected])
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include "kzoommainwindow.h"
+#include "kzoommainwindow.moc"
+
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kmenubar.h>
+#include <kcmenumngr.h>
+
+
+KZoomMainWindow::KZoomMainWindow(uint min, uint max, uint step,
+ const char *name)
+ : KMainWindow(0, name), m_zoomStep(step), m_minZoom(min), m_maxZoom(max)
+{
+ installEventFilter(this);
+
+ m_zoomInAction =
+ KStdAction::zoomIn(this, SLOT(zoomIn()), actionCollection());
+ m_zoomOutAction =
+ KStdAction::zoomOut(this, SLOT(zoomOut()), actionCollection());
+ m_menu =
+ KStdAction::showMenubar(this, SLOT(toggleMenubar()), actionCollection());
+}
+
+
+void KZoomMainWindow::init(const char *popupName)
+{
+ // zoom
+ setZoom(readZoomSetting());
+
+ // menubar
+ m_menu->setChecked( menubarVisibleSetting() );
+ toggleMenubar();
+
+ // context popup
+ if (popupName) {
+ QPopupMenu *popup =
+ static_cast<QPopupMenu *>(factory()->container(popupName, this));
+ Q_ASSERT(popup);
+ if (popup)
+ KContextMenuManager::insert(this, popup);
+ }
+}
+
+void KZoomMainWindow::addWidget(QWidget *widget)
+{
+ widget->adjustSize();
+
+ QWidget *tlw = widget->topLevelWidget();
+ KZoomMainWindow *zm =
+ static_cast<KZoomMainWindow *>(tlw->qt_cast("KZoomMainWindow"));
+
+ Q_ASSERT(zm);
+ zm->m_widgets.append(widget);
+ connect(widget, SIGNAL(destroyed()), zm, SLOT(widgetDestroyed()));
+}
+
+
+void KZoomMainWindow::widgetDestroyed()
+{
+ m_widgets.remove(static_cast<const QWidget *>(sender()));
+}
+
+
+bool KZoomMainWindow::eventFilter(QObject *o, QEvent *e)
+{
+ if ( e->type()==QEvent::LayoutHint )
+ setFixedSize(minimumSize()); // because K/QMainWindow
+ // does not manage fixed central widget
+ // with hidden menubar...
+ return KMainWindow::eventFilter(o, e);
+}
+
+
+void KZoomMainWindow::setZoom(uint zoom)
+{
+ m_zoom = zoom;
+ writeZoomSetting(m_zoom);
+
+ QPtrListIterator<QWidget> it(m_widgets);
+ for (; it.current(); ++it)
+ (*it)->adjustSize();
+
+ m_zoomOutAction->setEnabled( m_zoom > m_minZoom );
+ m_zoomInAction->setEnabled( m_zoom < m_maxZoom );
+}
+
+
+void KZoomMainWindow::zoomIn()
+{
+ setZoom(m_zoom + m_zoomStep);
+}
+
+
+void KZoomMainWindow::zoomOut()
+{
+ Q_ASSERT( m_zoom >= m_zoomStep );
+ setZoom(m_zoom - m_zoomStep);
+}
+
+
+void KZoomMainWindow::toggleMenubar()
+{
+ if ( m_menu->isChecked() )
+ menuBar()->show();
+ else
+ menuBar()->hide();
+}
+
+
+bool KZoomMainWindow::queryExit()
+{
+ writeMenubarVisibleSetting(m_menu->isChecked());
+
+ return KMainWindow::queryExit();
+}
diff --git a/kreversi/kzoommainwindow.h b/kreversi/kzoommainwindow.h
new file mode 100644
index 00000000..dee04139
--- /dev/null
+++ b/kreversi/kzoommainwindow.h
@@ -0,0 +1,138 @@
+/*
+ This file is part of the KDE games library
+ Copyright (C) 2004 Nicolas Hadacek ([email protected])
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef KZOOMMAINWINDOW_H
+#define KZOOMMAINWINDOW_H
+
+
+#include <kmainwindow.h>
+
+
+class KToggleAction;
+
+
+/**
+ * KZoomMainWindow is a main window of fixed size. Its size can be
+ * modified with the "zoom in"/"zoom out" actions.
+ *
+ * It manages one or several widgets: their adjustSize() method is
+ * called whenever the zoom level is changed.
+ * The usual implementation for those widget is to redefine adjustSize()
+ * with code like:
+ * /code
+ * setFixedSize(newsize);
+ * /endcode
+ *
+ * This class also has a "show/hide menubar" action and allows the use
+ * of a context popup menu (useful to restore the menubar when hidden).
+ */
+
+class KZoomMainWindow : public KMainWindow
+{
+ Q_OBJECT
+public:
+ /** Constructor. */
+ KZoomMainWindow(uint minZoom, uint maxZoom, uint zoomStep,
+ const char *name = 0);
+
+ /** Add a widget to be managed i.e. the adjustSize() method of the
+ * widget is called whenever the zoom is changed.
+ * This function assumes that the topLevelWidget() is the KZoomMainWindow.
+ */
+ static void addWidget(QWidget *widget);
+
+ uint zoom() const { return m_zoom; }
+
+public slots:
+ void zoomIn();
+ void zoomOut();
+ void toggleMenubar();
+
+protected:
+ /** You need to call this after the createGUI or setupGUI method
+ * is called.
+ * @param popupName is the name of the context popup menu as defined in
+ * the ui.rc file.
+ */
+ void init(const char *popupName = 0);
+
+ virtual void setZoom(uint zoom);
+ virtual bool eventFilter(QObject *o, QEvent *e);
+ virtual bool queryExit();
+
+ /** You need to implement this method since different application
+ * use different setting class names and keys.
+ * Use something like:
+ * /code
+ * Settings::setZoom(zoom);
+ * Settings::writeConfig();
+ * /endcode
+ */
+ virtual void writeZoomSetting(uint zoom) = 0;
+
+ /** Youneed to implement this method since different application
+ * use different setting class names and keys.
+ * Use something like:
+ * /code
+ * return Settings::zoom();
+ * /endcode
+ */
+ virtual uint readZoomSetting() const = 0;
+
+ /** You need to implement this method since different application
+ * use different setting class names and keys.
+ * Use something like:
+ * /code
+ * Settings::setMenubarVisible(visible);
+ * Settings::writeConfig();
+ * /endcode
+ */
+ virtual void writeMenubarVisibleSetting(bool visible) = 0;
+
+ /** You need to implement this method since different application
+ * use different setting class names and keys.
+ * Use something like:
+ * /code
+ * Settings::menubarVisible();
+ * /endcode
+ */
+ virtual bool menubarVisibleSetting() const = 0;
+
+private slots:
+ void widgetDestroyed();
+
+private:
+ uint m_zoom;
+ uint m_zoomStep;
+ uint m_minZoom;
+ uint m_maxZoom;
+
+ QPtrList<QWidget> m_widgets;
+
+ KAction *m_zoomInAction;
+ KAction *m_zoomOutAction;
+ KToggleAction *m_menu;
+
+ class KZoomMainWindowPrivate;
+ KZoomMainWindowPrivate *d;
+};
+
+
+#endif
diff --git a/kreversi/main.cpp b/kreversi/main.cpp
new file mode 100644
index 00000000..345e97da
--- /dev/null
+++ b/kreversi/main.cpp
@@ -0,0 +1,87 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * created 1997 by Mario Weilguni <[email protected]>
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+
+#include <kapplication.h>
+#include <kimageio.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <khighscore.h>
+
+#include "version.h"
+#include "kreversi.h"
+#include "highscores.h"
+
+
+static const char description[] = I18N_NOOP("KDE Board Game");
+
+int main(int argc, char **argv)
+{
+ KHighscore::init("kreversi");
+
+ KAboutData aboutData( "kreversi", I18N_NOOP("KReversi"),
+ KREVERSI_VERSION, description, KAboutData::License_GPL,
+ "(c) 1997-2000, Mario Weilguni");
+ aboutData.addAuthor("Mario Weilguni",0, "[email protected]");
+ aboutData.addAuthor("Benjamin Meyer",0, "[email protected]");
+ aboutData.addCredit("Mats Luthman", I18N_NOOP("Game engine, ported from his JAVA applet."), 0);
+ aboutData.addCredit("Stephan Kulow", I18N_NOOP("Comments and bugfixes."), 0);
+ aboutData.addCredit("Arne Klaassen", I18N_NOOP("Raytraced chips."), 0);
+ aboutData.addCredit("Inge Wallin", I18N_NOOP("Cleaning, bugfixes, some enhancements."), 0);
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+
+ KApplication a;
+ KGlobal::locale()->insertCatalogue("libkdegames");
+
+ // used for loading background pixmaps
+ KImageIO::registerFormats();
+ KExtHighscore::ExtManager highscores;
+
+ if (a.isRestored()){
+ RESTORE(KReversi)
+ }
+ else {
+ KReversi *kreversi = new KReversi;
+ a.setMainWidget(kreversi);
+ kreversi->show();
+ }
+
+ return a.exec();
+}
+
diff --git a/kreversi/pics/Makefile.am b/kreversi/pics/Makefile.am
new file mode 100644
index 00000000..e962996b
--- /dev/null
+++ b/kreversi/pics/Makefile.am
@@ -0,0 +1,8 @@
+pics_DATA = chips.png chips_mono.png
+
+picsdir = $(kde_datadir)/kreversi/pics
+
+SUBDIRS = background
+
+EXTRA_DIST = $(pics_DATA)
+
diff --git a/kreversi/pics/background/Dark_Wood.png b/kreversi/pics/background/Dark_Wood.png
new file mode 100644
index 00000000..cf487169
--- /dev/null
+++ b/kreversi/pics/background/Dark_Wood.png
Binary files differ
diff --git a/kreversi/pics/background/Earth.png b/kreversi/pics/background/Earth.png
new file mode 100644
index 00000000..fd9d4f82
--- /dev/null
+++ b/kreversi/pics/background/Earth.png
Binary files differ
diff --git a/kreversi/pics/background/Granite.png b/kreversi/pics/background/Granite.png
new file mode 100644
index 00000000..6fd04e93
--- /dev/null
+++ b/kreversi/pics/background/Granite.png
Binary files differ
diff --git a/kreversi/pics/background/Hexagon.png b/kreversi/pics/background/Hexagon.png
new file mode 100644
index 00000000..4a7b3de1
--- /dev/null
+++ b/kreversi/pics/background/Hexagon.png
Binary files differ
diff --git a/kreversi/pics/background/Light_Wood.png b/kreversi/pics/background/Light_Wood.png
new file mode 100644
index 00000000..04877a47
--- /dev/null
+++ b/kreversi/pics/background/Light_Wood.png
Binary files differ
diff --git a/kreversi/pics/background/Makefile.am b/kreversi/pics/background/Makefile.am
new file mode 100644
index 00000000..e106a1f7
--- /dev/null
+++ b/kreversi/pics/background/Makefile.am
@@ -0,0 +1,8 @@
+
+bg_DATA = Dark_Wood.png Granite.png Light_Wood.png Ocean.png Puzzle.png \
+Earth.png Hexagon.png Mystique.png Pipes.png Stones.png
+
+bgdir = $(kde_datadir)/kreversi/pics/background
+
+EXTRA_DIST = $(bg_DATA)
+
diff --git a/kreversi/pics/background/Mystique.png b/kreversi/pics/background/Mystique.png
new file mode 100644
index 00000000..55b9b960
--- /dev/null
+++ b/kreversi/pics/background/Mystique.png
Binary files differ
diff --git a/kreversi/pics/background/Ocean.png b/kreversi/pics/background/Ocean.png
new file mode 100644
index 00000000..6e420d6e
--- /dev/null
+++ b/kreversi/pics/background/Ocean.png
Binary files differ
diff --git a/kreversi/pics/background/Pipes.png b/kreversi/pics/background/Pipes.png
new file mode 100644
index 00000000..111edef0
--- /dev/null
+++ b/kreversi/pics/background/Pipes.png
Binary files differ
diff --git a/kreversi/pics/background/Puzzle.png b/kreversi/pics/background/Puzzle.png
new file mode 100644
index 00000000..4033fd80
--- /dev/null
+++ b/kreversi/pics/background/Puzzle.png
Binary files differ
diff --git a/kreversi/pics/background/Stones.png b/kreversi/pics/background/Stones.png
new file mode 100644
index 00000000..4ba7dc7f
--- /dev/null
+++ b/kreversi/pics/background/Stones.png
Binary files differ
diff --git a/kreversi/pics/chips.png b/kreversi/pics/chips.png
new file mode 100644
index 00000000..5a6ffda6
--- /dev/null
+++ b/kreversi/pics/chips.png
Binary files differ
diff --git a/kreversi/pics/chips_mono.png b/kreversi/pics/chips_mono.png
new file mode 100644
index 00000000..049d8c66
--- /dev/null
+++ b/kreversi/pics/chips_mono.png
Binary files differ
diff --git a/kreversi/prefs.kcfgc b/kreversi/prefs.kcfgc
new file mode 100644
index 00000000..173c0e55
--- /dev/null
+++ b/kreversi/prefs.kcfgc
@@ -0,0 +1,7 @@
+# Code generation options for kconfig_compiler
+File=kreversi.kcfg
+#IncludeFiles=defines.h
+ClassName=Prefs
+Singleton=true
+CustomAdditions=false
+Mutators=skill,Zoom,MenubarVisible
diff --git a/kreversi/qreversigame.cpp b/kreversi/qreversigame.cpp
new file mode 100644
index 00000000..d31bac4a
--- /dev/null
+++ b/kreversi/qreversigame.cpp
@@ -0,0 +1,93 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * created 1997 by Mario Weilguni <[email protected]>
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+
+#include "qreversigame.h"
+
+
+// ================================================================
+// class QReversiGame
+
+
+QReversiGame::QReversiGame(QObject *parent)
+ : QObject(parent), Game()
+{
+}
+
+
+QReversiGame::~QReversiGame()
+{
+}
+
+
+void QReversiGame::newGame()
+{
+ Game::newGame();
+
+ emit sig_newGame();
+}
+
+
+bool QReversiGame::doMove(Move move)
+{
+ bool retval = Game::doMove(move);
+ if (!retval)
+ return false;
+
+ emit sig_move(m_moveNumber, move);
+
+ if (!Game::moveIsAtAllPossible())
+ emit sig_gameOver();
+
+ return retval;
+}
+
+
+bool QReversiGame::undoMove()
+{
+ bool retval = Game::undoMove();
+
+ // Update all views.
+ emit sig_update();
+
+ return retval;
+}
+
+
+#include "qreversigame.moc"
+
diff --git a/kreversi/qreversigame.h b/kreversi/qreversigame.h
new file mode 100644
index 00000000..d1712832
--- /dev/null
+++ b/kreversi/qreversigame.h
@@ -0,0 +1,101 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * created 2005 by Inge Wallin <[email protected]>
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+#ifndef __QREVERSIGAME__H__
+#define __QREVERSIGAME__H__
+
+#include <qwidget.h>
+#include <qpixmap.h>
+
+#include "Position.h"
+#include "Game.h"
+#include "Move.h"
+
+
+class KConfig;
+
+
+
+// The main document class in the reversi program. The thing that
+// makes this a QReversiGame instead of just a ReversiGame is that it
+// emits signals that can be used to update a view.
+//
+// Signals:
+// updateBoard()
+// score()
+// turn(Color)
+// gameOver()
+//
+
+class QReversiGame : public QObject, public Game {
+ Q_OBJECT
+
+ public:
+ QReversiGame(QObject *parent = 0);
+ ~QReversiGame();
+
+ // Methods dealing with the game
+ void newGame();
+ bool doMove(Move move);
+ bool undoMove();
+#if 0
+ void loadSettings();
+
+ bool loadGame(KConfig *, bool noupdate = FALSE);
+ void saveGame(KConfig *);
+#endif
+
+ signals:
+ void sig_newGame();
+ void sig_move(uint, Move&); // A move has just been done.
+ void sig_update(); // Some other change than a move has been done
+ // Example: loadFile(), undoMove();
+ void sig_gameOver(); // The game is over.
+
+ // FIXME: To be removed:
+ //void updateBoard();
+ //void sig_score();
+ //void turn(Color);
+
+private:
+ // No members.
+};
+
+
+#endif
+
diff --git a/kreversi/qreversigameview.cpp b/kreversi/qreversigameview.cpp
new file mode 100644
index 00000000..92812657
--- /dev/null
+++ b/kreversi/qreversigameview.cpp
@@ -0,0 +1,299 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * created 2005 by Inge Wallin <[email protected]>
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+
+#include <qlayout.h>
+#include <qwidget.h>
+#include <qlabel.h>
+
+#include <klocale.h>
+#include <kdialog.h>
+
+#if 0
+#include <unistd.h>
+
+#include <qpainter.h>
+#include <qfont.h>
+
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+#include <knotifyclient.h>
+#include <klocale.h>
+#include <kexthighscore.h>
+#include <kdebug.h>
+
+#include "board.h"
+#include "Engine.h"
+#endif
+#include "prefs.h"
+
+#include "qreversigame.h"
+#include "qreversigameview.h"
+
+
+// ================================================================
+// class StatusWidget
+
+
+StatusWidget::StatusWidget(const QString &text, QWidget *parent)
+ : QWidget(parent, "status_widget")
+{
+ QHBoxLayout *hbox = new QHBoxLayout(this, 0, KDialog::spacingHint());
+ QLabel *label;
+
+ m_textLabel = new QLabel(text, this);
+ hbox->addWidget(m_textLabel);
+
+ m_pixLabel = new QLabel(this);
+ hbox->addWidget(m_pixLabel);
+
+ label = new QLabel(":", this);
+ hbox->addWidget(label);
+
+ m_scoreLabel = new QLabel(this);
+ hbox->addWidget(m_scoreLabel);
+}
+
+
+// Set the text label
+//
+
+void StatusWidget::setText(const QString &string)
+{
+ m_textLabel->setText(string);
+}
+
+
+// Set the pixel label - used to show the color.
+//
+
+void StatusWidget::setPixmap(const QPixmap &pixmap)
+{
+ m_pixLabel->setPixmap(pixmap);
+}
+
+
+// Set the score label - used to write the number of pieces.
+//
+
+void StatusWidget::setScore(uint s)
+{
+ m_scoreLabel->setText(QString::number(s));
+}
+
+
+// ================================================================
+// class QReversiGameView
+
+
+QReversiGameView::QReversiGameView(QWidget *parent, QReversiGame *game)
+ : QWidget(parent, "gameview")
+{
+ // Store a pointer to the game.
+ m_game = game;
+
+ // The widget stuff
+ createView();
+
+ // Other initializations.
+ m_humanColor = Nobody;
+
+ // Connect the game to the view.
+ connect(m_game, SIGNAL(sig_newGame()), this, SLOT(newGame()));
+ connect(m_game, SIGNAL(sig_move(uint, Move&)),
+ this, SLOT(moveMade(uint, Move&)));
+ connect(m_game, SIGNAL(sig_update()), this, SLOT(updateView()));
+ // The sig_gameOver signal is not used by the view.
+
+ // Reemit the signal from the board.
+ connect(m_boardView, SIGNAL(signalSquareClicked(int, int)),
+ this, SLOT(squareClicked(int, int)));
+}
+
+
+QReversiGameView::~QReversiGameView()
+{
+}
+
+
+// Create the entire view. Only called once from the constructor.
+
+void QReversiGameView::createView()
+{
+ QGridLayout *layout = new QGridLayout(this, 4, 2);
+
+ // The board
+ m_boardView = new QReversiBoardView(this, m_game);
+ m_boardView->loadSettings(); // Load the pixmaps used in the status widgets.
+ layout->addMultiCellWidget(m_boardView, 0, 3, 0, 0);
+
+ // The status widgets
+ m_blackStatus = new StatusWidget(QString::null, this);
+ m_blackStatus->setPixmap(m_boardView->chipPixmap(Black, 20));
+ layout->addWidget(m_blackStatus, 0, 1);
+ m_whiteStatus = new StatusWidget(QString::null, this);
+ m_whiteStatus->setPixmap(m_boardView->chipPixmap(White, 20));
+ layout->addWidget(m_whiteStatus, 1, 1);
+
+ // The "Moves" label
+ QLabel *movesLabel = new QLabel( i18n("Moves"), this);
+ movesLabel->setAlignment(AlignCenter);
+ layout->addWidget(movesLabel, 2, 1);
+
+ // The list of moves.
+ m_movesView = new QListBox(this, "moves");
+ m_movesView->setMinimumWidth(150);
+ layout->addWidget(m_movesView, 3, 1);
+}
+
+
+// ----------------------------------------------------------------
+// Slots
+
+
+// Recieves the sig_newGame signal from the game.
+
+void QReversiGameView::newGame()
+{
+ m_boardView->updateBoard(true);
+ m_movesView->clear();
+ updateStatus();
+}
+
+
+// Recieves the sig_move signal from the game.
+
+void QReversiGameView::moveMade(uint moveNum, Move &move)
+{
+ //FIXME: Error checks.
+ QString colorsWB[] = {
+ i18n("White"),
+ i18n("Black")
+ };
+ QString colorsRB[] = {
+ i18n("Red"),
+ i18n("Blue")
+ };
+
+ // Insert the new move in the listbox and mark it as the current one.
+ m_movesView->insertItem(QString("%1. %2 %3")
+ .arg(moveNum)
+ .arg(Prefs::grayscale() ? colorsWB[move.color()]
+ : colorsRB[move.color()])
+ .arg(move.asString()));
+ m_movesView->setCurrentItem(moveNum - 1);
+ m_movesView->ensureCurrentVisible();
+
+ // Animate all changed pieces.
+ m_boardView->animateChanged(move);
+ m_boardView->updateBoard();
+
+ // Update the score.
+ updateStatus();
+}
+
+
+// Recieves the sig_update signal from the game, and can be called
+// whenever a total update of the view is required.
+
+void QReversiGameView::updateView()
+{
+ m_boardView->updateBoard(true);
+ updateMovelist();
+ updateStatus();
+}
+
+
+// Only updates the status widgets (score).
+
+void QReversiGameView::updateStatus()
+{
+ m_blackStatus->setScore(m_game->score(Black));
+ m_whiteStatus->setScore(m_game->score(White));
+}
+
+
+// Only updates the status board.
+
+void QReversiGameView::updateBoard(bool force)
+{
+ m_boardView->updateBoard(force);
+}
+
+
+// Only updates the movelist. This method regenerates the list from
+// scratch.
+
+void QReversiGameView::updateMovelist()
+{
+ // FIXME: NYI
+}
+
+
+// This special slot is just because the external program doesn't have
+// access to the internal board view.
+//
+
+void QReversiGameView::squareClicked(int row, int col)
+{
+ emit signalSquareClicked(row, col);
+}
+
+
+// ----------------------------------------------------------------
+// Other public methods.
+
+
+void QReversiGameView::setHumanColor(Color color)
+{
+ m_humanColor = color;
+
+ if (color == Black) {
+ m_blackStatus->setText(i18n("You"));
+ m_whiteStatus->setText("");
+ }
+ else {
+ m_blackStatus->setText("");
+ m_whiteStatus->setText(i18n("You"));
+ }
+}
+
+
+#include "qreversigameview.moc"
+
diff --git a/kreversi/qreversigameview.h b/kreversi/qreversigameview.h
new file mode 100644
index 00000000..a3059a25
--- /dev/null
+++ b/kreversi/qreversigameview.h
@@ -0,0 +1,160 @@
+/* Yo Emacs, this -*- C++ -*-
+ *******************************************************************
+ *******************************************************************
+ *
+ *
+ * KREVERSI
+ *
+ *
+ *******************************************************************
+ *
+ * A Reversi (or sometimes called Othello) game
+ *
+ *******************************************************************
+ *
+ * created 2005 by Inge Wallin <[email protected]>
+ *
+ *******************************************************************
+ *
+ * This file is part of the KDE project "KREVERSI"
+ *
+ * KREVERSI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * KREVERSI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KREVERSI; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *******************************************************************
+ */
+
+#ifndef __QREVERSIGAMEVIEW__H__
+#define __QREVERSIGAMEVIEW__H__
+
+
+#include <qlistbox.h>
+
+#include "Score.h"
+#include "Move.h"
+#include "board.h"
+
+
+class KConfig;
+
+
+class QLabel;
+
+class QReversiGame;
+
+
+class StatusWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ StatusWidget(const QString &text, QWidget *parent);
+
+ void setText(const QString &string);
+ void setPixmap(const QPixmap &pixmap);
+ void setScore(uint score);
+
+private:
+ QLabel *m_textLabel;
+ QLabel *m_pixLabel;
+ QLabel *m_scoreLabel;
+};
+
+
+// The main game view
+
+class QReversiGameView : public QWidget {
+ Q_OBJECT
+
+public:
+
+ QReversiGameView(QWidget *parent, QReversiGame *game);
+ ~QReversiGameView();
+
+ // Proxy methods for the board view
+ void showHint(Move move) { m_boardView->showHint(move); }
+ void quitHint() { m_boardView->quitHint(); }
+
+ void setShowLegalMoves(bool show){ m_boardView->setShowLegalMoves(show); }
+ void setShowMarks(bool show) { m_boardView->setShowMarks(show); }
+ void setShowLastMove(bool show){ m_boardView->setShowLastMove(show); }
+
+ void setAnimationSpeed(uint speed){m_boardView->setAnimationSpeed(speed);}
+
+ // To get the pixmap for the status view
+ QPixmap chipPixmap(Color color, uint size) const
+ { return m_boardView->chipPixmap(color, size); }
+
+ // Proxy methods for the movelist
+ // FIXME: Not all of these need to be externally reachable
+ void insertMove(QString moveString) { m_movesView->insertItem(moveString); }
+ void removeMove(int moveNum) {
+ m_movesView->removeItem(moveNum);
+ updateStatus();
+ }
+ void setCurrentMove(int moveNum) {
+ m_movesView->setCurrentItem(moveNum);
+ m_movesView->ensureCurrentVisible();
+ }
+
+ // The status widgets.
+ void setHumanColor(Color color);
+
+ // Starts all: emits some signal, so it can't be called from
+ // constructor
+ void start() { m_boardView->start(); }
+
+ // Used by the outer KZoomMainWindow class.
+ void adjustSize() { m_boardView->adjustSize(); }
+
+ void loadSettings() { m_boardView->loadSettings(); }
+
+
+public slots:
+ void newGame();
+ void moveMade(uint moveNum, Move &move);
+
+ void updateView(); // Update the entire view.
+ void updateStatus(); // Update the status widgets (score)
+ void updateBoard(bool force = FALSE); // Update the board.
+ void updateMovelist(); // Update the move list.
+
+signals:
+ void signalSquareClicked(int, int);
+
+private slots:
+ // Internal slot to reemit the boards signal.
+ void squareClicked(int, int);
+
+private:
+ void createView();
+
+private:
+
+ // Pointer to the game we are displaying
+ QReversiGame *m_game; // Pointer to the game object (not owner).
+
+ Color m_humanColor;
+
+ // Widgets in the view.
+ QReversiBoardView *m_boardView;
+ QListBox *m_movesView;
+ StatusWidget *m_blackStatus;
+ StatusWidget *m_whiteStatus;
+};
+
+
+#endif
+
diff --git a/kreversi/settings.ui b/kreversi/settings.ui
new file mode 100644
index 00000000..b7c59ff5
--- /dev/null
+++ b/kreversi/settings.ui
@@ -0,0 +1,329 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>Settings</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Settings</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>431</width>
+ <height>323</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="4" column="0">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>kcfg_Grayscale</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Grayscale chips</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="0" column="1" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>kcfg_CompetitiveGameChoice</cstring>
+ </property>
+ <property name="title">
+ <string>Play Game</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>CasualGameChoice</cstring>
+ </property>
+ <property name="text">
+ <string>Casually</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>CompetitiveGameChoice</cstring>
+ </property>
+ <property name="text">
+ <string>Competitively</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox" row="2" column="1">
+ <property name="name">
+ <cstring>skillGroup</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Computer Skill</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSlider" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>kcfg_skill</cstring>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="maxValue">
+ <number>7</number>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>NoMarks</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>Beginner</cstring>
+ </property>
+ <property name="text">
+ <string>Beginner</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignLeft</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>Expert</cstring>
+ </property>
+ <property name="text">
+ <string>Expert</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>Average</cstring>
+ </property>
+ <property name="text">
+ <string>Average</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="2" column="0">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Animation Speed</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Slow</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignLeft</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Fast</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QSlider" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_AnimationSpeed</cstring>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="maxValue">
+ <number>10</number>
+ </property>
+ <property name="lineStep">
+ <number>1</number>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>NoMarks</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>kcfg_Animation</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Animation</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_BackgroundImageChoice</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Background</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>BackgroundColorChoice</cstring>
+ </property>
+ <property name="text">
+ <string>Color:</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_BackgroundImage</cstring>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>BackgroundImageChoice</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Image:</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_BackgroundColor</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>kcfg_Animation</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>groupBox2</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>BackgroundColorChoice</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_BackgroundColor</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>BackgroundImageChoice</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_BackgroundImage</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kreversi/sounds/Makefile.am b/kreversi/sounds/Makefile.am
new file mode 100644
index 00000000..83348417
--- /dev/null
+++ b/kreversi/sounds/Makefile.am
@@ -0,0 +1,7 @@
+soundsdir = $(kde_datadir)/kreversi/sounds
+sounds_DATA = reversi-click.wav reversi-won.wav
+
+EXTRA_DIST = $(sounds_DATA)
+
+appdatadir = $(kde_datadir)/kreversi
+appdata_DATA = eventsrc \ No newline at end of file
diff --git a/kreversi/sounds/eventsrc b/kreversi/sounds/eventsrc
new file mode 100644
index 00000000..cc525204
--- /dev/null
+++ b/kreversi/sounds/eventsrc
@@ -0,0 +1,566 @@
+[!Global!]
+IconName=kreversi
+Comment=KReversi
+Comment[be]=Рэверсі
+Comment[bn]=কে-রিভার্সি
+Comment[ca]=Reversi
+Comment[is]=Viðsnúningur
+Comment[ne]=केडीई रिभर्सी
+Comment[sv]=Othello
+Comment[zh_TW]=KReversi 黑白棋
+
+[click]
+Name=Click
+Name[be]=Пстрычка
+Name[bg]=Щракване
+Name[bn]=ক্লিক
+Name[br]=Klik
+Name[bs]=Klikni
+Name[ca]=Clic
+Name[cs]=Kliknutí
+Name[cy]=Clicio
+Name[da]=Klik
+Name[de]=Klick
+Name[el]=Κλικ
+Name[eo]=Kliki
+Name[es]=Clic
+Name[et]=Klõps
+Name[eu]=Klikatu
+Name[fa]=فشار
+Name[fi]=Napsauta
+Name[fr]=Clic
+Name[ga]=Cliceáil
+Name[he]=לחיצה
+Name[hr]=Klik
+Name[hu]=Kattintás
+Name[is]=Smella
+Name[it]=Clic
+Name[ja]=クリック
+Name[km]=ចុច
+Name[ko]=클릭
+Name[lt]=Paspausti
+Name[lv]=Klikšķis
+Name[mk]=Кликање
+Name[nb]=Klikk
+Name[nds]=Klick
+Name[ne]=क्लिक गर्नुहोस्
+Name[nl]=Klik
+Name[nn]=Klikk
+Name[pa]=ਦਬਾਓ
+Name[pl]=Dobierz
+Name[pt]=Carregar
+Name[pt_BR]=Clicar
+Name[ru]=Щелчок
+Name[se]=Coahkkal
+Name[sk]=Kliknutie
+Name[sl]=Klik
+Name[sr]=Кликни
+Name[sr@Latn]=Klikni
+Name[sv]=Klick
+Name[ta]=சொடுக்கு
+Name[tg]=Ангуштзанӣ
+Name[tr]=Tık
+Name[uk]=Клац
+Name[zh_CN]=单击
+Name[zh_TW]=點選
+Comment=Click
+Comment[be]=Пстрычка
+Comment[bg]=Щракване
+Comment[bn]=ক্লিক
+Comment[br]=Klik
+Comment[bs]=Klik
+Comment[ca]=Clic
+Comment[cs]=Kliknutí
+Comment[cy]=Clicio
+Comment[da]=Klik
+Comment[de]=Klick
+Comment[el]=Κλικ
+Comment[eo]=Kliki
+Comment[es]=Pulsación
+Comment[et]=Klõps
+Comment[eu]=Klikatu
+Comment[fa]=فشار
+Comment[fi]=Napsauta
+Comment[fr]=Clic
+Comment[ga]=Cliceáil
+Comment[he]=לחיצה
+Comment[hr]=Klik
+Comment[hu]=Kattintás
+Comment[is]=Smella
+Comment[it]=Clic
+Comment[ja]=クリック
+Comment[km]=ចុច
+Comment[lt]=Paspausti
+Comment[lv]=Klikšķis
+Comment[mk]=Вртење
+Comment[nb]=Klikk
+Comment[nds]=Klick
+Comment[ne]=क्लिक गर्नुहोस्
+Comment[nl]=Klik
+Comment[nn]=Klikk
+Comment[pa]=ਦਬਾਓ
+Comment[pl]=Kliknięcie
+Comment[pt]=Carregar
+Comment[pt_BR]=Clicar
+Comment[ru]=Щелчок
+Comment[se]=Coahkkal
+Comment[sk]=Kliknutie
+Comment[sl]=Klik
+Comment[sr]=Кликни
+Comment[sr@Latn]=Klikni
+Comment[sv]=Klick
+Comment[ta]=சொடுக்கு
+Comment[tg]=Ангушт задан
+Comment[tr]=Tık
+Comment[uk]=Клац
+Comment[zh_CN]=单击
+Comment[zh_TW]=點選
+default_presentation=1
+default_sound=reversi-click.wav
+
+[won]
+Name=Game won
+Name[ar]=ربحت اللعبة
+Name[be]=Перамога
+Name[bg]=Спечелихте
+Name[bn]=খেলা জিতেছেন
+Name[br]=Gounezet eo ar c'hoari
+Name[bs]=Pobjeda
+Name[ca]=Partida guanyada
+Name[cs]=Vyhraná hra
+Name[cy]=Gêm wedi ei ennill
+Name[da]=Spillet vundet
+Name[de]=Spiel gewonnen
+Name[el]=Παιχνίδι κερδήθηκε
+Name[eo]=Ludo venkita
+Name[es]=Partida ganada
+Name[et]=Mäng läbi, sina võitsid
+Name[eu]=Jokoa irabazi da
+Name[fa]=برد بازی
+Name[fi]=Peli voitettu
+Name[fr]=Partie gagnée
+Name[gl]=Xogo gañado
+Name[he]=ניצחת!
+Name[hi]=खेल में जीत हुई
+Name[hr]=Igra je dobivena
+Name[hu]=Győzelem
+Name[is]=Leikur unninn
+Name[it]=Partita vinta
+Name[ja]=ゲームに勝ち
+Name[km]=ល្បែង​បាន​ឈ្នះ
+Name[ko]=게임에서 이김
+Name[lt]=Žaidimas laimėtas
+Name[lv]=Spēle uzvarēta
+Name[mk]=Играта е добиена
+Name[nb]=Du vant
+Name[nds]=Speel wunnen
+Name[ne]=खेल जित्नु भयो
+Name[nl]=Spel gewonnen
+Name[nn]=Du vann
+Name[pa]=ਖੇਡ ਜਿੱਤੀ
+Name[pl]=Gra wygrana
+Name[pt]=Jogo ganho
+Name[pt_BR]=Jogo ganho
+Name[ro]=Joc cîştigat
+Name[ru]=Победа
+Name[se]=Don vuitet
+Name[sk]=Vyhraná hra
+Name[sl]=Igra je dobljena
+Name[sr]=Игра је добијена
+Name[sr@Latn]=Igra je dobijena
+Name[sv]=Du vann spelet
+Name[ta]=ஆட்டம் ஜெயிக்கப்பட்டது
+Name[tg]=Дар бозӣ ғолиб омадед
+Name[tr]=Oyun kazanıldı
+Name[uk]=Гру виграно
+Name[wa]=Djeu wangnî
+Name[zh_CN]=您赢了游戏
+Name[zh_TW]=遊戲獲勝
+Comment=Game won
+Comment[ar]=ربحت اللعبة
+Comment[be]=Перамога
+Comment[bg]=Спечелихте
+Comment[bn]=খেল খতম
+Comment[br]=Gounezet eo ar c'hoari
+Comment[bs]=Pobjeda
+Comment[ca]=Partida guanyada
+Comment[cs]=Vyhraná hra
+Comment[cy]=Gêm wedi ei ennill
+Comment[da]=Spil vundet
+Comment[de]=Spiel gewonnen
+Comment[el]=Παιχνίδι κερδήθηκε
+Comment[eo]=Ludo venkita
+Comment[es]=Partida ganada
+Comment[et]=Mäng läbi, sina võitsid
+Comment[eu]=Jokoa irabazi da
+Comment[fa]=برد بازی
+Comment[fi]=Peli voitettu
+Comment[fr]=Partie gagnée
+Comment[gl]=Xogo gañado
+Comment[he]=ניצחת!
+Comment[hi]=खेल में जीत हुई
+Comment[hr]=Igra je dobivena
+Comment[hu]=Győzelem
+Comment[is]=Leikur unninn
+Comment[it]=Partita vinta
+Comment[ja]=ゲームに勝ち
+Comment[km]=ល្បែង​បាន​ឈ្នះ
+Comment[ko]=게임에서 이김
+Comment[lt]=Žaidimas laimėtas
+Comment[lv]=Spēle ir uzvarēta
+Comment[mk]=Играта е добиена
+Comment[nb]=Du vant!
+Comment[nds]=Speel wunnen
+Comment[ne]=खेल जित्नु भयो
+Comment[nl]=Spel gewonnen
+Comment[nn]=Du vann
+Comment[pa]=ਖੇਡ ਜਿੱਤੀ
+Comment[pl]=Gra wygrana
+Comment[pt]=Jogo ganho
+Comment[pt_BR]=Jogo ganho
+Comment[ro]=Joc cîştigat
+Comment[ru]=Победа
+Comment[se]=Don vuitet
+Comment[sk]=Vyhraná hra
+Comment[sl]=Igra je dobljena
+Comment[sr]=Игра је добијена
+Comment[sr@Latn]=Igra je dobijena
+Comment[sv]=Du vann spelet
+Comment[ta]=ஆட்டம் ஜெயிக்கப்பட்டது
+Comment[tg]=Дар бозӣ ғолиб омадед
+Comment[tr]=Oyun kazanıldı
+Comment[uk]=Гру виграно
+Comment[wa]=Djeu wangnî
+Comment[zh_CN]=您赢了游戏
+Comment[zh_TW]=遊戲獲勝
+default_presentation=1
+default_sound=reversi-won.wav
+
+[lost]
+Name=Game lost
+Name[ar]=خسرت اللعبة
+Name[be]=Параза
+Name[bg]=Загубихте
+Name[bn]=খেলায় হেরে গিয়েছেন
+Name[br]=Kollet eo ar c'hoari
+Name[bs]=Poraz
+Name[ca]=Partida perduda
+Name[cs]=Prohraná hra
+Name[cy]=Gêm wedi ei golli
+Name[da]=Spil tabt
+Name[de]=Spiel verloren
+Name[el]=Παιχνίδι χάθηκε
+Name[eo]=Ludo malvenkita
+Name[es]=Partida perdida
+Name[et]=Mäng läbi, sina kaotasid
+Name[eu]=Jokoa galdu da
+Name[fa]=باخت بازی
+Name[fi]=Peli hävitty
+Name[fr]=Partie perdue
+Name[gl]=Xogo perdido
+Name[he]=המשחק הסתיים, הפסדת
+Name[hi]=खेल में हार हुई
+Name[hr]=Igra je izgubljena
+Name[hu]=Vereség
+Name[is]=Leik tapað
+Name[it]=Partita persa
+Name[ja]=ゲームに負け
+Name[km]=ល្បែង​បាន​ចាញ់
+Name[ko]=게임에서 짐
+Name[lt]=Žaidimas pralaimėtas
+Name[lv]=Spēle zaudēta
+Name[mk]=Играта е изгубена
+Name[nb]=Du tapte
+Name[nds]=Speel verloren
+Name[ne]=खेल हार्नु भयो
+Name[nl]=Spel verloren
+Name[nn]=Du tapte
+Name[pa]=ਖੇਡ ਹਾਰੀ
+Name[pl]=Koniec gry, przegrałeś
+Name[pt]=Jogo perdido
+Name[pt_BR]=Jogo perdido
+Name[ro]=Joc pierdut
+Name[ru]=Поражение
+Name[se]=Don vuoittohallet
+Name[sk]=Prehraná hra
+Name[sl]=Igra je izgubljena
+Name[sr]=Игра је изгубљена
+Name[sr@Latn]=Igra je izgubljena
+Name[sv]=Du förlorade spelet
+Name[ta]=ஆட்டம் இழக்கப்பட்டது
+Name[tg]=Дар бозӣ мағлуб шудед
+Name[tr]=Oyun kaybedildi
+Name[uk]=Гра програна
+Name[wa]=Djeu pierdou
+Name[zh_CN]=您输了游戏
+Name[zh_TW]=遊戲失敗
+Comment=Game lost
+Comment[ar]=خسرت اللعبة
+Comment[be]=Параза
+Comment[bg]=Загубихте
+Comment[bn]=খেলায় হেরে গিয়েছেন
+Comment[br]=Koll eo ar c'hoari
+Comment[bs]=Poraz
+Comment[ca]=Partida perduda
+Comment[cs]=Prohraná hra
+Comment[cy]=Gêm wedi ei golli
+Comment[da]=Spil tabt
+Comment[de]=Spiel verloren
+Comment[el]=Παιχνίδι χάθηκε
+Comment[eo]=Ludo malvenkita
+Comment[es]=Partida perdida
+Comment[et]=Mäng läbi, sina kaotasid
+Comment[eu]=Jokoa galdu da
+Comment[fa]=باخت بازی
+Comment[fi]=Peli hävitty
+Comment[fr]=Partie perdue
+Comment[gl]=Xogo perdido
+Comment[he]=המשחק הסתיים, הפסדת
+Comment[hi]=खेल में हार हुई
+Comment[hr]=Igra je izgubljena
+Comment[hu]=Vereség
+Comment[is]=Leik tapað
+Comment[it]=Partita persa
+Comment[ja]=ゲームに負け
+Comment[km]=ល្បែង​បាន​ចាញ់
+Comment[ko]=게임에서 짐
+Comment[lt]=Žaidimas pralaimėtas
+Comment[lv]=Spēle ir zaudēta
+Comment[mk]=Играта е изубена
+Comment[nb]=Du tapte
+Comment[nds]=Speel verloren
+Comment[ne]=खेल हार्नु भयो
+Comment[nl]=Spel verloren
+Comment[nn]=Du tapte
+Comment[pa]=ਖੇਡ ਹਾਰੀ
+Comment[pl]=Koniec gry, przegrałeś
+Comment[pt]=Jogo perdido
+Comment[pt_BR]=Jogo perdido
+Comment[ro]=Joc pierdut
+Comment[ru]=Поражение
+Comment[se]=Don vuoittohallet
+Comment[sk]=Prehraná hra
+Comment[sl]=Igra je izgubljena
+Comment[sr]=Игра је изгубљена
+Comment[sr@Latn]=Igra je izgubljena
+Comment[sv]=Du förlorade spelet
+Comment[ta]=ஆட்டம் இழக்கப்பட்டது
+Comment[tg]=Дар бозӣ мағлуб шудед
+Comment[tr]=Oyun kaybedildi
+Comment[uk]=Гра програна
+Comment[wa]=Djeu pierdou
+Comment[zh_CN]=您输了游戏
+Comment[zh_TW]=遊戲失敗
+default_presentation=0
+
+[draw]
+Name=Draw
+Name[be]=Нічыя
+Name[bg]=Равенство
+Name[bn]=অমীমাংসিত
+Name[br]=Tresañ
+Name[bs]=Crtaj
+Name[ca]=Empat
+Name[cs]=Remíza
+Name[cy]=Arlunio
+Name[da]=Træk
+Name[de]=Ziehen
+Name[el]=Ισοπαλία
+Name[eo]=Egaliĝo
+Name[es]=Dibujar
+Name[et]=Viik
+Name[eu]=Berdinketa
+Name[fa]=قرعه‌کشی
+Name[fi]=Tasapeli
+Name[fr]=Égalité
+Name[ga]=Tarraing
+Name[he]=תיקו
+Name[hr]=Crtanje
+Name[hu]=Döntetlen
+Name[is]=Jafntefli
+Name[it]=Pari
+Name[ja]=引き分け
+Name[km]=គូស
+Name[ko]=비김
+Name[lt]=Piešti
+Name[lv]=Vilkt
+Name[mk]=Нерешено
+Name[nb]=Uavgjort
+Name[nds]=Trecken
+Name[ne]=कोर्नुहोस्
+Name[nl]=Tekenen
+Name[nn]=Uavgjort
+Name[pa]=ਬਰਾਬਰ
+Name[pl]=Rysuj
+Name[pt]=Empate
+Name[pt_BR]=Empate
+Name[ru]=Ничья
+Name[sk]=Remíza
+Name[sl]=Poteg
+Name[sr]=Вуци
+Name[sr@Latn]=Vuci
+Name[sv]=Oavgjort
+Name[ta]=வரை
+Name[tg]=Кашидан
+Name[tr]=Berabere
+Name[uk]=Нічия
+Name[zh_CN]=平局
+Name[zh_TW]=平手
+Comment=Draw
+Comment[be]=Нічыя
+Comment[bg]=Равенство
+Comment[bn]=অমীমাংসিত
+Comment[br]=Tresañ
+Comment[bs]=Crtaj
+Comment[ca]=Empat
+Comment[cs]=Remíza
+Comment[cy]=Arlunio
+Comment[da]=Træk
+Comment[de]=Ziehen
+Comment[el]=Ισοπαλία
+Comment[eo]=Egaliĝo
+Comment[es]=Dibujar
+Comment[et]=Viik
+Comment[eu]=Berdinketa
+Comment[fa]=قرعه‌کشی
+Comment[fi]=Tasapeli
+Comment[fr]=Égalité
+Comment[ga]=Tarraing
+Comment[he]=תיקו
+Comment[hr]=Crtanje
+Comment[hu]=Döntetlen
+Comment[is]=Jafntefli
+Comment[it]=Pari
+Comment[ja]=引き分け
+Comment[km]=គូស
+Comment[lt]=Piešti
+Comment[lv]=Vilkt
+Comment[mk]=Нерешено
+Comment[nb]=Uavgjort
+Comment[nds]=Trecken
+Comment[ne]=कोर्नुहोस्
+Comment[nl]=Tekenen
+Comment[nn]=Uavgjort
+Comment[pa]=ਬਰਾਬਰ
+Comment[pl]=Dobranie karty
+Comment[pt]=Empate
+Comment[pt_BR]=Empate
+Comment[ru]=Ничья
+Comment[sk]=Remíza
+Comment[sl]=Poteg
+Comment[sr]=Вуци
+Comment[sr@Latn]=Vuci
+Comment[sv]=Oavgjort
+Comment[ta]=வரை
+Comment[tg]=Кашидан
+Comment[tr]=Beraberlik
+Comment[uk]=нічия
+Comment[zh_CN]=平局
+Comment[zh_TW]=平手
+default_presentation=0
+
+[illegal_move]
+Name=Illegal Move
+Name[be]=Няправільны ход
+Name[bg]=Невалиден ход
+Name[bn]=অবৈধ চাল
+Name[bs]=Nedozvoljen potez
+Name[ca]=Moviment il·legal
+Name[cs]=Neplatný tah
+Name[cy]=Symudiad Angyfreithlon
+Name[da]=Ulovligt træk
+Name[de]=Unerlaubter Zug
+Name[el]=Μη έγκυρη κίνηση
+Name[eo]=Nepermesita movo
+Name[es]=Movimiento ilegal
+Name[et]=Lubamatu käik
+Name[eu]=Legez kanpoko mugimendua
+Name[fa]=حرکت غیر مجاز
+Name[fi]=Laiton siirto
+Name[fr]=Déplacement interdit
+Name[ga]=Beart Neamhcheadaithe
+Name[he]=מהלך לא חוקי
+Name[hr]=Nepravilan potez
+Name[hu]=Szabálytalan lépés
+Name[is]=Ógildur leikur
+Name[it]=Mossa non lecita
+Name[ja]=不正な移動
+Name[km]=ការ​ផ្លាស់ទី​មិន​ត្រឹមត្រូវ
+Name[ko]=잘못된 움직임
+Name[lt]=Negalimas ėjimas
+Name[lv]=Nelegāls gājiens
+Name[mk]=Недозволен потег
+Name[nb]=Ugyldig trekk
+Name[nds]=Tog nich verlöövt
+Name[ne]=अवैध चाल
+Name[nl]=Foutieve zet
+Name[nn]=Ugyldig trekk
+Name[pa]=ਗਲਤ ਚਾਲ
+Name[pl]=Nieprawidłowy ruch
+Name[pt]=Jogada Inválida
+Name[pt_BR]=Movimento Ilegal
+Name[ru]=Неправильный ход
+Name[se]=Gustohis sirdin
+Name[sk]=Neplatný ťah
+Name[sl]=Neveljavna poteza
+Name[sr]=Недозвољен потез
+Name[sr@Latn]=Nedozvoljen potez
+Name[sv]=Felaktigt drag
+Name[ta]=நிகழ்ச்சியை வெளிப்படுத்து
+Name[tg]=Ҳаракати Нодуруст
+Name[tr]=Gecersiz Hamle
+Name[uk]=Недозволений хід
+Name[zh_CN]=无效移动
+Name[zh_TW]=不合法的移動
+Comment=Illegal move
+Comment[be]=Няправільны ход
+Comment[bg]=Невалиден ход
+Comment[bn]=অবৈধ চাল
+Comment[bs]=Nedozvoljen potez
+Comment[ca]=Moviment il·legal
+Comment[cs]=Neplatný tah
+Comment[cy]=Symudiad angyfreithlon
+Comment[da]=Ulovligt træk
+Comment[de]=Unerlaubter Zug
+Comment[el]=Μη έγκυρη κίνηση
+Comment[eo]=Nepermesita movo
+Comment[es]=Movimiento ilegal
+Comment[et]=Lubamatu käik
+Comment[eu]=Legez kanpoko mugimendua
+Comment[fa]=حرکت غیر مجاز
+Comment[fi]=Laiton siirto
+Comment[fr]=Déplacement interdit
+Comment[ga]=Beart neamhcheadaithe
+Comment[he]=מהלך לא חוקי
+Comment[hr]=Nepravilan potez
+Comment[hu]=Szabálytalan lépés
+Comment[is]=Ógildur leikur
+Comment[it]=Mossa non lecita
+Comment[ja]=不正な移動
+Comment[km]=ការ​ផ្លាស់ទី​មិន​ត្រឹមត្រូវ
+Comment[ko]=잘못된 움직임
+Comment[lt]=Negalimas ėjimas
+Comment[lv]=Šāds gājiens nav atļauts
+Comment[mk]=Недозволен потег
+Comment[nb]=Ugyldig trekk
+Comment[nds]=Tog nich verlöövt
+Comment[ne]=अवैध चाल
+Comment[nl]=Foutieve zet
+Comment[nn]=Ugyldig trekk
+Comment[pa]=ਗਲਤ ਚਾਲ
+Comment[pl]=Nieprawidłowy ruch
+Comment[pt]=Jogada inválida
+Comment[pt_BR]=Movimento ilegal
+Comment[ru]=Неправильный ход
+Comment[se]=Gustohis sirdin
+Comment[sk]=Neplatný ťah
+Comment[sl]=Neveljavna poteza
+Comment[sr]=Недозвољен потез
+Comment[sr@Latn]=Nedozvoljen potez
+Comment[sv]=Felaktigt drag
+Comment[ta]=தவறான நகர்த்தல்
+Comment[tr]=Geçersiz hamle
+Comment[uk]=Недозволений хід
+Comment[zh_CN]=无效移动
+Comment[zh_TW]=不合法的移動
+default_presentation=0
diff --git a/kreversi/sounds/reversi-click.wav b/kreversi/sounds/reversi-click.wav
new file mode 100644
index 00000000..0b3a2964
--- /dev/null
+++ b/kreversi/sounds/reversi-click.wav
Binary files differ
diff --git a/kreversi/sounds/reversi-won.wav b/kreversi/sounds/reversi-won.wav
new file mode 100644
index 00000000..8f5c0703
--- /dev/null
+++ b/kreversi/sounds/reversi-won.wav
Binary files differ
diff --git a/kreversi/version.h b/kreversi/version.h
new file mode 100644
index 00000000..d95b83ed
--- /dev/null
+++ b/kreversi/version.h
@@ -0,0 +1 @@
+#define KREVERSI_VERSION "1.7.1"