Import Upstream version 22.08.3
|
@ -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*
|
|
@ -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
|
|
@ -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']
|
|
@ -0,0 +1,6 @@
|
|||
Orignal Author:
|
||||
Aron Boström <aron.bostrom@gmail.com> (irc: hrafnahnef @ freenode)
|
||||
|
||||
Maintainer:
|
||||
Pelladi Gabor <pelladigabor@gmail.com>
|
||||
|
|
@ -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)
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
# SPDX-FileCopyrightText: 2021 Laurent Montel <montel@kde.org>
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
EXTENDED
|
|
@ -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!
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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
|
|
@ -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(¤tHash, ¤tHashData);
|
||||
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(¤tHash, ¤tHashData);
|
||||
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};
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
<RCC>
|
||||
<qresource prefix="/kxmlgui5/bovo">
|
||||
<file alias="bovoui.rc">gui/bovoui.rc</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -0,0 +1,2 @@
|
|||
kdoctools_create_handbook(index.docbook INSTALL_DESTINATION ${KDE_INSTALL_DOCBUNDLEDIR}/en SUBDIR bovo)
|
||||
|
|
@ -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 it’s already occupied by another game piece (regardless of whether it’s your pictogram or that of your opponent’s).
|
||||
</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:
|
||||
-->
|
After Width: | Height: | Size: 17 KiB |
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
add_executable (testbovo test.cpp)
|
||||
target_link_library (testbovo game)
|
||||
install (TARGETS testbovo ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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
|
|
@ -0,0 +1,6 @@
|
|||
# Code generation options for kconfig_compiler
|
||||
File=bovo.kcfg
|
||||
ClassName=Settings
|
||||
NameSpace=gui
|
||||
Singleton=true
|
||||
Mutators=true
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 990 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.4 KiB |
|
@ -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
|
||||
)
|
|
@ -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 iks‑oksa.</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 iks‑oksa.</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&product=bovo</url>
|
||||
<url type="help">https://docs.kde.org/?application=bovo</url>
|
||||
<url type="donation">https://www.kde.org/community/donations/?app=bovo&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>
|
|
@ -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]=五子棋棋盤遊戲
|
|
@ -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 "أنت!"
|
|
@ -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 "Звычайны"
|
|
@ -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 "Играта беше повторена."
|
|
@ -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."
|
|
@ -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."
|
|
@ -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 &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 &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:
|
||||
-->
|
After Width: | Height: | Size: 17 KiB |
|
@ -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."
|
|
@ -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."
|
|
@ -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:
|
||||
-->
|
|
@ -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!"
|
|
@ -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!"
|
|
@ -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:
|
||||
-->
|
|
@ -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 "Έχασες!"
|
|
@ -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!"
|
|
@ -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!"
|
|
@ -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."
|
|
@ -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:
|
||||
-->
|
|
@ -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!"
|