Import Upstream version 22.08.3

This commit is contained in:
rtlhq 2022-11-26 12:04:08 +08:00
commit 6106f22f9e
162 changed files with 25890 additions and 0 deletions

13
.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
# SPDX-License-Identifier: CC0-1.0
# SPDX-FileCopyrightText: none
.kdev4/
/build*/
*.kdev4
CMakeLists.txt.user*
.cmake/
/.clang-format
/compile_commands.json
.clangd
.cache
.idea
/cmake-build*

7
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: None
# SPDX-License-Identifier: CC0-1.0
include:
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows.yml

15
.kde-ci.yml Normal file
View File

@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: None
# SPDX-License-Identifier: CC0-1.0
Dependencies:
- 'on': ['@all']
'require':
'frameworks/extra-cmake-modules': '@stable'
'games/libkdegames': '@same'
'frameworks/kcoreaddons': '@stable'
'frameworks/kcrash': '@stable'
'frameworks/kdbusaddons': '@stable'
'frameworks/kdoctools': '@stable'
'frameworks/kxmlgui': '@stable'
Options:
require-passing-tests-on: [ 'Linux', 'FreeBSD']

6
AUTHORS Normal file
View File

@ -0,0 +1,6 @@
Orignal Author:
Aron Boström <aron.bostrom@gmail.com> (irc: hrafnahnef @ freenode)
Maintainer:
Pelladi Gabor <pelladigabor@gmail.com>

150
CMakeLists.txt Normal file
View File

@ -0,0 +1,150 @@
cmake_minimum_required (VERSION 3.16 FATAL_ERROR)
# KDE Application Version, managed by release script
set(RELEASE_SERVICE_VERSION_MAJOR "22")
set(RELEASE_SERVICE_VERSION_MINOR "08")
set(RELEASE_SERVICE_VERSION_MICRO "3")
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
project(bovo VERSION ${RELEASE_SERVICE_VERSION})
set (QT_MIN_VERSION "5.15.0")
set (KF5_MIN_VERSION "5.90.0")
find_package(ECM ${KF5_MIN_VERSION} REQUIRED CONFIG)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} )
include(KDEInstallDirs)
find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Widgets Svg Concurrent)
if (QT_MAJOR_VERSION STREQUAL "6")
find_package(Qt6SvgWidgets)
endif()
find_package(Qt${QT_MAJOR_VERSION}QuickWidgets ${REQUIRED_QT_VERSION} CONFIG)
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
CoreAddons
Crash
DBusAddons
DocTools
XmlGui
)
find_package(KF5KDEGames 4.9.0 REQUIRED)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(FeatureSummary)
include(ECMInstallIcons)
include(ECMSetupVersion)
include(ECMAddAppIcon)
include(KDEGitCommitHooks)
include(KDEClangFormat)
file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h *.c)
kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES})
# re-enabling exceptions (turned off in KDE)
kde_enable_exceptions()
#add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050f02)
add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x055900)
# Force c++11 as random_shuffle is removed in freebsd c++17
set(CMAKE_CXX_STANDARD 11)
set( bovogame_SRCS
game/game.cc
game/board.cc
game/dimension.cc
game/coord.cc
game/square.cc
game/move.cc )
set( bovoai_SRCS
ai/ai.cc
ai/aifactory.cc
ai/aron/aiaron.cc
ai/aron/aiboard.cc
ai/aron/aisquare.cc
ai/gabor/aigabor.cc
ai/gabor/standing.cpp
ai/gabor/node.cpp
ai/gabor/ai_interface.cpp
ai/gabor/ai_impl.cpp )
set(bovogui_SRCS
gui/hintitem.cc
gui/mark.cc
gui/theme.cc
gui/scene.cc
gui/view.cc
gui/mainwindow.cc
gui/main.cc
)
ecm_setup_version(${RELEASE_SERVICE_VERSION} VARIABLE_PREFIX BOVO VERSION_HEADER bovo_version.h)
set(bovo_SRCS
${bovogui_SRCS}
${bovoai_SRCS}
${bovogame_SRCS}
gui/mainwindow.h
gui/mark.h
gui/hintitem.h
gui/view.h
gui/theme.h
gui/scene.h
ai/gabor/ai_impl.h
ai/gabor/ai_interface.h
ai/gabor/aigabor.h
ai/gabor/node.h
ai/gabor/standing.h
ai/ai.h
ai/aifactory.h
ai/aron/aiboard.h
ai/aron/aiaron.h
ai/aron/aisquare.h
game/board.h
game/coord.h
game/game.h
game/square.h
game/dimension.h
game/common.h
game/move.h
bovo.qrc
)
include_directories(
${CMAKE_SOURCE_DIR}/game
${CMAKE_SOURCE_DIR}/gui
${CMAKE_SOURCE_DIR}/ai
)
kconfig_add_kcfg_files(bovo_SRCS gui/settings.kcfgc)
file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/*-apps-bovo.png")
ecm_add_app_icon(bovo_SRCS ICONS ${ICONS_SRCS})
add_executable(bovo ${bovo_SRCS})
target_link_libraries(bovo
KF5::CoreAddons
KF5::XmlGui
KF5::I18n
KF5KDEGames
KF5::DBusAddons
KF5::Crash
Qt${QT_MAJOR_VERSION}::Svg
Qt${QT_MAJOR_VERSION}::Concurrent
)
if (QT_MAJOR_VERSION STREQUAL "6")
target_link_libraries(bovo Qt6::SvgWidgets)
endif()
add_subdirectory (themes)
add_subdirectory (icons)
add_subdirectory (doc)
ki18n_install(po)
kdoctools_install(po)
install (TARGETS bovo ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
install (PROGRAMS org.kde.bovo.desktop DESTINATION ${KDE_INSTALL_APPDIR})
install (FILES org.kde.bovo.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT)

83
CMakePresets.json Normal file
View File

@ -0,0 +1,83 @@
{
"version": 2,
"configurePresets": [
{
"name": "dev",
"displayName": "Build as debug",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "asan",
"displayName": "Build with Asan support.",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-asan",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"ECM_ENABLE_SANITIZERS" : "'address;undefined'",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "unity",
"displayName": "Build with CMake unity support.",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-unity",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_UNITY_BUILD": "ON",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "release",
"displayName": "Build as release mode.",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "profile",
"displayName": "profile",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-profile",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "clazy",
"displayName": "clazy",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-clazy",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"environment": {
"CXX": "clazy",
"CCACHE_DISABLE": "ON"
}
}
],
"buildPresets": [
{
"name": "dev",
"configurePreset": "dev"
},
{
"name": "clazy",
"configurePreset": "clazy",
"environment": {
"CLAZY_CHECKS" : "level0,level1,detaching-member,ifndef-define-typo,isempty-vs-count,qrequiredresult-candidates,reserve-candidates,signal-with-return-value,unneeded-cast,function-args-by-ref,function-args-by-value,returning-void-expression,no-ctor-missing-parent-argument,isempty-vs-count,qhash-with-char-pointer-key,raw-environment-function,qproperty-type-mismatch,old-style-connect,qstring-allocations,container-inside-loop,heap-allocated-small-trivial-type,inefficient-qlist,qstring-varargs,level2,detaching-member,heap-allocated-small-trivial-type,isempty-vs-count,qstring-varargs,qvariant-template-instantiation,raw-environment-function,reserve-candidates,signal-with-return-value,thread-with-slots,no-ctor-missing-parent-argument,no-missing-typeinfo",
"CCACHE_DISABLE" : "ON"
}
}
]
}

View File

@ -0,0 +1,2 @@
# SPDX-FileCopyrightText: 2021 Laurent Montel <montel@kde.org>
# SPDX-License-Identifier: BSD-3-Clause

347
COPYING Normal file
View File

@ -0,0 +1,347 @@
NOTE! The GPL below is copyrighted by the Free Software Foundation, but
the instance of code that it refers to (the kde programs) are copyrighted
by the authors who actually wrote it.
---------------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

397
COPYING.DOC Normal file
View File

@ -0,0 +1,397 @@
GNU Free Documentation License
Version 1.2, November 2002
Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
0. PREAMBLE
The purpose of this License is to make a manual, textbook, or other
functional and useful document "free" in the sense of freedom: to
assure everyone the effective freedom to copy and redistribute it,
with or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way
to get credit for their work, while not being considered responsible
for modifications made by others.
This License is a kind of "copyleft", which means that derivative
works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft
license designed for free software.
We have designed this License in order to use it for manuals for free
software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals;
it can be used for any textual work, regardless of subject matter or
whether it is published as a printed book. We recommend this License
principally for works whose purpose is instruction or reference.
1. APPLICABILITY AND DEFINITIONS
This License applies to any manual or other work, in any medium, that
contains a notice placed by the copyright holder saying it can be
distributed under the terms of this License. Such a notice grants a
world-wide, royalty-free license, unlimited in duration, to use that
work under the conditions stated herein. The "Document", below,
refers to any such manual or work. Any member of the public is a
licensee, and is addressed as "you". You accept the license if you
copy, modify or distribute the work in a way requiring permission
under copyright law.
A "Modified Version" of the Document means any work containing the
Document or a portion of it, either copied verbatim, or with
modifications and/or translated into another language.
A "Secondary Section" is a named appendix or a front-matter section of
the Document that deals exclusively with the relationship of the
publishers or authors of the Document to the Document's overall subject
(or to related matters) and contains nothing that could fall directly
within that overall subject. (Thus, if the Document is in part a
textbook of mathematics, a Secondary Section may not explain any
mathematics.) The relationship could be a matter of historical
connection with the subject or with related matters, or of legal,
commercial, philosophical, ethical or political position regarding
them.
The "Invariant Sections" are certain Secondary Sections whose titles
are designated, as being those of Invariant Sections, in the notice
that says that the Document is released under this License. If a
section does not fit the above definition of Secondary then it is not
allowed to be designated as Invariant. The Document may contain zero
Invariant Sections. If the Document does not identify any Invariant
Sections then there are none.
The "Cover Texts" are certain short passages of text that are listed,
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
the Document is released under this License. A Front-Cover Text may
be at most 5 words, and a Back-Cover Text may be at most 25 words.
A "Transparent" copy of the Document means a machine-readable copy,
represented in a format whose specification is available to the
general public, that is suitable for revising the document
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or
for automatic translation to a variety of formats suitable for input
to text formatters. A copy made in an otherwise Transparent file
format whose markup, or absence of markup, has been arranged to thwart
or discourage subsequent modification by readers is not Transparent.
An image format is not Transparent if used for any substantial amount
of text. A copy that is not "Transparent" is called "Opaque".
Examples of suitable formats for Transparent copies include plain
ASCII without markup, Texinfo input format, LaTeX input format, SGML
or XML using a publicly available DTD, and standard-conforming simple
HTML, PostScript or PDF designed for human modification. Examples of
transparent image formats include PNG, XCF and JPG. Opaque formats
include proprietary formats that can be read and edited only by
proprietary word processors, SGML or XML for which the DTD and/or
processing tools are not generally available, and the
machine-generated HTML, PostScript or PDF produced by some word
processors for output purposes only.
The "Title Page" means, for a printed book, the title page itself,
plus such following pages as are needed to hold, legibly, the material
this License requires to appear in the title page. For works in
formats which do not have any title page as such, "Title Page" means
the text near the most prominent appearance of the work's title,
preceding the beginning of the body of the text.
A section "Entitled XYZ" means a named subunit of the Document whose
title either is precisely XYZ or contains XYZ in parentheses following
text that translates XYZ in another language. (Here XYZ stands for a
specific section name mentioned below, such as "Acknowledgements",
"Dedications", "Endorsements", or "History".) To "Preserve the Title"
of such a section when you modify the Document means that it remains a
section "Entitled XYZ" according to this definition.
The Document may include Warranty Disclaimers next to the notice which
states that this License applies to the Document. These Warranty
Disclaimers are considered to be included by reference in this
License, but only as regards disclaiming warranties: any other
implication that these Warranty Disclaimers may have is void and has
no effect on the meaning of this License.
2. VERBATIM COPYING
You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies
to the Document are reproduced in all copies, and that you add no other
conditions whatsoever to those of this License. You may not use
technical measures to obstruct or control the reading or further
copying of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough
number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and
you may publicly display copies.
3. COPYING IN QUANTITY
If you publish printed copies (or copies in media that commonly have
printed covers) of the Document, numbering more than 100, and the
Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
the back cover. Both covers must also clearly and legibly identify
you as the publisher of these copies. The front cover must present
the full title with all words of the title equally prominent and
visible. You may add other material on the covers in addition.
Copying with changes limited to the covers, as long as they preserve
the title of the Document and satisfy these conditions, can be treated
as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit
reasonably) on the actual cover, and continue the rest onto adjacent
pages.
If you publish or distribute Opaque copies of the Document numbering
more than 100, you must either include a machine-readable Transparent
copy along with each Opaque copy, or state in or with each Opaque copy
a computer-network location from which the general network-using
public has access to download using public-standard network protocols
a complete Transparent copy of the Document, free of added material.
If you use the latter option, you must take reasonably prudent steps,
when you begin distribution of Opaque copies in quantity, to ensure
that this Transparent copy will remain thus accessible at the stated
location until at least one year after the last time you distribute an
Opaque copy (directly or through your agents or retailers) of that
edition to the public.
It is requested, but not required, that you contact the authors of the
Document well before redistributing any large number of copies, to give
them a chance to provide you with an updated version of the Document.
4. MODIFICATIONS
You may copy and distribute a Modified Version of the Document under
the conditions of sections 2 and 3 above, provided that you release
the Modified Version under precisely this License, with the Modified
Version filling the role of the Document, thus licensing distribution
and modification of the Modified Version to whoever possesses a copy
of it. In addition, you must do these things in the Modified Version:
A. Use in the Title Page (and on the covers, if any) a title distinct
from that of the Document, and from those of previous versions
(which should, if there were any, be listed in the History section
of the Document). You may use the same title as a previous version
if the original publisher of that version gives permission.
B. List on the Title Page, as authors, one or more persons or entities
responsible for authorship of the modifications in the Modified
Version, together with at least five of the principal authors of the
Document (all of its principal authors, if it has fewer than five),
unless they release you from this requirement.
C. State on the Title page the name of the publisher of the
Modified Version, as the publisher.
D. Preserve all the copyright notices of the Document.
E. Add an appropriate copyright notice for your modifications
adjacent to the other copyright notices.
F. Include, immediately after the copyright notices, a license notice
giving the public permission to use the Modified Version under the
terms of this License, in the form shown in the Addendum below.
G. Preserve in that license notice the full lists of Invariant Sections
and required Cover Texts given in the Document's license notice.
H. Include an unaltered copy of this License.
I. Preserve the section Entitled "History", Preserve its Title, and add
to it an item stating at least the title, year, new authors, and
publisher of the Modified Version as given on the Title Page. If
there is no section Entitled "History" in the Document, create one
stating the title, year, authors, and publisher of the Document as
given on its Title Page, then add an item describing the Modified
Version as stated in the previous sentence.
J. Preserve the network location, if any, given in the Document for
public access to a Transparent copy of the Document, and likewise
the network locations given in the Document for previous versions
it was based on. These may be placed in the "History" section.
You may omit a network location for a work that was published at
least four years before the Document itself, or if the original
publisher of the version it refers to gives permission.
K. For any section Entitled "Acknowledgements" or "Dedications",
Preserve the Title of the section, and preserve in the section all
the substance and tone of each of the contributor acknowledgements
and/or dedications given therein.
L. Preserve all the Invariant Sections of the Document,
unaltered in their text and in their titles. Section numbers
or the equivalent are not considered part of the section titles.
M. Delete any section Entitled "Endorsements". Such a section
may not be included in the Modified Version.
N. Do not retitle any existing section to be Entitled "Endorsements"
or to conflict in title with any Invariant Section.
O. Preserve any Warranty Disclaimers.
If the Modified Version includes new front-matter sections or
appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all
of these sections as invariant. To do this, add their titles to the
list of Invariant Sections in the Modified Version's license notice.
These titles must be distinct from any other section titles.
You may add a section Entitled "Endorsements", provided it contains
nothing but endorsements of your Modified Version by various
parties--for example, statements of peer review or that the text has
been approved by an organization as the authoritative definition of a
standard.
You may add a passage of up to five words as a Front-Cover Text, and a
passage of up to 25 words as a Back-Cover Text, to the end of the list
of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or
through arrangements made by) any one entity. If the Document already
includes a cover text for the same cover, previously added by you or
by arrangement made by the same entity you are acting on behalf of,
you may not add another; but you may replace the old one, on explicit
permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License
give permission to use their names for publicity for or to assert or
imply endorsement of any Modified Version.
5. COMBINING DOCUMENTS
You may combine the Document with other documents released under this
License, under the terms defined in section 4 above for modified
versions, provided that you include in the combination all of the
Invariant Sections of all of the original documents, unmodified, and
list them all as Invariant Sections of your combined work in its
license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single
copy. If there are multiple Invariant Sections with the same name but
different contents, make the title of each such section unique by
adding at the end of it, in parentheses, the name of the original
author or publisher of that section if known, or else a unique number.
Make the same adjustment to the section titles in the list of
Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled "History"
in the various original documents, forming one section Entitled
"History"; likewise combine any sections Entitled "Acknowledgements",
and any sections Entitled "Dedications". You must delete all sections
Entitled "Endorsements".
6. COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and other documents
released under this License, and replace the individual copies of this
License in the various documents with a single copy that is included in
the collection, provided that you follow the rules of this License for
verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute
it individually under this License, provided you insert a copy of this
License into the extracted document, and follow this License in all
other respects regarding verbatim copying of that document.
7. AGGREGATION WITH INDEPENDENT WORKS
A compilation of the Document or its derivatives with other separate
and independent documents or works, in or on a volume of a storage or
distribution medium, is called an "aggregate" if the copyright
resulting from the compilation is not used to limit the legal rights
of the compilation's users beyond what the individual works permit.
When the Document is included in an aggregate, this License does not
apply to the other works in the aggregate which are not themselves
derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these
copies of the Document, then if the Document is less than one half of
the entire aggregate, the Document's Cover Texts may be placed on
covers that bracket the Document within the aggregate, or the
electronic equivalent of covers if the Document is in electronic form.
Otherwise they must appear on printed covers that bracket the whole
aggregate.
8. TRANSLATION
Translation is considered a kind of modification, so you may
distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include
translations of some or all Invariant Sections in addition to the
original versions of these Invariant Sections. You may include a
translation of this License, and all the license notices in the
Document, and any Warranty Disclaimers, provided that you also include
the original English version of this License and the original versions
of those notices and disclaimers. In case of a disagreement between
the translation and the original version of this License or a notice
or disclaimer, the original version will prevail.
If a section in the Document is Entitled "Acknowledgements",
"Dedications", or "History", the requirement (section 4) to Preserve
its Title (section 1) will typically require changing the actual
title.
9. TERMINATION
You may not copy, modify, sublicense, or distribute the Document except
as expressly provided for under this License. Any other attempt to
copy, modify, sublicense or distribute the Document is void, and will
automatically terminate your rights under this License. However,
parties who have received copies, or rights, from you under this
License will not have their licenses terminated so long as such
parties remain in full compliance.
10. FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versions
of the GNU Free Documentation License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns. See
http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number.
If the Document specifies that a particular numbered version of this
License "or any later version" applies to it, you have the option of
following the terms and conditions either of that specified version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation.
ADDENDUM: How to use this License for your documents
To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and
license notices just after the title page:
Copyright (c) YEAR YOUR NAME.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
replace the "with...Texts." line with this:
with the Invariant Sections being LIST THEIR TITLES, with the
Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.
If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of
free software license, such as the GNU General Public License,
to permit their use in free software.

4
ExtraDesktop.sh Normal file
View File

@ -0,0 +1,4 @@
#! /bin/sh
#This file outputs in a separate line each file with a .desktop syntax
#that needs to be translated but has a non .desktop extension
find themes -name themerc -print

8
HISTORY Normal file
View File

@ -0,0 +1,8 @@
HISTORY:
=======
2002: v0.0, Java source code as Swedish "gymnasium" (upper high school?) examination project
2007-02: v0.1, ai port to C++
2007-02-28: v0.2, command line interface
2007-03-02: v0.3, gui running, playable
2007-03-03: import into KDE SVN playground module
2009-03-23: added a new AI

8
INSTALL Normal file
View File

@ -0,0 +1,8 @@
Standard CMake build system
===========================
$ tar xjf bovo-X.Y-tar.bz2
$ mkdir -p /somewhere/a/build/dir
$ cd /somewhere/a/build/dir
$ cmake /path/to/source/code -DCMAKE_INSTALL_PREFIX=/somewhere/to/install/such/as/opt/kde4
$ make install

5
Messages.sh Normal file
View File

@ -0,0 +1,5 @@
#! /bin/sh
$EXTRACTRC `find . -name "*.kcfg"` >> rc.cpp
$XGETTEXT rc.cpp `find . -name '*.cc'` -o $podir/bovo.pot
rm -f rc.cpp

1
README.PACKAGERS Normal file
View File

@ -0,0 +1 @@
EXTENDED

167
TODO Normal file
View File

@ -0,0 +1,167 @@
Things I want before KDE 4 beta 2
=================================
[ ] Board is way to small at first startup.
[ ] There is no indication the game starts in a demo mode
[ ] Game over message is displayed in status bar. Not nice.
[X] Remove all names from source files. For copyright holders, refer to svn
log. We want collective code ownership.
['] Documentation/Handbook.
['] Game rules
['] Game features / "Help"
['] Game strategies
['] Game history (Gomoku, Connect5, ...)
[ ] Theme creation
[ ] Apidox.
[X] Ai
[X] Game
[ ] Gui
[ ] Mainpage.dox
[X] Fully i18n.
['] Code beautification.
[X] Ai
[X] Game
[ ] Gui
[ ] Naming conventions
[X] Indentation
[X] close namespace with comments
[X] close #endif with comments
[ ] sort functions, methods and properties
[X] name all #ifdefs __CLASNAME_H__
[ ] /* comment */ all private stuff
[ ] Tooltips.
[X] Theme support.
[ ] Configuration dialogue.
[X] Save AI level and theme from session to session.
[X] Logic cleanups.
[X] Allways use Player instead of int
[X] Give the best AI level a different name
[/] Get rid of exceptions, to fit into KDE (AI left)
[ ] Implement draws (yes, it have never ever happened to me in real life, but it
is not impossible in theory, ...right?)
[ ] "New game" doesn't mean a loss if it's just started.
[ ] Kidnap an artist for some decent artworks
=============================================================================
THEMES (4.0)
============
[ ] scribble (pen on paper) [IMPROVE]
[X] spacy
[X] gomoku
[ ] KDE vs Gnome
[X] high contrast
=============================================================================
FEATURES (4.1)
==============
[ ] Status message and game events printed "onboard"
[ ] configure dialogue
[ ] keyboard navigation ("no mouse" gameplay)
[ ] That nice new AI...
[ ] KNewsStuff2 for themes
[ ] Winning line fades in, move by move
[ ] "Stains" support
[ ] Rotate Stains by 90, 180 and 270 degrees
[ ] "Stains" extended (paint all buttons, menus etc in pen-on-paper style)
[-] Change replay & demo playback speed
[ ] Change board size
[ ] "Natural paper" whith coffee stains, etc.
[-] Save a replay
[ ] Open a replay
[-] Save an active game and open it again
[X] Start with latest game when opening
[X] Save stats from time to time
[ ] View history in a right or left pane, where previous moves are displayed.
[ ] Enable LAN gaming (broadcast the local domain for other willing to
participate.)
Look into kgamelib or what it is called. Create XML-like open protocol for
Bovo friends, letting Gnomes play with us (is it possible to add a feature
to the protocol that allways makes them loose? =P )
ADAPTING AI
===========
ADAPTING AI: AI skill starts at Normal, and then it gets reevaluated after
every gameover. The reevaluation takes into account the last 10 games played (if
10 games hasn't been played yet it's a new user and special rules will apply).
However, this 10 latest games is "evaluated" (who won the most, the player or
the AI?). If AI wins more than 4 out of 10 games, lower the difficulty by a few
points on a 100-level scale. If player wins more than half 7 games out of 10
games, make the AI slightly more challenging. This will mean that the player (as
he/she) gets better will start facing more challenging opponents, but still they
won't be disshearteningly hard. The algorithm is meant to mean that a balance
will occure were the player allways faces an opponent he will win ~60% of the
games against, making him feel good about him/herself, lowering his/her blood
pressure and making him/her like this game. :P
[ ] Implement background cogitating in AI (thinking over possible plays in a
separate thread while player is thinking).
[ ] Implement forsight in AI (AI guesses what moves the player might attempt)
[ ] Implement depth searching in AI (If player plays this, then I could play
this and the player could do this and I can do this...).
[ ] Implement width searching in AI (AI evaluates many possible moves; multiple
depths)
[ ] Make sure width+depth searches is reflected in the "root" of the AI, so the
AI chooses the path that seems like the best one. AI will be able to
deselect entirely paths it discovers leads to losses or strong
playerpositions.
[ ] Implement a board vurdering (count offensive and defensive points appart and
see which points is valued the most, to guess which player is most likely to
like a given board).
[ ] When a move is made by the player, drop all know redundant paths from the
strategy and focus on the ones left.
[ ] Make the AI cogitating thread do multi-tasking. That is, all
depth-width-searches gets added to a wait list, and the AI will in turn
vurdere them. Removes from this list should be easy as well (certain losses,
we want to avoid if the player is not of the weaker kind AND when the player
plays a move, all children to other moves must be removed -- Actually
it's better if we just clear eveything specified to be not in a certain
path.)
[ ] Make the aiboard reversable (return a copy and change the playedID) so it is
easy to alter between player and AI "thinking".
[ ] Make this super-AI adjustable, by making miss-calculations (only in
AI-thinking -- it has to presume player is allways a mastermidn) and by
selecting weaker moves (unless they are extremely obvious, like
four-in-a-row). Also make the AI weaker by limiting how deep and wide it is
allowed to calculate.
[ ] Make the width of paths adjustable by how likely they are. If there are many
similarly pointed moves to make, explore them all, but if there is only a
few great only evaluate those.
[ ] Set max depth and width. The closer to the root, the "wider" path is
allowed, and the better paths can also be explored wider and deeper.
[ ] Allow the AI a few seconds of cogitating before forcing it to make a move.
[ ] Find a nice balancing algorithm that ensures the player will face
slightly-easier opponents.
[ ] If 10 games hasn't been played yet, start with a random difficulty. If that
proves to be to hard, back down by half (and so on) or double the
difficulty, until the players starts loosing/winning. Then back down
halfways to the last value and continue to do so whenever the
winning/loosing situation changes but keep making it harder/easier if the
situation doesn't change. When 10 games has passed, start playing with
normal adaption.
[ ] Turn on highscore and connect that between adapted difficulty of AI and time
of play.
[ ] Turn on global highscore. Send in exceptionally great levels of difficulty a
player has reached to an Internet server, so a top-100 masterminds of the
KDE world list is created. :)
[ ] If window gets inactive, pause the AI cogitating thread.
[ ] Refactor out this cooooool adapting AI into a lib, which all KDE Board games
could use! (GSoC idea?)
BUGS
====
[X] Several marks are lost when winning line is painted in replay mode. Odd..
[ ] This might be buggy, haven't checked: when starting an autosaved game;
continue the computerbegins-playerbegins sequence (who made the first move in
the history?)
[ ] Area outside of scene isn't updated correctly when switching theme.
[X] Wins vs. Losses is not updated on startup, but at first when one both has won
and lost.
[X] At startup, playbackSpeed is reset to 2000, due to it beeing to big. Why?????
[X] Undo crashes.
OTHER
=====
[ ] Move this list to a wiki!
[X] Clean up the namespace mess.
[ ] THE SAME THING WE DO EVERY NIGHT, KONQI: TRY TO TAKE OVER THE WORLD!

39
ai/ai.cc Normal file
View File

@ -0,0 +1,39 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/**
* @file ai.cc implementing the Ai class
*/
#include "ai.h"
#include "aron/aiaron.h"
#include "gabor/aigabor.h"
/** namespace for AI stuff */
namespace ai {
Ai::~Ai() = default;
} /* namespace ai */

80
ai/ai.h Normal file
View File

@ -0,0 +1,80 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/**
* @file ai.h declaring the Ai class
*/
#ifndef BOVO_AI_H
#define BOVO_AI_H
#include <QObject>
#include <KgDifficulty>
#include "common.h"
using namespace bovo;
/** namespace for game engine */
namespace bovo
{
class Move;
class Coord;
class Dimension;
} /* namespace bovo */
/** namespace for AI stuff */
namespace ai
{
/**
* An AI player
*
* @code
* Dimension dimension(width, height);
* Ai* ai = aiFactory->createAi(dimension, easy, X, NotDemo);
* Coord move = getMoveFromPlayerEitherByNetworkOrGui();
* Coord aiMove = ai->move(move);
* doSomethingWithAiMoveLikeDisplayingItInTheGui(aiMove);
* @endcode
*/
class Ai : public QObject
{
Q_OBJECT
public:
/**
* @brief destructs this Ai
* @description destructs this Ai object
*/
~Ai() override;
virtual void cancelAndWait() = 0;
public Q_SLOTS:
virtual void changeBoard(const Move &move) = 0;
virtual void gameOver() = 0;
virtual void setSkill(KgDifficultyLevel::StandardLevel skill) = 0;
virtual void slotMove() = 0;
};
} /* namespace ai */
#endif // BOVO_AI_H

76
ai/aifactory.cc Normal file
View File

@ -0,0 +1,76 @@
/*******************************************************************
*
* Copyright 2009 Pelladi Gabor <pelladigabor@gmail.com>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/**
* @file aifactory.cc implementing the AiFactory class
*/
#include "aifactory.h"
#include "ai.h"
#include "aron/aiaron.h"
#include "gabor/aigabor.h"
/** namespace for AI stuff */
namespace ai {
AiFactory::AiFactory() {
m_aiList.append(QStringLiteral("Gabor"));
m_aiList.append(QStringLiteral("Aron"));
m_ai = 0;
}
AiFactory::~AiFactory() = default;
Ai* AiFactory::createAi(const Dimension& dimension, KgDifficultyLevel::StandardLevel skill,
Player player, DemoMode demoMode) const {
if (demoMode == Demo) {
return new AiAron(dimension, skill, player);
} else {
if (m_ai == 0) {
return new AiGabor(dimension, skill, player);
} else if (m_ai == 1) {
return new AiAron(dimension, skill, player);
} else {
qFatal("Invalid AI!");
return nullptr;
}
}
}
const QStringList& AiFactory::aiList() const {
return m_aiList;
}
int AiFactory::ai() const {
return m_ai;
}
void AiFactory::changeAi(int ai) {
if (0 <= ai && ai < m_aiList.size()) {
m_ai = ai;
}
}
} /* namespace ai */

106
ai/aifactory.h Normal file
View File

@ -0,0 +1,106 @@
/*******************************************************************
*
* Copyright 2009 Pelladi Gabor <pelladigabor@gmail.com>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/**
* @file aifactory.h declaring the AiFactory class
*/
#ifndef BOVO_AIFACTORY_H
#define BOVO_AIFACTORY_H
#include <QObject>
#include <QString>
#include <QStringList>
#include <KgDifficulty>
#include "common.h"
using namespace bovo;
/** namespace for game engine */
namespace bovo
{
class Dimension;
} /* namespace bovo */
/** namespace for AI stuff */
namespace ai
{
class Ai;
/**
* Provider of AI implementations
*/
class AiFactory : public QObject
{
Q_OBJECT
public:
/**
* @brief constructs an AiFactory
* @description constructs an AiFactory object
*/
AiFactory();
/**
* @brief destructs this AiFactory
* @description destructs this AiFactory object
*/
~AiFactory() override;
/**
* @brief Constructs an Ai with width, height, player and Skill
* @description Constructs an AI player with a specified width, height and
* skill as well as player id using the currently chosen implementation
* @param dimension the dimension controlling width and height
* @param skill the skill (difficulty level) the AI player will be playing with
* @param player player id of this AI
* @param demoMode indicates the current game mode
*/
Ai *createAi(const Dimension &dimension, KgDifficultyLevel::StandardLevel skill, Player player, DemoMode demoMode) const;
/**
* @brief returns the available AI-s
* @description returns a list of the names of the available AI-s
*/
const QStringList &aiList() const;
/**
* @brief returns the current AI
* @description returns the index of the current AI as present in the list
*/
int ai() const;
/**
* @brief change the AI
* @description changes the current AI to the specified index in the AI list
*/
void changeAi(int ai);
private:
QStringList m_aiList;
int m_ai;
};
} /* namespace ai */
#endif // BOVO_AIFACTORY_H

72
ai/aron/aiaron.cc Normal file
View File

@ -0,0 +1,72 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/**
* @file aiaron.cc implementing the AiAron class
*/
#include "aiaron.h"
#include "aiboard.h"
#include "coord.h"
#include "dimension.h"
#include "move.h"
using namespace bovo;
/** namespace for AI stuff */
namespace ai {
AiAron::AiAron(const Dimension& dimension, KgDifficultyLevel::StandardLevel skill,
Player player) {
m_board = new AiBoard(dimension, skill, player);
m_player = player;
}
AiAron::~AiAron() {
delete m_board;
}
void AiAron::cancelAndWait() {
}
/* public slots */
void AiAron::changeBoard(const Move& move) {
m_board->setPlayer(move);
}
void AiAron::gameOver() {
}
void AiAron::setSkill(KgDifficultyLevel::StandardLevel skill) {
m_board->setSkill(skill);
}
void AiAron::slotMove() {
Q_EMIT move(Move(m_player, m_board->move()));
}
} /* namespace ai */

67
ai/aron/aiaron.h Normal file
View File

@ -0,0 +1,67 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/**
* @file aiaron.h declaring the AiAron class
*/
#ifndef BOVO_AIARON_H
#define BOVO_AIARON_H
#include "../ai.h"
/** namespace for AI stuff */
namespace ai
{
class AiBoard;
/**
* Aron's implementation of the AI player
*/
class AiAron : public Ai
{
Q_OBJECT
public:
explicit AiAron(const Dimension &dimension, KgDifficultyLevel::StandardLevel skill, Player player);
~AiAron() override;
void cancelAndWait() override;
public Q_SLOTS:
void changeBoard(const Move &move) override;
void gameOver() override;
void setSkill(KgDifficultyLevel::StandardLevel skill) override;
void slotMove() override;
Q_SIGNALS:
void move(const Move &move);
private:
/* Playing board */
AiBoard *m_board;
/* AI Player id */
Player m_player;
};
} /* namespace ai */
#endif // BOVO_AIARON_H

486
ai/aron/aiboard.cc Normal file
View File

@ -0,0 +1,486 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/**
* @file AiBoard implementation
*/
#include "aiboard.h"
#include <ctime>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>
#include "aisquare.h"
#include "coord.h"
#include "dimension.h"
#include "move.h"
using namespace bovo;
using namespace std;
namespace ai {
AiBoard::AiBoard(const usi width, const usi height,
KgDifficultyLevel::StandardLevel skill, Player player)
: m_cleanBoard(true), m_player(player), m_skill(skill) {
m_dimension = new Dimension(width, height);
setup();
}
AiBoard::AiBoard(const Dimension& dimension,
KgDifficultyLevel::StandardLevel skill, Player player)
: m_cleanBoard(true), m_player(player), m_skill(skill) {
m_dimension = new Dimension(dimension.width(), dimension.height());
setup();
}
AiBoard::~AiBoard() {
for (int x = 0; x < m_dimension->width(); ++x) {
delete[] m_board[x];
}
delete[] m_board;
delete m_dimension;
}
bool AiBoard::empty(const Coord& c) const {
if (!m_dimension->ok(c)) {
throw outOfBounds();
}
return m_board[c.x()][c.y()].empty();
}
bool AiBoard::empty(const usi x, const usi y) const {
return empty(Coord(x, y));
}
usi AiBoard::height() const {
return m_dimension->height();
}
Coord AiBoard::move() {
if (m_cleanBoard) {
qsrand(static_cast<int>(std::time(nullptr)));
usi randX = qrand()%(m_dimension->width()/3) + m_dimension->width()/3;
usi randY = qrand()%(m_dimension->height()/3) + m_dimension->height()/3;
return Coord(randX, randY);
}
for (usi x = 0; x < m_dimension->width(); ++x) {
for (usi y = 0; y < m_dimension->height(); ++y) {
if (m_board[x][y].status()) {
Coord c(x, y);
setPoints(c, value(c, m_player));
addPoints(c, value(c, m_player == X ? O : X));
}
}
}
Coord out = evaluate();
return out;
}
Coord* AiBoard::moves() {
#ifdef __GNUC__
#warning Implement - Coord* AiBoard::moves(const Coord& c)
#endif
return new Coord();
}
Player AiBoard::player(const Coord& c) const {
if (!m_dimension->ok(c)) {
throw outOfBounds();
}
return m_board[c.x()][c.y()].player();
}
Player AiBoard::player(const usi x, const usi y) const {
return player(Coord(x, y));
}
bool AiBoard::setPlayer(const Move& move) {
m_cleanBoard = false;
zero(move.coord());
m_board[move.coord().x()][move.coord().y()].setPlayer(move.player());
if (win(move.coord())) {
m_gameover = true;
return true;
}
return false;
}
void AiBoard::setSkill(KgDifficultyLevel::StandardLevel skill) {
m_skill = skill;
}
usi AiBoard::width() const {
return m_dimension->width();
}
/* secret helper functions */
Coord next(const Coord& c, usi dir) {
const usi LEFT = 1;
const usi UP = 2;
const usi RIGHT = 4;
const usi DOWN = 8;
Coord tmp = c;
if (dir & LEFT) {
tmp = tmp.left();
} else if (dir & RIGHT) {
tmp = tmp.right();
}
if (dir & UP) {
tmp = tmp.up();
} else if (dir & DOWN) {
tmp = tmp.down();
}
return tmp;
}
bool cmp(const pair<uli, Coord> &a, const pair<uli, Coord> &b) {
return a.first > b.first;
}
/* Private methods */
Coord AiBoard::evaluate() const {
std::vector<std::pair<uli, Coord> > v, v2, v3;
for (int x = 0; x < m_dimension->width(); ++x) {
for (int y = 0; y < m_dimension->height(); ++y) {
v.emplace_back(points(Coord(x, y)), Coord(x, y));
}
}
sort(v.begin(), v.end(), cmp);
uli max = v.begin()->first;
for (auto it = v.begin();
it != v.end(); ++it) {
bool doBreak = false;
switch (m_skill) {
case KgDifficultyLevel::Impossible: // @TODO: Implement Impossible
case KgDifficultyLevel::VeryHard: //@TODO: Implement Very Hard
case KgDifficultyLevel::Hard:
if (it->first == max) {
v2.push_back(*it);
} else {
doBreak = true;
}
break;
case KgDifficultyLevel::Medium:
if (it->first * 1.2 >= max) {
v2.push_back(*it);
} else {
random_shuffle(v2.begin(), v2.end());
return v2.begin()->second;
}
break;
case KgDifficultyLevel::Easy:
if (it->first * 2 >= max) {
v2.push_back(*it);
} else {
random_shuffle(v2.begin(), v2.end());
return v2.begin()->second;
}
break;
case KgDifficultyLevel::VeryEasy:
if (it->first * 4 >= max) {
v2.push_back(*it);
} else {
random_shuffle(v2.begin(), v2.end());
return v2.begin()->second;
}
break;
case KgDifficultyLevel::RidiculouslyEasy:
default: // in case the gui sets the level to an illegal value
if (it->first * 7 >= max) {
v2.push_back(*it);
} else {
random_shuffle(v2.begin(), v2.end());
return v2.begin()->second;
}
break;
}
if (doBreak) {
break;
}
}
if (v2.empty()) {
throw gameover();
} else if (v2.size() == 1) {
return v2.begin()->second;
}
for (auto it = v2.begin();
it != v2.end(); ++it) {
v3.emplace_back(value2(it->second), it->second);
}
sort(v3.begin(), v3.end(), cmp);
if (v3.size() > 1) {
random_shuffle(v3.begin(), v3.end());
}
return v3.begin()->second;
}
uli AiBoard::points(const Coord& c) const {
if (!m_dimension->ok(c)) {
throw outOfBounds();
}
return m_board[c.x()][c.y()].points();
}
void AiBoard::addPoints(const Coord& c, uli points) {
if (!m_dimension->ok(c)) {
throw outOfBounds();
}
m_board[c.x()][c.y()].setPoints(m_board[c.x()][c.y()].points() + points);
}
void AiBoard::setPoints(const Coord& c, uli points) {
if (!m_dimension->ok(c)) {
throw outOfBounds();
}
m_board[c.x()][c.y()].setPoints(points);
m_board[c.x()][c.y()].setStatus(false);
}
void AiBoard::setup() {
m_gameover = false;
m_board = new AiSquare*[m_dimension->width()];
for (int x = 0; x < m_dimension->width(); ++x) {
m_board[x] = new AiSquare[m_dimension->height()];
}
}
uli AiBoard::value(const Coord& c, const usi pl) const {
if (!empty(c)) {
return 0;
}
usi oppositePlayer = (pl==1?2:1);
usi tp;
usi empty;
usi await;
usi leftsideEmpty;
uli tmpPoint = 1;
uli point = 0;
bool enemy = false;
for (int dir = 0; dir < 4; ++dir) {
for (int i = 1; i <= 5; ++i) {
tp = 0;
enemy = false;
empty = 0;
await = 0;
leftsideEmpty = 0;
for (int diff = 5-i; diff > 0-i; --diff) {
Coord tmp = c;
switch (dir) {
case 0:
tmp = Coord(c.x()-diff, c.y());
break;
case 1:
tmp = Coord(c.x(), c.y()-diff);
break;
case 2:
tmp = Coord(c.x()-diff, c.y()-diff);
break;
case 3:
tmp = Coord(c.x()+diff, c.y()-diff);
break;
}
if (m_dimension->ok(tmp)) {
if (player(tmp) == pl) {
empty += await;
await = 0;
++tp;
} else if (player(tmp) == oppositePlayer) {
enemy = true;
tp = 0;
} else {
if (tp > 0) {
++await;
} else {
++leftsideEmpty;
}
}
} else {
enemy = true;
tp = 0;
}
if (enemy) {
break;
}
}
tmpPoint = 1;
switch (tp) {
case 4:
tmpPoint *= (m_skill == KgDifficultyLevel::RidiculouslyEasy ? 7 : 231);
case 3:
tmpPoint *= (m_skill == KgDifficultyLevel::VeryEasy ? 21 :
(m_skill == KgDifficultyLevel::RidiculouslyEasy ? 12 : 231));
case 2:
tmpPoint *= (m_skill == KgDifficultyLevel::VeryEasy ? 21 : 231 );
break;
case 1:
tmpPoint *= m_skill == KgDifficultyLevel::RidiculouslyEasy ? 3 : 1;
break;
case 0:
tmpPoint = 0;
}
if (pl == m_player && m_skill != KgDifficultyLevel::RidiculouslyEasy
&& m_skill != KgDifficultyLevel::VeryEasy) {
tmpPoint *= 21;
}
if (empty < 2 && await > 0 && leftsideEmpty > 0) {
tmpPoint *= 8;
}
point += tmpPoint;
}
}
return point;
}
uli AiBoard::value2(const Coord& c) const {
uli p = 0;
usi lp = 0;
usi q = 1;
Coord tmp(c.x(), c.y());
bool test = true;
for (usi u = 1; u < 3; ++u) {
for (usi i = 0; i < 4; ++i) {
while (test) {
switch (i) {
case 0:
tmp = Coord(c.x()-q, c.y());
break;
case 1:
tmp = Coord(c.x(), c.y()-q);
break;
case 2:
tmp = Coord(c.x()-q, c.y()-q);
break;
case 3:
tmp = Coord(c.x()+q, c.y()-q);
break;
}
test = m_dimension->ok(tmp);
if (test) {
test = player(tmp) == u;
}
if (test) {
++lp;
}
++q;
}
test = true;
q = 1;
while (test) {
switch (i) {
case 0:
tmp = Coord(c.x()+q, c.y());
break;
case 1:
tmp = Coord(c.x(), c.y()+q);
break;
case 2:
tmp = Coord(c.x()+q, c.y()+q);
break;
case 3:
tmp = Coord(c.x()-q, c.y()+q);
break;
}
test = m_dimension->ok(tmp);
if (test) {
test = player(tmp) == u;
}
if (test) {
++lp;
}
++q;
}
switch (lp) {
case 0:
case 1:
p += lp;
break;
case 2:
p += (9*lp);
break;
case 3:
p += (8*9*lp+1);
break;
default:
p += 1000;
break;
}
test = true;
q = 1;
}
}
return p;
}
bool AiBoard::win(const Coord& c) const {
const usi LEFT = 1;
const usi UP = 2;
const usi RIGHT = 4;
const usi DOWN = 8;
usi DIR[8] = {
LEFT,
RIGHT,
UP,
DOWN,
LEFT | UP,
RIGHT | DOWN,
LEFT|DOWN,
RIGHT|UP
};
usi p = player(c);
for (int i = 0; i < 4; ++i) {
usi count = 1;
Coord tmp = next(c, DIR[2*i]);
while (m_dimension->ok(tmp) && player(tmp) == p) {
++count;
tmp = next(tmp, DIR[2*i]);
}
tmp = next(c, DIR[2*i+1]);
while (m_dimension->ok(tmp) && player(tmp) == p) {
++count;
tmp = next(tmp, DIR[2*i+1]);
}
if (count >= 5) {
return true;
}
}
return false;
}
void AiBoard::zero(const Coord& c) {
usi minX = c.x()-5 < 0 ? 0 : c.x()-5;
usi maxX = (c.x()+5 > m_dimension->width()-1) ? (m_dimension->width()-1) : c.x()+5;
usi minY = c.y()-5 < 0 ? 0 : c.y()-5;
usi maxY = (c.y()+5 > m_dimension->height()-1) ? (m_dimension->height()-1) : c.y()+5;
for (int x = minX; x <= maxX; ++x) {
for (int y = minY; y <= maxY; ++y) {
m_board[x][y].setStatus(true);
}
}
}
} /* namespace ai */

245
ai/aron/aiboard.h Normal file
View File

@ -0,0 +1,245 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/**
* @file file declaring the class AiBoard, which in fact is the AI
*/
#ifndef BOVO_AIBOARD_H
#define BOVO_AIBOARD_H
#include <KgDifficulty>
#include "common.h"
using namespace bovo;
/** namespace for game engine */
namespace bovo
{
class Coord;
class Dimension;
class Move;
} /* namespace bovo */
/** namespace for AI stuff */
namespace ai
{
class AiSquare;
/**
* An AI player
*
* This class might be somewhat missnamed. It doesn't just keep track of a
* playing board on the behalf og the AI. It is the entire AI implementation.
* it implements two algorithms to calculate best moves and it selects which
* move to play. It also can tell if a move is a winning move, but it doesn't
* track a history yet (but maybe it should?).
*
* It uses the standard stuff in common.h way to little.
*
* It is supposed to be slaughtered and split up in two, easing the
* implementation of AdaptingAi (the great feature to come! =P )
*
* Perhaps we want to use Qt4 rather than STL in most of these cases. When we
* implement AdaptingAi we have to depend on Qt4 and/or ThreadWeaver anyways.
*
* @code
* Dimension dimension(width, height);
* AiBoard ai(dimension, Easy);
* Coord move = getMoveFromPlayerEitherByNetworkOrGui();
* Coord aiMove = ai.move(move);
* doSomethingWithAiMoveLikeDisplayingItInTheGui(aiMove);
* @endcode
*/
class AiBoard
{
public:
/**
* @brief Constructs an AiBoard with width, height and Skill
* @description Constructs a Board object with a specified width, height and
* skill
* @param width the width
* @param height the height
* @param skill the skill (difficulty level) the AI player will be playing with
*/
AiBoard(const usi width, const usi height, KgDifficultyLevel::StandardLevel skill = KgDifficultyLevel::Medium, Player player = O);
/**
* @brief Constructs an AiBoard with width, height and Skill
* @description Constructs a Board object with a specified width and height
* specified by a Dimension and a skill
* @param width the width
* @param height the height
* @param skill the skill (difficulty level) the AI player will be playing with
*/
explicit AiBoard(const Dimension &dimension, KgDifficultyLevel::StandardLevel skill = KgDifficultyLevel::Medium, Player player = O);
/**
* @brief destructs this AiBoard
* @description destructs this AiBoard object
*/
~AiBoard();
/**
* @brief is a Coord empty or set?
* @description tells whether a given Coord is marked as empty or
* marked by a player
* @throw outOfBounds when coord is not on playing board
* @param coord Coord to check
* @return @c true if coord is empty, @c false otherwise
*/
bool empty(const Coord &) const;
/**
* @brief is a Coord empty or set?
* @description tells whether a given Coord is marked as empty or
* marked by a player
* @throw outOfBounds when coord is not on playing board
* @param x X-part of coordinate to check
* @param y X-part of coordinate to check
* @return @c true if coord is empty, @c false otherwise
*/
bool empty(const usi x, const usi y) const;
/**
* @brief height of AiBoard
* @description tells the number of rows in the playing board
* @return the number of rows
*/
usi height() const;
/**
* @brief get move from AI
* @description get the move the AI wants to play
* @return the move the AI wants to play
*/
Coord move();
/**
* @brief get move from AI
* @description Feed the latest move from the player to the AI and get a
* list of suggested AI moves in return. This should be a QList\<Coord>.
* @param coord the move the player played his latest turn
* @return the moves the AI suggest to play
* @todo Implement!
*/
Coord *moves();
/**
* @brief the player occupying a Coord
* @description tells which players occupies a certain square in the board
* @param coord the square to check
* @return @c X if player 1, @c O if player 2, @c No if empty
* @throw outOfBounds if coord isn't on the playing board
*/
Player player(const Coord &) const;
/**
* @brief the player occupying a Coord
* @description tells which players occupies a certain square in the board
* @param x the X-part of the Coord to check
* @param y the Y-part of the Coord to check
* @return @c X if player 1, @c O if player 2, @c No if empty
* @throw outOfBounds if coord isn't on the playing board
*/
Player player(const usi x, const usi y) const;
/**
* @brief set the player of a Coord
* @description sets which players should occupy a certain square in the
* playing board. Returns whether the game ends with this move (i.e. it
* was the winning move).
* @param move the Move to place
* @return @c true if this move resulted in a Game Over,
* @c false otherwise
* @throw busy if coord was already occupied
* @throw gameOver if game was already over
* @throw notValidPlayer if player wasn't X or O
*/
bool setPlayer(const Move &move);
/**
* @brief change Skill
* @description changes the Skill (difficulty level) of the AI player
*/
void setSkill(KgDifficultyLevel::StandardLevel skill);
/**
* @brief width of Board
* @description tells the number of columns in the playing board
* @return the number of columns
*/
usi width() const;
private:
/* Playing board property. */
AiSquare **m_board;
/* hasn't game really started? */
bool m_cleanBoard;
/* Dimension property of playing board. */
Dimension *m_dimension;
/* is Game Over? property */
bool m_gameover;
/* AI player property */
Player m_player;
/* AI Level property. */
KgDifficultyLevel::StandardLevel m_skill;
/* Return the best-fitting coordinate according to the specs.
* Use this when all the board has been given points. */
Coord evaluate() const;
/* returns, adds och sets points on a given square. */
uli points(const Coord &) const;
void addPoints(const Coord &, const uli points);
void setPoints(const Coord &, const uli points);
/* initialize this class */
void setup();
/* Do the real calculation of points for a given square.
* Player is the AI player you're optimizing. */
uli value(const Coord &, const usi player) const;
/* value2 performs a second evaluation in order to make out the tiny
* differences that haven't been spotted yet.
* Only run this when needed. */
uli value2(const Coord &) const;
/* is this move (coord) a winning move? */
bool win(const Coord &) const;
/* Marks all neighbour (5 squares in each
* direction) as in need of a recalculation
* of its points. */
void zero(const Coord &);
};
} /* namespace ai */
#endif // BOVO_AIBOARD_H

48
ai/aron/aisquare.cc Normal file
View File

@ -0,0 +1,48 @@
/*******************************************************************
*
* This file is part of the KDE project "Bovo"
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "aisquare.h"
using namespace bovo;
namespace ai {
AiSquare::AiSquare() : Square(), m_points(0), m_status(true) {
}
uli AiSquare::points() const {
return m_points;
}
void AiSquare::setPoints(uli points) {
m_points = points;
}
bool AiSquare::status() const {
return m_status;
}
void AiSquare::setStatus(bool status) {
m_status = status;
}
} /* namespace ai */

124
ai/aron/aisquare.h Normal file
View File

@ -0,0 +1,124 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/**
* @file Declares the Square class used by the AI internally (AiSquare)
*/
#ifndef BOVO_AISQUARE_H
#define BOVO_AISQUARE_H
#include "square.h"
#include "common.h"
using namespace bovo;
/** namespace for AI stuff */
namespace ai
{
/**
* AiSquare is used by the AI to represent a square in a playing board.
*
* This class is used internally by the AI to represent a square in a
* playing board. It extends the normal @c Square class with possibilities
* to keep a point attached to the square, as well as a bool marker that
* tells whether this square needs a recalculation of its points.
*
* Examples construction: (create a playing board)
* @code
* AiSquare** board = new AiSquare*[width];
* for (int x = 0; x < width; ++x) {
* board[x] = new AiSquare[height];
* }
* @endcode
*
* Example status use:
* @code
* if (board[x][y].status()) {
* unsigned long points = score(board, x, y );
* board[x][y].setPoints(points);
* board[x][y].setStatus(false);
* }
* @endcode
*
* Example mark needs to be repainted:
* @code
* // a neighbour of (x, y) has been marked as belonging to a player,
* // so (x, y) needs to be recalculated.
* board[x][y].setPoints(0);
* board[x][y].setStatus(true);
* @endcode
*
* @author bostrom (Aron Boström) <aron bostrom gmail com>
*/
class AiSquare : public Square
{
public:
/**
* @brief constructor of this AiSquare
* @description this constructor creates an AiSquare
*/
AiSquare();
/**
* @brief square points
* @description AI points of this square
* @return points of this square
* @see setPoints
*/
uli points() const;
/**
* @brief sets points
* @description sets the AI points of this square
* @param points the points to set
* @see points
*/
void setPoints(unsigned long int points);
/**
* @brief square status
* @description status represents whether this square is in neef of a
* recalculation of its points or not.
* @return @c true if this square needs a recalculation, @c false otherwise
* @see @c setStatus
*/
bool status() const;
/**
* @brief set status of this square
* @description sets this square's need to get its score recalculated.
* @param status the status to set. $c true means square is in need of a
* recalculation, $c false means it doesn't need to be recalculated.
* @see @c status
*/
void setStatus(bool status);
private:
uli m_points; /* unsigned long int points property */
bool m_status; /* bool status property */
};
} /* namespace ai */
#endif // BOVO_AISQUARE_H

328
ai/gabor/ai_impl.cpp Normal file
View File

@ -0,0 +1,328 @@
/*******************************************************************
*
* Copyright 2009 Pelladi Gabor <pelladigabor@gmail.com>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "ai_impl.h"
#include "node.h"
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <memory.h>
// hash table
static NodeHashData hashData[nodeHashSize];
const int hashMaxDepth = 8;
const int hashMinRemainingDepth = 2;
bool rand_inited = false;
AiImpl::AiImpl()
: table_size_x(20)
, table_size_y(20)
, start_depth(6)
, max_depth(6)
, depth_increment(2)
, force_thinking(false)
, heur_seed(normal_heur_seed)
, print_info(true)
, max_branch(100)
, timeOver(nullptr)
, rememberedStanding(table_size_x, table_size_y)
{
if (!rand_inited) {
rand_inited = true;
qsrand(static_cast<unsigned int>(std::time(nullptr)));
}
memset(hashData, 0, sizeof(hashData));
}
AiImpl::~AiImpl() = default;
void AiImpl::newGame()
{
Standing::initRefresh();
previousStandings.clear();
rememberedStanding = Standing(table_size_x, table_size_y);
}
void AiImpl::step(pos_T x, pos_T y)
{
previousStandings.push_back(rememberedStanding);
rememberedStanding.step(x, y);
if (print_info) {
printf("hval = %d\n", rememberedStanding.hval);
fflush(stdout);
}
}
void AiImpl::stepServer(pos_T x, pos_T y)
{
rememberedStanding.step_server(x, y);
}
void AiImpl::undo()
{
assert(!previousStandings.empty());
rememberedStanding = previousStandings.last();
previousStandings.removeLast();
}
Field AiImpl::think()
{
rememberedStanding.heur_seed = heur_seed;
// opening book
Field f = openingBook();
if (f.x < table_size_x && f.y < table_size_y && !rememberedStanding.table[f.x][f.y]) {
return f;
}
// global best step
pos_T bestX = max_table_size, bestY = max_table_size;
// alpha-beta pruning
Node *act;
Node *root;
hash_T currentHash;
NodeHashData currentHashData;
// step suggestion in the current depth limit
pos_T suggestedX = max_table_size, suggestedY = max_table_size;
// heuristic value of the search tree root
heur_T rootValue = 0.0;
// do a very fast initial search
depth_limit = 1;
do {
if (print_info)
printf(" depth limit: %2d", depth_limit);
act = root = new Node(new Standing(rememberedStanding), this);
// this prevents the AI from thinking if there is only one good move
if (!force_thinking && root->steps.size() == 1) {
suggestedX = root->steps.front()->lastx;
suggestedY = root->steps.front()->lasty;
rootValue = 0;
act = nullptr;
}
while (act && (timeOver == nullptr || !timeOver->isTimeOver())) {
// if this is a parent whose child has just been evaluated
if (act->child) {
if (act->signum > 0) {
// MAX
if (act->alpha < act->child->beta) {
act->alpha = act->child->beta;
act->is_exact = true;
if (!act->parent) {
suggestedX = act->child->standing->lastx;
suggestedY = act->child->standing->lasty;
rootValue = act->alpha;
}
if (act->alpha >= act->beta || act->alpha >= WinTreshold) {
act->evaluated = true;
currentHashData.entry_type = lower_bound;
currentHashData.value = act->alpha;
}
}
} else {
// MIN
if (act->beta > act->child->alpha) {
act->beta = act->child->alpha;
act->is_exact = true;
if (!act->parent) {
suggestedX = act->child->standing->lastx;
suggestedY = act->child->standing->lasty;
rootValue = act->beta;
}
if (act->alpha >= act->beta || act->beta <= -WinTreshold) {
act->evaluated = true;
currentHashData.entry_type = upper_bound;
currentHashData.value = act->beta;
}
}
}
delete act->child;
act->child = nullptr;
}
// if this parent has no more children to process
if (act->steps.empty()) {
act->evaluated = true;
if (act->signum > 0) {
// MAX
currentHashData.entry_type = act->is_exact ? exact : upper_bound;
currentHashData.value = act->alpha;
} else {
// MIN
currentHashData.entry_type = act->is_exact ? exact : lower_bound;
currentHashData.value = act->beta;
}
}
if (act->evaluated) {
// store the current standing in the hash table
if (act->depth <= hashMaxDepth && depth_limit - act->depth >= hashMinRemainingDepth && heur_seed <= normal_heur_seed) {
act->calcHash(&currentHash, &currentHashData);
hashData[currentHash] = currentHashData;
}
act = act->parent;
} else {
act->child = new Node(act->steps.front(), act);
act->steps.pop_front();
act = act->child;
// if this is a leaf
if (act->evaluated) {
act = act->parent;
continue;
}
// check whether we have already evaluated the standing elsewhere
if (act->depth <= hashMaxDepth && depth_limit - act->depth >= hashMinRemainingDepth && heur_seed <= normal_heur_seed) {
act->calcHash(&currentHash, &currentHashData);
NodeHashData *storedHashData = &hashData[currentHash];
if (storedHashData->remaining_depth >= depth_limit - act->depth && currentHashData.checksum == storedHashData->checksum) {
if (act->signum > 0) {
// MAX
if (storedHashData->entry_type == exact)
act->alpha = act->beta = storedHashData->value;
if (storedHashData->entry_type == lower_bound && act->alpha < storedHashData->value)
act->alpha = storedHashData->value;
if (storedHashData->entry_type == upper_bound && act->beta > storedHashData->value)
act->beta = storedHashData->value;
} else {
// MIN
if (storedHashData->entry_type == exact)
act->alpha = act->beta = storedHashData->value;
if (storedHashData->entry_type == upper_bound && act->beta > storedHashData->value)
act->beta = storedHashData->value;
if (storedHashData->entry_type == lower_bound && act->alpha < storedHashData->value)
act->alpha = storedHashData->value;
}
if (act->alpha >= act->beta) {
act->evaluated = true;
act = act->parent;
continue;
}
}
}
}
}
// check why we have left the while loop
if (!act) {
bestX = suggestedX;
bestY = suggestedY;
if (print_info) {
printf(" suggestion: (%2d, %2d) score: %6d\n", suggestedX, suggestedY, rootValue);
fflush(stdout);
}
} else {
if (print_info) {
printf(" time is over\n");
fflush(stdout);
}
}
delete root;
if (depth_limit < start_depth) {
depth_limit = start_depth;
} else {
depth_limit += depth_increment;
}
} while (depth_limit <= max_depth && (timeOver == nullptr || !timeOver->isTimeOver()));
assert((timeOver == nullptr || !timeOver->isTimeOver()) || !rememberedStanding.table[bestX][bestY]);
return {bestX, bestY};
}
Field AiImpl::openingBook()
{
if (rememberedStanding.stepCount == 0) {
pos_T x, y;
x = table_size_x / 2;
y = table_size_y / 2;
x += qrand() % 5 - 2;
y += qrand() % 5 - 2;
while (rememberedStanding.table[x][y])
x++;
return {x, y};
} else if (rememberedStanding.stepCount == 1) {
pos_T x, y;
x = rememberedStanding.lastx;
y = rememberedStanding.lasty;
int r = qrand() % 100;
if (r >= 20) {
if (x < table_size_x / 2) {
x++;
} else {
x--;
}
}
if (r < 80) {
if (y < table_size_y / 2) {
y++;
} else {
y--;
}
}
return {x, y};
} else if (rememberedStanding.stepCount == 2) {
pos_T x1, y1, x2, y2;
int dx, dy;
x1 = previousStandings.last().lastx;
y1 = previousStandings.last().lasty;
if (!(1 <= x1 && x1 < table_size_x - 1 && 1 <= y1 && y1 < table_size_y - 1)) {
return {max_table_size, max_table_size};
}
x2 = rememberedStanding.lastx;
y2 = rememberedStanding.lasty;
dx = (int)x1 - (int)x2;
dy = (int)y1 - (int)y2;
if (-1 <= dx && dx <= 1 && -1 <= dy && dy <= 1) {
if (dx == 0) {
return {static_cast<pos_T>((int)x1 + (qrand() % 2) * 2 - 1), static_cast<pos_T>((int)y1 + qrand() % 3 - 1)};
}
if (dy == 0) {
return {static_cast<pos_T>((int)x1 + qrand() % 3 - 1), static_cast<pos_T>((int)y1 + (qrand() % 2) * 2 - 1)};
}
if (qrand() % 2) {
if (qrand() % 2) {
return {static_cast<pos_T>((int)x1 + dx), y1};
} else {
return {x1, static_cast<pos_T>((int)y1 + dy)};
}
} else {
if (qrand() % 2) {
return {static_cast<pos_T>((int)x1 - dx), static_cast<pos_T>((int)y1 + dy)};
} else {
return {static_cast<pos_T>((int)x1 + dx), static_cast<pos_T>((int)y1 - dy)};
}
}
}
}
return {max_table_size, max_table_size};
}

84
ai/gabor/ai_impl.h Normal file
View File

@ -0,0 +1,84 @@
/*******************************************************************
*
* This file is part of the KDE project "Bovo"
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_AI_IMPL_H
#define BOVO_AI_IMPL_H
#include <QLinkedList>
#include "ai_interface.h"
#include "standing.h"
using previous_standings_T = QLinkedList<Standing>;
class AiImpl
{
public:
AiImpl();
virtual ~AiImpl();
// the width of the table
pos_T table_size_x;
// the height of the table
pos_T table_size_y;
// the starting depth for the search
int start_depth;
// the maximum depth for the search
int max_depth;
// the increment of the depth in every iteration
int depth_increment;
// if set, the ai will think in advance even when he has only one good move
// prevents the ai from wasting thinking time in a competition environment
bool force_thinking;
// the amount of random seed added to the heuristic function in every standing
heur_T heur_seed;
// if set, the ai will print information on the standard output
bool print_info;
// limits the amount of following steps to be investigated from a standing
unsigned int max_branch;
// interrupt class, returns true if time is over
AiTimeOver *timeOver;
// current search depth limit
int depth_limit;
// a new game has started
void newGame();
// the current player made a step
void step(pos_T x, pos_T y);
// the server made a step
void stepServer(pos_T x, pos_T y);
// undo last move
void undo();
// suggest a move for the current player
Field think();
private:
// the standing persisted across steps
Standing rememberedStanding;
// the game history for undo
previous_standings_T previousStandings;
// suggest a move for the current player from the opening book
Field openingBook();
};
#endif // BOVO_AI_IMPL_H

128
ai/gabor/ai_interface.cpp Normal file
View File

@ -0,0 +1,128 @@
/*******************************************************************
*
* This file is part of the KDE project "Bovo"
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "ai_interface.h"
#include "ai_impl.h"
#include <cassert>
AiInterface::AiInterface()
{
aiImpl = new AiImpl();
}
AiInterface::~AiInterface()
{
delete aiImpl;
}
void AiInterface::setTableSize(pos_T tableSize)
{
assert(5 <= tableSize && tableSize <= max_table_size);
aiImpl->table_size_x = aiImpl->table_size_y = tableSize;
}
void AiInterface::setTableSizeX(pos_T tableSizeX)
{
assert(5 <= tableSizeX && tableSizeX <= max_table_size);
aiImpl->table_size_x = tableSizeX;
}
void AiInterface::setTableSizeY(pos_T tableSizeY)
{
assert(5 <= tableSizeY && tableSizeY <= max_table_size);
aiImpl->table_size_y = tableSizeY;
}
void AiInterface::setDepth(int depth)
{
assert(depth > 0);
aiImpl->start_depth = aiImpl->max_depth = depth;
aiImpl->depth_increment = 2;
}
void AiInterface::setStartDepth(int startDepth)
{
assert(startDepth > 0);
aiImpl->start_depth = startDepth;
if (aiImpl->max_depth < aiImpl->start_depth)
aiImpl->max_depth = aiImpl->start_depth;
}
void AiInterface::setMaxDepth(int maxDepth)
{
assert(maxDepth > 0);
aiImpl->max_depth = maxDepth;
if (aiImpl->start_depth > aiImpl->max_depth)
aiImpl->start_depth = aiImpl->max_depth;
}
void AiInterface::setDepthIncrement(int depthIncrement)
{
assert(depthIncrement > 0);
aiImpl->depth_increment = depthIncrement;
}
void AiInterface::setForceThinking(bool forceThinking)
{
aiImpl->force_thinking = forceThinking;
}
void AiInterface::setRandomAmount(int randomAmount)
{
aiImpl->heur_seed = randomAmount;
}
void AiInterface::setPrintInfo(bool printInfo)
{
aiImpl->print_info = printInfo;
}
void AiInterface::setTimeOver(AiTimeOver *timeOver)
{
assert(timeOver);
aiImpl->timeOver = timeOver;
}
void AiInterface::newGame()
{
aiImpl->newGame();
}
void AiInterface::step(pos_T x, pos_T y)
{
aiImpl->step(x, y);
}
void AiInterface::stepServer(pos_T x, pos_T y)
{
aiImpl->stepServer(x, y);
}
void AiInterface::undo()
{
aiImpl->undo();
}
Field AiInterface::think()
{
return aiImpl->think();
}

106
ai/gabor/ai_interface.h Normal file
View File

@ -0,0 +1,106 @@
/*******************************************************************
*
* This file is part of the KDE project "Bovo"
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_AI_INTERFACE_H
#define BOVO_AI_INTERFACE_H
// a coordinate of the table
using pos_T = unsigned char;
// memory allocated for a standing
const pos_T max_table_size = 22;
// a pair of coordinates
struct Field {
pos_T x, y;
Field()
: x(0)
, y(0)
{
}
Field(pos_T x0, pos_T y0)
: x(x0)
, y(y0)
{
}
bool operator==(const Field &field)
{
return x == field.x && y == field.y;
}
};
class AiInterface;
class AiImpl;
class AiTimeOver
{
public:
virtual ~AiTimeOver() = default;
virtual bool isTimeOver() = 0;
};
class AiInterface
{
public:
AiInterface();
virtual ~AiInterface();
// set a square table with the specified size
void setTableSize(pos_T tableSize);
// set the width of the table
void setTableSizeX(pos_T tableSizeX);
// set the height of the table
void setTableSizeY(pos_T tableSizeY);
// set a fixed depth for the search
void setDepth(int depth);
// set the starting depth for the search
void setStartDepth(int startDepth);
// set the maximum depth for the search
void setMaxDepth(int startDepth);
// set the increment of the depth in every iteration
void setDepthIncrement(int startDepth);
// if set, the ai will think in advance even when he has only one good move
// prevents the ai from wasting thinking time in a competition environment
void setForceThinking(bool forceThinking);
// the amount of random seed added to the heuristic function in every standing
void setRandomAmount(int randomAmount);
// if set, the ai will print information on the standard output
void setPrintInfo(bool printInfo);
// interrupt function, returns true if time is over
void setTimeOver(AiTimeOver *timeOver);
// a new game has started
void newGame();
// the current player made a step
void step(pos_T x, pos_T y);
// the server made a step
void stepServer(pos_T x, pos_T y);
// undo last move
void undo();
// suggest a move for the current player
Field think();
private:
// implementation class
AiImpl *aiImpl;
};
#endif // BOVO_AI_INTERFACE_H

121
ai/gabor/aigabor.cc Normal file
View File

@ -0,0 +1,121 @@
/*******************************************************************
*
* Copyright 2009 Pelladi Gabor <pelladigabor@gmail.com>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "aigabor.h"
#include "coord.h"
#include "dimension.h"
#include "move.h"
#include <QElapsedTimer>
#include <QThread>
#include <QtConcurrentRun>
using namespace bovo;
/** namespace for AI stuff */
namespace ai {
/**
* @file aigabor.cc implementing the AiGabor class
*/
AiGabor::AiGabor(const Dimension& dimension, KgDifficultyLevel::StandardLevel skill,
Player player) : m_player(player), m_minThink(200) {
m_ai = new AiInterface();
m_ai->setTableSizeX(dimension.width());
m_ai->setTableSizeY(dimension.height());
m_ai->setPrintInfo(false);
m_ai->setTimeOver(this);
setSkill(skill);
m_ai->newGame();
qRegisterMetaType<Move>("Move");
}
AiGabor::~AiGabor() {
cancelAndWait();
delete m_ai;
}
void AiGabor::cancelAndWait() {
m_canceling = true;
m_future.waitForFinished();
}
bool AiGabor::isTimeOver() {
return m_canceling;
}
/* public slots */
void AiGabor::changeBoard(const Move& move) {
if (move.player() == No) {
m_ai->undo();
} else {
m_ai->step(move.x(), move.y());
}
}
void AiGabor::gameOver() {
}
void AiGabor::setSkill(KgDifficultyLevel::StandardLevel skill) {
switch (skill) {
case KgDifficultyLevel::RidiculouslyEasy: m_ai->setDepth(1); m_ai->setRandomAmount(10000); break;
case KgDifficultyLevel::VeryEasy: m_ai->setDepth(1); m_ai->setRandomAmount(9000); break;
case KgDifficultyLevel::Easy: m_ai->setDepth(1); m_ai->setRandomAmount(2000); break;
case KgDifficultyLevel::Medium: m_ai->setDepth(1); m_ai->setRandomAmount(2); break;
case KgDifficultyLevel::Hard: m_ai->setDepth(2); m_ai->setRandomAmount(2); break;
case KgDifficultyLevel::VeryHard: m_ai->setDepth(3); m_ai->setRandomAmount(2); break;
case KgDifficultyLevel::ExtremelyHard: m_ai->setDepth(6); m_ai->setRandomAmount(2); break;
case KgDifficultyLevel::Impossible: m_ai->setDepth(10); m_ai->setRandomAmount(2); break;
default: break;
}
}
void AiGabor::slotMove() {
if (!m_future.isFinished()) {
qFatal("Concurrent AI error");
}
m_canceling = false;
m_future = QtConcurrent::run(this, &ai::AiGabor::slotMoveImpl);
}
void AiGabor::slotMoveImpl() {
QElapsedTimer time;
time.start();
Field f = m_ai->think();
for (;;) {
int elapsed = time.elapsed();
if (elapsed >= m_minThink) {
break;
}
QThread::yieldCurrentThread();
}
if (!m_canceling) {
Q_EMIT move(Move(m_player, Coord(f.x, f.y)));
}
}
} /* namespace ai */

80
ai/gabor/aigabor.h Normal file
View File

@ -0,0 +1,80 @@
/*******************************************************************
*
* Copyright 2009 Pelladi Gabor <pelladigabor@gmail.com>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/**
* @file aigabor.h declaring the AiGabor class
*/
#ifndef BOVO_AIGABOR_H
#define BOVO_AIGABOR_H
#include <QFuture>
#include "../ai.h"
#include "ai_interface.h"
/** namespace for AI stuff */
namespace ai
{
/**
* Gabor's implementation of the AI player
*/
class AiGabor : public Ai, public AiTimeOver
{
Q_OBJECT
public:
explicit AiGabor(const Dimension &dimension, KgDifficultyLevel::StandardLevel skill, Player player);
~AiGabor() override;
void cancelAndWait() override;
bool isTimeOver() override;
public Q_SLOTS:
void changeBoard(const Move &move) override;
void gameOver() override;
void setSkill(KgDifficultyLevel::StandardLevel skill) override;
void slotMove() override;
Q_SIGNALS:
void move(const Move &move);
private:
/* AI brain */
AiInterface *m_ai;
/* AI Player id */
const Player m_player;
/* minimum thinking time in milliseconds */
const int m_minThink;
/* for getting information about the thinking thread */
QFuture<void> m_future;
/* should the thinking thead try to cancel */
bool m_canceling;
void slotMoveImpl();
};
} /* namespace ai */
#endif // BOVO_AIGABOR_H

130
ai/gabor/node.cpp Normal file
View File

@ -0,0 +1,130 @@
/*******************************************************************
*
* Copyright 2009 Pelladi Gabor <pelladigabor@gmail.com>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "node.h"
#include "ai_impl.h"
#include <cassert>
Node::Node(Standing *_standing, AiImpl *ai)
: standing(_standing)
, parent(nullptr)
, child(nullptr)
, depth(0)
, signum(_standing->current == 0 ? 1 : -1)
, alpha(MinHeur - 1)
, beta(MaxHeur + 1)
, is_exact(false)
, evaluated(false)
, depth_limit(ai->depth_limit)
, max_branch(ai->max_branch)
{
generateSteps();
}
Node::Node(Standing *_standing, Node *_parent)
: standing(_standing)
, parent(_parent)
, child(nullptr)
, depth(_parent->depth + 1)
, signum(-(_parent->signum))
, alpha(_parent->alpha)
, beta(_parent->beta)
, is_exact(false)
, evaluated(false)
, depth_limit(_parent->depth_limit)
, max_branch(_parent->max_branch)
{
generateSteps();
}
Node::~Node()
{
delete child;
delete standing;
qDeleteAll(steps);
}
void Node::generateSteps()
{
steps.clear();
if (depth >= depth_limit || standing->target) {
heur_T hv = standing->hval;
heur_T decay = depth_decay * depth;
if (hv > 0)
hv -= decay;
else if (hv < 0)
hv += decay;
if (-decay <= hv && hv <= decay)
hv = 0;
alpha = beta = hv;
evaluated = true;
return;
}
suggestions_T suggestions;
standing->getSuggestions(suggestions);
for (suggestions_T::iterator s = suggestions.begin(); s != suggestions.end(); ++s) {
pos_T x = s->x;
pos_T y = s->y;
assert(!standing->table[x][y]);
auto p = new Standing(*this->standing);
p->step(x, y);
heur_T pv = p->hval * signum;
steps_T::iterator i;
for (i = steps.begin(); i != steps.end() && signum * (*i)->hval > pv; ++i)
;
steps.insert(i, p);
// we only keep the best looking positions
if ((unsigned int)steps.size() > max_branch) {
delete steps.back();
steps.pop_back();
}
}
assert(steps.size() > 0);
}
void Node::calcHash(hash_T *hash, NodeHashData *data)
{
data->remaining_depth = depth_limit - depth;
assert(data->remaining_depth > 0);
hash_T c_hash = 0;
for (int i = 0; i < standing->table_size_x; i++) {
for (int j = 0; j < standing->table_size_y; j++) {
c_hash = c_hash * 3145 + standing->table[i][j];
}
}
c_hash += standing->current;
data->checksum = c_hash;
c_hash = 0;
for (int i = 0; i < standing->table_size_x; i++) {
for (int j = 0; j < standing->table_size_y; j++) {
c_hash = (c_hash * 5313 + standing->table[i][j]) % nodeHashSize;
}
}
c_hash += standing->current;
*hash = c_hash;
}

115
ai/gabor/node.h Normal file
View File

@ -0,0 +1,115 @@
/*******************************************************************
*
* Copyright 2009 Pelladi Gabor <pelladigabor@gmail.com>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_NODE_H
#define BOVO_NODE_H
#include <QLinkedList>
#include "ai_interface.h"
#include "standing.h"
// list of following steps
using steps_T = QLinkedList<Standing *>;
// type of hash value
using hash_T = unsigned long long;
// hash table entry type
using entry_type_T = index_T;
enum { exact = 1, lower_bound = 2, upper_bound = 3 };
// pragmas are not in the C++ standard and Sun Studio does not support the pack(x, y) one
#if defined(__SUNPRO_CC) || defined(__SUNPRO_C)
#pragma pack()
#else
#pragma pack(push, 1)
#endif
// a hash table entry
struct NodeHashData {
// is this data for the current position?
hash_T checksum;
// the result we are storing in the hash table
heur_T value;
// how deep we searched when we stored this result
index_T remaining_depth;
// type of the entry
entry_type_T entry_type;
};
#if defined(__SUNPRO_CC) || defined(__SUNPRO_C)
#pragma(pack)
#else
#pragma pack(pop)
#endif
// hash table maximum memory
const hash_T nodeHashMem = 16 * 1024 * 1024;
// how many entries we can store in the memory limit
const hash_T nodeHashSize = nodeHashMem / sizeof(NodeHashData);
// a node of the alphabeta tree
class Node
{
public:
// the standing this ndoe refers to
Standing *standing;
// parent node in the tree
Node *parent;
// child node in the tree
Node *child;
// depth of the current node
index_T depth;
// 1 for starting player, -1 for the other
heur_T signum;
// alpha value
heur_T alpha;
// beta value
heur_T beta;
// is this alpha/beta value exact, or coming from an upper level?
bool is_exact;
// true if this node has been fully evaluated
bool evaluated;
// the good steps that can be done from here
steps_T steps;
// how deep we can go in the tree
int depth_limit;
// limits the amount of following steps to be investigated
unsigned int max_branch;
// construct the root node
Node(Standing *_standing, AiImpl *ai);
// construct a child node
Node(Standing *_standing, Node *_parent);
// destructor
~Node();
// generate following steps
void generateSteps();
// calculate hash data
void calcHash(hash_T *hash, NodeHashData *data);
};
#endif // BOVO_NODE_H

701
ai/gabor/standing.cpp Normal file
View File

@ -0,0 +1,701 @@
/*******************************************************************
*
* This file is part of the KDE project "Bovo"
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "standing.h"
#include <QString>
#include <cassert>
#include <cstdlib>
#include <memory.h>
using string = QString;
// these are used by refresh() and getSuggestions()
const static PatternCount suggestValues = {{0, 8, 8, 6, 5, 3}, {0, 7, 7, 4, 2, 1}};
const static index_T suggestValueCount = 9;
// these are used by refresh()
// '0' : player's mark
// '@' : wall (edge) or enemy's mark
// '+' : free cell, where the player can continue the position or the enemy can block the position
// '-' : free cell, where the enemy can block the position
// '.' : free cell, but nobody should place here
// '?' : everything but player's mark, ie. wall, enemy or empty
const static string level0[] = {QStringLiteral("00000")};
const static string level1[] = {QStringLiteral(".0000+")};
const static string level2[] = {QStringLiteral("@0000+"),
QStringLiteral("+0000@"),
QStringLiteral("00+00"),
QStringLiteral("?000+0?"),
QStringLiteral("?0+000?")};
const static string level3[] = {QStringLiteral(".-000+."),
QStringLiteral("-+000-@"),
QStringLiteral("@-000+-"),
QStringLiteral("?-00+0-"),
QStringLiteral("@0-00+0."),
QStringLiteral("-0+00-?"),
QStringLiteral(".0+00-0@"),
QStringLiteral(".0-00+0.")};
const static string level4[] = {QStringLiteral("@000++"),
QStringLiteral("++000@"),
QStringLiteral("@0+00+0@"),
QStringLiteral("@0+00+?"),
QStringLiteral("?+00+0@"),
QStringLiteral("@00+0+"),
QStringLiteral("+0+00@"),
QStringLiteral("@+000+@"),
QStringLiteral("@00++0"),
QStringLiteral("0++00@"),
QStringLiteral("?.00++0?"),
QStringLiteral("?0++00.?"),
QStringLiteral("?.00++00.?"),
QStringLiteral("?0+0+0?")};
const static string level5[] = {QStringLiteral("?++00++?"),
QStringLiteral("@-00++."),
QStringLiteral(".++00-@"),
QStringLiteral(".+0+0+."),
QStringLiteral("@-0+0+."),
QStringLiteral(".+0+0-@"),
QStringLiteral("@0-0++0-0@"),
QStringLiteral("@0-0++0-?"),
QStringLiteral("?-0++0-0@"),
QStringLiteral("?-0++0-?")};
const static index_T patternTotals[heurLevels] = {1, 1, 5, 8, 14, 10};
const static string *patterns[heurLevels] = {level0, level1, level2, level3, level4, level5};
static bool refresh_inited = false;
const static index_T max_pattern_length = 10;
const static index_T patterns_total = 39;
static index_T mark_inv[2][256];
struct PatternData {
index_T length;
index_T level;
mark_T mark[max_pattern_length];
index_T next[4][max_pattern_length + 1];
};
static PatternData patternData[patterns_total];
const static PatternData *patternDataEnd = &patternData[patterns_total];
inline heur_T max(heur_T a, heur_T b)
{
return a > b ? a : b;
}
inline heur_T max(heur_T a, heur_T b, heur_T c)
{
return max(max(a, b), c);
}
inline heur_T min(heur_T a, heur_T b)
{
return a < b ? a : b;
}
inline heur_T min(heur_T a, heur_T b, heur_T c)
{
return min(min(a, b), c);
}
inline heur_T norm(heur_T a)
{
return max(-WinTreshold + 1, min(WinTreshold - 1, a));
}
inline count_T max(count_T a, count_T b)
{
return a > b ? a : b;
}
inline count_T min(count_T a, count_T b)
{
return a < b ? a : b;
}
void Standing::initRefresh()
{
if (!refresh_inited) {
refresh_inited = true;
mark_inv[0][mark[0]] = 0;
mark_inv[0][mark[1]] = 1;
mark_inv[0][mark[2]] = 2;
mark_inv[0][mark[3]] = 3;
mark_inv[1][mark[0]] = 1;
mark_inv[1][mark[1]] = 0;
mark_inv[1][mark[2]] = 2;
mark_inv[1][mark[3]] = 3;
index_T patternDataIndex = 0;
for (index_T level = 0; level < heurLevels; ++level) {
for (index_T patternIndex = 0; patternIndex < patternTotals[level]; ++patternIndex) {
patternData[patternDataIndex].length = (index_T)patterns[level][patternIndex].size();
assert(patternData[patternDataIndex].length <= max_pattern_length);
memcpy(&patternData[patternDataIndex].mark[0], patterns[level][patternIndex].toLatin1().data(), patternData[patternDataIndex].length);
patternData[patternDataIndex].level = level;
for (index_T q = 0; q <= patternData[patternDataIndex].length; ++q) {
for (index_T a = 0; a < 4; ++a) {
index_T k = min(patternData[patternDataIndex].length, q + 1);
mark_T current_mark = mark[a];
while (true) {
mark_T current_pattern = patternData[patternDataIndex].mark[k - 1];
bool good = !current_mark ? current_pattern == '-' || current_pattern == '+' || current_pattern == '.' || current_pattern == '?'
: current_mark == mark[0] ? current_pattern == '0'
: current_pattern == '@' || current_pattern == '?';
if (good)
for (index_T i = 0; i < k - 1; ++i) {
mark_T mark1 = patternData[patternDataIndex].mark[i];
mark_T mark2 = patternData[patternDataIndex].mark[i + (q + 1 - k)];
if (mark1 == '-' || mark1 == '.')
mark1 = '+';
if (mark2 == '-' || mark2 == '.')
mark2 = '+';
// I do not want to duplicate every ? into + and @ because it would slow things down
// ? is accepted for now blindly, but extra check is needed for every match
if (mark1 == '?' && mark2 != '0')
mark2 = '?';
if (mark2 == '?' && mark1 != '0')
mark1 = '?';
if (mark1 != mark2) {
good = false;
break;
}
}
if (good)
break;
k--;
if (!k)
break;
}
patternData[patternDataIndex].next[a][q] = k;
}
}
++patternDataIndex;
}
}
assert(patternDataIndex == patterns_total);
}
}
Standing::Standing(pos_T _table_size_x, pos_T _table_size_y)
: table_size_x(_table_size_x)
, table_size_y(_table_size_y)
, hval(0)
, heur_seed(normal_heur_seed)
, target(false)
, stepCount(0)
, current(0)
, lastx(0)
, lasty(0)
{
memset(table, 0, sizeof(table));
memset(suggest, 0, sizeof(suggest));
memset(matchCount, 0, sizeof(matchCount));
memset(matchCountRow, 0, sizeof(matchCountRow));
memset(matchCountColumn, 0, sizeof(matchCountColumn));
memset(matchCountDiagonalSum, 0, sizeof(matchCountDiagonalSum));
memset(matchCountDiagonalDiff, 0, sizeof(matchCountDiagonalDiff));
memset(suggestRow, 0, sizeof(suggestRow));
memset(suggestColumn, 0, sizeof(suggestColumn));
memset(suggestDiagonalSum, 0, sizeof(suggestDiagonalSum));
memset(suggestDiagonalDiff, 0, sizeof(suggestDiagonalDiff));
}
void Standing::step(pos_T x, pos_T y)
{
assert(x < table_size_x && y < table_size_y);
table[x][y] = mark[current];
current = 1 - current;
lastx = x;
lasty = y;
++stepCount;
evaluate();
}
void Standing::step_server(pos_T x, pos_T y)
{
assert(x < table_size_x && y < table_size_y);
table[x][y] = mark[2];
++stepCount;
evaluate();
}
void Standing::posfRow(pos_T pos, int y, count_T value0, count_T value1)
{
pos_T x = pos - 1;
assert(x < table_size_x && y < table_size_y);
suggestRow[0][x][y] = max(suggestRow[0][x][y], value0);
suggestRow[1][x][y] = max(suggestRow[1][x][y], value1);
assert(!((suggestRow[0][x][y] || suggestRow[1][x][y]) && table[x][y]));
}
void Standing::posfColumn(pos_T pos, int x, count_T value0, count_T value1)
{
pos_T y = pos - 1;
assert(x < table_size_x && y < table_size_y);
suggestColumn[0][x][y] = max(suggestColumn[0][x][y], value0);
suggestColumn[1][x][y] = max(suggestColumn[1][x][y], value1);
assert(!((suggestColumn[0][x][y] || suggestColumn[1][x][y]) && table[x][y]));
}
void Standing::posfDiagonalSum(pos_T pos, int sum, count_T value0, count_T value1)
{
pos_T y0 = sum < table_size_x ? 0 : sum - table_size_x + 1;
pos_T y = y0 + pos - 1;
pos_T x = sum - y;
assert(x < table_size_x && y < table_size_y);
suggestDiagonalSum[0][x][y] = max(suggestDiagonalSum[0][x][y], value0);
suggestDiagonalSum[1][x][y] = max(suggestDiagonalSum[1][x][y], value1);
assert(!((suggestDiagonalSum[0][x][y] || suggestDiagonalSum[1][x][y]) && table[x][y]));
}
void Standing::posfDiagonalDiff(pos_T pos, int diff, count_T value0, count_T value1)
{
pos_T y0 = -diff > 0 ? -diff : 0;
pos_T y = y0 + pos - 1;
pos_T x = diff + y;
assert(x < table_size_x && y < table_size_y);
suggestDiagonalDiff[0][x][y] = max(suggestDiagonalDiff[0][x][y], value0);
suggestDiagonalDiff[1][x][y] = max(suggestDiagonalDiff[1][x][y], value1);
assert(!((suggestDiagonalDiff[0][x][y] || suggestDiagonalDiff[1][x][y]) && table[x][y]));
}
void Standing::evaluate()
{
countMatches();
decide();
if (current)
hval *= -1;
int current_seed = qrand() % (2 * (int)heur_seed + 1) - (int)heur_seed;
int hval_int = (int)hval + current_seed;
hval = hval_int > MaxHeur ? MaxHeur : hval_int < MinHeur ? MinHeur : hval_int;
}
void Standing::countMatches()
{
sample_T sample;
sample.reserve(max(table_size_x, table_size_y) + 2);
sample.push_back(mark[2]);
for (pos_T x = 0; x < table_size_x; ++x) {
sample.push_back(table[x][lasty]);
suggestRow[0][x][lasty] = 0;
suggestRow[1][x][lasty] = 0;
}
sample.push_back(mark[2]);
refresh(sample, matchCountRow[lasty], lasty, &Standing::posfRow);
sample.clear();
sample.push_back(mark[2]);
for (pos_T y = 0; y < table_size_y; ++y) {
sample.push_back(table[lastx][y]);
suggestColumn[0][lastx][y] = 0;
suggestColumn[1][lastx][y] = 0;
}
sample.push_back(mark[2]);
refresh(sample, matchCountColumn[lastx], lastx, &Standing::posfColumn);
sample.clear();
sample.push_back(mark[2]);
int sum = lastx + lasty;
assert(0 <= sum && sum < table_size_x + table_size_y - 1);
pos_T y0 = sum < table_size_x ? 0 : sum - table_size_x + 1;
pos_T ym = sum < table_size_y ? sum + 1 : table_size_y;
assert(y0 < ym);
for (pos_T y = y0; y < ym; ++y) {
sample.push_back(table[sum - y][y]);
suggestDiagonalSum[0][sum - y][y] = 0;
suggestDiagonalSum[1][sum - y][y] = 0;
}
sample.push_back(mark[2]);
refresh(sample, matchCountDiagonalSum[sum], sum, &Standing::posfDiagonalSum);
sample.clear();
sample.push_back(mark[2]);
int diff = lastx - lasty;
assert(-table_size_y < diff && diff < table_size_x);
y0 = diff < 0 ? -diff : 0;
ym = min(table_size_y, table_size_x - diff);
assert(y0 < ym);
for (pos_T y = y0; y < ym; ++y) {
sample.push_back(table[y + diff][y]);
suggestDiagonalDiff[0][y + diff][y] = 0;
suggestDiagonalDiff[1][y + diff][y] = 0;
}
sample.push_back(mark[2]);
refresh(sample, matchCountDiagonalDiff[diff + table_size_y - 1], diff, &Standing::posfDiagonalDiff);
}
void Standing::refresh(sample_T &sample_vect, PatternCount &local, int inv, posf_T posf)
{
PatternCount newCount;
memset(newCount, 0, sizeof(newCount));
auto sample_size = (pos_T)sample_vect.size();
mark_T sample[2 * max_table_size - 1];
for (pos_T i = 0; i < sample_size; ++i) {
sample[i] = sample_vect[i];
}
const pos_T range = 3;
pos_T begin_pos = 1;
while (!sample[begin_pos])
++begin_pos;
if (begin_pos < range)
begin_pos = 0;
else
begin_pos -= range;
int end_pos = sample_size - 2;
while (!sample[end_pos])
end_pos--;
if (end_pos + range > sample_size - 1)
end_pos = sample_size - 1;
else
end_pos += range;
index_T correct[2][patterns_total];
for (index_T i = 0; i < patterns_total; ++i) {
correct[0][i] = 0;
correct[1][i] = 0;
}
index_T player = current;
do {
index_T *correct_player = correct[player];
index_T *mark_inv_player = mark_inv[player];
for (pos_T i = begin_pos; i <= end_pos; ++i) {
index_T sample_a = mark_inv_player[sample[i]];
assert(sample_a < 4);
index_T *current_correct = correct_player;
for (PatternData *current_pattern = patternData; current_pattern != patternDataEnd; ++current_pattern) {
index_T current_correct_val = current_pattern->next[sample_a][*current_correct];
*current_correct = current_correct_val;
if (current_correct_val == current_pattern->length) {
mark_T *pattern = current_pattern->mark;
pos_T pattern_size = current_pattern->length;
index_T level = current_pattern->level;
pos_T match_start_pos = i + 1 - pattern_size;
// probably a match, but check once again because ? symbols
bool good_match = true;
for (pos_T j = 0; j < pattern_size; ++j) {
assert(match_start_pos + j < sample_size);
if ((pattern[j] == '+' || pattern[j] == '-' || pattern[j] == '.') && sample[match_start_pos + j]) {
good_match = false;
break;
}
if (pattern[j] == '@' && !sample[match_start_pos + j]) {
good_match = false;
break;
}
}
if (good_match) {
++newCount[player][level];
for (pos_T j = 0; j < pattern_size; ++j) {
assert(match_start_pos + j < sample_size);
if (pattern[j] == '+') {
(this->*posf)(match_start_pos + j, inv, suggestValues[player][level], suggestValues[1 - player][level]);
} else if (pattern[j] == '-') {
(this->*posf)(match_start_pos + j, inv, player == 0 ? 0 : suggestValues[1][level], player == 1 ? 0 : suggestValues[1][level]);
}
}
}
}
++current_correct;
}
}
player ^= 1;
} while (player != current);
for (index_T k = 0; k < heurLevels; ++k) {
assert(matchCount[0][k] >= local[0][k] && matchCount[1][k] >= local[1][k]);
matchCount[0][k] = matchCount[0][k] + newCount[0][k] - local[0][k];
matchCount[1][k] = matchCount[1][k] + newCount[1][k] - local[1][k];
local[0][k] = newCount[0][k];
local[1][k] = newCount[1][k];
assert(matchCount[0][k] >= local[0][k] && matchCount[1][k] >= local[1][k]);
}
}
void Standing::decide()
{
// I have a 5
if (matchCount[current][0]) {
target = true;
hval = MaxHeur;
return;
}
// the opponent has a 5
if (matchCount[1 - current][0]) {
target = true;
hval = MinHeur;
return;
}
// the table is full
if (stepCount >= table_size_x * table_size_y) {
target = true;
hval = 0;
return;
}
// I have an open or a closed 4
if (matchCount[current][1] || matchCount[current][2]) {
hval = MaxHeur - depth_decay;
return;
}
// the opponent has an open 4 or two closed 4-s
if (matchCount[1 - current][1] || matchCount[1 - current][2] >= 2) {
hval = MinHeur + 2 * depth_decay;
return;
}
/*
0 0
0 0
0 1
? ?
? ?
? ?
*/
heur_T self_attack_4 =
(-90 + 40 * matchCount[current][4] + 7 * matchCount[current][5] - 10 * matchCount[1 - current][4] - 7 * matchCount[1 - current][5]) * HeurPercent;
heur_T opponent_attack_4 =
(90 + 10 * matchCount[current][4] + 7 * matchCount[current][5] - 40 * matchCount[1 - current][4] - 7 * matchCount[1 - current][5]) * HeurPercent;
heur_T self_attack_3 =
(-90 + 40 * matchCount[current][4] + 28 * matchCount[current][5] - 10 * matchCount[1 - current][4] - 7 * matchCount[1 - current][5]) * HeurPercent;
heur_T opponent_attack_3 =
(90 + 10 * matchCount[current][4] + 7 * matchCount[current][5] - 40 * matchCount[1 - current][4] - 28 * matchCount[1 - current][5]) * HeurPercent;
heur_T self_defense =
(8 + 10 * matchCount[current][4] + 7 * matchCount[current][5] - 10 * matchCount[1 - current][4] - 7 * matchCount[1 - current][5]) * HeurPercent;
heur_T opponent_defense =
(-8 + 10 * matchCount[current][4] + 7 * matchCount[current][5] - 10 * matchCount[1 - current][4] - 7 * matchCount[1 - current][5]) * HeurPercent;
// the opponent has a 4 and a 3
if (matchCount[1 - current][2] == 1 && matchCount[1 - current][3] >= 1) {
hval = MinHeur + 4 * depth_decay;
return;
}
// the opponent has a 4 and I don't have a 3
if (matchCount[1 - current][2] == 1 && matchCount[current][3] == 0) {
hval = norm(min(opponent_attack_4, max(opponent_attack_3, self_attack_4), max(opponent_defense, self_attack_3)));
return;
}
// the opponent has a 4 and I have one 3
if (matchCount[1 - current][2] == 1 && matchCount[current][3] == 1) {
hval = norm(min(opponent_attack_4, max(self_attack_3, min(self_defense, opponent_attack_3))));
return;
}
// the opponent has a 4 and I have two 3-s
if (matchCount[1 - current][2] == 1 && matchCount[current][3] >= 2) {
hval = norm(opponent_attack_4);
return;
}
/*
? ?
? ?
? ?
*/
// I have a 3
if (matchCount[current][3] >= 1) {
hval = MaxHeur - 3 * depth_decay;
return;
}
/*
0 ?
? ?
? ?
*/
// the opponent has two 3-s and I don't have 4 possibilities
if (matchCount[1 - current][3] >= 2 && matchCount[current][4] == 0) {
hval = MinHeur + 4 * depth_decay;
return;
}
// the opponent has two 3-s and I have 4 possibilities
if (matchCount[1 - current][3] >= 2 && matchCount[current][4] >= 1) {
hval = norm(self_attack_4);
return;
}
/*
0 1
? ?
? ?
*/
// the opponent has a 3
if (matchCount[1 - current][3] == 1) {
hval = norm(max(self_attack_4, min(opponent_attack_3, max(opponent_defense, self_attack_3))));
return;
}
/*
? ?
? ?
*/
// I can attack
hval = norm(max(self_attack_4, min(self_attack_3, opponent_attack_4), min(self_defense, opponent_attack_3)));
}
void Standing::getSuggestions(suggestions_T &suggestions)
{
// should we use smart cut-offs or play like a fool?
if (heur_seed < MaxHeur) {
Field suggestPos[suggestValueCount];
assert((memset(suggestPos, 255, sizeof(suggestPos)), true));
for (pos_T x = 0; x < table_size_x; ++x) {
for (pos_T y = 0; y < table_size_y; ++y) {
count_T val = max(suggestRow[current][x][y], suggestColumn[current][x][y]);
val = max(val, suggestDiagonalSum[current][x][y]);
val = max(val, suggestDiagonalDiff[current][x][y]);
suggestPos[val] = Field(x, y);
suggest[current][x][y] = val;
assert(!(val && table[x][y]));
}
}
suggestions.clear();
// if I can win now, do it
if (matchCount[current][1] || matchCount[current][2]) {
assert(suggestPos[8].x != 255);
suggestions.push_back(suggestPos[8]);
return;
}
// if the opponent can win next turn, stop him
if (matchCount[1 - current][1] || matchCount[1 - current][2]) {
assert(suggestPos[7].x != 255);
suggestions.push_back(suggestPos[7]);
return;
}
// if I can make a clear 4, do it
if (matchCount[current][3]) {
assert(suggestPos[6].x != 255);
suggestions.push_back(suggestPos[6]);
return;
}
index_T treshold;
// if the opponent has at least two 3-s, try creating 4-s as a last chance
if (matchCount[1 - current][3] >= 2 && matchCount[current][4])
treshold = 5;
else
// if the opponent has a 3, close it
if (matchCount[1 - current][3])
treshold = 4;
else
// if I can make a lot of 3-s and 4-s then attack, or destroy opponent's 4 possibilities
if (matchCount[current][4] + matchCount[current][5] >= 3)
treshold = 2;
else
// if I can make 3-s and 4-s, attack or defend
if (matchCount[current][4] || matchCount[current][5])
treshold = 1;
else
// if the opponent can make 3-s and 4-s, defend
if (matchCount[1 - current][4] || matchCount[1 - current][5])
treshold = 1;
else
// if nobody has nothing, try some close positions
treshold = 0;
if (treshold <= 2) {
int count = 0;
// filter far away defensive positions
if (treshold > 0) {
for (pos_T x = 0; x < table_size_x; ++x) {
for (pos_T y = 0; y < table_size_y; ++y) {
if (suggest[current][x][y] && suggest[current][x][y] <= 2) {
pos_T x1 = x > 0 ? x - 1 : 0;
pos_T x2 = x < table_size_x - 1 ? x + 2 : table_size_x;
pos_T y1 = y > 0 ? y - 1 : 0;
pos_T y2 = y < table_size_y - 1 ? y + 2 : table_size_y;
bool far = true;
for (pos_T xx = x1; xx < x2 && far; ++xx) {
for (pos_T yy = y1; yy < y2 && far; ++yy) {
if (table[xx][yy])
far = false;
}
}
if (far)
suggest[current][x][y] = 0;
}
if (suggest[current][x][y])
++count;
}
}
}
// if there are not enough smart positions
if (count < 4) {
// check every near position
treshold = 1;
for (pos_T x = 0; x < table_size_x; ++x) {
for (pos_T y = 0; y < table_size_y; ++y) {
if (table[x][y] && table[x][y] != mark[2]) {
pos_T x1 = x > 0 ? x - 1 : 0;
pos_T x2 = x < table_size_x - 1 ? x + 2 : table_size_x;
pos_T y1 = y > 0 ? y - 1 : 0;
pos_T y2 = y < table_size_y - 1 ? y + 2 : table_size_y;
for (pos_T xx = x1; xx < x2; ++xx) {
for (pos_T yy = y1; yy < y2; ++yy) {
if (!table[xx][yy])
suggest[current][xx][yy] = 1;
}
}
}
}
}
}
}
for (pos_T x = 0; x < table_size_x; ++x) {
for (pos_T y = 0; y < table_size_y; ++y) {
if (suggest[current][x][y] >= treshold) {
suggestions.push_back(Field(x, y));
}
}
}
} else {
for (pos_T x = 0; x < table_size_x; ++x) {
for (pos_T y = 0; y < table_size_y; ++y) {
if (table[x][y] && table[x][y] != mark[2]) {
pos_T x1 = x > 0 ? x - 1 : 0;
pos_T x2 = x < table_size_x - 1 ? x + 2 : table_size_x;
pos_T y1 = y > 0 ? y - 1 : 0;
pos_T y2 = y < table_size_y - 1 ? y + 2 : table_size_y;
for (pos_T xx = x1; xx < x2; ++xx) {
for (pos_T yy = y1; yy < y2; ++yy) {
if (!table[xx][yy])
suggest[current][xx][yy] = 1;
}
}
}
}
}
for (pos_T x = 0; x < table_size_x; ++x) {
for (pos_T y = 0; y < table_size_y; ++y) {
if (suggest[current][x][y]) {
suggestions.push_back(Field(x, y));
}
}
}
}
assert(suggestions.size() > 0);
}

159
ai/gabor/standing.h Normal file
View File

@ -0,0 +1,159 @@
/*******************************************************************
*
* Copyright 2009 Pelladi Gabor <pelladigabor@gmail.com>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_STANDING_H
#define BOVO_STANDING_H
#include <QLinkedList>
#include <QVector>
#include "ai_interface.h"
// a mark on the table
using mark_T = unsigned char;
// occurrences of a certain position
using count_T = unsigned char;
// small index for a constant array
using index_T = unsigned char;
// table symbols indexed with player number
const mark_T mark[] = {'o', 'x', '!', '\0'};
// the game table
typedef mark_T table_T[max_table_size][max_table_size];
// the value of the fields for the two players for the next step
typedef count_T suggest_T[2][max_table_size][max_table_size];
// heuristic type
using heur_T = short;
// type for total number of marks on the table
using stepCount_T = unsigned short;
// maximal and minimal value of the heuristic function
const heur_T MaxHeur = 10000;
const heur_T MinHeur = -MaxHeur;
// one hundredth of the maximum value
const heur_T HeurPercent = MaxHeur / 100;
// values above WinTreshold mean winning positions
const heur_T WinTreshold = 98 * HeurPercent;
// heuristic value decreases by this amount times the current depth
const heur_T depth_decay = 5;
// if the seed is too big, do not use the hash
const heur_T normal_heur_seed = 2;
// number of categories used in the heuristic function
const index_T heurLevels = 6;
// occurrence of patterns for the two players
typedef count_T PatternCount[2][heurLevels];
// a row, column or diagonal of the table
using sample_T = QVector<mark_T>;
// interesting fields for the two players for the next step
using suggestions_T = QLinkedList<Field>;
class Standing;
// callback function to convert a position of the sample into coordinates, and update suggestions accordingly
using posf_T = void (Standing::*)(pos_T, int, count_T, count_T);
// game state class
class Standing
{
public:
// the current game table
table_T table;
// the size of the table
pos_T table_size_x, table_size_y;
// the heuristic value of the standing
heur_T hval;
// the random seed added to the heuristic value
heur_T heur_seed;
// true if a player has won
bool target;
// total number of marks on the table
stepCount_T stepCount;
// the player on turn
index_T current;
// the move that created this standing
pos_T lastx, lasty;
// following move suggestion values
suggest_T suggest;
// calculate constant values for refresh
static void initRefresh();
// new game
Standing(pos_T _table_size_x, pos_T _table_size_y);
// copy a game state
Standing(const Standing &other) = default;
Standing &operator=(const Standing &other) = default;
// make a step
void step(pos_T x, pos_T y);
// mark a field a "wall", where neither player can step
void step_server(pos_T x, pos_T y);
// get the interesting fields for the two players for the next step
void getSuggestions(suggestions_T &suggestions);
private:
// global occurrence of patterns
PatternCount matchCount;
// occurrence of patterns in each row
PatternCount matchCountRow[max_table_size];
// occurrence of patterns in each column
PatternCount matchCountColumn[max_table_size];
// occurrence of patterns in each diagonal, where the sum of coordinates is constant
PatternCount matchCountDiagonalSum[2 * max_table_size - 1];
// occurrence of patterns in each diagonal, where the difference of coordinates is constant
PatternCount matchCountDiagonalDiff[2 * max_table_size - 1];
// interesting field values coming from row patterns
suggest_T suggestRow;
// interesting field values coming from column patterns
suggest_T suggestColumn;
// interesting field values coming from diagonal patterns, where the sum of coordinates is constant
suggest_T suggestDiagonalSum;
// interesting field values coming from diagonal patterns, where the difference of coordinates is constant
suggest_T suggestDiagonalDiff;
// callback function to convert a position of the row sample into coordinates, and update suggestions accordingly
void posfRow(pos_T pos, int y, count_T value0, count_T value1);
// callback function to convert a position of the column sample into coordinates, and update suggestions accordingly
void posfColumn(pos_T pos, int x, count_T value0, count_T value1);
// callback function to convert a position of the sum diagonal sample into coordinates, and update suggestions accordingly
void posfDiagonalSum(pos_T pos, int sum, count_T value0, count_T value1);
// callback function to convert a position of the diff diagonal sample into coordinates, and update suggestions accordingly
void posfDiagonalDiff(pos_T pos, int diff, count_T value0, count_T value1);
// calculate heuristic value
void evaluate();
// count occurrences of the patterns
void countMatches();
// refresh matchCount and suggest variables after a step
// this function consumes 90% of the thinking time
void refresh(sample_T &sample, PatternCount &local, int inv, posf_T posf);
// process pattern occurrences
void decide();
};
#endif // BOVO_STANDING_H

5
bovo.qrc Normal file
View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/kxmlgui5/bovo">
<file alias="bovoui.rc">gui/bovoui.rc</file>
</qresource>
</RCC>

2
doc/CMakeLists.txt Normal file
View File

@ -0,0 +1,2 @@
kdoctools_create_handbook(index.docbook INSTALL_DESTINATION ${KDE_INSTALL_DOCBUNDLEDIR}/en SUBDIR bovo)

287
doc/index.docbook Normal file
View File

@ -0,0 +1,287 @@
<?xml version="1.0" ?>
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
<!ENTITY % English "INCLUDE" > <!-- change language only here -->
<!ENTITY % addindex "IGNORE"> <!-- do not change this! -->
]>
<book id="bovo" lang="&language;"> <!-- do not change this! -->
<bookinfo>
<title>The &bovo; Handbook</title>
<authorgroup>
<author>
<firstname>Aron</firstname><surname>Bostrom</surname>
<affiliation><address>&Aron.Bostrom.mail;</address></affiliation>
</author>
<author>
<firstname>Eugene</firstname><surname>Trounev</surname>
<affiliation><address><email>eugene.trounev@gmail.com</email></address></affiliation>
</author>
<!-- TRANS:ROLES_OF_TRANSLATORS -->
</authorgroup>
<copyright>
<year>2007</year>
<holder>Aron Bostrom</holder>
</copyright>
<legalnotice>&FDLNotice;</legalnotice>
<date>2021-06-21</date>
<releaseinfo>KDE Gear 21.04</releaseinfo>
<abstract>
<para>This documentation describes the game of &bovo; version 1.1</para>
</abstract>
<!--List of relevan keywords-->
<keywordset>
<keyword>KDE</keyword> <!-- do not change this! -->
<keyword>kdegames</keyword> <!-- do not change this! -->
<keyword>game</keyword> <!-- do not change this! -->
<keyword>bovo</keyword><!--Application name goes here-->
<!-- Game genre. Use as many as necessary. Available game types are: Arcade, Board, Card, Dice, Toys, Logic, Strategy.-->
<keyword>arcade</keyword>
<keyword>board</keyword>
<keyword>noughts and crosses</keyword>
<!--Number of possible players. It can be: One, Two,..., Multiplayer-->
<keyword>two players</keyword>
<!--All other relevant keywords-->
<keyword>noughts</keyword>
<keyword>crosses</keyword>
<keyword>Gomoku</keyword>
<keyword>Connect Five</keyword>
<keyword>Connect5</keyword>
<keyword>Board game</keyword>
<keyword>X and O</keyword>
<keyword>Five in a row</keyword>
<keyword>Puzzle</keyword>
</keywordset>
</bookinfo>
<!--Content begins here: -->
<chapter id="introduction"><title>Introduction</title> <!-- do not change this! -->
<note><title>Gametype:</title><para>Board, Arcade</para></note><!-- Game genre. Use as many as necessary. Available game types are: Arcade, Board, Card, Dice, Toys, Logic, Strategy.-->
<note><title>Number of possible players:</title><para>Two</para></note><!--Number of possible players. It can be: One, Two,..., Multiplayer-->
<!--Short game description starts here. 3-4 sentences (paragraphs)-->
<para>
&bovo; is a Gomoku (from Japanese <foreignphrase lang="ja">五目並べ</foreignphrase>, <quote>five points</quote>) like game for two players, where the opponents alternate in placing their respective pictogram on the game board.
The aim of this game is to connect five of your own pieces in an unbroken row vertically, horizontally or diagonally.
</para>
<note><title>Note:</title><para>Also known as: Connect Five, Five in a row, X and O, Noughts and Crosses</para></note>
</chapter>
<chapter id="howto"><title>How to play</title> <!-- do not change this! -->
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="mainscreen.png" format="PNG"/>
</imageobject>
<textobject>
<phrase>&bovo; main screen</phrase>
</textobject>
</mediaobject>
</screenshot>
<!--IMPORTANT: If the game has no defined objective, please remove the below line.-->
<note><title>Objective:</title><para>Connect five of your own pieces in an unbroken row vertically, horizontally or diagonally.</para></note>
<para>
The first time &bovo; is started it is launched in demo mode where two AI players battle each other. You can always start a new game using the <guibutton>New</guibutton> button on the toolbar, the <menuchoice><guimenu>Game</guimenu><guimenuitem>New</guimenuitem></menuchoice> menu entry on the menubar or using the default shortcut <keycombo action="simul">&Ctrl;<keycap>N</keycap></keycombo>.
</para>
<note><title>Note:</title><para>
Because the first player always has an advantage over the second player, &bovo; will alternate the players, switching them every new game.
</para></note>
<para>
If you are the first player - start the game by placing your pictogram anywhere on the playing field. If you are the second player wait until the first player places the pictogram and then do the same yourself. You can place your mark into any square on the field, unless its already occupied by another game piece (regardless of whether its your pictogram or that of your opponents).
</para>
<para>
You have to place your pieces in a way that prevents your opponent from connecting five marks in an unbroken row vertically, horizontally or diagonally. In the same time you have to connect five of your own pieces in an unbroken row vertically, horizontally or diagonally. Whoever succeeds in doing so first wins the round.
</para>
</chapter>
<chapter id="rules_and_tips"><title>Game Rules, Strategies and Tips</title> <!-- do not change this! -->
<!--This section has to do with game rules. Please give a detailed description of those using lists or paragraphs.-->
<sect1 id="rules">
<title>Game Rules</title>
<itemizedlist>
<listitem><para>Players take turn to place their respective marks on the playing board.</para></listitem>
<listitem><para>A player cannot move their already placed mark or put their mark upon an already placed mark.</para></listitem>
<listitem><para>Players cannot forfeit their turns.</para></listitem>
<listitem><para>Player who reaches five marks connected in a straight line (be it vertical, horizontal or diagonal) wins the game.</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="tips">
<title>Game Tips</title>
<itemizedlist>
<listitem><para>When &bovo; is started the first time, it needs resizing. Resize the game window to desired size, and &bovo; will scale up the playing board.</para></listitem>
<listitem><para>The first time &bovo; is started it is launched in demo mode, where two AI players battle each other.</para></listitem>
<listitem><para>When &bovo; is exited prior to game over, the active game is auto saved. If &bovo; detects an auto saved game at startup, it is restored. If not, &bovo; launches a demo mode.</para></listitem>
<listitem><para>You can always start a new game with the <guibutton>New</guibutton> button in the toolbar, the <menuchoice><guimenu>Game</guimenu><guimenuitem>New</guimenuitem></menuchoice> menu entry in the menubar or with the default shortcut <keycombo action="simul">&Ctrl;<keycap>N</keycap></keycombo>.</para></listitem>
<listitem><para>If a new game is started when a game is already active, it is counted as a loss.</para></listitem>
<listitem><para>Changing the difficulty can be done with the <guilabel>Difficulty</guilabel> drop down box in the right end of the status bar, or from the <menuchoice><guimenu>Settings</guimenu><guimenuitem>Difficulty</guimenuitem></menuchoice> menu entry in the menubar.</para></listitem>
<listitem><para>The effect of changing difficulty takes place immediately.</para></listitem>
<listitem><para>You can switch the theme of &bovo; from the <menuchoice><guimenu>Settings</guimenu> <guisubmenu>Theme</guisubmenu></menuchoice> menu entry in the menubar. The theme is then switched immediately.</para></listitem>
<listitem><para>Animation can be switched on or off as you like from the <menuchoice><guimenu>Settings</guimenu> <guimenuitem>Animation</guimenuitem></menuchoice> menu entry in the menubar.</para></listitem>
<listitem><para>If you just realized you made a very bad move, you have the possibility to undo your last move from the toolbar, the menubar or with the default undo keyboard shortcut <keycombo action="simul">&Ctrl;<keycap>Z</keycap></keycombo>.</para><para>You can keep on undoing moves until you reaches the beginning of the game.</para></listitem>
<listitem><para>If you don't know what move to make, you can get a hint from the computer player with the <guibutton>Hint</guibutton> button. The game piece suggested by the &bovo; AI then flashes for a brief period of time.</para></listitem>
<listitem><para>When a game is over, the <guibutton>Replay</guibutton> action is enabled, which starts a replay of the last game.</para></listitem>
</itemizedlist>
</sect1>
</chapter>
<chapter id="interface"><title>Interface Overview</title> <!-- do not change this! -->
<sect1 id="menu">
<title>Menu Items</title>
<variablelist>
<varlistentry>
<term><menuchoice>
<shortcut><keycombo action="simul">&Ctrl;<keycap>N</keycap></keycombo>
</shortcut>
<guimenu>Game</guimenu>
<guimenuitem>New</guimenuitem></menuchoice></term>
<listitem><para>Starts a new game.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<menuchoice>
<guimenu>Game</guimenu>
<guimenuitem>Replay</guimenuitem></menuchoice></term>
<listitem><para>Replay the last game.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut><keycombo action="simul">&Ctrl;<keycap>Q</keycap></keycombo>
</shortcut>
<guimenu>Game</guimenu>
<guimenuitem>Quit</guimenuitem></menuchoice></term>
<listitem><para>Selecting this item will end your current game, and exit
&bovo;.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>Z</keycap>
</keycombo>
</shortcut>
<guimenu>Move</guimenu>
<guimenuitem>Undo</guimenuitem>
</menuchoice>
</term>
<listitem>
<para><action>Undo the last move you made.</action></para>
</listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycap>H</keycap>
</shortcut>
<guimenu>Move</guimenu>
<guimenuitem>Hint</guimenuitem>
</menuchoice></term>
<listitem>
<para><action>Display</action> a hint for the next move. The game piece suggested by the &bovo; AI then flashes for a brief period of time.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Settings</guimenu><guisubmenu>Theme</guisubmenu></menuchoice></term>
<listitem><para>Choose one of the themes <guimenuitem>Scribble</guimenuitem>, <guimenuitem>High Contrast</guimenuitem>,
<guimenuitem>Spacy</guimenuitem> or <guimenuitem>Gomoku</guimenuitem> for the game.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Animation
</guimenuitem></menuchoice></term>
<listitem><para>Switch the animation on or off.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Settings</guimenu><guisubmenu>Difficulty</guisubmenu></menuchoice></term>
<listitem><para>Choose the game difficulty from various levels from <guimenuitem>Ridiculously Easy</guimenuitem>
up to <guimenuitem>Impossible</guimenuitem>.</para></listitem>
</varlistentry>
</variablelist>
<para>
Additionally &bovo; has the common &kde; <guimenu>Settings</guimenu> and <guimenu>Help</guimenu>
menu items, for more information read the sections about the <ulink url="help:/fundamentals/menus.html#menus-settings"
>Settings Menu</ulink> and <ulink url="help:/fundamentals/menus.html#menus-help">Help Menu</ulink>
of the &kde; Fundamentals.
</para>
</sect1>
</chapter>
<chapter id="faq"><title>Frequently asked questions</title> <!-- do not change this! -->
<!--This chapter is for frequently asked questions. Please use <qandaset> <qandaentry> only!-->
<qandaset>
<!--Following is a standard list of FAQ questions.-->
<qandaentry>
<question><para>I want to change the way this game looks. Can I? </para></question>
<answer><para>Yes. To change &bovo;'s visual theme you can use the <menuchoice><guimenu>Settings</guimenu><guisubmenu>Theme</guisubmenu>
</menuchoice> menu entry on the menubar.</para></answer>
</qandaentry>
<qandaentry>
<question><para>Can I use the keyboard to play this game? </para></question>
<answer><para>No. The game of &bovo; cannot be played using keyboard.</para></answer>
</qandaentry>
<qandaentry>
<question><para>I have to quit the game now, but I am not finished yet. Can I save my progress?</para></question>
<answer><para>No. There is no <quote>Save</quote> feature in &bovo; but &bovo; restores the latest unfinished game on startup.</para></answer>
</qandaentry>
<qandaentry>
<question><para>Where are the highscores?</para></question>
<answer><para>&bovo; does not have this feature.</para></answer>
</qandaentry>
<!--Please add more Q&As if needed-->
</qandaset>
</chapter>
<chapter id="credits"><title>Credits and License</title> <!-- do not change this! -->
<!--This chapter is for credits and licenses.-->
<para>
&bovo;
</para>
<para>
Program copyright 2002, 2007 &Aron.Bostrom; &Aron.Bostrom.mail;
</para>
<para>
Documentation copyright 2007 &Aron.Bostrom; &Aron.Bostrom.mail;</para>
<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
&underFDL;
&underGPL;
</chapter>
&documentation.index;
</book>
<!--
Local Variables:
mode: sgml
sgml-minimize-attributes:nil
sgml-general-insert-case:lower
sgml-omittag:t
sgml-shorttag:t
sgml-namecase-general:t
sgml-always-quote-attributes:t
sgml-indent-step:0
sgml-indent-data:nil
sgml-parent-document:nil
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
-->

BIN
doc/mainscreen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

78
game/board.cc Normal file
View File

@ -0,0 +1,78 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "board.h"
#include "coord.h"
#include "dimension.h"
#include "move.h"
#include "square.h"
/**
* @file file implementing class Board,
* which is really not a Board but an entire game.
*/
/** namespace for game engine */
namespace bovo {
Board::Board(const Dimension& dimension) {
m_dimension = new Dimension(dimension.width(), dimension.height());
m_board = new Square*[m_dimension->width()];
for (int x = 0; x < m_dimension->width(); ++x) {
m_board[x] = new Square[m_dimension->height()];
}
}
Board::~Board() {
for (int x = 0; x < m_dimension->width(); ++x) {
delete[] m_board[x];
}
delete[] m_board;
delete m_dimension;
}
bool Board::empty(const Coord& coord) const {
if (!ok(coord)) {
return false;
}
return m_board[coord.x()][coord.y()].empty();
}
bool Board::ok(const Coord& coord) const {
return m_dimension->ok(coord);
}
Player Board::player(const Coord& c) const {
if (!ok(c)) {
return No;
}
return m_board[c.x()][c.y()].player();
}
void Board::setPlayer(const Move& move) {
if (!ok(move.coord())) {
return;
}
m_board[move.x()][move.y()].setPlayer(move.player());
}
} /* namespace bovo */

128
game/board.h Normal file
View File

@ -0,0 +1,128 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_BOARD_H
#define BOVO_BOARD_H
#include "common.h"
/** @file file declaring class Board */
/** namespace for game engine */
namespace bovo
{
class Coord;
class Dimension;
class Move;
class Square;
/**
* A playing board
*
* This class might be somewhat missnamed. It doesn't just keep track of a
* playing board. It also keeps track of a game history, if a player has won,
* and in that case how it has won.
*
* Maybe this class should be renamed to Game, or a lot of its code moved into
* gui/Game. On the other hand, maybe gui/Game should be moved into game,
* making it game/Game. But as gui/Game is dependent on Qt4, which I have tried
* to make sure ai/ and game/ isn't, it would break that design decision.
*
* However, maybe that is a stupid design decision which deserves to be broken.
* After all, this is a KDE 4 project, right? Did we have in mind some other
* project reusing our background code?
*
* @code
* Dimension dimension(width, height);
* Board board(dimension);
* board.setPlayer(Coord(x, y), X);
* @endcode
*/
class Board
{
public:
/**
* @brief Constructs a Board with width and height
* @description Constructs a Board object with a width and height specified
* by a Dimension
* @param dimension the Dimension containing the width and height
*/
explicit Board(const Dimension &dimension);
/**
* @brief destructs this Board
* @description destructs this Board object
*/
~Board();
/**
* @brief is a Coord empty or set?
* @description tells whether a given Coord is marked as empty or
* marked by a player
* @param coord Coord to check
* @return @c true if coord is empty, @c false otherwise
*/
bool empty(const Coord &coord) const;
/**
* @brief is Game Over?
* @description tells whether game is over (someone has won)
* @return @c true if someone has won, @c false if game is still on
*/
bool gameOver() const;
/**
* @brief is a coord in board?
* @description tells whether a given coordinate is within the limits of
* this playing board.
* @param coord coordinate to verify
* @return \c true if coord exist, \c false otherwise
*/
bool ok(const Coord &coord) const;
/**
* @brief the player occupying a Coord
* @description tells which players occupies a certain square in the board
* @param coord the square to check
* @return @c X if player 1, @c O if player 2, @c No if empty
*/
Player player(const Coord &coord) const;
/**
* @brief set the player of a Coord
* @description sets which player should occupy a certain square in the
* playing board.
* @param move the move to perform
*/
void setPlayer(const Move &);
private:
/* property holding the actual playing board */
Square **m_board;
/* property containing the dimension of the actual playing board */
Dimension *m_dimension;
};
} /* namespace bovo */
#endif // BOVO_BOARD_H

120
game/common.h Normal file
View File

@ -0,0 +1,120 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_COMMON_H
#define BOVO_COMMON_H
/** @file file containing common system wide typedefs, enums and exceptions */
/* Number of columns and rows (the same) */
#define NUMCOLS 22
/** namespace for game engine */
namespace bovo
{
/* a very short positive natural number, such as a X or Y coordinate */
using usi = unsigned short;
/* a very long positive natural number, such as score for a certain square */
using uli = unsigned long;
/**
* @brief Exception for a busy square
* @description Exception thrown when you tries to set a player of a square
* that is already occupied by a player ("X" or "O").
*
* @code
* try {
* throw busy();
* } catch (busy) {
* //<i> error handling code</i>
* }
* @endcode
*/
struct busy {
};
/**
* @brief Exception for a coordinate outside board
* @description Exception thrown when a trying to refer to a coordinate
* outside of playing board.
*
* @code
* try {
* throw outOfBounds();
* } catch (outOfBounds) {
* //<i> error handling code</i>
* }
* @endcode
*/
struct outOfBounds {
};
/**
* @brief Exception for Game Over
* @description Exception thrown when a Game is already over.
*
* @code
* try {
* throw gameover();
* } catch (gameover) {
* //<i> error handling code</i>
* }
* @endcode
*/
struct gameover {
};
/**
* Exception thrown when a player isn't valid (neither "X", "O" nor "No")
*
* @code
* try {
* throw notValidPlayer();
* } catch (notValidPlayer) {
* //<i> error handling code</i>
* }
* @endcode
*/
struct notValidPlayer {
};
/**
* Enum for the player id
*/
enum Player {
X = 1, /**< Player 1 */
O = 2, /**< Player 2 */
No = 0 /**< No player (empty) */
};
/**
* Enum for whether a game is in demo mode or playing mode
*/
enum DemoMode {
Demo = true, /**< Game is a demo */
NotDemo = false /**< Game is not a demo */
};
} /* namespace bovo */
#endif // BOVO_COMMON_H

60
game/coord.cc Normal file
View File

@ -0,0 +1,60 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "coord.h"
/** @file file implementing class Coord */
/** namespace for game engine */
namespace bovo {
Coord::Coord(usi x, usi y): m_x(x), m_y(y) {
}
Coord Coord::down() const {
return Coord(m_x, m_y+1);
}
Coord Coord::left() const {
return Coord(m_x-1, m_y);
}
bool Coord::null() const {
return m_x == static_cast<usi>(-1) && m_y == static_cast<usi>(-1);
}
Coord Coord::right() const {
return Coord(m_x+1, m_y);
}
Coord Coord::up() const {
return Coord(m_x, m_y-1);
}
usi Coord::x() const {
return m_x;
}
usi Coord::y() const {
return m_y;
}
} /* namespace bovo */

136
game/coord.h Normal file
View File

@ -0,0 +1,136 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_COORD_H
#define BOVO_COORD_H
#include "common.h"
/** @file file declaring the Coord class */
/** namespace for game engine */
namespace bovo
{
/**
* A coordinate
*
* This class describes a coordinate on a playing field. It is
* used as a container of an (x, y) coordinate pair that starts to
* count with Origo (0, 0) in upper left corner. No negative coordinates
* are allowed.
*
* If both x and y coordinates are static_cast<unsigned short int>(-1),
* a special case is applied. Then the coordinate is invalid (all
* coordinates outside of playing area are invalid) but it also means
* that the coordinate refers to a moment before any moved has been played.
* This can be queried with null().
*
* @code
* Coord move(const Coord& coord) {
* if (coord.null()) {
* return computeAiTurn();
* } else {
* markCoordAsOpposite(coord);
* return computeAiTurn();
* }
* }
* @endcode
*/
class Coord
{
public:
/**
* @brief standard constructor
* @description constructs a Coord with given X and Y coordinates
* @param x X coordinate
* @param y Y coordinate
*/
explicit Coord(usi x = -1, usi y = -1);
/**
* @brief copy constructor
* @description constructs a Coord that is a copy of a given Coord
* @param coord Coord to copy
*/
Coord(const Coord &coord) = default;
Coord &operator=(const Coord &coord) = default;
/**
* @brief
* @description
* @return
*/
Coord down() const;
/**
* @brief
* @description
* @return
*/
Coord left() const;
/**
* @brief is null?
* @description tells if this coord is a null coordinate (-1, -1)
* @return \c true if x == -1 and y == -1, \c false otherwise
*/
bool null() const;
/**
* @brief
* @description
* @return
*/
Coord right() const;
/**
* @brief
* @description
* @return
*/
Coord up() const;
/**
* @brief
* @description
* @return
*/
usi x() const;
/**
* @brief
* @description
* @return
*/
usi y() const;
private:
/* X coordinate property */
usi m_x;
/* Y coordinate property */
usi m_y;
};
} /* namespace bovo */
#endif // BOVO_COORD_H

50
game/dimension.cc Normal file
View File

@ -0,0 +1,50 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "dimension.h"
#include "coord.h"
namespace bovo {
Dimension::Dimension(usi width, usi height)
: m_height(height), m_width(width) {
}
Dimension::Dimension(const Dimension& dimension)
= default;
usi Dimension::height() const {
return m_height;
}
usi Dimension::width() const {
return m_width;
}
bool Dimension::ok(const Coord* c) const {
return c->x() < m_width && c->y() < m_height;
}
bool Dimension::ok(const Coord& c) const {
return c.x() < m_width && c.y() < m_height;
}
} /* namespace bovo */

113
game/dimension.h Normal file
View File

@ -0,0 +1,113 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_DIMENSION_H
#define BOVO_DIMENSION_H
#include "common.h"
/** @file file declaring the Dimension class */
/** namespace for game engine */
namespace bovo
{
class Coord;
/**
* Dimension is logic container of the width and height of a playing board
*
* Dimension keeps the size data of a playing board, that is how wide and how
* high the board is. It can also be used to verify a given Coord is inside
* the limits of the Dimension (i.e. the Coord is a valid Coord on the playing
* board).
*
* @code
* Dimension dim1(15, 15);
* Dimension dim2(dim1);
* Coord coord(18, 7);
* dim1.ok(coord); // <i>returns false</i>
* for (int i = 0; i < dim2.width(); ++i) {
* }
* @endcode
*/
class Dimension
{
public:
/**
* @brief standard constructor
* @description constructs a Dimension with a certain width and height
* @param width the number of columns of this Dimension
* @param height the number of rows of this Dimension
*/
Dimension(usi width, usi height);
/**
* @brief copy constructor
* @description constructs a Dimension that is a copy of a given
* dimension
* @param dimension the dimension to copy
*/
Dimension(const Dimension &dimension);
/**
* @brief height of Dimension
* @description the height (number of rows) of this Dimension
* @return the height of this Dimension
*/
usi height() const;
/**
* @brief width of Dimension
* @description the width (number of columns) of this Dimension
* @return the width of this Dimension
*/
usi width() const;
/**
* @brief decides if a Coord is legal
* @description decides if a given Coord is legal
* (i.e. inside the bounds of this Dimension)
* @param coord the coord to test
* @return @c true if coord is inside bounds, $c false otherwise
*/
bool ok(const Coord *c) const;
/**
* @brief decides if a Coord is legal
* @description decides if a given Coord is legal
* (i.e. inside the bounds of this Dimension)
* @param coord the coord to test
* @return @c true if coord is inside bounds, $c false otherwise
*/
bool ok(const Coord &coord) const;
private:
/* height property */
usi m_height;
/* width property */
usi m_width;
};
} /* namespace bovo */
#endif // BOVO_DIMENSION_H

420
game/game.cc Normal file
View File

@ -0,0 +1,420 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/** @file game.cc implements class Game in namespace bovo */
#include "game.h"
#include <QTimer>
#include <QString>
#include <QStringList>
#include "ai.h"
#include "aifactory.h"
#include "board.h"
#include "coord.h"
#include "dimension.h"
#include "move.h"
using namespace ai;
/** namespace for gui stuff */
namespace bovo
{
Game::Game(const Dimension& dimension, Player startingPlayer,
KgDifficultyLevel::StandardLevel skill, DemoMode demoMode,
unsigned int playTime, AiFactory* aiFactory)
: m_aiFactory(aiFactory), m_curPlayer(startingPlayer),m_computerMark(O),
m_demoMode(demoMode), m_inUndoState(false), m_playerMark(X),
m_playTime(playTime), m_replaying(false) {
m_board = new Board(dimension);
m_ai = m_aiFactory->createAi(dimension, skill, m_computerMark, demoMode);
m_winDir = -1;
m_gameOver = false;
m_stepCount = 0;
connect(this, &Game::boardChanged,
m_ai, &Ai::changeBoard);
connect(this, &Game::oposerTurn, m_ai, &Ai::slotMove,
Qt::QueuedConnection);
connect(m_ai, SIGNAL(move(Move)),
this, SLOT(move(Move)));
}
Game::Game(const Dimension& dimension, const QStringList &restoreGame,
KgDifficultyLevel::StandardLevel skill, unsigned int playTime,
AiFactory* aiFactory)
: m_aiFactory(aiFactory), m_computerMark(O), m_demoMode(NotDemo),
m_inUndoState(false), m_playerMark(X), m_playTime(playTime),
m_replaying(false) {
m_board = new Board(dimension);
m_ai = m_aiFactory->createAi(dimension, skill, m_computerMark, NotDemo);
m_winDir = -1;
m_gameOver = false;
m_stepCount = 0;
m_curPlayer = No;
for (const QString &turn : restoreGame) {
QStringList tmp = turn.split(QLatin1Char(':'));
if (tmp.count() != 2) {
qFatal("Wrong save file format!");
}
Player tmpPlayer = (tmp[0] == QLatin1String("1")) ? X : O;
if (m_curPlayer == No) {
m_curPlayer = tmpPlayer;
}
tmp = tmp[1].split(QLatin1Char(','));
if (tmp.count() != 2) {
qFatal("Wrong save file format!");
}
bool ok;
uint x = tmp[0].toUInt(&ok);
if (!ok) {
qFatal("Wrong save file format!");
}
uint y = tmp[1].toUInt(&ok);
if (!ok) {
qFatal("Wrong save file format!");
}
Move tmpMove(tmpPlayer, Coord(x, y));
m_board->setPlayer(tmpMove);
m_stepCount++;
m_history << tmpMove;
}
}
Game::~Game() {
delete m_board;
delete m_ai;
}
bool Game::computerTurn() const {
return m_curPlayer == m_computerMark;
}
DemoMode Game::demoMode() const {
return m_demoMode;
}
bool Game::isGameOver() const {
return m_gameOver || m_demoMode;
}
QList<Move> Game::history() const {
return m_history;
}
Move Game::latestMove() const {
if (m_history.empty()) {
return Move();
} else {
return m_history.back();
}
}
bool Game::ok(const Coord& coord) const {
return m_board->ok(coord);
}
Player Game::player() const {
return m_playerMark;
}
Player Game::player(const Coord& coord) const {
return m_board->player(coord);
}
bool Game::save(const QString& filename) const {
Q_UNUSED( filename );
QString fileContent;
fileContent.append(QStringLiteral("<bovo width=\"%1\" height=\"%2\">")
.arg(QStringLiteral("")).arg(QStringLiteral("")));
for (const Move &move : qAsConst(m_history)) {
fileContent.append(QStringLiteral("<move player=\"%1\" x=\"%2\" y=\"%3\" />").
arg(move.player()).arg(move.x()).arg(move.y()));
}
fileContent.append(QLatin1String("</bovo>"));
return false;
}
QStringList Game::saveLast() const {
QStringList save;
for (const Move &move : qAsConst(m_history)) {
save << QStringLiteral("%1:%2,%3").arg(move.player())
.arg(move.x()).arg(move.y());
}
return save;
}
void Game::setSkill(KgDifficultyLevel::StandardLevel skill) {
if (m_ai!=nullptr)
m_ai->setSkill(skill);
}
void Game::start() {
if (computerTurn()) {
Q_EMIT oposerTurn();
} else {
Q_EMIT playerTurn();
}
}
void Game::startRestored() {
connect(this, &Game::boardChanged,
m_ai, &Ai::changeBoard);
for (const Move &move : qAsConst(m_history)) {
Q_EMIT boardChanged(move);
}
connect(this, &Game::oposerTurn, m_ai, &Ai::slotMove,
Qt::QueuedConnection);
connect(m_ai, SIGNAL(move(Move)),
this, SLOT(move(Move)));
if (!m_history.isEmpty() && m_history.last().player() == X) {
m_curPlayer = O;
Q_EMIT oposerTurn();
} else {
m_curPlayer = X;
Q_EMIT playerTurn();
}
if (!m_history.isEmpty()) {
Q_EMIT undoAble();
}
}
short Game::winDir() const {
return m_winDir;
}
bool Game::boardFull() const {
return m_stepCount >= NUMCOLS * NUMCOLS;
}
void Game::cancelAndWait() {
m_ai->cancelAndWait();
}
/* public slots */
void Game::move(const Move& move) {
bool tmp_emptyHistory = m_history.empty();
if (!m_board->empty(move.coord()) || move.player() != m_curPlayer
|| m_inUndoState) {
return;
}
makeMove(move);
if (tmp_emptyHistory && !m_history.empty() && !m_demoMode) {
Q_EMIT undoAble();
}
}
void Game::replay() {
if (m_gameOver && !m_replaying) {
m_replaying = true;
m_replayIterator = m_history.constBegin();
m_replayIteratorEnd = m_history.constEnd();
disconnect(this, &Game::replayBegin, this, &Game::replayNext);
connect(this, &Game::replayBegin, this, &Game::replayNext);
Q_EMIT replayBegin();
}
}
void Game::undoLatest() {
m_inUndoState = true;
if (m_history.empty() || m_demoMode) {
m_inUndoState = false;
return;
}
if (m_gameOver) {
m_gameOver = false;
m_winDir = -1;
connect(this, &Game::boardChanged,
m_ai, &Ai::changeBoard);
connect(this, &Game::oposerTurn, m_ai, &Ai::slotMove,
Qt::QueuedConnection);
connect(m_ai, SIGNAL(move(Move)),
this, SLOT(move(Move)));
}
if (m_curPlayer == m_computerMark) {
m_ai->cancelAndWait();
Move move(No, m_history.last().coord());
m_history.removeLast();
m_board->setPlayer(move);
m_stepCount--;
Q_EMIT boardChanged(move);
m_curPlayer = m_playerMark;
Q_EMIT playerTurn();
} else if (m_curPlayer == m_playerMark) {
Move move(No, m_history.last().coord());
m_history.removeLast();
m_board->setPlayer(move);
m_stepCount--;
Q_EMIT boardChanged(move);
if (m_history.count() == 0) {
m_curPlayer = m_computerMark;
Q_EMIT oposerTurn();
} else {
Move move2(No, m_history.last().coord());
m_history.removeLast();
m_board->setPlayer(move2);
m_stepCount--;
Q_EMIT boardChanged(move2);
Q_EMIT playerTurn();
}
}
if (m_history.empty() && !m_demoMode) {
Q_EMIT undoNotAble();
}
m_inUndoState = false;
}
/* private slots */
void Game::replayNext() {
if (m_replayIterator != m_replayIteratorEnd) {
QTimer::singleShot(m_playTime, this, &Game::replayNext);
Q_EMIT boardChanged(*m_replayIterator);
++m_replayIterator;
} else {
m_replaying = false;
Q_EMIT replayEnd(winningMoves()); // FIX:!!!!!!!
}
}
/* private methods */
void Game::makeMove(const Move& move) {
if (move.player() != m_curPlayer) {
return;
}
m_board->setPlayer(move);
m_stepCount++;
m_winDir = win(move.coord());
if (m_winDir != -1) {
m_gameOver = true;
} else {
if (boardFull()) {
m_gameOver = true;
}
}
m_history << move;
m_curPlayer = (m_curPlayer == X ? O : X );
Q_EMIT boardChanged(move);
if (m_gameOver) {
QList<Move> moves = winningMoves();
Q_EMIT gameOver(moves);
this->disconnect(m_ai);
} else {
if (computerTurn()) {
if (m_demoMode) {
QTimer::singleShot(m_playTime, this, &Game::oposerTurn);
} else {
Q_EMIT oposerTurn();
}
} else {
if (m_demoMode) {
QTimer::singleShot(m_playTime, this, &Game::playerTurn);
} else {
Q_EMIT playerTurn();
}
}
}
}
Coord Game::next(const Coord& coord, usi dir) const {
const usi LEFT = 1;
const usi UP = 2;
const usi RIGHT = 4;
const usi DOWN = 8;
Coord tmp = coord;
if (dir & LEFT) {
tmp = tmp.left();
} else if (dir & RIGHT) {
tmp = tmp.right();
}
if (dir & UP) {
tmp = tmp.up();
} else if (dir & DOWN) {
tmp = tmp.down();
}
return tmp;
}
short Game::win(const Coord& c) const {
const usi LEFT = 1;
const usi UP = 2;
const usi RIGHT = 4;
const usi DOWN = 8;
usi DIR[8] = {LEFT, RIGHT, UP, DOWN, LEFT | UP, RIGHT | DOWN,
LEFT | DOWN, RIGHT | UP};
Player p = player(c);
for (int i = 0; i < 4; ++i) {
usi count = 1;
Coord tmp = next(c, DIR[2*i]);
while (m_board->ok(tmp) && player(tmp) == p) {
++count;
tmp = next(tmp, DIR[2*i]);
}
tmp = next(c, DIR[2*i+1]);
while (m_board->ok(tmp) && player(tmp) == p) {
++count;
tmp = next(tmp, DIR[2*i+1]);
}
if (count >= 5) {
return i;
}
}
return -1;
}
QList<Move> Game::winningMoves() const {
if (m_winDir == -1) {
return {};
}
QList<Move> moves;
short dy, dx;
switch (m_winDir) {
case 0: dx = 1; dy = 0; break;
case 1: dx = 0; dy = 1; break;
case 2: dx = 1; dy = 1; break;
default: dx = 1; dy = -1; break;
}
usi x = latestMove().x();
usi y = latestMove().y();
Player winner = player(Coord(x, y));
Player tmp;
while ((tmp = player(Coord(x, y))) == winner) {
moves << Move(player(Coord(x, y)), Coord(x, y));
x += dx;
y += dy;
}
x = latestMove().x() - dx;
y = latestMove().y() - dy;
while ((tmp = player(Coord(x, y))) == winner) {
moves << Move(player(Coord(x, y)), Coord(x, y));
x -= dx;
y -= dy;
}
return moves;
}
}

367
game/game.h Normal file
View File

@ -0,0 +1,367 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/** @file game.h declares class Game in namespace bovo */
#ifndef BOVO_GAME_H
#define BOVO_GAME_H
#include <KgDifficulty>
#include <QList>
#include <QObject>
#include <QStringList>
#include "common.h"
/** namespace for ai */
namespace ai
{
class Ai;
class AiFactory;
} /* namespace ai */
using namespace ai;
/** namespace for game engine */
namespace bovo
{
class Board;
class Dimension;
class Coord;
class Move;
/**
* The Game engine
*
* This class is supposed to replace the gui/Game class and the game/board
* class.
*
* It keeps track of the both players (AI, network, gui or whatever).
* It keeps track of the playing board, and its playing history.
* It can walk up or down the playing history (undo).
* It can call an AI player of its own, to give the active player a hint.
* It decides if a game has ended (someone has won or it is a draw).
* It can tell which is the winning line and the winning move.
*
* @code
* Dimension dimension(width, height);
* Game game(dimension, X);
* MoveStatus status = game.move(Coord(x, y));
* if (status.error()) {
* qDebug() << status.toQString() << endl;
* // status.turn() == true => not your turn
* // status.busy() == true => tried to play an already busy coordinate
* // status.gameOver() == true => game is already over
* }
* @endcode
*/
class Game : public QObject
{
Q_OBJECT
public:
/**
* @brief Constructs a Game
* @description Constructs a Game object with a playing board with
* width and height specified by a given Dimension, a starting Player and
* an AI skill level
* @param dimension the Dimension specifying the width and height
* @param startingPlayer the player who starts
* @param skill the skill (difficulty level) of the AI
* @param demoMode whether this game is a demo or not
* @param playTime time in ms for space between turns in demo and replay
* @param aiFactory provider of AI implementations
*/
Game(const Dimension &dimension,
Player startingPlayer,
KgDifficultyLevel::StandardLevel skill,
DemoMode demoMode,
unsigned int playTime,
AiFactory *aiFactory);
/**
* @brief Re-Constructs a saved Game
* @description Constructs a Game object with a playing board with
* width and height specified by a given Dimension, a game history and
* an AI skill level
* @param dimension the Dimension specifying the width and height
* @param restoreGame the game history to restore
* @param skill the skill (difficulty level) of the AI
* @param playTime time in ms for space between turns in demo and replay
* @param aiFactory provider of AI implementations
*/
Game(const Dimension &dimension, const QStringList &restoreGame, KgDifficultyLevel::StandardLevel skill, unsigned int playTime, AiFactory *aiFactory);
/**
* @brief destructs this Game
* @description destructs this Game object
*/
~Game() override;
/**
* @brief is it the computer's turn?
* @description tells whether the computer is the one with the current turn
* @return \c true if computer is at turn, \c false otherwise
*/
bool computerTurn() const;
/**
* @brief is game in demo mode?
* @return \c Demo if game is in demo mode, \c NotDemo otherwise
*/
DemoMode demoMode() const;
/**
* @brief is Game Over?
* @description tells whether game is over (someone has won) or not
* @return \c true if game has ended, \c false if game is still on
*/
bool isGameOver() const;
/**
* @brief the game history
* @description gives the history as a linked list, starting with oldest
* moves first.
* @return the game history
*/
QList<Move> history() const;
/**
* @brief the latest move
* @description returns the latest move that has been performed
* @return the latest move performed
*/
Move latestMove() const;
/**
* @brief is this coordinate on board?
* @description tells whether this coordinate is within the limits of the
* playing board.
* @param coord coordinate to verify
* @return \c true if coordinate is ok, \c false otherwise
*/
bool ok(const Coord &coord) const;
/**
* @brief the player id
* @return the player id
*/
Player player() const;
/**
* @brief sets the AI skill
* @description sets the skill level of the AI
* @param skill new skill (difficulty level) for the AI
*/
void setSkill(KgDifficultyLevel::StandardLevel skill);
/**
* @brief starts a new turn
* @description starts a new turn
*/
void start();
/**
* @brief gets the player of a coordinate
* @description returns the player id of a coordinate in the playing board
* @param coord coordinate to query
* @return \c X, \c O, or \c No
*/
Player player(const Coord &coord) const;
/**
* @brief save game
* Saves this game to a file
* @param filename savegame file
* @return \c true if game was saved successfully, \c false otherwise
*/
bool save(const QString &filename) const;
/**
* @brief return game history if it is not over yet
* This is used for saving an unfinished game upon quitting bovo,
* so we can continue this game next time.
* @return formatted savefile without line breaks
*/
QStringList saveLast() const;
/**
* @brief start a game that have been restored.
*/
void startRestored();
/**
* @brief in which direction was the winning line?
* @description tells in what direction the gameover was caused, or -1 if
* game is still on.
* @return @c -1 if game isn't over, @c 0 for horizontal,
* @c 1 for vertical, @c 2 for diagonal upperleft downwards right,
* @c 3 for bottomleft upwards right
*/
short winDir() const;
/**
* @brief returns if the board is full
* @description returns true if every field on the table is occupied
*/
bool boardFull() const;
/**
* @brief cancel the AI if it is thinking and wait for actual cancellation
* @description interrupts the thinking of the AI if it is thinking, and
* does not return until the AI thread has really finished
*/
void cancelAndWait();
public Q_SLOTS:
/**
* @brief make a move
* @param move move to make
*/
void move(const Move &move);
/**
* @brief start replaying game
* Starts the replay of this game, emitting the signal \c replayBegin()
*/
void replay();
/**
* @brief undo the latest move in the history
*/
void undoLatest();
Q_SIGNALS:
/**
* @brief emitted at game over
* @param moves Winning moves (winning line)
*/
void gameOver(const QList<Move> &moves);
/**
* @brief emitted when board has changed (needs repainting)
* @param move the Move that has changed the board, player()==No means undo
*/
void boardChanged(const Move &move);
/**
* @brief emitted when it is the player's turn
*/
void playerTurn();
/**
* @brief emitted when it is the player's turn
*/
void oposerTurn();
/**
* @brief emitted at replay, signaling the UI to clear itself
*/
void replayBegin();
/**
* @brief emitted when replay ends
* @param moves winning line
*/
void replayEnd(const QList<Move> &moves);
/**
* @brief emitted once this game is allowed to be undoed
*/
void undoAble();
/**
* @brief emitted once this game no longer is allowed to be undoed
*/
void undoNotAble();
private Q_SLOTS:
void replayNext();
private:
/**
* @brief make a move
* @description performs the specified move.
* @param move move to make
*/
void makeMove(const Move &move);
/* get a neighbour coord in a given direction */
Coord next(const Coord &coord, usi direction) const;
/* calculates if a coord is part of a winning line */
short win(const Coord &coord) const;
/* returns the winning line */
QList<Move> winningMoves() const;
/* AI */
Ai *m_ai;
/* AI factory */
AiFactory *m_aiFactory;
/* playing board */
Board *m_board;
/* Current player */
Player m_curPlayer;
/* computer player id */
Player m_computerMark;
/* Whether this is a demo game or not */
DemoMode m_demoMode;
/* is game over? */
bool m_gameOver;
/* game history */
QList<Move> m_history;
/* if game is in Undo state */
bool m_inUndoState;
/* user player id */
Player m_playerMark;
/* time in between two moves in replay and demo mode, in milliseconds */
unsigned int m_playTime;
/* is game in replay mode? */
bool m_replaying;
/* replay iterator for history list */
QList<Move>::const_iterator m_replayIterator;
/* replay iterator for the end of the history */
QList<Move>::const_iterator m_replayIteratorEnd;
/* winning direction, or -1 if game isn't won */
short m_winDir;
/* the number of marks on the board */
short m_stepCount;
};
} /* namespace bovo */
#endif // BOVO_GAME_H

65
game/move.cc Normal file
View File

@ -0,0 +1,65 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/** @file move.cc implements Move */
#include "move.h"
#include "common.h"
/** namespace for game engine */
namespace bovo {
Move::Move(Player player, int col, int row)
: m_coord(col, row), m_player(player) {
}
Move::Move(Player player, const Coord& coord)
: m_coord(coord), m_player(player) {
}
Move::Move(const Move &m)
= default;
Move::~Move() = default;
Coord Move::coord() const {
return m_coord;
}
Player Move::player() const {
return m_player;
}
bool Move::valid() const {
return m_player != No && m_coord.x() < NUMCOLS && m_coord.y() < NUMCOLS;
}
usi Move::x() const {
return m_coord.x();
}
usi Move::y() const {
return m_coord.y();
}
} /* namespace bovo */

118
game/move.h Normal file
View File

@ -0,0 +1,118 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
/** @file move.h declares Move */
#ifndef BOVO_MOVE_H
#define BOVO_MOVE_H
#include "common.h"
#include "coord.h"
/** namespace for game engine */
namespace bovo
{
/**
* @brief class representing a move (a Coord and a Player id)
* @description this class represents a game move, that is a player id (Player)
* and a coordinate (Coord).
*
* @code
* Move illegalMove(); // represents the move "-1", i.e. the move before the
* // first move in the game
* Move myMove(X, Coord(x, y));
* Move identicalMove(myMove.player(), myMove.x(), myMove.y());
* illegalMove.valid() == false;
* myMove.valid == true; // if Coord(x, y) is in range
* @endcode
*/
class Move
{
public:
/**
* @brief constructs Move
* @description creates a Move with a Player and a coordinate
* @param player player
* @param col x-coordinate
* @param row y-coordinate
*/
explicit Move(Player player = No, int col = -1, int row = -1);
/**
* @brief constructs Move
* @description creates a Move with a Player and a coordinate
* @param player player
* @param coord coordinate
*/
Move(Player player, const Coord &coord);
/**
* @brief constructs Move
* @description copy constructor for Move
*/
Move(const Move &m);
~Move();
/**
* @brief returns the Coord
* @return the coordinate
*/
Coord coord() const;
/**
* @brief returns the Player
* @return the player
*/
Player player() const;
/**
* @brief returns whether this is a valid move
* @description tells if the player of this move is X or O and the coord
* is within the playing board limits.
* @return \c true if move is valid, \c false otherwise
*/
bool valid() const;
/**
* @brief x-coordinate
* @return the x-coordinate
*/
usi x() const;
/**
* @brief y-coordinate
* @return the y-coordinate
*/
usi y() const;
private:
/* the coordinate */
Coord m_coord;
/* the player */
Player m_player;
};
} /* namespace gui */
#endif // BOVO_MOVE_H

44
game/square.cc Normal file
View File

@ -0,0 +1,44 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "square.h"
/** @file file implementing the Square class */
/** namespace for game engine */
namespace bovo {
Square::Square() : m_player(No) {
}
Player Square::player() const {
return m_player;
}
bool Square::empty() const {
return m_player == No;
}
void Square::setPlayer(Player player) {
m_player = player;
}
} /* namespace bovo */

88
game/square.h Normal file
View File

@ -0,0 +1,88 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_SQUARE_H
#define BOVO_SQUARE_H
#include "common.h"
/** @file file declaring the Square class */
/** namespace for game engine */
namespace bovo
{
/**
* A class representing a square in a playing board
*
* This class represents a Square in a playing board. It knows
* if it is empty or if it is marked by a player.
* You can set it to a player, if it is empty, otherwise it will
* throw an exception @c busy.
*
* @code
* Square square;
* if (square.empty()) { // <i>this will be true</i>
* square.setPlayer(X);
* }
* Player player = square.player(); // <i>X</i>
* @endcode
*/
class Square
{
public:
/**
* @brief Empty constructor
* @description Thie constructs an empty square,
* occupied by no player at all.
*/
Square();
/**
* @brief Is this Square empty?
* @description Tells whether this square is empty (@c true)
* or occupied by a player (@c false)
* @return @c true if square is empty, @c false otherwise
*/
bool empty() const;
/**
* @brief player of this square
* @description tells whether this square is occupied by
* player 1, player 2 och no player at all (empty).
* @return player id (X or O) or (No) if empty
*/
Player player() const;
/**
* @brief sets player id of this square
* @description sets the player id of this square to X or O
*/
void setPlayer(Player player);
private:
/* player property of this Square */
Player m_player;
};
} /* namespace bovo */
#endif // BOVO_SQUARE_H

3
game/test/CMakeLists.txt Normal file
View File

@ -0,0 +1,3 @@
add_executable (testbovo test.cpp)
target_link_library (testbovo game)
install (TARGETS testbovo ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})

409
game/test/test.cpp Normal file
View File

@ -0,0 +1,409 @@
/*******************************************************************
*
* Copyright 2002,2007 Aron Boström <aron.bostrom@gmail.com>
*
* This file is part of the KDE project "Bovo"
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include <cstdlib>
#include <ctime>
#include <iostream>
#include "board.h"
#include "dim.h"
using namespace luffarschack;
using namespace std;
struct error {
};
int tests = 0;
char ESC = 27;
void ok(const string &s)
{
cout << " " << s << "... ";
cout.setf(ios::right);
cout << ESC << "[32m"
<< " [OK] " << ESC << "[0m" << endl;
cout.setf(ios::left);
++tests;
}
void fail(const string &s)
{
cout << " " << s << "... ";
cout.setf(ios::right);
cout << ESC << "[31m"
<< " FAILED! " << ESC << "[0m" << endl;
cout.setf(ios::left);
}
void ass(const bool b, const string &s) throw(error)
{
if (b) {
ok(s);
return;
} else {
fail(s);
throw error();
}
}
void status(const string &s)
{
cout << endl << ESC << "[33m" << s << ':' << ESC << "[0m" << endl;
}
void testWidthHeight() throw(error)
{
status("Testing width and height");
short int WIDTH = 7;
short int HEIGHT = 9;
board b(WIDTH, HEIGHT);
ass(b.width() == WIDTH, "width() for board(int, int)");
ass(b.height() == HEIGHT, "height() for board(int, int)");
ass(b.width() != HEIGHT, "width != height for board(int, int)");
WIDTH = 13;
board b2(dim(WIDTH, HEIGHT));
ass(b2.width() == WIDTH, "width() for board(dim)");
ass(b2.height() == HEIGHT, "height() for board(dim)");
ass(b2.height() != WIDTH, "height != width for board(dim)");
}
void testOutsideBoundaries() throw(error)
{
status("Testing boundaries");
short int WIDTH = 3;
short int HEIGHT = 4;
board b(WIDTH, HEIGHT);
board b2(dim(WIDTH, HEIGHT));
bool test = false;
try {
for (short int i = 0; i < WIDTH; ++i)
for (short int j = 0; j < HEIGHT; ++j) {
coord c(i, j);
b.empty(c);
b2.empty(c);
b.player(c);
b2.player(c);
}
test = true;
} catch (outOfBounds) {
test = false;
}
ass(test, "inside boundaries");
test = false;
try {
coord c(-1, 0);
b.empty(c);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "empty() lesser than width");
test = false;
try {
coord c(0, -1);
b.empty(c);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "empty() lesser than height");
test = false;
try {
coord c(WIDTH, 0);
b.empty(c);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "empty() too wide");
test = false;
try {
coord c(0, HEIGHT);
b.empty(c);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "empty() too high");
test = false;
try {
coord c(-1, 0);
b.player(c);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "player() lesser than width");
test = false;
try {
coord c(0, -1);
b.player(c);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "player() lesser than height");
test = false;
try {
coord c(WIDTH, 0);
b.player(c);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "player() too wide");
test = false;
try {
coord c(0, HEIGHT);
b.player(c);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "player() too high");
test = false;
try {
coord c(-1, 0);
b.setPlayer(c, 1);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "setPlayer() lesser than width");
test = false;
try {
coord c(0, -1);
b.setPlayer(c, 1);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "setPlayer() lesser than height");
test = false;
try {
coord c(WIDTH, 0);
b.setPlayer(c, 1);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "setPlayer() too wide");
test = false;
try {
coord c(0, HEIGHT);
b.setPlayer(c, 1);
test = false;
} catch (outOfBounds) {
test = true;
}
ass(test, "setPlayer() too high");
}
void testSetPlayerAndEmpty() throw(error)
{
status("Testing setPlayer(coord, unsigned short int) and checking with empty(coord) and player(coord)");
unsigned short int WIDTH = 3;
unsigned short int HEIGHT = 4;
board b(WIDTH, HEIGHT);
bool test = false;
try {
for (unsigned short int i = 0; i < WIDTH; ++i)
for (unsigned short int j = 0; j < HEIGHT; ++j) {
coord c(i, j);
if (!b.empty(c) || b.player(c) != 0)
throw error();
}
test = true;
} catch (error) {
test = false;
}
ass(test, "board is empty and player is 0");
test = false;
try {
coord c(1, 1);
b.setPlayer(c, 1);
for (unsigned short int i = 0; i < WIDTH; ++i)
for (unsigned short int j = 0; j < HEIGHT; ++j) {
if (i == 1 && j == 1)
continue;
coord c2(i, j);
if (!b.empty(c2) || b.player(c2) != 0)
throw busy();
}
ass(b.player(c) == 1, "setPlayer(coord, 1) -> player(coord) == 1");
test = true;
} catch (busy) {
test = false;
}
ass(test, "board should still be empty");
test = false;
try {
coord c(1, 1);
b.setPlayer(c, 1);
test = false;
} catch (busy) {
test = true;
}
ass(test, "setPlayer(coord, 1) again should fail");
test = false;
try {
coord c(1, 1);
b.setPlayer(c, 2);
test = false;
} catch (busy) {
test = true;
}
ass(test, "setPlayer(coord, 2) should also fail");
ass(b.player(coord(1, 1)) == 1, "player(coord) should still be 1");
test = false;
try {
for (unsigned short int i = 0; i < WIDTH; ++i)
for (unsigned short int j = 0; j < HEIGHT; ++j) {
if (i == 1 && j == 1)
continue;
coord c2(i, j);
b.setPlayer(c2, 2);
}
ass(b.player(coord(0, 0)) == 2, "setPlayer(coord, 2) -> player(coord) == 2");
test = true;
} catch (busy) {
test = false;
}
ass(test, "board should be setable");
}
void testGameOver()
{
status("Testing game over");
unsigned short int WIDTH = 29;
unsigned short int HEIGHT = 29;
board b(dim(WIDTH, HEIGHT));
ass(!b.setPlayer(coord(1, 1), 1), "not five in row shouldn't win");
ass(!b.setPlayer(coord(2, 1), 1), "not five in row shouldn't win");
ass(!b.setPlayer(coord(4, 1), 1), "not five in row shouldn't win");
ass(!b.setPlayer(coord(5, 1), 1), "not five in row shouldn't win");
ass(!b.setPlayer(coord(6, 1), 1), "not five in row shouldn't win");
ass(!b.setPlayer(coord(7, 1), 1), "not five in row shouldn't win");
ass(!b.setPlayer(coord(3, 1), 2), "not five in row shouldn't win");
ass(!b.setPlayer(coord(8, 1), 2), "not five in row shouldn't win");
ass(!b.setPlayer(coord(9, 1), 1), "not five in row shouldn't win");
ass(!b.setPlayer(coord(10, 1), 1), "not five in row shouldn't win");
ass(!b.setPlayer(coord(11, 1), 1), "not five in row shouldn't win");
ass(!b.setPlayer(coord(13, 1), 1), "not five in row shouldn't win");
ass(!b.setPlayer(coord(14, 1), 1), "not five in row shouldn't win");
ass(!b.setPlayer(coord(15, 1), 1), "not five in row shouldn't win");
ass(b.setPlayer(coord(12, 1), 1), "five in row should win");
try {
b.setPlayer(coord(16, 1), 1);
ass(false, "Nothing should be done when game is over");
} catch (gameover) {
ass(b.empty(coord(16, 1)), "Nothing should be done when game is over");
}
board b5(dim(WIDTH, HEIGHT));
b5.setPlayer(coord(3, 2), 2);
b5.setPlayer(coord(4, 2), 2);
b5.setPlayer(coord(5, 2), 2);
ass(!b5.setPlayer(coord(6, 2), 2), "not five in row shouldn't win");
ass(b5.setPlayer(coord(7, 2), 2), "five in row SHOULD win");
board b4(dim(WIDTH, HEIGHT));
b4.setPlayer(coord(0, 0), 2);
b4.setPlayer(coord(1, 1), 2);
b4.setPlayer(coord(2, 2), 2);
ass(!b4.setPlayer(coord(3, 3), 2), "not five in diag shouldn't win");
ass(b4.setPlayer(coord(4, 4), 2), "five in diag SHOULD win");
board b2(dim(WIDTH, HEIGHT));
b2.setPlayer(coord(4, 0), 2);
b2.setPlayer(coord(3, 1), 2);
b2.setPlayer(coord(2, 2), 2);
ass(!b2.setPlayer(coord(1, 3), 2), "not five in other diag shouldn't win");
ass(b2.setPlayer(coord(0, 4), 2), "five in other diag SHOULD win");
board b3(dim(WIDTH, HEIGHT));
b3.setPlayer(coord(4, 0), 2);
b3.setPlayer(coord(4, 1), 2);
b3.setPlayer(coord(4, 2), 2);
ass(!b3.setPlayer(coord(4, 3), 2), "not five in col shouldn't win");
ass(b3.setPlayer(coord(4, 4), 2), "five in col SHOULD win");
}
void testSetNonvalidPlayer()
{
status("Testing setting a non-valid player");
board b = board(dim(1, 1));
bool test = false;
try {
b.setPlayer(coord(0, 0), 0);
test = false;
} catch (notValidPlayer) {
test = true;
}
ass(test, "player 0 (empty) should not work");
test = false;
try {
b.setPlayer(coord(0, 0), 3);
test = false;
} catch (notValidPlayer) {
test = true;
}
ass(test, "player 3 should not work either");
}
void testEcho()
{
board b = board(dim(20, 20));
unsigned short int player = 1;
qsrand((unsigned)time(0));
try {
while (true) {
coord c(0, 0);
while (true) {
c = coord(qrand() % 20, qrand() % 20);
if (b.empty(c))
break;
}
b.setPlayer(c, player);
player = player % 2 + 1;
}
} catch (busy) {
} catch (gameover) {
cout << endl << "Player " << player % 2 + 1 << " won" << endl;
}
b.echo();
}
int main()
{
try {
testWidthHeight();
testOutsideBoundaries();
testSetPlayerAndEmpty();
testSetNonvalidPlayer();
testGameOver();
testEcho();
cout << endl << ESC << "[32m" << tests << " tests passed!" << ESC << "[0m" << endl;
} catch (error) {
cerr << endl
<< ESC << "[31m"
<< "FEL FEL FEL!!!" << ESC << "[0m" << endl;
}
}

31
gui/bovo.kcfg Normal file
View File

@ -0,0 +1,31 @@
<?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" >
<kcfgfile name="bovorc"/>
<group name="bovo">
<entry name="theme" type="String">
<label>Theme</label>
<default>scribble</default>
</entry>
<entry name="playbackSpeed" type="Int">
<label>Speed of demo and replay playback.</label>
<min>150</min>
<max>2000</max>
<default>400</default>
</entry>
<entry name="animation" type="Bool">
<label>Whether moves should be animated or not.</label>
<default>true</default>
</entry>
<entry name="ai" type="Enum">
<label>AI engine to use.</label>
<choices>
<choice name="Gabor" />
<choice name="Aron" />
</choices>
<default>Gabor</default>
</entry>
</group>
</kcfg>

25
gui/bovoui.rc Normal file
View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<gui name="bovo"
version="5"
xmlns="http://www.kde.org/standards/kxmlgui/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0
http://www.kde.org/standards/kxmlgui/1.0/kxmlgui.xsd">
<MenuBar>
<Menu name="game">
<Action name="replay" />
</Menu>
<Menu name="settings">
<Action name="themes" />
<Action name="animation" />
</Menu>
</MenuBar>
<ToolBar name="mainToolBar">
<Action name="game_new" />
<Action name="replay" />
<Separator />
<Action name="move_undo" />
<Action name="move_hint" />
</ToolBar>
</gui>

132
gui/hintitem.cc Normal file
View File

@ -0,0 +1,132 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "hintitem.h"
#include <QTimer>
#include <QPainter>
#include <QSvgRenderer>
#include "common.h"
#include "coord.h"
#include "move.h"
#include "scene.h"
using namespace bovo;
namespace gui {
HintItem::HintItem(Scene* scene, const Move& hint, bool animate, qreal fill)
: QGraphicsSvgItem(), m_scene(scene), m_row(hint.y()),
m_col(hint.x()), m_fill(fill) {
m_sizeShrink = 1.0/(qrand()%5+7.0);
setElementId(QString(hint.player() == X ? QStringLiteral("x%1") : QStringLiteral("o%1"))
.arg(QString::number(qrand() % 5 + 1)));
m_tick = 16;
m_tickUp = true;
m_ticker = nullptr;
if (animate) {
m_ticker = new QTimer(this);
m_opacity = 0.0;
connect(m_ticker, &QTimer::timeout, this, &HintItem::tick);
m_ticker->start(30);
} else {
m_opacity = 0.4;
}
setPos(m_scene->cellCenter(m_col, m_row));
}
HintItem::~HintItem() {
if (m_ticker) {
disconnect(m_ticker, nullptr, this, nullptr);
m_ticker->stop();
m_ticker->deleteLater();
}
}
QRectF HintItem::boundingRect() const {
qreal width = m_scene->squareSize();
qreal height = width;
qreal margin = (1.0-m_fill) * width / 2.0;
return { -width / 2.0 + margin,
-height / 2.0 + margin,
width - 2.0*margin,
height - 2.0*margin};
}
void HintItem::killAnimation() {
if (m_ticker) {
m_ticker->stop();
disconnect(m_ticker, nullptr, this, nullptr);
m_opacity = 0.4;
update();
}
}
void HintItem::kill() {
connect(m_ticker, &QTimer::timeout, this, &HintItem::killTick);
m_ticker->start();
}
void HintItem::killTick() {
m_opacity -= 0.05;
update();
if (m_opacity <= 0.05) {
m_ticker->stop();
Q_EMIT killed();
}
}
void HintItem::tick() {
--m_tick;
if (m_tick == 0) {
killAnimation();
} else {
if (m_tickUp && m_tick > 5) {
m_opacity += 0.1;
} else if (m_tickUp) {
m_opacity -= 0.1;
m_tickUp = false;
} else {
m_opacity -= 0.1;
}
update();
}
}
// HintItem::setEnabled(enabled) {
// m_enabled = enabled;
// }
void HintItem::paint(QPainter *p, const QStyleOptionGraphicsItem*, QWidget*) {
p->setOpacity(m_opacity);
renderer()->render(p, elementId(), boundingRect());
}
void HintItem::setFill(qreal fill) {
m_fill = fill;
}
} /* namespace gui */

76
gui/hintitem.h Normal file
View File

@ -0,0 +1,76 @@
/*******************************************************************
*
* This file is part of the KDE project "Bovo"
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_HINTITEM_H
#define BOVO_HINTITEM_H
#include <QGraphicsSvgItem>
class QTimer;
namespace bovo
{
class Move;
}
using namespace bovo;
namespace gui
{
class Scene;
class HintItem : public QGraphicsSvgItem
{
Q_OBJECT
public:
HintItem(Scene *scene, const Move &move, bool animate = true, qreal fill = 0.75);
~HintItem() override;
void killAnimation();
void kill();
void setFill(qreal fill);
QRectF boundingRect() const override;
public Q_SLOTS:
void tick();
void killTick();
Q_SIGNALS:
void killed();
protected:
void paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *widget = nullptr) override;
private:
Scene *m_scene;
int m_row;
int m_col;
int m_tick;
bool m_animate;
qreal m_opacity;
bool m_tickUp;
qreal m_sizeShrink, m_fill;
QTimer *m_ticker;
};
} /* namespace gui */
#endif // BOVO_HINTITEM_H

76
gui/main.cc Normal file
View File

@ -0,0 +1,76 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include <QApplication>
#include <QCommandLineParser>
#include <KAboutData>
#include <Kdelibs4ConfigMigrator>
#include <KLocalizedString>
#include <KDBusService>
#include <KCrash>
#include "mainwindow.h"
#include "bovo_version.h"
using namespace gui;
int main(int argc, char **argv) {
// Fixes blurry icons with fractional scaling
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
QApplication app(argc, argv);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
Kdelibs4ConfigMigrator migrate(QStringLiteral("bovo"));
migrate.setConfigFiles(QStringList() << QStringLiteral("bovorc"));
migrate.setUiFiles(QStringList() << QStringLiteral("bovoui.rc"));
migrate.migrate();
#endif
KLocalizedString::setApplicationDomain("bovo");
KAboutData aboutData(QStringLiteral("bovo"), i18n("Bovo"),
QStringLiteral(BOVO_VERSION_STRING), i18n("KDE Five in a Row Board Game"), KAboutLicense::GPL,
i18n("(c) 2002-2007, Aron Boström"), QString(), QStringLiteral("https://kde.org/applications/games/org.kde.bovo"));
aboutData.addAuthor(i18n("Aron Boström"),i18n("Author"),
QStringLiteral("aron.bostrom@gmail.com"));
aboutData.setOrganizationDomain(QByteArray("kde.org"));
app.setWindowIcon(QIcon::fromTheme(QStringLiteral("bovo")));
aboutData.setProductName(QByteArray("bovo"));
KAboutData::setApplicationData(aboutData);
KCrash::initialize();
QCommandLineParser parser;
aboutData.setupCommandLine(&parser);
parser.process(app);
aboutData.processCommandLine(&parser);
KDBusService service;
if( app.isSessionRestored() ) {
kRestoreMainWindows<MainWindow>();
} else {
auto mainWin = new MainWindow();
mainWin->show();
}
return app.exec();
}

480
gui/mainwindow.cc Normal file
View File

@ -0,0 +1,480 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
// Class declaration
#include "mainwindow.h"
// Qt includes
#include <QWidget>
#include <QTimer>
#include <QBrush>
#include <QDir>
#include <QLabel>
#include <QIcon>
// KDE includes
#include <KActionCollection>
#include <KConfig>
#include <KConfigGroup>
#include <KgDifficulty>
#include <QStatusBar>
#include <KStandardGameAction>
#include <KSelectAction>
#include <KToggleAction>
#include <KLocalizedString>
// Bovo includes
#include "ai.h"
#include "aifactory.h"
#include "common.h"
#include "dimension.h"
#include "game.h"
#include "move.h"
#include "scene.h"
#include "theme.h"
#include "view.h"
// KConfig XT includes
#include "settings.h"
using namespace bovo;
using namespace ai;
namespace gui {
MainWindow::MainWindow(QWidget* parent)
: KXmlGuiWindow(parent), m_scene(nullptr), m_game(nullptr), m_wins(0),
m_losses(0), m_computerStarts(false), m_demoAi(nullptr),
m_aiFactory(nullptr), m_animate(true),
m_winsLabel (new QLabel(i18n("Wins: %1", m_wins))),
m_lossesLabel (new QLabel(i18n("Losses: %1", m_losses))) {
statusBar()->insertPermanentWidget(0, m_winsLabel);
statusBar()->insertPermanentWidget(1, m_lossesLabel);
m_aiFactory = new AiFactory();
KgDifficulty* diff = Kg::difficulty();
diff->addStandardLevelRange(
KgDifficultyLevel::RidiculouslyEasy,
KgDifficultyLevel::Impossible,
KgDifficultyLevel::Medium //default level
);
connect(diff, &KgDifficulty::currentLevelChanged, this, &MainWindow::changeSkill);
KgDifficultyGUI::init(this);
diff->setGameRunning(true);
setupThemes();
readConfig();
setupActions();
slotNewGame();
m_view = new View(m_scene, m_theme.backgroundColor(), this);
setCentralWidget(m_view);
m_view->show();
setupGUI();
QFontMetrics fm(font());
auto base = fm.boundingRect(QLatin1Char('x'));
setMinimumSize(base.width() * 45, base.height() * 55);
}
MainWindow::~MainWindow() {
save();
delete m_view;
delete m_game;
delete m_demoAi;
delete m_aiFactory;
delete m_scene;
}
void MainWindow::save() const {
if (m_game != nullptr) {
m_scene->activate(false);
QString rc = QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("bovorc"));
KConfig savegame(rc);
KConfigGroup lastGroup(&savegame, "Game");
if (!m_game->isGameOver() && m_game->demoMode() == NotDemo) {
const QStringList lastGame = m_game->saveLast();
lastGroup.writeXdgListEntry("Unfinished", lastGame); // XXX this is bogus
} else {
lastGroup.deleteEntry("Unfinished");
}
lastGroup.writeEntry("Wins", m_wins);
lastGroup.writeEntry("Losses", m_losses);
}
}
void MainWindow::setupThemes() {
QStringList themercs;
const QStringList themeDirs = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("themes"), QStandardPaths::LocateDirectory);
for (const QString &themeDir : themeDirs) {
const QStringList entries = QDir(themeDir).entryList(QDir::Dirs);
for(const QString &d : entries) {
QString themeFile = themeDir + QLatin1Char('/') + d + QLatin1String("/themerc");
if (QFile::exists(themeFile))
themercs.append(themeFile);
}
}
int i = 0;
for (const QString &themerc : qAsConst(themercs)) {
KConfig config(themerc);
KConfigGroup configGroup(&config, "Config");
const QString pathName = configGroup.readEntry("Path", QString());
m_themes << Theme(pathName, i);
++i;
}
}
void MainWindow::readConfig() {
const QString themePath = Settings::theme();
for (const Theme &tmpTheme : m_themes) {
if (tmpTheme.path() == themePath) {
m_theme = tmpTheme;
break;
}
}
m_playbackSpeed = Settings::playbackSpeed();
m_animate = Settings::animation();
m_aiFactory->changeAi(Settings::ai());
const QString rc = QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("bovorc"));
KConfig savegame(rc);
KConfigGroup lastGroup(&savegame, "Game");
m_lastGame = lastGroup.readXdgListEntry("Unfinished", QStringList()); // XXX this is bogus
const QString wins = lastGroup.readEntry("Wins", QString());
if (!wins.isEmpty()) {
bool ok;
updateWins(wins.toUInt(&ok));
}
const QString losses = lastGroup.readEntry("Losses", QString());
if (!losses.isEmpty()) {
bool ok;
updateLosses(losses.toUInt(&ok));
}
}
void MainWindow::saveSettings() {
Settings::setTheme(m_theme.path());
Settings::setPlaybackSpeed(m_playbackSpeed);
Settings::setAnimation(m_animate);
Settings::setAi(m_aiFactory->ai());
Settings::self()->save();
}
void MainWindow::setupActions() {
KStandardGameAction::gameNew(this, SLOT(slotNewGame()), actionCollection());
KStandardGameAction::quit(this, SLOT(close()), actionCollection());
auto replayAct = new QAction(QIcon::fromTheme( QStringLiteral( "media-playback-start" )),
i18n("&Replay"), this);
actionCollection()->addAction( QStringLiteral( "replay" ), replayAct);
replayAct->setToolTip(i18n("Replay game"));
replayAct->setWhatsThis(i18n("Replays your last game for you to watch."));
replayAct->setEnabled(false);
m_hintAct = KStandardGameAction::hint(this, SLOT(hint()), actionCollection());
m_hintAct->setEnabled(false);
auto animAct = new KToggleAction(i18n("&Animation"),this);
actionCollection()->addAction( QStringLiteral( "animation" ), animAct);
animAct->setChecked(m_animate);
connect(animAct, &QAction::toggled, this, &MainWindow::setAnimation);
m_themeAct = new KSelectAction(i18n("Theme"), this);
QStringList themes;
for (const Theme &theme : qAsConst(m_themes)) {
themes << theme.name();
}
m_themeAct->setItems(themes);
int themeId = 0;
for (const Theme &theme : qAsConst(m_themes)) {
if (theme.path() == m_theme.path()) {
themeId = theme.id();
break;
}
}
m_themeAct->setCurrentItem(themeId);
actionCollection()->addAction( QStringLiteral( "themes" ), m_themeAct);
m_themeAct->setIcon(QIcon::fromTheme( QStringLiteral( "games-config-theme" )));
connect(m_themeAct,SIGNAL(triggered(int)),this,SLOT(changeTheme(int)));
m_undoAct = KStandardGameAction::undo(this, SLOT(slotUndo()), actionCollection());
m_undoAct->setEnabled(false);
addAction(replayAct);
addAction(animAct);
addAction(m_themeAct);
}
void MainWindow::hint() {
if (m_game != nullptr) {
if (!m_game->computerTurn()) {
if (m_demoAi != nullptr) {
m_demoAi->slotMove();
}
}
}
}
void MainWindow::setAnimation(bool enabled) {
if (m_scene != nullptr) {
if (enabled != m_animate) {
m_scene->enableAnimation(enabled);
}
}
m_animate = enabled;
saveSettings();
}
void MainWindow::slotNewGame() {
m_demoMode = false;
if (m_game != nullptr) {
m_game->cancelAndWait();
if (m_scene != nullptr) {
disconnect(m_game, nullptr, m_scene, nullptr);
}
if (!m_game->isGameOver() && m_game->history().size() > 1) {
m_lossesLabel->setText(i18n("Losses: %1",++m_losses));
}
if (m_game->history().size() > 1) {
m_computerStarts = !m_computerStarts;
}
m_game->deleteLater();
m_game = nullptr;
}
if (m_demoAi != nullptr) {
m_demoAi->cancelAndWait();
m_demoAi->deleteLater();
m_demoAi = nullptr;
}
QAction* act = actionCollection()->action(QStringLiteral("replay"));
if (act != nullptr) {
act->setEnabled(false);
}
if (m_scene == nullptr && (m_lastGame.isEmpty())) { //first time, demo time
m_scene = new Scene(m_theme, m_animate);
m_demoMode = true;
slotNewDemo();
} else {
Kg::difficulty()->setGameRunning(true);
Dimension dimension(NUMCOLS, NUMCOLS);
if (m_scene == nullptr) {
m_scene = new Scene(m_theme, m_animate);
if (!m_lastGame.empty()) {
QString tmp = m_lastGame.first();
m_computerStarts = tmp.startsWith(QLatin1Char('2')) ? true : false;
}
m_game = new Game(dimension, m_lastGame, Kg::difficultyLevel(),
m_playbackSpeed, m_aiFactory);
} else {
m_game = new Game(dimension, m_computerStarts ? O : X,
Kg::difficultyLevel(), NotDemo, m_playbackSpeed,
m_aiFactory);
}
m_demoAi = m_aiFactory->createAi(dimension, KgDifficultyLevel::Easy, m_game->player(), Demo);
m_scene->setGame(m_game);
connect(m_game, &Game::undoAble, this, &MainWindow::enableUndo);
connect(m_game, &Game::undoNotAble, this, &MainWindow::disableUndo);
connect(m_game, &Game::playerTurn, this, &MainWindow::slotPlayerTurn);
connect(m_game, &Game::oposerTurn, this, &MainWindow::slotOposerTurn);
connect(m_game, &Game::gameOver,
this, &MainWindow::slotGameOver);
connect(m_game, &Game::boardChanged,
m_demoAi, &Ai::changeBoard);
connect(m_demoAi, SIGNAL(move(Move)),
m_scene, SLOT(hint(Move)));
m_hintAct->setEnabled(true);
if (m_lastGame.isEmpty()) {
m_game->start();
} else {
m_lastGame.clear();
m_game->startRestored();
}
}
}
void MainWindow::slotNewDemo() {
if (!m_demoMode) {
// a new game already started, do not start demo
return;
}
if (m_game != nullptr) {
m_game->deleteLater();
m_game = nullptr;
}
if (m_demoAi != nullptr) {
m_demoAi->deleteLater();
m_demoAi = nullptr;
}
Dimension dimension(NUMCOLS, NUMCOLS);
m_game = new Game(dimension, O, Kg::difficultyLevel(), Demo, m_playbackSpeed,
m_aiFactory);
m_demoAi = m_aiFactory->createAi(dimension, Kg::difficultyLevel(), X, Demo);
m_scene->setGame(m_game);
connect(m_game, &Game::boardChanged,
m_demoAi, &Ai::changeBoard);
connect(m_game, &Game::playerTurn, m_demoAi, &Ai::slotMove,
Qt::QueuedConnection);
connect(m_demoAi, SIGNAL(move(Move)),
m_game, SLOT(move(Move)));
connect(m_game, &Game::gameOver,
this, &MainWindow::slotNewDemoWait);
statusBar()->showMessage(i18n("Start a new Game to play"));
m_game->start();
Kg::difficulty()->setGameRunning(false);
}
void MainWindow::slotNewDemoWait() {
// m_scene->setWin(m_game->history());
QTimer::singleShot(8*m_playbackSpeed, this, &MainWindow::slotNewDemo);
}
void MainWindow::increaseWins() {
updateWins(m_wins + 1);
}
void MainWindow::decreaseWins() {
updateWins(m_wins > 0 ? m_wins - 1 : 0);
}
void MainWindow::updateWins(const int wins) {
m_wins = wins;
m_winsLabel->setText(i18n("Wins: %1", m_wins));
}
void MainWindow::increaseLosses() {
updateLosses(m_losses + 1);
}
void MainWindow::decreaseLosses() {
updateLosses(m_losses > 0 ? m_losses - 1 : 0);
}
void MainWindow::updateLosses(const int losses) {
m_losses = losses;
m_lossesLabel->setText(i18n("Losses: %1", m_losses));
}
void MainWindow::slotGameOver() {
if (m_game->boardFull()) {
statusBar()->showMessage(i18n("GAME OVER. Tie!"));
} else {
if (m_game->latestMove().player() == X) {
statusBar()->showMessage(i18n("GAME OVER. You won!"));
increaseWins();
} else {
statusBar()->showMessage(i18n("GAME OVER. You lost!"));
increaseLosses();
}
}
disconnect(m_game, nullptr, m_demoAi, nullptr);
m_hintAct->setEnabled(false);
actionCollection()->action(QStringLiteral("replay"))->setEnabled(true);
connect(actionCollection()->action(QStringLiteral("replay")), &QAction::triggered,
this, &MainWindow::replay);
}
void MainWindow::slotPlayerTurn() {
statusBar()->showMessage(i18n("It is your turn."));
}
void MainWindow::slotOposerTurn() {
statusBar()->showMessage(i18n("Waiting for computer."));
}
void MainWindow::slotUndo() {
if (m_game == nullptr)
return;
if (m_game->isGameOver()) {
if (!m_game->boardFull()) {
if (m_game->latestMove().player() == X) {
decreaseWins();
} else {
decreaseLosses();
}
}
connect(m_game, &Game::boardChanged,
m_demoAi, &Ai::changeBoard);
m_hintAct->setEnabled(true);
actionCollection()->action(QStringLiteral("replay"))->setEnabled(false);
disconnect(actionCollection()->action(QStringLiteral("replay")), &QAction::triggered,
this, &MainWindow::replay);
}
m_game->undoLatest();
}
void MainWindow::replay() {
if (!m_game->isGameOver()) {
return;
}
statusBar()->showMessage(i18n("Replaying game"));
actionCollection()->action(QStringLiteral("replay"))->setEnabled(false);
disableUndo();
disconnect(actionCollection()->action(QStringLiteral("replay")), &QAction::triggered,
this, &MainWindow::replay);
disconnect(m_game, nullptr, this, nullptr);
connect(m_game, &Game::replayEnd,
this, &MainWindow::reEnableReplay);
disconnect(m_game, nullptr, m_scene, nullptr);
connect(m_game, &Game::replayBegin, m_scene, &Scene::replay);
connect(m_game, &Game::replayEnd, m_scene, &Scene::slotGameOver);
m_game->replay();
}
void MainWindow::reEnableReplay() {
actionCollection()->action(QStringLiteral("replay"))->setEnabled(true);
statusBar()->showMessage(i18n("Game replayed."));
connect(actionCollection()->action(QStringLiteral("replay")), &QAction::triggered,
this, &MainWindow::replay);
}
void MainWindow::changeSkill() {
if (m_game!=nullptr)
m_game->setSkill(Kg::difficultyLevel());
}
void MainWindow::changeTheme(int themeId) {
for (const Theme &theme : qAsConst(m_themes)) {
if (themeId == theme.id()) {
m_theme = theme;
m_scene->setTheme(m_theme);
saveSettings();
return;
}
}
}
void MainWindow::enableUndo() {
m_undoAct->setEnabled(true);
}
void MainWindow::disableUndo() {
m_undoAct->setEnabled(false);
}
} /* namespace gui */
// Class moc

115
gui/mainwindow.h Normal file
View File

@ -0,0 +1,115 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_MAINWINDOW_H
#define BOVO_MAINWINDOW_H
#include <QString>
#include <QStringList>
#include <KXmlGuiWindow>
#include "common.h"
#include "theme.h"
class QLabel;
namespace ai
{
class Ai;
class AiFactory;
}
namespace bovo
{
class Game;
}
using namespace bovo;
using namespace ai;
class KSelectAction;
namespace gui
{
class Scene;
class View;
class MainWindow : public KXmlGuiWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override;
public Q_SLOTS:
void hint();
void slotNewGame();
void slotPlayerTurn();
void slotOposerTurn();
void slotGameOver();
void slotNewDemo();
void slotNewDemoWait();
void slotUndo();
void replay();
void changeSkill();
void changeTheme(int);
void reEnableReplay();
void enableUndo();
void disableUndo();
void setupThemes();
void save() const;
void setAnimation(bool enabled);
private:
Scene *m_scene;
View *m_view;
Game *m_game;
Theme m_theme;
QList<Theme> m_themes;
int m_wins, m_losses;
void setupActions();
void increaseWins();
void decreaseWins();
void updateWins(const int wins);
void increaseLosses();
void decreaseLosses();
void updateLosses(const int losses);
QAction *m_hintAct;
QAction *m_undoAct;
KSelectAction *m_themeAct;
bool m_computerStarts;
Ai *m_demoAi;
AiFactory *m_aiFactory;
void readConfig();
void saveSettings();
int m_playbackSpeed;
QStringList m_lastGame;
bool m_animate;
bool m_demoMode;
QLabel *m_winsLabel;
QLabel *m_lossesLabel;
};
} /* namespace gui */
#endif // BOVO_MAINWINDOW_H

137
gui/mark.cc Normal file
View File

@ -0,0 +1,137 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "mark.h"
#include <QTimer>
#include <QPainter>
#include <QSvgRenderer>
#include "common.h"
#include "coord.h"
#include "move.h"
#include "scene.h"
using namespace bovo;
namespace gui {
Mark::Mark(Scene* scene, const Move& move, bool animate, qreal fill) : QGraphicsSvgItem(),
m_scene(scene), m_row(move.y()), m_col(move.x()), m_fill(fill) {
m_sizeShrink = 1.0/12.0; //1.0/(qrand()%5+7.0);
setElementId(QString(move.player() == X ? QStringLiteral("x%1") : QStringLiteral("o%1"))
.arg(QString::number(qrand() % 5 + 1)));
m_tick = 20;
m_ticker = nullptr;
if (animate) {
m_ticker = new QTimer(this);
m_opacity = 0.0;
connect(m_ticker, &QTimer::timeout, this, &Mark::tick);
m_ticker->start(30);
} else {
m_opacity = 1.0;
}
setPos(m_scene->cellCenter(m_col, m_row));
}
Mark::~Mark() {
if (m_ticker) {
disconnect(m_ticker, &QTimer::timeout, this, &Mark::tick);
m_ticker->stop();
m_ticker->deleteLater();
}
}
QRectF Mark::boundingRect() const {
qreal width = m_scene->squareSize();
qreal height = width;
qreal margin = (1.0-m_fill) * width / 2.0;
return { -width / 2.0 + margin,
-height / 2.0 + margin,
width - 2.0*margin,
height - 2.0*margin};
}
void Mark::killAnimation() {
if (m_ticker != nullptr) {
m_ticker->stop();
disconnect(m_ticker, nullptr, this, nullptr);
m_ticker->deleteLater();
m_ticker = nullptr;
m_opacity = 1.0;
update();
}
}
void Mark::kill() {
if (m_ticker) {
disconnect(m_ticker, &QTimer::timeout, this, &Mark::tick);
m_ticker->stop();
} else {
m_ticker = new QTimer(this);
}
connect(m_ticker, &QTimer::timeout, this, &Mark::killTick);
m_ticker->start(30);
}
void Mark::killTick() {
m_opacity -= 0.1;
update();
if (m_opacity <= 0.1) {
m_ticker->stop();
Q_EMIT killed(this);
}
}
void Mark::tick() {
--m_tick;
if (m_tick == 0) {
killAnimation();
} else {
m_opacity += 0.1;
update();
}
}
void Mark::paint(QPainter *p, const QStyleOptionGraphicsItem*, QWidget*) {
p->setOpacity(m_opacity);
renderer()->render(p, elementId(), boundingRect());
}
void Mark::setFill(qreal fill) {
if (m_fill != fill) {
m_fill = fill;
prepareGeometryChange();
}
}
usi Mark::col() const {
return m_col;
}
usi Mark::row() const {
return m_row;
}
} /* namespace gui */

79
gui/mark.h Normal file
View File

@ -0,0 +1,79 @@
/*******************************************************************
*
* This file is part of the KDE project "Bovo"
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_MARK_H
#define BOVO_MARK_H
#include <QGraphicsSvgItem>
#include "common.h"
namespace bovo
{
class Move;
}
using namespace bovo;
class QTimer;
namespace gui
{
class Scene;
class Mark : public QGraphicsSvgItem
{
Q_OBJECT
public:
Mark(Scene *scene, const Move &move, bool animate = true, qreal fill = 0.75);
~Mark() override;
void killAnimation();
void kill();
usi row() const;
usi col() const;
void setFill(qreal fill);
QRectF boundingRect() const override;
public Q_SLOTS:
void tick();
void killTick();
Q_SIGNALS:
void killed(Mark *thisMark);
protected:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *widget = nullptr) override;
private:
Scene *m_scene;
int m_row;
int m_col;
qreal m_sizeShrink, m_fill;
int m_tick;
bool m_animate;
qreal m_opacity;
QTimer *m_ticker;
};
} /* namespace gui */
#endif // BOVO_MARH_H

404
gui/scene.cc Normal file
View File

@ -0,0 +1,404 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "scene.h"
#include <QTime>
#include <QTimer>
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsView>
#include <QSvgRenderer>
#include <KConfig>
#include <KConfigGroup>
#include <KDesktopFile>
#include "common.h"
#include "coord.h"
#include "game.h"
#include "hintitem.h"
#include "mark.h"
#include "move.h"
#include "theme.h"
using namespace bovo;
namespace gui {
Scene::Scene(const Theme& theme, bool animation)
: m_activate(false), m_game(nullptr), m_curCellSize(10.0), m_player(No), m_animation(animation),
m_paintMarker(false), m_showLast(false) {
/** @todo read theme from some configuration, I guess */
/** @todo read file names from from some configuration, I guess */
m_renderer = nullptr;
loadTheme(theme);
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
m_hintTimer = new QTimer(this);
m_hintTimer->setSingleShot(true);
m_hintItem = nullptr;
setSceneRect( 0, 0, m_curCellSize*(NUMCOLS+2), m_curCellSize*(NUMCOLS+2) );
}
Scene::~Scene() {
if (m_renderer) {
m_renderer->deleteLater();
}
if (m_hintItem) {
m_hintItem->deleteLater();
}
if (m_hintTimer) {
m_hintTimer->disconnect();
m_hintTimer->stop();
m_hintTimer->deleteLater();
}
}
qreal Scene::squareSize() const {
return m_curCellSize;
}
void Scene::loadTheme(const Theme& theme) {
m_fill = theme.fill();
QColor color(theme.backgroundColor());
QPalette bgPal;
const auto vs = views();
for (QGraphicsView* view : vs) {
bgPal.setColor(view->backgroundRole(), color.isValid() ? color : Qt::white);
view->setPalette(bgPal);
}
if (m_renderer == nullptr)
m_renderer = new QSvgRenderer(theme.svg());
else
m_renderer->load(theme.svg());
const QList<QGraphicsItem*> allMarks = items();
for (QGraphicsItem* item : allMarks) {
if (Mark* mark = qgraphicsitem_cast<Mark *>(item)) {
mark->setFill(m_fill);
mark->update(mark->boundingRect());
}
else if (auto hintItem = qgraphicsitem_cast<HintItem *>(item)) {
hintItem->setFill(m_fill);
hintItem->update(hintItem->boundingRect());
}
}
}
void Scene::setTheme(const Theme& theme) {
loadTheme(theme);
invalidate(0, 0, width(), height());
}
void Scene::activate(bool activate) {
m_activate = activate;
}
void Scene::setWin() {
if (!m_game->isGameOver()) {
return;
}
invalidate(0, 0, width(), height());
}
void Scene::setGame(Game* game) {
destroyHint();
m_winningMoves = QList<Move>();
m_game = game;
m_player = m_game->player();
connect(m_game, &Game::boardChanged, this, &Scene::updateBoard);
if (!m_game->demoMode()) {
connect(m_game, &Game::playerTurn, this, &Scene::slotPlayerTurn);
connect(m_game, &Game::oposerTurn, this, &Scene::slotOposerTurn);
}
connect(m_game, &Game::gameOver, this, &Scene::slotGameOver);
connect(this, &Scene::move, m_game, &Game::move);
qDeleteAll(items()); //remove all marks
m_paintMarker = false;
m_showLast = false;
invalidate(0, 0, width(), height());
}
void Scene::updateBoard(const Move& move) {
destroyHint();
if (move.valid()) {
setShowLast(move.x(), move.y());
Mark* mark = new Mark(this, move, m_animation, m_fill);
mark->setSharedRenderer(m_renderer);
addItem(mark);
} else if (move.player() == No) {
if (!m_game->isGameOver() && !m_winningMoves.empty()) {
m_winningMoves = QList<Move>();
invalidate(0, 0, width(), height());
}
removeShowLast();
const QList<QGraphicsItem*> allMarks = items();
for (QGraphicsItem* item : allMarks) {
if (Mark* mark = qgraphicsitem_cast<Mark *>(item)) {
if (mark->row() == move.y() && mark->col() == move.x()) {
if (m_animation) {
connect(mark, &Mark::killed, this, &Scene::killMark);
mark->kill();
} else {
removeItem(mark);
delete mark;
}
}
}
}
}
}
QPointF Scene::cellCenter(int x, int y) const {
return cellTopLeft(x, y) + QPointF(m_curCellSize/2.0, m_curCellSize/2.0);
}
QPointF Scene::cellTopLeft(int x, int y) const {
return {(x+1) * m_curCellSize, (y+1) * m_curCellSize};
}
void Scene::drawBackground(QPainter *p, const QRectF&) {
QRectF sRect = sceneRect();
int minSize = qMin(static_cast<int>(sRect.width()),
static_cast<int>(sRect.height()));
qreal shrinkSize = static_cast<qreal>(NUMCOLS) /
static_cast<qreal>(NUMCOLS+2);
qreal size = static_cast<qreal>(minSize) /
static_cast<qreal>(NUMCOLS+2);
/* sRect.setWidth(minSize*cellSize);
sRect.setHeight(minSize*cellSize);
sRect.setLeft(cellSize);*/
QRectF tmpRect(size, size, minSize*shrinkSize, minSize*shrinkSize);
m_renderer->render(p, QStringLiteral("background"));
m_renderer->render(p, QStringLiteral("grid"), tmpRect);
}
void Scene::drawForeground(QPainter *p, const QRectF& bounds) {
if (m_paintMarker) {
QRectF rect(cellTopLeft(m_col, m_row), QSizeF(m_curCellSize,
m_curCellSize));
qreal adjusting((1.0-m_fill)*m_curCellSize/2.0);
rect.adjust(adjusting, adjusting, -adjusting, -adjusting);
if (bounds.intersects(rect)) {
p->setOpacity(0.4);
m_renderer->render(p, QStringLiteral("x1"), rect);
p->setOpacity(1);
}
}
if (m_showLast) {
QRectF rect(cellTopLeft(m_lastCol, m_lastRow), QSizeF(m_curCellSize,
m_curCellSize));
if (bounds.intersects(rect)) {
m_renderer->render(p, QStringLiteral("last"), rect);
}
}
if (!m_winningMoves.empty()) {
QList<Move>::const_iterator it = m_winningMoves.constBegin();
QList<Move>::const_iterator end = m_winningMoves.constEnd();
while (it != end) {
QRectF tmpRect(cellTopLeft(it->x(), it->y()), QSizeF(m_curCellSize,
m_curCellSize));
if (bounds.intersects(tmpRect)) {
m_renderer->render(p, QStringLiteral("win"), tmpRect);
}
++it;
}
}
}
void Scene::mouseMoveEvent(QGraphicsSceneMouseEvent *ev) {
if (!m_game->isGameOver() && !m_game->computerTurn() && m_activate) {
QRectF boardRect(cellTopLeft(0, 0), QSizeF(m_curCellSize * NUMCOLS,
m_curCellSize * NUMCOLS));
if (!boardRect.contains(ev->scenePos())) {
removePaintMarker();
} else {
uint row = (uint)((ev->scenePos().y()-boardRect.y()) / m_curCellSize);
uint col = (uint)((ev->scenePos().x()-boardRect.x()) / m_curCellSize);
row = qMax(row, static_cast<uint>(0));
row = qMin(static_cast<uint>(NUMCOLS-1), row);
col = qMax(col, static_cast<uint>(0));
col = qMin(static_cast<uint>(NUMCOLS-1), col);
if (m_row != row || m_col != col || !m_paintMarker) {
if (m_game->player(Coord(col, row)) == No) {
setPaintMarker(col, row);
} else {
removePaintMarker();
}
}
}
}
}
void Scene::mousePressEvent( QGraphicsSceneMouseEvent* ev ) {
if (m_game->isGameOver() || m_game->computerTurn() || !m_activate) {
return;
}
QRectF boardRect(cellTopLeft(0, 0), QSizeF(m_curCellSize * NUMCOLS,
m_curCellSize * NUMCOLS));
if (!boardRect.contains(ev->scenePos())) {
return;
}
int row = (int)((ev->scenePos().y()-boardRect.y()) / m_curCellSize);
int col = (int)((ev->scenePos().x()-boardRect.x()) / m_curCellSize);
row = qMax(row, 0);
row = qMin(NUMCOLS-1, row);
col = qMax(col, 0);
col = qMin(NUMCOLS-1, col);
Q_EMIT move(Move(m_player, Coord(col, row)));
}
void Scene::removePaintMarker() {
if (!m_paintMarker) {
return;
}
m_paintMarker = false;
QRectF rectOld(cellTopLeft(m_col, m_row), QSizeF(m_curCellSize,
m_curCellSize));
qreal adjusting((1.0-m_fill)*m_curCellSize/2.0);
rectOld.adjust(adjusting, adjusting, -adjusting, -adjusting);
invalidate(rectOld, ForegroundLayer);
}
void Scene::setPaintMarker(uint col, uint row) {
if (m_paintMarker == true && m_col == col && m_row == row) {
return;
}
removePaintMarker();
m_paintMarker = true;
m_col = col;
m_row = row;
QRectF rect(cellTopLeft(m_col, m_row), QSizeF(m_curCellSize,
m_curCellSize));
qreal adjusting((1.0-m_fill)*m_curCellSize/2.0);
rect.adjust(adjusting, adjusting, -adjusting, -adjusting);
invalidate(rect, ForegroundLayer);
}
void Scene::removeShowLast() {
if (!m_showLast) {
return;
}
m_showLast = false;
QRectF rectOld(cellTopLeft(m_lastCol, m_lastRow), QSizeF(m_curCellSize,
m_curCellSize));
invalidate(rectOld, ForegroundLayer);
}
void Scene::setShowLast(uint col, uint row) {
if (m_showLast == true && m_lastCol == col && m_lastRow == row) {
return;
}
removeShowLast();
m_showLast = true;
m_lastCol = col;
m_lastRow = row;
QRectF rect(cellTopLeft(m_lastCol, m_lastRow), QSizeF(m_curCellSize,
m_curCellSize));
invalidate(rect, ForegroundLayer);
}
void Scene::slotPlayerTurn() {
activate(true);
}
void Scene::slotOposerTurn() {
removePaintMarker();
activate(false);
}
void Scene::slotGameOver(const QList<Move>& win) {
removePaintMarker();
removeShowLast();
m_winningMoves = win;
setWin();
activate(false);
}
void Scene::hint(const Move& hint) {
destroyHint();
m_hintItem = new HintItem(this, hint, m_animation, m_fill);
m_hintItem->setSharedRenderer(m_renderer);
addItem(m_hintItem);
connect(m_hintTimer, &QTimer::timeout, this, &Scene::hintTimeout);
m_hintTimer->start(2000);
}
void Scene::destroyHint() {
if (m_hintItem != nullptr) {
m_hintTimer->disconnect();
m_hintTimer->stop();
m_hintItem->killAnimation();
removeItem(m_hintItem);
m_hintItem->deleteLater();
m_hintItem = nullptr;
}
}
void Scene::hintTimeout() {
if (!m_animation) {
destroyHint();
} else if (m_hintItem != nullptr) {
connect(m_hintItem, &HintItem::killed, this, &Scene::destroyHint);
m_hintItem->kill();
}
}
void Scene::enableAnimation(bool enabled) {
m_animation = enabled;
if (!m_animation) {
killAnimations();
}
}
void Scene::killAnimations() {
if (m_hintItem != nullptr) {
m_hintItem->killAnimation();
}
}
void Scene::killMark(Mark* mark) {
removeItem(mark);
mark->deleteLater();
}
void Scene::replay() {
const QList<QGraphicsItem*> allMarks = items();
for (QGraphicsItem* mark : allMarks) {
removeItem(mark);
delete mark;
}
m_winningMoves = QList<Move>();
invalidate(0, 0, width(), height());
connect(m_game, &Game::boardChanged, this, &Scene::updateBoard);
}
bool Scene::event(QEvent *event) {
bool ret = QGraphicsScene::event(event);
if (event->type() == QEvent::Leave) {
removePaintMarker();
}
return ret;
}
} /* namespace gui */

118
gui/scene.h Normal file
View File

@ -0,0 +1,118 @@
/*******************************************************************
*
* This file is part of the KDE project "Bovo"
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_SCENE_H
#define BOVO_SCENE_H
#include <QGraphicsScene>
#include <QList>
#include "common.h"
class QSvgRenderer;
class QPainter;
class QTimer;
namespace bovo
{
class Move;
class Game;
}
using namespace bovo;
namespace gui
{
class HintItem;
class Mark;
class Theme;
class Scene : public QGraphicsScene
{
Q_OBJECT
public:
explicit Scene(const Theme &theme, bool animation = true);
~Scene() override;
void activate(bool activate);
void setGame(Game *game);
bool isBusy() const;
void setTheme(const Theme &theme);
qreal squareSize() const;
QPointF cellCenter(int x, int y) const;
QPointF cellTopLeft(int x, int y) const;
public Q_SLOTS:
void updateBoard(const Move &move);
void slotPlayerTurn();
void slotOposerTurn();
void slotGameOver(const QList<Move> &winningMoves);
void hint(const Move &hint);
void hintTimeout();
void destroyHint();
void enableAnimation(bool enabled);
void setWin();
void replay();
void killMark(Mark *);
protected:
bool event(QEvent *event) override;
Q_SIGNALS:
void move(const Move &);
private:
void drawBackground(QPainter *p, const QRectF &rect) override;
void drawForeground(QPainter *p, const QRectF &rect) override;
void mousePressEvent(QGraphicsSceneMouseEvent *) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *) override;
void killAnimations();
bool m_activate;
Game *m_game;
QSvgRenderer *m_bkgndRenderer;
QSvgRenderer *m_renderer;
qreal m_curCellSize;
QList<Move>::const_iterator m_replayEnd;
QList<Move>::const_iterator m_replayIterator;
QTimer *m_replayTimer;
QTimer *m_hintTimer;
// int m_hintCounter;
HintItem *m_hintItem;
Player m_player;
bool m_animation;
QList<Move> m_winningMoves;
uint m_row;
uint m_col;
bool m_paintMarker;
uint m_lastRow;
uint m_lastCol;
bool m_showLast;
void removePaintMarker();
void setPaintMarker(uint col, uint row);
void removeShowLast();
void setShowLast(uint col, uint row);
qreal m_fill;
void loadTheme(const Theme &theme);
};
} /* namespace gui */
#endif // BOVO_SCENE_H

6
gui/settings.kcfgc Normal file
View File

@ -0,0 +1,6 @@
# Code generation options for kconfig_compiler
File=bovo.kcfg
ClassName=Settings
NameSpace=gui
Singleton=true
Mutators=true

102
gui/theme.cc Normal file
View File

@ -0,0 +1,102 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "theme.h"
#include "settings.h"
#include <KConfig>
#include <KConfigGroup>
#include <KDesktopFile>
#include <QStandardPaths>
namespace gui {
Theme::Theme() = default;
Theme::Theme(const QString& path, const int id)
: m_id(id), m_path(path) {
QString themePath = QStringLiteral("themes/%1/").arg(m_path);
themePath = QStandardPaths::locate(QStandardPaths::AppDataLocation, themePath, QStandardPaths::LocateDirectory);
QString themerc = themePath + QLatin1String("themerc");
KDesktopFile themeConfig(themerc);
m_name = themeConfig.readName();
m_comment = themeConfig.readComment();
KConfig config(themerc);
KConfigGroup configGroup(&config, "Config");
m_backgroundColor = configGroup.readEntry("BackgroundColor", "white");
m_fill = configGroup.readEntry("Fill", 0.75);
m_gridColor = configGroup.readEntry("GridColor", "black");
QString gridTypeStr = configGroup.readEntry("GridType", "svg");
if (gridTypeStr == QLatin1String("svg")) {
m_gridType = SvgGrid;
} else if (gridTypeStr == QLatin1String("gomoku")) {
m_gridType = GomokuGrid;
} else if (gridTypeStr == QLatin1String("squares")) {
m_gridType = SquaresGrid;
}
m_svg = themePath + configGroup.readEntry("Svg", "theme.svg");
}
QColor Theme::backgroundColor() const {
return m_backgroundColor;
}
QString Theme::comment() const {
return m_comment;
}
qreal Theme::fill() const {
return m_fill;
}
QColor Theme::gridColor() const {
return m_gridColor;
}
GridType Theme::gridType() const {
return m_gridType;
}
int Theme::id() const {
return m_id;
}
QString Theme::name() const {
return m_name;
}
QString Theme::path() const {
return m_path;
}
QString Theme::svg() const {
return m_svg;
}
} /* namespace gui */

64
gui/theme.h Normal file
View File

@ -0,0 +1,64 @@
/*******************************************************************
*
* This file is part of the KDE project "Bovo"
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_THEME_H
#define BOVO_THEME_H
// Qt includes
#include <QColor>
#include <QString>
namespace gui
{
enum GridType { SvgGrid, GomokuGrid, SquaresGrid };
class Theme
{
public:
Theme();
Theme(const QString &path, const int id);
QColor backgroundColor() const;
QString comment() const;
qreal fill() const;
QColor gridColor() const;
GridType gridType() const;
int id() const;
QString name() const;
QString path() const;
QString svg() const;
private:
QColor m_backgroundColor;
QString m_comment;
qreal m_fill;
QColor m_gridColor;
GridType m_gridType;
int m_id;
QString m_name;
QString m_path;
QString m_svg;
};
} /* namespace gui */
#endif // BOVO_THEME_H

57
gui/view.cc Normal file
View File

@ -0,0 +1,57 @@
/*******************************************************************
*
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
// Declaration include
#include "view.h"
// Qt Includes
#include <QColor>
#include <QGraphicsScene>
#include <QResizeEvent>
// Bovo includes
#include "scene.h"
namespace gui {
View::View(Scene* scene, const QColor& bgColor, QWidget *parent) : QGraphicsView(scene, parent),
m_scene(scene) {
Q_UNUSED(bgColor);
setFrameStyle(QFrame::NoFrame);
// setCacheMode(QGraphicsView::CacheBackground);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setMinimumSize(sizeHint());
resize(sizeHint());
setAlignment(Qt::AlignLeft | Qt::AlignTop);
}
void View::resizeEvent( QResizeEvent* ev ) {
fitInView(sceneRect(), Qt::KeepAspectRatio);
QGraphicsView::resizeEvent(ev);
}
QSize View::sizeHint() const {
return {static_cast<int>(m_scene->width()),
static_cast<int>(m_scene->height())};
}
} /* namespace gui */

47
gui/view.h Normal file
View File

@ -0,0 +1,47 @@
/*******************************************************************
*
* This file is part of the KDE project "Bovo"
*
* Bovo 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.
*
* Bovo 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 Bovo; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef BOVO_VIEW_H
#define BOVO_VIEW_H
#include <QGraphicsView>
namespace gui
{
class Scene;
class bgColor;
class View : public QGraphicsView
{
public:
View(Scene *scene, const QColor &bgColor, QWidget *parent);
private:
void resizeEvent(QResizeEvent *) override;
QSize sizeHint() const override;
Scene *m_scene;
};
} /* namespace gui */
#endif // BOVO_VIEW_H

BIN
icons/128-apps-bovo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
icons/16-apps-bovo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

BIN
icons/22-apps-bovo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
icons/32-apps-bovo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
icons/48-apps-bovo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
icons/64-apps-bovo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

4
icons/CMakeLists.txt Normal file
View File

@ -0,0 +1,4 @@
ecm_install_icons(ICONS
128-apps-bovo.png 16-apps-bovo.png 22-apps-bovo.png 32-apps-bovo.png 48-apps-bovo.png 64-apps-bovo.png DESTINATION ${KDE_INSTALL_ICONDIR}
THEME hicolor
)

BIN
icons/hisc-app-bovo.svgz Normal file

Binary file not shown.

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

148
org.kde.bovo.appdata.xml Normal file
View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="utf-8"?>
<component type="desktop">
<id>org.kde.bovo.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-2.0+</project_license>
<name>Bovo</name>
<name xml:lang="ar">بوڤو</name>
<name xml:lang="bs">Bovo</name>
<name xml:lang="ca">Bovo</name>
<name xml:lang="ca-valencia">Bovo</name>
<name xml:lang="cs">Bovo</name>
<name xml:lang="da">Bovo</name>
<name xml:lang="de">Bovo</name>
<name xml:lang="el">Bovo</name>
<name xml:lang="en-GB">Bovo</name>
<name xml:lang="es">Bovo</name>
<name xml:lang="et">Bovo</name>
<name xml:lang="eu">Bovo</name>
<name xml:lang="fi">Bovo</name>
<name xml:lang="fr">Bovo</name>
<name xml:lang="gl">Bovo</name>
<name xml:lang="hu">Bovo</name>
<name xml:lang="id">Bovo</name>
<name xml:lang="it">Bovo</name>
<name xml:lang="ka">Bovo</name>
<name xml:lang="ko">Bovo</name>
<name xml:lang="nds">Bovo</name>
<name xml:lang="nl">Bovo</name>
<name xml:lang="nn">Bovo</name>
<name xml:lang="pl">Bovo</name>
<name xml:lang="pt">Bovo</name>
<name xml:lang="pt-BR">Bovo</name>
<name xml:lang="ru">Bovo</name>
<name xml:lang="sk">Bovo</name>
<name xml:lang="sl">Bovo</name>
<name xml:lang="sr">Бово</name>
<name xml:lang="sr-Latn">Bovo</name>
<name xml:lang="sr-ijekavian">Бово</name>
<name xml:lang="sr-ijekavianlatin">Bovo</name>
<name xml:lang="sv">Bovo</name>
<name xml:lang="tr">Bovo</name>
<name xml:lang="uk">Bovo</name>
<name xml:lang="x-test">xxBovoxx</name>
<name xml:lang="zh-CN">Bovo</name>
<name xml:lang="zh-TW">五子棋_Bovo</name>
<summary>"Five in a row" board game</summary>
<summary xml:lang="ar">لعبة خمسة في صفّ</summary>
<summary xml:lang="ca">Joc de tauler «cinc en fila»</summary>
<summary xml:lang="ca-valencia">Joc de tauler «cinc en fila»</summary>
<summary xml:lang="cs">Desková hra "Pět v řadě"</summary>
<summary xml:lang="da">"Fem på række"-brætspil</summary>
<summary xml:lang="de">"Fünf-Gewinnt-Brettspiel</summary>
<summary xml:lang="el">«Πέντε στη σειρά» επιτραπέζιο παιχνίδι</summary>
<summary xml:lang="en-GB">"Five in a row" board game</summary>
<summary xml:lang="es">Juego de mesa «Cinco en línea»</summary>
<summary xml:lang="et">"Viis ühes reas" lauamäng</summary>
<summary xml:lang="eu">«Bosteko artzain jokoa» taula-jokoa</summary>
<summary xml:lang="fi">”Viiden suora” -lautapeli</summary>
<summary xml:lang="fr">Jeu de plateau « Cinq-en-ligne »</summary>
<summary xml:lang="gl">Xogo de taboleiro «pai, fillo e nai»</summary>
<summary xml:lang="hu">Ötöt egy sorba táblajáték</summary>
<summary xml:lang="id">Permainan kartu "five in a row"</summary>
<summary xml:lang="it">Gioco da tavolo «Five in a row»</summary>
<summary xml:lang="ka">"ხუთი ზედიზედ" სამაგიდო თამაში</summary>
<summary xml:lang="ko">오목 게임</summary>
<summary xml:lang="nl">Bordspel "Vijf-op-een-rij"</summary>
<summary xml:lang="nn">«Fem på rad»-spel</summary>
<summary xml:lang="pl">Gra planszowa "Pięć w rzędzie"</summary>
<summary xml:lang="pt">Jogo de tabuleiro de "Cinco em linha"</summary>
<summary xml:lang="pt-BR">Jogo de tabuleiro "Cinco em linha"</summary>
<summary xml:lang="ru">Японские крестики-нолики</summary>
<summary xml:lang="sk">Stolová hra Piškvorky</summary>
<summary xml:lang="sl">Namizna igra »Pet v vrsto«</summary>
<summary xml:lang="sr">Игра на табли „пет у низу“</summary>
<summary xml:lang="sr-Latn">Igra na tabli „pet u nizu“</summary>
<summary xml:lang="sr-ijekavian">Игра на табли „пет у низу“</summary>
<summary xml:lang="sr-ijekavianlatin">Igra na tabli „pet u nizu“</summary>
<summary xml:lang="sv">"Fem-i-rad" brädspel</summary>
<summary xml:lang="tr">"Satırda beş" tahta oyunu</summary>
<summary xml:lang="uk">Настільна гра «П’ять у ряд»</summary>
<summary xml:lang="x-test">xx"Five in a row" board gamexx</summary>
<summary xml:lang="zh-CN">五子棋游戏</summary>
<summary xml:lang="zh-TW">「五子棋」棋盤遊戲</summary>
<description>
<p>
Bovo is a Gomoku (from Japanese 五目並べ - lit. "five points") like game for two players, where the opponents
alternate in placing their respective pictogram on the game board. (Also known as: Connect Five, Five in a row, X and O,
Naughts and Crosses)
</p>
<p xml:lang="ar">بوفو هي لعبة تشبه جوموكا (من اليابانية 五目並べ حرفيا "خمس نقاط") للاعبين، حيث يتناوب الخصوم في وضع الرسم التخطيطي الخاص بهم على لوحة اللعبة. (المعروفة أيضا باسم: صل الخمسة، خمسة في صف، X و O، الأصفار و الأخطاء)</p>
<p xml:lang="bs">Bovo je Gomoku (od japanskog 五目並べ - lit. "pet poena") slična igra za dva igrača, gdje se protivnici smjenjuju u stavljanju svog dijela piktograma na tabli. (Poznat i kao: poveži pet, pet u nizu, X i O, križić i kružić)</p>
<p xml:lang="ca">El Bovo és un joc semblant al Gomoku (del japonès 五目並べ - lit. «cinc punts») per a dos jugadors, a on els oponents situen els seus ideogrames respectius alternativament en el tauler de joc. També conegut com a: Connecta cinc, Cinc en fila, X i O, Zeros i creus.</p>
<p xml:lang="ca-valencia">Bovo és un joc pareixent a Gomoku (del japonés 五目並べ - lit. «cinc punts») per a dos jugadors, a on els oponents situen els seus ideogrames respectius de manera alternativa en el tauler de joc. També conegut com a: Connecta cinc, Cinc en fila, X i O, Zeros i creus.</p>
<p xml:lang="da">Bovo er et Gomoku-lignende spil (fra japansk 五目並べ - bogstaveligt "fem point") for to spillere, hvor modspillerne skiftes til at placere deres piktogram på spillepladen (Kendes os som Forbind fem, Fem på række eller kryds og bolle).</p>
<p xml:lang="de">Bovo ist ein Gomoku (aus dem japanischen wörtlich „Fünf Punkte“) ähnliches Spiel für zwei Spieler, bei dem die Gegner abwechselnd ihre jeweiligen Piktogramme auf dem Brett platzieren. Auch bekannt als: Fünf verbinden, Fünf in einer Reihe, X und O, Nullen und Kreuze</p>
<p xml:lang="el">Το Bovo είναι ένα είδος παιχνιδιού Gomoku (στα Ιαπωνικά 五目並べ - κυρ. "πέντε πόντοι" για δύο παίκτες, στο οποίο οι αντίπαλοι τοποθετούν εναλλάξ ο καθένας το δικό του πικτόγραμμα στον πίνακα του παιχνιδιού. (Είναι επίσης γνωστό ως Σύνδεσε πέντε, Πέντε στη γραμμή, Χ και Ο, κύκλοι και σταυροί)</p>
<p xml:lang="en-GB">Bovo is a Gomoku (from Japanese 五目並べ - lit. "five points") like game for two players, where the opponents alternate in placing their respective pictogram on the game board. (Also known as: Connect Five, Five in a row, X and O, Naughts and Crosses)</p>
<p xml:lang="es">Bovo es un juego para dos jugadores similar al Gomoku (del japonés 五目並べ, que significa «cinco puntos»). Los dos oponentes juegan por turnos para colocar su respectivo pictograma en el juego del tablero. (También se conoce como: «Conecta cinco», «Cinco en línea», «X y O» o «Ceros y cruces»).</p>
<p xml:lang="et">Bovo on Gomoku (jaapani keeles 五目並べ, otsetõlkes "viis punkti") moodi mäng kahele mängijale, kus vastased asetavad kordamööda oma piktogrammi mängulauale. (Seda tuntakse ka nimetuste all "Viis ühes reas", "X-id ja 0-id" jne.; sarnane on ka tripstrapstrull.)</p>
<p xml:lang="eu">Bovo Gomoku-ren (Japonieraz 五目並べ - lit. "bost puntu") gisako bi jokalarirentzako joko bat da, jokalariek txandaka ipintzen dituzte haien piktogramak joko-taulan. (Beste izen hauekin ere ezaguna: bosteko artzain jokoa, lotu bost, bost ilaran, X eta O, zeroak eta gurutzeak)</p>
<p xml:lang="fi">Bovo on Gomokun (japaniksi 五目並べ kirjaimellisesti ”viisi pistettä”) kaltainen peli kahdelle, jossa vastustajat asettavat vuorotellen merkkinsä pelilaudalle. Tunnetaan myös nimillä viiden suora ja ristinolla.</p>
<p xml:lang="fr">Bovo est un jeu pour deux joueurs inspiré du Gomoku (du japonais 五目並べ signifiant « cinq points »). Les adversaires placent chacun à leur tour leurs symboles sur la tableau de jeu. Également connu sous le nom de « cinq en ligne », « X et O », « morpion ».</p>
<p xml:lang="gl">Bovo é un xogo para dous xogadores similar ao Gomoku (do xaponés 五目並べ, «cinco puntos»), no que os opoñentes sitúan os seus pictogramas no taboleiro por quendas. O xogo tamén se coñece como «Conectar cinco», «Cinco en liña», etc.</p>
<p xml:lang="hu">A Bovo egy, a Gomokuhoz (japánul 五目並べ - szó szerint „öt pont”) hasonló játékos két személynek, ahol az ellenfelek felváltva teszik fel piktogramjaikat a táblára.</p>
<p xml:lang="id">Bovo adalah sebuah permainan seperti Gomoku (dari Jepang 五目並べ - susastra. "five points") untuk dua pemain, di mana lawan bergantian dalam menempatkan pictogram masing-masing di papan permainan. Bisa disebut sebagai: Nyambung Lima, Sederet Lima, X dan O, Bulat dan Silang (Juga dikenal sebagai: Connect Five, Five in a row, X and O, Naughts and Crosses))</p>
<p xml:lang="it">Bovo è un gioco per due giocatori simile al Gomoku (dal giapponese 五目並べ - lett. «cinque punti»), in cui i contendenti si alternano nel piazzare i propri pittogrammi sul piano di gioco. (È noto anche come: Connect Five, Five in a row, X and O, Naughts and Crosses)</p>
<p xml:lang="ko">Bovo는 2인용 오목 게임이며, 게임 판에 플레이어별로 말을 두는 게임입니다.</p>
<p xml:lang="nds">Bovo is en Speel as Gomoku (ut japaansch 五目並べ“ - „fief Pünkt“) för twee Spelers. De Twee wesselt sik af un leggt ehr Piktogramm op't Speelbrett. (Warrt ok „Fief verbinnen“, „Fief in de Reeg“, „X un O“ oder „Nixen un Nullen“ nöömt.)</p>
<p xml:lang="nl">Bovo is een Gomoku (uit het Japans 五目並べ - letterlijk "vijf punten")-achtig spel voor twee spelers, waar de opponenten afwisselen in het plaatsen van hun respectievelijke pictogram op het spelbord. (Ook bekend als: Boter-Kaas-en-Eieren, Vijf verbinden, Vijf op een rij, X en O, Naughts and Crosses)</p>
<p xml:lang="nn">Bovo er eit Gomoku-likande spel (frå japansk «五目並べ », som tyder «fem brikker på rad») for to spelarar. Spelarane byter på å plassera ut piktogram på spelebrettet. (Spelkonseptet er òg kjent under namna «fem på rad», «bondesjakk» og «tripp-trapp-tresko».)</p>
<p xml:lang="pl">Bovo to gra dla dwóch graczy w rodzaju Gomoku (z japońskiego 五目並べ - lit. "pięć punktów"), gdzie gracze na zmianę umieszczają odpowiadające im piktogramy na planszy. (Gra znana również jako: Połącz piątkę, Piątka w rzędzie, X i O, Kółko i krzyżyk)</p>
<p xml:lang="pt">O Bovo é um jogo semelhante ao Gomoku (do Japonês 五目並べ - lit. "cinco pontos") para dois jogadores, onde os adversários vão colocando o seu pictograma respectivo no tabuleiro do jogo. (Também conhecido como: Liga Cinco, Cinco em Linha, X e O, Bolas e Cruzes)</p>
<p xml:lang="pt-BR">Bovo é um jogo do tipo Gomoku (do Japonês 五目並べ - lit. "cinco pontos") para dois jogadores, onde os adversários alternam na colocação das suas marcas respectivas no tabuleiro. (Também conhecido como: Conectar Cinco, Cinco-em-Linha, X e O, Bolas e Cruzes)</p>
<p xml:lang="ru">Bovo — игра для двух игроков, произошедшая от Гомоку (в переводе с японского 五目並べ — «пять точек»). Соперники по очереди ставят свою отметку на игровой доске. Другие названия: крестики-нолики, пять в ряд.</p>
<p xml:lang="sk">Bovo je Gomoku (z japonského 五目並べ - "päť bodov") hra pre dvoch hráčov, kde protivníci sa striedajú v umiestňovaní ich piktogramov na hraciu plochu. (Známe aj ako: Connect Five, Päť v rade, X a O, Naughts and Crosses)</p>
<p xml:lang="sl">Bovo je igra podobna Gomoku (iz japonskega 五目並べ - lit. "pet točk") za dva igralca, ki izmenično postavljata njun piktogram na igralno ploščo. Igra je znana tudi kot: Poveži pet, Pet v vrsto, Križci in krogci.</p>
<p xml:lang="sr">Бово је игра налик на гомоку (од јапанског 五目並べ, буквално „пет тачака“) за два играча, где противници наизменично смештају свој пиктограм на играчку таблу. Проширена верзија икс‑окса.</p>
<p xml:lang="sr-Latn">Bovo je igra nalik na gomoku (od japanskog 五目並べ, bukvalno „pet tačaka“) za dva igrača, gde protivnici naizmenično smeštaju svoj piktogram na igračku tablu. Proširena verzija iksoksa.</p>
<p xml:lang="sr-ijekavian">Бово је игра налик на гомоку (од јапанског 五目並べ, буквално „пет тачака“) за два играча, где противници наизменично смештају свој пиктограм на играчку таблу. Проширена верзија икс‑окса.</p>
<p xml:lang="sr-ijekavianlatin">Bovo je igra nalik na gomoku (od japanskog 五目並べ, bukvalno „pet tačaka“) za dva igrača, gde protivnici naizmenično smeštaju svoj piktogram na igračku tablu. Proširena verzija iksoksa.</p>
<p xml:lang="sv">Bovo är ett spel för två spelare som liknar Gomoku (från japanska 五目並べ, ordagrant "fem poäng"), där motståndarna omväxlande placerar sina respektive symboler på spelbrädet (också känt som luffarschack, fem-i-rad, kryss och ringar).</p>
<p xml:lang="tr">Bovo, Gomoku (Japonca 五目並べ - "beş nokta") benzeri rakiplerin oyun kartına kendi simgelerini yerleştirdikleri iki oyunculu bir oyundur. (Şu isimlerle de bilinir: Beşliyi Bağla, Bir satırda beşli, X ve O, Satırlar ve Çarpılar)</p>
<p xml:lang="uk">Bovo — гра, подібна до гомоку (від японського 五目並べ — букв. «п’ять точок»), розрахована на двох гравців. У грі суперники почергово малюють власні значки на ігровій дошці. Інші назви гри: з’єднай п’ять, п’ять у рядок, хрестики-нулики.</p>
<p xml:lang="x-test">xxBovo is a Gomoku (from Japanese 五目並べ - lit. "five points") like game for two players, where the opponents alternate in placing their respective pictogram on the game board. (Also known as: Connect Five, Five in a row, X and O, Naughts and Crosses)xx</p>
<p xml:lang="zh-CN">Bovo 是一个双人五子棋游戏,对战双方在棋盘上各自放置自己的棋子。</p>
<p xml:lang="zh-TW">Bovo 是一套五子棋遊戲,兩個玩家誰先形成五個子連在一起就獲勝。</p>
</description>
<url type="homepage">https://games.kde.org/games/bovo</url>
<url type="bugtracker">https://bugs.kde.org/enter_bug.cgi?format=guided&amp;product=bovo</url>
<url type="help">https://docs.kde.org/?application=bovo</url>
<url type="donation">https://www.kde.org/community/donations/?app=bovo&amp;source=appdata</url>
<screenshots>
<screenshot type="default">
<image>https://cdn.kde.org/screenshots/bovo/bovo.png</image>
</screenshot>
</screenshots>
<project_group>KDE</project_group>
<provides>
<binary>bovo</binary>
</provides>
<releases>
<release version="22.08.3" date="2022-11-03"/>
<release version="22.08.2" date="2022-10-13"/>
<release version="22.08.1" date="2022-09-08"/>
<release version="22.08.0" date="2022-08-18"/>
</releases>
<content_rating type="oars-1.1"/>
</component>

126
org.kde.bovo.desktop Executable file
View File

@ -0,0 +1,126 @@
[Desktop Entry]
Type=Application
Exec=bovo -qwindowtitle %c
Icon=bovo
Terminal=false
StartupNotify=true
X-DBUS-StartupType=Multi
X-DBUS-ServiceName=org.kde.bovo
X-DocPath=bovo/index.html
Categories=Qt;KDE;Game;BoardGame;
Name=Bovo
Name[ar]=بوڤو
Name[bs]=Bovo
Name[ca]=Bovo
Name[ca@valencia]=Bovo
Name[cs]=Bovo
Name[da]=Bovo
Name[de]=Bovo
Name[el]=Bovo
Name[en_GB]=Bovo
Name[eo]=Bovo
Name[es]=Bovo
Name[et]=Bovo
Name[eu]=Bovo
Name[fa]=بُوُ
Name[fi]=Bovo
Name[fr]=Bovo
Name[ga]=Bovo
Name[gl]=Bovo
Name[hne]=बोवो
Name[hr]=Bovo
Name[hu]=Bovo
Name[id]=Bovo
Name[it]=Bovo
Name[ja]=Bovo
Name[ka]=Bovo
Name[kk]=Бово
Name[km]=Bovo
Name[ko]=Bovo
Name[lt]=Bovo
Name[lv]=Bovo
Name[mai]=Bovo
Name[mr]=बोव्हो
Name[ms]=Bovo
Name[nb]=Bovo
Name[nds]=Bovo
Name[ne]=बोभो
Name[nl]=Bovo
Name[nn]=Bovo
Name[pa]=ਬੋਵੋ
Name[pl]=Bovo
Name[pt]=Bovo
Name[pt_BR]=Bovo
Name[ro]=Bovo
Name[ru]=Bovo
Name[sk]=Bovo
Name[sl]=Bovo
Name[sq]=Bovo
Name[sr]=Бово
Name[sr@ijekavian]=Бово
Name[sr@ijekavianlatin]=Bovo
Name[sr@latin]=Bovo
Name[sv]=Bovo
Name[te]=బొవొ
Name[tr]=Bovo
Name[ug]=Bovo
Name[uk]=Бово
Name[wa]=Bovo
Name[x-test]=xxBovoxx
Name[zh_CN]=Bovo
Name[zh_TW]=Bovo
GenericName=Five-in-a-row Board Game
GenericName[ar]=لعبة خمسة في صفّ
GenericName[bs]=Pet-u-redu Igra na ploči
GenericName[ca]=Joc de cinc en fila
GenericName[ca@valencia]=Joc de cinc en fila
GenericName[cs]=Desková hra "pět v řadě"
GenericName[da]=Fem-på-række-brætspil
GenericName[de]=Fünf-Gewinnt-Brettspiel
GenericName[el]=Επιτραπέζιο παιχνίδι Πέντε στη σειρά
GenericName[en_GB]=Five-in-a-row Board Game
GenericName[eo]=Gobanga bretludo
GenericName[es]=Juego de mesa de cinco en línea
GenericName[et]=Viis ritta lauamäng
GenericName[eu]=Bosteko artzain-jokoa
GenericName[fa]=بازی تخته پنج در یک سطر
GenericName[fi]=Viiden suora
GenericName[fr]=Jeu de plateau « Cinq-en-ligne »
GenericName[ga]=Cluiche cláir cúig-cinn-as-a-chéile
GenericName[gl]=Xogo de taboleiro «pai, fillo e nai»
GenericName[hne]=बोर्ड मं एक लकीर मं पांच वाले खेल
GenericName[hu]=Ötöt egy sorba táblajáték
GenericName[id]=Permainan Papan lima dalam sebaris
GenericName[is]=Fimm-í-röð borðleikur
GenericName[it]=Forza 5, gioco da tavolo
GenericName[ja]=五目並べ
GenericName[kk]="Бесеуін - қатарға" ойны
GenericName[km]=ល្បែង​ក្ដារ ប្រាំ​ក្នុង​មួយ​ជួរ
GenericName[ko]=오목 게임
GenericName[lt]=Penki-vienoje-eilutėje stalo žaidimas
GenericName[lv]=Galda spēle pieci-rindā
GenericName[mr]=एका-ओळीत-पाच बोर्ड खेळ
GenericName[nb]=Brettspill fem på rad
GenericName[nds]="Fief op de Reeg"-Speel
GenericName[ne]=एक पङ्क्तिमा पाँच बोर्ड खेल
GenericName[nl]=Vijf-op-een-rij bordspel
GenericName[nn]=Fem på rad
GenericName[pl]=Gra planszowa "Pięć w rzędzie"
GenericName[pt]=Jogo de Tabuleiro Cinco-em-Linha
GenericName[pt_BR]=Jogo de tabuleiro como Reversi
GenericName[ro]=Joc de table Cinci-în-linie
GenericName[ru]=Японские крестики-нолики
GenericName[sk]=Stolová hra Piškvorky
GenericName[sl]=Namizna igra Pet v vrsto
GenericName[sr]=Игра на табли „пет у низу“
GenericName[sr@ijekavian]=Игра на табли „пет у низу“
GenericName[sr@ijekavianlatin]=Igra na tabli „pet u nizu“
GenericName[sr@latin]=Igra na tabli „pet u nizu“
GenericName[sv]=Fem-i-rad brädspel
GenericName[tr]=Bir-satırda-beş Tahta Oyunu
GenericName[ug]=بىر-قۇردا-بەش تاختا ئويۇنى
GenericName[uk]=Гра на дошці (п'ять-в-рядку)
GenericName[wa]=Djeu «cénk e roye»
GenericName[x-test]=xxFive-in-a-row Board Gamexx
GenericName[zh_CN]=五子棋游戏
GenericName[zh_TW]=五子棋棋盤遊戲

158
po/ar/bovo.po Normal file
View File

@ -0,0 +1,158 @@
# translation of bovo.po to
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
# Youssef Chahibi <chahibi@gmail.com>, 2007.
# Safa Alfulaij <safa1996alfulaij@gmail.com>, 2015.
# Zayed Al-Saidi <zayed.alsaidi@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2021-07-26 23:02+0400\n"
"Last-Translator: Zayed Al-Saidi <zayed.alsaidi@gmail.com>\n"
"Language-Team: ar\n"
"Language: ar\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
"X-Generator: Lokalize 21.07.70\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "صفا الفليج"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "safa1996alfulaij@gmail.com"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "السّمة"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "سرعة تشغيل العرض والإعادة."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "ما إذا كان يجب تحريك الحركات أم لا."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "محرّك الذّكاء الإصطناعيّ لاستخدامه."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "بوڤو"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "لعبة كدي خمسة في صفّ"
#: gui/main.cc:52
#, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "(c) 2002-2007, Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "المؤلّف"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "الانتصارات: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "الخسارات: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "أ&عد"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "أعد اللعبة"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "يعيد لك آخر لعبة لتشاهدها."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "ال&تحريك"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "ابدأ لعبة جديدة للعبها"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "انتهت اللعبة. تعادل!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "انتهت اللعبة. لقد ربحت!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "انتهت اللعبة. لقد خسرت!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "حان دورك."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "ينتظر الحاسوب."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "يعيد اللعبة"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "أُعيدت اللعبة"
#, fuzzy
#~ msgid "You won!"
#~ msgstr "أنت!"
#, fuzzy
#~ msgid "You lost!"
#~ msgstr "أنت!"

172
po/be/bovo.po Normal file
View File

@ -0,0 +1,172 @@
# translation of bovo.po to Belarusian
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Darafei Praliaskouski <komzpa@licei2.com>, 2007.
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2007-06-01 10:33+0300\n"
"Last-Translator: Darafei Praliaskouski <komzpa@licei2.com>\n"
"Language-Team: Belarusian <i18n@mova.org>\n"
"Language: be\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || n%10>=5 && n%10<=9 || n"
"%100>=11 && n%100<=14 ? 2 : 3);\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr ""
#, fuzzy, kde-format
#| msgid "You lost!"
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "Вы прайгралі!"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Тэма"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr ""
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr ""
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr ""
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr ""
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr ""
#: gui/main.cc:52
#, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr ""
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr ""
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Аўтар"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr ""
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr ""
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr ""
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr ""
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr ""
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr ""
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr ""
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr ""
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr ""
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr ""
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "Ваш ход."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "Чакаем камп'ютэр"
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr ""
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr ""
#~ msgid "You won!"
#~ msgstr "Вы выйгралі!"
#~ msgid "You lost!"
#~ msgstr "Вы прайгралі!"
#~ msgid "Very Easy"
#~ msgstr "Вельмі просты"
#~ msgid "Easy"
#~ msgstr "Лёгка"
#~ msgid "Medium"
#~ msgstr "Сярэдні"
#~ msgid "Hard"
#~ msgstr "Складана"
#~ msgid "Normal"
#~ msgstr "Звычайны"

147
po/bg/bovo.po Normal file
View File

@ -0,0 +1,147 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Petar Toushkov <pt.launchpad@gmail.com>, 2009.
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2009-05-08 20:34+0200\n"
"Last-Translator: Petar Toushkov <pt.launchpad@gmail.com>\n"
"Language-Team: Bulgarian <dict@fsa-bg.org>\n"
"Language: bg\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 0.3\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Petar Toushkov"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "pt.launchpad@gmail.com"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Тема"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "Скорост на демонстрацията и повторението на играта."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "Да бъдат ли анимирани ходовете."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "Кой енджин на ИИ да бъде използван."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "Игра на пет поредни за KDE."
#: gui/main.cc:52
#, fuzzy, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "(c) 2002,2007 Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Автор"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Победи: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Загуби: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "&Повторение"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Повторение на играта"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "Повтаря последната ви игра."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Анимация"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Започване на нова игра"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "КРАЙ НА ИГРАТА. Равенство!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "КРАЙ НА ИГРАТА. Вие победихте!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "КРАЙ НА ИГРАТА. Вие изгубихте!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "Ваш ред е."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "Компютърът е на ход."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "Повторение на играта"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "Играта беше повторена."

150
po/bs/bovo.po Normal file
View File

@ -0,0 +1,150 @@
# Bosnian translation for kdegames
# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010
# This file is distributed under the same license as the kdegames package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: kdegames\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2014-10-20 19:34+0000\n"
"Last-Translator: Samir Ribić <Unknown>\n"
"Language-Team: Bosnian <bs@li.org>\n"
"Language: bs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Launchpad (build 17341)\n"
"X-Launchpad-Export-Date: 2015-02-15 05:57+0000\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Haris Smajlagić,Samir Ribić"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "Haris@etf.ba,samir.ribic@etf.unsa.ba"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Tema"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "Brzina demoa i ponavljanja snimka."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "Treba li animirati poteze."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "Željeni motor VI."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "Igra na tabli „pet u nizu“ za KDE"
#: gui/main.cc:52
#, fuzzy, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "© 2002, 2007, Aron Bostrem"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Bostrem"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Autor"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Pobjeda: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Poraza: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "&Ponovi"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Ponovi partiju"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "Ponavlja posljednju partiju koju ste odigrali."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Animacija"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Započnite novu partiju"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "KRAJ IGRE. Neriješeno!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "KRAJ IGRE. Pobjeda!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "KRAJ IGRE. Poraz!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "Vaš potez."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "Čeka se računar."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "Ponavljam partiju"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "Partija ponovljena."

154
po/ca/bovo.po Normal file
View File

@ -0,0 +1,154 @@
# Translation of bovo.po to Catalan
# Copyright (C) 2007-2022 This_file_is_part_of_KDE
# This file is distributed under the license LGPL version 2.1 or
# version 3 or later versions approved by the membership of KDE e.V.
#
# Albert Astals Cid <aacid@kde.org>, 2007.
# Manuel Tortosa <manutortosa@gmail.com>, 2009.
# Manuel Tortosa Moreno <manutortosa@gmail.com>, 2009.
# Josep M. Ferrer <txemaq@gmail.com>, 2010, 2015, 2021, 2022.
# Antoni Bella Pérez <antonibella5@yahoo.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2022-03-20 19:59+0100\n"
"Last-Translator: Josep M. Ferrer <txemaq@gmail.com>\n"
"Language-Team: Catalan <kde-i18n-ca@kde.org>\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Accelerator-Marker: &\n"
"X-Generator: Lokalize 20.12.0\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Albert Astals Cid,Manuel Tortosa"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "aacid@kde.org,manutortosa@gmail.com"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Tema"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "Velocitat de reproducció de la demostració i la repetició."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "Si s'han d'animar els moviments o no."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "Motor d'intel·ligència artificial a usar."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "Joc de taula de cinc en fila del KDE"
#: gui/main.cc:52
#, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "(c) 2002-2007, Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Autor"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Victòries: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Derrotes: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "&Repetició"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Repeteix una partida"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "Repeteix la vostra última partida per tal que la vegeu."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Animació"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Inicia una partida nova"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "FI DE LA PARTIDA. Heu empatat!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "FI DE LA PARTIDA. Heu guanyat!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "FI DE LA PARTIDA. Heu perdut!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "És el vostre torn."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "S'està esperant l'ordinador."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "S'està repetint la partida"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "S'ha acabat la repetició de la partida."

View File

@ -0,0 +1,598 @@
<?xml version="1.0" ?>
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
<!ENTITY % Catalan "INCLUDE"
> <!-- change language only here -->
<!ENTITY % addindex "IGNORE"
> <!-- do not change this! -->
]>
<book id="bovo" lang="&language;"
> <!-- do not change this! -->
<bookinfo>
<title
>El manual del &bovo;</title>
<authorgroup>
<author
><firstname
>Aron</firstname
><surname
>Bostrom</surname
> <affiliation
><address
>&Aron.Bostrom.mail;</address
></affiliation>
</author>
<author
><firstname
>Eugene</firstname
><surname
>Trounev</surname
> <affiliation
><address
><email
>eugene.trounev@gmail.com</email
></address
></affiliation>
</author>
&traductor.Antoni.Bella;
</authorgroup>
<copyright>
<year
>2007</year>
<holder
>Aron Bostrom</holder>
</copyright>
<legalnotice
>&FDLNotice;</legalnotice>
<date
>21 de juny de 2021</date>
<releaseinfo
>KDE Gear 21.04</releaseinfo>
<abstract>
<para
>Aquesta documentació descriu el joc &bovo; versió 1.1</para>
</abstract>
<!--List of relevan keywords-->
<keywordset>
<keyword
>KDE</keyword
> <!-- do not change this! -->
<keyword
>kdegames</keyword
> <!-- do not change this! -->
<keyword
>joc</keyword
> <!-- do not change this! -->
<keyword
>bovo</keyword
><!--Application name goes here-->
<!-- Game genre. Use as many as necessary. Available game types are: Arcade, Board, Card, Dice, Toys, Logic, Strategy.-->
<keyword
>arcade</keyword>
<keyword
>tauler</keyword>
<keyword
>zeros i creus</keyword>
<!--Number of possible players. It can be: One, Two,..., Multiplayer-->
<keyword
>dos jugadors</keyword>
<!--All other relevant keywords-->
<keyword
>zeros</keyword>
<keyword
>creus</keyword>
<keyword
>Gomoku</keyword>
<keyword
>Connecta cinc</keyword>
<keyword
>Connecta5</keyword>
<keyword
>joc de taula</keyword>
<keyword
>X i O</keyword>
<keyword
>Cinc en una fila</keyword>
<keyword
>trencaclosques</keyword>
</keywordset>
</bookinfo>
<!--Content begins here: -->
<chapter id="introduction"
><title
>Introducció</title
> <!-- do not change this! -->
<note
><title
>Tipus de joc:</title
><para
>Tauler, arcade</para
></note
><!-- Game genre. Use as many as necessary. Available game types are: Arcade, Board, Card, Dice, Toys, Logic, Strategy.-->
<note
><title
>Nombre de possibles jugadors:</title
><para
>Dos</para
></note
><!--Number of possible players. It can be: One, Two,..., Multiplayer-->
<!--Short game description starts here. 3-4 sentences (paragraphs)-->
<para
>El &bovo; és un Gomoku (del japonès <foreignphrase lang="ja"
>五目並べ</foreignphrase
>, <quote
>cinc punts</quote
>) com un joc per a dos jugadors, on els adversaris s'alternen per a col·locar els seus respectius pictogrames sobre el tauler de joc. L'objectiu és connectar cinc de les teves pròpies peces en una fila de forma ininterrompuda en vertical, horitzontal o diagonal. </para>
<note
><title
>Nota:</title
><para
>També conegut com: Connecta cinc, Cinc en una fila, X i O, Zeros i creus</para
></note>
</chapter>
<chapter id="howto"
><title
>Com es juga</title
> <!-- do not change this! -->
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="mainscreen.png" format="PNG"/>
</imageobject>
<textobject>
<phrase
>Pantalla principal del &bovo;</phrase>
</textobject>
</mediaobject>
</screenshot>
<!--IMPORTANT: If the game has no defined objective, please remove the below line.-->
<note
><title
>Objectiu:</title
><para
>Connectar cinc de les peces pròpies en una fila de forma ininterrompuda en vertical, horitzontal o diagonal.</para
></note>
<para
>La primera vegada que s'inicia el &bovo;, s'inicia en el mode de demostració on dos jugadors de la IA lluiten entre si. Sempre podreu iniciar una partida nova emprant el botó <guibutton
>Nova</guibutton
> de la barra d'eines, l'entrada de menú <menuchoice
><guimenu
>Joc</guimenu
><guimenuitem
>Nova</guimenuitem
></menuchoice
> a la barra de menús o emprant la drecera predeterminada <keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
>. </para>
<note
><title
>Nota:</title
><para
>A causa que el primer jugador sempre té un avantatge sobre el segon, el &bovo; alternarà els jugadors, canviant-los en cada partida nova. </para
></note>
<para
>Si sou el primer jugador, comenceu la partida col·locant el pictograma en qualsevol lloc del camp de joc. Si sou el segon jugador, espereu fins que el primer jugador col·loqui el seu pictograma i després feu el mateix. Podeu col·locar la vostra marca en qualsevol quadrat del camp, a menys que ja estigui ocupat per una altra peça del joc (independentment de si és el vostre pictograma o el de l'adversari). </para>
<para
>Heu de situar les vostres peces tot evitant que l'adversari connecti cinc marques en una fila de forma ininterrompuda en vertical, horitzontal o diagonal. Al mateix temps, n'heu de connectar cinc de les vostres pròpies en aquest mateix format. Qui ho aconsegueixi primer, guanyarà la tanda. </para>
</chapter>
<chapter id="rules_and_tips"
><title
>Les regles del joc, estratègies i consells</title
> <!-- do not change this! -->
<!--This section has to do with game rules. Please give a detailed description of those using lists or paragraphs.-->
<sect1 id="rules">
<title
>Les regles del joc</title>
<itemizedlist>
<listitem
><para
>Els jugadors fan torns per a posar les seves respectives marques sobre el tauler de joc.</para
></listitem>
<listitem
><para
>Un jugador no pot moure la seva marca ja col·locada o posar-ne una sobre d'una altra.</para
></listitem>
<listitem
><para
>Els jugadors no poden perdre el seu torn.</para
></listitem>
<listitem
><para
>El jugador que aconsegueixi cinc marques connectades en línia recta (ja sigui en vertical, horitzontal o diagonal) guanyarà la partida.</para
></listitem>
</itemizedlist>
</sect1>
<sect1 id="tips">
<title
>Consells de joc</title>
<itemizedlist>
<listitem
><para
>Quan s'inicia el &bovo; per primera vegada, caldrà canviar-ne la mida. Canvieu la mida de la finestra de joc a la mida desitjada i el &bovo; escalarà el tauler de joc.</para
></listitem>
<listitem
><para
>La primera vegada que s'inicia el &bovo;, s'inicia en el mode de demostració, on dos jugadors de la IA s'enfronten entre si.</para
></listitem>
<listitem
><para
>Quan se surt del &bovo; abans que acabi la partida, la partida activa es desarà automàticament. Si durant l'inici, el &bovo; detecta una partida desada automàticament, es restaurà. Si no és així, el &bovo; llançarà un mode de demostració.</para
></listitem>
<listitem
><para
>Sempre podeu iniciar una patida nova amb el botó <guibutton
>Nova</guibutton
> de la barra d'eines, l'entrada de menú <menuchoice
><guimenu
>Joc</guimenu
><guimenuitem
>Nova</guimenuitem
></menuchoice
> a la barra de menús o amb la drecera predeterminada <keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
>.</para
></listitem>
<listitem
><para
>Si s'inicia una partida nova quan ja n'hi ha una activa, aquesta última es comptarà com a perduda.</para
></listitem>
<listitem
><para
>Es pot canviar la dificultat amb la llista desplegable <guilabel
>Dificultat</guilabel
> al costat dret de la barra d'estat, o des de l'entrada de menú <menuchoice
><guimenu
>Arranjament</guimenu
><guimenuitem
>Dificultat</guimenuitem
></menuchoice
> a la barra de menús.</para
></listitem>
<listitem
><para
>L'efecte de canviar la dificultat té lloc immediatament.</para
></listitem>
<listitem
><para
>Podeu canviar el tema del &bovo; des de l'entrada de menú <menuchoice
><guimenu
>Arranjament</guimenu
> <guisubmenu
>Tema</guisubmenu
></menuchoice
> a la barra de menús. A continuació, el tema es canviarà immediatament.</para
></listitem>
<listitem
><para
>L'animació es pot activar o desactivar com més us agradi des de l'entrada de menú <menuchoice
><guimenu
>Arranjament</guimenu
> <guimenuitem
>Animació</guimenuitem
></menuchoice
> a la barra de menús.</para
></listitem>
<listitem
><para
>Si us adoneu que heu realitzat un moviment molt dolent, teniu la possibilitat de desfer el vostre últim moviment des de la barra d'eines, la barra de menús o amb la drecera de teclat predeterminada per a desfer <keycombo action="simul"
>&Ctrl;<keycap
>Z</keycap
></keycombo
>.</para
><para
>Podreu seguir desfent moviments fins que arribeu al començament de la partida.</para
></listitem>
<listitem
><para
>Si no sabeu quin moviment fer, podeu obtenir un consell del jugador ordinador amb el botó <guibutton
>Consell</guibutton
>. La peça de la partida aconsellada pel &bovo; parpellejarà durant un breu període de temps.</para
></listitem>
<listitem
><para
>Quan s'acabi una partida, s'habilitarà l'acció <guibutton
>Repeteix</guibutton
>, la qual començarà una repetició de l'última partida.</para
></listitem>
</itemizedlist>
</sect1>
</chapter>
<chapter id="interface"
><title
>Resum de la interfície</title
> <!-- do not change this! -->
<sect1 id="menu">
<title
>Elements de menú</title>
<variablelist>
<varlistentry>
<term
><menuchoice
><shortcut
><keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
></shortcut
> <guimenu
>Joc</guimenu
> <guimenuitem
>Nova</guimenuitem
></menuchoice
></term>
<listitem
><para
>Comença una partida nova.</para
></listitem>
</varlistentry>
<varlistentry>
<term>
<menuchoice
><guimenu
>Joc</guimenu
> <guimenuitem
>Repetició</guimenuitem
></menuchoice
></term>
<listitem
><para
>Torna a jugar l'última partida.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
><keycombo action="simul"
>&Ctrl;<keycap
>Q</keycap
></keycombo
> </shortcut
> <guimenu
>Joc</guimenu
> <guimenuitem
>Surt</guimenuitem
></menuchoice
></term>
<listitem
><para
>En seleccionar aquest element s'acabarà la teva partida en joc i se sortirà del &nbsp;&bovo;.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
><keycombo action="simul"
>&Ctrl;<keycap
>Z</keycap
></keycombo
> </shortcut
> <guimenu
>Mou</guimenu
> <guimenuitem
>Desfés</guimenuitem
> </menuchoice>
</term>
<listitem>
<para
><action
>Desfà l'últim moviment que heu realitzat.</action
></para>
</listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
><keycap
>H</keycap
></shortcut
> <guimenu
>Mou</guimenu
> <guimenuitem
>Consell</guimenuitem
> </menuchoice
></term>
<listitem>
<para
><action
>Mostra</action
> una pista per al pròxim moviment. La peça del joc aconsellada per la IA del &nbsp;&bovo; parpellejarà durant un breu període de temps.</para>
</listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Arranjament</guimenu
> <guisubmenu
>Tema</guisubmenu
></menuchoice
></term>
<listitem
><para
>Tria un dels temes <guimenuitem
>Scribble</guimenuitem
>, <guimenuitem
>Contrast alt</guimenuitem
>, <guimenuitem
>Espai</guimenuitem
> o <guimenuitem
>Gomoku</guimenuitem
> per al joc.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Arranjament</guimenu
><guimenuitem
>Animació</guimenuitem
></menuchoice
></term>
<listitem
><para
>Activa o desactiva l'animació.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Arranjament</guimenu
> <guisubmenu
>Dificultat</guisubmenu
></menuchoice
></term>
<listitem
><para
>Tria la dificultat del joc entre diversos nivells, des de <guimenuitem
> Ridículament fàcil</guimenuitem
> fins a <guimenuitem
>Impossible</guimenuitem
>.</para
></listitem>
</varlistentry>
</variablelist>
<para
>De manera addicional, el &bovo; té la configuració comuna al &kde; i els elements dels menús <guimenu
>Arranjament</guimenu
> i <guimenu
>Ajuda</guimenu
>. Per a obtenir més informació, llegiu les seccions sobre <ulink url="help:/fundamentals/menus.html#menus-settings"
>El menú Arranjament</ulink
> i <ulink url="help:/fundamentals/menus.html#menus-help"
>El menú Ajuda</ulink
> en els Fonaments del &kde;. </para>
</sect1>
</chapter>
<chapter id="faq"
><title
>Preguntes més freqüents</title
> <!-- do not change this! -->
<!--This chapter is for frequently asked questions. Please use <qandaset
> <qandaentry
> only!-->
<qandaset>
<!--Following is a standard list of FAQ questions.-->
<qandaentry>
<question
><para
>Vull canviar l'aparença d'aquest joc. Puc fer-ho? </para
></question>
<answer
><para
>Sí. Per a canviar el tema visual del &bovo;, podeu utilitzar l'entrada de menú <menuchoice
><guimenu
>Arranjament</guimenu
> <guisubmenu
>Tema</guisubmenu
></menuchoice
> a la barra de menús.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>Puc utilitzar el teclat per a jugar a aquest joc? </para
></question>
<answer
><para
>No. Aquest joc no es pot jugar amb el teclat.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>He de sortir del joc ara, però encara no he acabat. Puc desar el meu progrés?</para
></question>
<answer
><para
>No. No hi ha una característica com <quote
>Desa</quote
> en el &bovo;, però a l'inici sí que es restaura la darrera partida sense acabar.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>On es troben les puntuacions més altes?</para
></question>
<answer
><para
>El &bovo; no té aquesta característica.</para
></answer>
</qandaentry>
<!--Please add more Q&As if needed-->
</qandaset>
</chapter>
<chapter id="credits"
><title
>Crèdits i llicència</title
> <!-- do not change this! -->
<!--This chapter is for credits and licenses.-->
<para
>&bovo; </para>
<para
>Copyright del programa 2002, 2007 &Aron.Bostrom; &Aron.Bostrom.mail; </para>
<para
>Copyright de la documentació 2007 &Aron.Bostrom; &Aron.Bostrom.mail;</para>
<para
>Traductor de la documentació: &credits.Antoni.Bella;</para
> &underFDL; &underGPL; </chapter>
&documentation.index;
</book>
<!--
Local Variables:
mode: sgml
sgml-minimize-attributes:nil
sgml-general-insert-case:lower
sgml-omittag:t
sgml-shorttag:t
sgml-namecase-general:t
sgml-always-quote-attributes:t
sgml-indent-step:0
sgml-indent-data:nil
sgml-parent-document:nil
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
-->

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

154
po/ca@valencia/bovo.po Normal file
View File

@ -0,0 +1,154 @@
# Translation of bovo.po to Catalan (Valencian)
# Copyright (C) 2007-2022 This_file_is_part_of_KDE
# This file is distributed under the license LGPL version 2.1 or
# version 3 or later versions approved by the membership of KDE e.V.
#
# Albert Astals Cid <aacid@kde.org>, 2007.
# Manuel Tortosa <manutortosa@gmail.com>, 2009.
# Manuel Tortosa Moreno <manutortosa@gmail.com>, 2009.
# Josep M. Ferrer <txemaq@gmail.com>, 2010, 2015, 2021, 2022.
# Antoni Bella Pérez <antonibella5@yahoo.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2022-03-20 19:59+0100\n"
"Last-Translator: Josep M. Ferrer <txemaq@gmail.com>\n"
"Language-Team: Catalan <kde-i18n-ca@kde.org>\n"
"Language: ca@valencia\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Accelerator-Marker: &\n"
"X-Generator: Lokalize 20.12.0\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Albert Astals Cid,Manuel Tortosa"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "aacid@kde.org,manutortosa@gmail.com"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Tema"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "Velocitat de reproducció de la demostració i la repetició."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "Si s'han d'animar els moviments o no."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "Motor d'intel·ligència artificial que s'utilitzarà."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "Joc de taula de cinc en fila de KDE"
#: gui/main.cc:52
#, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "(c) 2002-2007, Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Autoria"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Victòries: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Derrotes: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "&Repetició"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Repetix una partida"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "Repetix la vostra última partida per tal que la vegeu."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Animació"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Inicia una partida nova"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "FI DE LA PARTIDA. Heu empatat!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "FI DE LA PARTIDA. Heu guanyat!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "FI DE LA PARTIDA. Heu perdut!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "És el vostre torn."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "S'està esperant l'ordinador."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "S'està repetint la partida"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "S'ha acabat la repetició de la partida."

147
po/cs/bovo.po Normal file
View File

@ -0,0 +1,147 @@
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Vít Pelčák <vit@pelcak.org>, 2011, 2015.
#
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2015-01-27 10:47+0100\n"
"Last-Translator: Vít Pelčák <vit@pelcak.org>\n"
"Language-Team: Czech <kde-i18n-doc@kde.org>\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Lokalize 2.0\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Lukáš Tinkl,David Kolibáč"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "lukas@kde.org,david@kolibac.cz"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Motiv"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "Rychlost ukázky a přehrání záznamu."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "Zda mají být pohyby animovány nebo ne."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "Umělá inteligence, která se má použít."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "Desková hra \"pět v řadě\""
#: gui/main.cc:52
#, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "(c) 2002-2007, Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Autor"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Vítězství: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Prohry: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "Přeh&rát"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Přehrát hru"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "Přehraje záznam poslední hry."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Animace"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Spusťte novou hru"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "KONEC HRY. Remíza!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "KONEC HRY. Vyhráli jste!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "KONEC HRY. Prohráli jste!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "Jste na tahu."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "Čeká se na počítač."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "Hra se přehrává"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "Hra přehrána."

View File

@ -0,0 +1,612 @@
<?xml version="1.0" ?>
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
<!ENTITY % Czech "INCLUDE"
> <!-- change language only here -->
<!ENTITY % addindex "IGNORE"
> <!-- do not change this! -->
]>
<book id="bovo" lang="&language;"
> <!-- do not change this! -->
<bookinfo>
<title
>Příručka aplikace &bovo;</title>
<authorgroup>
<author
><firstname
>Aron</firstname
><surname
>Bostrom</surname
> <affiliation
><address
>&Aron.Bostrom.mail;</address
></affiliation>
</author>
<author
><firstname
>Eugene</firstname
><surname
>Trounev</surname
> <affiliation
><address
><email
>eugene.trounev@gmail.com</email
></address
></affiliation>
</author>
<othercredit role="translator"
><firstname
>Lukáš</firstname
><surname
>Vlček</surname
><affiliation
><address
><email
>lukas.vlcek777@gmail.com</email
></address
></affiliation
><contrib
>Překlad</contrib
></othercredit
>
</authorgroup>
<copyright>
<year
>2007</year>
<holder
>Aron Bostrom</holder>
</copyright>
<legalnotice
>&FDLNotice;</legalnotice>
<date
>9.5.2016</date>
<releaseinfo
>1.1 (Aplikace 16.04)</releaseinfo>
<abstract>
<para
>Tato dokumentace popisuje hru &bovo; ve verzi 1.1.</para>
</abstract>
<!--List of relevan keywords-->
<keywordset>
<keyword
>KDE</keyword
> <!-- do not change this! -->
<keyword
>kdegames</keyword
> <!-- do not change this! -->
<keyword
>hra</keyword
> <!-- do not change this! -->
<keyword
>bovo</keyword
><!--Application name goes here-->
<!-- Game genre. Use as many as necessary. Available game types are: Arcade, Board, Card, Dice, Toys, Logic, Strategy.-->
<keyword
>arkáda</keyword>
<keyword
>desková</keyword>
<keyword
>nuly a křížky</keyword>
<!--Number of possible players. It can be: One, Two,..., Multiplayer-->
<keyword
>dva hráči</keyword>
<!--All other relevant keywords-->
<keyword
>nuly</keyword>
<keyword
>křížky</keyword>
<keyword
>Gomoku</keyword>
<keyword
>Spoj pět</keyword>
<keyword
>Spoj5</keyword>
<keyword
>Desková hra</keyword>
<keyword
>X a O</keyword>
<keyword
>Pět v řadě</keyword>
<keyword
>Hlavolam</keyword>
</keywordset>
</bookinfo>
<!--Content begins here: -->
<chapter id="introduction"
><title
>Úvod</title
> <!-- do not change this! -->
<note
><title
>Typ hry:</title
><para
>Desková, arkáda</para
></note
><!-- Game genre. Use as many as necessary. Available game types are: Arcade, Board, Card, Dice, Toys, Logic, Strategy.-->
<note
><title
>Počet možných hráčů:</title
><para
>Dva</para
></note
><!--Number of possible players. It can be: One, Two,..., Multiplayer-->
<!--Short game description starts here. 3-4 sentences (paragraphs)-->
<para
>&bovo; je hra Gomoku (z japonského <foreignphrase lang="ja"
>五目並べ</foreignphrase
> doslovně "pět bodů") pro dva soupeřící hráče, kteří se střídají v umísťování svých značek na herní desku. Cílem hry je spojit pět vlastních neoddělených značek v řádku, sloupci či úhlopříčce. </para>
<note
><title
>Poznámka:</title
><para
>Je také známá jako: Spoj pět, Pět v řadě, X a O, Nuly a křížky</para
></note>
</chapter>
<chapter id="howto"
><title
>Jak hrát</title
> <!-- do not change this! -->
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="mainscreen.png" format="PNG"/>
</imageobject>
<textobject>
<phrase
>Hlavní obrazovka hry &bovo;</phrase>
</textobject>
</mediaobject>
</screenshot>
<!--IMPORTANT: If the game has no defined objective, please remove the below line.-->
<note
><title
>Cíl:</title
><para
>Spojte pět Vašich vlastních symbolů v neporušené svislé, vodorovné nebo úhlopříčné řadě.</para
></note>
<para
>Aplikace &bovo; je při prvním startu spuštěna v režimu demo, ve kterém soupeří dva hráči oba s umělou inteligencí. Spustit novou hru můžete vždy použitím tlačítka <guibutton
>Nová</guibutton
> na nástrojové liště, vybráním položky <menuchoice
><guimenu
>Hra</guimenu
><guimenuitem
>Nová</guimenuitem
></menuchoice
> z hlavní nabídky nebo použitím klávesové zkratky <keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
>. </para>
<note
><title
>Poznámka:</title
><para
>Protože první hráč má vždy přednost před druhým hráčem, aplikace &bovo; bude střídat hráče při každé nové hře. </para
></note>
<para
>Jste-li první hráč - začínáte hru umístěním Vašeho symbolu kdekoli na herní ploše. Jste-li druhý hráč, čekáte dokud první hráč neumístí symbol a je řada na Vás. Váši značku můžete umístit do kteréhokoli čtverce na ploše, není-li již obsazen jiným herním obrazcem (bez ohledu, je-li to Váš symbol nebo Vašeho protivníka). </para>
<para
>Váš obrazec musíte umístit tak, že zabrání Vašemu protivníkovi ve spojení pěti značek v nepřerušené vodorovné, svislé nebo úhlopříčné řadě. Kdokoli uspěje jako první - vyhrává kolo. </para>
</chapter>
<chapter id="rules_and_tips"
><title
>Herní pravidla, strategie a tipy</title
> <!-- do not change this! -->
<!--This section has to do with game rules. Please give a detailed description of those using lists or paragraphs.-->
<sect1 id="rules">
<title
>Herní pravidla</title>
<itemizedlist>
<listitem
><para
>Hráči se střídají v umísťování svých vlastních značek na herní desku.</para
></listitem>
<listitem
><para
>Hráč nemůže přesunout jejich již umístěné značky nebo umístit svoji značku na již umístěnou značku.</para
></listitem>
<listitem
><para
>Hráči nemohou přijít o svoje hodnocení.</para
></listitem>
<listitem
><para
>Hráč, který dosáhne pěti značek spojených rovnou čarou (svislou, vodorovnou nebo úhlopříčnou), vyhrává hru.</para
></listitem>
</itemizedlist>
</sect1>
<sect1 id="tips">
<title
>Herní tipy</title>
<itemizedlist>
<listitem
><para
>Když &bovo; spuštěno poprvé, potřebuje změnit velikost okna. Změňte velikost herního okna na požadovanou velikost a aplikace &bovo; překreslí hrací desku.</para
></listitem>
<listitem
><para
>Aplikace &bovo; je při prvním startu spuštěna v režimu demo, ve kterém soupeří dva hráči oba s umělou inteligencí.</para
></listitem>
<listitem
><para
>Když je aplikace &bovo; ukončena před koncem hry, je aktivní hra automaticky uložena. Zjistí-li aplikace &bovo; při startu uloženou hru, obnoví ji. Nezjisti-li, aplikace &bovo; spustí režim demo.</para
></listitem>
<listitem
><para
>Novou hru můžete začít vždy pomocí tlačítka <guibutton
>Nová</guibutton
>, zvolením položky <menuchoice
><guimenu
>Hra</guimenu
><guimenuitem
>Nová</guimenuitem
></menuchoice
> v hlavní nabídce nebo pomocí výchozí klávesové zkratky <keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
>.</para
></listitem>
<listitem
><para
>Je-li nová hra spuštěna při již aktivní hře, je to započítáno jako prohra.</para
></listitem>
<listitem
><para
>Obtížnost můžete měnit pomocí roletového seznamu <guilabel
>Obtížnost</guilabel
> v pravé části stavové lišty nebo položkou <menuchoice
><guimenu
>Nastavení</guimenu
><guimenuitem
>Obtížnost</guimenuitem
></menuchoice
> v hlavní nabídce.</para
></listitem>
<listitem
><para
>Provedení změny obtížnosti proběhne ihned.</para
></listitem>
<listitem
><para
>Motiv aplikace &bovo; můžete přepnout pomocí nabídky <menuchoice
><guimenu
>Nastavení</guimenu
> <guisubmenu
>Motiv</guisubmenu
></menuchoice
> v hlavní nabídce. Motiv je pak ihned přepnut.</para
></listitem>
<listitem
><para
>Animaci můžete zapnout nebo vypnout, jak se Vám líbí, položkou <menuchoice
><guimenu
>Nastavení</guimenu
> <guimenuitem
>Animace</guimenuitem
></menuchoice
> v hlavní nabídce.</para
></listitem>
<listitem
><para
>Pokud jste si uvědomili, že jste udělali velmi špatný tah, máte možnost vrátit poslední tah z nástrojové lišty, hlavní nabídky nebo pomocí výchozí klávesové zkratky <keycombo action="simul"
>&Ctrl;<keycap
>Z</keycap
></keycombo
>.</para
><para
>Tahy můžete neustále vracet, dokud nedosáhnete začátku hry.</para
></listitem>
<listitem
><para
>Nevíte-li jak táhnout, můžete dostat radu od počítačového hráče pomocí tlačítka <guibutton
>Rada</guibutton
>. Herní symbol je navržen umělou inteligencí aplikací &bovo;, který pak na krátkou dobu bliká.</para
></listitem>
<listitem
><para
>Když hra skončila, je zpřístupněna činnost <guibutton
>Přehrát</guibutton
>, která spouští přehrávání poslední hry.</para
></listitem>
</itemizedlist>
</sect1>
</chapter>
<chapter id="interface"
><title
>Náhled na rozhraní</title
> <!-- do not change this! -->
<sect1 id="menu">
<title
>Položky hlavní nabídky</title>
<variablelist>
<varlistentry>
<term
><menuchoice
><shortcut
><keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
></shortcut
> <guimenu
>Hra</guimenu
> <guimenuitem
>Nová</guimenuitem
></menuchoice
></term>
<listitem
><para
>Spouští novou hru.</para
></listitem>
</varlistentry>
<varlistentry>
<term>
<menuchoice
><guimenu
>Hra</guimenu
> <guimenuitem
>Přehrát</guimenuitem
></menuchoice
></term>
<listitem
><para
>Přehraje poslední hru.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
><keycombo action="simul"
>&Ctrl;<keycap
>Q</keycap
></keycombo
></shortcut
> <guimenu
>Hra</guimenu
> <guimenuitem
>Ukončit</guimenuitem
></menuchoice
></term>
<listitem
><para
>Výběr této položky ukončí hru a zavře aplikaci &bovo;.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
> <keycombo action="simul"
>&Ctrl;<keycap
>Z</keycap
> </keycombo
> </shortcut
> <guimenu
>Tah</guimenu
> <guimenuitem
>Zpět</guimenuitem
> </menuchoice>
</term>
<listitem>
<para
><action
>Vrací zpět poslední tah.</action
></para>
</listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
> <keycap
>H</keycap
> </shortcut
> <guimenu
>Tah</guimenu
> <guimenuitem
>Rada</guimenuitem
> </menuchoice
></term>
<listitem>
<para
><action
>Zobrazuje</action
> radu pro další tah. Herní symbol je navržen umělou inteligencí aplikací &bovo;, který pak na krátkou dobu bliká.</para>
</listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Nastavení</guimenu
><guisubmenu
>Motiv</guisubmenu
></menuchoice
></term>
<listitem
><para
>Vyberte jeden z motivů pro hru: <guimenuitem
>Scribble</guimenuitem
>, <guimenuitem
>Vysoký kontrast</guimenuitem
>, <guimenuitem
>Vesmír</guimenuitem
> nebo <guimenuitem
>Gomoku</guimenuitem
>.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Nastavení</guimenu
><guimenuitem
>Animace </guimenuitem
></menuchoice
></term>
<listitem
><para
>Zapíná nebo vypíná animaci.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Nastavení</guimenu
><guisubmenu
>Obtížnost</guisubmenu
></menuchoice
></term>
<listitem
><para
>Vyberte obtížnost hry od <guimenuitem
>Směšně jednoduchá</guimenuitem
> až po <guimenuitem
>Nemožná</guimenuitem
>.</para
></listitem>
</varlistentry>
</variablelist>
<para
>&bovo; má běžné položky &kde; nabídek <guimenu
>Nastavení</guimenu
> a <guimenu
>Nápověda</guimenu
>. Pro více informací si přečtěte část o <ulink url="help:/fundamentals/ui.html#menus-settings"
>nabídce Nastavení</ulink
> a <ulink url="help:/fundamentals/ui.html#menus-help"
>nabídce Nápověda</ulink
> v nápovědě Základy &kde;. </para>
</sect1>
</chapter>
<chapter id="faq"
><title
>Často kladené otázky</title
> <!-- do not change this! -->
<!--This chapter is for frequently asked questions. Please use <qandaset
> <qandaentry
> only!-->
<qandaset>
<!--Following is a standard list of FAQ questions.-->
<qandaentry>
<question
><para
>Chci změnit vzhled hry. Mohu? </para
></question>
<answer
><para
>Ano. Chcete-li změnit visuální motiv aplikace &bovo;, můžete použít volbu hlavní nabídky <menuchoice
><guimenu
>Nastavení</guimenu
><guisubmenu
>Motiv</guisubmenu
> </menuchoice
>.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>Mohu při hraní použít klávesnici? </para
></question>
<answer
><para
>Ne. Hru &bovo; nelze hrát pomocí klávesnice.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>Musím ukončit svoji hru ještě před dokončením. Mohu uložit svůj průběh?</para
></question>
<answer
><para
>Ne. Zde v aplikaci &bovo; není možnost <quote
>Uložit</quote
>, ale &bovo; ukládá poslední nedokončenou hru.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>Kde jsou nejlepší výsledky?</para
></question>
<answer
><para
>&bovo; nemá tuto funkci.</para
></answer>
</qandaentry>
<!--Please add more Q&As if needed-->
</qandaset>
</chapter>
<chapter id="credits"
><title
>Informace o autorech a licenční ujednání</title
> <!-- do not change this! -->
<!--This chapter is for credits and licenses.-->
<para
>&bovo; </para>
<para
>Program copyright 2002, 2007 &Aron.Bostrom; &Aron.Bostrom.mail; </para>
<para
>Documentation copyright 2007 &Aron.Bostrom; &Aron.Bostrom.mail;</para>
<para
>Překlad dokumentace Lukáš Vlček <email
>lukas.vlcek777@gmail.com</email
></para
> &underFDL; &underGPL; </chapter>
&documentation.index;
</book>
<!--
Local Variables:
mode: sgml
sgml-minimize-attributes:nil
sgml-general-insert-case:lower
sgml-omittag:t
sgml-shorttag:t
sgml-namecase-general:t
sgml-always-quote-attributes:t
sgml-indent-step:0
sgml-indent-data:nil
sgml-parent-document:nil
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
-->

157
po/da/bovo.po Normal file
View File

@ -0,0 +1,157 @@
# translation of bovo.po to
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Martin Schlander <mschlander@opensuse.org>, 2008, 2009, 2015.
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2015-05-26 22:11+0200\n"
"Last-Translator: Martin Schlander <mschlander@opensuse.org>\n"
"Language-Team: Danish <dansk@dansk-gruppen.dk>\n"
"Language: da\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 1.5\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Martin Schlander"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "mschlander@opensuse.org"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Tema"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "Hastighed på demo og afspilning af gengivelse."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "Om træk skal animeres eller ej."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "AI-motor der skal bruges."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "Brætspillet fem på række til KDE"
#: gui/main.cc:52
#, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "(c) 2002-2007, Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Udvikler"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Vinder: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Taber: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "&Gengivelse"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Gengiv spillet"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "Gengiver dit sidste spil så du kan kigge på."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Animation"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Start et nyt spil"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "SPILLET ER SLUT. Uafgjort!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "SPILLET ER SLUT. Du vandt!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "SPILLET ER SLUT. Du tabte!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "Det er din tur."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "Venter på computeren."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "Gengiver spil"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "Spil gengivet."
#~ msgid "Difficulty level: strength of the computer player."
#~ msgstr "Sværhedsgrad: Computerspillerens styrke."
#~ msgid "You won!"
#~ msgstr "Du vandt!"
#~ msgid "You lost!"
#~ msgstr "Du tabte!"

159
po/de/bovo.po Normal file
View File

@ -0,0 +1,159 @@
# Stefan Winter <swinter@kde.org>, 2007.
# Stefan Winter <Stefan Winter <swinter@kde.org>>, 2007.
# Johannes Obermayr <johannesobermayr@gmx.de>, 2009.
# Panagiotis Papadopoulos <pano_90@gmx.net>, 2009.
# Frederik Schwarzer <schwarzer@kde.org>, 2011.
# Burkhard Lück <lueck@hube-lueck.de>, 2015.
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2015-03-07 19:37+0100\n"
"Last-Translator: Burkhard Lück <lueck@hube-lueck.de>\n"
"Language-Team: German <kde-i18n-de@kde.org>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Stefan Winter"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "swinter@kde.org"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Design"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "Geschwindigkeit für die Wiedergabe der Demonstration und Aufzeichnung."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "Ist diese Einstellung aktiviert, werden die Spielzüge animiert."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "Die zu verwendende künstliche Intelligenz."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "KDE „Fünf gewinnt“ Brettspiel"
#: gui/main.cc:52
#, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "© 2002-2007, Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Autor"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Gewonnen: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Verloren: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "&Vorführung"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Aufzeichnung wiedergeben"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr ""
"Das letzte Spiel wird im Zeitraffer wiedergegeben, sodass Sie es sich "
"ansehen können."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Animation"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Ein neues Spiel starten"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "SPIEL BEENDET. Unentschieden!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "SPIEL BEENDET. Sie haben gewonnen!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "SPIEL BEENDET. Sie haben verloren!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "Sie sind dran."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "Warten auf den Computer."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "Aufzeichnung wird wiedergegeben"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "Vorführung beendet."
#~ msgid "Difficulty level: strength of the computer player."
#~ msgstr "Schwierigkeitsgrad: Stärke des Computerspielers."
#~ msgid "You won!"
#~ msgstr "Sie haben gewonnen!"
#~ msgid "You lost!"
#~ msgstr "Sie haben verloren!"

View File

@ -0,0 +1,612 @@
<?xml version="1.0" ?>
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
<!ENTITY % German "INCLUDE"
> <!-- change language only here -->
<!ENTITY % addindex "IGNORE"
> <!-- do not change this! -->
]>
<book id="bovo" lang="&language;"
> <!-- do not change this! -->
<bookinfo>
<title
>Das Handbuch zu &bovo;</title>
<authorgroup>
<author
><firstname
>Aron</firstname
><surname
>Bostrom</surname
> <affiliation
><address
>&Aron.Bostrom.mail;</address
></affiliation>
</author>
<author
><firstname
>Eugene</firstname
><surname
>Trounev</surname
> <affiliation
><address
><email
>eugene.trounev@gmail.com</email
></address
></affiliation>
</author>
<othercredit role="translator"
><firstname
>Burkhard</firstname
><surname
>Lück</surname
><affiliation
><address
><email
>lueck@hube-lueck.de</email
></address
></affiliation
><contrib
>Übersetzung</contrib
></othercredit
>
</authorgroup>
<copyright>
<year
>2007</year>
<holder
>Aron Bostrom</holder>
</copyright>
<legalnotice
>&FDLNotice;</legalnotice>
<date
>2021-06-21</date>
<releaseinfo
>KDE Gear 21.04</releaseinfo>
<abstract>
<para
>Dieses Handbuch beschreibt das Spiel &bovo; in der Version 1.1</para>
</abstract>
<!--List of relevan keywords-->
<keywordset>
<keyword
>KDE</keyword
> <!-- do not change this! -->
<keyword
>kdegames</keyword
> <!-- do not change this! -->
<keyword
>Spiel</keyword
> <!-- do not change this! -->
<keyword
>bovo</keyword
><!--Application name goes here-->
<!-- Game genre. Use as many as necessary. Available game types are: Arcade, Board, Card, Dice, Toys, Logic, Strategy.-->
<keyword
>Arcade</keyword>
<keyword
>Brettspiel</keyword>
<keyword
>Nullen und Kreuze</keyword>
<!--Number of possible players. It can be: One, Two,..., Multiplayer-->
<keyword
>zwei Spieler</keyword>
<!--All other relevant keywords-->
<keyword
>Nullen</keyword>
<keyword
>Kreuze</keyword>
<keyword
>Gomoku</keyword>
<keyword
>Fünf verbinden</keyword>
<keyword
>5 verbinden</keyword>
<keyword
>Brettspiel</keyword>
<keyword
>X und O</keyword>
<keyword
>Fünf in einer Reihe</keyword>
<keyword
>Spiel</keyword>
</keywordset>
</bookinfo>
<!--Content begins here: -->
<chapter id="introduction"
><title
>Einführung</title
> <!-- do not change this! -->
<note
><title
>Spieltyp:</title
><para
>Brettspiel, Arcade</para
></note
><!-- Game genre. Use as many as necessary. Available game types are: Arcade, Board, Card, Dice, Toys, Logic, Strategy.-->
<note
><title
>Anzahl der Spieler:</title
><para
>Zwei</para
></note
><!--Number of possible players. It can be: One, Two,..., Multiplayer-->
<!--Short game description starts here. 3-4 sentences (paragraphs)-->
<para
>&bovo; ist ein Gomoku (aus dem japanischen <foreignphrase lang="ja"
>五目並べ</foreignphrase
>, wörtlich <quote
>Fünf Punkte</quote
>) ähnliches Spiel für zwei Spieler, bei dem die Gegner abwechselnd ihre jeweiligen Piktogramme auf dem Brett platzieren. Das Ziel des Spiels ist es, fünf der eigenen Symbole in einer durchgehenden Reihe vertikal, horizontal oder diagonal zu verbinden. </para>
<note
><title
>Hinweis:</title
><para
>Auch bekannt als: Fünf verbinden, Fünf in einer Reihe, X und O, Nullen und Kreuze</para
></note>
</chapter>
<chapter id="howto"
><title
>Spielanleitung</title
> <!-- do not change this! -->
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="mainscreen.png" format="PNG"/>
</imageobject>
<textobject>
<phrase
>&bovo;-Hauptfenster</phrase>
</textobject>
</mediaobject>
</screenshot>
<!--IMPORTANT: If the game has no defined objective, please remove the below line.-->
<note
><title
>Ziel des Spiels:</title
><para
>Verbinden Sie fünf Ihrer eigenen Symbole in einer durchgehenden Reihe vertikal, horizontal oder diagonal. </para
></note>
<para
>Beim ersten Start von &bovo; wird ein Demomodus gestartet, bei dem zwei KI-Spieler gegeneinander antreten. Sie können mit dem Knopf <guibutton
>Neu</guibutton
> in der Werkzeugleiste, dem Menüeintrag <menuchoice
><guimenu
>Spiel</guimenu
><guimenuitem
>Neu</guimenuitem
></menuchoice
> oder durch das voreingestellte Tastenkürzel <keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
> jederzeit ein neues Spiel starten. </para>
<note
><title
>Hinweis:</title
><para
>Da der erste Spieler dem zweiten gegenüber immer einen Vorteil hat, führen die Spieler bei jedem neuen Spiel abwechselnd den ersten Zug aus. </para
></note>
<para
>Wenn Sie der erste Spieler sind, starten Sie das Spiel, indem Sie Ihr Piktogramm irgendwo auf dem Spielfeld platzieren. Als zweiter Spieler warten Sie, bis der erste Spieler sein Piktogramm platziert hat und verfahren dann ebenso. Sie können ihr Symbol in jedes Quadrat auf dem Feld setzen, sofern es noch nicht besetzt ist (sei es von einem eigenen Symbol oder dem des Gegners). </para>
<para
>Sie müssen durch geschicktes Setzen ihrer Symbole verhindern, dass Ihr Gegner fünf Markierungen in einer durchgehenden Reihe vertikal, horizontal oder diagonal anordnet. Gleichzeitig müssen Sie fünf Ihrer eigenen Symbole vertikal, horizontal oder diagonal in einer durchgehenden Reihe platzieren. Wer zuerst Erfolg damit hat, gewinnt die Runde. </para>
</chapter>
<chapter id="rules_and_tips"
><title
>Spielregeln, Spielstrategien und Tipps</title
> <!-- do not change this! -->
<!--This section has to do with game rules. Please give a detailed description of those using lists or paragraphs.-->
<sect1 id="rules">
<title
>Spielregeln</title>
<itemizedlist>
<listitem
><para
>Die Spieler setzen abwechselnd ihre jeweiligen Symbole auf das Spielbrett.</para
></listitem>
<listitem
><para
>Ein bereits platziertes Symbol kann vom Spieler weder bewegt noch durch ein anderes Symbol ersetzt werden.</para
></listitem>
<listitem
><para
>Spieler müssen in jeder Runde einen Zug ausführen und können nicht aussetzen.</para
></listitem>
<listitem
><para
>Der Spieler, der fünf Symbole in einer geraden Linie (sei es vertikal, horizontal oder diagonal) verbinden kann, gewinnt das Spiel.</para
></listitem>
</itemizedlist>
</sect1>
<sect1 id="tips">
<title
>Spieltipps</title>
<itemizedlist>
<listitem
><para
>Beim ersten Start von &bovo; muss die Größe des Spielfelds angepasst werden. Verändern Sie die Fenstergröße wie gewünscht, das Spielbrett wird der neuen Fenstergröße angepasst.</para
></listitem>
<listitem
><para
>Beim ersten Start von &bovo; wird ein Demomodus gestartet, bei dem zwei KI-Spieler gegeneinander antreten.</para
></listitem>
<listitem
><para
>Wenn &bovo; vor Spielende geschlossen wird, wird das laufende Spiel automatisch gesichert. Entdeckt &bovo; beim Start ein automatisch gesichertes Spiel, wird dieses wiederhergestellt. Anderenfalls wird ein Demomodus gestartet.</para
></listitem>
<listitem
><para
>Um ein neues Spiel zu starten, klicken Sie in der Werkzeugleiste auf <guibutton
>Neu</guibutton
>, wählen im Menü <menuchoice
><guimenu
>Spiel</guimenu
><guimenuitem
>Neu</guimenuitem
></menuchoice
> oder drücken auf der Tastatur <keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
>.</para
></listitem>
<listitem
><para
>Wenn Sie ein neues Spiel beginnen, wird das laufende Spiel als verloren gewertet.</para
></listitem>
<listitem
><para
>Der Schwierigkeitsgrad kann über das Auswahlfeld <guilabel
>Schwierigkeitsgrad</guilabel
> am rechten Ende der Statusleiste oder mit <menuchoice
><guimenu
>Einstellungen</guimenu
> <guimenuitem
>Schwierigkeitsgrad</guimenuitem
></menuchoice
> in der Menüleiste geändert werden.</para
></listitem>
<listitem
><para
>Der Schwierigkeitsgrad ändert sich umgehend.</para
></listitem>
<listitem
><para
>Sie können das Design von &bovo; mit <menuchoice
><guimenu
>Einstellungen</guimenu
> <guisubmenu
>Design</guisubmenu
></menuchoice
> in der Menüleiste wechseln. Das Design wird umgehend geändert.</para
></listitem>
<listitem
><para
>Animationen können auf Wunsch mit <menuchoice
><guimenu
>Einstellungen</guimenu
> <guimenuitem
>Animation</guimenuitem
></menuchoice
> in der Menüleiste an- oder ausgeschaltet werden.</para
></listitem>
<listitem
><para
>Wenn Sie bemerken, dass Sie einen sehr schlechten Zug getätigt haben, können Sie diesen über die Werkzeugleiste, die Menüleiste oder durch das Standard-Tastenkürzel <keycombo action="simul"
>&Ctrl;<keycap
>Z</keycap
></keycombo
> zurücknehmen.</para
><para
>Sie können bis zum Anfang des Spiels alle Spielzüge zurücknehmen.</para
></listitem>
<listitem
><para
>Falls Sie nicht wissen, welchen Zug Sie tätigen sollen, können Sie mit dem Knopf <guibutton
>Tipp</guibutton
> einen Tipp vom Computer-Spieler erhalten. Der von &bovo; vorgeschlagene Spielzug wird dann für kurze Zeit angezeigt.</para
></listitem>
<listitem
><para
>Wenn ein Spiel zu Ende ist, wird der Knopf <guibutton
>Vorführung</guibutton
> aktiviert, der das letzte Spiels wieder vorführt.</para
></listitem>
</itemizedlist>
</sect1>
</chapter>
<chapter id="interface"
><title
>Die Benutzeroberfläche</title
> <!-- do not change this! -->
<sect1 id="menu">
<title
>Menüeinträge</title>
<variablelist>
<varlistentry>
<term
><menuchoice
><shortcut
><keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
> </shortcut
> <guimenu
>Spiel</guimenu
> <guimenuitem
>Neu</guimenuitem
></menuchoice
></term>
<listitem
><para
>Startet ein neues Spiel.</para
></listitem>
</varlistentry>
<varlistentry>
<term>
<menuchoice
><guimenu
>Spiel</guimenu
> <guimenuitem
>Vorführung</guimenuitem
></menuchoice
></term>
<listitem
><para
>Das letzte Spiel vorführen.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
><keycombo action="simul"
>&Ctrl;<keycap
>Q</keycap
></keycombo
> </shortcut
> <guimenu
>Spiel</guimenu
> <guimenuitem
>Beenden</guimenuitem
></menuchoice
></term>
<listitem
><para
>Wählen Sie diesen Eintrag, wird das aktuelle Spiel und auch &bovo; beendet.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
> <keycombo action="simul"
>&Ctrl;<keycap
>Z</keycap
> </keycombo
> </shortcut
> <guimenu
>Zug</guimenu
> <guimenuitem
>Zurücknehmen</guimenuitem
> </menuchoice>
</term>
<listitem>
<para
><action
>Nimmt den zuletzt ausgeführten Zug wieder zurück.</action
></para>
</listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
> <keycap
>H</keycap
> </shortcut
> <guimenu
>Zug</guimenu
> <guimenuitem
>Tipp</guimenuitem
> </menuchoice
></term>
<listitem>
<para
>Einen Tipp für den nächsten Zug <action
>anzeigen</action
>. Der von &bovo; vorgeschlagene Spielzug wird dann für kurze Zeit angezeigt.</para>
</listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Einstellungen</guimenu
><guisubmenu
>Design</guisubmenu
></menuchoice
></term>
<listitem
><para
>Auswahl eines der Designs <guimenuitem
>Scribble</guimenuitem
>, <guimenuitem
>Hoher Kontrast</guimenuitem
>, <guimenuitem
>Spacy</guimenuitem
> oder <guimenuitem
>Gomoku</guimenuitem
> für das Spiel.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Einstellungen</guimenu
><guimenuitem
>Animation </guimenuitem
></menuchoice
></term>
<listitem
><para
>Schaltet die Animation ein oder aus.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Einstellungen</guimenu
><guisubmenu
>Schwierigkeitsgrad</guisubmenu
></menuchoice
></term>
<listitem
><para
>Auswahl von verschiedenen Schwierigkeitsstufen von <guimenuitem
>Lächerlich einfach</guimenuitem
> bis <guimenuitem
>Unmöglich</guimenuitem
> für das Spiel.</para
></listitem>
</varlistentry>
</variablelist>
<para
>Zusätzlich hat &bovo; die bekannten &kde;-Einträge im Menü <guimenu
>Einstellungen</guimenu
> und <guimenu
>Hilfe</guimenu
>, weitere Informationen dazu finden Sie in den Abschnitten über die Menüs <ulink url="help:/fundamentals/menus.html#menus-settings"
>Einstellungen</ulink
> und <ulink url="help:/fundamentals/menus.html#menus-help"
>Hilfe</ulink
> der &kde;-Grundlagen. </para>
</sect1>
</chapter>
<chapter id="faq"
><title
>Häufig gestellte Fragen</title
> <!-- do not change this! -->
<!--This chapter is for frequently asked questions. Please use <qandaset
> <qandaentry
> only!-->
<qandaset>
<!--Following is a standard list of FAQ questions.-->
<qandaentry>
<question
><para
>Kann ich das Erscheinungsbild des Spiels ändern? </para
></question>
<answer
><para
>Ja, um das Design für &bovo; zu ändern, wählen Sie <menuchoice
><guimenu
>Einstellungen</guimenu
><guisubmenu
>Design</guisubmenu
></menuchoice
> in der Menüleiste.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>Kann ich mit der Tastatur spielen? </para
></question>
<answer
><para
>Nein, &bovo; kann nicht mit der Tastatur gespielt werden.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>Ich muss das Spiel unterbrechen, kann ich den aktuellen Spielstand speichern?</para
></question>
<answer
><para
>Nein, in &bovo; können Sie den aktuellen Spielstand nicht speichern.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>Wo finde ich die Bestenliste?</para
></question>
<answer
><para
>In &bovo; gibt es keine Bestenliste.</para
></answer>
</qandaentry>
<!--Please add more Q&As if needed-->
</qandaset>
</chapter>
<chapter id="credits"
><title
>Danksagungen und Lizenz</title
> <!-- do not change this! -->
<!--This chapter is for credits and licenses.-->
<para
>&bovo; </para>
<para
>Programm Copyright 2002, 2007 &Aron.Bostrom; &Aron.Bostrom.mail; </para>
<para
>Dokumentation Copyright 2007 &Aron.Bostrom; &Aron.Bostrom.mail;</para>
<para
>Übersetzung Burkhard Lück<email
>lueck@hube-lueck.de</email
></para
> &underFDL; &underGPL; </chapter>
&documentation.index;
</book>
<!--
Local Variables:
mode: sgml
sgml-minimize-attributes:nil
sgml-general-insert-case:lower
sgml-omittag:t
sgml-shorttag:t
sgml-namecase-general:t
sgml-always-quote-attributes:t
sgml-indent-step:0
sgml-indent-data:nil
sgml-parent-document:nil
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
-->

158
po/el/bovo.po Normal file
View File

@ -0,0 +1,158 @@
# translation of bovo.po to greek
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Toussis Manolis <manolis@koppermind.homelinux.org>, 2007, 2009.
# Spiros Georgaras <sng@hellug.gr>, 2007.
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2009-04-23 21:47+0300\n"
"Last-Translator: Stelios <sstavra@gmail.com>\n"
"Language-Team: Greek <kde-i18n-el@kde.org>\n"
"Language: el\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Lokalize 2.0\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Τούσης Μανώλης"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "manolis@koppermind.homelinux.org"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Θέμα"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "Ταχύτητα της επίδειξης και της αναπαραγωγής ριπλέι."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "Αν θα υπάρχει εφέ των κινήσεων ή όχι."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "Μηχανή ΤΝ που θα χρησιμοποιηθεί."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "Επιτραπέζιο παιχνίδι 'πέντε στη σειρά' για το KDE"
#: gui/main.cc:52
#, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "(c) 2002-2007, Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Συγγραφέας"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Νίκες: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Ήττες: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "&Επανάληψη"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Επανάληψη παιχνιδιού"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "Επαναλαμβάνει το τελευταίο παιχνίδι για να το παρακολουθήσετε."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Κίνηση γραφικών"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Έναρξη ενός νέου παιχνιδιού"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "Τέλος παιχνιδιού. Ισοπαλία!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "Τέλος παιχνιδιού. Νίκησες!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "Τέλος παιχνιδιού. Έχασες!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "Είναι η σειρά σας."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "Αναμονή υπολογιστή."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "Επανάληψη παιχνιδιού"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "Το παιχνίδι επαναλήφθηκε."
#~ msgid "Difficulty level: strength of the computer player."
#~ msgstr "Επίπεδο δυσκολίας: δύναμη του παίκτη του υπολογιστή."
#~ msgid "You won!"
#~ msgstr "Νίκησες!"
#~ msgid "You lost!"
#~ msgstr "Έχασες!"

156
po/en_GB/bovo.po Normal file
View File

@ -0,0 +1,156 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Andrew Coles <andrew_coles@yahoo.co.uk>, 2009, 2015.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2015-01-31 15:34+0000\n"
"Last-Translator: \n"
"Language-Team: British English <kde-l10n-en_gb@kde.org>\n"
"Language: en_GB\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Lokalize 1.5\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Andrew Coles"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "andrew_coles@yahoo.co.uk"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Theme"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "Speed of demo and replay playback."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "Whether moves should be animated or not."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "AI engine to use."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "KDE Five in a Row Board Game"
#: gui/main.cc:52
#, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "(c) 2002-2007, Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Author"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Wins: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Losses: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "&Replay"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Replay game"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "Replays your last game for you to watch."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Animation"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Start a new Game to play"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "GAME OVER. Tie!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "GAME OVER. You won!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "GAME OVER. You lost!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "It is your turn."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "Waiting for computer."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "Replaying game"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "Game replayed."
#~ msgid "Difficulty level: strength of the computer player."
#~ msgstr "Difficulty level: strength of the computer player."
#~ msgid "You won!"
#~ msgstr "You won!"
#~ msgid "You lost!"
#~ msgstr "You lost!"

156
po/eo/bovo.po Normal file
View File

@ -0,0 +1,156 @@
# translation of bovo.po to esperanto
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
# Pierre-Marie Pédrot <pedrotpmx@wanadoo.fr>, 2007.
#
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2007-12-08 12:49+0100\n"
"Last-Translator: Pierre-Marie Pédrot <pedrotpmx@wanadoo.fr>\n"
"Language-Team: esperanto <kde-i18n-eo@kde.org>\n"
"Language: eo\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Pierre-Marie Pédrot"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "pedrotpmx@wanadoo.fr"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Etoso"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr ""
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr ""
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr ""
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "KDE gobanga ludo"
#: gui/main.cc:52
#, fuzzy, kde-format
#| msgid "(c) 2002,2007 Aron Boström"
msgid "(c) 2002-2007, Aron Boström"
msgstr "(c) 2002,2007 Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Aŭtoro"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Gajnoj: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Perdoj: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "&Reludi"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Refari la ludon"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "Refaras vian lastan ludon por ke vi povas vidi ĝin."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Animacio"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Komenci no"
#: gui/mainwindow.cc:382
#, fuzzy, kde-format
#| msgid "GAME OVER. You won!"
msgid "GAME OVER. Tie!"
msgstr "Fino de ludo. Vi gajnis!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "Fino de ludo. Vi gajnis!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "Fino de ludo. Vi perdis!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "Estas via vico."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "Atendante la komputilon."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "Refarante la ludon"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "Ludo refariĝis."
#~ msgid "You won!"
#~ msgstr "Vi gajnis!"
#~ msgid "You lost!"
#~ msgstr "Vi perdis!"

152
po/es/bovo.po Normal file
View File

@ -0,0 +1,152 @@
# translation of bovo.po to Spanish
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Santiago Fernández Sancho <santi@kde-es.org>, 2007.
# Eloy Cuadra <ecuadra@eloihr.net>, 2009, 2015, 2021.
# Huever, 2009.
# Kira J. Fernandez <kirajfdez@gmail.com>, 2010.
# Sofía Priego <spriego@darksylvania.net>, %Y.
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2021-10-17 12:18+0100\n"
"Last-Translator: Sofía Priego <spriego@darksylvania.net>\n"
"Language-Team: Spanish <kde-l10n-es@kde.org>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 21.08.2\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Sofía Priego,Santiago Fernández Sancho,Kira J. Fernández"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "spriego@darksylvania.net,santi@kde-es.org,kirajfdez@gmail.com"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Tema"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "Velocidad de la demostración y de la repetición del juego."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "Indica si se deben animar los movimientos o no."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "Motor de inteligencia artificial a usar."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "Juego de mesa de cinco en línea para KDE"
#: gui/main.cc:52
#, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "© 2002-2007, Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Autor"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Gana: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Pierde: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "&Repetir"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Reproducir partida"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "Reproduce la última partida para que pueda verla."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Animación"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Iniciar una partida nueva"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "PARTIDA TERMINADA. ¡Empate!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "PARTIDA TERMINADA. ¡Ha ganado!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "PARTIDA TERMINADA. ¡Ha perdido!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "Es su turno."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "Esperando a la máquina."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "Repitiendo partida"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "Partida repetida."

View File

@ -0,0 +1,642 @@
<?xml version="1.0" ?>
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
<!ENTITY % Spanish "INCLUDE"
> <!-- change language only here -->
<!ENTITY % addindex "IGNORE"
> <!-- do not change this! -->
]>
<book id="bovo" lang="&language;"
> <!-- do not change this! -->
<bookinfo>
<title
>Manual de &bovo;</title>
<authorgroup>
<author
><firstname
>Aron</firstname
><surname
>Bostrom</surname
> <affiliation
><address
>&Aron.Bostrom.mail;</address
></affiliation>
</author>
<author
><firstname
>Eugene</firstname
><surname
>Trounev</surname
> <affiliation
><address
><email
>eugene.trounev@gmail.com</email
></address
></affiliation>
</author>
<othercredit role="translator"
><firstname
>Rocío</firstname
><surname
>Gallego</surname
><affiliation
><address
><email
>traducciones@rociogallego.com</email
></address
></affiliation
><contrib
>Traducción</contrib
></othercredit
><othercredit role="translator"
><firstname
>Santiago</firstname
><surname
>Fernández Sancho</surname
><affiliation
><address
><email
>santi@kde-es.org</email
></address
></affiliation
><contrib
>Traductor</contrib
></othercredit
><othercredit role="translator"
><firstname
>Kira</firstname
><surname
>J. Fernández</surname
><affiliation
><address
><email
>kirajfdez@gmail.com</email
></address
></affiliation
><contrib
>Traductora</contrib
></othercredit
>
</authorgroup>
<copyright>
<year
>2007</year>
<holder
>Aron Bostrom</holder>
</copyright>
<legalnotice
>&FDLNotice;</legalnotice>
<date
>2021-06-21</date>
<releaseinfo
>KDE Gear 21.04</releaseinfo>
<abstract>
<para
>Esta documentación describe el juego &bovo; versión 1.1</para>
</abstract>
<!--List of relevan keywords-->
<keywordset>
<keyword
>KDE</keyword
> <!-- do not change this! -->
<keyword
>kdegames</keyword
> <!-- do not change this! -->
<keyword
>juego</keyword
> <!-- do not change this! -->
<keyword
>bovo</keyword
><!--Application name goes here-->
<!-- Game genre. Use as many as necessary. Available game types are: Arcade, Board, Card, Dice, Toys, Logic, Strategy.-->
<keyword
>arcade</keyword>
<keyword
>tablero</keyword>
<keyword
>ceros y cruces</keyword>
<!--Number of possible players. It can be: One, Two,..., Multiplayer-->
<keyword
>dos jugadores</keyword>
<!--All other relevant keywords-->
<keyword
>ceros</keyword>
<keyword
>cruces</keyword>
<keyword
>Gomoku</keyword>
<keyword
>Cinco en línea</keyword>
<keyword
>Conecta5</keyword>
<keyword
>Juego de tablero</keyword>
<keyword
>X y O</keyword>
<keyword
>Cinco en línea</keyword>
<keyword
>Rompecabezas</keyword>
</keywordset>
</bookinfo>
<!--Content begins here: -->
<chapter id="introduction"
><title
>Introducción</title
> <!-- do not change this! -->
<note
><title
>Tipo de juego:</title
><para
>Tablero, Arcade</para
></note
><!-- Game genre. Use as many as necessary. Available game types are: Arcade, Board, Card, Dice, Toys, Logic, Strategy.-->
<note
><title
>Número de posibles jugadores:</title
><para
>Dos</para
></note
><!--Number of possible players. It can be: One, Two,..., Multiplayer-->
<!--Short game description starts here. 3-4 sentences (paragraphs)-->
<para
>&bovo; es un Gomoku (del japonés <foreignphrase lang="ja"
>五目並べ</foreignphrase
>, literalmente «cinco puntos») como el juego para dos jugadores, en el que los oponentes se alternan para situar sus respectivos pictogramas en el tablero de juego. El propósito de este juego es conectar cinco de sus piezas en una línea continua vertical, horizontal o diagonal. </para>
<note
><title
>Nota:</title
><para
>También se conoce como: Conecta cinco, Cinco en línea, X y O, Ceros y cruces</para
></note>
</chapter>
<chapter id="howto"
><title
>Cómo jugar</title
> <!-- do not change this! -->
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="mainscreen.png" format="PNG"/>
</imageobject>
<textobject>
<phrase
>Ventana principal de &bovo;</phrase>
</textobject>
</mediaobject>
</screenshot>
<!--IMPORTANT: If the game has no defined objective, please remove the below line.-->
<note
><title
>Objetivo:</title
><para
>Conectar cinco de sus piezas en una línea continua vertical, horizontal o diagonal.</para
></note>
<para
>La primera vez que se inicia &bovo; se inicia en modo de demostración, donde dos jugadores de IA se baten el uno contra el otro. Siempre puede iniciar una nueva partida usando el botón <guibutton
>Nuevo</guibutton
> de la barra de herramientas, la entrada de menú <menuchoice
><guimenu
>Juego</guimenu
><guimenuitem
>Nuevo</guimenuitem
></menuchoice
> en la barra de menús o usando el acceso rápido predeterminado <keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
>. </para>
<note
><title
>Nota:</title
><para
>Puesto que el primer jugador siempre tiene ventaja sobre el segundo, &bovo; alternará los jugadores, cambiándolos en cada nueva partida. </para
></note>
<para
>Si es el primer jugador - inicie el juego colocando su pictograma en cualquier punto del tablero de juego. Si es el segundo jugador espere hasta que el primer jugador haya colocado el pictograma y a continuación haga lo mismo. Puede colocar su marca en cualquier cuadrado del campo, a menos que ya esté ocupado por otra pieza del juego (no importa si es un pictograma suyo o de su oponente). </para>
<para
>Debe colocar sus piezas de forma que evite que su oponente conecte cinco marcas en una línea continua vertical, horizontal o diagonal. Al mismo tiempo, debe conectar cinco de sus propias piezas en una línea continua vertical, horizontal o diagonal. El que consiga hacerlo primero, gana la partida. </para>
</chapter>
<chapter id="rules_and_tips"
><title
>Reglas del juego, estrategias y consejos</title
> <!-- do not change this! -->
<!--This section has to do with game rules. Please give a detailed description of those using lists or paragraphs.-->
<sect1 id="rules">
<title
>Reglas del juego</title>
<itemizedlist>
<listitem
><para
>Los jugadores se turnarán para colocar sus respectivas marcas en el tablero de juego.</para
></listitem>
<listitem
><para
>Un jugador no puede mover una marca que ya esté colocada o colocar su marca sobre otra ya existente.</para
></listitem>
<listitem
><para
>Los jugadores no pueden penalizar sus turnos.</para
></listitem>
<listitem
><para
>El jugador que primero consiga cinco marcas conectadas en una línea recta (puede ser vertical, horizontal o diagonal) gana el juego.</para
></listitem>
</itemizedlist>
</sect1>
<sect1 id="tips">
<title
>Consejos del juego</title>
<itemizedlist>
<listitem
><para
>Cuando &bovo; se inicia por primera vez, necesita redimensionarse. Redimensione la ventana de juego al tamaño deseado, y &bovo; escalará el tablero de juego.</para
></listitem>
<listitem
><para
>La primera vez que se inicia &bovo; lo hace en modo demostración, donde dos jugadores de IA se baten uno contra otro.</para
></listitem>
<listitem
><para
>Si se sale de &bovo; antes de finalizar la partida, el juego activo se guarda automáticamente. Si &bovo; detecta un juego guardado de forma automática al inicio, lo restaura. Si no, &bovo; inicia el modo de demostración.</para
></listitem>
<listitem
><para
>Siempre puede iniciar una partida nueva con el botón <guibutton
>Nuevo</guibutton
> de la barra de herramientas, la entrada de menú <menuchoice
><guimenu
>Juego</guimenu
><guimenuitem
>Nuevo</guimenuitem
></menuchoice
> de la barra de menú o con el acceso rápido predeterminado <keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
>.</para
></listitem>
<listitem
><para
>Si se inicia una partida nueva cuando exista una partida activa, esta se cuenta como perdida.</para
></listitem>
<listitem
><para
>Se puede cambiar la dificultad con el desplegable <guilabel
>Dificultad</guilabel
> en el extremo derecho de la barra de estado, o usando la opción del menú <menuchoice
><guimenu
>Preferencias</guimenu
><guimenuitem
>Dificultad</guimenuitem
></menuchoice
>.</para
></listitem>
<listitem
><para
>El cambio en la dificultad tendrá efecto inmediatamente.</para
></listitem>
<listitem
><para
>Puede cambiar el tema de &bovo; usando la opción del menú <menuchoice
> <guimenu
>Preferencias</guimenu
> <guisubmenu
>Tema</guisubmenu
></menuchoice
>. El tema se cambiará inmediatamente.</para
></listitem>
<listitem
><para
>Se puede activar y desactivar la animación a voluntad usando la opción del menú <menuchoice
><guimenu
>Preferencias</guimenu
> <guimenuitem
>Animación</guimenuitem
></menuchoice
>.</para
></listitem>
<listitem
><para
>Si se da cuenta de que ha realizado un mal movimiento, tiene la posibilidad de deshacerlo usando la barra de herramientas, la barra de menú o el acceso rápido de teclado predeterminado para «deshacer» <keycombo action="simul"
> &Ctrl;<keycap
>Z</keycap
></keycombo
>.</para
><para
>Puede continuar deshaciendo movimientos hasta que alcance el inicio de la partida.</para
></listitem>
<listitem
><para
>Si no sabe qué movimiento hacer, puede pedir una pista a la máquina con el botón <guibutton
>Pista</guibutton
>. El movimiento sugerido por la IA de &bovo; parpadeará durante un breve periodo de tiempo.</para
></listitem>
<listitem
><para
>Al finalizar la partida, se activará el botón <guibutton
>Reproducir</guibutton
>, que comienza a reproducir la última partida.</para
></listitem>
</itemizedlist>
</sect1>
</chapter>
<chapter id="interface"
><title
>Vista general de la interfaz</title
> <!-- do not change this! -->
<sect1 id="menu">
<title
>Opciones de menú</title>
<variablelist>
<varlistentry>
<term
><menuchoice
><shortcut
><keycombo action="simul"
>&Ctrl;<keycap
>N</keycap
></keycombo
> </shortcut
> <guimenu
>Juego</guimenu
> <guimenuitem
>Nuevo</guimenuitem
></menuchoice
></term>
<listitem
><para
>Inicia una partida nueva.</para
></listitem>
</varlistentry>
<varlistentry>
<term>
<menuchoice
><guimenu
>Juego</guimenu
> <guimenuitem
>Reproducir</guimenuitem
></menuchoice
></term>
<listitem
><para
>Reproduce la última partida.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
><keycombo action="simul"
>&Ctrl;<keycap
>Q</keycap
></keycombo
> </shortcut
> <guimenu
>Juego</guimenu
> <guimenuitem
>Salir</guimenuitem
></menuchoice
></term>
<listitem
><para
>Seleccionando este elemento finalizará su partida actual y saldrá de &bovo;.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
> <keycombo action="simul"
>&Ctrl;<keycap
>Z</keycap
> </keycombo
> </shortcut
> <guimenu
>Mover</guimenu
> <guimenuitem
>Deshacer</guimenuitem
> </menuchoice>
</term>
<listitem>
<para
><action
>Deshace el último movimiento.</action
></para>
</listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><shortcut
> <keycap
>H</keycap
> </shortcut
> <guimenu
>Mover</guimenu
> <guimenuitem
>Pista</guimenuitem
> </menuchoice
></term>
<listitem>
<para
><action
>Mostrar</action
> proporciona una pista para el siguiente movimiento. La pieza sugerida por la IA de &bovo; parpadea por un breve periodo de tiempo.</para>
</listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Preferencias</guimenu
><guisubmenu
>Tema</guisubmenu
></menuchoice
></term>
<listitem
><para
>Elige uno de los temas <guimenuitem
>Garabatos</guimenuitem
>, <guimenuitem
>Alto contraste</guimenuitem
>, <guimenuitem
>Espacio</guimenuitem
> o <guimenuitem
>Gomoku</guimenuitem
> para el juego.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Preferencias</guimenu
><guimenuitem
>Animación</guimenuitem
></menuchoice
></term>
<listitem
><para
>Activa o desactiva la animación.</para
></listitem>
</varlistentry>
<varlistentry>
<term
><menuchoice
><guimenu
>Preferencias</guimenu
><guisubmenu
>Dificultad</guisubmenu
></menuchoice
></term>
<listitem
><para
>Permite seleccionar entre varios niveles de dificultad del juego, desde <guimenuitem
>Ridículamente fácil</guimenuitem
> hasta <guimenuitem
>Imposible</guimenuitem
>.</para
></listitem>
</varlistentry>
</variablelist>
<para
>Además &bovo; tiene las opciones de menú <guimenu
>Preferencias</guimenu
> y <guimenu
>Ayuda</guimenu
> comunes de &kde;. Para obtener más información, consulte las secciones sobre el <ulink url="help:/fundamentals/menus.html#menus-settings"
>Menú «Preferencias»</ulink
> y <ulink url="help:/fundamentals/menus.html#menus-help"
>Menú «Ayuda» </ulink
> de «Aspectos básicos de &kde;». </para>
</sect1>
</chapter>
<chapter id="faq"
><title
>Preguntas frecuentes</title
> <!-- do not change this! -->
<!--This chapter is for frequently asked questions. Please use <qandaset
> <qandaentry
> only!-->
<qandaset>
<!--Following is a standard list of FAQ questions.-->
<qandaentry>
<question
><para
>Quiero cambiar el aspecto del juego. ¿Puedo? </para
></question>
<answer
><para
>Sí. Para cambiar el tema visual de &bovo; puede usar la opción del menú <menuchoice
><guimenu
>Preferencias</guimenu
><guisubmenu
>Tema</guisubmenu
> </menuchoice
>.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>¿Puedo usar el teclado para jugar a este juego? </para
></question>
<answer
><para
>No. Las partidas de &bovo; no se pueden jugar usando el teclado.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>Tengo que salir de la partida ahora, pero todavía no he terminado. ¿Puedo guardar mi progreso?</para
></question>
<answer
><para
>No. No existe la función «Guardar» en &bovo;, aunque &bovo; restaura la última partida no finalizada cuando se inicia.</para
></answer>
</qandaentry>
<qandaentry>
<question
><para
>¿Dónde están las mejores puntuaciones?</para
></question>
<answer
><para
>&bovo; no tiene esta funcionalidad.</para
></answer>
</qandaentry>
<!--Please add more Q&As if needed-->
</qandaset>
</chapter>
<chapter id="credits"
><title
>Créditos y licencia</title
> <!-- do not change this! -->
<!--This chapter is for credits and licenses.-->
<para
>&bovo; </para>
<para
>Copyright del programa 2002, 2007 &Aron.Bostrom; &Aron.Bostrom.mail; </para>
<para
>Copyright de la documentación 2007 &Aron.Bostrom; &Aron.Bostrom.mail;</para>
<para
>Traducido por Rocío Gallego <email
>traducciones@rociogallego.com</email
>, Santiago Fernández Sancho <email
>santi@kde-es.org</email
> y Kira J. Fernández <email
>kirajfdez@gmail.com</email
>.</para
> &underFDL; &underGPL; </chapter>
&documentation.index;
</book>
<!--
Local Variables:
mode: sgml
sgml-minimize-attributes:nil
sgml-general-insert-case:lower
sgml-omittag:t
sgml-shorttag:t
sgml-namecase-general:t
sgml-always-quote-attributes:t
sgml-indent-step:0
sgml-indent-data:nil
sgml-parent-document:nil
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
-->

157
po/et/bovo.po Normal file
View File

@ -0,0 +1,157 @@
# translation of bovo.po to Estonian
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Marek Laane <bald@smail.ee>, 2007, 2009, 2016.
msgid ""
msgstr ""
"Project-Id-Version: bovo\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2021-12-29 00:45+0000\n"
"PO-Revision-Date: 2016-01-13 14:19+0200\n"
"Last-Translator: Marek Laane <qiilaq69@gmail.com>\n"
"Language-Team: Estonian <kde-et@linux.ee>\n"
"Language: et\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 1.5\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Marek Laane"
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "bald@smail.ee"
#. i18n: ectx: label, entry (theme), group (bovo)
#: gui/bovo.kcfg:9 gui/mainwindow.cc:204
#, kde-format
msgid "Theme"
msgstr "Teema"
#. i18n: ectx: label, entry (playbackSpeed), group (bovo)
#: gui/bovo.kcfg:13
#, kde-format
msgid "Speed of demo and replay playback."
msgstr "Demo ja korduse kiirus."
#. i18n: ectx: label, entry (animation), group (bovo)
#: gui/bovo.kcfg:19
#, kde-format
msgid "Whether moves should be animated or not."
msgstr "Kas liikumine animeerida või mitte."
#. i18n: ectx: label, entry (ai), group (bovo)
#: gui/bovo.kcfg:23
#, kde-format
msgid "AI engine to use."
msgstr "Kasutatav AI mootor."
#: gui/main.cc:50
#, kde-format
msgid "Bovo"
msgstr "Bovo"
#: gui/main.cc:51
#, kde-format
msgid "KDE Five in a Row Board Game"
msgstr "KDE viis ritta lauamäng"
#: gui/main.cc:52
#, kde-format
msgid "(c) 2002-2007, Aron Boström"
msgstr "(c) 2002-2007: Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Aron Boström"
msgstr "Aron Boström"
#: gui/main.cc:53
#, kde-format
msgid "Author"
msgstr "Autor"
#: gui/mainwindow.cc:67 gui/mainwindow.cc:364
#, kde-format
msgid "Wins: %1"
msgstr "Võidud: %1"
#: gui/mainwindow.cc:68 gui/mainwindow.cc:258 gui/mainwindow.cc:377
#, kde-format
msgid "Losses: %1"
msgstr "Kaotused: %1"
#: gui/mainwindow.cc:190
#, kde-format
msgid "&Replay"
msgstr "&Mängi uuesti"
#: gui/mainwindow.cc:192
#, kde-format
msgid "Replay game"
msgstr "Mängi uuesti"
#: gui/mainwindow.cc:193
#, kde-format
msgid "Replays your last game for you to watch."
msgstr "Mängib uuesti läbi sinu viimase mängu."
#: gui/mainwindow.cc:199
#, kde-format
msgid "&Animation"
msgstr "&Animatsioon"
#: gui/mainwindow.cc:344
#, kde-format
msgid "Start a new Game to play"
msgstr "Mängimiseks käivita uus mäng"
#: gui/mainwindow.cc:382
#, kde-format
msgid "GAME OVER. Tie!"
msgstr "MÄNG ON LÄBI. Viik!"
#: gui/mainwindow.cc:385
#, kde-format
msgid "GAME OVER. You won!"
msgstr "MÄNG ON LÄBI. Sina võitsid!"
#: gui/mainwindow.cc:388
#, kde-format
msgid "GAME OVER. You lost!"
msgstr "MÄNG ON LÄBI. Sa kaotasid!"
#: gui/mainwindow.cc:400
#, kde-format
msgid "It is your turn."
msgstr "Sinu kord on käia."
#: gui/mainwindow.cc:404
#, kde-format
msgid "Waiting for computer."
msgstr "Arvuti ootamine."
#: gui/mainwindow.cc:432
#, kde-format
msgid "Replaying game"
msgstr "Taasmängimine"
#: gui/mainwindow.cc:448
#, kde-format
msgid "Game replayed."
msgstr "Mäng on uuesti läbi mängitud."
#~ msgid "Difficulty level: strength of the computer player."
#~ msgstr "Raskusaste: arvutimängija tase."
#~ msgid "You won!"
#~ msgstr "Sina võitsid!"
#~ msgid "You lost!"
#~ msgstr "Sa kaotasid!"

Some files were not shown because too many files have changed in this diff Show More