add pgn-extract 22.11
This commit is contained in:
8
add-timectl.bash
Executable file
8
add-timectl.bash
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
str='[TimeControl "3600"]'
|
||||
str='[TimeControl "40/7200:20/3600:3600"]'
|
||||
filein="$1"
|
||||
fileout="$filein.new"
|
||||
echo "in=$filein out=$fileout"
|
||||
sed -e '/^\[Black ".*"\]/a '"$str" < "$filein" > "$fileout"
|
674
pgn-extract/COPYING
Normal file
674
pgn-extract/COPYING
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. 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
|
||||
them 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 prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. 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.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey 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;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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 that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
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.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
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.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
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
|
||||
state 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) <year> <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program 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, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU 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 Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
135
pgn-extract/Makefile
Normal file
135
pgn-extract/Makefile
Normal file
@@ -0,0 +1,135 @@
|
||||
# Make file for the pgn-extract program.
|
||||
#
|
||||
# This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
# Copyright (C) 1994-2022 David J. Barnes
|
||||
#
|
||||
# pgn-extract 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
# https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
|
||||
OBJS=grammar.o lex.o map.o decode.o moves.o lists.o apply.o output.o eco.o \
|
||||
lines.o end.o main.o hashing.o argsfile.o mymalloc.o fenmatcher.o \
|
||||
taglines.o zobrist.o
|
||||
DEBUGINFO=-g
|
||||
|
||||
# These flags are particularly severe on checking warnings.
|
||||
# It may be that they are not all appropriate to your environment.
|
||||
# For instance, not all environments have prototypes available for
|
||||
# the standard library functions.
|
||||
|
||||
# Linux users might need to add -D__linux__ to these in order to
|
||||
# use strcasecmp instead of strcmpi (cf output.c)
|
||||
|
||||
# Mac OS X users might need to add -D__unix__ to CFLAGS
|
||||
# and use CC=cc or CC=gcc
|
||||
|
||||
OPTIMISE=-O3
|
||||
|
||||
CFLAGS+=-c -pedantic -Wall -Wshadow -Wformat -Wpointer-arith \
|
||||
-Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings \
|
||||
-Wsign-compare -Wimplicit-function-declaration $(DEBUGINFO) \
|
||||
-I/usr/local/lib/ansi-include -std=c99 \
|
||||
$(CPPFLAGS) \
|
||||
$(OPTIMISE)
|
||||
|
||||
CC=gcc
|
||||
LIBS=-lm
|
||||
|
||||
# AIX 3.2 Users might like to use these alternatives for CFLAGS and CC.
|
||||
# Thanks to Erol Basturk for providing them.
|
||||
AIX_CFLAGS=-c -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_ALL_SOURCE
|
||||
AIX_CC=xlc
|
||||
|
||||
pgn-extract : $(OBJS)
|
||||
$(CC) $(DEBUGINFO) $(ORIGCFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o pgn-extract
|
||||
|
||||
purify : $(OBJS)
|
||||
purify $(CC) $(DEBUGINFO) $(OBJS) -o pgn-extract
|
||||
|
||||
clean:
|
||||
rm -f core pgn-extract *.o
|
||||
|
||||
mymalloc.o : mymalloc.c mymalloc.h
|
||||
$(CC) $(CFLAGS) mymalloc.c
|
||||
|
||||
apply.o : apply.c defs.h lex.h grammar.h typedef.h map.h bool.h apply.h taglist.h\
|
||||
eco.h decode.h moves.h hashing.h mymalloc.h output.h fenmatcher.h\
|
||||
zobrist.h
|
||||
$(CC) $(CFLAGS) apply.c
|
||||
|
||||
argsfile.o : argsfile.c argsfile.h bool.h defs.h typedef.h lines.h \
|
||||
taglist.h tokens.h lex.h taglines.h moves.h eco.h apply.h output.h \
|
||||
lists.h mymalloc.h fenmatcher.h
|
||||
$(CC) $(CFLAGS) argsfile.c
|
||||
|
||||
decode.o : decode.c defs.h typedef.h taglist.h lex.h bool.h decode.h lists.h \
|
||||
tokens.h mymalloc.h
|
||||
$(CC) $(CFLAGS) decode.c
|
||||
|
||||
eco.o : eco.c defs.h lex.h typedef.h map.h bool.h eco.h taglist.h apply.h \
|
||||
mymalloc.h
|
||||
$(CC) $(CFLAGS) eco.c
|
||||
|
||||
end.o : end.c end.h bool.h defs.h typedef.h lines.h tokens.h lex.h mymalloc.h \
|
||||
apply.h grammar.h
|
||||
$(CC) $(CFLAGS) end.c
|
||||
|
||||
grammar.o : grammar.c bool.h defs.h typedef.h lex.h taglist.h map.h lists.h\
|
||||
moves.h apply.h output.h tokens.h eco.h end.h grammar.h hashing.h \
|
||||
mymalloc.h
|
||||
$(CC) $(CFLAGS) grammar.c
|
||||
|
||||
hashing.o : hashing.c hashing.h bool.h defs.h typedef.h tokens.h\
|
||||
taglist.h lex.h mymalloc.h zobrist.h
|
||||
$(CC) $(CFLAGS) hashing.c
|
||||
|
||||
lex.o : lex.c bool.h defs.h typedef.h tokens.h taglist.h map.h\
|
||||
lists.h decode.h moves.h lines.h grammar.h mymalloc.h apply.h\
|
||||
output.h
|
||||
$(CC) $(CFLAGS) lex.c
|
||||
|
||||
lines.o : lines.c bool.h lines.h mymalloc.h
|
||||
$(CC) $(CFLAGS) lines.c
|
||||
|
||||
lists.o : lists.c lists.h taglist.h bool.h defs.h typedef.h mymalloc.h moves.h
|
||||
$(CC) $(CFLAGS) lists.c
|
||||
|
||||
main.o : main.c bool.h defs.h typedef.h tokens.h taglist.h lex.h moves.h\
|
||||
map.h lists.h output.h end.h grammar.h hashing.h \
|
||||
argsfile.h mymalloc.h
|
||||
$(CC) $(CFLAGS) main.c
|
||||
|
||||
map.o : map.c defs.h lex.h typedef.h map.h bool.h decode.h taglist.h \
|
||||
mymalloc.h
|
||||
$(CC) $(CFLAGS) map.c
|
||||
|
||||
moves.o : moves.c defs.h typedef.h lex.h bool.h map.h lists.h moves.h apply.h\
|
||||
lines.h taglist.h mymalloc.h fenmatcher.h
|
||||
$(CC) $(CFLAGS) moves.c
|
||||
|
||||
fenmatcher.o : fenmatcher.c grammar.h apply.h bool.h defs.h fenmatcher.h mymalloc.h\
|
||||
typedef.h end.h
|
||||
$(CC) $(CFLAGS) fenmatcher.c
|
||||
|
||||
output.o : output.c output.h taglist.h bool.h typedef.h defs.h lex.h grammar.h\
|
||||
apply.h mymalloc.h
|
||||
$(CC) $(CFLAGS) output.c
|
||||
|
||||
taglines.o : taglines.c bool.h defs.h typedef.h tokens.h taglist.h lex.h lines.h \
|
||||
lists.h moves.h output.h taglines.h
|
||||
$(CC) $(CFLAGS) taglines.c
|
||||
|
||||
zobrist.o : zobrist.c zobrist.h bool.h defs.h typedef.h apply.h decode.h grammar.h
|
||||
$(CC) $(CFLAGS) zobrist.c
|
140
pgn-extract/Makefile-windows
Normal file
140
pgn-extract/Makefile-windows
Normal file
@@ -0,0 +1,140 @@
|
||||
# Make file for the pgn-extract program.
|
||||
#
|
||||
# This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
# Copyright (C) 1994-2022 David J. Barnes
|
||||
#
|
||||
# pgn-extract 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
# https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
|
||||
OBJS=grammar.o lex.o map.o decode.o moves.o lists.o apply.o output.o eco.o \
|
||||
lines.o end.o main.o hashing.o argsfile.o mymalloc.o fenmatcher.o \
|
||||
taglines.o zobrist.o
|
||||
DEBUGINFO=-g
|
||||
|
||||
# These flags are particularly severe on checking warnings.
|
||||
# It may be that they are not all appropriate to your environment.
|
||||
# For instance, not all environments have prototypes available for
|
||||
# the standard library functions.
|
||||
|
||||
# Linux users might need to add -D__linux__ to these in order to
|
||||
# use strcasecmp instead of strcmpi (cf output.c)
|
||||
|
||||
# Mac OS X users might need to add -D__unix__ to CFLAGS
|
||||
# and use CC=cc or CC=gcc
|
||||
|
||||
OPTIMISE=-O3
|
||||
|
||||
CFLAGS+=-c -pedantic -Wall -Wshadow -Wformat -Wpointer-arith \
|
||||
-Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings \
|
||||
-Wsign-compare -Wimplicit-function-declaration $(DEBUGINFO) \
|
||||
-I/usr/local/lib/ansi-include -std=c99 \
|
||||
$(CPPFLAGS) \
|
||||
$(OPTIMISE)
|
||||
|
||||
CC=gcc
|
||||
# Libraries required for a static link of regex.
|
||||
LIBS=-lm /mingw64/lib/libregex.a \
|
||||
/mingw64/lib/libtre.a\
|
||||
/mingw64/lib/libintl.a \
|
||||
/mingw64/lib/libiconv.a
|
||||
LDFLAGS=
|
||||
|
||||
# AIX 3.2 Users might like to use these alternatives for CFLAGS and CC.
|
||||
# Thanks to Erol Basturk for providing them.
|
||||
AIX_CFLAGS=-c -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_ALL_SOURCE
|
||||
AIX_CC=xlc
|
||||
|
||||
pgn-extract : $(OBJS)
|
||||
$(CC) $(DEBUGINFO) $(ORIGCFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o pgn-extract
|
||||
|
||||
purify : $(OBJS)
|
||||
purify $(CC) $(DEBUGINFO) $(OBJS) -o pgn-extract
|
||||
|
||||
clean:
|
||||
rm -f core pgn-extract *.o
|
||||
|
||||
mymalloc.o : mymalloc.c mymalloc.h
|
||||
$(CC) $(CFLAGS) mymalloc.c
|
||||
|
||||
apply.o : apply.c defs.h lex.h grammar.h typedef.h map.h bool.h apply.h taglist.h\
|
||||
eco.h decode.h moves.h hashing.h mymalloc.h output.h fenmatcher.h\
|
||||
zobrist.h
|
||||
$(CC) $(CFLAGS) apply.c
|
||||
|
||||
argsfile.o : argsfile.c argsfile.h bool.h defs.h typedef.h lines.h \
|
||||
taglist.h tokens.h lex.h taglines.h moves.h eco.h apply.h output.h \
|
||||
lists.h mymalloc.h fenmatcher.h
|
||||
$(CC) $(CFLAGS) argsfile.c
|
||||
|
||||
decode.o : decode.c defs.h typedef.h taglist.h lex.h bool.h decode.h lists.h \
|
||||
tokens.h mymalloc.h
|
||||
$(CC) $(CFLAGS) decode.c
|
||||
|
||||
eco.o : eco.c defs.h lex.h typedef.h map.h bool.h eco.h taglist.h apply.h \
|
||||
mymalloc.h
|
||||
$(CC) $(CFLAGS) eco.c
|
||||
|
||||
end.o : end.c end.h bool.h defs.h typedef.h lines.h tokens.h lex.h mymalloc.h \
|
||||
apply.h grammar.h
|
||||
$(CC) $(CFLAGS) end.c
|
||||
|
||||
grammar.o : grammar.c bool.h defs.h typedef.h lex.h taglist.h map.h lists.h\
|
||||
moves.h apply.h output.h tokens.h eco.h end.h grammar.h hashing.h \
|
||||
mymalloc.h
|
||||
$(CC) $(CFLAGS) grammar.c
|
||||
|
||||
hashing.o : hashing.c hashing.h bool.h defs.h typedef.h tokens.h\
|
||||
taglist.h lex.h mymalloc.h zobrist.h
|
||||
$(CC) $(CFLAGS) hashing.c
|
||||
|
||||
lex.o : lex.c bool.h defs.h typedef.h tokens.h taglist.h map.h\
|
||||
lists.h decode.h moves.h lines.h grammar.h mymalloc.h apply.h\
|
||||
output.h
|
||||
$(CC) $(CFLAGS) lex.c
|
||||
|
||||
lines.o : lines.c bool.h lines.h mymalloc.h
|
||||
$(CC) $(CFLAGS) lines.c
|
||||
|
||||
lists.o : lists.c lists.h taglist.h bool.h defs.h typedef.h mymalloc.h moves.h
|
||||
$(CC) $(CFLAGS) lists.c
|
||||
|
||||
main.o : main.c bool.h defs.h typedef.h tokens.h taglist.h lex.h moves.h\
|
||||
map.h lists.h output.h end.h grammar.h hashing.h \
|
||||
argsfile.h mymalloc.h
|
||||
$(CC) $(CFLAGS) main.c
|
||||
|
||||
map.o : map.c defs.h lex.h typedef.h map.h bool.h decode.h taglist.h \
|
||||
mymalloc.h
|
||||
$(CC) $(CFLAGS) map.c
|
||||
|
||||
moves.o : moves.c defs.h typedef.h lex.h bool.h map.h lists.h moves.h apply.h\
|
||||
lines.h taglist.h mymalloc.h fenmatcher.h
|
||||
$(CC) $(CFLAGS) moves.c
|
||||
|
||||
fenmatcher.o : fenmatcher.c grammar.h apply.h bool.h defs.h fenmatcher.h mymalloc.h\
|
||||
typedef.h end.h
|
||||
$(CC) $(CFLAGS) fenmatcher.c
|
||||
|
||||
output.o : output.c output.h taglist.h bool.h typedef.h defs.h lex.h grammar.h\
|
||||
apply.h mymalloc.h
|
||||
$(CC) $(CFLAGS) output.c
|
||||
|
||||
taglines.o : taglines.c bool.h defs.h typedef.h tokens.h taglist.h lex.h lines.h \
|
||||
lists.h moves.h output.h taglines.h
|
||||
$(CC) $(CFLAGS) taglines.c
|
||||
|
||||
zobrist.o : zobrist.c zobrist.h bool.h defs.h typedef.h apply.h decode.h grammar.h
|
||||
$(CC) $(CFLAGS) zobrist.c
|
2790
pgn-extract/apply.c
Normal file
2790
pgn-extract/apply.c
Normal file
File diff suppressed because it is too large
Load Diff
46
pgn-extract/apply.h
Normal file
46
pgn-extract/apply.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#ifndef APPLY_H
|
||||
#define APPLY_H
|
||||
|
||||
void add_fen_castling(Game *game_details, Board *board);
|
||||
Boolean apply_move_list(Game *game_details,unsigned *plycount, unsigned max_depth);
|
||||
Boolean apply_move(Move *move_details, Board *board);
|
||||
Board *apply_eco_move_list(Game *game_details,unsigned *number_of_half_moves);
|
||||
void build_basic_EPD_string(const Board *board,char *fen);
|
||||
char coloured_piece_to_SAN_letter(Piece coloured_piece);
|
||||
Piece convert_FEN_char_to_piece(char c);
|
||||
CommentList *create_match_comment(const Board *board);
|
||||
void free_board(Board *board);
|
||||
char *get_FEN_string(const Board *board);
|
||||
Board *new_fen_board(const char *fen);
|
||||
Board *new_game_board(const char *fen);
|
||||
const char *piece_str(Piece piece);
|
||||
Board *rewrite_game(Game *game_details);
|
||||
char SAN_piece_letter(Piece piece);
|
||||
Boolean save_polyglot_hashcode(const char *value);
|
||||
/* letters should contain a string of the form: "PNBRQK" */
|
||||
void set_output_piece_characters(const char *letters);
|
||||
void store_hash_value(Move *move_details,const char *fen);
|
||||
|
||||
#endif // APPLY_H
|
||||
|
1812
pgn-extract/argsfile.c
Normal file
1812
pgn-extract/argsfile.c
Normal file
File diff suppressed because it is too large
Load Diff
74
pgn-extract/argsfile.h
Normal file
74
pgn-extract/argsfile.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
/* Classifications for the arguments allowed in an argsfile. */
|
||||
#ifndef ARGSFILE_H
|
||||
#define ARGSFILE_H
|
||||
|
||||
typedef enum {
|
||||
SEVEN_TAG_ROSTER_ARGUMENT = '7',
|
||||
GAMES_PER_FILE_ARGUMENT = '#',
|
||||
ALTERNATIVE_HELP_ARGUMENT = '?',
|
||||
LONG_FORM_ARGUMENT = '-',
|
||||
APPEND_TO_OUTPUT_FILE_ARGUMENT = 'a',
|
||||
MOVE_BOUNDS_ARGUMENT = 'b',
|
||||
CHECK_FILE_ARGUMENT = 'c',
|
||||
DUPLICATES_FILE_ARGUMENT = 'd',
|
||||
USE_ECO_FILE_ARGUMENT = 'e',
|
||||
FILE_OF_FILES_ARGUMENT = 'f',
|
||||
HELP_ARGUMENT = 'h',
|
||||
WRITE_TO_LOG_FILE_ARGUMENT = 'l',
|
||||
NON_MATCHING_GAMES_ARGUMENT = 'n',
|
||||
WRITE_TO_OUTPUT_FILE_ARGUMENT = 'o',
|
||||
PLY_BOUNDS_ARGUMENT = 'p',
|
||||
CHECK_ONLY_ARGUMENT = 'r',
|
||||
KEEP_SILENT_ARGUMENT = 's',
|
||||
TAGS_ARGUMENT = 't',
|
||||
MOVES_ARGUMENT = 'v',
|
||||
LINE_WIDTH_ARGUMENT = 'w',
|
||||
POSITIONS_ARGUMENT = 'x',
|
||||
ENDINGS_COLOURED_ARGUMENT = 'y',
|
||||
ENDINGS_ARGUMENT = 'z',
|
||||
FILE_OF_ARGUMENTS_ARGUMENT = 'A',
|
||||
DONT_KEEP_COMMENTS_ARGUMENT = 'C',
|
||||
DONT_KEEP_DUPLICATES_ARGUMENT = 'D',
|
||||
ECO_OUTPUT_LEVEL_ARGUMENT = 'E',
|
||||
OUTPUT_FEN_STRING_ARGUMENT = 'F',
|
||||
HASHCODE_MATCH_ARGUMENT = 'H',
|
||||
APPEND_TO_LOG_FILE_ARGUMENT = 'L',
|
||||
MATCH_CHECKMATE_ARGUMENT = 'M',
|
||||
DONT_KEEP_NAGS_ARGUMENT = 'N',
|
||||
DONT_MATCH_PERMUTATIONS_ARGUMENT = 'P',
|
||||
TAG_ROSTER_ARGUMENT = 'R',
|
||||
USE_SOUNDEX_ARGUMENT = 'S',
|
||||
TAG_EXTRACTION_ARGUMENT = 'T',
|
||||
SUPPRESS_ORIGINALS_ARGUMENT = 'U',
|
||||
DONT_KEEP_VARIATIONS_ARGUMENT = 'V',
|
||||
OUTPUT_FORMAT_ARGUMENT = 'W',
|
||||
USE_VIRTUAL_HASH_TABLE_ARGUMENT = 'Z',
|
||||
NO_ARGUMENT_MATCH = '\0' /* No argument match. */
|
||||
} ArgType;
|
||||
|
||||
void process_argument(char arg_letter,const char *associated_value);
|
||||
int process_long_form_argument(const char *argument, const char *associated_value);
|
||||
|
||||
#endif // ARGSFILE_H
|
||||
|
31
pgn-extract/bool.h
Normal file
31
pgn-extract/bool.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
/* Define a type for Booleans.
|
||||
* This is used everywhere.
|
||||
*/
|
||||
#ifndef BOOL_H
|
||||
#define BOOL_H
|
||||
|
||||
typedef enum { FALSE, TRUE } Boolean;
|
||||
|
||||
#endif // BOOL_H
|
||||
|
486
pgn-extract/changes.html
Normal file
486
pgn-extract/changes.html
Normal file
@@ -0,0 +1,486 @@
|
||||
<head>
|
||||
<title>Change History</title>
|
||||
<link rel="author" href="mailto:d.j.barnes@kent.ac.uk">
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
|
||||
<meta name="Author" content="David J. Barnes">
|
||||
<meta name="Description" content="Change history for pgn-extract">
|
||||
<meta name="Keywords"
|
||||
content="pgn-extract change history">
|
||||
<link href="style.css" rel="stylesheet" type="text/css" media="all">
|
||||
</head>
|
||||
<body>
|
||||
<div id="body">
|
||||
<div id="page-wrapper">
|
||||
<div id="page">
|
||||
<h2>Change History</h2>
|
||||
<ul>
|
||||
<li>10th August 2022: Bug fix with -z for failure to match the final position and not
|
||||
necessarily marking the first match in a game when there are multiple matches.
|
||||
|
||||
<li>7th August 2022: Bug fix for -z when only one side's pieces are listed.
|
||||
|
||||
<li>27th June 2022: --firstgame and --gamelimit added. Suggested by Peter Stein.
|
||||
|
||||
<li>23rd June 2022: Regular expressions added to tag matching via -t. Suggested by Peter
|
||||
Stein.
|
||||
|
||||
<li>18th May 2022: --seventyfive added.
|
||||
|
||||
<li>17th May 2022: --repetition5 added.
|
||||
|
||||
<li>16th May 2022: Multiple numeric matches of a single tag with -t now
|
||||
require all matches to be true. This allows selection of ranges of values
|
||||
via < and > operators, for instance.
|
||||
Floating-point numerical values are accepted.
|
||||
|
||||
<li>3rd May 2022: Bug fix for failure to clear a pointer to freed memory.
|
||||
|
||||
<li>27th Mar 2022: Relational operator (>, <, etc.) may be used to match
|
||||
any wholly numeric tag values via the -t flag.
|
||||
|
||||
<li>23rd Feb 2022: Bug fix for material matches where games involve promotion.
|
||||
|
||||
<li>17th Feb 2022: Added recognition of some en passant indicators in the input. They are deleted
|
||||
in the output version.
|
||||
|
||||
<li>26th Jan 2022: Added recognition of single-line comments. I have no idea why these escaped my
|
||||
attention over the past 27 years!
|
||||
<br>Fixed inconsistent conversion of polyglot hashcodes shorter than 16 digits, and output hashcodes
|
||||
with leading zeros where appropriate. The fix affected correct operation of the -H option.
|
||||
<br>Replaced nonsense Result tags with *.
|
||||
<br>Fixed incorrect TotalPlyCount when --totalplycount and --splitvariants are used together.
|
||||
<br>Thanks for Robert Gamble for highlighting these issues.
|
||||
|
||||
<li>18th Jan 2022: Bug fix to --evaluation that counted illegal ep moves in the Shannon evaluation.
|
||||
|
||||
<li>28 Dec 2021: Edits to the index to make it a little more structured.
|
||||
|
||||
<li>24th Nov 2021: Added -Wfen.
|
||||
|
||||
<li>16th July 2021: Added --deletesamesetup.
|
||||
|
||||
<li>25th June 2021: Extended matching of TimeControl to include the formats
|
||||
of sudden death and sandclock.
|
||||
|
||||
<li>19th June 2021: Added --addfencastling following a suggestion from
|
||||
David Barlow.
|
||||
|
||||
<li>4th Apr 2021: Added --detag following a suggestion by Gabriele Battaglia.
|
||||
|
||||
<li>2nd Mar 2021: Make duplicate suppression work with input from stdin. Added --minply, --maxply,
|
||||
--minmoves, --maxmoves as clearer alternatives to -p and -b.
|
||||
|
||||
<li>27th Jan 2021: Bug fix to --fixtagstrings.
|
||||
|
||||
<li>3rd Jan 2021: Added --linenumbers following a suggestion by Ejner Borgbjerg.
|
||||
|
||||
<li>8th Nov 2020: Added --fixtagstrings.
|
||||
|
||||
<li>7th Nov 2020: Date matches with -t and -T extended to match on month and day as well as year.
|
||||
|
||||
<li>7th Oct 2020: Added --wtm and --btm.
|
||||
|
||||
<li>25th Jul 2020: Added limited relational TimeControl matching with -t following
|
||||
a suggestion by Erwin Wouterson.
|
||||
|
||||
<li>2nd Jul 2020: Added missing 'ep' for en passant moves with -Wxlalg and -Wxolalg.
|
||||
|
||||
<li>12th Feb 2020: Bug fix to eliminate illegal pawn moves in long algebraic notation.
|
||||
|
||||
<li>13th Oct 2019: Suppressed repeated error message with malformed dates when matching a Date tag with a relational operator.
|
||||
|
||||
<li>31st Jul 2019: Added --startply.
|
||||
|
||||
<li>21st Jun 2019: Added --fenpattern, --fenpatterni, --materialy and --materialz as command-line arguments.
|
||||
|
||||
<li>9th May 2019: Delete NAGs appearing before the first move of a game. $220 is
|
||||
sometimes used (e.g., by ChessPad) as a print-board indicator.
|
||||
|
||||
<li>22nd Apr 2019: Improved --repetition so that it does not give false positives when
|
||||
castling rights or who is to move are different.
|
||||
<p>Retain next move number rather than resetting to 1 with --dropply and --dropbefore.
|
||||
|
||||
<li>14th Apr 2019: Fixed a memory error in v18-10 that occurred when a positional match was found but the moves of the game were invalid.
|
||||
|
||||
<li>28th Mar 2019: Added --xroster to suppress tags that are not required with -R.
|
||||
|
||||
<li>13th Nov 2018: Missing SetUp tags no longer elicit an error message as this contravention of the standard is so common.
|
||||
|
||||
<li>28th Oct 2018: Negative value accepted with --dropply to indicates plies to be
|
||||
retained at the end of the game.
|
||||
|
||||
<li>18th Oct 2018: open game files in binary mode to cope with the Ctrl
|
||||
characters that appear in some.
|
||||
|
||||
<li>17th Oct 2018: Accept Z0 as an alternative to --.</li>
|
||||
|
||||
<li>13th Oct 2018: Added --dropbefore as a result of a suggestion by Josip Salai.
|
||||
Fixed missing SetUp tag with --dropply.
|
||||
Fixed -H to work with 32-bit Windows.</li>
|
||||
|
||||
<li>7th Oct 2018: Added -y.</li>
|
||||
|
||||
<li>19th Aug 2018: Fixed a memory leak with -z.</li>
|
||||
|
||||
<li>11th July 2018: Added the MatchLabel tag and FENPatternI matching
|
||||
with -t after a suggestion by Hedinn Steingrimsson.
|
||||
In addition, significantly improved the efficiency of FENPattern
|
||||
matches.</li>
|
||||
|
||||
<li>3rd July 2018: Added the MaterialMatch tag with -z after a suggestion
|
||||
by Hedinn Steingrimsson.</li>
|
||||
|
||||
<li>23rd Apr 2018: With -R, include tags in the output that are not explicitly
|
||||
listed in the roster order. This aligns the behaviour with the documentation.</li>
|
||||
|
||||
<li>9th Feb 2018: Suppress warning for null moves when --allownullmoves is used.
|
||||
With --fixresulttags, prefer the terminating result if either it or the result
|
||||
tag is "*".</li>
|
||||
|
||||
<li>29th Dec 2017: Corrected failure to OR rather than AND the pseudo Elo
|
||||
tag used with -t.</li>
|
||||
|
||||
<li>17th Dec 2017: Accepted multiple NAG comment pairs after a move.
|
||||
If NAGs are suppressed then the associated comments are retained.</li>
|
||||
|
||||
<li>30th Nov 2017: Added --nestedcomments.</li>
|
||||
|
||||
<li>12th Nov 2017: Added --dropply after a suggestion by Heiko Bruns.</li>
|
||||
|
||||
<li>5th Oct 2017: Only require "960" in Variant tag strings for
|
||||
Chess960 games.</li>
|
||||
|
||||
<li>23rd Sep 2017: Added the previously documented, but
|
||||
unimplemented --underpromotion.</li>
|
||||
|
||||
<li>3rd Sep 2017: Bug fix for zero-move games which were not being
|
||||
followed by a blank line.</li>
|
||||
|
||||
<li>26th July 2017: --matchplylimit added following a suggestion by James Ward.</li>
|
||||
|
||||
<li>23rd July 2017: Bug fix for --splitvariants.</li>
|
||||
|
||||
<li>21st July 2017: Added --nobadresults to suppress games with inconsistent
|
||||
result indications.
|
||||
|
||||
Fixed failure to correct terminating result with --fixresulttags.
|
||||
|
||||
Added --allownullmoves.</li>
|
||||
|
||||
<li>15th July 2017: Added -Tf for FEN pattern matching.</li>
|
||||
|
||||
<li>8th July 2017: Added --plycount. With -z, use a FEN tag (if present) to count
|
||||
the number of pieces.</li>
|
||||
|
||||
<li>6th July 2017: Adjusted -z to work correctly with a position stability value of 0.
|
||||
Implemented the suggestion of Josip Salai that that FEN as the marker with --markmatches
|
||||
should be interpreted as a request to output the FEN encoding of the match position.</li>
|
||||
|
||||
<li>28th June 2017: Added a c1 comment to -Wepd output to record the game's result.
|
||||
Added the requirement that the Variant tag contain the string "chess 960" to be
|
||||
considered as Chess960 games on output. This primarily affects encoding of castling
|
||||
moves in long-algebraic notation.</li>
|
||||
|
||||
<li>6th June 2017: Added a second number to the -# flag to control file numbering.</li>
|
||||
|
||||
<li>4th June 2017: Chess960 long algebraic castling notation accommodated
|
||||
on both input and output. This is where castling is indicated by specifying
|
||||
the Rook's column as the destination for the King.</li>
|
||||
|
||||
<li>2nd June 2017: With --fixresulttags don't report inconsistent results that
|
||||
can be fixed.</li>
|
||||
|
||||
<li>21st May 2017: Added --commentlines after a suggestion
|
||||
by Gabriele Battaglia.</li>
|
||||
|
||||
<li>21st April 2017: Optional limiting depth added to --splitvariants.</li>
|
||||
|
||||
<li>7th April 2017: License updated to version 3 of the GPL.</li>
|
||||
|
||||
<li>31st March 2017: Added --splitvariants after a suggestion by Vladimir Volovich
|
||||
to add functionality found in pgnsplit.</li>
|
||||
|
||||
<li>19th February 2017: Extended --selectonly and added --skipmatching after
|
||||
a suggestion by Folkert van Heusden.</li>
|
||||
|
||||
<li>16th February 2017: Fixed runtime failure when -x and -n were used together.
|
||||
Added missing SetUp tag when a FEN tag is present.
|
||||
Correct "1/2" in a Result tag to "1/2-1/2".
|
||||
Added explicit Q promotion when unspecified.
|
||||
Fixed lack of output with -W (i.e., output as source).</li>
|
||||
|
||||
<li>29th January 2017: Added --hashcomments to add a comment containing
|
||||
a polyglot hash code after each move. Added -H for Zobrist polyglot hash
|
||||
matches.</li>
|
||||
|
||||
<li>Added text after -F for FEN-position output at arbitrary positions and not simply
|
||||
at the end of a game. Suggested by Josip Salai.</li>
|
||||
|
||||
<li>22nd January 2017: Added --stopafter.</li>
|
||||
|
||||
<li>20th January 2017: Added --nosetuptags and --onlysetuptags following a
|
||||
discussion with Mike Crockett. Added -p[elu] for finer control of game
|
||||
length matching than provided by -b.</li>
|
||||
|
||||
<li>14th January 2017: Fixed --fuzzydepth.</li>
|
||||
|
||||
<li>9th January 2017: Improved the efficiency of (lack of) stalemate detection.</li>
|
||||
|
||||
<li>1st January 2017: Added --fixresulttags for conflicts between the game termination
|
||||
and the result tag.
|
||||
Source code rewrites of function names for more consistent naming.</li>
|
||||
|
||||
<li>8th November 2016: Allows 'b' as a trailing promotion character, previously disallowed.</li>
|
||||
|
||||
<li>3rd September 2016: Added --quiescent for position quiescence after a suggestion from
|
||||
Mike Crockett.</li>
|
||||
|
||||
<li>17th April 2016: Added --tagsubstr for substring matches on tags.</li>
|
||||
<li>4th March 2016: Added --quiet to suppress the number of games processed, as an extension of -s.
|
||||
(Suggested by Norm Pollock.)</li>
|
||||
<li>21st November 2015: Added recognition of Chess960 FEN encodings and application of its
|
||||
castling rules.</li>
|
||||
<li>16th October 2015: Added --fifty, --repetition, and warnings about inconsistent results in tags on
|
||||
checkmate and stalemate after suggestions by Norm Pollock.</li>
|
||||
<li>6th May 2015: Fixed errors in the half-move clock on castling and pawn promotion, thanks
|
||||
to Brandon RichardWebster.</li>
|
||||
<li>23rd Mar 2015: Added --nofauxep after a suggestion by Norm Pollock.</li>
|
||||
<li>21st Mar 2015: Fixed off-by-one in move number output with -F when white-to-move.</li>
|
||||
<li>20th Mar 2015: Added -Wxlalg at the suggestion of Bruce Ramsey.</li>
|
||||
<li>8th Jan 2015: Fixed bug in game counting with -#.
|
||||
Suppressed games with null moves (--) in the main line.</li>
|
||||
<li>28th October 2014. Added --selectonly after a suggestion by Francis Steen.</li>
|
||||
<li>2nd September 2014. Corrected an error in the generation of hashcodes
|
||||
when a promotion is made.</li>
|
||||
<li>31st May 2014. Added --addhashcode.</li>
|
||||
<li>25th May 2014. Added --totalplycount for Erich Körber.</li>
|
||||
<li>5th March 2014. Added --keepbroken to allow broken games to be output.
|
||||
Added at the request of Mark Crowther primarily to deal with the problem of live
|
||||
recording where the kings are moved to the centre of the board at the end of
|
||||
a game and erroneously included in the score.</li>
|
||||
|
||||
<li>6th September 2013. Corrected failure to 'or' together multiple
|
||||
dates with -T and -t.</li>
|
||||
|
||||
<li>16th May 2013. Corrected an error in the whole-move number in
|
||||
FEN output, thanks to Vincent Fleuranceau.</li>
|
||||
|
||||
<li>14th May 2013. Null move notation (--) in variations recognised.</li>
|
||||
|
||||
<li>16th April 2013. Added --fuzzydepth. This is due to Owen D. Lyne who
|
||||
requested this functionality years ago - sorry for taking so long, Owen!</li>
|
||||
|
||||
<li>11th April 2013. Added -Wuci.</li>
|
||||
|
||||
<li>29th March 2013. Added --version.</li>
|
||||
|
||||
<li>26th March 2013. Fixed crash when a string to be output is longer than the output line length.</li>
|
||||
|
||||
<li>12th March 2013. Added long-form versions of -a, -c, -d and -o:
|
||||
--append, --checkfile, --duplicates and --output.</li>
|
||||
|
||||
<li>9th February 2013. Added pattern matching based on
|
||||
FEN descriptions and --markmatches for JS.</li>
|
||||
|
||||
<li>23rd December 2012. Added --fencomments for Tyler Eaves.</li>
|
||||
|
||||
<li>2nd December 2012. Allowed 0 for --plylimit.</li>
|
||||
|
||||
<li>22nd September 2008. Added --stalemate for Wieland Belka.</li>
|
||||
|
||||
<li>15th September 2008. Added --nochecks and fixed -A so that it
|
||||
handles long-form arguments properly.</li>
|
||||
|
||||
<li>22nd December 2007. Added --notags, --plylimit, --nomovenumbers and
|
||||
--noresults after a suggestion by Wieland Belka to be able to create opening books.</li>
|
||||
|
||||
<br>Added --evaluation for Folkert van Heusden.</li>
|
||||
|
||||
<br>Added --stalemate for Norm Pollock.</li>
|
||||
|
||||
<br>Added calculation of the half-move clock to FEN strings.</li>
|
||||
|
||||
<br>Most of the arguments taking filenames can now be separated from
|
||||
the filename with a space.</li>
|
||||
|
||||
<br>Gradually adding long-form alternatives for arguments, e.g.
|
||||
--seven, --notags, etc.</li>
|
||||
|
||||
<li>24th April 2007. Fixed a bug with mate annotation. Added the -M flag for
|
||||
checkmate matches, which is due to Richard Jones.</li>
|
||||
|
||||
<li>19th October 2005. Added language-specific letters to -Welalg
|
||||
following a suggestion from Folkert van Heusden.</li>
|
||||
|
||||
<li>1st May 2004: Fixed an error with ECO classification that
|
||||
was causing the file list to be out of sync.</li>
|
||||
|
||||
<li>29th April 2004: Buffered game text before outputting it,
|
||||
so that trailing spaces on lines (which violate the PGN spec)
|
||||
can be deleted.<br>
|
||||
Games with zero moves are now acceptable.</li>
|
||||
<li>26th April 2004: Slight modification to one of the hashing
|
||||
|
||||
values made in order to try to avoid clashes in ECO matches.
|
||||
ECO matches now have a discretion of up to 6 half moves.</li>
|
||||
|
||||
<li>13th February 2002: Added -Welalg as an output format following
|
||||
a suggestion from Rafal Furdzik.</li>
|
||||
|
||||
<li>27th March 2001
|
||||
<ul>
|
||||
<li>Added output of EPD via -Wepd.
|
||||
<li>Fixed a long standing error in FEN castling rights. These were
|
||||
not being withdrawn if a Rook was captured on its home square.
|
||||
Pointed out by Karl-Martin Skontorp, who also provided the
|
||||
incentive to add -Wepd.
|
||||
</ul></li>
|
||||
|
||||
<li>26th April 2000
|
||||
Added the -R flag for tag ordering.</li>
|
||||
|
||||
<li>22nd April 2000
|
||||
Completed implementation of -A to work with all flags.</li>
|
||||
|
||||
<li>21st April 2000
|
||||
<ul>
|
||||
<li>Added the -F flag.
|
||||
<li>Added support for reading Russian source files.
|
||||
</ul></li>
|
||||
|
||||
<li>11th April 2000
|
||||
<ul>
|
||||
<li>Added the -A flag.
|
||||
<li>Extended usage of -Wsan to support output in different languages.
|
||||
<li>Usage of -e with -7 retains an ECO tag in matched games.
|
||||
<li>FEN tags with the -t flag are used as positional matches
|
||||
(equivalent to -x matches).
|
||||
<li>Non-standard tags are now retained in game output.
|
||||
</ul></li>
|
||||
|
||||
<li>12th January 2000
|
||||
C compiler with Red Hat Linux 6 was no longer happy with
|
||||
static initialisations involving stdin, stdout and stderr.
|
||||
Changes made to lex.c and main.c to work around this.
|
||||
Pointed out by Mladen Bestvina.</li>
|
||||
|
||||
<li>18th October 1999
|
||||
Numbers greater than 3 allowed with -E, at the request of Owen Lyne.</li>
|
||||
|
||||
<li>15th December 1997
|
||||
Treat \r as WHITESPACE (for DOS files).</li>
|
||||
|
||||
<li>8th June 1997
|
||||
Added -b flag to set bounds on the number of moves in a game to
|
||||
be matched.</li>
|
||||
|
||||
<li>2nd May 1997
|
||||
Corrected small error when strings were not terminated properly.
|
||||
In tags, this resulted in the corrected tag ending in ]"] instead
|
||||
of "].</li>
|
||||
|
||||
<li>17th February 1997
|
||||
Added a little more error recovery.</li>
|
||||
|
||||
<li>15th November 1996
|
||||
Added -Z.</li>
|
||||
|
||||
<li>23rd Sep 1996
|
||||
It is no longer necessary to omit move numbers from the variations
|
||||
files (-v and -x). This makes it easier to cut and paste games
|
||||
of interest into these files.</li>
|
||||
|
||||
<li>28th Jun 1996
|
||||
It is no longer necessary to terminate the tag file (-t).
|
||||
Relational operators added in the tag file (-t).
|
||||
Added -E flag.</li>
|
||||
|
||||
<li>7th May 1996
|
||||
Corrected failure to make ECO classification when combined with -x.
|
||||
Added lalg and halg as long algebraic output formats.</li>
|
||||
|
||||
<li>9th Oct 1995
|
||||
Add -#</li>
|
||||
|
||||
<li>25th Sep 1995:
|
||||
Default to reading stdin if no file arguments are provided.</li>
|
||||
|
||||
<li>24th Jul 1995:
|
||||
Added setup from FEN tags.</li>
|
||||
|
||||
<li>18th Jul 1995:
|
||||
<ul>
|
||||
<li>Added material balance matches with -z.
|
||||
<li>Added 'L' as a minor piece letter in ending files.
|
||||
</ul></li>
|
||||
|
||||
<li>14th Jul 1995:
|
||||
Made the order of arguments immaterial.</li>
|
||||
|
||||
<li>5th Jul 1995:
|
||||
<ul>
|
||||
<li>Added ECO classification with -e.
|
||||
<li>Fixed false partial substring matches with -v, e.g. textual
|
||||
variation move Nc6 is now no longer matched by game move c6.
|
||||
</ul></li>
|
||||
|
||||
<li>22nd Mar 1995:
|
||||
Made permutation matching with -v the default and added -P
|
||||
to suppress it.</li>
|
||||
|
||||
<li>Jan 1995: Added -n and -L.</li>
|
||||
|
||||
<li>17th Nov 1994: Liberated the program from using YACC and Lex.</li>
|
||||
|
||||
<li>13th Oct 1994: Released test version with ChessMaster output.</li>
|
||||
|
||||
<li>20th Sep 1994: Added move rewriting and -W flag.</li>
|
||||
|
||||
<li>7th Sep 1994: Added -D flag.</li>
|
||||
|
||||
<li>6th Sep 1994: Added -C and -V flags and soundex matching.</li>
|
||||
|
||||
<li>5th Sep 1994:
|
||||
<ul>
|
||||
<li>Integrated the positional variation code from a separately
|
||||
developed program.
|
||||
<li>Added -N flag.
|
||||
<li>Added ! to the textual variation syntax.
|
||||
<li>Removed the writing to extract.pgn that was present in an
|
||||
earlier unreleased version.
|
||||
<li>Added -d flag.
|
||||
</ul></li>
|
||||
|
||||
<li>8th Jul 1994:
|
||||
<ul>
|
||||
<li>Added -o flag.
|
||||
<li>Discarded writing to standard output in DOS version because of
|
||||
extensive problems trying to make this work with redirected
|
||||
output. Instead, output is written to the file extract.pgn.
|
||||
</ul></li>
|
||||
|
||||
<li>6th Jul 1994: Added -7 flag.</li>
|
||||
|
||||
<li>9th May 1994: Added -p flag for variation permutations.</li>
|
||||
|
||||
<li>6th May 1994: Added * as a don't-care move in variations files.</li>
|
||||
|
||||
<li>26th Apr 1994: Added the -t flag for files of extraction criteria.</li>
|
||||
|
||||
<li>25th Apr 1994: Added the -T flag for extraction criteria.</li>
|
||||
|
||||
<li>22nd Apr 1994: Added the -f flag for handling lists of PGN files.</li>
|
||||
|
||||
<li>13th Apr 1994:
|
||||
<ul>
|
||||
<li>Cleaned up the game-length determination by reading/writing files
|
||||
in binary-mode.
|
||||
<li>Added -a flag for appending to existing .pgn files.
|
||||
<li>Added multiple input files.
|
||||
<li>Made verbose output the default behaviour.
|
||||
</ul></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
21
pgn-extract/copyright
Normal file
21
pgn-extract/copyright
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
670
pgn-extract/decode.c
Normal file
670
pgn-extract/decode.c
Normal file
@@ -0,0 +1,670 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
/* This file contains functions concerned with decoding
|
||||
* the original text of a move in order to determine:
|
||||
* which MoveClass it is in;
|
||||
* any start and end square information.
|
||||
* It extracts this information purely from the move text
|
||||
* rather than analysing the move within the context of
|
||||
* a board position.
|
||||
* This information is later refined by the semantic analysis
|
||||
* phase of the program as part of the checking of a game score.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "bool.h"
|
||||
#include "mymalloc.h"
|
||||
#include "defs.h"
|
||||
#include "typedef.h"
|
||||
#include "decode.h"
|
||||
#include "tokens.h"
|
||||
#include "taglist.h"
|
||||
#include "lex.h"
|
||||
|
||||
/* Does the character represent a column of the board? */
|
||||
Boolean
|
||||
is_col(char c)
|
||||
{
|
||||
return (FIRSTCOL <= c) && (c <= LASTCOL);
|
||||
}
|
||||
|
||||
/* Does the character represent a rank of the board? */
|
||||
Boolean
|
||||
is_rank(char c)
|
||||
{
|
||||
return (FIRSTRANK <= c) && (c <= LASTRANK);
|
||||
}
|
||||
|
||||
/* What kind of piece is *move likely to represent?
|
||||
* Note, the provision for double-character pieces,
|
||||
* like a Russian King, means we need access to a
|
||||
* string rather than a single char.
|
||||
*/
|
||||
Piece
|
||||
is_piece(const unsigned char *move)
|
||||
{
|
||||
Piece piece = EMPTY;
|
||||
|
||||
switch (*move) {
|
||||
case 'K': case 'k':
|
||||
piece = KING;
|
||||
break;
|
||||
case 'Q': case 'q':
|
||||
case 'D': /* Dutch/German. */
|
||||
case RUSSIAN_QUEEN:
|
||||
piece = QUEEN;
|
||||
break;
|
||||
case 'R': case 'r':
|
||||
case 'T': /* Dutch/German. */
|
||||
case RUSSIAN_ROOK:
|
||||
piece = ROOK;
|
||||
break;
|
||||
case 'N': case 'n':
|
||||
case 'P': /* Dutch. */
|
||||
case 'S': /* German. */
|
||||
piece = KNIGHT;
|
||||
break;
|
||||
case 'B':
|
||||
case 'L': /* Dutch/German. */
|
||||
case RUSSIAN_BISHOP:
|
||||
/* Lower case 'b' is most likely to be a pawn reference. */
|
||||
piece = BISHOP;
|
||||
break;
|
||||
case RUSSIAN_KNIGHT_OR_KING:
|
||||
if (RUSSIAN_PIECE_CHECK(*(move + 1)) == RUSSIAN_KING_SECOND_LETTER) {
|
||||
piece = KING;
|
||||
}
|
||||
else {
|
||||
piece = KNIGHT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return piece;
|
||||
}
|
||||
|
||||
/* Is the symbol a capturing one?
|
||||
* In fact, this is used to recognise any general separator
|
||||
* between two parts of a move, e.g.:
|
||||
* Nxc3, e2-e4, etc.
|
||||
*/
|
||||
|
||||
static Boolean
|
||||
is_capture(char c)
|
||||
{
|
||||
return (c == 'x') || (c == 'X') || (c == ':') || (c == '-');
|
||||
}
|
||||
|
||||
static Boolean
|
||||
is_castling_character(char c)
|
||||
{
|
||||
return (c == 'O') || (c == '0') || (c == 'o');
|
||||
}
|
||||
|
||||
Boolean
|
||||
is_check(char c)
|
||||
{
|
||||
return (c == '+') || (c == '#');
|
||||
}
|
||||
|
||||
/* Allocate space in which to return the information that
|
||||
* has been gleaned from the move.
|
||||
*/
|
||||
Move *
|
||||
new_move_structure(void)
|
||||
{
|
||||
Move *move = (Move *) malloc_or_die(sizeof (Move));
|
||||
|
||||
move->terminating_result = NULL;
|
||||
move->piece_to_move = EMPTY;
|
||||
move->captured_piece = EMPTY;
|
||||
move->promoted_piece = EMPTY;
|
||||
move->check_status = NOCHECK;
|
||||
move->epd = NULL;
|
||||
move->fen_suffix = NULL;
|
||||
move->zobrist = ~0;
|
||||
move->evaluation = 0;
|
||||
move->NAGs = NULL;
|
||||
move->comment_list = NULL;
|
||||
move->Variants = NULL;
|
||||
move->prev = NULL;
|
||||
move->next = NULL;
|
||||
return move;
|
||||
}
|
||||
|
||||
/* Work out whatever can be gleaned from move_string of
|
||||
* the starting and ending points of the given move.
|
||||
* The move may be any legal string.
|
||||
* The scanning here is libertarian, so it relies heavily on
|
||||
* illegal moves having already been filtered out by the process
|
||||
* of lexical analysis.
|
||||
*/
|
||||
Move *
|
||||
decode_move(const unsigned char *move_string)
|
||||
{ /* The four components of the co-ordinates when known. */
|
||||
Rank from_rank = 0, to_rank = 0;
|
||||
Col from_col = 0, to_col = 0;
|
||||
MoveClass class;
|
||||
Boolean Ok = TRUE;
|
||||
/* Temporary locations until known whether they are from_ or to_. */
|
||||
Col col = 0;
|
||||
Rank rank = 0;
|
||||
/* A pointer to move along the move string. */
|
||||
const unsigned char *move = move_string;
|
||||
/* A pointer to the structure containing the details to be returned. */
|
||||
Move *move_details;
|
||||
Piece piece_to_move = EMPTY;
|
||||
|
||||
/* Make an initial distinction between pawn moves and piece moves. */
|
||||
if (is_col(*move)) {
|
||||
/* Pawn move. */
|
||||
class = PAWN_MOVE;
|
||||
piece_to_move = PAWN;
|
||||
col = *move;
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
/* e4, e2e4 */
|
||||
rank = *move;
|
||||
move++;
|
||||
if (is_capture(*move)) {
|
||||
move++;
|
||||
}
|
||||
if (is_col(*move)) {
|
||||
from_col = col;
|
||||
from_rank = rank;
|
||||
to_col = *move;
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
to_rank = *move;
|
||||
move++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
to_col = col;
|
||||
to_rank = rank;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (is_capture(*move)) {
|
||||
/* axb */
|
||||
move++;
|
||||
}
|
||||
if (is_col(*move)) {
|
||||
/* ab, or bg8 for liberal bishop moves. */
|
||||
from_col = col;
|
||||
to_col = *move;
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
to_rank = *move;
|
||||
move++;
|
||||
/* Check the sanity of this. */
|
||||
if ((from_col != 'b') &&
|
||||
(from_col != (to_col + 1)) && (from_col != (to_col - 1))) {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Check the sanity of this. */
|
||||
if ((from_col != (to_col + 1)) && (from_col != (to_col - 1))) {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
print_error_context(GlobalState.logfile);
|
||||
fprintf(GlobalState.logfile, "Unknown pawn move %s.\n",
|
||||
move_string);
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
if (Ok) {
|
||||
/* Look for promotions. */
|
||||
if (*move == '=') {
|
||||
move++;
|
||||
}
|
||||
/* djb From v17-27 allow a trailing 'b' as a Bishop promotion. */
|
||||
if (is_piece(move) != EMPTY || *move == 'b') {
|
||||
class = PAWN_MOVE_WITH_PROMOTION;
|
||||
/* @@@ Strictly speaking, if the piece is a RUSSIAN_KING
|
||||
* then we should skip two chars.
|
||||
*/
|
||||
move++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((piece_to_move = is_piece(move)) != EMPTY) {
|
||||
class = PIECE_MOVE;
|
||||
/* Check for a two-character piece. */
|
||||
if ((RUSSIAN_PIECE_CHECK(*move) == RUSSIAN_KNIGHT_OR_KING) &&
|
||||
(piece_to_move == KING)) {
|
||||
move++;
|
||||
}
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
/* A disambiguating rank.
|
||||
* R1e1, R1xe3.
|
||||
*/
|
||||
from_rank = *move;
|
||||
move++;
|
||||
if (is_capture(*move)) {
|
||||
move++;
|
||||
}
|
||||
if (is_col(*move)) {
|
||||
to_col = *move;
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
to_rank = *move;
|
||||
move++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
print_error_context(GlobalState.logfile);
|
||||
fprintf(GlobalState.logfile, "Unknown piece move %s.\n",
|
||||
move_string);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (is_capture(*move)) {
|
||||
/* Rxe1 */
|
||||
move++;
|
||||
if (is_col(*move)) {
|
||||
to_col = *move;
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
to_rank = *move;
|
||||
move++;
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
print_error_context(GlobalState.logfile);
|
||||
fprintf(GlobalState.logfile,
|
||||
"Unknown piece move %s.\n", move_string);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
print_error_context(GlobalState.logfile);
|
||||
fprintf(GlobalState.logfile, "Unknown piece move %s.\n",
|
||||
move_string);
|
||||
}
|
||||
}
|
||||
else if (is_col(*move)) {
|
||||
col = *move;
|
||||
move++;
|
||||
if (is_capture(*move)) {
|
||||
move++;
|
||||
}
|
||||
if (is_rank(*move)) {
|
||||
/* Re1, Re1d1, Re1xd1 */
|
||||
rank = *move;
|
||||
move++;
|
||||
if (is_capture(*move)) {
|
||||
move++;
|
||||
}
|
||||
if (is_col(*move)) {
|
||||
/* Re1d1 */
|
||||
from_col = col;
|
||||
from_rank = rank;
|
||||
to_col = *move;
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
to_rank = *move;
|
||||
move++;
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
print_error_context(GlobalState.logfile);
|
||||
fprintf(GlobalState.logfile,
|
||||
"Unknown piece move %s.\n", move_string);
|
||||
}
|
||||
}
|
||||
else {
|
||||
to_col = col;
|
||||
to_rank = rank;
|
||||
}
|
||||
}
|
||||
else if (is_col(*move)) {
|
||||
/* Rae1 */
|
||||
from_col = col;
|
||||
to_col = *move;
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
to_rank = *move;
|
||||
move++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
print_error_context(GlobalState.logfile);
|
||||
fprintf(GlobalState.logfile, "Unknown piece move %s.\n",
|
||||
move_string);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
print_error_context(GlobalState.logfile);
|
||||
fprintf(GlobalState.logfile, "Unknown piece move %s.\n", move_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_castling_character(*move)) {
|
||||
/* Some form of castling. */
|
||||
move++;
|
||||
/* Allow separators to be optional. */
|
||||
if (*move == '-') {
|
||||
move++;
|
||||
}
|
||||
if (is_castling_character(*move)) {
|
||||
move++;
|
||||
if (*move == '-') {
|
||||
move++;
|
||||
}
|
||||
if (is_castling_character(*move)) {
|
||||
class = QUEENSIDE_CASTLE;
|
||||
move++;
|
||||
}
|
||||
else {
|
||||
class = KINGSIDE_CASTLE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
print_error_context(GlobalState.logfile);
|
||||
fprintf(GlobalState.logfile, "Unknown castling move %s.\n", move_string);
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
else if (strcmp((char *) move_string, NULL_MOVE_STRING) == 0) {
|
||||
class = NULL_MOVE;
|
||||
}
|
||||
else {
|
||||
print_error_context(GlobalState.logfile);
|
||||
fprintf(GlobalState.logfile, "Unknown move %s.\n", move_string);
|
||||
Ok = FALSE;
|
||||
}
|
||||
if (Ok && class != NULL_MOVE) {
|
||||
/* Allow trailing checks. */
|
||||
while (is_check(*move)) {
|
||||
move++;
|
||||
}
|
||||
if (*move == '\0') {
|
||||
/* Nothing more to check. */
|
||||
}
|
||||
else if (((strcmp((const char *) move, "ep") == 0) ||
|
||||
(strcmp((const char *) move, "e.p.") == 0)) &&
|
||||
(class == PAWN_MOVE)) {
|
||||
/* These are ok. */
|
||||
class = ENPASSANT_PAWN_MOVE;
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
print_error_context(GlobalState.logfile);
|
||||
fprintf(GlobalState.logfile,
|
||||
"Unknown text trailing move %s <%s>.\n", move_string, move);
|
||||
}
|
||||
}
|
||||
/* Store all of the details gathered, even if the move is illegal. */
|
||||
if (!Ok) {
|
||||
class = UNKNOWN_MOVE;
|
||||
}
|
||||
move_details = new_move_structure();
|
||||
strcpy((char *) move_details->move, (const char *) move_string);
|
||||
move_details->class = class;
|
||||
move_details->piece_to_move = piece_to_move;
|
||||
move_details->from_col = from_col;
|
||||
move_details->from_rank = from_rank;
|
||||
move_details->to_col = to_col;
|
||||
move_details->to_rank = to_rank;
|
||||
move_details->captured_piece = EMPTY;
|
||||
move_details->check_status = NOCHECK;
|
||||
return move_details;
|
||||
}
|
||||
|
||||
Move *
|
||||
decode_algebraic(Move *move_details, Board *board)
|
||||
{
|
||||
int from_r = RankConvert(move_details->from_rank);
|
||||
int from_c = ColConvert(move_details->from_col);
|
||||
Piece piece_to_move = EXTRACT_PIECE(board->board[from_r][from_c]);
|
||||
|
||||
if (piece_to_move != EMPTY) {
|
||||
/* Check for the special case of castling. */
|
||||
if ((piece_to_move == KING) && (move_details->from_col == 'e')) {
|
||||
if (move_details->to_col == 'g') {
|
||||
move_details->class = KINGSIDE_CASTLE;
|
||||
}
|
||||
else if (move_details->to_col == 'c') {
|
||||
move_details->class = QUEENSIDE_CASTLE;
|
||||
}
|
||||
else {
|
||||
move_details->class = PIECE_MOVE;
|
||||
move_details->piece_to_move = piece_to_move;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (piece_to_move == PAWN) {
|
||||
move_details->class = PAWN_MOVE;
|
||||
}
|
||||
else {
|
||||
move_details->class = PIECE_MOVE;
|
||||
}
|
||||
move_details->piece_to_move = piece_to_move;
|
||||
}
|
||||
move_details->captured_piece = EMPTY;
|
||||
move_details->check_status = NOCHECK;
|
||||
}
|
||||
return move_details;
|
||||
}
|
||||
|
||||
/* See if move_string seems to represent the text of a valid move.
|
||||
* Don't print any error messages, just return TRUE or FALSE.
|
||||
*/
|
||||
Boolean
|
||||
move_seems_valid(const unsigned char *move_string)
|
||||
{
|
||||
MoveClass class;
|
||||
Boolean Ok = TRUE;
|
||||
/* A pointer to move along the move string. */
|
||||
unsigned const char *move = move_string;
|
||||
|
||||
/* Make an initial distinction between pawn moves and piece moves. */
|
||||
if (is_col(*move)) {
|
||||
/* Pawn move. */
|
||||
class = PAWN_MOVE;
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
/* e4, e2e4 */
|
||||
move++;
|
||||
if (is_capture(*move)) {
|
||||
move++;
|
||||
}
|
||||
if (is_col(*move)) {
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
move++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (is_capture(*move)) {
|
||||
/* axb */
|
||||
move++;
|
||||
}
|
||||
if (is_col(*move)) {
|
||||
/* ab */
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
move++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
if (Ok) {
|
||||
/* Look for promotions. */
|
||||
if (*move == '=') {
|
||||
move++;
|
||||
}
|
||||
/* djb From v17-27 allow a trailing 'b' as a Bishop promotion. */
|
||||
if (is_piece(move) != EMPTY || *move == 'b') {
|
||||
class = PAWN_MOVE_WITH_PROMOTION;
|
||||
/* @@@ Strictly speaking, if the piece is a RUSSIAN_KING
|
||||
* then we should skip two chars.
|
||||
*/
|
||||
move++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_piece(move) != EMPTY) {
|
||||
class = PIECE_MOVE;
|
||||
/* Check for a two-character piece. */
|
||||
if ((RUSSIAN_PIECE_CHECK(*move) == RUSSIAN_KNIGHT_OR_KING) &&
|
||||
(is_piece(move) == KING)) {
|
||||
move++;
|
||||
}
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
/* A disambiguating rank.
|
||||
* R1e1, R1xe3.
|
||||
*/
|
||||
move++;
|
||||
if (is_capture(*move)) {
|
||||
move++;
|
||||
}
|
||||
if (is_col(*move)) {
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
move++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (is_capture(*move)) {
|
||||
/* Rxe1 */
|
||||
move++;
|
||||
if (is_col(*move)) {
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
move++;
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
else if (is_col(*move)) {
|
||||
move++;
|
||||
if (is_capture(*move)) {
|
||||
move++;
|
||||
}
|
||||
if (is_rank(*move)) {
|
||||
/* Re1, Re1d1, Re1xd1 */
|
||||
move++;
|
||||
if (is_capture(*move)) {
|
||||
move++;
|
||||
}
|
||||
if (is_col(*move)) {
|
||||
/* Re1d1 */
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
move++;
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_col(*move)) {
|
||||
/* Rae1 */
|
||||
move++;
|
||||
if (is_rank(*move)) {
|
||||
move++;
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_castling_character(*move)) {
|
||||
/* Some form of castling. */
|
||||
move++;
|
||||
/* Allow separators to be optional. */
|
||||
if (*move == '-') {
|
||||
move++;
|
||||
}
|
||||
if (is_castling_character(*move)) {
|
||||
move++;
|
||||
if (*move == '-') {
|
||||
move++;
|
||||
}
|
||||
if (is_castling_character(*move)) {
|
||||
class = QUEENSIDE_CASTLE;
|
||||
move++;
|
||||
}
|
||||
else {
|
||||
class = KINGSIDE_CASTLE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
if (Ok) {
|
||||
/* Allow trailing checks. */
|
||||
while (is_check(*move)) {
|
||||
move++;
|
||||
}
|
||||
if (*move == '\0') {
|
||||
/* Nothing more to check. */
|
||||
}
|
||||
else if (((strcmp((const char *) move, "ep") == 0) ||
|
||||
(strcmp((const char *) move, "e.p.") == 0)) &&
|
||||
(class == PAWN_MOVE)) {
|
||||
/* These are ok. */
|
||||
class = ENPASSANT_PAWN_MOVE;
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
return Ok;
|
||||
}
|
35
pgn-extract/decode.h
Normal file
35
pgn-extract/decode.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#ifndef DECODE_H
|
||||
#define DECODE_H
|
||||
|
||||
Move *new_move_structure(void);
|
||||
Piece is_piece(const unsigned char *move);
|
||||
Move *decode_move(const unsigned char *move_string);
|
||||
Move *decode_algebraic(Move *move_details, Board *board);
|
||||
Boolean is_check(char c);
|
||||
Boolean is_col(char c);
|
||||
Boolean is_rank(char c);
|
||||
Boolean move_seems_valid(const unsigned char *move_string);
|
||||
|
||||
#endif // DECODE_H
|
||||
|
152
pgn-extract/defs.h
Normal file
152
pgn-extract/defs.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
/* These colour values are used as modifiers of the Piece values to
|
||||
* produce pieces of the appropriate colours.
|
||||
* A coloured piece is formed by shifting the piece value and setting the
|
||||
* bottom bit to either 0 (BLACK) or 1 (WHITE).
|
||||
*/
|
||||
#ifndef DEFS_H
|
||||
#define DEFS_H
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum { BLACK, WHITE } Colour;
|
||||
typedef enum {
|
||||
OFF, EMPTY,
|
||||
/* The order of these is important and used in several places.
|
||||
* In particular, several for-loops iterate from PAWN to KING.
|
||||
*/
|
||||
PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
|
||||
/* Must be last. */
|
||||
NUM_PIECE_VALUES
|
||||
} Piece;
|
||||
/* Different classes of move determined by the lexical analyser. */
|
||||
typedef enum { PAWN_MOVE, PAWN_MOVE_WITH_PROMOTION, ENPASSANT_PAWN_MOVE,
|
||||
PIECE_MOVE, KINGSIDE_CASTLE, QUEENSIDE_CASTLE,
|
||||
NULL_MOVE,
|
||||
UNKNOWN_MOVE
|
||||
} MoveClass;
|
||||
|
||||
/* Whether who is to move matters for positional matches. */
|
||||
typedef enum { WHITE_TO_MOVE, BLACK_TO_MOVE, EITHER_TO_MOVE } WhoseMove;
|
||||
|
||||
/* Types for algebraic rank and column. */
|
||||
typedef char Rank;
|
||||
typedef char Col;
|
||||
|
||||
/* Define the base characters for ranks and columns. */
|
||||
#define RANKBASE '1'
|
||||
#define COLBASE 'a'
|
||||
#define FIRSTRANK (RANKBASE)
|
||||
#define LASTRANK (RANKBASE+BOARDSIZE-1)
|
||||
#define FIRSTCOL (COLBASE)
|
||||
#define LASTCOL (COLBASE+BOARDSIZE-1)
|
||||
|
||||
/* Convert the given rank to the correct index into a board. */
|
||||
#define RankConvert(rank) ((FIRSTRANK <= (rank)) && ((rank) <= LASTRANK)?\
|
||||
((rank)-RANKBASE+HEDGE):0)
|
||||
/* Convert the given column to the correct index into a board. */
|
||||
#define ColConvert(col) ((FIRSTCOL <= (col)) && ((col) <= LASTCOL)?\
|
||||
((col)-COLBASE+HEDGE):0)
|
||||
|
||||
/* Convert a board index back to Rank or Col form. */
|
||||
#define ToRank(r) ((r)+RANKBASE-HEDGE)
|
||||
#define ToCol(c) ((c)+COLBASE-HEDGE)
|
||||
#define COLOUR_OFFSET(colour) (((colour) == WHITE)? 1 : -1)
|
||||
|
||||
#define BOARDSIZE 8
|
||||
/* Define the size of a hedge around the board.
|
||||
* This should have a size of 2 to make calculation of Knight moves easier.
|
||||
*/
|
||||
#define HEDGE 2
|
||||
|
||||
/* Define a type for position hashing.
|
||||
* The original type for this is unsigned long.
|
||||
* @@@ At some point, it would be worth moving this to uint64_t to be
|
||||
* consistent with the polyglot/zobrist hashing function.
|
||||
*/
|
||||
typedef uint64_t HashCode;
|
||||
|
||||
typedef struct {
|
||||
Piece board[HEDGE+BOARDSIZE+HEDGE][HEDGE+BOARDSIZE+HEDGE];
|
||||
/* Who has the next move. */
|
||||
Colour to_move;
|
||||
/* The current move number. */
|
||||
unsigned move_number;
|
||||
/* Rook starting columns for the 4 castling options.
|
||||
* This accommodates Chess960.
|
||||
*/
|
||||
Col WKingCastle, WQueenCastle;
|
||||
Col BKingCastle, BQueenCastle;
|
||||
/* Keep track of where the two kings are, to make check-detection
|
||||
* simple.
|
||||
*/
|
||||
Col WKingCol; Rank WKingRank;
|
||||
Col BKingCol; Rank BKingRank;
|
||||
/* Is EnPassant capture possible? If so then ep_rank and ep_col have
|
||||
* the square on which this can be made.
|
||||
*/
|
||||
Boolean EnPassant;
|
||||
Rank ep_rank;
|
||||
Col ep_col;
|
||||
/* NB: @@@
|
||||
* This value is based on a relatively weak hashing approach
|
||||
* that really needs updating to properly use the Zobrist hash.
|
||||
*/
|
||||
HashCode weak_hash_value;
|
||||
/* Provision for storing a Zobrist hash value. However,
|
||||
* this is only set if GlobalState.add_hashcode_comments.
|
||||
* At some point, it should supersede the weak_hash_value.
|
||||
*/
|
||||
uint64_t zobrist;
|
||||
/* The half-move clock since the last pawn move or capture. */
|
||||
unsigned halfmove_clock;
|
||||
} Board;
|
||||
|
||||
/* Define a type that can be used to create a list of possible source
|
||||
* squares for a move.
|
||||
*/
|
||||
typedef struct move_pair {
|
||||
Col from_col;
|
||||
Rank from_rank;
|
||||
Col to_col;
|
||||
Rank to_rank;
|
||||
struct move_pair *next;
|
||||
} MovePair;
|
||||
|
||||
/* Conversion macros. */
|
||||
#define PIECE_SHIFT 3
|
||||
#define MAKE_COLOURED_PIECE(colour,piece) ((Piece) (((piece) << PIECE_SHIFT) | (colour)))
|
||||
#define W(piece) MAKE_COLOURED_PIECE(WHITE,piece)
|
||||
#define B(piece) MAKE_COLOURED_PIECE(BLACK,piece)
|
||||
/* Conversion macro, from one colour to another. */
|
||||
#define OPPOSITE_COLOUR(colour) (!(colour))
|
||||
#define EXTRACT_COLOUR(coloured_piece) ((coloured_piece) & 0x01)
|
||||
#define EXTRACT_PIECE(coloured_piece) ((coloured_piece) >> PIECE_SHIFT)
|
||||
|
||||
/* The string for internally representing the non-standard PGN
|
||||
* notation for null moves.
|
||||
*/
|
||||
#define NULL_MOVE_STRING ("--")
|
||||
|
||||
|
||||
#endif // DEFS_H
|
||||
|
332
pgn-extract/eco.c
Normal file
332
pgn-extract/eco.c
Normal file
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "bool.h"
|
||||
#include "mymalloc.h"
|
||||
#include "defs.h"
|
||||
#include "typedef.h"
|
||||
#include "map.h"
|
||||
#include "tokens.h"
|
||||
#include "taglist.h"
|
||||
#include "lex.h"
|
||||
#include "eco.h"
|
||||
#include "apply.h"
|
||||
|
||||
/* Place a limit on how distant a position may be from the ECO line
|
||||
* it purports to match. This is to try to stop collisions way past
|
||||
* where the line could still be active.
|
||||
*/
|
||||
#define ECO_HALF_MOVE_LIMIT 6
|
||||
/* Keep track of the longest ECO line, in half moves, plus
|
||||
* ECO_HALF_MOVE_LIMIT.
|
||||
* If a line exceeds this length, don't bother attempting
|
||||
* a match.
|
||||
*/
|
||||
static unsigned maximum_half_moves = ECO_HALF_MOVE_LIMIT;
|
||||
|
||||
/* Define a table to hold hash values of the ECO positions.
|
||||
* This is used to enable duplicate detection.
|
||||
*/
|
||||
#define ECO_TABLE_SIZE 4096
|
||||
static EcoLog **EcoTable;
|
||||
|
||||
#if INCLUDE_UNUSED_FUNCTIONS
|
||||
|
||||
static void
|
||||
dumpEcoTable(void)
|
||||
{
|
||||
unsigned ix;
|
||||
for (ix = 0; ix < ECO_TABLE_SIZE; ix++) {
|
||||
if (EcoTable[ix] != NULL) {
|
||||
EcoLog *entry = NULL;
|
||||
for (entry = EcoTable[ix]; entry != NULL; entry = entry->next) {
|
||||
fprintf(stderr, "%s %lu %lu ", entry->ECO_tag,
|
||||
entry->required_hash_value,
|
||||
entry->cumulative_hash_value);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return at how many points this match works.
|
||||
*
|
||||
* This is a heuristic attempt to permit later
|
||||
* longer matches to be chosen in preference to
|
||||
* earlier shorter matches, while avoiding the
|
||||
* greater probability of false matches when there
|
||||
* are a lot of ECO lines and we are further into
|
||||
* a game.
|
||||
*/
|
||||
static int
|
||||
eco_match_level(EcoLog *entry, HashCode current_hash_value,
|
||||
HashCode cumulative_hash_value, unsigned half_moves_played)
|
||||
{
|
||||
int level = 0;
|
||||
if (entry != NULL) {
|
||||
if (entry->required_hash_value == current_hash_value) {
|
||||
level++;
|
||||
if (entry->cumulative_hash_value == cumulative_hash_value) {
|
||||
level++;
|
||||
if (entry->half_moves == half_moves_played) {
|
||||
level++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
/* Quality values for aspects of an ECO match.
|
||||
* Currently unused.
|
||||
*/
|
||||
static int ECO_REQUIRED_HASH_VALUE = 1;
|
||||
static int ECO_HALF_MOVE_VALUE = 1;
|
||||
static int ECO_CUMULATIVE_HASH_VALUE = 0;
|
||||
|
||||
/* Rate the quality of the given match.
|
||||
* Currently unused.
|
||||
*/
|
||||
static int eco_match_quality(EcoLog* entry,
|
||||
HashCode current_hash_value,
|
||||
HashCode cumulative_hash_value,
|
||||
int half_moves_played)
|
||||
{
|
||||
int quality = 0;
|
||||
if (entry->required_hash_value == current_hash_value) {
|
||||
quality += ECO_REQUIRED_HASH_VALUE;
|
||||
if (abs(half_moves_played - entry->half_moves) <= ECO_HALF_MOVE_LIMIT) {
|
||||
quality += ECO_HALF_MOVE_VALUE;
|
||||
}
|
||||
if (entry->cumulative_hash_value == cumulative_hash_value) {
|
||||
quality += ECO_CUMULATIVE_HASH_VALUE;
|
||||
}
|
||||
}
|
||||
return quality;
|
||||
}
|
||||
#endif
|
||||
|
||||
void initEcoTable(void)
|
||||
{
|
||||
/* Avoid multiple calls. */
|
||||
if (EcoTable == NULL) {
|
||||
int i;
|
||||
EcoTable = (EcoLog **) malloc_or_die(ECO_TABLE_SIZE * sizeof (EcoLog *));
|
||||
|
||||
for (i = 0; i < ECO_TABLE_SIZE; i++) {
|
||||
EcoTable[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter the ECO details of game into EcoTable.
|
||||
*/
|
||||
void
|
||||
save_eco_details(const Game *game_details, const Board *final_position, unsigned number_of_half_moves)
|
||||
{
|
||||
unsigned ix = game_details->final_hash_value % ECO_TABLE_SIZE;
|
||||
EcoLog *entry = NULL;
|
||||
/* Assume that it can be saved: that there is no collision. */
|
||||
Boolean can_save = TRUE;
|
||||
/* In an effort to save string space, keep a record of the
|
||||
* last entry stored, because there is a good chance that it
|
||||
* will have the same ECO_tag and Opening_tag as the next
|
||||
* one.
|
||||
*/
|
||||
static EcoLog *last_entry = NULL;
|
||||
|
||||
for (entry = EcoTable[ix]; (entry != NULL) && can_save; entry = entry->next) {
|
||||
if ((entry->required_hash_value == game_details->final_hash_value) &&
|
||||
(entry->half_moves == number_of_half_moves) &&
|
||||
(entry->cumulative_hash_value == game_details->cumulative_hash_value)) {
|
||||
const char *tag = entry->ECO_tag,
|
||||
*opening = entry->Opening_tag,
|
||||
*variation = entry->Variation_tag;
|
||||
if (tag == NULL) {
|
||||
tag = "";
|
||||
}
|
||||
if (opening == NULL) {
|
||||
opening = "";
|
||||
}
|
||||
if (variation == NULL) {
|
||||
variation = "";
|
||||
}
|
||||
fprintf(GlobalState.logfile, "ECO hash collision of ");
|
||||
fprintf(GlobalState.logfile, "%s %s %s", tag, opening, variation);
|
||||
fprintf(GlobalState.logfile, " against ");
|
||||
tag = game_details->tags[ECO_TAG];
|
||||
opening = game_details->tags[OPENING_TAG];
|
||||
variation = game_details->tags[VARIATION_TAG];
|
||||
if (tag == NULL) {
|
||||
tag = "";
|
||||
}
|
||||
if (opening == NULL) {
|
||||
opening = "";
|
||||
}
|
||||
if (variation == NULL) {
|
||||
variation = "";
|
||||
}
|
||||
fprintf(GlobalState.logfile, "%s %s %s\n", tag, opening, variation);
|
||||
fprintf(GlobalState.logfile, "Possible duplicate move sequences.\n");
|
||||
|
||||
can_save = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_save) {
|
||||
/* First occurrence, so add it to the log. */
|
||||
entry = (EcoLog *) malloc_or_die(sizeof (*entry));
|
||||
|
||||
entry->required_hash_value = game_details->final_hash_value;
|
||||
entry->cumulative_hash_value = game_details->cumulative_hash_value;
|
||||
/* Keep a record of the current move number as a sanity
|
||||
* check on matches.
|
||||
*/
|
||||
entry->half_moves = number_of_half_moves;
|
||||
/* Check for a new greater depth. */
|
||||
if (number_of_half_moves + ECO_HALF_MOVE_LIMIT > maximum_half_moves) {
|
||||
maximum_half_moves = number_of_half_moves + ECO_HALF_MOVE_LIMIT;
|
||||
}
|
||||
if (game_details->tags[ECO_TAG] != NULL) {
|
||||
if ((last_entry != NULL) && (last_entry->ECO_tag != NULL) &&
|
||||
(strcmp(last_entry->ECO_tag, game_details->tags[ECO_TAG]) == 0)) {
|
||||
/* Share the last entry's tag. */
|
||||
entry->ECO_tag = last_entry->ECO_tag;
|
||||
}
|
||||
else {
|
||||
entry->ECO_tag = copy_string(game_details->tags[ECO_TAG]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
entry->ECO_tag = NULL;
|
||||
}
|
||||
if (game_details->tags[OPENING_TAG] != NULL) {
|
||||
if ((last_entry != NULL) && (last_entry->Opening_tag != NULL) &&
|
||||
(strcmp(last_entry->Opening_tag,
|
||||
game_details->tags[OPENING_TAG]) == 0)) {
|
||||
/* Share the last entry's tag. */
|
||||
entry->Opening_tag = last_entry->Opening_tag;
|
||||
}
|
||||
else {
|
||||
entry->Opening_tag = copy_string(game_details->tags[OPENING_TAG]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
entry->Opening_tag = NULL;
|
||||
}
|
||||
if (game_details->tags[VARIATION_TAG] != NULL) {
|
||||
entry->Variation_tag = copy_string(game_details->tags[VARIATION_TAG]);
|
||||
}
|
||||
else {
|
||||
entry->Variation_tag = NULL;
|
||||
}
|
||||
if (game_details->tags[SUB_VARIATION_TAG] != NULL) {
|
||||
entry->Sub_Variation_tag =
|
||||
copy_string(game_details->tags[SUB_VARIATION_TAG]);
|
||||
}
|
||||
else {
|
||||
entry->Sub_Variation_tag = NULL;
|
||||
}
|
||||
/* Link it into the head at this index. */
|
||||
entry->next = EcoTable[ix];
|
||||
EcoTable[ix] = entry;
|
||||
/* Keep this one for next time around. */
|
||||
last_entry = entry;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look in EcoTable for current_hash_value.
|
||||
* Use cumulative_hash_value to refine the match.
|
||||
* An exact match is preferable to a partial match.
|
||||
*/
|
||||
EcoLog *
|
||||
eco_matches(const Board *board, HashCode cumulative_hash_value,
|
||||
unsigned half_moves_played)
|
||||
{
|
||||
HashCode current_hash_value = board->weak_hash_value;
|
||||
EcoLog *possible = NULL;
|
||||
|
||||
/* Don't bother trying if we are too far on in the game. */
|
||||
if (half_moves_played <= maximum_half_moves) {
|
||||
/* Where to look. */
|
||||
unsigned ix = current_hash_value % ECO_TABLE_SIZE;
|
||||
EcoLog *entry;
|
||||
|
||||
for (entry = EcoTable[ix]; entry != NULL; entry = entry->next) {
|
||||
if (entry->required_hash_value == current_hash_value) {
|
||||
/* See if we have a full match. */
|
||||
if (half_moves_played == entry->half_moves &&
|
||||
entry->cumulative_hash_value == cumulative_hash_value) {
|
||||
return entry;
|
||||
}
|
||||
else if ((half_moves_played - entry->half_moves) <=
|
||||
ECO_HALF_MOVE_LIMIT) {
|
||||
/* Retain this as a possible. */
|
||||
possible = entry;
|
||||
}
|
||||
else {
|
||||
/* Ignore it, as the lines are too distant. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return possible;
|
||||
}
|
||||
|
||||
/* Depending upon the ECO_level and the eco string of the
|
||||
* current game, open the correctly named ECO file.
|
||||
*/
|
||||
FILE *
|
||||
open_eco_output_file(EcoDivision ECO_level, const char *eco)
|
||||
{ /* Allow space for the maximum number of
|
||||
* ECO digits plus a .pgn suffix.
|
||||
*/
|
||||
static const char suffix[] = ".pgn";
|
||||
|
||||
enum {
|
||||
MAXNAME = MAX_ECO_LEVEL + sizeof (suffix) - 1
|
||||
};
|
||||
static char filename[MAXNAME + 1];
|
||||
|
||||
if ((eco == NULL) || !isalpha((int) *eco)) {
|
||||
strcpy(filename, "noeco.pgn");
|
||||
}
|
||||
else if (ECO_level == DONT_DIVIDE) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Internal error: ECO division in open_eco_output_file\n");
|
||||
strcpy(filename, "noeco");
|
||||
}
|
||||
else if (ECO_level == DONT_DIVIDE) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Internal error: ECO division in open_eco_output_file\n");
|
||||
strcpy(filename, "noeco");
|
||||
}
|
||||
else {
|
||||
strncpy(filename, eco, ECO_level);
|
||||
filename[ECO_level] = '\0';
|
||||
strcat(filename, suffix);
|
||||
}
|
||||
return must_open_file(filename, "a");
|
||||
}
|
51
pgn-extract/eco.h
Normal file
51
pgn-extract/eco.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
/* Define a type to hold hash values of interest. */
|
||||
#ifndef ECO_H
|
||||
#define ECO_H
|
||||
|
||||
typedef struct EcoLog {
|
||||
HashCode required_hash_value;
|
||||
/* cumulative_hash_value is used to disambiguate clashing
|
||||
* final hash values in duplicate detection.
|
||||
*/
|
||||
HashCode cumulative_hash_value;
|
||||
/* How deep the line is, from the half_moves associated with
|
||||
* the board when the line is played out.
|
||||
*/
|
||||
unsigned half_moves;
|
||||
const char *ECO_tag;
|
||||
const char *Opening_tag;
|
||||
const char *Variation_tag;
|
||||
const char *Sub_Variation_tag;
|
||||
struct EcoLog *next;
|
||||
} EcoLog;
|
||||
|
||||
EcoLog *eco_matches(const Board *board, HashCode cumulative_hash_value,
|
||||
unsigned half_moves_played);
|
||||
Boolean add_ECO(Game game_details);
|
||||
FILE *open_eco_output_file(EcoDivision ECO_level,const char *eco);
|
||||
void initEcoTable(void);
|
||||
void save_eco_details(const Game *game_details, const Board *final_position, unsigned number_of_moves);
|
||||
|
||||
#endif // ECO_H
|
||||
|
12143
pgn-extract/eco.pgn
Normal file
12143
pgn-extract/eco.pgn
Normal file
File diff suppressed because it is too large
Load Diff
758
pgn-extract/end.c
Normal file
758
pgn-extract/end.c
Normal file
@@ -0,0 +1,758 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "bool.h"
|
||||
#include "mymalloc.h"
|
||||
#include "defs.h"
|
||||
#include "typedef.h"
|
||||
#include "end.h"
|
||||
#include "lines.h"
|
||||
#include "tokens.h"
|
||||
#include "taglist.h"
|
||||
#include "lex.h"
|
||||
#include "apply.h"
|
||||
#include "grammar.h"
|
||||
|
||||
/**
|
||||
* Code to handle specifications describing the state of the board
|
||||
* in terms of numbers of pieces and material balance between opponents.
|
||||
*
|
||||
* Games are then matched against these specifications.
|
||||
*/
|
||||
|
||||
/* Keep a list of endings to be found. */
|
||||
static Material_details *endings_to_match = NULL;
|
||||
|
||||
/* What kind of piece is the character, c, likely to represent?
|
||||
* NB: This is NOT the same as is_piece() in decode.c
|
||||
*/
|
||||
/* Define pseudo-letter for minor pieces, used later. */
|
||||
#define MINOR_PIECE 'L'
|
||||
|
||||
static Piece
|
||||
is_English_piece(char c)
|
||||
{
|
||||
Piece piece = EMPTY;
|
||||
|
||||
switch (c) {
|
||||
case 'K': case 'k':
|
||||
piece = KING;
|
||||
break;
|
||||
case 'Q': case 'q':
|
||||
piece = QUEEN;
|
||||
break;
|
||||
case 'R': case 'r':
|
||||
piece = ROOK;
|
||||
break;
|
||||
case 'N': case 'n':
|
||||
piece = KNIGHT;
|
||||
break;
|
||||
case 'B': case 'b':
|
||||
piece = BISHOP;
|
||||
break;
|
||||
case 'P': case 'p':
|
||||
piece = PAWN;
|
||||
break;
|
||||
}
|
||||
return piece;
|
||||
}
|
||||
|
||||
/* Initialise the count of required pieces prior to reading
|
||||
* in the data.
|
||||
*/
|
||||
static Material_details *
|
||||
new_ending_details(Boolean both_colours)
|
||||
{
|
||||
Material_details *details = (Material_details *) malloc_or_die(sizeof (Material_details));
|
||||
int c;
|
||||
Piece piece;
|
||||
|
||||
details->both_colours = both_colours;
|
||||
for (piece = PAWN; piece <= KING; piece++) {
|
||||
for (c = 0; c < 2; c++) {
|
||||
details->num_pieces[c][piece] = 0;
|
||||
details->occurs[c][piece] = EXACTLY;
|
||||
}
|
||||
}
|
||||
/* Fill out some miscellaneous colour based information. */
|
||||
for (c = 0; c < 2; c++) {
|
||||
/* Only the KING is a requirement for each side. */
|
||||
details->num_pieces[c][KING] = 1;
|
||||
details->match_depth[c] = 0;
|
||||
/* How many general minor pieces to match. */
|
||||
details->num_minor_pieces[c] = 0;
|
||||
details->minor_occurs[c] = EXACTLY;
|
||||
}
|
||||
/* Assume that the match must always have a depth of at least two for
|
||||
* two half-move stability.
|
||||
*/
|
||||
details->move_depth = 2;
|
||||
details->next = NULL;
|
||||
return details;
|
||||
}
|
||||
|
||||
static const char *
|
||||
extract_combination(const char *p, Occurs *p_occurs, int *p_number, const char *line)
|
||||
{
|
||||
Boolean Ok = TRUE;
|
||||
Occurs occurs = EXACTLY;
|
||||
int number = 1;
|
||||
|
||||
if (isdigit((int) *p)) {
|
||||
/* Only single digits are allowed. */
|
||||
number = *p - '0';
|
||||
p++;
|
||||
if (isdigit((int) *p)) {
|
||||
fprintf(GlobalState.logfile, "Number > 9 is too big in %s.\n",
|
||||
line);
|
||||
while (isdigit((int) *p)) {
|
||||
p++;
|
||||
}
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
if (Ok) {
|
||||
/* Look for trailing annotations. */
|
||||
switch (*p) {
|
||||
case '*':
|
||||
number = 0;
|
||||
occurs = NUM_OR_MORE;
|
||||
p++;
|
||||
break;
|
||||
case '+':
|
||||
occurs = NUM_OR_MORE;
|
||||
p++;
|
||||
break;
|
||||
case '-':
|
||||
occurs = NUM_OR_LESS;
|
||||
p++;
|
||||
break;
|
||||
case '?':
|
||||
number = 1;
|
||||
occurs = NUM_OR_LESS;
|
||||
p++;
|
||||
break;
|
||||
case '=':
|
||||
case '#':
|
||||
case '<':
|
||||
case '>':
|
||||
switch (*p) {
|
||||
case '=':
|
||||
p++;
|
||||
occurs = SAME_AS_OPPONENT;
|
||||
break;
|
||||
case '#':
|
||||
p++;
|
||||
occurs = NOT_SAME_AS_OPPONENT;
|
||||
break;
|
||||
case '<':
|
||||
p++;
|
||||
if (*p == '=') {
|
||||
occurs = LESS_EQ_THAN_OPPONENT;
|
||||
p++;
|
||||
}
|
||||
else {
|
||||
occurs = LESS_THAN_OPPONENT;
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
p++;
|
||||
if (*p == '=') {
|
||||
occurs = MORE_EQ_THAN_OPPONENT;
|
||||
p++;
|
||||
}
|
||||
else {
|
||||
occurs = MORE_THAN_OPPONENT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Ok) {
|
||||
*p_occurs = occurs;
|
||||
*p_number = number;
|
||||
return p;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract a single piece set of information from line.
|
||||
* Return where we have got to as the result.
|
||||
* colour == WHITE means we are looking at the first set of
|
||||
* pieces, so some of the notation is illegal (i.e. the relative ops).
|
||||
*
|
||||
* The basic syntax for a piece description is:
|
||||
* piece [number] [occurs]
|
||||
* For instance:
|
||||
* P2+ Pawn occurs at least twice or more.
|
||||
* R= Rook occurs same number of times as opponent. (colour == BLACK)
|
||||
* P1>= Exactly one pawn more than the opponent. (colour == BLACK)
|
||||
*/
|
||||
static const char *
|
||||
extract_piece_information(const char *line, Material_details *details, Colour colour)
|
||||
{
|
||||
const char *p = line;
|
||||
Boolean Ok = TRUE;
|
||||
|
||||
while (Ok && (*p != '\0') && !isspace((int) *p) && *p != MATERIAL_CONSTRAINT) {
|
||||
Piece piece = is_English_piece(*p);
|
||||
/* By default a piece should occur exactly once. */
|
||||
Occurs occurs = EXACTLY;
|
||||
int number = 1;
|
||||
|
||||
if (piece != EMPTY) {
|
||||
/* Skip over the piece. */
|
||||
p++;
|
||||
p = extract_combination(p, &occurs, &number, line);
|
||||
if (p != NULL) {
|
||||
if ((piece == KING) && (number != 1)) {
|
||||
fprintf(GlobalState.logfile, "A king must occur exactly once.\n");
|
||||
number = 1;
|
||||
}
|
||||
else if ((piece == PAWN) && (number > 8)) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"No more than 8 pawns are allowed.\n");
|
||||
number = 8;
|
||||
}
|
||||
details->num_pieces[colour][piece] = number;
|
||||
details->occurs[colour][piece] = occurs;
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
else if (isalpha((int) *p) && (toupper((int) *p) == MINOR_PIECE)) {
|
||||
p++;
|
||||
p = extract_combination(p, &occurs, &number, line);
|
||||
if (p != NULL) {
|
||||
details->num_minor_pieces[colour] = number;
|
||||
details->minor_occurs[colour] = occurs;
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(GlobalState.logfile, "Unknown symbol at %s\n", p);
|
||||
Ok = FALSE;
|
||||
}
|
||||
}
|
||||
if (Ok) {
|
||||
/* Make a sanity check on the use of minor pieces. */
|
||||
if ((details->num_minor_pieces[colour] > 0) ||
|
||||
(details->minor_occurs[colour] != EXACTLY)) {
|
||||
/* Warn about use of BISHOP and KNIGHT letters. */
|
||||
if ((details->num_pieces[colour][BISHOP] > 0) ||
|
||||
(details->occurs[colour][BISHOP] != EXACTLY) ||
|
||||
(details->num_pieces[colour][KNIGHT] > 0) ||
|
||||
(details->occurs[colour][KNIGHT] != EXACTLY)) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Warning: the mixture of minor pieces in %s is not guaranteed to work.\n",
|
||||
line);
|
||||
fprintf(GlobalState.logfile,
|
||||
"In a single set it is advisable to stick to either L or B and/or N.\n");
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract the piece specification from line and fill out
|
||||
* details with the pattern information.
|
||||
*/
|
||||
static Boolean
|
||||
decompose_line(const char *line, Material_details *details)
|
||||
{
|
||||
const char *p = line;
|
||||
Boolean Ok = TRUE;
|
||||
|
||||
/* Skip initial space. */
|
||||
while (isspace((int) *p)) {
|
||||
p++;
|
||||
}
|
||||
|
||||
/* Look for a move depth. */
|
||||
if (isdigit((int) *p)) {
|
||||
unsigned depth;
|
||||
|
||||
depth = *p - '0';
|
||||
p++;
|
||||
while (isdigit((int) *p)) {
|
||||
depth = (depth * 10)+(*p - '0');
|
||||
p++;
|
||||
}
|
||||
while (isspace((int) *p)) {
|
||||
p++;
|
||||
}
|
||||
details->move_depth = depth;
|
||||
}
|
||||
|
||||
/* Extract two pairs of piece information.
|
||||
* NB: If the first set of pieces consists of a lone king then that must
|
||||
* be included explicitly. If the second set consists of a lone
|
||||
* king then that can be omitted.
|
||||
*/
|
||||
p = extract_piece_information(p, details, WHITE);
|
||||
if (p != NULL) {
|
||||
while ((*p != '\0') && (isspace((int) *p) || (*p == MATERIAL_CONSTRAINT))) {
|
||||
p++;
|
||||
}
|
||||
if (*p != '\0') {
|
||||
p = extract_piece_information(p, details, BLACK);
|
||||
}
|
||||
else {
|
||||
/* No explicit requirements for the other colour. */
|
||||
Piece piece;
|
||||
|
||||
for (piece = PAWN; piece <= KING; piece++) {
|
||||
details->num_pieces[BLACK][piece] = 0;
|
||||
details->occurs[BLACK][piece] = EXACTLY;
|
||||
}
|
||||
details->num_pieces[BLACK][KING] = 1;
|
||||
details->occurs[BLACK][KING] = EXACTLY;
|
||||
}
|
||||
}
|
||||
if (p != NULL) {
|
||||
/* Allow trailing text as a comment. */
|
||||
}
|
||||
else {
|
||||
Ok = FALSE;
|
||||
}
|
||||
return Ok;
|
||||
}
|
||||
|
||||
/* A new game to be looked for. Indicate that we have not
|
||||
* started matching any yet.
|
||||
*/
|
||||
static void
|
||||
reset_match_depths(Material_details *endings)
|
||||
{
|
||||
for (; endings != NULL; endings = endings->next) {
|
||||
endings->match_depth[WHITE] = 0;
|
||||
endings->match_depth[BLACK] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to find a match for the given number of piece details. */
|
||||
static Boolean
|
||||
piece_match(int num_available, int num_to_find, int num_opponents, Occurs occurs)
|
||||
{
|
||||
Boolean match = FALSE;
|
||||
|
||||
switch (occurs) {
|
||||
case EXACTLY:
|
||||
match = num_available == num_to_find;
|
||||
break;
|
||||
case NUM_OR_MORE:
|
||||
match = num_available >= num_to_find;
|
||||
break;
|
||||
case NUM_OR_LESS:
|
||||
match = num_available <= num_to_find;
|
||||
break;
|
||||
case SAME_AS_OPPONENT:
|
||||
match = num_available == num_opponents;
|
||||
break;
|
||||
case NOT_SAME_AS_OPPONENT:
|
||||
match = num_available != num_opponents;
|
||||
break;
|
||||
case LESS_THAN_OPPONENT:
|
||||
match = (num_available + num_to_find) <= num_opponents;
|
||||
break;
|
||||
case MORE_THAN_OPPONENT:
|
||||
match = (num_available - num_to_find) >= num_opponents;
|
||||
break;
|
||||
case LESS_EQ_THAN_OPPONENT:
|
||||
/* This means exactly num_to_find less than the
|
||||
* opponent.
|
||||
*/
|
||||
match = (num_available + num_to_find) == num_opponents;
|
||||
break;
|
||||
case MORE_EQ_THAN_OPPONENT:
|
||||
/* This means exactly num_to_find greater than the
|
||||
* opponent.
|
||||
*/
|
||||
match = (num_available - num_to_find) == num_opponents;
|
||||
break;
|
||||
default:
|
||||
fprintf(GlobalState.logfile,
|
||||
"Inconsistent state %d in piece_match.\n", occurs);
|
||||
match = FALSE;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
/* Try to find a match against one player's pieces in the piece_set_colour
|
||||
* set of details_to_find.
|
||||
*/
|
||||
static Boolean
|
||||
piece_set_match(const Material_details *details_to_find,
|
||||
int num_pieces[2][NUM_PIECE_VALUES],
|
||||
Colour game_colour, Colour piece_set_colour)
|
||||
{
|
||||
Boolean match = TRUE;
|
||||
Piece piece;
|
||||
/* Determine whether we failed on a match for minor pieces or not. */
|
||||
Boolean minor_failure = FALSE;
|
||||
|
||||
/* No need to check KING. */
|
||||
for (piece = PAWN; (piece < KING) && match; piece++) {
|
||||
int num_available = num_pieces[game_colour][piece];
|
||||
int num_opponents = num_pieces[OPPOSITE_COLOUR(game_colour)][piece];
|
||||
int num_to_find = details_to_find->num_pieces[piece_set_colour][piece];
|
||||
Occurs occurs = details_to_find->occurs[piece_set_colour][piece];
|
||||
|
||||
match = piece_match(num_available, num_to_find, num_opponents, occurs);
|
||||
if (!match) {
|
||||
if ((piece == KNIGHT) || (piece == BISHOP)) {
|
||||
minor_failure = TRUE;
|
||||
/* Carry on trying to match. */
|
||||
match = TRUE;
|
||||
}
|
||||
else {
|
||||
minor_failure = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
/* Ensure that the minor pieces match if there is a minor pieces
|
||||
* requirement.
|
||||
*/
|
||||
int num_to_find = details_to_find->num_minor_pieces[piece_set_colour];
|
||||
Occurs occurs = details_to_find->minor_occurs[piece_set_colour];
|
||||
|
||||
if ((num_to_find > 0) || (occurs != EXACTLY)) {
|
||||
int num_available =
|
||||
num_pieces[game_colour][BISHOP] +
|
||||
num_pieces[game_colour][KNIGHT];
|
||||
int num_opponents = num_pieces[OPPOSITE_COLOUR(game_colour)][BISHOP] +
|
||||
num_pieces[OPPOSITE_COLOUR(game_colour)][KNIGHT];
|
||||
|
||||
match = piece_match(num_available, num_to_find, num_opponents, occurs);
|
||||
}
|
||||
else if (minor_failure) {
|
||||
/* We actually failed with proper matching of individual minor
|
||||
* pieces, and no minor match fixup is possible.
|
||||
*/
|
||||
match = FALSE;
|
||||
}
|
||||
else {
|
||||
/* Match stands. */
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
/* Look for a material match between current_details and
|
||||
* details_to_find. Only return TRUE if we have both a match
|
||||
* and match_depth >= move_depth in details_to_find.
|
||||
* NB: If the game ends before the required depth is reached then a
|
||||
* potential match would be missed. This could be considered
|
||||
* as a bug.
|
||||
*/
|
||||
static Boolean
|
||||
material_match(Material_details *details_to_find, int num_pieces[2][NUM_PIECE_VALUES],
|
||||
Colour game_colour)
|
||||
{
|
||||
Boolean match = TRUE;
|
||||
Colour piece_set_colour = WHITE;
|
||||
|
||||
match = piece_set_match(details_to_find, num_pieces, game_colour,
|
||||
piece_set_colour);
|
||||
if (match) {
|
||||
game_colour = OPPOSITE_COLOUR(game_colour);
|
||||
piece_set_colour = OPPOSITE_COLOUR(piece_set_colour);
|
||||
match = piece_set_match(details_to_find, num_pieces, game_colour,
|
||||
piece_set_colour);
|
||||
/* Reset colour to its original value. */
|
||||
game_colour = OPPOSITE_COLOUR(game_colour);
|
||||
}
|
||||
|
||||
if (match) {
|
||||
if (details_to_find->match_depth[game_colour] < details_to_find->move_depth) {
|
||||
/* Not a full match yet. */
|
||||
match = FALSE;
|
||||
details_to_find->match_depth[game_colour]++;
|
||||
}
|
||||
else {
|
||||
/* A stable match. */
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Reset the match counter. */
|
||||
details_to_find->match_depth[game_colour] = 0;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
/* Extract the numbers of each type of piece from the given board. */
|
||||
static void extract_pieces_from_board(int num_pieces[2][NUM_PIECE_VALUES], const Board *board)
|
||||
{
|
||||
/* Set up num_pieces from the board. */
|
||||
for(int c = 0; c < 2; c++) {
|
||||
for(int p = 0; p < NUM_PIECE_VALUES; p++) {
|
||||
num_pieces[c][p] = 0;
|
||||
}
|
||||
}
|
||||
for(char rank = FIRSTRANK; rank <= LASTRANK; rank++) {
|
||||
for(char col = FIRSTCOL; col <= LASTCOL; col++) {
|
||||
int r = RankConvert(rank);
|
||||
int c = ColConvert(col);
|
||||
|
||||
Piece coloured_piece = board->board[r][c];
|
||||
if(coloured_piece != EMPTY) {
|
||||
int p = EXTRACT_PIECE(coloured_piece);
|
||||
num_pieces[EXTRACT_COLOUR(coloured_piece)][p]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see whether the given moves lead to a position
|
||||
* that matches the given 'ending' position.
|
||||
* In other words, a position with the required balance
|
||||
* of pieces.
|
||||
*/
|
||||
static Boolean
|
||||
look_for_material_match(Game *game_details)
|
||||
{
|
||||
Boolean game_ok = TRUE;
|
||||
Boolean match_comment_added = FALSE;
|
||||
Move *next_move = game_details->moves;
|
||||
Move *move_for_comment = NULL;
|
||||
Colour colour = WHITE;
|
||||
/* The initial game position has the full set of piece details. */
|
||||
int num_pieces[2][NUM_PIECE_VALUES] = {
|
||||
/* Dummies for OFF and EMPTY at the start. */
|
||||
/* P N B R Q K */
|
||||
{0, 0, 8, 2, 2, 2, 1, 1},
|
||||
{0, 0, 8, 2, 2, 2, 1, 1}
|
||||
};
|
||||
Board *board = new_game_board(game_details->tags[FEN_TAG]);
|
||||
|
||||
if(game_details->tags[FEN_TAG] != NULL) {
|
||||
extract_pieces_from_board(num_pieces, board);
|
||||
}
|
||||
/* Ensure that all previous match indications are cleared. */
|
||||
reset_match_depths(endings_to_match);
|
||||
|
||||
/* Keep going while the game is ok, and we have some more
|
||||
* moves and we haven't exceeded the search depth without finding
|
||||
* a match.
|
||||
*/
|
||||
Boolean matches = FALSE;
|
||||
Boolean end_of_game = FALSE;
|
||||
Boolean white_matches = FALSE, black_matches = FALSE;
|
||||
while (game_ok && !matches && !end_of_game) {
|
||||
for (Material_details *details_to_find = endings_to_match; !matches && (details_to_find != NULL);
|
||||
details_to_find = details_to_find->next) {
|
||||
/* Try before applying each move.
|
||||
* Note, that we wish to try both ways around because we might
|
||||
* have WT,BT WF,BT ... If we don't try BLACK on WHITE success
|
||||
* then we might miss a match because a full match takes several
|
||||
* separate individual match steps.
|
||||
*/
|
||||
white_matches = material_match(details_to_find, num_pieces, WHITE);
|
||||
if(details_to_find->both_colours) {
|
||||
black_matches = material_match(details_to_find, num_pieces, BLACK);
|
||||
}
|
||||
else {
|
||||
black_matches = FALSE;
|
||||
}
|
||||
if (white_matches || black_matches) {
|
||||
matches = TRUE;
|
||||
/* See whether a matching comment is required. */
|
||||
if (GlobalState.add_position_match_comments && !match_comment_added) {
|
||||
CommentList *match_comment = create_match_comment(board);
|
||||
if (move_for_comment != NULL) {
|
||||
append_comments_to_move(move_for_comment, match_comment);
|
||||
}
|
||||
else {
|
||||
if(game_details->prefix_comment == NULL) {
|
||||
game_details->prefix_comment = match_comment;
|
||||
}
|
||||
else {
|
||||
CommentList *comm = game_details->prefix_comment;
|
||||
while(comm->next != NULL) {
|
||||
comm = comm->next;
|
||||
}
|
||||
comm->next = match_comment;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(matches) {
|
||||
/* Nothing required. */
|
||||
}
|
||||
else if(next_move == NULL) {
|
||||
end_of_game = TRUE;
|
||||
}
|
||||
else if (*(next_move->move) != '\0') {
|
||||
/* Try the next position. */
|
||||
if (apply_move(next_move, board)) {
|
||||
/* Remove any captured pieces. */
|
||||
if (next_move->captured_piece != EMPTY) {
|
||||
num_pieces[OPPOSITE_COLOUR(colour)][next_move->captured_piece]--;
|
||||
}
|
||||
if (next_move->promoted_piece != EMPTY) {
|
||||
num_pieces[colour][next_move->promoted_piece]++;
|
||||
/* Remove the promoting pawn. */
|
||||
num_pieces[colour][PAWN]--;
|
||||
}
|
||||
|
||||
move_for_comment = next_move;
|
||||
colour = OPPOSITE_COLOUR(colour);
|
||||
next_move = next_move->next;
|
||||
}
|
||||
else {
|
||||
game_ok = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* An empty move. */
|
||||
fprintf(GlobalState.logfile,
|
||||
"Internal error: Empty move in look_for_material_match.\n");
|
||||
game_ok = FALSE;
|
||||
}
|
||||
}
|
||||
(void) free((void *) board);
|
||||
if(game_ok && matches) {
|
||||
if(GlobalState.add_match_tag) {
|
||||
game_details->tags[MATERIAL_MATCH_TAG] =
|
||||
copy_string(white_matches ? "White" : "Black");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see whether the given moves lead to a position
|
||||
* that matches one of the required 'material match' positions.
|
||||
* In other words, a position with the required balance
|
||||
* of pieces.
|
||||
*/
|
||||
Boolean
|
||||
check_for_material_match(Game *game)
|
||||
{
|
||||
/* Match if there are no endings to match. */
|
||||
if(endings_to_match != NULL) {
|
||||
return look_for_material_match(game);
|
||||
}
|
||||
else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Does the board's material match the constraints of details_to_find?
|
||||
* Return TRUE if it does, FALSE otherwise.
|
||||
*/
|
||||
Boolean
|
||||
constraint_material_match(Material_details *details_to_find, const Board *board)
|
||||
{
|
||||
/* Only a single match position is required. */
|
||||
details_to_find->move_depth = 0;
|
||||
details_to_find->match_depth[0] = 0;
|
||||
details_to_find->match_depth[1] = 0;
|
||||
|
||||
int num_pieces[2][NUM_PIECE_VALUES];
|
||||
extract_pieces_from_board(num_pieces, board);
|
||||
Boolean white_matches = material_match(details_to_find, num_pieces, WHITE);
|
||||
Boolean black_matches;
|
||||
|
||||
if(details_to_find->both_colours) {
|
||||
black_matches = material_match(details_to_find, num_pieces, BLACK);
|
||||
}
|
||||
else {
|
||||
black_matches = FALSE;
|
||||
}
|
||||
return white_matches || black_matches;
|
||||
}
|
||||
|
||||
/* Decompose the text of line to extract two sets of
|
||||
* piece configurations.
|
||||
* If both_colours is TRUE then matches will be tried
|
||||
* for both colours in each configuration.
|
||||
* Otherwise, the first set of pieces are assumed to
|
||||
* be white and the second to be black.
|
||||
* If pattern_constraint is TRUE then the description
|
||||
* is a constraint of a FEN pattern and should not be
|
||||
* retained as a separate material match.
|
||||
*/
|
||||
Material_details *
|
||||
process_material_description(const char *line, Boolean both_colours, Boolean pattern_constraint)
|
||||
{
|
||||
Material_details *details = NULL;
|
||||
|
||||
if (non_blank_line(line)) {
|
||||
details = new_ending_details(both_colours);
|
||||
|
||||
if (decompose_line(line, details)) {
|
||||
if(!pattern_constraint) {
|
||||
/* Add it on to the list. */
|
||||
details->next = endings_to_match;
|
||||
endings_to_match = details;
|
||||
}
|
||||
}
|
||||
else {
|
||||
(void) free((void *) details);
|
||||
details = NULL;
|
||||
}
|
||||
}
|
||||
return details;
|
||||
}
|
||||
|
||||
/* Read a file containing material matches. */
|
||||
Boolean
|
||||
build_endings(const char *infile, Boolean both_colours)
|
||||
{
|
||||
FILE *fp = fopen(infile, "r");
|
||||
Boolean Ok = TRUE;
|
||||
|
||||
if (fp == NULL) {
|
||||
fprintf(GlobalState.logfile, "Cannot open %s for reading.\n", infile);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
char *line;
|
||||
while ((line = read_line(fp)) != NULL) {
|
||||
if(process_material_description(line, both_colours, FALSE) == NULL) {
|
||||
Ok = FALSE;
|
||||
}
|
||||
(void) free(line);
|
||||
}
|
||||
(void) fclose(fp);
|
||||
}
|
||||
return Ok;
|
||||
}
|
70
pgn-extract/end.h
Normal file
70
pgn-extract/end.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#ifndef END_H
|
||||
#define END_H
|
||||
|
||||
/* Define a type to represent classes of occurrance. */
|
||||
typedef enum {
|
||||
EXACTLY, NUM_OR_MORE, NUM_OR_LESS,
|
||||
SAME_AS_OPPONENT, NOT_SAME_AS_OPPONENT,
|
||||
LESS_THAN_OPPONENT, MORE_THAN_OPPONENT,
|
||||
LESS_EQ_THAN_OPPONENT, MORE_EQ_THAN_OPPONENT
|
||||
} Occurs;
|
||||
|
||||
/* Define a structure to hold details on the occurrances of
|
||||
* each of the pieces.
|
||||
*/
|
||||
typedef struct material_details {
|
||||
/* Whether the pieces are to be tried against
|
||||
* both colours.
|
||||
*/
|
||||
Boolean both_colours;
|
||||
/* The number of each set of pieces. */
|
||||
int num_pieces[2][NUM_PIECE_VALUES];
|
||||
Occurs occurs[2][NUM_PIECE_VALUES];
|
||||
/* Numbers of general minor pieces. */
|
||||
int num_minor_pieces[2];
|
||||
Occurs minor_occurs[2];
|
||||
/* How long a given relationship must last to be recognised.
|
||||
* This value is in half moves.
|
||||
*/
|
||||
unsigned move_depth;
|
||||
/* How long a match relationship has been matched.
|
||||
* This is always reset to zero on failure and incremented on
|
||||
* success. A full match is only returned when match_depth == move_depth.
|
||||
*/
|
||||
unsigned match_depth[2];
|
||||
struct material_details *next;
|
||||
} Material_details;
|
||||
|
||||
/* Character to separate a pattern from material constraints.
|
||||
* NB: This is used to add a material constraint to a FEN pattern.
|
||||
*/
|
||||
#define MATERIAL_CONSTRAINT ':'
|
||||
|
||||
Boolean check_for_material_match(Game *game);
|
||||
Boolean build_endings(const char *infile, Boolean both_colours);
|
||||
Material_details *process_material_description(const char *line, Boolean both_colours, Boolean pattern_constraint);
|
||||
Boolean constraint_material_match(Material_details *details_to_find, const Board *board);
|
||||
|
||||
#endif // END_H
|
||||
|
632
pgn-extract/fenmatcher.c
Normal file
632
pgn-extract/fenmatcher.c
Normal file
@@ -0,0 +1,632 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "bool.h"
|
||||
#include "mymalloc.h"
|
||||
#include "defs.h"
|
||||
#include "typedef.h"
|
||||
#include "grammar.h"
|
||||
#include "apply.h"
|
||||
#include "fenmatcher.h"
|
||||
#include "end.h"
|
||||
|
||||
/* Character on an encoded board representing an empty square. */
|
||||
#define EMPTY_SQUARE '_'
|
||||
/* Pattern meta characters. */
|
||||
#define NON_EMPTY_SQUARE '!'
|
||||
#define ANY_SQUARE_STATE '?'
|
||||
#define ZERO_OR_MORE_OF_ANYTHING '*'
|
||||
#define ANY_WHITE_PIECE 'A'
|
||||
#define ANY_BLACK_PIECE 'a'
|
||||
#define NOT_A_PAWN 'm'
|
||||
|
||||
/* Symbols for closures. */
|
||||
#define CCL_START '['
|
||||
#define CCL_END ']'
|
||||
#define NCCL '^'
|
||||
|
||||
/**
|
||||
* Based on original pattern matching code by Rob Pike.
|
||||
* Taken from:
|
||||
* http://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
|
||||
* and ideas from Kernighan and Plauger's "Software Tools".
|
||||
*/
|
||||
|
||||
/* A single rank of a FEN-based patterns to match.
|
||||
* Ranks are chained as a linear list via next_rank and
|
||||
* alternatives for the same rank via alternative_rank.
|
||||
* The optional_label (if any) is stored with the final rank of
|
||||
* the list.
|
||||
*/
|
||||
typedef struct FENPatternMatch {
|
||||
char *rank;
|
||||
const char *optional_label;
|
||||
struct FENPatternMatch *alternative_rank;
|
||||
struct FENPatternMatch *next_rank;
|
||||
Material_details *constraint;
|
||||
} FENPatternMatch;
|
||||
|
||||
static FENPatternMatch *pattern_tree = NULL;
|
||||
|
||||
static Boolean matchhere(const char *regexp, const char *text);
|
||||
static Boolean matchstar(const char *regexp, const char *text);
|
||||
static Boolean matchccl(const char *regexp, const char *text);
|
||||
static Boolean matchnccl(const char *regexp, const char *text);
|
||||
static Boolean matchone(char regchar, char textchar);
|
||||
static void convert_rank_to_text(const Board *board, Rank rank, char *text);
|
||||
static const char *reverse_fen_pattern(const char *pattern);
|
||||
static void pattern_tree_insert(char **ranks, const char *label, Material_details *constraint);
|
||||
static void insert_pattern(FENPatternMatch *node, FENPatternMatch *next);
|
||||
static const char *pattern_match_rank(const Board *board,
|
||||
FENPatternMatch *pattern, int patternIndex,
|
||||
char ranks[BOARDSIZE+1][BOARDSIZE+1]);
|
||||
|
||||
/*
|
||||
* Add a FENPattern to be matched. If add_reverse is TRUE then
|
||||
* additionally add a second pattern that has the colours reversed.
|
||||
* If label is non-NULL then associate it with fen_pattern for possible
|
||||
* output in a tag when the pattern is matched.
|
||||
*/
|
||||
void
|
||||
add_fen_pattern(const char *fen_pattern, Boolean add_reverse, const char *label)
|
||||
{
|
||||
/* Check the pattern has reasonable syntax. */
|
||||
/* Count the number of rank dividers. */
|
||||
int dividers = 0;
|
||||
/* Count the number of symbols in each rank - must be
|
||||
* at least one.
|
||||
*/
|
||||
int rankSymbols = 0;
|
||||
Boolean ok = TRUE;
|
||||
const char *p = fen_pattern;
|
||||
const char *rank_start = fen_pattern;
|
||||
Boolean in_closure = FALSE;
|
||||
char **ranks = (char **) malloc_or_die(BOARDSIZE * sizeof(*ranks));
|
||||
while (*p != '\0' && *p != ' ' && *p != MATERIAL_CONSTRAINT && ok) {
|
||||
if (*p == '/') {
|
||||
/* End of this rank. */
|
||||
if (rankSymbols == 0) {
|
||||
/* Nothing on the previous rank. */
|
||||
ok = FALSE;
|
||||
}
|
||||
else {
|
||||
int num_chars = p - rank_start;
|
||||
ranks[dividers] = (char *) malloc_or_die(num_chars + 1);
|
||||
strncpy(ranks[dividers], rank_start, num_chars);
|
||||
ranks[dividers][num_chars] = '\0';
|
||||
dividers++;
|
||||
|
||||
rank_start = p + 1;
|
||||
}
|
||||
rankSymbols = 0;
|
||||
}
|
||||
else if (*p == CCL_START) {
|
||||
if (!in_closure) {
|
||||
in_closure = TRUE;
|
||||
}
|
||||
else {
|
||||
ok = FALSE;
|
||||
fprintf(GlobalState.logfile,
|
||||
"Nested closures not allowed: %s\n",
|
||||
fen_pattern);
|
||||
}
|
||||
}
|
||||
else if (*p == CCL_END) {
|
||||
if (in_closure) {
|
||||
in_closure = FALSE;
|
||||
}
|
||||
else {
|
||||
ok = FALSE;
|
||||
fprintf(GlobalState.logfile,
|
||||
"Missing %c to match %c: %s\n",
|
||||
CCL_START, CCL_END,
|
||||
fen_pattern);
|
||||
}
|
||||
}
|
||||
else if (*p == NCCL) {
|
||||
if (!in_closure) {
|
||||
ok = FALSE;
|
||||
fprintf(GlobalState.logfile,
|
||||
"%c not allowed outside %c...%c: %s\n",
|
||||
NCCL,
|
||||
CCL_START, CCL_END,
|
||||
fen_pattern);
|
||||
}
|
||||
}
|
||||
else {
|
||||
rankSymbols++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if (dividers != BOARDSIZE - 1) {
|
||||
ok = FALSE;
|
||||
}
|
||||
else if (rankSymbols == 0) {
|
||||
ok = FALSE;
|
||||
}
|
||||
else if(ok) {
|
||||
/* Store the final regexp of the pattern. */
|
||||
int num_chars = p - rank_start;
|
||||
ranks[dividers] = (char *) malloc_or_die(num_chars + 1);
|
||||
strncpy(ranks[dividers], rank_start, num_chars);
|
||||
ranks[dividers][num_chars] = '\0';
|
||||
}
|
||||
if (ok) {
|
||||
Material_details *constraint;
|
||||
if(*p == MATERIAL_CONSTRAINT) {
|
||||
p++;
|
||||
/* Deal with a constraint on the material that must also match. */
|
||||
constraint = process_material_description(p, add_reverse, TRUE);
|
||||
}
|
||||
else {
|
||||
constraint = NULL;
|
||||
}
|
||||
pattern_tree_insert(ranks, label != NULL ? copy_string(label) : copy_string(""), constraint);
|
||||
|
||||
/* Do the same again if a reversed version is required. */
|
||||
if(add_reverse) {
|
||||
char *pattern = copy_string(fen_pattern);
|
||||
/* Terminate at the end of the board position
|
||||
as we are not interested in the castling rights
|
||||
or who is to move.
|
||||
*/
|
||||
pattern[p - fen_pattern] = '\0';
|
||||
const char *reversed = reverse_fen_pattern(pattern);
|
||||
if(label != NULL) {
|
||||
/* Add a suffix to make it clear that this is
|
||||
* a match of the inverted form.
|
||||
*/
|
||||
char *rlabel = (char *) malloc_or_die(strlen(label) + 1 + 1);
|
||||
strcpy(rlabel, label);
|
||||
strcat(rlabel, "I");
|
||||
add_fen_pattern(reversed, FALSE, rlabel);
|
||||
}
|
||||
else {
|
||||
add_fen_pattern(reversed, FALSE, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(GlobalState.logfile, "FEN Pattern: %s badly formed.\n",
|
||||
fen_pattern);
|
||||
}
|
||||
}
|
||||
|
||||
/* Invert the colour sense of the given FENPattern.
|
||||
* Return the inverted form.
|
||||
*/
|
||||
static const char *reverse_fen_pattern(const char *pattern)
|
||||
{
|
||||
/* Completely switch the rows and invert the case of each piece letter. */
|
||||
char **rows = (char **) malloc_or_die(8 * sizeof(*rows));
|
||||
char *start = copy_string(pattern);
|
||||
char *end = start;
|
||||
/* Isolate each row in its new order. */
|
||||
int row;
|
||||
for(row = BOARDSIZE - 1; row >= 0 && *start != '\0'; row--) {
|
||||
/* Find the end of the next row. */
|
||||
while(*end != '/' && *end != '\0') {
|
||||
end++;
|
||||
}
|
||||
rows[row] = (char *) malloc_or_die((end - start + 1) * sizeof(**rows));
|
||||
strncpy(rows[row], start, end - start);
|
||||
rows[row][end - start] = '\0';
|
||||
start = end;
|
||||
if(*start != '\0') {
|
||||
start++;
|
||||
}
|
||||
end++;
|
||||
}
|
||||
char *reversed = (char *) malloc_or_die(strlen(pattern) + 1);
|
||||
/* Copy across the rows, flipping the colours. */
|
||||
char *nextchar = reversed;
|
||||
for(row = 0; row < 8; row++) {
|
||||
const char *text = rows[row];
|
||||
while(*text != '\0') {
|
||||
if(isalpha(*text)) {
|
||||
if(islower(*text)) {
|
||||
*nextchar = toupper(*text);
|
||||
}
|
||||
else {
|
||||
*nextchar = tolower(*text);
|
||||
}
|
||||
}
|
||||
else {
|
||||
*nextchar = *text;
|
||||
}
|
||||
text++;
|
||||
nextchar++;
|
||||
}
|
||||
if(row != BOARDSIZE - 1) {
|
||||
*nextchar = '/';
|
||||
nextchar++;
|
||||
}
|
||||
}
|
||||
*nextchar = '\0';
|
||||
return reversed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert the ranks of a single pattern into the current pattern tree
|
||||
* to consolidate similar patterns.
|
||||
*/
|
||||
static void
|
||||
pattern_tree_insert(char **ranks, const char *label, Material_details *constraint)
|
||||
{
|
||||
FENPatternMatch *match = (FENPatternMatch *) malloc_or_die(sizeof(*match));
|
||||
/* Create a linked list for the ranks.
|
||||
* Place the label in the final link.
|
||||
*/
|
||||
FENPatternMatch *next = match;
|
||||
for(int i = 0; i < BOARDSIZE; i++) {
|
||||
next->rank = ranks[i];
|
||||
next->alternative_rank = NULL;
|
||||
if(i != BOARDSIZE - 1) {
|
||||
next->next_rank = (FENPatternMatch *) malloc_or_die(sizeof(*match));
|
||||
next->optional_label = NULL;
|
||||
next->constraint = NULL;
|
||||
next = next->next_rank;
|
||||
}
|
||||
else {
|
||||
next->next_rank = NULL;
|
||||
next->optional_label = label;
|
||||
next->constraint = constraint;
|
||||
}
|
||||
}
|
||||
if(pattern_tree == NULL) {
|
||||
pattern_tree = match;
|
||||
}
|
||||
else {
|
||||
/* Find the place to insert this list in the existing tree. */
|
||||
insert_pattern(pattern_tree, match);
|
||||
}
|
||||
}
|
||||
|
||||
/* Starting at node, try to insert next into the tree.
|
||||
* Return TRUE on success, FALSE on failure.
|
||||
*/
|
||||
static void
|
||||
insert_pattern(FENPatternMatch *node, FENPatternMatch *next)
|
||||
{
|
||||
Boolean inserted = FALSE;
|
||||
while(!inserted && strcmp(node->rank, next->rank) == 0) {
|
||||
if(node->next_rank != NULL) {
|
||||
/* Same pattern. Move to the next rank of both. */
|
||||
node = node->next_rank;
|
||||
next = next->next_rank;
|
||||
}
|
||||
else {
|
||||
/* Patterns are duplicates. */
|
||||
fprintf(GlobalState.logfile, "Warning: duplicate FEN patterns detected.\n");
|
||||
inserted = TRUE;
|
||||
}
|
||||
}
|
||||
if(!inserted) {
|
||||
/* Insert as an alternative. */
|
||||
if(node->alternative_rank != NULL) {
|
||||
insert_pattern(node->alternative_rank, next);
|
||||
}
|
||||
else {
|
||||
node->alternative_rank = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to match the board against one of the FEN patterns.
|
||||
* Return NULL if no match, otherwise a possible label for the
|
||||
* match to be added to the game's tags. An empty string is
|
||||
* used for no label.
|
||||
*/
|
||||
const char *
|
||||
pattern_match_board(const Board *board)
|
||||
{
|
||||
const char *match_label = NULL;
|
||||
if(pattern_tree != NULL) {
|
||||
/* Don't convert any ranks of the board until they
|
||||
* are required.
|
||||
*/
|
||||
char ranks[BOARDSIZE+1][BOARDSIZE+1];
|
||||
for(int i = 0; i < BOARDSIZE; i++) {
|
||||
ranks[i][0] = '\0';
|
||||
}
|
||||
match_label = pattern_match_rank(board, pattern_tree, 0, ranks);
|
||||
}
|
||||
return match_label;
|
||||
}
|
||||
|
||||
|
||||
/* Match ranks[patternIndex ...] against board.
|
||||
* return the corresponding match label if a match is found.
|
||||
* Return NULL if no match is found.
|
||||
*/
|
||||
static const char *pattern_match_rank(const Board *board, FENPatternMatch *pattern, int patternIndex, char ranks[BOARDSIZE+1][BOARDSIZE+1])
|
||||
{
|
||||
const char *match_label = NULL;
|
||||
if(ranks[patternIndex][0] == '\0') {
|
||||
/* Convert the required rank.
|
||||
* Convert the others when/if needed.
|
||||
*/
|
||||
convert_rank_to_text(board, LASTRANK - patternIndex, ranks[patternIndex]);
|
||||
}
|
||||
while(match_label == NULL && pattern != NULL) {
|
||||
if(matchhere(pattern->rank, ranks[patternIndex])) {
|
||||
if(patternIndex == BOARDSIZE - 1) {
|
||||
/* The board matches the pattern. */
|
||||
if(pattern->constraint != NULL) {
|
||||
if(constraint_material_match(pattern->constraint, board)) {
|
||||
match_label = pattern->optional_label;
|
||||
}
|
||||
}
|
||||
else {
|
||||
match_label = pattern->optional_label;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Try next rank.*/
|
||||
match_label = pattern_match_rank(board, pattern->next_rank, patternIndex + 1, ranks);
|
||||
}
|
||||
}
|
||||
|
||||
if(match_label == NULL) {
|
||||
pattern = pattern->alternative_rank;
|
||||
}
|
||||
}
|
||||
return match_label;
|
||||
}
|
||||
|
||||
/**
|
||||
* matchhere: search for regexp at beginning of text
|
||||
*/
|
||||
static Boolean
|
||||
matchhere(const char *regexp, const char *text)
|
||||
{
|
||||
if (regexp[0] == '\0' && text[0] == '\0') {
|
||||
return TRUE;
|
||||
}
|
||||
if (regexp[0] == ZERO_OR_MORE_OF_ANYTHING) {
|
||||
return matchstar(regexp + 1, text);
|
||||
}
|
||||
if (*text != '\0') {
|
||||
switch (*regexp) {
|
||||
case ANY_SQUARE_STATE:
|
||||
return matchhere(regexp + 1, text + 1);
|
||||
break;
|
||||
case NON_EMPTY_SQUARE:
|
||||
case ANY_WHITE_PIECE:
|
||||
case ANY_BLACK_PIECE:
|
||||
case NOT_A_PAWN:
|
||||
if (matchone(*regexp, *text)) {
|
||||
return matchhere(regexp + 1, text + 1);
|
||||
}
|
||||
break;
|
||||
case CCL_START:
|
||||
/* Closure */
|
||||
if (regexp[1] == NCCL) {
|
||||
return matchnccl(regexp + 2, text);
|
||||
}
|
||||
else {
|
||||
return matchccl(regexp + 1, text);
|
||||
}
|
||||
break;
|
||||
case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8':
|
||||
{
|
||||
/* The number of empty squares required. */
|
||||
int empty = regexp[0] - '0';
|
||||
Boolean matches = TRUE;
|
||||
/* The number matched. */
|
||||
int match_count = 0;
|
||||
while (matches && match_count < empty) {
|
||||
if (text[match_count] == EMPTY_SQUARE) {
|
||||
match_count++;
|
||||
}
|
||||
else {
|
||||
matches = FALSE;
|
||||
}
|
||||
}
|
||||
if (matches) {
|
||||
return matchhere(regexp + 1, text + match_count);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (*regexp == *text) {
|
||||
return matchhere(regexp + 1, text + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* No match. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* matchstar: leftmost longest search on a single rank.
|
||||
*/
|
||||
static Boolean
|
||||
matchstar(const char *regexp, const char *text)
|
||||
{
|
||||
const char *t;
|
||||
|
||||
/* Find the end of this rank. */
|
||||
for (t = text; *t != '\0'; t++) {
|
||||
;
|
||||
}
|
||||
/* Try from the longest match to the shortest until success. */
|
||||
do {
|
||||
/* * matches zero or more */
|
||||
if (matchhere(regexp, t)) {
|
||||
return TRUE;
|
||||
}
|
||||
} while (t-- > text);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if regchar matches textchar, FALSE otherwise.
|
||||
*/
|
||||
static Boolean
|
||||
matchone(char regchar, char textchar)
|
||||
{
|
||||
if (regchar == textchar) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
switch (regchar) {
|
||||
case NON_EMPTY_SQUARE:
|
||||
return textchar != EMPTY_SQUARE;
|
||||
case ANY_WHITE_PIECE:
|
||||
/* Match any white piece. */
|
||||
switch (textchar) {
|
||||
case 'K':
|
||||
case 'Q':
|
||||
case 'R':
|
||||
case 'N':
|
||||
case 'B':
|
||||
case 'P':
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
case ANY_BLACK_PIECE:
|
||||
/* Match any black piece. */
|
||||
switch (textchar) {
|
||||
case 'k':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 'n':
|
||||
case 'b':
|
||||
case 'p':
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
case ANY_SQUARE_STATE:
|
||||
return TRUE;
|
||||
case NOT_A_PAWN:
|
||||
switch(textchar) {
|
||||
case 'P':
|
||||
case 'p':
|
||||
return FALSE;
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Match any of the character closure.
|
||||
*/
|
||||
static Boolean
|
||||
matchccl(const char *regexp, const char *text)
|
||||
{
|
||||
while (*regexp != CCL_END &&
|
||||
!matchone(*regexp, *text) && *regexp != '\0') {
|
||||
regexp++;
|
||||
}
|
||||
if (matchone(*regexp, *text)) {
|
||||
do {
|
||||
regexp++;
|
||||
} while (*regexp != CCL_END && *regexp != '\0');
|
||||
return matchhere(regexp + 1, text + 1);
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Match any of the characters not in the closure.
|
||||
*/
|
||||
static Boolean
|
||||
matchnccl(const char *regexp, const char *text)
|
||||
{
|
||||
while (*regexp != CCL_END &&
|
||||
!matchone(*regexp, *text) && *regexp != '\0') {
|
||||
regexp++;
|
||||
}
|
||||
if (*regexp == CCL_END) {
|
||||
return matchhere(regexp + 1, text + 1);
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Build a basic EPD string from the given board. */
|
||||
static char *
|
||||
convert_board_to_text(const Board *board)
|
||||
{
|
||||
Rank rank;
|
||||
int ix = 0;
|
||||
/* Allow space for a full board and '/' separators in between. */
|
||||
char *text = (char *) malloc_or_die(8 * 8 + 8);
|
||||
for (rank = LASTRANK; rank >= FIRSTRANK; rank--) {
|
||||
const Piece *rankP = board->board[RankConvert(rank)];
|
||||
Col col;
|
||||
for (col = FIRSTCOL; col <= LASTCOL; col++) {
|
||||
int coloured_piece = rankP[ColConvert(col)];
|
||||
if (coloured_piece != EMPTY) {
|
||||
text[ix] = coloured_piece_to_SAN_letter(coloured_piece);
|
||||
}
|
||||
else {
|
||||
text[ix] = EMPTY_SQUARE;
|
||||
}
|
||||
ix++;
|
||||
}
|
||||
if (rank != FIRSTRANK) {
|
||||
text[ix] = '/';
|
||||
ix++;
|
||||
}
|
||||
}
|
||||
text[ix] = '\0';
|
||||
return text;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Build a basic EPD string from rank of the given board. */
|
||||
static void
|
||||
convert_rank_to_text(const Board *board, Rank rank, char *text)
|
||||
{
|
||||
const Piece *rankP = board->board[RankConvert(rank)];
|
||||
int ix = 0;
|
||||
Col col;
|
||||
for (col = FIRSTCOL; col <= LASTCOL; col++) {
|
||||
int coloured_piece = rankP[ColConvert(col)];
|
||||
if (coloured_piece != EMPTY) {
|
||||
text[ix] = coloured_piece_to_SAN_letter(coloured_piece);
|
||||
}
|
||||
else {
|
||||
text[ix] = EMPTY_SQUARE;
|
||||
}
|
||||
ix++;
|
||||
}
|
||||
text[ix] = '\0';
|
||||
}
|
29
pgn-extract/fenmatcher.h
Normal file
29
pgn-extract/fenmatcher.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#ifndef FENMATCHER_H
|
||||
#define FENMATCHER_H
|
||||
|
||||
void add_fen_pattern(const char *fen_pattern, Boolean add_reverse, const char *label);
|
||||
const char *pattern_match_board(const Board *board);
|
||||
|
||||
#endif // FENMATCHER_H
|
||||
|
1426
pgn-extract/grammar.c
Normal file
1426
pgn-extract/grammar.c
Normal file
File diff suppressed because it is too large
Load Diff
36
pgn-extract/grammar.h
Normal file
36
pgn-extract/grammar.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#ifndef GRAMMAR_H
|
||||
#define GRAMMAR_H
|
||||
|
||||
int yyparse(SourceFileType file_type);
|
||||
void free_string_list(StringList *list);
|
||||
void init_game_header(void);
|
||||
void increase_game_header_tags_length(unsigned new_length);
|
||||
void report_details(FILE *outfp);
|
||||
void append_comments_to_move(Move *move,CommentList *Comment);
|
||||
/* The following function is used for linking list items together. */
|
||||
StringList *save_string_list_item(StringList *list,const char *str);
|
||||
void free_comment_list(CommentList *comment_list);
|
||||
|
||||
#endif // GRAMMAR_H
|
||||
|
604
pgn-extract/hashing.c
Normal file
604
pgn-extract/hashing.c
Normal file
@@ -0,0 +1,604 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
/* For unlink() */
|
||||
#include <io.h>
|
||||
#else
|
||||
/* For unlink() */
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "bool.h"
|
||||
#include "mymalloc.h"
|
||||
#include "defs.h"
|
||||
#include "typedef.h"
|
||||
#include "tokens.h"
|
||||
#include "taglist.h"
|
||||
#include "lex.h"
|
||||
#include "hashing.h"
|
||||
#include "zobrist.h"
|
||||
|
||||
/* Routines, similar in nature to those in apply.c
|
||||
* to implement a duplicate hash-table lookup using
|
||||
* an external file, rather than malloc'd memory.
|
||||
* The only limit should be a file system limit.
|
||||
* NB: Using an external, virtual file seems obsolete now.
|
||||
*
|
||||
* This version should be slightly more accurate than
|
||||
* the alternative because the final_ and cumulative_
|
||||
* hash values are both stored, rather than the XOR
|
||||
* of them.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The name of the file used.
|
||||
* This is overwritten each time, and removed on normal
|
||||
* program exit.
|
||||
*/
|
||||
static char VIRTUAL_FILE[] = "virtual.tmp";
|
||||
|
||||
/* Define the size of the hash table.
|
||||
*/
|
||||
#define LOG_TABLE_SIZE 100003
|
||||
|
||||
/* Define a table to hold hash values of the extracted games.
|
||||
* This is used to enable duplicate detection.
|
||||
*/
|
||||
typedef struct {
|
||||
/* Record the file offset of the first and last entries
|
||||
* for an index. (head == -1) => empty.
|
||||
*/
|
||||
long head, tail;
|
||||
} LogHeaderEntry;
|
||||
|
||||
/* If use_virtual_hash_table */
|
||||
static LogHeaderEntry *VirtualLogTable = NULL;
|
||||
|
||||
/* Define a table to hold hash values of the extracted games.
|
||||
* This is used to enable duplicate detection when not using
|
||||
* the virtual hash table.
|
||||
*/
|
||||
static HashLog **LogTable = NULL;
|
||||
|
||||
/* Define a type to hold hash values of interest.
|
||||
* This is used both to aid in duplicate detection
|
||||
* and in finding positional variations.
|
||||
*/
|
||||
typedef struct VirtualHashLog {
|
||||
/* Store the final position hash value and
|
||||
* the cumulative hash value for a game.
|
||||
*/
|
||||
HashCode final_hash_value, cumulative_hash_value;
|
||||
/* Record the file list index for the file this game was first found in. */
|
||||
int file_number;
|
||||
/* Record the file offset of the next element
|
||||
* in this list. -1 => end-of-list.
|
||||
*/
|
||||
long next;
|
||||
} VirtualHashLog;
|
||||
|
||||
static FILE *hash_file = NULL;
|
||||
|
||||
static const char *previous_virtual_occurance(Game game_details);
|
||||
|
||||
/*
|
||||
* Check whether the position counts indicate a desired repetition.
|
||||
* If we are checking for repetition return TRUE if it does and FALSE otherwise.
|
||||
* If we are not then return TRUE.
|
||||
*/
|
||||
Boolean check_for_only_repetition(PositionCount *position_counts)
|
||||
{
|
||||
if (GlobalState.check_for_repetition > 0) {
|
||||
PositionCount *entry = position_counts;
|
||||
while (entry != NULL && entry->count < GlobalState.check_for_repetition) {
|
||||
entry = entry->next;
|
||||
}
|
||||
return entry != NULL;
|
||||
}
|
||||
else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode the castling rights of the current board
|
||||
* as a 4-bit pattern.
|
||||
*/
|
||||
static unsigned short
|
||||
encode_castling_rights(const Board *board)
|
||||
{
|
||||
unsigned short rights = 0;
|
||||
if(board->WKingCastle) {
|
||||
rights |= 0x08;
|
||||
}
|
||||
if(board->WQueenCastle) {
|
||||
rights |= 0x04;
|
||||
}
|
||||
if(board->BKingCastle) {
|
||||
rights |= 0x02;
|
||||
}
|
||||
if(board->BQueenCastle) {
|
||||
rights |= 0x01;
|
||||
}
|
||||
return rights;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if the position on board matches the entry details
|
||||
* for the purposes of position repetition matches:
|
||||
* + Same board position (based on a hash value)
|
||||
* + Same castling rights.
|
||||
* + Same en passant status (i.e., no ep possible).
|
||||
* + Same player to move.
|
||||
*/
|
||||
static Boolean
|
||||
position_matches(PositionCount *entry, const Board *board)
|
||||
{
|
||||
if(board->weak_hash_value != entry->hash_value) {
|
||||
return FALSE;
|
||||
}
|
||||
else if(board->to_move != entry->to_move) {
|
||||
return FALSE;
|
||||
}
|
||||
else if(encode_castling_rights(board) != entry->castling_rights) {
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
if(board->EnPassant) {
|
||||
return board->ep_rank == entry->ep_rank && board->ep_col == entry->ep_col;
|
||||
}
|
||||
else {
|
||||
return entry->ep_rank == '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add hash_value as a position in the current game.
|
||||
* Return the number of times this position has occurred.
|
||||
* NB: The assumption is that position_counts is not NULL.
|
||||
*/
|
||||
unsigned
|
||||
update_position_counts(PositionCount *position_counts, const Board *board)
|
||||
{
|
||||
//fprintf(stderr, "U: %d,%d\n", board->ep_rank, board->ep_col);
|
||||
PositionCount *entry = position_counts;
|
||||
if (position_counts == NULL) {
|
||||
/* Don't try to match in variations. */
|
||||
return 0;
|
||||
}
|
||||
/* Try to find an existing entry. */
|
||||
while (entry != NULL && !position_matches(entry, board)) {
|
||||
entry = entry->next;
|
||||
}
|
||||
if (entry == NULL) {
|
||||
/* New position. */
|
||||
entry = new_position_count_list(board);
|
||||
/* Insert just after the head of the list. */
|
||||
entry->next = position_counts->next;
|
||||
position_counts->next = entry;
|
||||
}
|
||||
else {
|
||||
/* Increment the count. */
|
||||
entry->count++;
|
||||
}
|
||||
return entry->count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the list of position counts.
|
||||
*/
|
||||
void
|
||||
free_position_count_list(PositionCount *position_counts)
|
||||
{
|
||||
PositionCount *entry = position_counts;
|
||||
while (entry != NULL) {
|
||||
PositionCount *next = entry->next;
|
||||
(void) free((void *) entry);
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new position count list.
|
||||
* This will have a single entry at its head.
|
||||
*/
|
||||
PositionCount *
|
||||
new_position_count_list(const Board *board)
|
||||
{
|
||||
PositionCount *head = (PositionCount *) malloc_or_die(sizeof (*head));
|
||||
head->hash_value = board->weak_hash_value;
|
||||
head->to_move = board->to_move;
|
||||
head->castling_rights = encode_castling_rights(board);
|
||||
if(board->EnPassant) {
|
||||
head->ep_rank = board->ep_rank;
|
||||
head->ep_col = board->ep_col;
|
||||
}
|
||||
else {
|
||||
head->ep_rank = '\0';
|
||||
head->ep_col = '\0';
|
||||
}
|
||||
head->count = 1;
|
||||
head->next = NULL;
|
||||
return head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an identical copy of the given list.
|
||||
*/
|
||||
PositionCount *copy_position_count_list(PositionCount *original)
|
||||
{
|
||||
PositionCount *copy = NULL;
|
||||
PositionCount *tail = NULL;
|
||||
while (original != NULL) {
|
||||
PositionCount *entry = (PositionCount *) malloc_or_die(sizeof (*entry));
|
||||
entry->hash_value = original->hash_value;
|
||||
entry->to_move = original->to_move;
|
||||
entry->castling_rights = original->castling_rights;
|
||||
entry->count = original->count;
|
||||
entry->next = NULL;
|
||||
|
||||
if (copy == NULL) {
|
||||
copy = entry;
|
||||
}
|
||||
else {
|
||||
tail->next = entry;
|
||||
}
|
||||
tail = entry;
|
||||
original = original->next;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/* Determine which table to initialise, depending
|
||||
* on whether use_virtual_hash_table is set or not.
|
||||
*/
|
||||
void
|
||||
init_duplicate_hash_table(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (GlobalState.use_virtual_hash_table) {
|
||||
VirtualLogTable = (LogHeaderEntry *)
|
||||
malloc_or_die(LOG_TABLE_SIZE * sizeof (*VirtualLogTable));
|
||||
for (i = 0; i < LOG_TABLE_SIZE; i++) {
|
||||
VirtualLogTable[i].head = VirtualLogTable[i].tail = -1;
|
||||
}
|
||||
hash_file = fopen(VIRTUAL_FILE, "w+b");
|
||||
if (hash_file == NULL) {
|
||||
fprintf(GlobalState.logfile, "Unable to open %s\n",
|
||||
VIRTUAL_FILE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogTable = (HashLog**) malloc_or_die(LOG_TABLE_SIZE * sizeof (*LogTable));
|
||||
for (i = 0; i < LOG_TABLE_SIZE; i++) {
|
||||
LogTable[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Close and remove the temporary file if in use. */
|
||||
void
|
||||
clear_duplicate_hash_table(void)
|
||||
{
|
||||
if (GlobalState.use_virtual_hash_table) {
|
||||
if (hash_file != NULL) {
|
||||
(void) fclose(hash_file);
|
||||
unlink(VIRTUAL_FILE);
|
||||
hash_file = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Retrieve a duplicate table entry from the hash file. */
|
||||
static int
|
||||
retrieve_virtual_entry(long ix, VirtualHashLog *entry)
|
||||
{
|
||||
if (hash_file == NULL) {
|
||||
return 0;
|
||||
}
|
||||
else if (fseek(hash_file, ix, SEEK_SET) != 0) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Fseek error to %ld in retrieve_virtual_entry\n", ix);
|
||||
return 0;
|
||||
}
|
||||
else if (fread((void *) entry, sizeof (*entry), 1, hash_file) != 1) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Fread error from %ld in retrieve_virtual_entry\n", ix);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a duplicate table entry to the hash file. */
|
||||
static int
|
||||
write_virtual_entry(long where, const VirtualHashLog *entry)
|
||||
{
|
||||
if (fseek(hash_file, where, SEEK_SET) != 0) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Fseek error to %ld in write_virtual_entry\n", where);
|
||||
return 0;
|
||||
}
|
||||
else if (fwrite((void *) entry, sizeof (*entry), 1, hash_file) != 1) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Fwrite error from %ld in write_virtual_entry\n", where);
|
||||
fflush(hash_file);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* Written ok. */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the name of the original file if it looks like we
|
||||
* have met the moves in game_details before, otherwise return
|
||||
* NULL. A match is assumed to be so if both
|
||||
* the final_ and cumulative_ hash values in game_details
|
||||
* are already present in VirtualLogTable.
|
||||
*/
|
||||
static const char *
|
||||
previous_virtual_occurance(Game game_details)
|
||||
{
|
||||
unsigned ix = game_details.final_hash_value % LOG_TABLE_SIZE;
|
||||
VirtualHashLog entry;
|
||||
Boolean duplicate = FALSE;
|
||||
const char *original_filename = NULL;
|
||||
|
||||
|
||||
/* Are we keeping this information? */
|
||||
if (GlobalState.suppress_duplicates || GlobalState.suppress_originals ||
|
||||
GlobalState.duplicate_file != NULL) {
|
||||
if (VirtualLogTable[ix].head < 0l) {
|
||||
/* First occurrence. */
|
||||
}
|
||||
else {
|
||||
int keep_going =
|
||||
retrieve_virtual_entry(VirtualLogTable[ix].head, &entry);
|
||||
|
||||
while (keep_going && !duplicate) {
|
||||
if ((entry.final_hash_value == game_details.final_hash_value) &&
|
||||
(entry.cumulative_hash_value == game_details.cumulative_hash_value)) {
|
||||
/* We have a match.
|
||||
* Determine where it first occured.
|
||||
*/
|
||||
original_filename = input_file_name(entry.file_number);
|
||||
duplicate = TRUE;
|
||||
}
|
||||
else if (entry.next >= 0l) {
|
||||
keep_going = retrieve_virtual_entry(entry.next, &entry);
|
||||
}
|
||||
else {
|
||||
keep_going = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!duplicate) {
|
||||
/* Write an entry for it. */
|
||||
/* Where to write the next VirtualHashLog entry. */
|
||||
static long next_free_entry = 0l;
|
||||
|
||||
/* Avoid valgrind error when writing unset bytes that
|
||||
* are part of the structure padding.
|
||||
*/
|
||||
memset((void *) &entry, 0, sizeof(entry));
|
||||
/* Store the XOR of the two hash values. */
|
||||
entry.final_hash_value = game_details.final_hash_value;
|
||||
entry.cumulative_hash_value = game_details.cumulative_hash_value;
|
||||
entry.file_number = current_file_number();
|
||||
entry.next = -1l;
|
||||
|
||||
/* Write out these details. */
|
||||
if (write_virtual_entry(next_free_entry, &entry)) {
|
||||
long where_written = next_free_entry;
|
||||
/* Move on ready for next time. */
|
||||
next_free_entry += sizeof (entry);
|
||||
|
||||
/* Now update the index table. */
|
||||
if (VirtualLogTable[ix].head < 0l) {
|
||||
/* First occurrence. */
|
||||
VirtualLogTable[ix].head =
|
||||
VirtualLogTable[ix].tail = where_written;
|
||||
}
|
||||
else {
|
||||
VirtualHashLog tail;
|
||||
|
||||
if (retrieve_virtual_entry(VirtualLogTable[ix].tail, &tail)) {
|
||||
tail.next = where_written;
|
||||
(void) write_virtual_entry(VirtualLogTable[ix].tail, &tail);
|
||||
/* Store the new tail address. */
|
||||
VirtualLogTable[ix].tail = where_written;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return original_filename;
|
||||
}
|
||||
|
||||
/* Return the name of the original file if it looks like we
|
||||
* have met the moves in game_details before, otherwise return
|
||||
* NULL.
|
||||
* For non-fuzzy comparison, a match is assumed to be so if both
|
||||
* final_ and cumulative_ hash values are already present
|
||||
* as a pair in LogTable.
|
||||
* Fuzzy matches depend on the match depth and do not use the
|
||||
* cumulative hash value.
|
||||
*/
|
||||
const char *
|
||||
previous_occurance(Game game_details, unsigned plycount)
|
||||
{
|
||||
const char *original_filename = NULL;
|
||||
if (GlobalState.use_virtual_hash_table) {
|
||||
original_filename = previous_virtual_occurance(game_details);
|
||||
}
|
||||
else {
|
||||
/* Are we keeping this information? */
|
||||
if (GlobalState.suppress_duplicates ||
|
||||
GlobalState.suppress_originals ||
|
||||
GlobalState.fuzzy_match_duplicates ||
|
||||
GlobalState.duplicate_file != NULL) {
|
||||
Boolean duplicate = FALSE;
|
||||
// Entry index.
|
||||
unsigned ix;
|
||||
HashLog *entry;
|
||||
|
||||
ix = game_details.final_hash_value % LOG_TABLE_SIZE;
|
||||
entry = LogTable[ix];
|
||||
/* Check for non-fuzzy matches first. */
|
||||
while (entry != NULL && !duplicate) {
|
||||
if (entry->final_hash_value == game_details.final_hash_value &&
|
||||
entry->cumulative_hash_value == game_details.cumulative_hash_value) {
|
||||
/* An exact match. */
|
||||
duplicate = TRUE;
|
||||
/* Determine where it first occurred. */
|
||||
original_filename = input_file_name(entry->file_number);
|
||||
}
|
||||
else {
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
if (!duplicate && GlobalState.fuzzy_match_duplicates) {
|
||||
ix = game_details.fuzzy_duplicate_hash % LOG_TABLE_SIZE;
|
||||
entry = LogTable[ix];
|
||||
while (entry != NULL && !duplicate) {
|
||||
if (GlobalState.fuzzy_match_depth == 0 &&
|
||||
entry->final_hash_value == game_details.final_hash_value) {
|
||||
/* Accept positional match at the end of the game. */
|
||||
duplicate = TRUE;
|
||||
}
|
||||
else {
|
||||
/* Need to check at the fuzzy_match_depth. */
|
||||
if (entry->final_hash_value == game_details.fuzzy_duplicate_hash) {
|
||||
duplicate = TRUE;
|
||||
}
|
||||
}
|
||||
if (duplicate) {
|
||||
/* We have a match.
|
||||
* Determine where it first occurred.
|
||||
*/
|
||||
original_filename = input_file_name(entry->file_number);
|
||||
}
|
||||
else {
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!duplicate) {
|
||||
/* First occurrence, so add it to the log. */
|
||||
entry = (HashLog *) malloc_or_die(sizeof (*entry));
|
||||
|
||||
if (!GlobalState.fuzzy_match_duplicates) {
|
||||
/* Store the two hash values. */
|
||||
entry->final_hash_value = game_details.final_hash_value;
|
||||
entry->cumulative_hash_value = game_details.cumulative_hash_value;
|
||||
}
|
||||
else if (GlobalState.fuzzy_match_depth > 0 &&
|
||||
plycount >= GlobalState.fuzzy_match_depth) {
|
||||
/* Store just the hash value from the fuzzy depth. */
|
||||
entry->final_hash_value = game_details.fuzzy_duplicate_hash;
|
||||
entry->cumulative_hash_value = 0;
|
||||
}
|
||||
else {
|
||||
/* Store the two hash values. */
|
||||
entry->final_hash_value = game_details.final_hash_value;
|
||||
entry->cumulative_hash_value = game_details.cumulative_hash_value;
|
||||
}
|
||||
entry->file_number = current_file_number();
|
||||
/* Link it into the head at this index. */
|
||||
entry->next = LogTable[ix];
|
||||
LogTable[ix] = entry;
|
||||
}
|
||||
/* Without a filename, suppressing duplicates on stdin does not work. */
|
||||
if(duplicate && original_filename == NULL) {
|
||||
original_filename = "_stdin_";
|
||||
}
|
||||
}
|
||||
}
|
||||
return original_filename;
|
||||
}
|
||||
|
||||
/* Define a table to hold the zobrist/polyglot hash codes of starting positions.
|
||||
* Size should be a prime number for collision avoidance.
|
||||
*/
|
||||
#define SETUP_TABLE_SIZE 31957
|
||||
static HashLog *polyglot_codes_of_interest[SETUP_TABLE_SIZE];
|
||||
/* Whether the standard starting position has been seen in the
|
||||
* games processed. This avoids having to generate the zobrist
|
||||
* hash for all games that have no Setup/FEN tags.
|
||||
*/
|
||||
static Boolean standard_start_seen = FALSE;
|
||||
|
||||
/* Check whether the starting position of the given game
|
||||
* has been met before.
|
||||
* Return FALSE if duplicate starting positions are not being
|
||||
* deleted or if the current position has not been met before.
|
||||
* Otherwise return TRUE.
|
||||
*/
|
||||
Boolean check_duplicate_setup(const Game *game_details)
|
||||
{
|
||||
Boolean keep = TRUE;
|
||||
if(GlobalState.delete_same_setup) {
|
||||
if(game_details->tags[FEN_TAG] != NULL) {
|
||||
uint64_t hash = generate_zobrist_hash_from_fen(game_details->tags[FEN_TAG]);
|
||||
unsigned ix = hash % SETUP_TABLE_SIZE;
|
||||
Boolean found = FALSE;
|
||||
for (HashLog *entry = polyglot_codes_of_interest[ix]; !found && (entry != NULL);
|
||||
entry = entry->next) {
|
||||
/* We can test against just the position value. */
|
||||
if (entry->final_hash_value == hash) {
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
if(found) {
|
||||
keep = FALSE;
|
||||
}
|
||||
else {
|
||||
HashLog *entry = (HashLog *) malloc_or_die(sizeof (*entry));
|
||||
/* We don't include the cumulative hash value as this
|
||||
* is the starting position.
|
||||
*/
|
||||
entry->cumulative_hash_value = 0;
|
||||
entry->final_hash_value = hash;
|
||||
/* Link it into the head at this index. */
|
||||
entry->next = polyglot_codes_of_interest[ix];
|
||||
polyglot_codes_of_interest[ix] = entry;
|
||||
}
|
||||
}
|
||||
else if(standard_start_seen) {
|
||||
keep = FALSE;
|
||||
}
|
||||
else {
|
||||
standard_start_seen = TRUE;
|
||||
}
|
||||
}
|
||||
return keep;
|
||||
}
|
||||
|
66
pgn-extract/hashing.h
Normal file
66
pgn-extract/hashing.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
/* Define a type to hold hash values of interest.
|
||||
* This is used both to aid in duplicate detection
|
||||
* and in finding positional variations.
|
||||
*/
|
||||
#ifndef HASHING_H
|
||||
#define HASHING_H
|
||||
|
||||
typedef struct HashLog {
|
||||
/* Store both the final position hash value and
|
||||
* the cumulative hash value for a game.
|
||||
*/
|
||||
HashCode final_hash_value;
|
||||
HashCode cumulative_hash_value;
|
||||
/* Record the file list index for the file this game was first found in. */
|
||||
unsigned file_number;
|
||||
struct HashLog *next;
|
||||
} HashLog;
|
||||
|
||||
/*
|
||||
* A structure for counting the number of times a position arises
|
||||
* in a game.
|
||||
*/
|
||||
typedef struct PositionCount {
|
||||
HashCode hash_value;
|
||||
Colour to_move;
|
||||
unsigned short castling_rights;
|
||||
Rank ep_rank;
|
||||
Col ep_col;
|
||||
unsigned count;
|
||||
struct PositionCount *next;
|
||||
} PositionCount;
|
||||
|
||||
|
||||
Boolean check_duplicate_setup(const Game *game_details);
|
||||
Boolean check_for_only_repetition(PositionCount *position_counts);
|
||||
void clear_duplicate_hash_table(void);
|
||||
PositionCount *copy_position_count_list(PositionCount *original);
|
||||
void free_position_count_list(PositionCount *position_counts);
|
||||
void init_duplicate_hash_table(void);
|
||||
PositionCount *new_position_count_list(const Board *board);
|
||||
const char *previous_occurance(Game game_details, unsigned plycount);
|
||||
unsigned update_position_counts(PositionCount *position_counts, const Board *board);
|
||||
|
||||
#endif // HASHING_H
|
||||
|
2422
pgn-extract/help.html
Normal file
2422
pgn-extract/help.html
Normal file
File diff suppressed because it is too large
Load Diff
217
pgn-extract/index.html
Normal file
217
pgn-extract/index.html
Normal file
@@ -0,0 +1,217 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>pgn-extract: Portable Game Notation (PGN) Manipulator for Chess Games</title>
|
||||
<link rev="made" href="mailto:d.j.barnes @ kent.ac.uk">
|
||||
<meta name="Author" content="David J. Barnes">
|
||||
<meta name="Description"
|
||||
CONTENT="Directory with source of program to manipulate
|
||||
chess games recorded in Portable Game Notation (PGN)
|
||||
format">
|
||||
<meta name="Keywords" content="Chess PGN Portable Game Notation
|
||||
Database
|
||||
pgn-extract">
|
||||
<link href="style.css" rel="stylesheet" type="text/css" media="all">
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-2248758-2"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'UA-2248758-2');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body">
|
||||
|
||||
<div id="banner-wrapper">
|
||||
<div id="banner">
|
||||
<h1 align="center">pgn-extract:<br />A Portable Game Notation (PGN) Manipulator for Chess Games<br />
|
||||
Version 22-11 by <a href="https://www.cs.kent.ac.uk/~djb/">David J. Barnes</a>
|
||||
(<a href="https://twitter.com/kentdjb">@kentdjb</a>)<br />
|
||||
<a href="pgn-extract.xml">
|
||||
<img alt="RSS feed image" src="feed.png" width="25" height="25"></a>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="page-wrapper">
|
||||
<div id="page">
|
||||
<h2>Introduction</h2>
|
||||
<p>This is the home page for
|
||||
the <em>pgn-extract</em> program,
|
||||
which is a <em>command-line</em> program for searching, manipulating and formatting
|
||||
chess games recorded in the Portable Game Notation (PGN) or something close. It
|
||||
is capable of handling files containing millions of games. It also recognises Chess960
|
||||
encodings.
|
||||
<p>A <a href="https://www.cs.kent.ac.uk/people/staff/djb/pgn-extract/help.html">full
|
||||
description of pgn-extract's functionality</a> is available and included
|
||||
with the sources.
|
||||
|
||||
<p>Here you can find the C source code and Windows binaries for the current
|
||||
version.
|
||||
pgn-extract compiles and runs under Windows, Linux and Mac OS X.
|
||||
This program is made available under the terms of the
|
||||
<a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/COPYING">GNU
|
||||
General Public License (Version 3).</a>
|
||||
|
||||
<h2>Getting-started video for Windows users</h2>
|
||||
<p>For Windows users who are really only interested in getting
|
||||
the binary working, there is <a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/intro.mp4">a short introductory video</a>.
|
||||
|
||||
<h2>Overview</h2>
|
||||
<p>The program is designed to make it easy to extract and format selected games from a
|
||||
PGN format data file based on a wide variety of criteria.
|
||||
The criteria include:
|
||||
<ul>
|
||||
<li><p>textual move sequences;</p></li>
|
||||
<li><p>the position reached after a sequence of moves;</p></li>
|
||||
<li><p>information in the tag fields;</p></li>
|
||||
<li><p>fuzzy board position;</p></li>
|
||||
<li><p>and material balance in the ending.</p></li>
|
||||
</ul>
|
||||
<p>Over the on-going 20+ year course of its development, it has also added
|
||||
lots of features for controlling what is output (e.g., different
|
||||
algebraic formats, EPD, no move numbers, restricting game length, etc.)
|
||||
|
||||
<p>The program includes a semantic analyser which will
|
||||
report errors in game scores and it is also able to detect duplicate
|
||||
games found in its input files.
|
||||
|
||||
<p>The range of input move formats accepted is fairly wide.
|
||||
The output is normally in English Standard
|
||||
Algebraic Notation (SAN) but this can be varied to long-algebraic or UCI,
|
||||
for instance.
|
||||
|
||||
<p>Extracted games may be written out either including or excluding
|
||||
comments, NAGs, variations, move numbers, tags and/or results.
|
||||
Games may be given ECO classifications
|
||||
derived from the accompanying file eco.pgn, or a customised version
|
||||
provided by the user.
|
||||
|
||||
<p>The program is designed to be relatively memory-friendly, so it
|
||||
does not retain a game's moves in memory once it has been processed.
|
||||
This also makes it suitable for bulk processing very large collections of games
|
||||
- it can efficiently process files containing several millions of games.
|
||||
|
||||
<p>Use the <em>--help</em> argument to the program to
|
||||
get the full lists of arguments.
|
||||
|
||||
<h2>New in recent versions</h2>
|
||||
<p>These are the main changes in the most recent versions:
|
||||
<ul>
|
||||
<li><p>Extended matching of TimeControl to include the formats
|
||||
of sudden death and sandclock.
|
||||
<li><p>Added --detag to delete tags that are not required.
|
||||
<li><p>Added --addfencastling to add potentially missing castling rights to FEN tags.
|
||||
<li><p>Made duplicate suppression work with input from stdin.
|
||||
<li><p>Added --deletesamesetup to identify unique starting positions.
|
||||
<li><p>Added -Wfen to output a game as a sequence of FEN positions.
|
||||
</ul>
|
||||
|
||||
<h2>Available Files</h2>
|
||||
<p>You can take a copy of the full source and
|
||||
documentation as either
|
||||
<a
|
||||
href="https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-22-11.tgz">pgn-extract-22-11.tgz</a>
|
||||
or
|
||||
<a
|
||||
href="https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-22-11.zip">pgn-extract-22-11.zip</a>.
|
||||
Alternatively, a Windows
|
||||
<a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract.exe">64-bit</a>
|
||||
binary is also available.
|
||||
</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><b>Name</b></td>
|
||||
<td align="center"><b>Description</b></td>
|
||||
<td align="center"><b>Size</b></td>
|
||||
<td align="center"><b>Date</b></td>
|
||||
</tr>
|
||||
|
||||
<tr valign="top">
|
||||
<td><a
|
||||
href="https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-22-11.tgz">pgn-extract-22-11.tgz</a><br>
|
||||
<td>GZipped tar file
|
||||
of the complete source of the latest version of the program.<br>
|
||||
Includes <a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/help.html">usage documentation</a>,
|
||||
Makefile for compilation and
|
||||
<a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/eco.pgn">eco.pgn</a> file for ECO classification.</td>
|
||||
<td align="right">424K bytes </td><td>03 May 2022</td>
|
||||
</tr>
|
||||
|
||||
<tr valign="top">
|
||||
<td><a
|
||||
href="https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-22-11.zip">pgn-extract-22-11.zip</a></td>
|
||||
<td>Zipped file of the complete source of the latest version of the program.<br>
|
||||
Includes <a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/help.html">usage documentation</a>, Makefile for compilation and
|
||||
<a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/eco.pgn">eco.pgn</a> file for ECO classification.</td>
|
||||
<td align="right">582K bytes </td><td>03 May 2022</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract.exe">pgn-extract.exe</a></td>
|
||||
<td>Windows 64-bit binary of the latest version of the program.</td>
|
||||
<td align="right">1.2M bytes </td><td>03 May 2022</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/eco.zip">eco.zip</a></td>
|
||||
<td>Zipped version of <a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/eco.pgn">eco.pgn</a>.</td>
|
||||
<td align="right">32K bytes </td><td></td>
|
||||
</tr>
|
||||
|
||||
<tr valign="top">
|
||||
<td><a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/eco.pgn">eco.pgn</a></td>
|
||||
<td>File of openings with PGN classification.<br>
|
||||
This file is already included in the source archives.
|
||||
</td>
|
||||
<td align="right">254K bytes </td><td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="https://www.cs.kent.ac.uk/~djb/pgn-extract/COPYING">COPYING</a></td>
|
||||
<td>GNU General Public License (version 3).</td>
|
||||
<td align="right">35K bytes </td><td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>Blog post about data mining with pgn-extract</h2>
|
||||
<p>In October 2018 I wrote <a href="http://blogs.kent.ac.uk/djb/2018/10/14/data-mining-with-pgn-extract/">blog post</a>
|
||||
about using pgn-extract to mine a PGN database.
|
||||
As an example it looks at the effect of having a bishop pair versus a knight pair.
|
||||
|
||||
<h2>Answers on Chess StackExchange using pgn-extract</h2>
|
||||
<p>I am active on <a href="https://chess.stackexchange.com/">Chess StackExchange</a> as
|
||||
<a href="https://chess.stackexchange.com/users/12951/kentdjb">kentdjb</a>
|
||||
and aim to respond to pgn-extract related questions, although email to me is my preferred way to raise
|
||||
potential issues with the program.
|
||||
<p>From time to time, I have provided answers to questions that involve
|
||||
the use of pgn-extract for analysis tasks:
|
||||
<ul>
|
||||
<li><p><a href="https://chess.stackexchange.com/questions/23938/is-there-a-record-for-threefold-repetition-for-when-the-claimed-positions-are-th/24276#24276">Three-fold repetition</a>.
|
||||
<li><p><a href="https://chess.stackexchange.com/questions/24166/what-professional-game-has-the-quickest-sequence-starting-from-move-one-to-qua/24274#24274">Quadrupled pawns</a>.
|
||||
<li><p><a href="https://chess.stackexchange.com/questions/24245/how-often-does-castling-occur-in-grandmaster-games/24247#24247">Frequency of occurrence of castlng</a>.
|
||||
</ul>
|
||||
|
||||
<h2>Feedback</h2>
|
||||
<p>Feedback and suggestions for further features are always welcome, although I can't always
|
||||
promise to undertake significant development work.
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<address>
|
||||
<p>© 1994-2022 David J. Barnes<br />
|
||||
<a href="https://www.cs.kent.ac.uk/~djb/">My home page</a> at the University of Kent.<br />
|
||||
<a href="mailto:d.j.barnes @ kent.ac.uk">d.j.barnes @ kent.ac.uk</a><br />
|
||||
<a href="https://twitter.com/kentdjb">@kentdjb</a><br />
|
||||
Last updated: 15th August 2022: version 22-11 released.<br />
|
||||
</p>
|
||||
</address>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
1682
pgn-extract/lex.c
Normal file
1682
pgn-extract/lex.c
Normal file
File diff suppressed because it is too large
Load Diff
98
pgn-extract/lex.h
Normal file
98
pgn-extract/lex.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
/* Define a type to make it easy to return where we are
|
||||
* in the input line. This type is returned from those functions
|
||||
* that may modify the line/linep pair in next_token().
|
||||
*/
|
||||
#ifndef LEX_H
|
||||
#define LEX_H
|
||||
|
||||
typedef struct{
|
||||
/* Start of the malloc'ed line. */
|
||||
char *line;
|
||||
/* The next char to access in line, if line is not NULL. */
|
||||
unsigned char *linep;
|
||||
/* What token resulted. */
|
||||
TokenType token;
|
||||
} LinePair;
|
||||
|
||||
/* Define a type to hold a list of input files. */
|
||||
typedef struct {
|
||||
/* The list should have a (char *)NULL on the end. */
|
||||
const char **files;
|
||||
SourceFileType *file_type;
|
||||
/* Keep track of the number of files in the list. */
|
||||
unsigned num_files;
|
||||
/* Keep track of how many the list may hold. */
|
||||
unsigned max_files;
|
||||
} FILE_LIST;
|
||||
|
||||
#if 1
|
||||
#define RUSSIAN_KNIGHT_OR_KING (0x008a)
|
||||
#define RUSSIAN_KING_SECOND_LETTER (0x00e0)
|
||||
#define RUSSIAN_QUEEN (0x0094)
|
||||
#define RUSSIAN_ROOK (0x008b)
|
||||
#define RUSSIAN_BISHOP (0x0091)
|
||||
#define RUSSIAN_PAWN (0x00af)
|
||||
#else
|
||||
#define RUSSIAN_KNIGHT_OR_KING (0x00eb)
|
||||
#define RUSSIAN_KING_SECOND_LETTER (0x00d2)
|
||||
#define RUSSIAN_QUEEN (0x00e6)
|
||||
#define RUSSIAN_ROOK (0x00ec)
|
||||
#define RUSSIAN_BISHOP (0x00f3)
|
||||
#endif
|
||||
/* Define a macro for checking the value of a char against
|
||||
* one of the Russian piece letters.
|
||||
*/
|
||||
#define RUSSIAN_PIECE_CHECK(c) ((c) & 0x00ff)
|
||||
|
||||
/* Shared prototypes for the non-static functions in the
|
||||
* lexical analyser.
|
||||
*/
|
||||
void add_filename_to_source_list(const char *filename,SourceFileType file_type);
|
||||
void add_filename_list_from_file(FILE *fp,SourceFileType file_type);
|
||||
unsigned current_file_number(void);
|
||||
void free_move_list(Move *move_list);
|
||||
LinePair gather_tag(char *line, unsigned char *linep);
|
||||
LinePair gather_string(char *line, unsigned char *linep);
|
||||
void init_lex_tables(void);
|
||||
const char *input_file_name(unsigned file_number);
|
||||
unsigned long get_line_number(void);
|
||||
Boolean is_character_class(unsigned char ch, TokenType character_class);
|
||||
Boolean is_suppressed_tag(TagName tag);
|
||||
char *next_input_line(FILE *fp);
|
||||
TokenType next_token(void);
|
||||
Boolean open_eco_file(const char *eco_file);
|
||||
Boolean open_first_file(void);
|
||||
void print_error_context(FILE *fp);
|
||||
char *read_line(FILE *fpin);
|
||||
void reset_line_number(void);
|
||||
void restart_lex_for_new_game(void);
|
||||
void save_assessment(const char *assess);
|
||||
TokenType skip_to_next_game(TokenType token);
|
||||
void suppress_tag(const char *tag_string);
|
||||
const char *tag_header_string(TagName tag);
|
||||
void yyerror(const char *s);
|
||||
int yywrap(void);
|
||||
|
||||
#endif // LEX_H
|
||||
|
73
pgn-extract/lines.c
Normal file
73
pgn-extract/lines.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "bool.h"
|
||||
#include "mymalloc.h"
|
||||
#include "lines.h"
|
||||
|
||||
/* Define a character that may be used to comment a line in, e.g.
|
||||
* the variations files.
|
||||
* Use the PGN escape mechanism character, for consistency.
|
||||
*/
|
||||
#define COMMENT_CHAR '%'
|
||||
|
||||
/* Return TRUE if line contains a non-space character, but
|
||||
* is not a comment line.
|
||||
*/
|
||||
Boolean
|
||||
non_blank_line(const char *line)
|
||||
{
|
||||
Boolean blank = TRUE;
|
||||
|
||||
if (line != NULL) {
|
||||
if (comment_line(line)) {
|
||||
/* Comment lines count as blanks. */
|
||||
}
|
||||
else {
|
||||
while (blank && (*line != '\0')) {
|
||||
if (!isspace((int) *line)) {
|
||||
blank = FALSE;
|
||||
}
|
||||
else {
|
||||
line++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return !blank;
|
||||
}
|
||||
|
||||
Boolean
|
||||
blank_line(const char *line)
|
||||
{
|
||||
return !non_blank_line(line);
|
||||
}
|
||||
|
||||
/* Should the given line be regarded as a comment line? */
|
||||
Boolean
|
||||
comment_line(const char *line)
|
||||
{
|
||||
return *line == COMMENT_CHAR;
|
||||
}
|
30
pgn-extract/lines.h
Normal file
30
pgn-extract/lines.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#ifndef LINES_H
|
||||
#define LINES_H
|
||||
|
||||
Boolean non_blank_line(const char *line);
|
||||
Boolean blank_line(const char *line);
|
||||
Boolean comment_line(const char *line);
|
||||
|
||||
#endif // LINES_H
|
||||
|
892
pgn-extract/lists.c
Normal file
892
pgn-extract/lists.c
Normal file
@@ -0,0 +1,892 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <regex.h>
|
||||
#include "bool.h"
|
||||
#include "mymalloc.h"
|
||||
#include "defs.h"
|
||||
#include "typedef.h"
|
||||
#include "lists.h"
|
||||
#include "taglist.h"
|
||||
#include "moves.h"
|
||||
|
||||
/* Define a type to permit tag strings to be associated with
|
||||
* a TagOperator for selecting relationships between them
|
||||
* and a game to be matched.
|
||||
*/
|
||||
typedef struct tag_selection {
|
||||
char *tag_string;
|
||||
TagOperator operator;
|
||||
} TagSelection;
|
||||
|
||||
/* Definitions for maintaining arrays of tag strings.
|
||||
* These arrays are used for various purposes:
|
||||
* lists of white/black players to extract on.
|
||||
* lists of other criteria to extract on.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
/* How many elements we have currently allocated for.
|
||||
* If this is > 0 then we should always have allocated exactly
|
||||
* one more than this number to simplify the (char **) NULL
|
||||
* termination of the list.
|
||||
*/
|
||||
unsigned num_allocated_elements;
|
||||
/* num_used_elements should always be <= num_allocated elements. */
|
||||
unsigned num_used_elements;
|
||||
/* The list of elements.
|
||||
* Elements 0 .. num_used_elements point to null-terminated strings.
|
||||
* list[num_used_elements] == (char **) NULL once the list is complete.
|
||||
*/
|
||||
TagSelection *tag_strings;
|
||||
} StringArray;
|
||||
|
||||
/* Functions to allow creation of string lists. */
|
||||
/* Allow a string list for every known tag.
|
||||
* It is important that these lists should be initialised to
|
||||
* { 0, 0, (TagSelection *) NULL }
|
||||
* which happens by default, anyway.
|
||||
* This array, and its length (tag_list_length) are initialised
|
||||
* by calling init_tag_lists.
|
||||
*/
|
||||
static StringArray *TagLists;
|
||||
static int tag_list_length = 0;
|
||||
|
||||
static char *soundex(const char *str);
|
||||
static Boolean check_list(int tag, const char *tag_string, const StringArray *list);
|
||||
static Boolean check_time_period(const char *tag_string, unsigned period, const StringArray *list);
|
||||
|
||||
void init_tag_lists(void)
|
||||
{
|
||||
int i;
|
||||
tag_list_length = ORIGINAL_NUMBER_OF_TAGS;
|
||||
TagLists = (StringArray *) malloc_or_die(tag_list_length * sizeof (*TagLists));
|
||||
for (i = 0; i < tag_list_length; i++) {
|
||||
TagLists[i].num_allocated_elements = 0;
|
||||
TagLists[i].num_used_elements = 0;
|
||||
TagLists[i].tag_strings = (TagSelection *) NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Extend the tag list to the new length.
|
||||
*/
|
||||
static void
|
||||
extend_tag_list_length(int new_length)
|
||||
{
|
||||
if (new_length < tag_list_length) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Internal error: inappropriate call to extend_tag_list_length().\n");
|
||||
fprintf(GlobalState.logfile,
|
||||
"New length of %d is not greater than existing length of %d\n",
|
||||
new_length, tag_list_length);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
TagLists = (StringArray *) realloc_or_die((void *) TagLists,
|
||||
new_length * sizeof (*TagLists));
|
||||
for (i = tag_list_length; i < new_length; i++) {
|
||||
TagLists[i].num_allocated_elements = 0;
|
||||
TagLists[i].num_used_elements = 0;
|
||||
TagLists[i].tag_strings = (TagSelection *) NULL;
|
||||
}
|
||||
tag_list_length = new_length;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add str to the list of strings in list.
|
||||
* List may be a new list, in which case space is allocated
|
||||
* for it.
|
||||
* Return the index on success, otherwise -1.
|
||||
*/
|
||||
static int
|
||||
add_to_taglist(const char *str, StringArray *list)
|
||||
{
|
||||
Boolean everything_ok = TRUE;
|
||||
|
||||
if (list->num_allocated_elements == list->num_used_elements) {
|
||||
/* We need more space. */
|
||||
if (list->num_allocated_elements == 0) {
|
||||
/* No elements in the list. */
|
||||
list->tag_strings = (TagSelection *) malloc_or_die((INIT_LIST_SPACE + 1) *
|
||||
sizeof (TagSelection));
|
||||
if (list->tag_strings != NULL) {
|
||||
list->num_allocated_elements = INIT_LIST_SPACE;
|
||||
list->num_used_elements = 0;
|
||||
}
|
||||
else {
|
||||
everything_ok = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
list->tag_strings = (TagSelection *) realloc_or_die((void *) list->tag_strings,
|
||||
(list->num_allocated_elements + MORE_LIST_SPACE + 1) *
|
||||
sizeof (TagSelection));
|
||||
if (list->tag_strings != NULL) {
|
||||
list->num_allocated_elements += MORE_LIST_SPACE;
|
||||
}
|
||||
else {
|
||||
everything_ok = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (everything_ok) {
|
||||
/* There is space. */
|
||||
const unsigned len = strlen(str) + 1;
|
||||
unsigned ix = list->num_used_elements;
|
||||
|
||||
list->tag_strings[ix].operator = NONE;
|
||||
list->tag_strings[ix].tag_string = (char *) malloc_or_die(len);
|
||||
|
||||
if (list->tag_strings[ix].tag_string != NULL) {
|
||||
strcpy(list->tag_strings[ix].tag_string, str);
|
||||
list->num_used_elements++;
|
||||
/* Make sure that the list is properly terminated at all times. */
|
||||
list->tag_strings[ix + 1].tag_string = NULL;
|
||||
return (int) ix;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Simple soundex code supplied by John Brogan
|
||||
* (jwbrogan@unix2.netaxs.com), 26th Aug 1994.
|
||||
* John writes:
|
||||
* "In recognition of the large number of strong players from countries
|
||||
* with Slavic based languages, I tried to tailor the soundex code
|
||||
* to match any reasonable transliteration of a Slavic name into
|
||||
* English. Thus, Nimzovich will match Nimsowitsch, Tal will match
|
||||
* Talj, etc. Unfortunately, in order to be sure not to miss any
|
||||
* valid matches, I had to make the code so tolerant that it sometimes
|
||||
* comes up with some wildly false matches. This, to me, is better
|
||||
* than missing some games, but your mileage may differ."
|
||||
*
|
||||
* This looks like it was originally derived from the public domain
|
||||
* version released by N. Dean Pentcheff, 1989, which was, itself,
|
||||
* based on that in D.E. Knuth's "The art of computer programming.",
|
||||
* Volume 3: Sorting and searching. Addison-Wesley Publishing Company:
|
||||
* Reading, Mass. Page 392.
|
||||
* Amended by David Barnes, 2nd Sep 1994.
|
||||
*/
|
||||
|
||||
/* Define a maximum length for the soundex result. */
|
||||
#define MAXSOUNDEX 50
|
||||
|
||||
/* Calculate a soundex string for instr.
|
||||
* The space used is statically allocated, so the caller
|
||||
* will have to allocate its own for the result if it
|
||||
* to be retained across different calls.
|
||||
*/
|
||||
static char *
|
||||
soundex(const char *str)
|
||||
{
|
||||
static char sbuf[MAXSOUNDEX + 1];
|
||||
/* An index into sbuf. */
|
||||
unsigned sindex = 0;
|
||||
/* Keep track of the last character to compress repeated letters. */
|
||||
char lastc = ' ';
|
||||
/* ABCDEFGHIJKLMNOPQRSTUVWXYZ */
|
||||
const char *mapping = "01230120002455012622011202";
|
||||
char initial_letter = *str;
|
||||
|
||||
/* Special case for names that begin with 'J',
|
||||
* otherwise Janosevic == Nimzovich.
|
||||
* In addition, we really want Yusupov to match Jusupov.
|
||||
*/
|
||||
if (islower((int) initial_letter)) {
|
||||
initial_letter = toupper(initial_letter);
|
||||
}
|
||||
if ((initial_letter == 'Y') || (initial_letter == 'J')) {
|
||||
sbuf[sindex] = '7';
|
||||
str++;
|
||||
sindex++;
|
||||
}
|
||||
|
||||
while ((*str != '\0') && (sindex < MAXSOUNDEX)) {
|
||||
char ch = *str;
|
||||
|
||||
/* We are only interested in alphabetics, and duplicate
|
||||
* characters are reduced to singletons.
|
||||
*/
|
||||
if (isalpha((int) ch) && (ch != lastc)) {
|
||||
char translation;
|
||||
|
||||
if (islower((int) ch)) {
|
||||
ch = toupper(ch);
|
||||
}
|
||||
/* Pick up the translation. */
|
||||
translation = mapping[ch - 'A'];
|
||||
if ((translation != '0') && (translation != lastc)) {
|
||||
sbuf[sindex] = translation;
|
||||
sindex++;
|
||||
lastc = translation;
|
||||
}
|
||||
}
|
||||
str++;
|
||||
}
|
||||
sbuf[sindex] = '\0';
|
||||
return (sbuf);
|
||||
}
|
||||
|
||||
/* Return TRUE if tag is one on which soundex matching should
|
||||
* be used, if requested.
|
||||
*/
|
||||
static Boolean
|
||||
soundex_tag(int tag)
|
||||
{
|
||||
Boolean use_soundex = FALSE;
|
||||
|
||||
switch (tag) {
|
||||
case WHITE_TAG:
|
||||
case BLACK_TAG:
|
||||
case PSEUDO_PLAYER_TAG:
|
||||
case EVENT_TAG:
|
||||
case SITE_TAG:
|
||||
case ANNOTATOR_TAG:
|
||||
use_soundex = TRUE;
|
||||
break;
|
||||
}
|
||||
return use_soundex;
|
||||
}
|
||||
|
||||
/* Add tagstr to the list of tags to be matched.
|
||||
* If we are using soundex matching, then store
|
||||
* its soundex version rather than its plain text.
|
||||
*/
|
||||
void
|
||||
add_tag_to_list(int tag, const char *tagstr, TagOperator operator)
|
||||
{
|
||||
if (tag >= tag_list_length) {
|
||||
/* A new tag - one without a pre-defined _TAG #define.
|
||||
* Make sure there is room for it in TagList.
|
||||
*/
|
||||
extend_tag_list_length(tag + 1);
|
||||
}
|
||||
if(tag == FEN_TAG) {
|
||||
add_fen_pattern_match(tagstr, FALSE, NULL);
|
||||
}
|
||||
else if ((tag >= 0) && (tag < tag_list_length)) {
|
||||
const char *string_to_store = tagstr;
|
||||
int ix;
|
||||
|
||||
if (GlobalState.use_soundex) {
|
||||
if (soundex_tag(tag)) {
|
||||
string_to_store = soundex(tagstr);
|
||||
}
|
||||
}
|
||||
ix = add_to_taglist(string_to_store, &TagLists[tag]);
|
||||
if (ix >= 0) {
|
||||
TagLists[tag].tag_strings[ix].operator = operator;
|
||||
}
|
||||
/* Ensure that we know we are checking tags. */
|
||||
GlobalState.check_tags = TRUE;
|
||||
}
|
||||
else {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Illegal tag number %d in add_tag_to_list.\n", tag);
|
||||
}
|
||||
}
|
||||
|
||||
/* Argstr is an extraction argument.
|
||||
* The type of argument is indicated by the first letter of
|
||||
* argstr:
|
||||
* a -- annotator of the game
|
||||
* b -- player of the black pieces
|
||||
* d -- date of the game
|
||||
* e -- ECO code
|
||||
* p -- player of either colour
|
||||
* r -- result
|
||||
* w -- player of the white pieces
|
||||
* The remainder of argstr is the argument string to be entered
|
||||
* into the appropriate list.
|
||||
*/
|
||||
void
|
||||
extract_tag_argument(const char *argstr)
|
||||
{
|
||||
const char *arg = &(argstr[1]);
|
||||
|
||||
switch (*argstr) {
|
||||
case 'a':
|
||||
add_tag_to_list(ANNOTATOR_TAG, arg, NONE);
|
||||
break;
|
||||
case 'b':
|
||||
add_tag_to_list(BLACK_TAG, arg, NONE);
|
||||
break;
|
||||
case 'd':
|
||||
add_tag_to_list(DATE_TAG, arg, NONE);
|
||||
break;
|
||||
case 'e':
|
||||
add_tag_to_list(ECO_TAG, arg, NONE);
|
||||
break;
|
||||
case 'f':
|
||||
add_tag_to_list(FEN_TAG, arg, NONE);
|
||||
break;
|
||||
case 'h':
|
||||
add_tag_to_list(HASHCODE_TAG, arg, NONE);
|
||||
break;
|
||||
case 'p':
|
||||
add_tag_to_list(PSEUDO_PLAYER_TAG, arg, NONE);
|
||||
break;
|
||||
case 'r':
|
||||
add_tag_to_list(RESULT_TAG, arg, NONE);
|
||||
break;
|
||||
case 't':
|
||||
add_tag_to_list(TIME_CONTROL_TAG, arg, NONE);
|
||||
break;
|
||||
case 'w':
|
||||
add_tag_to_list(WHITE_TAG, arg, NONE);
|
||||
break;
|
||||
default:
|
||||
fprintf(GlobalState.logfile,
|
||||
"Unknown type of tag extraction argument: %s\n",
|
||||
argstr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine whether lhs operator rhs is TRUE or FALSE. */
|
||||
static Boolean
|
||||
relative_numeric_match(TagOperator operator, double lhs, double rhs)
|
||||
{
|
||||
switch (operator) {
|
||||
case LESS_THAN:
|
||||
return lhs < rhs;
|
||||
case LESS_THAN_OR_EQUAL_TO:
|
||||
return lhs <= rhs;
|
||||
case GREATER_THAN:
|
||||
return lhs > rhs;
|
||||
case GREATER_THAN_OR_EQUAL_TO:
|
||||
return lhs >= rhs;
|
||||
case EQUAL_TO:
|
||||
return lhs == rhs;
|
||||
case NOT_EQUAL_TO:
|
||||
return lhs != rhs;
|
||||
case NONE:
|
||||
fprintf(GlobalState.logfile, "Internal error: NONE in call to relative_numeric_match.\n");
|
||||
return FALSE;
|
||||
default:
|
||||
fprintf(GlobalState.logfile, "Internal error: missing case in call to relative_numeric_match.\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for one of list->strings matching the date_string.
|
||||
* Return TRUE on match, FALSE on failure.
|
||||
* It is only necessary for a prefix of tag to match
|
||||
* the string.
|
||||
*/
|
||||
|
||||
/* Set limits on the allowable ranges for dates extracted from games.
|
||||
* Because of century changes, it is difficult to know what
|
||||
* best to do with two digit year numbers; so exclude them.
|
||||
*/
|
||||
#define MINDATE 100
|
||||
#define MAXDATE 3000
|
||||
|
||||
static Boolean
|
||||
check_date(const char *date_string, const StringArray *list)
|
||||
{
|
||||
unsigned list_index;
|
||||
|
||||
/* Care needed because dates with operators must be ANDed and
|
||||
* dates without operators must be ORed.
|
||||
* The first match is used to set wanted properly for the first time.
|
||||
*/
|
||||
Boolean wanted = FALSE;
|
||||
unsigned game_year, game_month = 1, game_day = 1;
|
||||
if(sscanf(date_string, "%u", &game_year) == 1) {
|
||||
/* Try to extract month and day from the game's date string. */
|
||||
sscanf(date_string, "%*u.%u.%u", &game_month, &game_day);
|
||||
double encoded_game_date = 10000 * game_year + 100 * game_month + game_day;
|
||||
for (list_index = 0; list_index < list->num_used_elements; list_index++) {
|
||||
const char *list_string = list->tag_strings[list_index].tag_string;
|
||||
TagOperator operator = list->tag_strings[list_index].operator;
|
||||
|
||||
if (*list_string == 'b') {
|
||||
operator = LESS_THAN;
|
||||
list_string++;
|
||||
}
|
||||
else if (*list_string == 'a') {
|
||||
operator = GREATER_THAN;
|
||||
list_string++;
|
||||
}
|
||||
else {
|
||||
/* No prefix. */
|
||||
}
|
||||
if (operator != NONE) {
|
||||
/* We have a relational comparison. */
|
||||
unsigned list_year, list_month = 1, list_day = 1;
|
||||
if (sscanf(list_string, "%u", &list_year) == 1) {
|
||||
if((game_year > MINDATE) && (game_year < MAXDATE)) {
|
||||
sscanf(list_string, "%*u.%u.%u", &list_month, &list_day);
|
||||
double encoded_list_date = 10000 * list_year + 100 * list_month + list_day;
|
||||
Boolean matches = relative_numeric_match(operator, encoded_game_date, encoded_list_date);
|
||||
if (list_index == 0) {
|
||||
wanted = matches;
|
||||
}
|
||||
else {
|
||||
wanted = wanted && matches;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Bad format, or out of range. Assume not wanted.
|
||||
* Don't report the bad date in the game.
|
||||
*/
|
||||
wanted = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Bad format. Assume not wanted. */
|
||||
wanted = FALSE;
|
||||
/* While this will give an error for each game, a bad date
|
||||
* in the list of tags to be matched needs reporting.
|
||||
*/
|
||||
fprintf(GlobalState.logfile,
|
||||
"Failed to extract year from %s.\n", list_string);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* No need to check if we already have a match. */
|
||||
if (list_index == 0 || !wanted) {
|
||||
/* Just a straight prefix match. */
|
||||
wanted = strncmp(date_string, list_string, strlen(list_string)) == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return wanted;
|
||||
}
|
||||
|
||||
/* Check whether the TimeControl value matches the requirements. */
|
||||
static Boolean
|
||||
check_time_control(const char *tc_string, const StringArray *list)
|
||||
{
|
||||
Boolean wanted = FALSE;
|
||||
if(*tc_string == '\0' || *tc_string == '?' || *tc_string == '-') {
|
||||
/* Nothing to compare. */
|
||||
}
|
||||
else {
|
||||
/* Examine just the first if there are multiple controls. */
|
||||
char *control = copy_string(tc_string);
|
||||
char *sep = strchr(control, ':');
|
||||
if(sep != NULL) {
|
||||
*sep = '\0';
|
||||
}
|
||||
if(strchr(control, '+') != NULL) {
|
||||
/* Period+increment. */
|
||||
unsigned period;
|
||||
if(sscanf(control,"%u", &period) == 1) {
|
||||
wanted = check_time_period(control, period, list);
|
||||
}
|
||||
}
|
||||
else if(*control == '*') {
|
||||
/* Sandclock. */
|
||||
unsigned period;
|
||||
if(sscanf(control + 1,"%u", &period) == 1) {
|
||||
wanted = check_time_period(control, period, list);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Look for the format moves/seconds. */
|
||||
char *slash = strchr(control, '/');
|
||||
if(slash != NULL) {
|
||||
unsigned period;
|
||||
if(sscanf(slash + 1, "%u", &period) == 1) {
|
||||
wanted = check_time_period(control, period, list);
|
||||
}
|
||||
}
|
||||
else if(isdigit(*control)) {
|
||||
/* Sudden death. */
|
||||
const char *digit = control;
|
||||
while(isdigit(*digit)) {
|
||||
digit++;
|
||||
}
|
||||
if(*digit == '\0') {
|
||||
unsigned period;
|
||||
if(sscanf(control,"%u", &period) == 1) {
|
||||
wanted = check_time_period(control, period, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(void) free((void *) control);
|
||||
}
|
||||
return wanted;
|
||||
}
|
||||
|
||||
/* Compare the given time period against those provided for matches.
|
||||
* Return TRUE if a match is found.
|
||||
*/
|
||||
static Boolean
|
||||
check_time_period(const char *tag_string, unsigned period, const StringArray *list)
|
||||
{
|
||||
Boolean wanted = FALSE;
|
||||
unsigned list_index;
|
||||
for (list_index = 0; (list_index < list->num_used_elements) && !wanted; list_index++) {
|
||||
const char *list_string = list->tag_strings[list_index].tag_string;
|
||||
TagOperator operator = list->tag_strings[list_index].operator;
|
||||
|
||||
if (operator != NONE) {
|
||||
/* We have a relational comparison. */
|
||||
unsigned list_period;
|
||||
if ((sscanf(list_string, "%u", &list_period) == 1)) {
|
||||
wanted = relative_numeric_match(operator, (double) period, (double) list_period);
|
||||
}
|
||||
else {
|
||||
/* Bad format. */
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Just a straight prefix match. */
|
||||
if (strncmp(tag_string, list_string, strlen(list_string)) == 0) {
|
||||
wanted = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wanted;
|
||||
}
|
||||
|
||||
/* Check whether the Elo value matches any of those
|
||||
* in the list.
|
||||
*/
|
||||
static Boolean
|
||||
check_elo(const char *elo_string, StringArray *list)
|
||||
{
|
||||
unsigned list_index;
|
||||
Boolean wanted = FALSE;
|
||||
unsigned game_elo;
|
||||
if(sscanf(elo_string, "%u", &game_elo) == 1) {
|
||||
for (list_index = 0; (list_index < list->num_used_elements) && !wanted; list_index++) {
|
||||
const char *list_string = list->tag_strings[list_index].tag_string;
|
||||
TagOperator operator = list->tag_strings[list_index].operator;
|
||||
|
||||
if (operator != NONE) {
|
||||
/* We have a relational comparison. */
|
||||
unsigned list_elo;
|
||||
if ((sscanf(list_string, "%u", &list_elo) == 1)) {
|
||||
wanted = relative_numeric_match(operator, (double) game_elo, (double) list_elo);
|
||||
}
|
||||
else {
|
||||
/* Bad format, or out of range. Assume not wanted. */
|
||||
wanted = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Just a straight prefix match. */
|
||||
if (strncmp(elo_string, list_string, strlen(list_string)) == 0) {
|
||||
wanted = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return wanted;
|
||||
}
|
||||
|
||||
/* Check for matches of tag_string in list->strings.
|
||||
* Return TRUE on match, FALSE on failure.
|
||||
* For non-numeric tags, ANY match is considered.
|
||||
* Either a prefix of tag is checked, or anywhere
|
||||
* in the tag if tag_match_anywhere is set.
|
||||
* For numeric tags with relational operators, ALL operators must match.
|
||||
*/
|
||||
static Boolean
|
||||
check_list(int tag, const char *tag_string, const StringArray *list)
|
||||
{
|
||||
unsigned list_index;
|
||||
Boolean wanted = FALSE;
|
||||
const char *search_str;
|
||||
Boolean tag_string_is_numeric;
|
||||
/* Whether to consider possible numeric range comparison
|
||||
* in the case of numeric tag values, if there is no
|
||||
* other match.
|
||||
*/
|
||||
Boolean possible_range_check = FALSE;
|
||||
/* Where there is a possible regex check. */
|
||||
Boolean possible_regex_check = FALSE;
|
||||
const char *t;
|
||||
|
||||
if (GlobalState.use_soundex && soundex_tag(tag)) {
|
||||
search_str = soundex(tag_string);
|
||||
}
|
||||
else {
|
||||
search_str = tag_string;
|
||||
}
|
||||
/* Determine whether the search string is numeric or not.
|
||||
* If it is numeric then it could be used in a
|
||||
* relational match.
|
||||
*/
|
||||
t = search_str;
|
||||
if(*t == '+' || *t == '-') {
|
||||
t++;
|
||||
}
|
||||
/* Potential for imprecision in that multiple '.' would be accepted. */
|
||||
while(isdigit(*t) || *t == '.') {
|
||||
t++;
|
||||
}
|
||||
tag_string_is_numeric = *t == '\0';
|
||||
|
||||
for (list_index = 0; (list_index < list->num_used_elements) && !wanted;
|
||||
list_index++) {
|
||||
const TagSelection *selection = &list->tag_strings[list_index];
|
||||
const char *list_string = selection->tag_string;
|
||||
|
||||
if (GlobalState.tag_match_anywhere) {
|
||||
/* Match anywhere in the tag. */
|
||||
if (strstr(search_str, list_string) != NULL) {
|
||||
wanted = TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Match only at the beginning of the tag. */
|
||||
if (strncmp(search_str, list_string, strlen(list_string)) == 0) {
|
||||
wanted = TRUE;
|
||||
}
|
||||
}
|
||||
if(!wanted && selection->operator != NONE) {
|
||||
if(tag_string_is_numeric) {
|
||||
/* Defer to a later check. */
|
||||
possible_range_check = TRUE;
|
||||
}
|
||||
if(selection->operator == REGEX) {
|
||||
/* Defer to a later check. */
|
||||
possible_regex_check = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(! wanted) {
|
||||
if(possible_range_check) {
|
||||
/* Check the relational operators.
|
||||
* This requires ALL to match rather than ANY.
|
||||
* There will be at least one comparison, so this
|
||||
* initial value of wanted will be discarded before
|
||||
* the end of the method.
|
||||
*/
|
||||
wanted = TRUE;
|
||||
for (list_index = 0; (list_index < list->num_used_elements) && wanted;
|
||||
list_index++) {
|
||||
const TagSelection *selection = &list->tag_strings[list_index];
|
||||
switch(selection->operator) {
|
||||
case EQUAL_TO:
|
||||
case NOT_EQUAL_TO:
|
||||
case LESS_THAN:
|
||||
case GREATER_THAN:
|
||||
case LESS_THAN_OR_EQUAL_TO:
|
||||
case GREATER_THAN_OR_EQUAL_TO:
|
||||
{
|
||||
const char *list_string = selection->tag_string;
|
||||
double tag_value, list_value;
|
||||
if(sscanf(search_str, "%lf", &tag_value) == 1 &&
|
||||
sscanf(list_string, "%lf", &list_value) == 1) {
|
||||
wanted = relative_numeric_match(selection->operator,
|
||||
tag_value, list_value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
default:
|
||||
fprintf(GlobalState.logfile, "Internal error: missing case in call to check_list.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(! wanted && possible_regex_check) {
|
||||
for (list_index = 0; (list_index < list->num_used_elements) && ! wanted;
|
||||
list_index++) {
|
||||
const TagSelection *selection = &list->tag_strings[list_index];
|
||||
if(selection->operator == REGEX) {
|
||||
const char *list_string = selection->tag_string;
|
||||
regex_t regex;
|
||||
|
||||
if(regcomp(®ex, list_string, 0) == 0) {
|
||||
if(regexec(®ex, search_str, 0, NULL, 0) == 0) {
|
||||
wanted = TRUE;
|
||||
}
|
||||
}
|
||||
regfree(®ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return wanted;
|
||||
}
|
||||
|
||||
/* Check the Tag Details of this current game against those in
|
||||
* the wanted lists. Check all details apart from any ECO
|
||||
* tag as this is checked separately by CheckECOTag.
|
||||
* An empty list implies that there is no restriction on
|
||||
* the values in the corresponding tag field.
|
||||
* In consequence, completely empty lists imply that all
|
||||
* games reaching this far are wanted.
|
||||
* Return TRUE if wanted, FALSE otherwise.
|
||||
*/
|
||||
Boolean
|
||||
check_tag_details_not_ECO(char *Details[], int num_details)
|
||||
{
|
||||
Boolean wanted = TRUE;
|
||||
int tag;
|
||||
|
||||
if (GlobalState.check_tags) {
|
||||
/* Sanity check. */
|
||||
if (num_details < tag_list_length) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Internal error: mismatch in tag set lengths in ");
|
||||
fprintf(GlobalState.logfile,
|
||||
"CheckTagDetailsNotECO: %d vs %d\n",
|
||||
num_details, tag_list_length);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* PSEUDO_PLAYER_TAG and PSEUDO_ELO_TAG are treated differently,
|
||||
* since they have the effect of or-ing together the WHITE_ and BLACK_ lists.
|
||||
* Otherwise, different tag lists are and-ed.
|
||||
*/
|
||||
if (TagLists[PSEUDO_PLAYER_TAG].num_used_elements != 0) {
|
||||
/* Check both the White and Black lists. */
|
||||
if (Details[WHITE_TAG] != NULL) {
|
||||
wanted = check_list(WHITE_TAG, Details[WHITE_TAG],
|
||||
&TagLists[PSEUDO_PLAYER_TAG]);
|
||||
/* If we didn't find a player there, try for the opponent. */
|
||||
if (!wanted && (Details[BLACK_TAG] != NULL)) {
|
||||
wanted = check_list(BLACK_TAG, Details[BLACK_TAG],
|
||||
&TagLists[PSEUDO_PLAYER_TAG]);
|
||||
}
|
||||
}
|
||||
else if (Details[BLACK_TAG] != NULL) {
|
||||
wanted = check_list(BLACK_TAG, Details[BLACK_TAG],
|
||||
&TagLists[PSEUDO_PLAYER_TAG]);
|
||||
}
|
||||
else {
|
||||
wanted = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (TagLists[PSEUDO_ELO_TAG].num_used_elements != 0) {
|
||||
/* Check both the White and Black lists. */
|
||||
if (Details[WHITE_ELO_TAG] != NULL) {
|
||||
wanted = check_elo(Details[WHITE_ELO_TAG],
|
||||
&TagLists[PSEUDO_ELO_TAG]);
|
||||
/* If we didn't find the ELO there, try for the opponent. */
|
||||
if (!wanted && (Details[BLACK_ELO_TAG] != NULL)) {
|
||||
wanted = check_elo(Details[BLACK_ELO_TAG],
|
||||
&TagLists[PSEUDO_ELO_TAG]);
|
||||
}
|
||||
}
|
||||
else if (Details[BLACK_ELO_TAG] != NULL) {
|
||||
wanted = check_elo(Details[BLACK_ELO_TAG],
|
||||
&TagLists[PSEUDO_ELO_TAG]);
|
||||
}
|
||||
else {
|
||||
wanted = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* No PSEUDO_*_TAG info to check. */
|
||||
}
|
||||
|
||||
/* Check the remaining tags in turn as long as we still have a match. */
|
||||
for (tag = 0; (tag < tag_list_length) && wanted; tag++) {
|
||||
if (tag == PSEUDO_PLAYER_TAG) {
|
||||
}
|
||||
else if (tag == PSEUDO_ELO_TAG) {
|
||||
}
|
||||
else if (tag == ECO_TAG) {
|
||||
/* This is handled separately. */
|
||||
}
|
||||
else if (TagLists[tag].num_used_elements != 0) {
|
||||
if (Details[tag] != NULL) {
|
||||
if (tag == DATE_TAG) {
|
||||
wanted = check_date(Details[tag], &TagLists[DATE_TAG]);
|
||||
}
|
||||
else if ((tag == WHITE_ELO_TAG) || (tag == BLACK_ELO_TAG)) {
|
||||
wanted = check_elo(Details[tag], &TagLists[tag]);
|
||||
}
|
||||
else if (tag == TIME_CONTROL_TAG) {
|
||||
wanted = check_time_control(Details[tag], &TagLists[TIME_CONTROL_TAG]);
|
||||
}
|
||||
else {
|
||||
wanted = check_list(tag, Details[tag], &TagLists[tag]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Required tag not present. */
|
||||
wanted = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Not used. */
|
||||
}
|
||||
}
|
||||
}
|
||||
return wanted;
|
||||
}
|
||||
|
||||
/* Check just the ECO tag from the game's tag details. */
|
||||
Boolean
|
||||
check_ECO_tag(char *Details[])
|
||||
{
|
||||
Boolean wanted = TRUE;
|
||||
|
||||
if (GlobalState.check_tags) {
|
||||
if (TagLists[ECO_TAG].num_used_elements != 0) {
|
||||
if (Details[ECO_TAG] != NULL) {
|
||||
wanted = check_list(ECO_TAG, Details[ECO_TAG], &TagLists[ECO_TAG]);
|
||||
}
|
||||
else {
|
||||
/* Required tag not present. */
|
||||
wanted = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wanted;
|
||||
}
|
||||
|
||||
/* Check whether the tags fit with the setting of GlobalState.setup_status.
|
||||
* Return TRUE if they do, false otherwise.
|
||||
*/
|
||||
Boolean
|
||||
check_setup_tag(char *Details[])
|
||||
{
|
||||
switch (GlobalState.setup_status) {
|
||||
case SETUP_TAG_OK:
|
||||
return TRUE;
|
||||
case NO_SETUP_TAG:
|
||||
return Details[SETUP_TAG] == NULL;
|
||||
case SETUP_TAG_ONLY:
|
||||
return Details[SETUP_TAG] != NULL;
|
||||
default:
|
||||
fprintf(GlobalState.logfile, "Internal error: setup status %u not recognised.",
|
||||
GlobalState.setup_status);
|
||||
exit(1);
|
||||
}
|
||||
}
|
53
pgn-extract/lists.h
Normal file
53
pgn-extract/lists.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
/* Define values for the amount of space to initially malloc
|
||||
* and incrementally realloc in a list.
|
||||
*/
|
||||
#ifndef LISTS_H
|
||||
#define LISTS_H
|
||||
|
||||
#define INIT_LIST_SPACE 10
|
||||
#define MORE_LIST_SPACE 5
|
||||
|
||||
/* Tags to be sought may have an operator to specify the
|
||||
* relationship between value in the tag list and that in
|
||||
* the game. For instance, in order to find games before 1962
|
||||
* use Date < "1962". The < turns into a LESS_THAN operator.
|
||||
* Potentially any tag may have an operator, but not all make
|
||||
* sense in all circumstances.
|
||||
*/
|
||||
typedef enum {
|
||||
NONE,
|
||||
LESS_THAN, GREATER_THAN, EQUAL_TO, NOT_EQUAL_TO,
|
||||
LESS_THAN_OR_EQUAL_TO, GREATER_THAN_OR_EQUAL_TO,
|
||||
REGEX
|
||||
} TagOperator;
|
||||
|
||||
void extract_tag_argument(const char *argstr);
|
||||
void add_tag_to_list(int tag,const char *tagstr,TagOperator operator);
|
||||
Boolean check_tag_details_not_ECO(char *Details[],int num_details);
|
||||
Boolean check_ECO_tag(char *Details[]);
|
||||
void init_tag_lists(void);
|
||||
Boolean check_setup_tag(char *Details[]);
|
||||
|
||||
#endif // LISTS_H
|
||||
|
442
pgn-extract/main.c
Normal file
442
pgn-extract/main.c
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "bool.h"
|
||||
#include "mymalloc.h"
|
||||
#include "defs.h"
|
||||
#include "typedef.h"
|
||||
#include "tokens.h"
|
||||
#include "taglist.h"
|
||||
#include "lex.h"
|
||||
#include "moves.h"
|
||||
#include "map.h"
|
||||
#include "lists.h"
|
||||
#include "output.h"
|
||||
#include "end.h"
|
||||
#include "grammar.h"
|
||||
#include "hashing.h"
|
||||
#include "argsfile.h"
|
||||
|
||||
/* The maximum length of an output line. This is conservatively
|
||||
* slightly smaller than the PGN export standard of 80.
|
||||
*/
|
||||
#define MAX_LINE_LENGTH 75
|
||||
|
||||
/* Define a file name relative to the current directory representing
|
||||
* a file of ECO classificiations.
|
||||
*/
|
||||
#ifndef DEFAULT_ECO_FILE
|
||||
#define DEFAULT_ECO_FILE "eco.pgn"
|
||||
#endif
|
||||
|
||||
/* This structure holds details of the program state
|
||||
* available to all parts of the program.
|
||||
* This goes against the grain of good structured programming
|
||||
* principles, but most of these fields are set from the program's
|
||||
* arguments and are read-only thereafter. If I had done this in
|
||||
* C++ there would have been a cleaner interface!
|
||||
*/
|
||||
StateInfo GlobalState = {
|
||||
FALSE, /* skipping_current_game */
|
||||
FALSE, /* check_only (-r) */
|
||||
2, /* verbosity level (-s and --quiet) */
|
||||
TRUE, /* keep_NAGs (-N) */
|
||||
TRUE, /* keep_comments (-C) */
|
||||
TRUE, /* keep_variations (-V) */
|
||||
ALL_TAGS, /* tag_output_form (-7, --notags) */
|
||||
TRUE, /* match_permutations (-v) */
|
||||
FALSE, /* positional_variations (-x) */
|
||||
FALSE, /* use_soundex (-S) */
|
||||
FALSE, /* suppress_duplicates (-D) */
|
||||
FALSE, /* suppress_originals (-U) */
|
||||
FALSE, /* fuzzy_match_duplicates (--fuzzy) */
|
||||
0, /* fuzzy_match_depth (--fuzzy) */
|
||||
FALSE, /* check_tags */
|
||||
FALSE, /* add_ECO (-e) */
|
||||
FALSE, /* parsing_ECO_file (-e) */
|
||||
DONT_DIVIDE, /* ECO_level (-E) */
|
||||
SAN, /* output_format (-W) */
|
||||
MAX_LINE_LENGTH, /* max_line_length (-w) */
|
||||
FALSE, /* use_virtual_hash_table (-Z) */
|
||||
FALSE, /* check_move_bounds (-b) */
|
||||
FALSE, /* match_only_checkmate (-M) */
|
||||
FALSE, /* match_only_stalemate (--stalemate) */
|
||||
TRUE, /* keep_move_numbers (--nomovenumbers) */
|
||||
TRUE, /* keep_results (--noresults) */
|
||||
TRUE, /* keep_checks (--nochecks) */
|
||||
FALSE, /* output_evaluation (--evaluation) */
|
||||
FALSE, /* keep_broken_games (--keepbroken) */
|
||||
FALSE, /* suppress_redundant_ep_info (--nofauxep) */
|
||||
FALSE, /* json_format (--json) */
|
||||
FALSE, /* tag_match_anywhere (--tagsubstr) */
|
||||
FALSE, /* match_underpromotion (--underpromotion) */
|
||||
0, /* depth_of_positional_search */
|
||||
0, /* num_games_processed */
|
||||
0, /* num_games_matched */
|
||||
0, /* games_per_file (-#) */
|
||||
1, /* next_file_number */
|
||||
0, /* lower_move_bound */
|
||||
10000, /* upper_move_bound */
|
||||
-1, /* output_ply_limit (--plylimit) */
|
||||
0, /* stability_threshold (--stable) */
|
||||
1, /* first */
|
||||
~0, /* game_limit */
|
||||
0, /* maximum_matches */
|
||||
0, /* drop_ply_number (--dropply) */
|
||||
1, /* startply (--startply) */
|
||||
0, /* check_for_repetition (--repetition) */
|
||||
0, /* check_for_N_move_rule (--fifty, --seventyfive) */
|
||||
FALSE, /* output_FEN_string */
|
||||
FALSE, /* add_FEN_comments (--fencomments) */
|
||||
FALSE, /* add_hashcode_comments (--hashcomments) */
|
||||
FALSE, /* add_position_match_comments (--markmatches) */
|
||||
FALSE, /* output_plycount (--plycount) */
|
||||
FALSE, /* output_total_plycount (--totalplycount) */
|
||||
FALSE, /* add_hashcode_tag (--addhashcode) */
|
||||
FALSE, /* fix_result_tags (--fixresulttags) */
|
||||
FALSE, /* fix_tag_strings (--fixtagstrings) */
|
||||
FALSE, /* add_fen_castling (--addfencastling) */
|
||||
FALSE, /* separate_comment_lines (--commentlines) */
|
||||
FALSE, /* split_variants (--separatevariants) */
|
||||
FALSE, /* reject_inconsistent_results (--nobadresults) */
|
||||
FALSE, /* allow_null_moves (--allownullmoves) */
|
||||
FALSE, /* allow_nested_comments (--nestedcomments) */
|
||||
FALSE, /* add_match_tag (--addmatchtag) */
|
||||
FALSE, /* add_matchlabel_tag (--addlabeltag) */
|
||||
FALSE, /* only_output_wanted_tags (--xroster) */
|
||||
FALSE, /* delete_same_setup (--deletesamesetup) */
|
||||
FALSE, /* lichess_comment_fix (--lichesscommentfix) */
|
||||
0, /* split_depth_limit */
|
||||
NORMALFILE, /* current_file_type */
|
||||
SETUP_TAG_OK, /* setup_status */
|
||||
EITHER_TO_MOVE, /* whose_move */
|
||||
"MATCH", /* position_match_comment (--markmatches) */
|
||||
(char *) NULL, /* FEN_comment_pattern (-Fpattern) */
|
||||
(char *) NULL, /* drop_comment_pattern (--dropbefore) */
|
||||
(char *) NULL, /* line_number_marker (--linenumbers) */
|
||||
(char *) NULL, /* current_input_file */
|
||||
DEFAULT_ECO_FILE, /* eco_file (-e) */
|
||||
(FILE *) NULL, /* outputfile (-o, -a). Default is stdout */
|
||||
(char *) NULL, /* output_filename (-o, -a) */
|
||||
(FILE *) NULL, /* logfile (-l). Default is stderr */
|
||||
(FILE *) NULL, /* duplicate_file (-d) */
|
||||
(FILE *) NULL, /* non_matching_file (-n) */
|
||||
NULL, /* matching_game_numbers */
|
||||
NULL, /* next_game_number_to_output */
|
||||
NULL, /* skip_game_numbers */
|
||||
NULL, /* next_game_number_to_skip */
|
||||
};
|
||||
|
||||
/* Prepare the output file handles in GlobalState. */
|
||||
static void
|
||||
init_default_global_state(void)
|
||||
{
|
||||
GlobalState.outputfile = stdout;
|
||||
GlobalState.logfile = stderr;
|
||||
set_output_line_length(MAX_LINE_LENGTH);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int argnum;
|
||||
|
||||
/* Prepare global state. */
|
||||
init_default_global_state();
|
||||
/* Prepare the Game_Header. */
|
||||
init_game_header();
|
||||
/* Prepare the tag lists for -t/-T matching. */
|
||||
init_tag_lists();
|
||||
/* Prepare the hash tables for transposition detection. */
|
||||
init_hashtab();
|
||||
/* Initialise the lexical analyser's tables. */
|
||||
init_lex_tables();
|
||||
/* Allow for some arguments. */
|
||||
for (argnum = 1; argnum < argc;) {
|
||||
const char *argument = argv[argnum];
|
||||
if (argument[0] == '-') {
|
||||
switch (argument[1]) {
|
||||
/* Arguments with no additional component. */
|
||||
case SEVEN_TAG_ROSTER_ARGUMENT:
|
||||
case DONT_KEEP_COMMENTS_ARGUMENT:
|
||||
case DONT_KEEP_DUPLICATES_ARGUMENT:
|
||||
case DONT_KEEP_VARIATIONS_ARGUMENT:
|
||||
case DONT_KEEP_NAGS_ARGUMENT:
|
||||
case DONT_MATCH_PERMUTATIONS_ARGUMENT:
|
||||
case CHECK_ONLY_ARGUMENT:
|
||||
case KEEP_SILENT_ARGUMENT:
|
||||
case USE_SOUNDEX_ARGUMENT:
|
||||
case MATCH_CHECKMATE_ARGUMENT:
|
||||
case SUPPRESS_ORIGINALS_ARGUMENT:
|
||||
case USE_VIRTUAL_HASH_TABLE_ARGUMENT:
|
||||
process_argument(argument[1], "");
|
||||
argnum++;
|
||||
break;
|
||||
|
||||
/* Argument rewritten as a different one. */
|
||||
case ALTERNATIVE_HELP_ARGUMENT:
|
||||
process_argument(HELP_ARGUMENT, "");
|
||||
argnum++;
|
||||
break;
|
||||
|
||||
/* Arguments where an additional component is required.
|
||||
* It must be adjacent to the argument and not separated from it.
|
||||
*/
|
||||
case TAG_EXTRACTION_ARGUMENT:
|
||||
process_argument(argument[1], &(argument[2]));
|
||||
argnum++;
|
||||
break;
|
||||
|
||||
/* Arguments where an additional component is optional.
|
||||
* If it is present, it must be adjacent to the argument
|
||||
* letter and not separated from it.
|
||||
*/
|
||||
case HELP_ARGUMENT:
|
||||
case OUTPUT_FORMAT_ARGUMENT:
|
||||
case USE_ECO_FILE_ARGUMENT:
|
||||
process_argument(argument[1], &(argument[2]));
|
||||
argnum++;
|
||||
break;
|
||||
|
||||
/* Long form arguments. */
|
||||
case LONG_FORM_ARGUMENT:
|
||||
{
|
||||
/* How many args (1 or 2) are processed. */
|
||||
int args_processed;
|
||||
/* This argument might need the following argument
|
||||
* as an associated value.
|
||||
*/
|
||||
const char *possible_associated_value = "";
|
||||
if (argnum + 1 < argc) {
|
||||
possible_associated_value = argv[argnum + 1];
|
||||
}
|
||||
/* Find out how many arguments were consumed
|
||||
* (1 or 2).
|
||||
*/
|
||||
args_processed =
|
||||
process_long_form_argument(&argument[2],
|
||||
possible_associated_value);
|
||||
argnum += args_processed;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Arguments with a required filename component. */
|
||||
case FILE_OF_ARGUMENTS_ARGUMENT:
|
||||
case APPEND_TO_OUTPUT_FILE_ARGUMENT:
|
||||
case CHECK_FILE_ARGUMENT:
|
||||
case DUPLICATES_FILE_ARGUMENT:
|
||||
case FILE_OF_FILES_ARGUMENT:
|
||||
case WRITE_TO_LOG_FILE_ARGUMENT:
|
||||
case APPEND_TO_LOG_FILE_ARGUMENT:
|
||||
case NON_MATCHING_GAMES_ARGUMENT:
|
||||
case WRITE_TO_OUTPUT_FILE_ARGUMENT:
|
||||
case TAG_ROSTER_ARGUMENT:
|
||||
{ /* We require an associated file argument. */
|
||||
const char argument_letter = argument[1];
|
||||
const char *filename = &(argument[2]);
|
||||
if (*filename == '\0') {
|
||||
/* Try to pick it up from the next argument. */
|
||||
argnum++;
|
||||
if (argnum < argc) {
|
||||
filename = argv[argnum];
|
||||
argnum++;
|
||||
}
|
||||
/* Make sure the associated_value does not look
|
||||
* like the next argument.
|
||||
*/
|
||||
if ((*filename == '\0') || (*filename == '-')) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Usage: -%c filename\n",
|
||||
argument_letter);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
argnum++;
|
||||
}
|
||||
process_argument(argument[1], filename);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Arguments with a required following value. */
|
||||
case ECO_OUTPUT_LEVEL_ARGUMENT:
|
||||
case GAMES_PER_FILE_ARGUMENT:
|
||||
case LINE_WIDTH_ARGUMENT:
|
||||
case MOVE_BOUNDS_ARGUMENT:
|
||||
case PLY_BOUNDS_ARGUMENT:
|
||||
{ /* We require an associated argument. */
|
||||
const char argument_letter = argument[1];
|
||||
const char *associated_value = &(argument[2]);
|
||||
if (*associated_value == '\0') {
|
||||
/* Try to pick it up from the next argument. */
|
||||
argnum++;
|
||||
if (argnum < argc) {
|
||||
associated_value = argv[argnum];
|
||||
argnum++;
|
||||
}
|
||||
/* Make sure the associated_value does not look
|
||||
* like the next argument.
|
||||
*/
|
||||
if ((*associated_value == '\0') ||
|
||||
(*associated_value == '-')) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Usage: -%c value\n",
|
||||
argument_letter);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
argnum++;
|
||||
}
|
||||
process_argument(argument[1], associated_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case OUTPUT_FEN_STRING_ARGUMENT:
|
||||
/* May be following by an optional argument immediately after
|
||||
* the argument letter.
|
||||
*/
|
||||
process_argument(argument[1], &argument[2]);
|
||||
argnum++;
|
||||
break;
|
||||
/* Argument that require different treatment because they
|
||||
* are present on the command line rather than an argsfile.
|
||||
*/
|
||||
case TAGS_ARGUMENT:
|
||||
case MOVES_ARGUMENT:
|
||||
case POSITIONS_ARGUMENT:
|
||||
case ENDINGS_ARGUMENT:
|
||||
case ENDINGS_COLOURED_ARGUMENT:
|
||||
{
|
||||
/* From the command line, we require an
|
||||
* associated file argument.
|
||||
* Check this here, as it is not the case
|
||||
* when reading arguments from an argument file.
|
||||
*/
|
||||
const char *filename = &(argument[2]);
|
||||
const char argument_letter = argument[1];
|
||||
if (*filename == '\0') {
|
||||
/* Try to pick it up from the next argument. */
|
||||
argnum++;
|
||||
if (argnum < argc) {
|
||||
filename = argv[argnum];
|
||||
argnum++;
|
||||
}
|
||||
/* Make sure the filename does not look
|
||||
* like the next argument.
|
||||
*/
|
||||
if ((*filename == '\0') || (*filename == '-')) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Usage: -%cfilename or -%c filename\n",
|
||||
argument_letter, argument_letter);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
argnum++;
|
||||
}
|
||||
process_argument(argument_letter, filename);
|
||||
}
|
||||
break;
|
||||
case HASHCODE_MATCH_ARGUMENT:
|
||||
process_argument(argument[1], &argument[2]);
|
||||
argnum++;
|
||||
break;
|
||||
default:
|
||||
fprintf(GlobalState.logfile,
|
||||
"Unknown flag %s. Use -%c for usage details.\n",
|
||||
argument, HELP_ARGUMENT);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Should be a file name containing games. */
|
||||
add_filename_to_source_list(argument, NORMALFILE);
|
||||
argnum++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make some adjustments to other settings if JSON output is required. */
|
||||
if (GlobalState.json_format) {
|
||||
if (GlobalState.output_format != EPD &&
|
||||
GlobalState.output_format != CM &&
|
||||
GlobalState.ECO_level == DONT_DIVIDE) {
|
||||
GlobalState.keep_comments = FALSE;
|
||||
GlobalState.keep_variations = FALSE;
|
||||
GlobalState.keep_results = FALSE;
|
||||
}
|
||||
else {
|
||||
fprintf(GlobalState.logfile, "JSON output is not currently supported with -E, -Wepd or -Wcm\n");
|
||||
GlobalState.json_format = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare the hash tables for duplicate detection. */
|
||||
init_duplicate_hash_table();
|
||||
|
||||
if (GlobalState.add_ECO) {
|
||||
/* Read in a list of ECO lines in order to classify the games. */
|
||||
if (open_eco_file(GlobalState.eco_file)) {
|
||||
/* Indicate that the ECO file is currently being parsed. */
|
||||
GlobalState.parsing_ECO_file = TRUE;
|
||||
yyparse(ECOFILE);
|
||||
reset_line_number();
|
||||
GlobalState.parsing_ECO_file = FALSE;
|
||||
}
|
||||
else {
|
||||
fprintf(GlobalState.logfile, "Unable to open the ECO file %s.\n",
|
||||
GlobalState.eco_file);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Open up the first file as the source of input. */
|
||||
if (!open_first_file()) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
yyparse(GlobalState.current_file_type);
|
||||
|
||||
/* @@@ I would prefer this to be somewhere else. */
|
||||
if (GlobalState.json_format &&
|
||||
!GlobalState.check_only &&
|
||||
GlobalState.num_games_matched > 0) {
|
||||
fputs("\n]\n", GlobalState.outputfile);
|
||||
}
|
||||
|
||||
/* Remove any temporary files. */
|
||||
clear_duplicate_hash_table();
|
||||
if (GlobalState.verbosity > 1) {
|
||||
fprintf(GlobalState.logfile, "%lu game%s matched out of %lu.\n",
|
||||
GlobalState.num_games_matched,
|
||||
GlobalState.num_games_matched == 1 ? "" : "s",
|
||||
GlobalState.num_games_processed);
|
||||
}
|
||||
if ((GlobalState.logfile != stderr) && (GlobalState.logfile != NULL)) {
|
||||
(void) fclose(GlobalState.logfile);
|
||||
}
|
||||
return 0;
|
||||
}
|
2467
pgn-extract/map.c
Normal file
2467
pgn-extract/map.c
Normal file
File diff suppressed because it is too large
Load Diff
48
pgn-extract/map.h
Normal file
48
pgn-extract/map.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#ifndef MAP_H
|
||||
#define MAP_H
|
||||
|
||||
void init_hashtab(void);
|
||||
Boolean determine_move_details(Colour colour,Move *move_details, Board *board);
|
||||
HashCode hash_lookup(Col col, Rank rank, Piece piece, Colour colour);
|
||||
void make_move(MoveClass class, Col from_col, Rank from_rank, Col to_col, Rank to_rank,
|
||||
Piece piece, Colour colour,Board *board);
|
||||
CheckStatus king_is_in_check(const Board *board,Colour king_colour);
|
||||
MovePair *find_pawn_moves(Col from_col, Rank from_rank, Col to_col,Rank to_rank,
|
||||
Colour colour, const Board *board);
|
||||
MovePair *find_knight_moves(Col to_col,Rank to_rank, Colour colour, const Board *board);
|
||||
MovePair *find_bishop_moves(Col to_col,Rank to_rank, Colour colour, const Board *board);
|
||||
MovePair *find_rook_moves(Col to_col,Rank to_rank, Colour colour, const Board *board);
|
||||
MovePair *find_queen_moves(Col to_col,Rank to_rank, Colour colour, const Board *board);
|
||||
MovePair *find_king_moves(Col to_col,Rank to_rank, Colour colour, const Board *board);
|
||||
MovePair *exclude_checks(Piece piece, Colour colour,MovePair *possibles,
|
||||
const Board *board);
|
||||
void free_move_pair_list(MovePair *move_list);
|
||||
Boolean king_is_in_checkmate(Colour colour,Board *board);
|
||||
Col find_castling_king_col(Colour colour, const Board *board);
|
||||
Col find_castling_rook_col(Colour colour, const Board *board, MoveClass castling);
|
||||
MovePair *find_all_moves(const Board *board, Colour colour);
|
||||
Boolean at_least_one_move(const Board *board, Colour colour);
|
||||
|
||||
#endif // MAP_H
|
||||
|
786
pgn-extract/moves.c
Normal file
786
pgn-extract/moves.c
Normal file
@@ -0,0 +1,786 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
/***
|
||||
* These routines are concerned with gathering moves of
|
||||
* the various sorts of variations specified by the -v
|
||||
* and -x flags. In the former case, there are also functions
|
||||
* for checking the moves of a game against the variation
|
||||
* lists that are wanted. Checking of the variations specified
|
||||
* by the -x flag is handled elsewhere by apply_move_list().
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "bool.h"
|
||||
#include "mymalloc.h"
|
||||
#include "lines.h"
|
||||
#include "defs.h"
|
||||
#include "typedef.h"
|
||||
#include "map.h"
|
||||
#include "lists.h"
|
||||
#include "tokens.h"
|
||||
#include "taglist.h"
|
||||
#include "lex.h"
|
||||
#include "moves.h"
|
||||
#include "apply.h"
|
||||
#include "decode.h"
|
||||
#include "fenmatcher.h"
|
||||
|
||||
/* Define a character that can be used in the variations file to
|
||||
* mean that we don't mind what move was played at this point.
|
||||
* So:
|
||||
* * b6
|
||||
* means look for all games in which Black playes 1...b6, regardless
|
||||
* of White's first move.
|
||||
*/
|
||||
#define ANY_MOVE '*'
|
||||
/* Define a character that can be used in the variations file to
|
||||
* mean that we do not wish to match a particular move.
|
||||
* So:
|
||||
* e4 c5 !Nf3
|
||||
* means look for games in which Black does not play 2. Nf3 against
|
||||
* the Sicilian defence.
|
||||
*/
|
||||
#define DISALLOWED_MOVE '!'
|
||||
|
||||
/* Hold details of a single move within a variation. */
|
||||
typedef struct {
|
||||
/* Characters of the move.
|
||||
* Alternative notations for the same move are separated by
|
||||
* a non-move character, e.g.:
|
||||
* cxd|cxd4|c5xd4
|
||||
* could all be alternatives for the same basic pawn capture.
|
||||
*/
|
||||
char *move;
|
||||
/* If we are interested in matching the moves in any order,
|
||||
* then we need to record whether or not the current move has
|
||||
* been matched or not.
|
||||
*/
|
||||
Boolean matched;
|
||||
} variant_move;
|
||||
|
||||
/* Hold details of a single variation, with a pointer to
|
||||
* an alternative variation.
|
||||
*/
|
||||
typedef struct variation_list {
|
||||
/* The list of moves. */
|
||||
variant_move *moves;
|
||||
/* Keep a count of how many ANY_MOVE moves there are in the move
|
||||
* list for each colour. If these are non-zero then one is used
|
||||
* when a match fails when looking for permutations.
|
||||
*/
|
||||
unsigned num_white_any_moves;
|
||||
unsigned num_black_any_moves;
|
||||
/* Keep a count of how many DISALLOWED_MOVE moves there are in the move
|
||||
* list for each colour. If these are non-zero then the game
|
||||
* must be searched for them when looking for permutations before
|
||||
* the full search is made.
|
||||
*/
|
||||
unsigned num_white_disallowed_moves;
|
||||
unsigned num_black_disallowed_moves;
|
||||
/* How many half-moves in the variation? */
|
||||
unsigned length;
|
||||
struct variation_list *next;
|
||||
} variation_list;
|
||||
|
||||
/* The head of the variations-of-interest list. */
|
||||
static variation_list *games_to_keep = NULL;
|
||||
|
||||
static Boolean textual_variation_match(const char *variation_move,
|
||||
const unsigned char *actual_move);
|
||||
|
||||
/*** Functions concerned with reading details of the variations
|
||||
*** of interest.
|
||||
***/
|
||||
|
||||
/* Remove any move number prefix from str.
|
||||
* Return NULL if there is no move (only number)
|
||||
* otherwise return the head of the move portion.
|
||||
*/
|
||||
static char *
|
||||
strip_move_number(char *str)
|
||||
{
|
||||
while (isdigit((int) *str)) {
|
||||
str++;
|
||||
}
|
||||
while (*str == '.') {
|
||||
str++;
|
||||
}
|
||||
if (*str != '\0') {
|
||||
return str;
|
||||
}
|
||||
else {
|
||||
return (char *) NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Define values for malloc/realloc allocation. */
|
||||
#define INIT_MOVE_NUMBER 10
|
||||
#define MOVE_INCREMENT 5
|
||||
|
||||
/* Break up a single line of moves into a list of moves
|
||||
* comprising a variation.
|
||||
*/
|
||||
static variation_list *
|
||||
compose_variation(char *line)
|
||||
{
|
||||
variation_list *variation;
|
||||
variant_move *move_list;
|
||||
/* Keep track of the number of moves extracted from line. */
|
||||
unsigned num_moves = 0;
|
||||
unsigned max_moves = 0;
|
||||
char *move;
|
||||
|
||||
variation = (variation_list *) malloc_or_die(sizeof (variation_list));
|
||||
/* We don't yet know how many ANY_MOVEs or DISALLOWED_MOVES there
|
||||
* will be in this variation.
|
||||
*/
|
||||
variation->num_white_any_moves = 0;
|
||||
variation->num_black_any_moves = 0;
|
||||
variation->num_white_disallowed_moves = 0;
|
||||
variation->num_black_disallowed_moves = 0;
|
||||
/* Allocate an initial number of pointers for the moves of the variation. */
|
||||
move_list = (variant_move *) malloc_or_die(INIT_MOVE_NUMBER *
|
||||
sizeof (*move_list));
|
||||
max_moves = INIT_MOVE_NUMBER;
|
||||
/* Find the first move. */
|
||||
move = strtok(line, " ");
|
||||
while (move != NULL) {
|
||||
if ((move = strip_move_number(move)) == NULL) {
|
||||
/* Only a move number. */
|
||||
}
|
||||
else {
|
||||
/* See if we need some more space. */
|
||||
if (num_moves == max_moves) {
|
||||
move_list = (variant_move *) realloc_or_die((void *) move_list,
|
||||
(max_moves + MOVE_INCREMENT) * sizeof (*move_list));
|
||||
if (move_list == NULL) {
|
||||
/* Catastrophic failure. */
|
||||
free((void *) variation);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
max_moves += MOVE_INCREMENT;
|
||||
}
|
||||
}
|
||||
/* Keep the move and initialise the matched field for
|
||||
* when we start matching games.
|
||||
*/
|
||||
move_list[num_moves].move = move;
|
||||
move_list[num_moves].matched = FALSE;
|
||||
/* Keep track of moves that will match anything. */
|
||||
if (*move == ANY_MOVE) {
|
||||
/* Odd numbered half-moves in the variant list are Black. */
|
||||
if (num_moves & 0x01) {
|
||||
variation->num_black_any_moves++;
|
||||
}
|
||||
else {
|
||||
variation->num_white_any_moves++;
|
||||
}
|
||||
/* Beware of the potential for false matches. */
|
||||
if (strlen(move) > 1) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Warning: %c in %s should not be followed by additional move text.\n",
|
||||
*move, move);
|
||||
fprintf(GlobalState.logfile, "It could give false matches.\n");
|
||||
}
|
||||
}
|
||||
else if (*move == DISALLOWED_MOVE) {
|
||||
/* Odd numbered half-moves in the variant list are Black. */
|
||||
if (num_moves & 0x01) {
|
||||
variation->num_black_disallowed_moves++;
|
||||
}
|
||||
else {
|
||||
variation->num_white_disallowed_moves++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Unadorned move. */
|
||||
}
|
||||
num_moves++;
|
||||
}
|
||||
move = strtok((char *) NULL, " ");
|
||||
}
|
||||
variation->moves = move_list;
|
||||
variation->length = num_moves;
|
||||
variation->next = NULL;
|
||||
return variation;
|
||||
}
|
||||
|
||||
/* Read each line of input and decompose it into a variation
|
||||
* to be placed in the games_to_keep list.
|
||||
*/
|
||||
void
|
||||
add_textual_variations_from_file(FILE *fpin)
|
||||
{
|
||||
char *line;
|
||||
|
||||
while ((line = read_line(fpin)) != NULL) {
|
||||
add_textual_variation_from_line(line);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the text of the given line to the list of games_to_keep.
|
||||
*/
|
||||
void
|
||||
add_textual_variation_from_line(char *line)
|
||||
{
|
||||
if (non_blank_line(line)) {
|
||||
variation_list *next_variation = compose_variation(line);
|
||||
if (next_variation != NULL) {
|
||||
next_variation->next = games_to_keep;
|
||||
games_to_keep = next_variation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*** Functions concerned with reading details of the positional
|
||||
*** variations of interest.
|
||||
***/
|
||||
|
||||
/* Break up a single line of moves into a list of moves
|
||||
* comprising a positional variation.
|
||||
* In doing so, set GlobalState.depth_of_positional_search
|
||||
* if this variation is longer than the default.
|
||||
*/
|
||||
static Move *
|
||||
compose_positional_variation(char *line)
|
||||
{
|
||||
char *move;
|
||||
/* Build a linked list of the moves of the variation. */
|
||||
Move *head = NULL, *tail = NULL;
|
||||
Boolean Ok = TRUE;
|
||||
/* Keep track of the ply depth. */
|
||||
unsigned depth = 0;
|
||||
|
||||
move = strtok(line, " ");
|
||||
while (Ok && (move != NULL) && (*move != '*')) {
|
||||
if ((move = strip_move_number(move)) == NULL) {
|
||||
/* Only a move number. */
|
||||
}
|
||||
else {
|
||||
Move *next = decode_move((unsigned char *) move);
|
||||
|
||||
if (next == NULL) {
|
||||
fprintf(GlobalState.logfile, "Failed to identify %s\n", move);
|
||||
Ok = FALSE;
|
||||
}
|
||||
else {
|
||||
/* Chain it on to the list. */
|
||||
if (tail == NULL) {
|
||||
head = next;
|
||||
tail = next;
|
||||
}
|
||||
else {
|
||||
tail->next = next;
|
||||
tail = next;
|
||||
}
|
||||
next->next = NULL;
|
||||
}
|
||||
depth++;
|
||||
}
|
||||
/* Pick up the next likely move. */
|
||||
move = strtok(NULL, " ");
|
||||
}
|
||||
if (Ok) {
|
||||
/* Determine whether the depth of this variation exceeds
|
||||
* the current default.
|
||||
* Depth is counted in ply.
|
||||
* Add some extras, in order to catch transpositions.
|
||||
*/
|
||||
depth += 8;
|
||||
if (depth > GlobalState.depth_of_positional_search) {
|
||||
GlobalState.depth_of_positional_search = depth;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (head != NULL) {
|
||||
free_move_list(head);
|
||||
}
|
||||
head = NULL;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
/* Read each line of input and decompose it into a positional variation
|
||||
* to be placed in the list of required hash values.
|
||||
*/
|
||||
void
|
||||
add_positional_variations_from_file(FILE *fpin)
|
||||
{
|
||||
char *line;
|
||||
|
||||
while ((line = read_line(fpin)) != NULL) {
|
||||
add_positional_variation_from_line(line);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
add_positional_variation_from_line(char *line)
|
||||
{
|
||||
if (non_blank_line(line)) {
|
||||
Move *next_variation = compose_positional_variation(line);
|
||||
if (next_variation != NULL) {
|
||||
/* We need a NULL fen string, because this is from
|
||||
* the initial position.
|
||||
*/
|
||||
store_hash_value(next_variation, (const char *) NULL);
|
||||
free_move_list(next_variation);
|
||||
/* We need to know globally that positional variations
|
||||
* are of interest.
|
||||
*/
|
||||
GlobalState.positional_variations = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Treat fen_string as being a position to be matched.
|
||||
*/
|
||||
void
|
||||
add_fen_positional_match(const char *fen_string)
|
||||
{
|
||||
store_hash_value((Move *) NULL, fen_string);
|
||||
GlobalState.positional_variations = TRUE;
|
||||
}
|
||||
|
||||
/* Treat fen_pattern as being a position to be matched.
|
||||
*/
|
||||
void
|
||||
add_fen_pattern_match(const char *fen_pattern, Boolean add_reverse, const char *label)
|
||||
{
|
||||
add_fen_pattern(fen_pattern, add_reverse, label);
|
||||
GlobalState.positional_variations = TRUE;
|
||||
}
|
||||
|
||||
/* Roughly define a move character for the purposes of textual
|
||||
* matching.
|
||||
*/
|
||||
static Boolean
|
||||
move_char(char c)
|
||||
{
|
||||
return (Boolean) isalpha((int) c) || isdigit((int) c) || (c == '-');
|
||||
}
|
||||
|
||||
/* Return TRUE if there is a match for actual_move in variation_move.
|
||||
* A match means that the string in actual_move is found surrounded
|
||||
* by non-move characters in variation_move. For instance,
|
||||
* variation_move == "Nc6|Nf3|f3" would match
|
||||
* actual_move == "f3" but not actual_move == "c6".
|
||||
*/
|
||||
static Boolean
|
||||
textual_variation_match(const char *variation_move, const unsigned char *actual_move)
|
||||
{
|
||||
const char *match_point;
|
||||
Boolean found = FALSE;
|
||||
|
||||
for (match_point = variation_move; !found && (match_point != NULL);) {
|
||||
/* Try for a match from where we are. */
|
||||
match_point = strstr(match_point, (const char *) actual_move);
|
||||
if (match_point != NULL) {
|
||||
/* A possible match. Make sure that the match point
|
||||
* is surrounded by non-move characters so as to be sure
|
||||
* that we haven't picked up part way through a variation string.
|
||||
* Assume success.
|
||||
*/
|
||||
found = TRUE;
|
||||
if (match_point != variation_move) {
|
||||
if (move_char(match_point[-1])) {
|
||||
found = FALSE;
|
||||
}
|
||||
}
|
||||
if (move_char(match_point[strlen((const char *) actual_move)])) {
|
||||
found = FALSE;
|
||||
}
|
||||
if (!found) {
|
||||
/* Move on the match point and try again. */
|
||||
while (move_char(*match_point)) {
|
||||
match_point++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
|
||||
}
|
||||
|
||||
/*** Functions concerned with matching the moves of the current game
|
||||
*** against the variations of interest.
|
||||
***/
|
||||
|
||||
/* Do the moves of the current game match the given variation?
|
||||
* Go for a straight 1-1 match in the ordering, without considering
|
||||
* permutations.
|
||||
* Return TRUE if so, FALSE otherwise.
|
||||
*/
|
||||
static Boolean
|
||||
straight_match(Move *current_game_head, variation_list variation)
|
||||
{
|
||||
variant_move *moves_of_the_variation;
|
||||
/* Which is the next move that we wish to match. */
|
||||
Move *next_move;
|
||||
unsigned move_index = 0;
|
||||
/* Assume that it matches. */
|
||||
Boolean matches = TRUE;
|
||||
|
||||
/* Access the head of the current game. */
|
||||
next_move = current_game_head;
|
||||
/* Go for a straight move-by-move match in the order in which
|
||||
* the variation is listed.
|
||||
* Point at the head of the moves list.
|
||||
*/
|
||||
moves_of_the_variation = variation.moves;
|
||||
move_index = 0;
|
||||
while (matches && (next_move != NULL) && (move_index < variation.length)) {
|
||||
Boolean this_move_matches;
|
||||
|
||||
if (*(moves_of_the_variation[move_index].move) == ANY_MOVE) {
|
||||
/* Still matching as we don't care what the actual move is. */
|
||||
}
|
||||
else {
|
||||
this_move_matches =
|
||||
textual_variation_match(moves_of_the_variation[move_index].move,
|
||||
next_move->move);
|
||||
if (this_move_matches) {
|
||||
/* We found a match, check that it isn't disallowed. */
|
||||
if (*moves_of_the_variation[move_index].move == DISALLOWED_MOVE) {
|
||||
/* This move is disallowed and implies failure. */
|
||||
matches = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (*moves_of_the_variation[move_index].move != DISALLOWED_MOVE) {
|
||||
/* No match found for this move. */
|
||||
matches = FALSE;
|
||||
}
|
||||
else {
|
||||
/* This is ok, because we didn't want a match. */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/* If we are still matching, go on to the next move. */
|
||||
if (matches) {
|
||||
move_index++;
|
||||
next_move = next_move->next;
|
||||
}
|
||||
}
|
||||
/* The game could be shorter than the variation, so don't rely
|
||||
* on the fact that matches is still true.
|
||||
*/
|
||||
matches = (move_index == variation.length);
|
||||
return matches;
|
||||
}
|
||||
|
||||
/* Do the moves of the current game match the given variation?
|
||||
* Try all possible orderings for the moves, within the
|
||||
* constraint of proper WHITE/BLACK moves.
|
||||
* The parameter variation is passed as a copy because we modify
|
||||
* the num_ fields within it.
|
||||
* Note that there is a possibility of a false match in this
|
||||
* function if a variant move is specified in a form such as:
|
||||
* *|c4
|
||||
* This is because the num_ field is set from this on the basis of the
|
||||
* ANY_MOVE character at the start. However, this could also match a
|
||||
* normal move with its c4 component. If it is used for the latter
|
||||
* purpose then it should not count as an any_ move. There is a warning
|
||||
* issued about this when variations are read in.
|
||||
* Return TRUE if we match, FALSE otherwise.
|
||||
*
|
||||
* The DISALLOWED_MOVE presents some problems with permutation matches
|
||||
* because an ANY_MOVE could match an otherwise disallowed move. The
|
||||
* approach that has been taken is to cause matching of a single disallowed
|
||||
* move to result in complete failure of the current match.
|
||||
*/
|
||||
static Boolean
|
||||
permutation_match(Move *current_game_head, variation_list variation)
|
||||
{
|
||||
variant_move *moves_of_the_variation;
|
||||
/* Which is the next move that we wish to match? */
|
||||
Move *next_move;
|
||||
unsigned variant_index = 0;
|
||||
/* Assume that it matches. */
|
||||
Boolean matches = TRUE;
|
||||
/* How many moves have we matched?
|
||||
* When this reaches variation.length we have a full match.
|
||||
*/
|
||||
unsigned matched_moves = 0;
|
||||
Boolean white_to_move = TRUE;
|
||||
|
||||
moves_of_the_variation = variation.moves;
|
||||
/* Clear all of the matched fields of the variation. */
|
||||
for (variant_index = 0; variant_index < variation.length; variant_index++) {
|
||||
moves_of_the_variation[variant_index].matched = FALSE;
|
||||
}
|
||||
/* Access the head of the current game. */
|
||||
next_move = current_game_head;
|
||||
|
||||
/*** Stage One.
|
||||
* The first task is to ensure that there are no DISALLOWED_MOVEs in
|
||||
* the current game.
|
||||
*/
|
||||
if ((variation.num_white_disallowed_moves > 0) ||
|
||||
(variation.num_black_disallowed_moves > 0)) {
|
||||
unsigned tested_moves = 0;
|
||||
Boolean disallowed_move_found = FALSE;
|
||||
|
||||
/* Keep going as long as we still have not found a diallowed move,
|
||||
* we haven't matched the whole variation, and we haven't reached the end of
|
||||
* the game.
|
||||
*/
|
||||
while ((!disallowed_move_found) && (tested_moves < variation.length) &&
|
||||
(next_move != NULL)) {
|
||||
/* We want to see if next_move is a disallowed move of the variation. */
|
||||
if (white_to_move) {
|
||||
/* White; start with the first move. */
|
||||
variant_index = 0;
|
||||
}
|
||||
else {
|
||||
/* For a Black move, start at the second half-move in the list, if any. */
|
||||
variant_index = 1;
|
||||
}
|
||||
/* Try each move of the variation in turn, until a match is found. */
|
||||
while ((!disallowed_move_found) && (variant_index < variation.length)) {
|
||||
if ((*moves_of_the_variation[variant_index].move ==
|
||||
DISALLOWED_MOVE) &&
|
||||
(textual_variation_match(
|
||||
moves_of_the_variation[variant_index].move, next_move->move))) {
|
||||
/* Found one. */
|
||||
disallowed_move_found = TRUE;
|
||||
}
|
||||
if (!disallowed_move_found) {
|
||||
/* Move on to the next available move -- 2 half moves along. */
|
||||
variant_index += 2;
|
||||
}
|
||||
}
|
||||
if (!disallowed_move_found) {
|
||||
/* Ok so far, so move on. */
|
||||
tested_moves++;
|
||||
white_to_move = !white_to_move;
|
||||
next_move = next_move->next;
|
||||
}
|
||||
}
|
||||
if (disallowed_move_found) {
|
||||
/* This rules out the whole match. */
|
||||
matches = FALSE;
|
||||
}
|
||||
else {
|
||||
/* In effect, each DISALLOWED_MOVE now becomes an ANY_MOVE. */
|
||||
for (variant_index = 0; variant_index < variation.length; variant_index++) {
|
||||
if (*moves_of_the_variation[variant_index].move == DISALLOWED_MOVE) {
|
||||
moves_of_the_variation[variant_index].matched = TRUE;
|
||||
if ((variant_index & 1) == 0) {
|
||||
variation.num_white_any_moves++;
|
||||
}
|
||||
else {
|
||||
variation.num_black_any_moves++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*** Stage Two.
|
||||
* Having eliminated moves which have been disallowed, try permutations
|
||||
* of the variation against the moves of the current game.
|
||||
*/
|
||||
/* Access the head of the current game. */
|
||||
next_move = current_game_head;
|
||||
white_to_move = TRUE;
|
||||
/* Keep going as long as we still have matches, we haven't
|
||||
* matched the whole variation, and we haven't reached the end of
|
||||
* the game.
|
||||
*/
|
||||
while (matches && (matched_moves < variation.length) && (next_move != NULL)) {
|
||||
/* Assume failure. */
|
||||
matches = FALSE;
|
||||
/* We want to find next_move in an unmatched move of the variation. */
|
||||
if (white_to_move) {
|
||||
/* Start with the first move. */
|
||||
variant_index = 0;
|
||||
}
|
||||
else {
|
||||
/* For a Black move, start at the second half-move in the list, if any. */
|
||||
variant_index = 1;
|
||||
}
|
||||
/* Try each move of the variation in turn, until a match is found. */
|
||||
while ((!matches) && (variant_index < variation.length)) {
|
||||
if (moves_of_the_variation[variant_index].matched) {
|
||||
/* We can't try this. */
|
||||
}
|
||||
else {
|
||||
Boolean this_move_matches = textual_variation_match(
|
||||
moves_of_the_variation[variant_index].move,
|
||||
next_move->move);
|
||||
if (this_move_matches) {
|
||||
/* Found it. */
|
||||
moves_of_the_variation[variant_index].matched = TRUE;
|
||||
matches = TRUE;
|
||||
}
|
||||
}
|
||||
if (!matches) {
|
||||
/* Move on to the next available move -- 2 half moves along. */
|
||||
variant_index += 2;
|
||||
}
|
||||
}
|
||||
/* See if we made a straight match. */
|
||||
if (!matches) {
|
||||
/* See if we have some ANY_MOVEs available. */
|
||||
if (white_to_move && (variation.num_white_any_moves > 0)) {
|
||||
matches = TRUE;
|
||||
variation.num_white_any_moves--;
|
||||
}
|
||||
else if (!white_to_move && (variation.num_black_any_moves > 0)) {
|
||||
matches = TRUE;
|
||||
variation.num_black_any_moves--;
|
||||
}
|
||||
else {
|
||||
/* No slack. */
|
||||
}
|
||||
}
|
||||
/* We have tried everything, did we succeed? */
|
||||
if (matches) {
|
||||
/* Yes, so move on. */
|
||||
matched_moves++;
|
||||
next_move = next_move->next;
|
||||
white_to_move = !white_to_move;
|
||||
}
|
||||
}
|
||||
if (matches) {
|
||||
/* Ensure that we completed the variation. */
|
||||
matches = matched_moves == (variation.length);
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
/* Determine whether or not the current game is wanted.
|
||||
* It will be if we are either not looking for checkmate-only
|
||||
* games, or if we are and the games does end in checkmate.
|
||||
*/
|
||||
Boolean
|
||||
check_for_only_checkmate(const Game *game_details)
|
||||
{
|
||||
if (GlobalState.match_only_checkmate) {
|
||||
const Move *moves = game_details->moves;
|
||||
/* Check that the final move is checkmate. */
|
||||
while (moves != NULL && moves->check_status != CHECKMATE) {
|
||||
moves = moves->next;
|
||||
}
|
||||
if (moves == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* No restriction to a checkmate game. */
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine whether or not the current game is wanted.
|
||||
* It will be if we are either not looking for stalemate-only
|
||||
* games, or if we are and the games does end in stalemate.
|
||||
*/
|
||||
Boolean
|
||||
check_for_only_stalemate(const Board *board, const Move *moves)
|
||||
{
|
||||
if (GlobalState.match_only_stalemate) {
|
||||
return is_stalemate(board, moves);
|
||||
}
|
||||
else {
|
||||
/* No restriction to a stalemate game. */
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether the final position on the given board
|
||||
* is stalemate or not.
|
||||
*/
|
||||
Boolean
|
||||
is_stalemate(const Board *board, const Move *moves)
|
||||
{
|
||||
if (moves != NULL) {
|
||||
/* Check that the final move is not check or checkmate. */
|
||||
const Move *move = moves;
|
||||
while (move->next != NULL) {
|
||||
move = move->next;
|
||||
}
|
||||
if (move->check_status != NOCHECK) {
|
||||
/* Cannot be stalemate. */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return !at_least_one_move(board, board->to_move);
|
||||
}
|
||||
|
||||
/* Determine whether or not the current game is wanted.
|
||||
* It will be if it matches one of the current variations
|
||||
* and its tag details match those that we are interested in.
|
||||
*/
|
||||
Boolean
|
||||
check_textual_variations(const Game *game_details)
|
||||
{
|
||||
Boolean wanted = FALSE;
|
||||
variation_list *variation;
|
||||
|
||||
if (games_to_keep != NULL) {
|
||||
for (variation = games_to_keep; (variation != NULL) && !wanted;
|
||||
variation = variation->next) {
|
||||
if (GlobalState.match_permutations) {
|
||||
wanted = permutation_match(game_details->moves, *variation);
|
||||
}
|
||||
else {
|
||||
wanted = straight_match(game_details->moves, *variation);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* There are no variations, assume that selection is done
|
||||
* on the basis of the Details.
|
||||
*/
|
||||
wanted = TRUE;
|
||||
}
|
||||
return wanted;
|
||||
}
|
||||
|
||||
/* Determine whether the number of ply in this game
|
||||
* is within the bounds of what we want.
|
||||
*/
|
||||
Boolean
|
||||
check_move_bounds(unsigned plycount)
|
||||
{
|
||||
|
||||
if (GlobalState.check_move_bounds) {
|
||||
return (GlobalState.lower_move_bound <= plycount) &&
|
||||
(plycount <= GlobalState.upper_move_bound);
|
||||
}
|
||||
else {
|
||||
// No restriction.
|
||||
return TRUE;
|
||||
}
|
||||
}
|
38
pgn-extract/moves.h
Normal file
38
pgn-extract/moves.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#ifndef MOVES_H
|
||||
#define MOVES_H
|
||||
|
||||
void add_positional_variations_from_file(FILE *fpin);
|
||||
void add_positional_variation_from_line(char *line);
|
||||
void add_textual_variations_from_file(FILE *fpin);
|
||||
void add_textual_variation_from_line(char *line);
|
||||
Boolean check_textual_variations(const Game *game_details);
|
||||
Boolean check_move_bounds(unsigned plycount);
|
||||
void add_fen_positional_match(const char *fen_string);
|
||||
void add_fen_pattern_match(const char *fen_pattern, Boolean add_reverse, const char *label);
|
||||
Boolean check_for_only_checkmate(const Game *game_details);
|
||||
Boolean check_for_only_stalemate(const Board *board, const Move *moves);
|
||||
Boolean is_stalemate(const Board *board, const Move *moves);
|
||||
|
||||
#endif // MOVES_H
|
||||
|
52
pgn-extract/mymalloc.c
Normal file
52
pgn-extract/mymalloc.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mymalloc.h"
|
||||
|
||||
/* Allocate the required space or abort the program. */
|
||||
void *
|
||||
malloc_or_die(size_t nbytes)
|
||||
{
|
||||
void *result;
|
||||
|
||||
result = malloc(nbytes);
|
||||
if (result == NULL) {
|
||||
perror("malloc or die");
|
||||
abort();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Allocate the required space or abort the program. */
|
||||
void *
|
||||
realloc_or_die(void *space, size_t nbytes)
|
||||
{
|
||||
void *result;
|
||||
|
||||
result = realloc(space, nbytes);
|
||||
if (result == NULL) {
|
||||
perror("realloc or die");
|
||||
abort();
|
||||
}
|
||||
return result;
|
||||
}
|
30
pgn-extract/mymalloc.h
Normal file
30
pgn-extract/mymalloc.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#ifndef MYMALLOC_H
|
||||
#define MYMALLOC_H
|
||||
|
||||
void *malloc_or_die(size_t nbytes);
|
||||
void *realloc_or_die(void *space,size_t nbytes);
|
||||
char *copy_string(const char *str);
|
||||
|
||||
#endif // MYMALLOC_H
|
||||
|
1797
pgn-extract/output.c
Normal file
1797
pgn-extract/output.c
Normal file
File diff suppressed because it is too large
Load Diff
38
pgn-extract/output.h
Normal file
38
pgn-extract/output.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#ifndef OUTPUT_H
|
||||
#define OUTPUT_H
|
||||
|
||||
void format_game(Game *current_game,FILE *outputfile);
|
||||
void print_str(FILE *fp, const char *str);
|
||||
void terminate_line(FILE *fp);
|
||||
OutputFormat which_output_format(const char *arg);
|
||||
const char *output_file_suffix(OutputFormat format);
|
||||
void add_to_output_tag_order(TagName tag);
|
||||
void set_output_line_length(unsigned max);
|
||||
void add_plycount(const Game *game);
|
||||
void add_total_plycount(const Game *game, Boolean count_variations);
|
||||
/* Provide enough static space to build FEN string. */
|
||||
#define FEN_SPACE 100
|
||||
|
||||
#endif // OUTPUT_H
|
||||
|
45
pgn-extract/pgn-extract.man
Normal file
45
pgn-extract/pgn-extract.man
Normal file
@@ -0,0 +1,45 @@
|
||||
.TH PGN-EXTRACT 1 "May 19, 2013"
|
||||
.SH NAME
|
||||
pgn-extract - a Portable Game Notation (PGN) extractor
|
||||
.SH SYNOPSIS
|
||||
.B pgn-extract
|
||||
[flags] file.pgn [file.pgn ...]
|
||||
.SH DESCRIPTION
|
||||
.B pgn-extract
|
||||
is a free, open-source program pgn-extract, which is designed to
|
||||
support the processing, searching and extraction of chess games from
|
||||
files written in PGN format. There are several ways to specify the
|
||||
criteria on which to extract: textual move sequences, the position
|
||||
reached after a sequence of moves, information in the tag fields, and
|
||||
material balance in the ending. Full ANSI C source and a 32-bit
|
||||
Windows binary for the program are available under the terms of the
|
||||
GNU General Public License. The program includes a semantic analyser
|
||||
which will report errors in game scores and it is also able to detect
|
||||
duplicate games found in one or more of its input files.
|
||||
|
||||
The range of input move formats accepted is fairly wide and includes
|
||||
recognition of lower-case piece letters for English and upper-case
|
||||
piece letters for Dutch and German. The default output is in English
|
||||
Standard Algebraic Notation (SAN), although there is some support for
|
||||
output in different notations.
|
||||
|
||||
Extracted games may be written out either including or excluding
|
||||
comments, NAGs, and variations. Games may be given ECO classifications
|
||||
derived from the accompanying file eco.pgn, or a customised version
|
||||
provided by the user.
|
||||
|
||||
Plus, lots of other useful features that have gradually found their
|
||||
way into what was once a relatively simple program!
|
||||
.SH OPTIONS
|
||||
Run
|
||||
.B pgn-extract -h
|
||||
to get all the options.
|
||||
|
||||
A complete description of each option can be found in
|
||||
.B /usr/share/doc/pgn-extract/help.html
|
||||
.SH AUTHOR
|
||||
pgn-extract was written by David J. Barnes <d.j.barnes@kent.ac.uk>.
|
||||
|
||||
This manual page was written by Peter van Rossum <petervr@debian.org>
|
||||
and Vincent Legout <vlegout@debian.org>, for the Debian GNU/Linux
|
||||
system.
|
125
pgn-extract/pgn-extract.xml
Normal file
125
pgn-extract/pgn-extract.xml
Normal file
@@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<rss version="2.0">
|
||||
|
||||
<channel>
|
||||
<title>Home Page for pgn-extract</title>
|
||||
<link>https://www.cs.kent.ac.uk/~djb/pgn-extract/</link>
|
||||
<description>A Portable Game Notation (PGN) manipulator</description>
|
||||
|
||||
<item>
|
||||
<title>Version 22-11</title>
|
||||
<link>https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-22-11.tgz</link>
|
||||
<description>C source code for version 22-11.
|
||||
Windows binary available from the home page.
|
||||
A couple of bug fixes associated with position matching via -z.
|
||||
New options --firstgame, --gamelimit, --seventyfive and --repetition5.
|
||||
Regular expression matches via -t.
|
||||
</description>
|
||||
<guid isPermaLink="false">pgn-extract-22-11-announce</guid>
|
||||
<pubDate>15 August 2022 21:00:00 GMT</pubDate>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>Version 22-07</title>
|
||||
<link>https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-22-07.tgz</link>
|
||||
<description>C source code for version 22-07.
|
||||
Windows binary available from the home page.
|
||||
This is largely a bug fix release to fix failure to NULL a freed pointer.
|
||||
In addition, relational operators may now be used to match
|
||||
any wholly numeric tag values via the -t flag.
|
||||
</description>
|
||||
<guid isPermaLink="false">pgn-extract-22-07-announce</guid>
|
||||
<pubDate>03 May 2022 22:00:00 GMT</pubDate>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>Version 22-05</title>
|
||||
<link>https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-22-05.tgz</link>
|
||||
<description>C source code for version 22-05.
|
||||
Windows binary available from the home page.
|
||||
This is largely a bug fix release.
|
||||
</description>
|
||||
<guid isPermaLink="false">pgn-extract-22-05-announce</guid>
|
||||
<pubDate>23 Feb 2022 21:00:00 GMT</pubDate>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>Version 21-08</title>
|
||||
<link>https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-21-08.tgz</link>
|
||||
<description>C source code for version 21-08. Windows 64-bit and 32-bit
|
||||
binaries available from the home page.
|
||||
This is a catch-up release for the end of the year. It adds a
|
||||
de-tagging option, and extended
|
||||
matching of TimeControl to include the formats of sudden death and sandclock. </description>
|
||||
<guid isPermaLink="false">pgn-extract-21-08-announce</guid>
|
||||
<pubDate>28 Dec 2021 17:00:00 GMT</pubDate>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>Version 21-02</title>
|
||||
<link>https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-21-02.tgz</link>
|
||||
<description>C source code for version 21-02. win32 binary available from
|
||||
the home page.
|
||||
This version is mainly a bug-fix release for the --fixtagstrings option but
|
||||
it also adds the --linenumbers option.
|
||||
</description>
|
||||
<guid isPermaLink="false">pgn-extract-21-02-announce</guid>
|
||||
<pubDate>27 Jan 2021 11:45:00 GMT</pubDate>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>Version 20-06</title>
|
||||
<link>https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-20-06.tgz</link>
|
||||
<description>C source code for version 20-06. win32 binary available from
|
||||
the home page.
|
||||
This version is mainly an end-of-year release to catch up on a few additions
|
||||
since version 20-03.
|
||||
Date matches extended to match on month and day as well as year and a few more
|
||||
command-line options: --fixtagstrings attempts to fix common bad string formats
|
||||
in tag strings; and --wtm/--btm add the requirement for white-to-move/black-to-move
|
||||
in matches.
|
||||
</description>
|
||||
<guid isPermaLink="false">pgn-extract-20-06-announce</guid>
|
||||
<pubDate>18 Dec 2020 21:00:00 GMT</pubDate>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>Version 20-03</title>
|
||||
<link>https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-20-03.tgz</link>
|
||||
<description>C source code for version 20-03. win32 binary available from
|
||||
the home page.
|
||||
This version contains a few bug fixes and adds --startply, --fenpattern and --material
|
||||
command-line options.
|
||||
There is also limited relational matching for the TimeControl tag.
|
||||
</description>
|
||||
<guid isPermaLink="false">pgn-extract-20-03-announce</guid>
|
||||
<pubDate>25 July 2020 21:00:00 GMT</pubDate>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>Version 19-04</title>
|
||||
<link>https://www.cs.kent.ac.uk/~djb/pgn-extract/pgn-extract-19-04.tgz</link>
|
||||
<description>C source code for version 19-04. win32 binary available from
|
||||
the home page. This version fixes a memory error with some positional match
|
||||
combinations and false positives with --repetition.
|
||||
It also adds --xroster to suppress additional tags with -R and adds a short
|
||||
man page courtesy of Vincent Legout.
|
||||
</description>
|
||||
<guid isPermaLink="false">pgn-extract-19-04-announce</guid>
|
||||
<pubDate>23 April 2019 21:00:00 GMT</pubDate>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>Using pgn-extract to mine chess data</title>
|
||||
<link>https://blogs.kent.ac.uk/djb/2018/10/14/data-mining-with-pgn-extract/</link>
|
||||
<description>A blog post about using pgn-extract to investigate the
|
||||
effect of material balances, with a particular focus on the case
|
||||
of the bishop pair.
|
||||
</description>
|
||||
<guid isPermaLink="false">pgn-extract-data-mining</guid>
|
||||
<pubDate>16 October 2018 07:45:00 GMT</pubDate>
|
||||
</item>
|
||||
|
||||
</channel>
|
||||
|
||||
</rss>
|
520
pgn-extract/style.css
Executable file
520
pgn-extract/style.css
Executable file
@@ -0,0 +1,520 @@
|
||||
/*
|
||||
Design by Free CSS Templates
|
||||
http://www.freecsstemplates.org
|
||||
Released for free under a Creative Commons Attribution 2.5 License
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0px 0px 0px 0px;
|
||||
padding: 0;
|
||||
background: #FFFFFF;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-weight: 200;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 2em;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
p, ol, ul, pre, td {
|
||||
margin-top: 0px;
|
||||
padding: 0px;
|
||||
color: #070707;
|
||||
/* color: #000000; */
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
p, ol {
|
||||
/* line-height: 180%; */
|
||||
}
|
||||
|
||||
p {
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
table, th, td {
|
||||
margin-left: 20px;
|
||||
border: 1px solid black;
|
||||
padding: 5px;
|
||||
text-align: left;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-left: 2em;
|
||||
font-family: "Courier New", "Lucida Console", monospace;
|
||||
}
|
||||
|
||||
strong {
|
||||
}
|
||||
|
||||
a {
|
||||
color: #5C5539;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
img.border {
|
||||
}
|
||||
|
||||
img.alignleft {
|
||||
float: left;
|
||||
}
|
||||
|
||||
img.alignright {
|
||||
float: right;
|
||||
}
|
||||
|
||||
img.aligncenter {
|
||||
margin: 0px auto;
|
||||
}
|
||||
|
||||
hr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/** WRAPPER */
|
||||
|
||||
#wrapper {
|
||||
overflow: hidden;
|
||||
background: #FFFFFF;
|
||||
}
|
||||
|
||||
.container {
|
||||
/* width: 1200px; */
|
||||
margin: 0px auto;
|
||||
}
|
||||
|
||||
.clearfix {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
|
||||
#header-wrapper {
|
||||
overflow: hidden;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
#header {
|
||||
/* width: 1200px; */
|
||||
height: 150px;
|
||||
margin: 0 auto;
|
||||
padding: 0px 0px;
|
||||
}
|
||||
|
||||
/* Logo */
|
||||
|
||||
#logo {
|
||||
float: left;
|
||||
width: 310px;
|
||||
height: 150px;
|
||||
padding: 0px 0px 0px 40px;
|
||||
}
|
||||
|
||||
#logo h1 {
|
||||
padding: 50px 0px 0px 0px;
|
||||
text-transform: lowercase;
|
||||
letter-spacing: -2px;
|
||||
font-size: 3.6em;
|
||||
}
|
||||
|
||||
#logo h1 a {
|
||||
text-decoration: none;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
|
||||
/* Menu */
|
||||
|
||||
#menu {
|
||||
float: right;
|
||||
width: 810px;
|
||||
height: 80px;
|
||||
padding: 20px 40px 0px 0px;
|
||||
}
|
||||
|
||||
#menu ul {
|
||||
float: right;
|
||||
margin: 0;
|
||||
padding: 40px 0px 0px 0px;
|
||||
list-style: none;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
#menu li {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#menu a {
|
||||
display: block;
|
||||
margin-left: 1px;
|
||||
padding: 7px 20px 7px 20px;
|
||||
letter-spacing: 1px;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-family: 'Oswald', sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 300;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
#menu a:hover, #menu .current_page_item a {
|
||||
text-decoration: none;
|
||||
background: #1B5902;
|
||||
border-radius: 5px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* Page */
|
||||
|
||||
#page-wrapper {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#page {
|
||||
overflow: hidden;
|
||||
/* width: 1120px; */
|
||||
margin: 0px auto;
|
||||
padding: 20px 40px;
|
||||
color: #8F8F8F;
|
||||
border-top: 3px solid #A1A1A1;
|
||||
}
|
||||
|
||||
/** CONTENT */
|
||||
|
||||
#wide-content {
|
||||
}
|
||||
|
||||
#wide-content h2 {
|
||||
padding: 0px 0px 20px 0px;
|
||||
letter-spacing: -1px;
|
||||
font-size: 36px;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
|
||||
/** CONTENT */
|
||||
|
||||
#content {
|
||||
float: right;
|
||||
width: 800px;
|
||||
padding: 0px 0px 0px 0px;
|
||||
}
|
||||
|
||||
#content h2 {
|
||||
padding: 0px 0px 20px 0px;
|
||||
letter-spacing: -1px;
|
||||
font-size: 36px;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
#content .subtitle {
|
||||
padding: 0px 0px 30px 0px;
|
||||
text-transform: uppercase;
|
||||
font-family: 'Oswald', sans-serif;
|
||||
font-size: 18px;
|
||||
color: #81AFC5;
|
||||
}
|
||||
|
||||
/** SIDEBAR */
|
||||
|
||||
#sidebar {
|
||||
float: left;
|
||||
width: 290px;
|
||||
padding: 0px 0px 20px 0px;
|
||||
}
|
||||
|
||||
#sidebar h2 {
|
||||
padding: 0px 0px 30px 0px;
|
||||
letter-spacing: -1px;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
|
||||
#footer {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#footer p {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
#footer a {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
/* Three Column Footer Content */
|
||||
|
||||
|
||||
#footer-bg {
|
||||
overflow: hidden;
|
||||
padding: 40px 0px;
|
||||
background:#E5E0DD url(images/main-bsg.png) repeat;
|
||||
}
|
||||
|
||||
#footer-content {
|
||||
color: #67C8E3;
|
||||
}
|
||||
|
||||
#footer-content h2 {
|
||||
margin: 0px;
|
||||
padding: 0px 0px 30px 0px;
|
||||
letter-spacing: -1px;
|
||||
text-shadow: 1px 1px 0px #FFFFFF;
|
||||
text-transform: uppercase;
|
||||
font-size: 20px;
|
||||
font-weight: 200;
|
||||
color: #93776E;
|
||||
}
|
||||
|
||||
#footer-content a {
|
||||
}
|
||||
|
||||
#footer-content a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
#column1 {
|
||||
float: left;
|
||||
width: 280px;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
#column1 p {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
#column2 {
|
||||
float: left;
|
||||
width: 280px;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
#column3 {
|
||||
float: left;
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
#column4 {
|
||||
float: right;
|
||||
width: 260px;
|
||||
}
|
||||
|
||||
|
||||
/* Banner Style */
|
||||
|
||||
#banner-wrapper {
|
||||
background: #FFFFFF;
|
||||
}
|
||||
|
||||
#banner {
|
||||
overflow: hidden;
|
||||
background: #FFFFFF;
|
||||
/* width: 1160px; */
|
||||
margin: 20px auto 50px auto;
|
||||
}
|
||||
|
||||
#banner h1 {
|
||||
text-align: center
|
||||
}
|
||||
|
||||
#banner .img-border {
|
||||
height: 500px;
|
||||
border: 20px solid #FFFFFF;
|
||||
}
|
||||
|
||||
/* Button Style */
|
||||
|
||||
.button-style {
|
||||
display: inline-block;
|
||||
margin-top: 30px;
|
||||
padding: 7px 30px;
|
||||
background: #36332E;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.button-style a {
|
||||
letter-spacing: 1px;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
font-family: 'Oswald', sans-serif;
|
||||
font-weight: 300;
|
||||
font-size: 16px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* List Style 1 */
|
||||
|
||||
ul.style1 {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
ul.style1 li {
|
||||
padding: 25px 0px 15px 0px;
|
||||
border-top: 1px solid #A1A1A1;
|
||||
}
|
||||
|
||||
ul.style1 a {
|
||||
text-decoration: none;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
ul.style1 a:hover {
|
||||
text-decoration: underline;
|
||||
color: #6B6B6B;
|
||||
}
|
||||
|
||||
ul.style1 .first {
|
||||
padding-top: 0px;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
/** LIST STYLE 3 */
|
||||
|
||||
ul.style3 {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
ul.style3 li {
|
||||
padding: 10px 0px 10px 0px;
|
||||
border-top: 1px solid #A1A1A1;
|
||||
}
|
||||
|
||||
ul.style3 a {
|
||||
text-decoration: none;
|
||||
color: #949494;
|
||||
}
|
||||
|
||||
ul.style3 a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
ul.style3 .first {
|
||||
padding-top: 0px;
|
||||
border-top: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
ul.style3 .date {
|
||||
width: 87px;
|
||||
background-color: #36332E;
|
||||
margin-top: 20px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
ul.style3 .first .date
|
||||
{
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
|
||||
/* Recent News */
|
||||
|
||||
#recent-news {
|
||||
overflow: hidden;
|
||||
width: 1120px;
|
||||
margin: 0px auto;
|
||||
padding: 50px 40px;
|
||||
background: #36332E;
|
||||
color: #8C8C8C;
|
||||
}
|
||||
|
||||
#recent-news h2 {
|
||||
padding: 0px 0px 20px 0px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 2.5em;
|
||||
color: #EDEDED;
|
||||
}
|
||||
|
||||
#recent-news .date {
|
||||
padding: 0px 0px 10px 0px;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
color: #E3E3E3;
|
||||
}
|
||||
|
||||
#recent-news p {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#recent-news a {
|
||||
font-style: normal;
|
||||
color: #B8B8B8;
|
||||
}
|
||||
|
||||
#recent-news #rbox1 {
|
||||
float: left;
|
||||
width: 250px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
#recent-news #rbox2 {
|
||||
float: left;
|
||||
width: 250px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
#recent-news #rbox3 {
|
||||
float: left;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
#recent-news #rbox4 {
|
||||
float: right;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
/* Button Style */
|
||||
|
||||
.button-style1 {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.button-style1 a {
|
||||
padding: 10px 25px;
|
||||
background: #EBB462;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
text-shadow: 1px 1px 0px #FCE3BB;
|
||||
color: #36332E !important;
|
||||
}
|
267
pgn-extract/taglines.c
Normal file
267
pgn-extract/taglines.c
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "bool.h"
|
||||
#include "defs.h"
|
||||
#include "typedef.h"
|
||||
#include "tokens.h"
|
||||
#include "taglist.h"
|
||||
#include "lex.h"
|
||||
#include "lines.h"
|
||||
#include "lists.h"
|
||||
#include "moves.h"
|
||||
#include "output.h"
|
||||
#include "taglines.h"
|
||||
|
||||
static FILE *yyin = NULL;
|
||||
|
||||
/* Read the list of extraction criteria from TagFile.
|
||||
* This doesn't use the normal lexical analyser before the
|
||||
* PGN files are processed but circumvents next_token by
|
||||
* calling get_tag() and get_string. This allows it to detect
|
||||
* EOF before yywrap() is called.
|
||||
* Be careful to leave lex in the right state.
|
||||
*/
|
||||
void
|
||||
read_tag_file(const char *TagFile)
|
||||
{
|
||||
yyin = fopen(TagFile, "r");
|
||||
if (yyin != NULL) {
|
||||
Boolean keep_reading = TRUE;
|
||||
|
||||
while (keep_reading) {
|
||||
char *line = next_input_line(yyin);
|
||||
if (line != NULL) {
|
||||
keep_reading = process_tag_line(TagFile, line);
|
||||
}
|
||||
else {
|
||||
keep_reading = FALSE;
|
||||
}
|
||||
}
|
||||
(void) fclose(yyin);
|
||||
/* Call yywrap in order to set up for the next (first) input file. */
|
||||
(void) yywrap();
|
||||
yyin = NULL;
|
||||
}
|
||||
else {
|
||||
fprintf(GlobalState.logfile,
|
||||
"Unable to open %s for reading.\n", TagFile);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the contents of a file that lists the
|
||||
* required output ordering for tags.
|
||||
*/
|
||||
void
|
||||
read_tag_roster_file(const char *RosterFile)
|
||||
{
|
||||
Boolean keep_reading = TRUE;
|
||||
yyin = must_open_file(RosterFile, "r");
|
||||
|
||||
while (keep_reading) {
|
||||
char *line = next_input_line(yyin);
|
||||
if (line != NULL) {
|
||||
keep_reading = process_roster_line(line);
|
||||
}
|
||||
else {
|
||||
keep_reading = FALSE;
|
||||
}
|
||||
}
|
||||
(void) fclose(yyin);
|
||||
/* Call yywrap in order to set up for the next (first) input file. */
|
||||
(void) yywrap();
|
||||
}
|
||||
|
||||
/* Extract a tag/value pair from the given line.
|
||||
* Return TRUE if this was successful.
|
||||
*/
|
||||
Boolean
|
||||
process_tag_line(const char *TagFile, char *line)
|
||||
{
|
||||
Boolean keep_reading = TRUE;
|
||||
if (non_blank_line(line)) {
|
||||
unsigned char *linep = (unsigned char *) line;
|
||||
/* We should find a tag. */
|
||||
LinePair resulting_line = gather_tag(line, linep);
|
||||
TokenType tag_token;
|
||||
|
||||
/* Pick up where we are now. */
|
||||
line = resulting_line.line;
|
||||
linep = resulting_line.linep;
|
||||
tag_token = resulting_line.token;
|
||||
if (tag_token != NO_TOKEN) {
|
||||
/* Pick up which tag it was. */
|
||||
int tag_index = yylval.tag_index;
|
||||
/* Allow for an optional operator. */
|
||||
TagOperator operator = NONE;
|
||||
|
||||
/* Skip whitespace. */
|
||||
while (is_character_class(*linep, WHITESPACE)) {
|
||||
linep++;
|
||||
}
|
||||
/* Allow for an optional operator. */
|
||||
if (is_character_class(*linep, OPERATOR)) {
|
||||
switch (*linep) {
|
||||
case '<':
|
||||
linep++;
|
||||
if (*linep == '=') {
|
||||
linep++;
|
||||
operator = LESS_THAN_OR_EQUAL_TO;
|
||||
}
|
||||
else if (*linep == '>') {
|
||||
linep++;
|
||||
operator = NOT_EQUAL_TO;
|
||||
}
|
||||
else {
|
||||
operator = LESS_THAN;
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
linep++;
|
||||
if (*linep == '=') {
|
||||
linep++;
|
||||
operator = GREATER_THAN_OR_EQUAL_TO;
|
||||
}
|
||||
else {
|
||||
operator = GREATER_THAN;
|
||||
}
|
||||
break;
|
||||
case '=':
|
||||
linep++;
|
||||
if (*linep == '~') {
|
||||
operator = REGEX;
|
||||
linep++;
|
||||
}
|
||||
else {
|
||||
operator = EQUAL_TO;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(GlobalState.logfile,
|
||||
"Internal error: unknown operator in %s\n", line);
|
||||
linep++;
|
||||
break;
|
||||
}
|
||||
/* Skip whitespace. */
|
||||
while (is_character_class(*linep, WHITESPACE)) {
|
||||
linep++;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_character_class(*linep, DOUBLE_QUOTE)) {
|
||||
/* A string, as expected. */
|
||||
linep++;
|
||||
resulting_line = gather_string(line, linep);
|
||||
line = resulting_line.line;
|
||||
linep = resulting_line.linep;
|
||||
if (tag_token == TAG) {
|
||||
/* Treat FEN and FENPattern tags as special cases.
|
||||
* Use the position they represent to indicate
|
||||
* a positional match.
|
||||
*/
|
||||
if (tag_index == FEN_TAG) {
|
||||
add_fen_positional_match(yylval.token_string);
|
||||
(void) free((void *) yylval.token_string);
|
||||
}
|
||||
else if (tag_index == PSEUDO_FEN_PATTERN_TAG ||
|
||||
tag_index == PSEUDO_FEN_PATTERN_I_TAG) {
|
||||
/* Skip whitespace. */
|
||||
while (is_character_class(*linep, WHITESPACE)) {
|
||||
linep++;
|
||||
}
|
||||
const char *label;
|
||||
if(*linep != '\0') {
|
||||
/* Treat the remainder of the line as a label. */
|
||||
label = (const char *) linep;
|
||||
}
|
||||
else {
|
||||
label = NULL;
|
||||
}
|
||||
/* Generate an inverted version as well if
|
||||
* it is PSEUDO_FEN_PATTERN_I_TAG.
|
||||
*/
|
||||
add_fen_pattern_match(yylval.token_string,
|
||||
tag_index == PSEUDO_FEN_PATTERN_I_TAG, label);
|
||||
(void) free((void *) yylval.token_string);
|
||||
}
|
||||
else {
|
||||
add_tag_to_list(tag_index, yylval.token_string, operator);
|
||||
(void) free((void *) yylval.token_string);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!GlobalState.skipping_current_game) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"File %s: unrecognised tag name %s\n",
|
||||
TagFile, line);
|
||||
}
|
||||
(void) free((void *) yylval.token_string);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!GlobalState.skipping_current_game) {
|
||||
fprintf(GlobalState.logfile,
|
||||
"File %s: missing quoted tag string in %s at %s\n",
|
||||
TagFile, line, linep);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Terminate the reading, as we have run out of tags. */
|
||||
keep_reading = FALSE;
|
||||
}
|
||||
}
|
||||
return keep_reading;
|
||||
}
|
||||
|
||||
/* Extract a tag name from the given line.
|
||||
* Return TRUE if this was successful.
|
||||
*/
|
||||
Boolean
|
||||
process_roster_line(char *line)
|
||||
{
|
||||
Boolean keep_reading = TRUE;
|
||||
if (non_blank_line(line)) {
|
||||
unsigned char *linep = (unsigned char *) line;
|
||||
/* We should find a tag. */
|
||||
LinePair resulting_line = gather_tag(line, linep);
|
||||
TokenType tag_token;
|
||||
|
||||
/* Pick up where we are now. */
|
||||
line = resulting_line.line;
|
||||
linep = resulting_line.linep;
|
||||
tag_token = resulting_line.token;
|
||||
if (tag_token != NO_TOKEN) {
|
||||
/* Pick up which tag it was. */
|
||||
int tag_index = yylval.tag_index;
|
||||
add_to_output_tag_order((TagName) tag_index);
|
||||
}
|
||||
else {
|
||||
/* Terminate the reading, as we have run out of tags. */
|
||||
keep_reading = FALSE;
|
||||
}
|
||||
}
|
||||
return keep_reading;
|
||||
}
|
32
pgn-extract/taglines.h
Normal file
32
pgn-extract/taglines.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
#ifndef TAGLINES_H
|
||||
#define TAGLINES_H
|
||||
|
||||
void read_tag_file(const char *TagFile);
|
||||
void read_tag_roster_file(const char *RosterFile);
|
||||
Boolean process_tag_line(const char *TagFile,char *line);
|
||||
Boolean process_roster_line(char *line);
|
||||
|
||||
|
||||
#endif // TAGLINES_H
|
||||
|
112
pgn-extract/taglist.h
Normal file
112
pgn-extract/taglist.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
|
||||
* Copyright (C) 1994-2022 David J. Barnes
|
||||
*
|
||||
* pgn-extract 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* pgn-extract 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 pgn-extract. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
|
||||
* https://www.cs.kent.ac.uk/people/staff/djb/
|
||||
*/
|
||||
|
||||
/* Define indices for the set of pre-defined tags.
|
||||
* Higher values are created dynamically as new
|
||||
* tags are recognised in the source files.
|
||||
*/
|
||||
|
||||
/* List the tags so that the strings that they represent
|
||||
* would be in alphabetical order. E.g. note that EVENT_TAG and
|
||||
* EVENT_DATE_TAG should be in this order because the strings are
|
||||
* "Event" and "EventDate".
|
||||
*/
|
||||
#ifndef TAGLIST_H
|
||||
#define TAGLIST_H
|
||||
|
||||
typedef enum {
|
||||
ANNOTATOR_TAG,
|
||||
BLACK_TAG,
|
||||
BLACK_ELO_TAG,
|
||||
BLACK_NA_TAG,
|
||||
BLACK_TITLE_TAG,
|
||||
BLACK_TYPE_TAG,
|
||||
BLACK_USCF_TAG,
|
||||
BOARD_TAG,
|
||||
DATE_TAG,
|
||||
ECO_TAG,
|
||||
/* The PSEUDO_ELO_TAG is not a real PGN one. It is used with the -t
|
||||
* argument so that it becomes possible to indicate a rating of either colour.
|
||||
*/
|
||||
PSEUDO_ELO_TAG,
|
||||
EVENT_TAG,
|
||||
EVENT_DATE_TAG,
|
||||
EVENT_SPONSOR_TAG,
|
||||
FEN_TAG,
|
||||
/* The PSEUDO_FEN_PATTERN_TAGs are not real PGN ones. They are used with the -t
|
||||
* argument so that it becomes possible to indicate a FEN-based board pattern.
|
||||
* The _I version indicates that the pattern should be tried in both its
|
||||
* written form and inverted for the opposite colour.
|
||||
*/
|
||||
PSEUDO_FEN_PATTERN_TAG,
|
||||
PSEUDO_FEN_PATTERN_I_TAG,
|
||||
HASHCODE_TAG,
|
||||
LONG_ECO_TAG,
|
||||
/* The MATCHLABEL_TAG is not a real PGN one. It is used with the -t
|
||||
* argument and FENPattern pseudo tag so that it becomes possible to
|
||||
* which FENPattern has been matched in a game.
|
||||
*/
|
||||
MATCHLABEL_TAG,
|
||||
/* The MATERIAL_MATCH_TAG is not a real PGN one. It is used with the -z
|
||||
* argument so that it becomes possible to indicate which player's material
|
||||
* matches the first material pattern in a match.
|
||||
*/
|
||||
MATERIAL_MATCH_TAG,
|
||||
MODE_TAG,
|
||||
NIC_TAG,
|
||||
OPENING_TAG,
|
||||
/* The PSEUDO_PLAYER_TAG is not a real PGN one. It is used with the -t
|
||||
* argument so that it becomes possible to indicate a player of either colour.
|
||||
*/
|
||||
PSEUDO_PLAYER_TAG,
|
||||
PLY_COUNT_TAG,
|
||||
/* The TOTAL_PLY_COUNT_TAG is used with the --totalplycount argument
|
||||
* so record the total number of plies in a game.
|
||||
*/
|
||||
TOTAL_PLY_COUNT_TAG,
|
||||
RESULT_TAG,
|
||||
ROUND_TAG,
|
||||
SECTION_TAG,
|
||||
SETUP_TAG,
|
||||
SITE_TAG,
|
||||
STAGE_TAG,
|
||||
SUB_VARIATION_TAG,
|
||||
TERMINATION_TAG,
|
||||
TIME_TAG,
|
||||
TIME_CONTROL_TAG,
|
||||
UTC_DATE_TAG,
|
||||
UTC_TIME_TAG,
|
||||
VARIANT_TAG,
|
||||
VARIATION_TAG,
|
||||
WHITE_TAG,
|
||||
WHITE_ELO_TAG,
|
||||
WHITE_NA_TAG,
|
||||
WHITE_TITLE_TAG,
|
||||
WHITE_TYPE_TAG,
|
||||
WHITE_USCF_TAG,
|
||||
/* The following should always be last. It should not be used
|
||||
* as a tag identification.
|
||||
*/
|
||||
ORIGINAL_NUMBER_OF_TAGS
|
||||
} TagName;
|
||||
|
||||
#endif // TAGLIST_H
|
||||
|
960
pgn-extract/test/Makefile
Normal file
960
pgn-extract/test/Makefile
Normal file
@@ -0,0 +1,960 @@
|
||||
# Makefile to run a battery of tests of the basic functionality of pgn-extract.
|
||||
# Copyright (C) David J. Barnes, 2013-2020
|
||||
#
|
||||
# Each test is run and then, where relevant, a comparison is made between
|
||||
# the output files generated in the current directory and the 'oracle'
|
||||
# files that exist in $(OUTPUT).
|
||||
#
|
||||
# Beware of case-insensitive filenames when testing flags that
|
||||
# differ only in letter case. In general, double letters have been
|
||||
# used for output-files generated from using upper-case flag letters.
|
||||
|
||||
# Customise these for different OSs.
|
||||
SEP=/
|
||||
RM=rm -f
|
||||
CMP=cmp
|
||||
|
||||
# Possible Windows settings
|
||||
#SEP=\\
|
||||
#RM=del
|
||||
#CMP=diff
|
||||
|
||||
PGN_EXTRACT=..$(SEP)pgn-extract
|
||||
# Use for memory checking if valgrind is installed.
|
||||
#PGN_EXTRACT=valgrind --dsymutil=yes ..$(SEP)pgn-extract
|
||||
#PGN_EXTRACT=valgrind --dsymutil=yes --leak-check=full ..$(SEP)pgn-extract
|
||||
|
||||
# Location of the file of ECO classifications.
|
||||
ECO_FILE=..$(SEP)eco.pgn
|
||||
|
||||
# Location of the input files
|
||||
INPUT=infiles
|
||||
# Location of the oracle output files
|
||||
OUTPUT=outfiles
|
||||
|
||||
# Test everything.
|
||||
all: no-flags-1 no-flags-2 test-7 test-append test-AA test-b test-p \
|
||||
test-checkfile test-nocomments test-duplicates \
|
||||
test-noduplicates test-e test-EE test-f test-FF test-h test-l \
|
||||
test-LL test-checkmate test-n test-NN test-output test-PP test-r \
|
||||
test-RR test-s test-SS test-t test-TT test-nounique test-v \
|
||||
test-VV test-linelength test-WW test-x test-ZZ test-y test-z test-hash \
|
||||
test-evaluation test-fencomments test-markmatches test-nochecks \
|
||||
test-nomovenumbers test-noresults test-notags test-plylimit \
|
||||
test-stalemate test-long-line test-plycount test-addhashcode \
|
||||
test-selectonly test-fifty test-repetition test-promotion \
|
||||
test-fixresulttags test-fuzzydepth test-setup test-stopafter \
|
||||
test-skipmatching test-splitvariants test-nobadresults test-allownullmoves \
|
||||
test-matchplylimit test-nestedcomments test-FENPattern test-dropply \
|
||||
test-startply test-linenumbers test-seventyfive
|
||||
|
||||
# BEWARE: This removes all PGN files in the current directory.
|
||||
# The required test PGN files are assumed to be in $(INPUT).
|
||||
clean:
|
||||
-$(RM) *.pgn *og.txt
|
||||
|
||||
# No flags:
|
||||
# + No input file.
|
||||
# - Input file(s): N$(SEP)A
|
||||
# - Example input:
|
||||
# f3 e5 g4 Qh4 0-1
|
||||
# - Resulting output should be that the game input on standard input is
|
||||
# formatted as PGN on standard output.
|
||||
# - Expected output:
|
||||
# Contents of fools-mate.pgn on standard output.
|
||||
no-flags-1:
|
||||
echo "test: No input file."
|
||||
$(PGN_EXTRACT) --quiet < $(INPUT)$(SEP)fools-mate.txt
|
||||
|
||||
# No flags:
|
||||
# + Single input file
|
||||
# - Input file(s): fools-mate.txt
|
||||
# - Resulting output should be the input formatted as PGN on standard output.
|
||||
# - Expected output: Contents of fools-mate.pgn should appear on standard output.
|
||||
no-flags-2:
|
||||
echo "test: No flags."
|
||||
$(PGN_EXTRACT) --quiet $(INPUT)$(SEP)fools-mate.txt
|
||||
|
||||
# -7 $(SEP) --seven
|
||||
# + Input file with games having tags additional to the seven tag roster.
|
||||
# - Input file(s): test-7.pgn
|
||||
# - Game output should have only the tags of the seven tag roster.
|
||||
# - Expected output: test-7-out.pgn
|
||||
test-7:
|
||||
echo "test-7:"
|
||||
$(PGN_EXTRACT) -7 -otest-7-out.pgn --quiet $(INPUT)$(SEP)test-7.pgn
|
||||
$(CMP) test-7-out.pgn $(OUTPUT)$(SEP)test-7-out.pgn
|
||||
|
||||
# -a $(SEP) --append
|
||||
# + Input file containing games in any accepted format.
|
||||
# - Input file(s): test-a.txt
|
||||
# - Resulting output should contain two versions of the input game
|
||||
# formatted in PGN. The --output command is run first to create
|
||||
# a new file, then the -a version to append to that file.
|
||||
# - Expected output: test-a-out.pgn
|
||||
test-append:
|
||||
echo "test-append:"
|
||||
$(PGN_EXTRACT) --output test-a-out.pgn --quiet $(INPUT)$(SEP)test-a.txt
|
||||
$(PGN_EXTRACT) -atest-a-out.pgn --quiet $(INPUT)$(SEP)test-a.txt
|
||||
$(CMP) test-a-out.pgn $(OUTPUT)$(SEP)test-a-out.pgn
|
||||
|
||||
$(PGN_EXTRACT) --output test-a-out.pgn --quiet $(INPUT)$(SEP)test-a.txt
|
||||
$(PGN_EXTRACT) --append test-a-out.pgn --quiet $(INPUT)$(SEP)test-a.txt
|
||||
$(CMP) test-a-out.pgn $(OUTPUT)$(SEP)test-a-out.pgn
|
||||
|
||||
# -A
|
||||
# + Input file containing games and a file of arguments.
|
||||
# - Input file(s): fischer.pgn, petrosian.pgn, arglist.txt
|
||||
# - Resulting output should be files separating the unique and
|
||||
# duplicated games in the input files.
|
||||
# - Expected output: test-AA-unique.pgn, test-AA-dupes.pgn
|
||||
test-AA:
|
||||
echo "test-AA:"
|
||||
$(PGN_EXTRACT) -C -A$(INPUT)$(SEP)argslist.txt --quiet
|
||||
$(CMP) test-AA-dupes.pgn $(OUTPUT)$(SEP)test-AA-dupes.pgn
|
||||
$(CMP) test-AA-unique.pgn $(OUTPUT)$(SEP)test-AA-unique.pgn
|
||||
|
||||
# -b
|
||||
# + Input file containing games of different length.
|
||||
# - Input file(s): fischer.pgn
|
||||
# - Resulting output: games whose number of moves is within
|
||||
# the specified bounds.
|
||||
#
|
||||
test-b: test-bl45 test-bu45 test-bu30
|
||||
|
||||
# -p
|
||||
# + Input file containing games of different length.
|
||||
# - Input file(s): fischer.pgn
|
||||
# - Resulting output: games whose number of ply is within
|
||||
# the specified bounds.
|
||||
#
|
||||
test-p: test-pl90 test-pu90 test-pu60
|
||||
|
||||
# - Expected output: 45 moves or more: test-bl45-out.pgn
|
||||
test-bl45:
|
||||
echo "test-b:"
|
||||
$(PGN_EXTRACT) -bl45 -otest-bl45-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-bl45-out.pgn $(OUTPUT)$(SEP)test-bl45-out.pgn
|
||||
|
||||
# - Expected output: 45 moves or less: test-bu45-out.pgn
|
||||
test-bu45:
|
||||
echo "test-b:"
|
||||
$(PGN_EXTRACT) -bu45 -otest-bu45-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-bu45-out.pgn $(OUTPUT)$(SEP)test-bu45-out.pgn
|
||||
|
||||
# - Expected output: exactly 30 moves: test-b30-out.pgn
|
||||
test-bu30:
|
||||
echo "test-b:"
|
||||
$(PGN_EXTRACT) -b30 -otest-b30-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-b30-out.pgn $(OUTPUT)$(SEP)test-b30-out.pgn
|
||||
|
||||
# - Expected output: 90 moves or more: test-pl90-out.pgn
|
||||
test-pl90:
|
||||
echo "test-p:"
|
||||
$(PGN_EXTRACT) -pl90 -otest-pl90-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-pl90-out.pgn $(OUTPUT)$(SEP)test-pl90-out.pgn
|
||||
|
||||
# - Expected output: 90 moves or less: test-pu90-out.pgn
|
||||
test-pu90:
|
||||
echo "test-p:"
|
||||
$(PGN_EXTRACT) -pu90 -otest-pu90-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-pu90-out.pgn $(OUTPUT)$(SEP)test-pu90-out.pgn
|
||||
|
||||
# - Expected output: exactly 60 moves: test-p60-out.pgn
|
||||
test-pu60:
|
||||
echo "test-p:"
|
||||
$(PGN_EXTRACT) -p60 -otest-p60-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-p60-out.pgn $(OUTPUT)$(SEP)test-p60-out.pgn
|
||||
|
||||
#
|
||||
# -c $(SEP) --checkfile
|
||||
# + Input files containing games.
|
||||
# - Input file(s): fischer.pgn, petrosian.pgn
|
||||
# - Resulting output should contain matched games that do not already occur in
|
||||
# the check file.
|
||||
# - Expected output: test-c-out.pgn
|
||||
test-checkfile:
|
||||
echo "test-checkfile:"
|
||||
$(PGN_EXTRACT) -c$(INPUT)$(SEP)petrosian.pgn -D -TpPetrosian -otest-c-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-c-out.pgn $(OUTPUT)$(SEP)test-c-out.pgn
|
||||
$(PGN_EXTRACT) -c$(INPUT)$(SEP)clist.txt -D -TpPetrosian -otest-c-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-c-out.pgn $(OUTPUT)$(SEP)test-c-out.pgn
|
||||
|
||||
# -C $(SEP) --nocomments
|
||||
# + Input file containing games with comments
|
||||
# - Input file(s): test-C.pgn
|
||||
# - Resulting output should have all comments removed.
|
||||
# - Expected output: test-CC-out.pgn
|
||||
test-nocomments:
|
||||
echo "test-nocomments:"
|
||||
$(PGN_EXTRACT) -C -otest-CC-out.pgn --quiet $(INPUT)$(SEP)test-C.pgn
|
||||
$(CMP) test-CC-out.pgn $(OUTPUT)$(SEP)test-CC-out.pgn
|
||||
|
||||
# -d $(SEP) --duplicates
|
||||
# + Input file containing games with duplicates and non-duplicates.
|
||||
# - Input file(s): fischer.pgn, $(INPUT)$(SEP)petrosian.pgn
|
||||
# - Resulting output should be files separating the unique and
|
||||
# duplicated games in the input files.
|
||||
# - Expected output: test-d-unique.pgn, test-d-dupes.pgn
|
||||
test-duplicates:
|
||||
echo "test-duplicates:"
|
||||
$(PGN_EXTRACT) -C -dtest-d-dupes.pgn -otest-d-unique.pgn --quiet $(INPUT)$(SEP)fischer.pgn $(INPUT)$(SEP)petrosian.pgn
|
||||
$(CMP) test-d-dupes.pgn $(OUTPUT)$(SEP)test-d-dupes.pgn
|
||||
$(CMP) test-d-unique.pgn $(OUTPUT)$(SEP)test-d-unique.pgn
|
||||
|
||||
# -D $(SEP) --noduplicates
|
||||
# + Input file containing games with duplicates and non-duplicates.
|
||||
# - Input file(s): fischer.pgn, $(INPUT)$(SEP)petrosian.pgn
|
||||
# - Resulting output should be a file containing the combined input
|
||||
# with duplicate games removed.
|
||||
# - Expected output: test-DD-unique.pgn
|
||||
test-noduplicates:
|
||||
echo "test-noduplicates:"
|
||||
$(PGN_EXTRACT) -D -otest-DD-unique.pgn --quiet $(INPUT)$(SEP)fischer.pgn $(INPUT)$(SEP)petrosian.pgn
|
||||
$(CMP) test-DD-unique.pgn $(OUTPUT)$(SEP)test-DD-unique.pgn
|
||||
$(PGN_EXTRACT) --noduplicates -otest-DD-unique.pgn --quiet $(INPUT)$(SEP)fischer.pgn $(INPUT)$(SEP)petrosian.pgn
|
||||
$(CMP) test-DD-unique.pgn $(OUTPUT)$(SEP)test-DD-unique.pgn
|
||||
|
||||
# -e
|
||||
# + Input file containing games without ECO classifications.
|
||||
# - Input file(s): test-e.pgn and eco.pgn in the test folder.
|
||||
# - Resulting output should have ECO classification added to the tags.
|
||||
# - Expected output: test-e-out.pgn
|
||||
test-e:
|
||||
echo "test-e:"
|
||||
$(PGN_EXTRACT) -e$(ECO_FILE) -otest-e-out.pgn --quiet $(INPUT)$(SEP)test-e.pgn
|
||||
$(CMP) test-e-out.pgn $(OUTPUT)$(SEP)test-e-out.pgn
|
||||
|
||||
# -E
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-ucE.pgn and eco.pgn if -e flag is used.
|
||||
# - Resulting output should be separate files for each ECO classification
|
||||
# at the level of the initial letter (A-E).
|
||||
# NB: The test removes existing A-E files first because this option appends
|
||||
# to existing files, which breaks the comparison test otherwise.
|
||||
# - Expected output: A.pgn, B.pgn, E.pgn
|
||||
test-EE:
|
||||
echo "test-EE:"
|
||||
-$(RM) [A-E].pgn
|
||||
$(PGN_EXTRACT) -e$(ECO_FILE) -E1 --quiet $(INPUT)$(SEP)test-ucE.pgn
|
||||
$(CMP) A.pgn $(OUTPUT)$(SEP)A.pgn
|
||||
$(CMP) B.pgn $(OUTPUT)$(SEP)B.pgn
|
||||
$(CMP) E.pgn $(OUTPUT)$(SEP)E.pgn
|
||||
|
||||
# -f
|
||||
# + Input files containing games.
|
||||
# - Input file(s): test-f1.pgn, test-f2.pgn, files.txt
|
||||
# - Resulting output should be the combination of the input files.
|
||||
# - Expected output: test-f-out.pgn
|
||||
test-f:
|
||||
echo "test-f:"
|
||||
$(PGN_EXTRACT) --quiet -f$(INPUT)$(SEP)files.txt -otest-f-out.pgn
|
||||
$(CMP) test-f-out.pgn $(OUTPUT)$(SEP)test-f-out.pgn
|
||||
|
||||
# -F:
|
||||
# + Input file containing games without a trailing FEN comment.
|
||||
# - Input file(s): test-F.pgn
|
||||
# - Resulting output should have a comment at the end containing
|
||||
# the FEN description of the final position.
|
||||
# - Expected output: test-FF-out.pgn
|
||||
test-FF:
|
||||
echo "test-FF:"
|
||||
$(PGN_EXTRACT) -F -otest-FF-out.pgn --quiet $(INPUT)$(SEP)test-F.pgn
|
||||
$(CMP) test-FF-out.pgn $(OUTPUT)$(SEP)test-FF-out.pgn
|
||||
$(PGN_EXTRACT) -Fdiagram -otest-FF-text-out.pgn --quiet $(INPUT)$(SEP)test-F-text.pgn
|
||||
$(CMP) test-FF-text-out.pgn $(OUTPUT)$(SEP)test-FF-text-out.pgn
|
||||
|
||||
#
|
||||
# -h $(SEP) -? $(SEP) --help
|
||||
# + No input required.
|
||||
# - Input file(s): N$(SEP)A
|
||||
# - Resulting output should be a description of how to use pgn-extract
|
||||
# - Expected output: N$(SEP)A
|
||||
# Also:
|
||||
# ..$(SEP)pgn-extract -?
|
||||
# ..$(SEP)pgn-extract --help
|
||||
test-h:
|
||||
echo "test-h:"
|
||||
-$(PGN_EXTRACT) -h
|
||||
|
||||
# -l
|
||||
# + Input file containing games.
|
||||
# - Input file(s): fischer.pgn
|
||||
# - Resulting output: List of games parsed written to log.txt
|
||||
# - Expected output: log.txt
|
||||
test-l:
|
||||
echo "test-l:"
|
||||
$(PGN_EXTRACT) -llog.txt -otest-l-out.pgn $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) log.txt $(OUTPUT)$(SEP)log.txt
|
||||
$(CMP) test-l-out.pgn $(OUTPUT)$(SEP)test-l-out.pgn
|
||||
|
||||
# -L
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-L1.pgn, test-L2.pgn
|
||||
# - Resulting output should be that log.txt contains the combined
|
||||
# logs from two runs of pgn-extract.
|
||||
# - Expected output: log.txt
|
||||
test-LL:
|
||||
echo "test-LL:"
|
||||
$(PGN_EXTRACT) -lLLog.txt -r $(INPUT)$(SEP)test-L1.pgn
|
||||
$(PGN_EXTRACT) -LLLog.txt -r $(INPUT)$(SEP)test-L2.pgn
|
||||
$(CMP) LLog.txt $(OUTPUT)$(SEP)LLog.txt
|
||||
|
||||
# -M $(SEP) --checkmate
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-checkmate.pgn
|
||||
# - Resulting output should contain only those games that end in checkmate.
|
||||
# - Expected output: test-checkmate-out.pgn
|
||||
test-checkmate:
|
||||
echo "test-checkmate:"
|
||||
$(PGN_EXTRACT) --checkmate -otest-checkmate-out.pgn --quiet $(INPUT)$(SEP)test-checkmate.pgn
|
||||
$(CMP) test-checkmate-out.pgn $(OUTPUT)$(SEP)test-checkmate-out.pgn
|
||||
|
||||
# -n
|
||||
# + Input file containing games.
|
||||
# - Input file(s): petrosian.pgn
|
||||
# - Resulting output should be separate files containing matched
|
||||
# and non-matched games.
|
||||
# - Expected output: test-n-matched.pgn, test-n-unmatched.pgn
|
||||
test-n:
|
||||
echo "test-n:"
|
||||
$(PGN_EXTRACT) -TpFischer -otest-n-matched.pgn -ntest-n-unmatched.pgn --quiet $(INPUT)$(SEP)petrosian.pgn
|
||||
$(CMP) test-n-matched.pgn $(OUTPUT)$(SEP)test-n-matched.pgn
|
||||
$(CMP) test-n-unmatched.pgn $(OUTPUT)$(SEP)test-n-unmatched.pgn
|
||||
|
||||
# -N $(SEP) --nonags
|
||||
# + Input file containing games with NAGs.
|
||||
# - Input file(s): test-N.pgn
|
||||
# - Resulting output should have all NAGs removed.
|
||||
# - Expected output: test-NN-out.pgn
|
||||
test-NN:
|
||||
echo "test-NN:"
|
||||
$(PGN_EXTRACT) -N -otest-NN-out.pgn --quiet $(INPUT)$(SEP)test-N.pgn
|
||||
$(CMP) test-NN-out.pgn $(OUTPUT)$(SEP)test-NN-out.pgn
|
||||
# Comments after multiple nags.
|
||||
$(PGN_EXTRACT) -otest-nagcomments-out.pgn --quiet $(INPUT)$(SEP)test-nagcomments.pgn
|
||||
# Deleting NAGs with comments after multiple nags.
|
||||
$(PGN_EXTRACT) -N -atest-nagcomments-out.pgn --quiet $(INPUT)$(SEP)test-nagcomments.pgn
|
||||
$(CMP) test-nagcomments-out.pgn $(OUTPUT)$(SEP)test-nagcomments-out.pgn
|
||||
$(CMP) test-nagcomments-out.pgn $(OUTPUT)$(SEP)test-nagcomments-out.pgn
|
||||
|
||||
#
|
||||
# -o $(SEP) --output
|
||||
# + Input file containing games in any accepted format.
|
||||
# - Input file(s): test-o.txt
|
||||
# - Resulting output should contain the input game formatted in PGN.
|
||||
# - Expected output: test-o-out.pgn
|
||||
test-output:
|
||||
echo "test-output:"
|
||||
$(PGN_EXTRACT) -otest-o-out.pgn --quiet $(INPUT)$(SEP)test-o.txt
|
||||
$(CMP) test-o-out.pgn $(OUTPUT)$(SEP)test-o-out.pgn
|
||||
$(PGN_EXTRACT) --output test-o-out.pgn --quiet $(INPUT)$(SEP)test-o.txt
|
||||
$(CMP) test-o-out.pgn $(OUTPUT)$(SEP)test-o-out.pgn
|
||||
|
||||
# -P
|
||||
# + Input file containing games with different sequences for the same
|
||||
# opening.
|
||||
# - Input file(s): test-P.pgn, Pvars.txt
|
||||
# - Resulting output should be games whose opening move exactly match
|
||||
# the sequence specified in Pvars.txt
|
||||
# - Expected output: test-PP-out.pgn
|
||||
test-PP:
|
||||
echo "test-PP:"
|
||||
$(PGN_EXTRACT) -P -v$(INPUT)$(SEP)Pvars.txt -otest-PP-out.pgn --quiet $(INPUT)$(SEP)test-P.pgn
|
||||
$(CMP) test-PP-out.pgn $(OUTPUT)$(SEP)test-PP-out.pgn
|
||||
|
||||
# -r
|
||||
# + Input file containing games in any accepted format.
|
||||
# - Input file(s): test-r.text
|
||||
# - Resulting output should contain tag summary lines for the games
|
||||
# matched and a report of any errors.
|
||||
# - Expected output: test-r-log.txt
|
||||
test-r:
|
||||
echo "test-r:"
|
||||
$(PGN_EXTRACT) -r -ltest-r-log.txt $(INPUT)$(SEP)test-r.txt
|
||||
# $(CMP) test-r-log.txt $(OUTPUT)$(SEP)test-r-log.txt
|
||||
|
||||
# -R
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-R.pgn, roster.txt
|
||||
# - Resulting output should contain games with their tag roster in
|
||||
# the order specified in roster.txt
|
||||
# - Expected output: test-R-out.pgn
|
||||
test-RR:
|
||||
echo "test-RR:"
|
||||
$(PGN_EXTRACT) -R$(INPUT)$(SEP)roster.txt --output test-RR-out.pgn --quiet $(INPUT)$(SEP)test-R.pgn
|
||||
$(CMP) test-RR-out.pgn $(OUTPUT)$(SEP)test-RR-out.pgn
|
||||
|
||||
# -s
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-s.pgn
|
||||
# - Resulting output should be silent, with games written to the output file.
|
||||
# - Expected output: test-s-out.pgn
|
||||
test-s:
|
||||
echo "test-s:"
|
||||
$(PGN_EXTRACT) -s -o test-s-out.pgn $(INPUT)$(SEP)test-s.pgn
|
||||
$(CMP) test-s-out.pgn $(OUTPUT)$(SEP)test-s-out.pgn
|
||||
|
||||
# -S
|
||||
# + Input file containing games whose players' names have slight
|
||||
# sound variations from anglesized versions.
|
||||
# - Input file(s): test-ucS.pgn
|
||||
# - Resulting output should be games that match by ignoring slight
|
||||
# soundex differences.
|
||||
# - Expected output: test-SS-out.pgn
|
||||
test-SS:
|
||||
echo "test-SS:"
|
||||
$(PGN_EXTRACT) -S -TpPetrosian -otest-SS-out.pgn --quiet $(INPUT)$(SEP)test-ucS.pgn
|
||||
$(CMP) test-SS-out.pgn $(OUTPUT)$(SEP)test-SS-out.pgn
|
||||
|
||||
# -t
|
||||
# + Input file containing games and a file of tag criteria.
|
||||
# - Input file(s): test-t.pgn, taglist.txt
|
||||
# - Resulting output should be only those games whose tags match
|
||||
# all of the criteria.
|
||||
# - Expected output: test-t-out.pgn
|
||||
test-t:
|
||||
echo "test-t:"
|
||||
$(PGN_EXTRACT) -t$(INPUT)$(SEP)taglist.txt -otest-t-out.pgn --quiet $(INPUT)$(SEP)test-t.pgn
|
||||
$(CMP) test-t-out.pgn $(OUTPUT)$(SEP)test-t-out.pgn
|
||||
$(PGN_EXTRACT) -t$(INPUT)$(SEP)test-tFEN.txt -otest-tFEN-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-tFEN-out.pgn $(OUTPUT)$(SEP)test-tFEN-out.pgn
|
||||
|
||||
# -T
|
||||
# + Input file containing games with tag information.
|
||||
# - Input file(s): fischer.pgn, test-Ta.pgn (and eco.pgn for -Te test.)
|
||||
# - Resulting output should contain only those games whose tag information
|
||||
# matches that specified.
|
||||
# - Expected output: test-Ta-out.pgn, test-Tb-out.pgn, test-Td-out.pgn,
|
||||
# test-Tdd-out.pgn test-Te-out.pgn, test-Tp-out.pgn,
|
||||
# test-Tw-out.pgn
|
||||
test-TT:
|
||||
echo "test-TT:"
|
||||
$(PGN_EXTRACT) -Td1970 -otest-TTd-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-TTd-out.pgn $(OUTPUT)$(SEP)test-TTd-out.pgn
|
||||
$(PGN_EXTRACT) -Td1960 -Td1962 -otest-TTdd-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-TTdd-out.pgn $(OUTPUT)$(SEP)test-TTdd-out.pgn
|
||||
$(PGN_EXTRACT) -TbPetrosian -otest-TTb-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-TTb-out.pgn $(OUTPUT)$(SEP)test-TTb-out.pgn
|
||||
$(PGN_EXTRACT) -e$(ECO_FILE) -TeB14 -otest-Te-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(PGN_EXTRACT) -TpPetrosian -otest-TTp-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-TTp-out.pgn $(OUTPUT)$(SEP)test-TTp-out.pgn
|
||||
$(PGN_EXTRACT) -Tr0-1 -otest-TTr-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-TTr-out.pgn $(OUTPUT)$(SEP)test-TTr-out.pgn
|
||||
$(PGN_EXTRACT) -TwFischer -otest-TTw-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-TTw-out.pgn $(OUTPUT)$(SEP)test-TTw-out.pgn
|
||||
$(PGN_EXTRACT) -TaBarnes -otest-TTa-out.pgn --quiet $(INPUT)$(SEP)test-Ta.pgn
|
||||
$(CMP) test-TTa-out.pgn $(OUTPUT)$(SEP)test-TTa-out.pgn
|
||||
|
||||
# -U $(SEP) --nounique
|
||||
# + Input file containing games with duplicates and non-duplicates.
|
||||
# - Input file(s): fischer.pgn, petrosian.pgn
|
||||
# - Resulting output should be a file containing just the duplicate games.
|
||||
# - Expected output: test-U-unique.pgn
|
||||
test-nounique:
|
||||
echo "test-nounique:"
|
||||
$(PGN_EXTRACT) -U -otest-UU-unique.pgn --quiet $(INPUT)$(SEP)fischer.pgn $(INPUT)$(SEP)petrosian.pgn
|
||||
$(CMP) test-UU-unique.pgn $(OUTPUT)$(SEP)test-UU-unique.pgn
|
||||
$(PGN_EXTRACT) --nounique -otest-UU-unique.pgn --quiet $(INPUT)$(SEP)fischer.pgn $(INPUT)$(SEP)petrosian.pgn
|
||||
$(CMP) test-UU-unique.pgn $(OUTPUT)$(SEP)test-UU-unique.pgn
|
||||
|
||||
# -v
|
||||
# + Input file containing games.
|
||||
# - Input file(s): najdorf.pgn, vvars.txt
|
||||
# - Resulting output should be only those games whose opening moves
|
||||
# textually match (in any order) the moves in vars.txt.
|
||||
# - Expected output: test-v-out.pgn
|
||||
test-v:
|
||||
echo "test-v:"
|
||||
$(PGN_EXTRACT) -v$(INPUT)$(SEP)vvars.txt -otest-v-out.pgn --quiet $(INPUT)$(SEP)najdorf.pgn
|
||||
$(CMP) test-v-out.pgn $(OUTPUT)$(SEP)test-v-out.pgn
|
||||
|
||||
# -V
|
||||
# + Input file containing games with variations
|
||||
# - Input file(s): test-V.pgn
|
||||
# - Resulting output should have all variations removed.
|
||||
# - Expected output: test-V-out.pgn
|
||||
test-VV:
|
||||
echo "test-VV:"
|
||||
$(PGN_EXTRACT) -V -otest-VV-out.pgn --quiet $(INPUT)$(SEP)test-V.pgn
|
||||
$(CMP) test-VV-out.pgn $(OUTPUT)$(SEP)test-VV-out.pgn
|
||||
|
||||
# -w $(SEP) --linelength
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-w.pgn
|
||||
# - Resulting output Games formatted up to the specified line length.
|
||||
# The default is 75.
|
||||
# - Expected output: test-w60-out.pgn, test-w75-out.pgn, test-w1000-out.pgn
|
||||
test-linelength:
|
||||
echo "test-linelength:"
|
||||
$(PGN_EXTRACT) -w60 -otest-w60-out.pgn --quiet $(INPUT)$(SEP)test-w.pgn
|
||||
$(CMP) test-w60-out.pgn $(OUTPUT)$(SEP)test-w60-out.pgn
|
||||
$(PGN_EXTRACT) -w75 -otest-w75-out.pgn --quiet $(INPUT)$(SEP)test-w.pgn
|
||||
$(CMP) test-w75-out.pgn $(OUTPUT)$(SEP)test-w75-out.pgn
|
||||
$(PGN_EXTRACT) -w1000 -otest-w1000-out.pgn --quiet $(INPUT)$(SEP)test-w.pgn
|
||||
$(CMP) test-w1000-out.pgn $(OUTPUT)$(SEP)test-w1000-out.pgn
|
||||
|
||||
$(PGN_EXTRACT) --linelength 60 -otest-w60-out.pgn --quiet $(INPUT)$(SEP)test-w.pgn
|
||||
$(CMP) test-w60-out.pgn $(OUTPUT)$(SEP)test-w60-out.pgn
|
||||
$(PGN_EXTRACT) --linelength 75 -otest-w75-out.pgn --quiet $(INPUT)$(SEP)test-w.pgn
|
||||
$(CMP) test-w75-out.pgn $(OUTPUT)$(SEP)test-w75-out.pgn
|
||||
$(PGN_EXTRACT) --linelength 1000 -otest-w1000-out.pgn --quiet $(INPUT)$(SEP)test-w.pgn
|
||||
$(CMP) test-w1000-out.pgn $(OUTPUT)$(SEP)test-w1000-out.pgn
|
||||
|
||||
# -W
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-ucW.pgn
|
||||
# - Resulting output should be games formatted in the specified notation:
|
||||
# halg (hyphenated long algebraic), lalg (non-hyphenated long algebraic),
|
||||
# elalg (enhanced long algebraic), xlalg (enhanced with capture info),
|
||||
# uci (UCI-compatible output),
|
||||
# and alternative piece letters.
|
||||
# - Expected output: test-WWhalg-out.pgn, test-WWlalg-out.pgn,
|
||||
# test-WWelalg-out.pgn, test-WWdeutsch-out.pgn,
|
||||
# test-WWuci-out.pgn
|
||||
test-WW:
|
||||
echo "test-WW:"
|
||||
$(PGN_EXTRACT) -Whalg -otest-WWhalg-out.pgn --quiet $(INPUT)$(SEP)test-ucW.pgn
|
||||
$(CMP) test-WWhalg-out.pgn $(OUTPUT)$(SEP)test-WWhalg-out.pgn
|
||||
$(PGN_EXTRACT) -Wlalg -otest-WWlalg-out.pgn --quiet $(INPUT)$(SEP)test-ucW.pgn
|
||||
$(CMP) test-WWlalg-out.pgn $(OUTPUT)$(SEP)test-WWlalg-out.pgn
|
||||
$(PGN_EXTRACT) -Welalg -otest-WWelalg-out.pgn --quiet $(INPUT)$(SEP)test-ucW.pgn
|
||||
$(CMP) test-WWelalg-out.pgn $(OUTPUT)$(SEP)test-WWelalg-out.pgn
|
||||
$(PGN_EXTRACT) -Wxlalg -otest-WWxlalg-out.pgn --quiet $(INPUT)$(SEP)test-ucW.pgn
|
||||
$(CMP) test-WWxlalg-out.pgn $(OUTPUT)$(SEP)test-WWxlalg-out.pgn
|
||||
$(PGN_EXTRACT) -WsanBSLTDK -otest-WWdeutsch-out.pgn --quiet $(INPUT)$(SEP)test-ucW.pgn
|
||||
$(CMP) test-WWdeutsch-out.pgn $(OUTPUT)$(SEP)test-WWdeutsch-out.pgn
|
||||
$(PGN_EXTRACT) -Wuci -otest-WWuci-out.pgn --quiet $(INPUT)$(SEP)test-ucW.pgn
|
||||
$(CMP) test-WWuci-out.pgn $(OUTPUT)$(SEP)test-WWuci-out.pgn
|
||||
$(PGN_EXTRACT) -Wepd -otest-WWepd-out.pgn --quiet $(INPUT)$(SEP)test-ucW.pgn
|
||||
$(CMP) test-WWepd-out.pgn $(OUTPUT)$(SEP)test-WWepd-out.pgn
|
||||
|
||||
# -x
|
||||
# + Input file containing games.
|
||||
# - Input file(s): najdorf.pgn, xvars.txt
|
||||
# - Resulting output should be only those games which match
|
||||
# the result of reaching the opening sequence in vars.txt.
|
||||
# - Expected output: test-x-out.pgn
|
||||
test-x:
|
||||
echo "test-x:"
|
||||
$(PGN_EXTRACT) -x$(INPUT)$(SEP)xvars.txt -otest-x-out.pgn --quiet $(INPUT)$(SEP)najdorf.pgn
|
||||
$(CMP) test-x-out.pgn $(OUTPUT)$(SEP)test-x-out.pgn
|
||||
$(PGN_EXTRACT) -x$(INPUT)$(SEP)xvars.txt -otest-x-out.pgn -ntest-xn-out.pgn --quiet $(INPUT)$(SEP)najdorf.pgn
|
||||
$(CMP) test-xn-out.pgn $(OUTPUT)$(SEP)test-xn-out.pgn
|
||||
|
||||
# -y
|
||||
# + Input file containing games.
|
||||
# - Input file(s): fischer.pgn, zmatch.txt
|
||||
# - Resulting output should be games whose material balance matches that
|
||||
# specified in ymatch.txt
|
||||
# - Expected output: test-y-out.pgn
|
||||
test-y:
|
||||
echo "test-y:"
|
||||
$(PGN_EXTRACT) -y$(INPUT)$(SEP)ymatch.txt --markmatches MATCH -otest-y-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-y-out.pgn $(OUTPUT)$(SEP)test-y-out.pgn
|
||||
$(PGN_EXTRACT) --materialy "q*r*p*b2n2< q=r=p=b2<n2" --markmatches MATCH -otest-y-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-y-out.pgn $(OUTPUT)$(SEP)test-y-out.pgn
|
||||
|
||||
# -z
|
||||
# + Input file containing games.
|
||||
# - Input file(s): fischer.pgn, zmatch.txt
|
||||
# - Resulting output should be games whose material balance matches that
|
||||
# specified in zmatch.txt
|
||||
# - Expected output: test-z-out.pgn
|
||||
test-z:
|
||||
echo "test-z:"
|
||||
$(PGN_EXTRACT) -z$(INPUT)$(SEP)zmatch.txt -otest-z-out.pgn --markmatches MATCH --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-z-out.pgn $(OUTPUT)$(SEP)test-z-out.pgn
|
||||
$(PGN_EXTRACT) --materialz "q*r*p*b2n2< q=r=p=b2<n2" -otest-z-out.pgn --markmatches MATCH --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-z-out.pgn $(OUTPUT)$(SEP)test-z-out.pgn
|
||||
|
||||
# -Z
|
||||
# + Input file containing games with duplicates and non-duplicates.
|
||||
# - Input file(s): fischer.pgn, petrosian.pgn
|
||||
# - Resulting output should be files separating the unique and
|
||||
# duplicated games in the input files.
|
||||
# - Expected output: test-ZZ-unique.pgn, test-ZZ-dupes.pgn
|
||||
test-ZZ:
|
||||
echo "test-ZZ:"
|
||||
$(PGN_EXTRACT) -C -Z -dtest-ZZ-dupes.pgn -otest-ZZ-unique.pgn --quiet $(INPUT)$(SEP)fischer.pgn $(INPUT)$(SEP)petrosian.pgn
|
||||
$(CMP) test-ZZ-dupes.pgn $(OUTPUT)$(SEP)test-ZZ-dupes.pgn
|
||||
$(CMP) test-ZZ-unique.pgn $(OUTPUT)$(SEP)test-ZZ-unique.pgn
|
||||
|
||||
# -#
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-hash.pgn
|
||||
# - Resulting output The input file split in to separate sub-files,
|
||||
# each containing 10 games, except the last which may contain fewer.
|
||||
# - Expected output: 1.pgn, 2.pgn
|
||||
test-hash:
|
||||
echo "test-hash:"
|
||||
$(PGN_EXTRACT) -#20 --quiet $(INPUT)$(SEP)test-hash.pgn
|
||||
$(CMP) 1.pgn $(OUTPUT)$(SEP)1.pgn
|
||||
$(CMP) 2.pgn $(OUTPUT)$(SEP)2.pgn
|
||||
|
||||
$(PGN_EXTRACT) -#20,10 --quiet $(INPUT)$(SEP)test-hash.pgn
|
||||
$(CMP) 10.pgn $(OUTPUT)$(SEP)10.pgn
|
||||
$(CMP) 11.pgn $(OUTPUT)$(SEP)11.pgn
|
||||
|
||||
# --evaluation
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-evaluation.pgn
|
||||
# - Resulting output should include an evaluation value in a comment
|
||||
# after every move.
|
||||
# - Expected output: test-evaluation-out.pgn
|
||||
test-evaluation:
|
||||
echo "test-evaluation:"
|
||||
$(PGN_EXTRACT) --evaluation -otest-evaluation-out.pgn --quiet $(INPUT)$(SEP)test-evaluation.pgn
|
||||
$(CMP) test-evaluation-out.pgn $(OUTPUT)$(SEP)test-evaluation-out.pgn
|
||||
|
||||
# --fencomments
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-fencomments.pgn
|
||||
# - Resulting output should have a comment after every move containing a
|
||||
# FEN description of the position after that move.
|
||||
# - Expected output: test-fencomments-out.pgn
|
||||
test-fencomments:
|
||||
echo "test-fencomments:"
|
||||
$(PGN_EXTRACT) --fencomments -otest-fencomments-out.pgn --quiet $(INPUT)$(SEP)test-fencomments.pgn
|
||||
$(CMP) test-fencomments-out.pgn $(OUTPUT)$(SEP)test-fencomments-out.pgn
|
||||
|
||||
# --markmatches
|
||||
# + Input file containing games.
|
||||
# - Input file(s): najdorf.pgn, xvars.txt
|
||||
# - Resulting output should be only those games which match
|
||||
# the result of reaching the opening sequence in vars.txt.
|
||||
# The point of each match is marked with the comment { MATCH }
|
||||
# - Expected output: test-markmatches-out.pgn
|
||||
test-markmatches:
|
||||
echo "test-markmatches:"
|
||||
$(PGN_EXTRACT) --markmatches MATCH -x$(INPUT)$(SEP)xvars.txt -otest-markmatches-out.pgn --quiet $(INPUT)$(SEP)najdorf.pgn
|
||||
$(CMP) test-markmatches-out.pgn $(OUTPUT)$(SEP)test-markmatches-out.pgn
|
||||
|
||||
# --nestedcomments
|
||||
# + Input file containing games.
|
||||
# - Input file(s): nested-comment.pgn
|
||||
# - Resulting output should have retained the nested comment.
|
||||
# - Expected output: test-nestedcomments-out.pgn
|
||||
test-nestedcomments:
|
||||
echo "test-nestedcomments:"
|
||||
$(PGN_EXTRACT) --nestedcomments -otest-nestedcomments-out.pgn --quiet $(INPUT)$(SEP)nested-comment.pgn
|
||||
$(CMP) test-nestedcomments-out.pgn $(OUTPUT)$(SEP)test-nestedcomments-out.pgn
|
||||
|
||||
# --nochecks
|
||||
# + Input file containing games with moves involving moves that give check
|
||||
# and$(SEP)or mate.
|
||||
# - Input file(s): test-nochecks.pgn
|
||||
# - Resulting output should contain games with no check indicators after moves.
|
||||
# - Expected output: test-nochecks-out.pgn
|
||||
test-nochecks:
|
||||
echo "test-nochecks:"
|
||||
$(PGN_EXTRACT) --nochecks -otest-nochecks-out.pgn --quiet $(INPUT)$(SEP)test-nochecks.pgn
|
||||
$(CMP) test-nochecks-out.pgn $(OUTPUT)$(SEP)test-nochecks-out.pgn
|
||||
|
||||
# --nomovenumbers
|
||||
# + Input file containing games with move numbers.
|
||||
# - Input file(s): test-nomovenumbers.pgn
|
||||
# - Resulting output should contain games with no move numbers.
|
||||
# - Expected output: test-nomovenumbers-out.pgn
|
||||
test-nomovenumbers:
|
||||
echo "test-nomovenumbers:"
|
||||
$(PGN_EXTRACT) -otest-nomovenumbers-out.pgn --nomovenumbers --quiet $(INPUT)$(SEP)test-nomovenumbers.pgn
|
||||
$(CMP) test-nomovenumbers-out.pgn $(OUTPUT)$(SEP)test-nomovenumbers-out.pgn
|
||||
|
||||
# --noresults
|
||||
# + Input file containing games with results.
|
||||
# - Input file(s): test-noresults.pgn
|
||||
# - Resulting output should contain games with no results.
|
||||
# - Expected output: test-noresults-out.pgn
|
||||
test-noresults:
|
||||
echo "test-noresults:"
|
||||
$(PGN_EXTRACT) -otest-noresults-out.pgn --noresults --quiet $(INPUT)$(SEP)test-noresults.pgn
|
||||
$(CMP) test-noresults-out.pgn $(OUTPUT)$(SEP)test-noresults-out.pgn
|
||||
|
||||
# --notags
|
||||
# + Input file containing games with tag information.
|
||||
# - Input file(s): test-notags.pgn
|
||||
# - Resulting output should contain games with no tag information.
|
||||
# - Expected output: test-notags-out.pgn
|
||||
test-notags:
|
||||
echo "test-notags:"
|
||||
$(PGN_EXTRACT) -otest-notags-out.pgn --notags --quiet $(INPUT)$(SEP)test-notags.pgn
|
||||
$(CMP) test-notags-out.pgn $(OUTPUT)$(SEP)test-notags-out.pgn
|
||||
|
||||
# --plylimit
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-plylimit.pgn
|
||||
# - Resulting output should contain games whose number of moves (plies) are
|
||||
# limited at the specified ply limit.
|
||||
# - Expected output: test-plylimit-out.pgn
|
||||
test-plylimit:
|
||||
echo "test-plylimit:"
|
||||
$(PGN_EXTRACT) --plylimit 10 -otest-plylimit-out.pgn --quiet $(INPUT)$(SEP)test-plylimit.pgn
|
||||
$(CMP) test-plylimit-out.pgn $(OUTPUT)$(SEP)test-plylimit-out.pgn
|
||||
|
||||
# --dropply
|
||||
# + Input file containing games.
|
||||
# - Input file(s): najdorf.pgn
|
||||
# - Resulting output should contain games whose number of moves (plies) are
|
||||
# have been reduced by the given number from the beginning or end.
|
||||
# - Expected output: test-dropply-out.pgn
|
||||
test-dropply:
|
||||
echo "test-dropply:"
|
||||
$(PGN_EXTRACT) --dropply 10 -otest-dropply-out.pgn --quiet $(INPUT)$(SEP)najdorf.pgn
|
||||
$(PGN_EXTRACT) --dropply 11 -atest-dropply-out.pgn --quiet $(INPUT)$(SEP)najdorf.pgn
|
||||
$(PGN_EXTRACT) --dropply -1 -atest-dropply-out.pgn --quiet $(INPUT)$(SEP)najdorf.pgn
|
||||
$(PGN_EXTRACT) --dropply -2 -atest-dropply-out.pgn --quiet $(INPUT)$(SEP)najdorf.pgn
|
||||
$(CMP) test-dropply-out.pgn $(OUTPUT)$(SEP)test-dropply-out.pgn
|
||||
|
||||
# --selectonly
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-selectonly.pgn
|
||||
# - Resulting output should contain only two matched games.
|
||||
# - Expected output: test-selectonly-out.pgn
|
||||
test-selectonly:
|
||||
echo "test-selectonly:"
|
||||
$(PGN_EXTRACT) -TpPetrosian --selectonly 2,3 -otest-selectonly-out.pgn --quiet $(INPUT)$(SEP)test-selectonly.pgn
|
||||
$(CMP) test-selectonly-out.pgn $(OUTPUT)$(SEP)test-selectonly-out.pgn
|
||||
|
||||
# --skipmatching
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-skipmatching.pgn
|
||||
# - Resulting output should contain a single matched game.
|
||||
# - Expected output: test-selectonly-out.pgn
|
||||
test-skipmatching:
|
||||
echo "test-skipmatching:"
|
||||
$(PGN_EXTRACT) -TpKeres --skipmatching 1,2 -otest-skipmatching-out.pgn --quiet $(INPUT)$(SEP)fischer.pgn
|
||||
$(CMP) test-skipmatching-out.pgn $(OUTPUT)$(SEP)test-skipmatching-out.pgn
|
||||
|
||||
# --splitvariants
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-splitvariants.pgn
|
||||
# - Resulting output should contain a separate game
|
||||
# for every variation in the input file.
|
||||
# - Expected output: test-splitvariants-out.pgn
|
||||
test-splitvariants:
|
||||
echo "test-splitvariants:"
|
||||
$(PGN_EXTRACT) --splitvariants -otest-splitvariants-out.pgn --quiet $(INPUT)$(SEP)test-splitvariants.pgn
|
||||
$(CMP) test-splitvariants-out.pgn $(OUTPUT)$(SEP)test-splitvariants-out.pgn
|
||||
|
||||
# --stalemate
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-stalemate.pgn
|
||||
# - Resulting output should contain only those games that end in stalemate.
|
||||
# - Expected output: test-stalemate-out.pgn
|
||||
test-stalemate:
|
||||
echo "test-stalemate:"
|
||||
$(PGN_EXTRACT) --stalemate -otest-stalemate-out.pgn --quiet $(INPUT)$(SEP)test-stalemate.pgn
|
||||
$(CMP) test-stalemate-out.pgn $(OUTPUT)$(SEP)test-stalemate-out.pgn
|
||||
|
||||
# --fifty
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-fifty.pgn
|
||||
# - Resulting output should contain only those games to which the fifty-move rule
|
||||
# applies, with the comment { FIFTY } at the approriate point.
|
||||
# - Expected output: test-fifty-out.pgn
|
||||
test-fifty:
|
||||
echo "test-fifty:"
|
||||
$(PGN_EXTRACT) --fifty --markmatches FIFTY -otest-fifty-out.pgn --quiet $(INPUT)$(SEP)test-fifty.pgn
|
||||
$(CMP) test-fifty-out.pgn $(OUTPUT)$(SEP)test-fifty-out.pgn
|
||||
|
||||
# --seventyfive
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-seventyfive.pgn
|
||||
# - Resulting output should contain only those games to which the seventy-five-move rule
|
||||
# applies, with the comment { SEVENTYFIVE } at the approriate point.
|
||||
# - Expected output: test-seventyfive-out.pgn
|
||||
test-seventyfive:
|
||||
echo "test-seventyfive:"
|
||||
$(PGN_EXTRACT) --seventyfive --markmatches SEVENTYFIVE -otest-seventyfive-out.pgn --quiet $(INPUT)$(SEP)test-seventyfive.pgn
|
||||
$(CMP) test-seventyfive-out.pgn $(OUTPUT)$(SEP)test-seventyfive-out.pgn
|
||||
|
||||
# --repetition
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-repetition.pgn
|
||||
# - Resulting output should contain only those games which contain a 3-fold repetition,
|
||||
# with the comment { REPEAT } at the approriate point.
|
||||
# - Expected output: test-repetition-out.pgn
|
||||
test-repetition:
|
||||
echo "test-repetition:"
|
||||
$(PGN_EXTRACT) --repetition --markmatches REPEAT -otest-repetition-out.pgn --quiet $(INPUT)$(SEP)test-repetition.pgn
|
||||
$(CMP) test-repetition-out.pgn $(OUTPUT)$(SEP)test-repetition-out.pgn
|
||||
|
||||
# --plycount and --totalplycount
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-plycount.pgn
|
||||
# - Resulting output should contain games with PlyCount and TotalPlyCount tags.
|
||||
# - Expected output: test-plycount-out.pgn
|
||||
test-plycount:
|
||||
echo "test-plycount:"
|
||||
$(PGN_EXTRACT) --plycount --totalplycount -otest-plycount-out.pgn --quiet $(INPUT)$(SEP)test-plycount.pgn
|
||||
$(CMP) test-plycount-out.pgn $(OUTPUT)$(SEP)test-plycount-out.pgn
|
||||
|
||||
# --addhashcode
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-addhashcode.pgn
|
||||
# - Resulting output should contain games with a HashCode tag.
|
||||
# - Expected output: test-addhashcode-out.pgn
|
||||
test-addhashcode:
|
||||
echo "test-addhashcode:"
|
||||
$(PGN_EXTRACT) --addhashcode -otest-addhashcode-out.pgn --quiet $(INPUT)$(SEP)test-addhashcode.pgn
|
||||
$(CMP) test-addhashcode-out.pgn $(OUTPUT)$(SEP)test-addhashcode-out.pgn
|
||||
|
||||
# Test on a file with a string too long to be output within the
|
||||
# defined line length.
|
||||
# + Input file containing a game with a very long comment.
|
||||
# + Input file(s): test-long-line.pgn
|
||||
# + Resulting output should contain the game properly formatted and
|
||||
# the log file should contain an error message reporting the problem.
|
||||
# + Expected output: test-long-line-out.pgn, test-long-line-log.txt
|
||||
test-long-line:
|
||||
echo "test long line:"
|
||||
$(PGN_EXTRACT) -otest-long-line-out.pgn -ltest-long-line-log.txt $(INPUT)$(SEP)test-long-line.pgn
|
||||
$(CMP) test-long-line-out.pgn $(OUTPUT)$(SEP)test-long-line-out.pgn
|
||||
# $(CMP) test-long-line-log.txt $(OUTPUT)$(SEP)test-long-line-log.txt
|
||||
|
||||
# Promotion characters.
|
||||
# + Input file with games involving a promotion
|
||||
# - Input file(s): test-promotion-in.pgn
|
||||
# - Game output should have all games with promotions.
|
||||
# - Expected output: test-promotion-out.pgn
|
||||
test-promotion:
|
||||
echo "test-promotion:"
|
||||
$(PGN_EXTRACT) -otest-promotion-out.pgn --quiet $(INPUT)$(SEP)test-promotion-in.pgn
|
||||
$(CMP) test-promotion-out.pgn $(OUTPUT)$(SEP)test-promotion-out.pgn
|
||||
$(PGN_EXTRACT) --underpromotion -otest-underpromotion-out.pgn --quiet $(INPUT)$(SEP)test-promotion-in.pgn
|
||||
$(CMP) test-underpromotion-out.pgn $(OUTPUT)$(SEP)test-underpromotion-out.pgn
|
||||
|
||||
# Inconsistent Result tags
|
||||
# + Input file with games where the Result tag conflicts with checkmate or stalemate.
|
||||
# - Input file(s): test-fixresulttags-in.pgn
|
||||
# - Game output should have consistent Result tags
|
||||
# - Expected output: test-fixresulttags-out.pgn
|
||||
test-fixresulttags:
|
||||
echo "test-fixresulttags:"
|
||||
$(PGN_EXTRACT) --fixresulttags -otest-fixresulttags-out.pgn -lfix-results-log.txt --quiet $(INPUT)$(SEP)test-fixresulttags-in.pgn
|
||||
$(CMP) test-fixresulttags-out.pgn $(OUTPUT)$(SEP)test-fixresulttags-out.pgn
|
||||
# $(CMP) fix-results-log.txt $(OUTPUT)$(SEP)fix-results-log.txt
|
||||
|
||||
# --fuzzydepth
|
||||
# + Input file containing games with fuzzy duplicates and non-duplicates.
|
||||
# - Input file(s): $(INPUT)$(SEP)test-fuzzydepth.pgn
|
||||
# - Resulting output should be files separating the unique and
|
||||
# duplicated games in the input files.
|
||||
# - Expected output: test-fuzzydepth0-unique.pgn, test-fuzzydepth0-dupes.pgn
|
||||
test-fuzzydepth:
|
||||
echo "test-duplicates:"
|
||||
$(PGN_EXTRACT) -C --fuzzydepth 0 -dtest-fuzzydepth0-dupes.pgn -otest-fuzzydepth0-unique.pgn --quiet $(INPUT)$(SEP)test-fuzzydepth.pgn
|
||||
$(CMP) test-fuzzydepth0-dupes.pgn $(OUTPUT)$(SEP)test-fuzzydepth0-dupes.pgn
|
||||
$(CMP) test-fuzzydepth0-unique.pgn $(OUTPUT)$(SEP)test-fuzzydepth0-unique.pgn
|
||||
$(PGN_EXTRACT) -C --fuzzydepth 3 -dtest-fuzzydepth3-dupes.pgn -otest-fuzzydepth3-unique.pgn --quiet $(INPUT)$(SEP)test-fuzzydepth.pgn
|
||||
$(CMP) test-fuzzydepth3-dupes.pgn $(OUTPUT)$(SEP)test-fuzzydepth3-dupes.pgn
|
||||
$(CMP) test-fuzzydepth3-unique.pgn $(OUTPUT)$(SEP)test-fuzzydepth3-unique.pgn
|
||||
$(PGN_EXTRACT) -C --fuzzydepth 4 -dtest-fuzzydepth4-dupes.pgn -otest-fuzzydepth4-unique.pgn --quiet $(INPUT)$(SEP)test-fuzzydepth.pgn
|
||||
$(CMP) test-fuzzydepth4-dupes.pgn $(OUTPUT)$(SEP)test-fuzzydepth4-dupes.pgn
|
||||
$(CMP) test-fuzzydepth4-unique.pgn $(OUTPUT)$(SEP)test-fuzzydepth4-unique.pgn
|
||||
$(PGN_EXTRACT) -C --fuzzydepth 5 -dtest-fuzzydepth5-dupes.pgn -otest-fuzzydepth5-unique.pgn --quiet $(INPUT)$(SEP)test-fuzzydepth.pgn
|
||||
$(CMP) test-fuzzydepth5-dupes.pgn $(OUTPUT)$(SEP)test-fuzzydepth5-dupes.pgn
|
||||
$(CMP) test-fuzzydepth5-unique.pgn $(OUTPUT)$(SEP)test-fuzzydepth5-unique.pgn
|
||||
|
||||
# Selection or exclusion of games with SetUp tags.
|
||||
# + Input file with games involving SetUp tags.
|
||||
# - Input file(s): test-setup-in.pgn
|
||||
# - Game output should either have only games with SetUp tags
|
||||
# or only those without.
|
||||
# - Expected output: test-nosetup-out.pgn test-onlysetup-out.pgn
|
||||
test-setup:
|
||||
echo "test-setup:"
|
||||
$(PGN_EXTRACT) --nosetuptags -otest-nosetup-out.pgn --quiet $(INPUT)$(SEP)test-setup-in.pgn
|
||||
$(CMP) test-nosetup-out.pgn $(OUTPUT)$(SEP)test-nosetup-out.pgn
|
||||
$(PGN_EXTRACT) --onlysetuptags -otest-onlysetup-out.pgn --quiet $(INPUT)$(SEP)test-setup-in.pgn
|
||||
$(CMP) test-onlysetup-out.pgn $(OUTPUT)$(SEP)test-onlysetup-out.pgn
|
||||
|
||||
# --stopafter
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-stopafter.pgn
|
||||
# - Resulting output should contain a single matched game.
|
||||
# - Expected output: test-stopafter-out.pgn
|
||||
test-stopafter:
|
||||
echo "test-stopafter:"
|
||||
$(PGN_EXTRACT) -TpPetrosian --stopafter 1 -otest-stopafter-out.pgn --quiet $(INPUT)$(SEP)test-stopafter.pgn
|
||||
$(CMP) test-stopafter-out.pgn $(OUTPUT)$(SEP)test-stopafter-out.pgn
|
||||
|
||||
# --nobadresults
|
||||
# + Input file containing games with inconsistent or incomplete results.
|
||||
# - Input file(s): test-nobadresults.pgn
|
||||
# - Resulting output should contain only those games which are not
|
||||
# strictly inconsistent.
|
||||
# - Expected output: test-nobadresults-out.pgn
|
||||
test-nobadresults:
|
||||
echo "test-nobadresults:"
|
||||
$(PGN_EXTRACT) --nobadresults -otest-nobadresults-out.pgn -ltest-nobadresults-log.txt --quiet $(INPUT)$(SEP)test-nobadresults.pgn
|
||||
$(CMP) test-nobadresults-out.pgn $(OUTPUT)$(SEP)test-nobadresults-out.pgn
|
||||
# $(CMP) test-nobadresults-log.txt $(OUTPUT)$(SEP)test-nobadresults-log.txt
|
||||
|
||||
# --allownullmoves
|
||||
# + Input file containing games with inconsistent or incomplete results.
|
||||
# - Input file(s): test-allownullmoves.pgn
|
||||
# - Resulting output should contain only those games which are not
|
||||
# strictly inconsistent.
|
||||
# - Expected output: test-allownullmoves-out.pgn
|
||||
test-allownullmoves:
|
||||
echo "test-allownullmoves:"
|
||||
$(PGN_EXTRACT) --allownullmoves -otest-allownullmoves-out.pgn -ltest-allownullmoves-log.txt --quiet $(INPUT)$(SEP)test-allownullmoves.pgn
|
||||
$(CMP) test-allownullmoves-out.pgn $(OUTPUT)$(SEP)test-allownullmoves-out.pgn
|
||||
# $(CMP) test-allownullmoves-log.txt $(OUTPUT)$(SEP)test-allownullmoves-log.txt
|
||||
|
||||
# --matchplylimit
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-matchplylimit.pgn
|
||||
# - Resulting output should contain games whose number of moves (plies) are
|
||||
# limited at the specified ply limit.
|
||||
# - Expected output: test-matchplylimit-out.pgn
|
||||
test-matchplylimit:
|
||||
echo "test-matchplylimit:"
|
||||
-$(RM) test-matchplylimit-out.pgn
|
||||
$(PGN_EXTRACT) -Hdb55d4fcaadc775e --matchplylimit 8 --markmatches match -atest-matchplylimit-out.pgn --quiet $(INPUT)$(SEP)test-matchplylimit.pgn
|
||||
$(PGN_EXTRACT) -Hdb55d4fcaadc775e --matchplylimit 9 --markmatches match -atest-matchplylimit-out.pgn --quiet $(INPUT)$(SEP)test-matchplylimit.pgn
|
||||
$(PGN_EXTRACT) -Hdb55d4fcaadc775e --matchplylimit 10 --markmatches match -atest-matchplylimit-out.pgn --quiet $(INPUT)$(SEP)test-matchplylimit.pgn
|
||||
$(PGN_EXTRACT) -Hdb55d4fcaadc775e --matchplylimit 150 --markmatches match -atest-matchplylimit-out.pgn --quiet $(INPUT)$(SEP)test-matchplylimit.pgn
|
||||
$(CMP) test-matchplylimit-out.pgn $(OUTPUT)$(SEP)test-matchplylimit-out.pgn
|
||||
|
||||
# -A/-t with FENPattern and FENPatternI
|
||||
# Test both FENPattern and FENPatternI and add a MatchLabel tag
|
||||
# if the pattern has an associated label.
|
||||
test-FENPattern:
|
||||
echo "test-FENPattern:"
|
||||
$(PGN_EXTRACT) -otest-FENPattern-out.pgn -ltest-FENPattern-log.txt --quiet \
|
||||
-A$(INPUT)$(SEP)test-FENPattern.txt --addlabeltag --markmatches HERE \
|
||||
$(INPUT)$(SEP)petrosian.pgn
|
||||
$(CMP) test-FENPattern-out.pgn $(OUTPUT)$(SEP)test-FENPattern-out.pgn
|
||||
$(PGN_EXTRACT) -otest-FENPattern-cli-out.pgn -ltest-FENPattern-log.txt --quiet \
|
||||
--fenpattern "*/*/*/*/???pN???/???P????/*/*" \
|
||||
--fenpatterni "*/*/*/*/???Np???/????P???/*/*" \
|
||||
--markmatches HERE \
|
||||
$(INPUT)$(SEP)petrosian.pgn
|
||||
$(CMP) test-FENPattern-cli-out.pgn $(OUTPUT)$(SEP)test-FENPattern-cli-out.pgn
|
||||
# $(CMP) test-FENPattern-log.txt $(OUTPUT)$(SEP)test-FENPattern-log.txt
|
||||
|
||||
# --startply
|
||||
# + Input file containing games.
|
||||
# - Input file(s): test-startply.pgn
|
||||
# - Resulting output should contain games matching the given FEN pattern,
|
||||
# only starting the match at the specified ply.
|
||||
# - Expected output: test-startply-out.pgn
|
||||
test-startply:
|
||||
echo "test-startply:"
|
||||
-$(RM) test-startply-out.pgn
|
||||
$(PGN_EXTRACT) --startply 8 -Tf"*/*/4p3/3pP3/2pP4/2P5/*/*" --markmatches match -atest-startply-out.pgn --quiet $(INPUT)$(SEP)test-startply.pgn
|
||||
$(PGN_EXTRACT) --startply 9 -Tf"*/*/4p3/3pP3/2pP4/2P5/*/*" --markmatches match -atest-startply-out.pgn --quiet $(INPUT)$(SEP)test-startply.pgn
|
||||
$(PGN_EXTRACT) --startply 10 -Tf"*/*/4p3/3pP3/2pP4/2P5/*/*" --markmatches match -atest-startply-out.pgn --quiet $(INPUT)$(SEP)test-startply.pgn
|
||||
$(PGN_EXTRACT) --startply 11 -Tf"*/*/4p3/3pP3/2pP4/2P5/*/*" --markmatches match -atest-startply-out.pgn --quiet $(INPUT)$(SEP)test-startply.pgn
|
||||
$(PGN_EXTRACT) --startply 100 -Tf"*/*/4p3/3pP3/2pP4/2P5/*/*" --markmatches match -atest-startply-out.pgn --quiet $(INPUT)$(SEP)test-startply.pgn
|
||||
$(PGN_EXTRACT) --startply 200 -Tf"*/*/4p3/3pP3/2pP4/2P5/*/*" --markmatches match -atest-startply-out.pgn --quiet $(INPUT)$(SEP)test-startply.pgn
|
||||
$(CMP) test-startply-out.pgn $(OUTPUT)$(SEP)test-startply-out.pgn
|
||||
|
||||
test-linenumbers:
|
||||
echo "test-linenumbers:"
|
||||
-$(RM) test-linenumbers-out.pgn
|
||||
$(PGN_EXTRACT) --quiet --linenumbers marker infiles/petrosian.pgn -o test-linenumbers-out.pgn
|
||||
$(CMP) test-linenumbers-out.pgn $(OUTPUT)$(SEP)test-linenumbers-out.pgn
|
1
pgn-extract/test/infiles/Pvars.txt
Normal file
1
pgn-extract/test/infiles/Pvars.txt
Normal file
@@ -0,0 +1 @@
|
||||
c4 Nf6 Nc3 e6 d4 Bb4
|
6
pgn-extract/test/infiles/alg.txt
Normal file
6
pgn-extract/test/infiles/alg.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
b2b3 e7e5 c1b2 d7d6 d2d4 e5d4 d1d4 b8c6 d4d2 g8f6 b1c3 c8e6 e2e4 d6d5 e4d5
|
||||
e6d5 d2e3+ f8e7 g1f3 e8g8 f1e2 f8e8 e1c1 e7b4 e3d3 b4c3 b2c3 d8e7 h1e1 f6e4
|
||||
c3b2 a8d8 d3e3 b7b6 e2b5 e7e6 f3d4 c6d4 d1d4 c7c5 d4e4 d5e4 b5e8 d8e8 f2f3
|
||||
e4d5 e3e6 e8e6 e1e6 d5e6 c1d2 g8f8 b2e5 b6b5 e5b8 a7a6 b8a7 c5c4 d2c3 f8e7
|
||||
c3d4 e7d6 a7c5+ d6d7 c5a7 d7d6 a7c5+ d6d7 d4c3 g7g6 c5d4 f7f5 1/2-1/2
|
||||
|
15
pgn-extract/test/infiles/argslist.txt
Normal file
15
pgn-extract/test/infiles/argslist.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
% Strip variations.
|
||||
:--novars
|
||||
% Silent mode
|
||||
:-s
|
||||
% Duplicates file.
|
||||
:-dtest-AA-dupes.pgn
|
||||
% Unique file.
|
||||
:--output test-AA-unique.pgn
|
||||
% Tag criteria
|
||||
:-t
|
||||
White "Fischer"
|
||||
Black "Petrosian"
|
||||
% The game files.
|
||||
:infiles/fischer.pgn
|
||||
:infiles/petrosian.pgn
|
19
pgn-extract/test/infiles/barnes-horton.pgn
Normal file
19
pgn-extract/test/infiles/barnes-horton.pgn
Normal file
@@ -0,0 +1,19 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
1
pgn-extract/test/infiles/clist.txt
Normal file
1
pgn-extract/test/infiles/clist.txt
Normal file
@@ -0,0 +1 @@
|
||||
infiles/petrosian.pgn
|
2
pgn-extract/test/infiles/files.txt
Normal file
2
pgn-extract/test/infiles/files.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
infiles/test-f1.pgn
|
||||
infiles/test-f2.pgn
|
581
pgn-extract/test/infiles/fischer.pgn
Normal file
581
pgn-extract/test/infiles/fischer.pgn
Normal file
@@ -0,0 +1,581 @@
|
||||
[Event "Milwaukee Northwestern"]
|
||||
[Site "?"]
|
||||
[Date "1957"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Kampars, N."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 e6 6. d4 Nd7 7. Bd3 dxe4
|
||||
8. Nxe4 Ngf6 9. O-O Nxe4 10. Qxe4 Nf6 11. Qe3 Nd5 12. Qf3 Qf6 13. Qxf6 Nxf6
|
||||
14. Rd1 O-O-O 15. Be3 Nd5 16. Bg5 Be7 17. Bxe7 Nxe7 18. Be4 Nd5 19. g3 Nf6
|
||||
20. Bf3 Kc7 21. Kf1 Rhe8 22. Be2 e5 23. dxe5 Rxe5 24. Bc4 Rxd1+ 25. Rxd1
|
||||
Re7 26. Bb3 Ne4 27. Rd4 Nd6 28. c3 f6 29. Bc2 h6 30. Bd3 Nf7 31. f4 Rd7 32.
|
||||
Rxd7+ Kxd7 33. Kf2 Nd6 34. Kf3 f5 35. Ke3 c5 36. Be2 Ke6 37. Bd3 1/2-1/2
|
||||
|
||||
[Event "US Open"]
|
||||
[Site "?"]
|
||||
[Date "1957"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Addison, William G."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 dxe4 4. Nxe4 Nf6 5. Nxf6+ exf6 6. Bc4 Bd6 7. Qe2+
|
||||
Qe7 8. Qxe7+ Kxe7 9. d4 Bf5 10. Bb3 Re8 11. Be3 Kf8 12. O-O-O Nd7 13. c4
|
||||
Rad8 14. Bc2 Bxc2 15. Kxc2 f5 16. Rhe1 f4 17. Bd2 Nf6 18. Ne5 g5 19. f3 Nh5
|
||||
20. Ng4 Kg7 21. Bc3 Kg6 22. Rxe8 Rxe8 23. c5 Bb8 24. d5 cxd5 25. Rxd5 f5
|
||||
26. Ne5+ Bxe5 27. Rxe5 Nf6 28. Rxe8 Nxe8 29. Be5 Kh5 30. Kd3 g4 31. b4 a6
|
||||
32. a4 gxf3 33. gxf3 Kh4 34. b5 axb5 35. a5 Kh3 36. c6 1-0
|
||||
|
||||
[Event "West Orange Open"]
|
||||
[Site "?"]
|
||||
[Date "1957"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Goldsmith, Julius"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d6 3. d4 Nd7 4. Nf3 e5 5. Bc4 Be7 6. dxe5 Nxe5 7. Nxe5 dxe5
|
||||
8. Qh5 g6 9. Qxe5 Nf6 10. Bg5 Bd7 11. O-O-O O-O 12. Rxd7 Qxd7 13. Bxf6 Bxf6
|
||||
14. Qxf6 Rae8 15. f3 Qc7 16. h4 Qe5 17. Qxe5 Rxe5 18. Rd1 Re7 19. Rd6 Kg7
|
||||
20. a3 f5 21. Kd2 fxe4 22. Nxe4 Rf4 23. h5 gxh5 24. Rd8 h4 25. Rg8+ Kh6 26.
|
||||
Ke3 Rf5 27. Rg4 Rh5 28. Kf2 Rg7 29. Rxg7 Kxg7 30. Bf1 Rd5 31. Bd3 h6 32.
|
||||
Ke3 Rh5 33. Nd6 h3 34. gxh3 Rxh3 35. Nxb7 Rh5 36. b4 Re5+ 37. Kf4 Re7 38.
|
||||
Nd8 c5 39. bxc5 Kf6 40. c6 Rc7 41. Be4 Ke7 42. Nb7 Kf6 43. Nd6 Re7 44. c7
|
||||
1-0
|
||||
|
||||
[Event "Bad Portoroz Interzonal"]
|
||||
[Site "?"]
|
||||
[Date "1958"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Cardoso, Rudolfo T."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 dxe4 4. Nxe4 Bg4 5. h3 Bxf3 6. Qxf3 Nd7 7. Ng5
|
||||
Ngf6 8. Qb3 e6 9. Qxb7 Nd5 10. Ne4 Nb4 11. Kd1 f5 12. c3 Rb8 13. Qxa7 fxe4
|
||||
14. cxb4 Bxb4 15. Qd4 O-O 16. Bc4 Nc5 17. Qxd8 Rbxd8 18. Rf1 Rd4 19. b3
|
||||
Bxd2 20. Ke2 Bxc1 21. Raxc1 Rfd8 22. Rfd1 Kf8 23. Rxd4 Rxd4 24. Rd1 Rxd1
|
||||
25. Kxd1 Ke7 26. Kd2 Kd6 27. Kc3 Nd7 28. Kd4 Nf6 29. a4 c5+ 30. Ke3 g5 31.
|
||||
Be2 Kc6 32. Bc4 e5 33. a5 h6 34. Kd2 h5 35. Ke3 h4 36. Be2 Kb7 37. Bc4 Kc6
|
||||
38. Ke2 Kb7 39. Kd2 Kc6 40. Ke3 Kb7 41. Kd2 Kc7 42. g4 Kc6 43. Kc3 Ne8 44.
|
||||
b4 Nd6 45. Bf1 cxb4+ 46. Kxb4 Nc8 47. Bg2 Kd5 48. a6 Na7 49. Ka5 Kc5 50.
|
||||
Bxe4 Nb5 51. Bg2 Na7 52. Ka4 Nb5 53. Kb3 Kb6 54. Kc4 Kxa6 55. Kd5 Kb6 56.
|
||||
Kxe5 Kc7 57. Kf6 Nc3 58. Kxg5 Nd1 59. f4 Kd6 60. Kxh4 Ke6 61. Kg5 Kf7 62.
|
||||
f5 1-0
|
||||
|
||||
[Event "USA Championship"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Weinstein, Raymond"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Be7 8.
|
||||
Bg2 dxe4 9. dxe4 e5 10. O-O Nbd7 11. Nd1 O-O 12. Ne3 g6 13. Rd1 Qc7 14. Ng4
|
||||
h5 15. Nxf6+ Nxf6 16. Bg5 Nh7 17. Bh6 Rfd8 18. Bf1 Bg5 19. Bxg5 Nxg5 20.
|
||||
Qe3 Qe7 21. h4 Ne6 22. Bc4 b5 23. Bxe6 Qxe6 24. Qc5 Qc4 25. Qxc4 bxc4 26.
|
||||
b3 Rd4 27. Rxd4 exd4 28. Kf1 Re8 29. f3 Re5 30. Rd1 c5 31. c3 dxc3 32. Rc1
|
||||
f5 33. exf5 Rxf5 34. Rxc3 cxb3 35. Rxb3 c4 36. Ra3 Rc5 37. Ke2 c3 38. Kd1
|
||||
c2+ 39. Kc1 a5 40. Rb3 Kg7 41. Rb7+ Kf6 42. Rb6+ Kg7 43. g4 1/2-1/2
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Benko, Pal"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Qb6 10. b3 a5 11. a3 Bxd2+ 12. Nxd2 Qc5 13. Qd1 h5 14. h4
|
||||
Nbd7 15. Bg2 Ng4 16. O-O g5 17. b4 Qe7 18. Nf3 gxh4 19. Nxh4 Nde5 20. Qd2
|
||||
Rg8 21. Qf4 f6 22. bxa5 Rxa5 23. Rfb1 b5 24. Nf3 Ra4 25. Bh3 Nxf3+ 26. Qxf3
|
||||
Kd7 27. Kg2 Qg7 28. Rb4 Rga8 29. Rxa4 Rxa4 30. Bxg4 hxg4 31. Qf4 Ra8 32.
|
||||
Rh1 Rg8 33. a4 bxa4 34. Rb1 e5 35. Rb7+ Kd6 36. Rxg7 exf4 37. Rxg8 f3+ 38.
|
||||
Kh1 Kc5 39. Rb8 1-0
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Keres, Paul"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Qb6 10. b3 Nbd7 11. Bg2 a5 12. a3 Bxd2+ 13. Nxd2 Qc5 14. Qd1
|
||||
h5 15. Nf3 Qc3+ 16. Ke2 Qc5 17. Qd2 Ne5 18. b4 Nxf3 19. Bxf3 Qe5 20. Qf4
|
||||
Nd7 21. Qxe5 Nxe5 22. bxa5 Kd7 23. Rhb1 Kc7 24. Rb4 Rxa5 25. Bg2 g5 26. f4
|
||||
gxf4 27. gxf4 Ng6 28. Kf3 Rg8 29. Bf1 e5 30. fxe5 Nxe5+ 31. Ke2 c5 32. Rb3
|
||||
b6 33. Rab1 Rg6 34. h4 Ra6 35. Bh3 Rg3 36. Bf1 Rg4 37. Bh3 Rxh4 38. Rh1 Ra8
|
||||
39. Rbb1 Rg8 40. Rbf1 Rg3 41. Bf5 Rg2+ 42. Kd1 Rhh2 43. Rxh2 Rxh2 44. Rg1
|
||||
c4 45. dxc4 Nxc4 46. Rg7 Kd6 47. Rxf7 Ne3+ 48. Kc1 Rxc2+ 49. Kb1 Rh2 50.
|
||||
Rd7+ Ke5 51. Re7+ Kf4 52. Rd7 Nd1 53. Kc1 Nc3 54. Bh7 h4 55. Rf7+ Ke3 0-1
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Keres, Paul"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Qb6 10. b3 a5 11. a3 Be7 12. Bg2 a4 13. b4 Nbd7 14. O-O c5
|
||||
15. Ra2 O-O 16. bxc5 Bxc5 17. Qe2 e5 18. f4 Rfc8 19. h4 Rc6 20. Bh3 Qc7 21.
|
||||
fxe5 Nxe5 22. Bf4 Bd6 23. h5 Ra5 24. h6 Ng6 25. Qf3 Rh5 26. Bg4 Nxf4 27.
|
||||
Bxh5 N4xh5 28. g4 Bh2+ 29. Kg2 Nxg4 30. Nd2 Ne3+ 0-1
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Olafsson, Fridrik"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Nf6 4. e5 Ne4 5. Ne2 Qb6 6. d4 c5 7. dxc5 Qxc5 8.
|
||||
Ned4 Nc6 9. Bb5 a6 10. Bxc6+ bxc6 11. O-O Qb6 12. e6 fxe6 13. Bf4 g6 14.
|
||||
Be5 Nf6 15. Ng5 Bh6 16. Ndxe6 Bxg5 17. Nxg5 O-O 18. Qd2 Bf5 19. Rae1 Rad8
|
||||
20. Bc3 Rd7 21. Ne6 Bxe6 22. Rxe6 d4 23. Bb4 Nd5 24. Ba3 Rf7 25. g3 Nc7 26.
|
||||
Re5 Nd5 27. Qd3 Nf6 28. Qc4 Ng4 29. Re6 Qb5 30. Qxb5 axb5 31. Rxc6 Ne5 32.
|
||||
Rc8+ Kg7 33. Bb4 Nf3+ 34. Kg2 e5 35. Rd1 g5 36. Bf8+ Rxf8 37. Rxf8 Kxf8 38.
|
||||
Kxf3 Kf7 39. c3 Ke6 40. cxd4 exd4 41. Ke4 Rf7 42. f3 1-0
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Smyslov, Vasily V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bh5 5. exd5 cxd5 6. Bb5+ Nc6 7. g4 Bg6
|
||||
8. Ne5 Rc8 9. h4 f6 10. Nxg6 hxg6 11. d4 e6 12. Qd3 Kf7 13. h5 gxh5 14.
|
||||
gxh5 Nge7 15. Be3 Nf5 16. Bxc6 Rxc6 17. Ne2 Qa5+ 18. c3 Qa6 19. Qc2 Bd6 20.
|
||||
Bf4 Bxf4 21. Nxf4 Rh6 22. Qe2 Qxe2+ 23. Kxe2 Rh8 24. Kd3 b5 25. Rhe1 b4 26.
|
||||
cxb4 Rc4 27. Nxe6 Rxh5 28. b3 Rh3+ 29. Kd2 Rcc3 30. Nf4 Rhf3 31. Re2 g5 32.
|
||||
Nxd5 Rcd3+ 33. Kc1 Rxd4 34. Ne3 Nxe3 35. fxe3 Rxb4 36. Kd2 g4 37. Rc1 Rb7
|
||||
38. Rg1 Rd7+ 39. Kc2 f5 40. e4 Kf6 41. exf5 g3 42. Re8 Rg7 43. Rf8+ Ke7 44.
|
||||
Ra8 Kd6 45. Rf8 Rf2+ 46. Kd3 g2 47. f6 Rg3+ 48. Kc4 Ke6 49. Re1+ Kf5 50. f7
|
||||
Rg7 51. Rg1 Kf6 52. a4 Rxf7 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Yugoslavia, Bled"]
|
||||
[Date "1959.??.??"]
|
||||
[Round "02"]
|
||||
[White "Fischer, R."]
|
||||
[Black "Petrosian, T."]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Bxd2+ 10. Nxd2 e5 11. Bg2 c5 12. O-O Nc6 13. Qe2 g5 14. Nf3
|
||||
h6 15. h4 Rg8 16. a3 Qe7 17. hxg5 hxg5 18. Qd2 Nd7 19. c3 O-O-O 20. cxd4
|
||||
exd4 21. b4 Kb8 22. Rfc1 Nce5 23. Nxe5 Qxe5 24. Rc4 Rc8 25. Rac1 g4 26. Qb2
|
||||
Rgd8 27. a4 Qe7 28. Rb1 Ne5 29. Rxc5 Rxc5 30. bxc5 Nxd3 31. Qd2 Nxc5 32.
|
||||
Qf4+ Qc7 33. Qxg4 Nxa4 34. e5 Nc5 35. Qf3 d3 36. Qe3 d2 37. Bf3 Na4 38. Qe4
|
||||
Nc5 39. Qe2 a6 40. Kg2 Ka7 41. Qe3 Rd3 42. Qf4 Qd7 43. Qc4 b6 44. Rd1 a5
|
||||
45. Qf4 Rd4 46. Qh6 b5 47. Qe3 Kb6 48. Qh6+ Ne6 49. Qe3 Ka6 50. Be2 a4 51.
|
||||
Qc3 Kb6 52. Qe3 Nc5 53. Bf3 b4 54. Qh6+ Ne6 55. Qh8 Qd8 56. Qh7 Qd7 57. Qh8
|
||||
b3 58. Qb8+ Ka5 59. Qa8+ Kb5 60. Qb8+ Kc4 61. Qg8 Kc3 62. Bh5 Nd8 63. Bf3
|
||||
a3 64. Qf8 Kb2 65. Qh8 Ne6 66. Qa8 a2 67. Qa5 Qa4 68. Rxd2+ Ka3 0-1
|
||||
|
||||
[Event "?"]
|
||||
[Site "Yugoslavia, Zagreb"]
|
||||
[Date "1959.??.??"]
|
||||
[Round "16"]
|
||||
[White "Fischer, R."]
|
||||
[Black "Petrosian, T."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Bxd2+ 10. Nxd2 e5 11. Bg2 c5 12. O-O Nc6 13. Qe2 Qe7 14. f4
|
||||
O-O-O 15. a3 Ne8 16. b4 cxb4 17. Nc4 f6 18. fxe5 fxe5 19. axb4 Nc7 20. Na5
|
||||
Nb5 21. Nxc6 bxc6 22. Rf2 g6 23. h4 Kb7 24. h5 Qxb4 25. Rf7+ Kb6 26. Qf2 a5
|
||||
27. c4 Nc3 28. Rf1 a4 29. Qf6 Qc5 30. Rxh7 Rdf8 31. Qxg6 Rxh7 32. Qxh7
|
||||
Rxf1+ 33. Bxf1 a3 34. h6 a2 35. Qg8 a1=Q 36. h7 Qd6 37. h8=Q Qa7 38. g4 Kc5
|
||||
39. Qf8 Qae7 40. Qa8 Kb4 41. Qh2 Kb3 42. Qa1 Qa3 43. Qxa3+ Kxa3 44. Qh6 Qf7
|
||||
45. Kg2 Kb3 46. Qd2 Qh7 47. Kg3 Qxe4 48. Qf2 Qh1 1/2-1/2
|
||||
|
||||
[Event "Zurich"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Larsen, Bent"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nf3 d5 3. Nc3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. a3 Bc5 8.
|
||||
Be2 O-O 9. O-O Nbd7 10. Qg3 Bd4 11. Bh6 Ne8 12. Bg5 Ndf6 13. Bf3 Qd6 14.
|
||||
Bf4 Qc5 15. Rab1 dxe4 16. dxe4 e5 17. Bg5 Bxc3 18. bxc3 b5 19. c4 a6 20.
|
||||
Bd2 Qe7 21. Bb4 Nd6 22. Rfd1 Rfd8 23. cxb5 cxb5 24. Rd3 Qe6 25. Rbd1 Nb7
|
||||
26. Bc3 Rxd3 27. cxd3 Re8 28. Kh2 h6 29. d4 Nd6 30. Re1 Nc4 31. dxe5 Nxe5
|
||||
32. Bd1 Ng6 33. e5 Nd5 34. Bb3 Qc6 35. Bb2 Ndf4 36. Rd1 a5 37. Rd6 Qe4 38.
|
||||
Rd7 Ne6 39. Bd5 Qe2 40. Bc3 b4 41. axb4 axb4 42. Bxb4 Qxe5 43. Ba5 Qxg3+
|
||||
44. Kxg3 Re7 45. Rd6 Nef4 46. Bf3 Ne6 47. Bb6 Ne5 48. Bd5 Rd7 49. Rxd7 Nxd7
|
||||
50. Be3 Nf6 51. Bc6 g5 52. Kf3 Kg7 53. Ba4 Nd5 54. Bc1 h5 55. Bb2+ Kh6 56.
|
||||
Bb3 Ndf4 57. Bc2 Ng6 58. Kg3 Nef4 59. Be4 Nh4 60. Bf6 Nhg6 61. Kf3 Nh4+ 62.
|
||||
Kg3 Nhg6 63. Kh2 h4 64. Kg1 Nh5 65. Bc3 Ngf4 66. Kf1 Ng7 67. Bf6 Nfh5 68.
|
||||
Be5 f6 69. Bd6 f5 70. Bf3 Nf4 71. Ke1 Kg6 72. Kd2 Nge6 73. Be5 Nc5 74. Ke3
|
||||
Nce6 75. Bc6 Kf7 76. Kf3 Ke7 77. Bb7 Ng6 78. Bc3 Ngf4 79. Ba6 Nd5 80. Be5
|
||||
Nf6 81. Bd3 g4+ 82. Ke2 Nd7 83. Bh2 gxh3 84. gxh3 Kf6 85. Ke3 Ne5 86. Be2
|
||||
Ng6 87. Bf1 f4+ 88. Kf3 Ne5+ 89. Ke4 Ng5+ 90. Kxf4 Nef3 91. Bg3 hxg3 92.
|
||||
fxg3 1/2-1/2
|
||||
|
||||
[Event "Buenos Aires"]
|
||||
[Site "?"]
|
||||
[Date "1960"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Foguelman, Alberto"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Bf5 5. Ng3 Bg6 6. Nh3 Nf6 7. Nf4 e5
|
||||
8. dxe5 Qxd1+ 9. Kxd1 Ng4 10. Nxg6 hxg6 11. Ne4 Nxe5 12. Be2 f6 13. c3 Nbd7
|
||||
14. Be3 O-O-O 15. Kc2 Nb6 16. h4 Nec4 17. Bf4 Nd5 18. Bg3 Nd6 19. Nxd6+
|
||||
Bxd6 20. Bxd6 Rxd6 21. g3 Kc7 22. c4 Nb4+ 23. Kc3 c5 24. a3 Re8 25. Bf1 Nc6
|
||||
26. Bd3 Ne5 27. Be4 Ng4 28. Bxg6 Re2 29. Rae1 Rxf2 30. Re7+ Kb6 31. Be4 Re2
|
||||
32. Rxb7+ Ka6 33. Re7 Kb6 34. b4 Nf2 35. Rb7+ Ka6 36. b5+ Ka5 37. Rxa7+ Kb6
|
||||
38. Ra6+ Kc7 39. b6+ Rxb6 40. Rxb6 Nxe4+ 41. Kd3 Kxb6 42. Rg1 Rd2+ 43. Kxe4
|
||||
Rd4+ 44. Kf5 Rxc4 45. Re1 Rc3 46. g4 Rf3+ 47. Kg6 Rxa3 48. Kxg7 Rg3 49. Re4
|
||||
f5 50. Re6+ Kb5 51. g5 Rg4 52. g6 Rxh4 53. Kf7 c4 54. g7 Rh7 55. Rg6 c3 56.
|
||||
Kf6 Rxg7 57. Rxg7 Kc4 58. Kxf5 c2 1/2-1/2
|
||||
|
||||
[Event "Buenos Aires"]
|
||||
[Site "?"]
|
||||
[Date "1960"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Ivkov, Boris"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. c4 Nf6 5. Nc3 e6 6. Nf3 Be7 7. c5 O-O 8.
|
||||
b4 b6 9. Bd3 bxc5 10. bxc5 Nc6 11. O-O Bd7 12. h3 Ne8 13. Bf4 Bf6 14. Bb5
|
||||
Nc7 15. Be2 Nxd4 16. Nxd4 e5 17. c6 Be8 18. Bg3 exd4 19. Bxc7 Qxc7 20. Nxd5
|
||||
Qd6 21. Nxf6+ Qxf6 22. c7 Rc8 23. Rc1 Bc6 24. Rc4 Rxc7 25. Bd3 Rd7 26. Qc2
|
||||
Bd5 27. Ra4 g6 28. Qc5 Rfd8 29. Bb5 Rd6 30. Rd1 Be6 31. Bd3 Rd5 32. Qxa7
|
||||
Bxh3 33. Be4 R5d7 34. Qa6 Qxa6 35. Rxa6 Be6 36. a4 d3 37. Rd2 Rd4 38. f3
|
||||
Bd5 39. Bxd5 R8xd5 40. Kf2 Rc4 41. a5 Ra4 42. Rc6 Ra3 43. Rc1 h5 44. Rcd1
|
||||
Kg7 45. a6 g5 46. a7 Rxa7 47. Rxd3 Ra2+ 48. Kg1 Rxd3 49. Rxd3 Kg6 50. Kh2
|
||||
Ra4 51. Rd5 g4 52. fxg4 hxg4 53. g3 Kf6 54. Rd7 Ke5 55. Kg2 f5 56. Rd2 Rc4
|
||||
57. Re2+ Kd4 58. Rf2 Rc5 59. Rf4+ Ke3 60. Kg1 1/2-1/2
|
||||
|
||||
[Event "Leipzig Olympiad Final"]
|
||||
[Site "?"]
|
||||
[Date "1960"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Euwe, Max"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. c4 Nf6 5. Nc3 Nc6 6. Nf3 Bg4 7. cxd5 Nxd5
|
||||
8. Qb3 Bxf3 9. gxf3 e6 10. Qxb7 Nxd4 11. Bb5+ Nxb5 12. Qc6+ Ke7 13. Qxb5
|
||||
Nxc3 14. bxc3 Qd7 15. Rb1 Rd8 16. Be3 Qxb5 17. Rxb5 Rd7 18. Ke2 f6 19. Rd1
|
||||
Rxd1 20. Kxd1 Kd7 21. Rb8 Kc6 22. Bxa7 g5 23. a4 Bg7 24. Rb6+ Kd5 25. Rb7
|
||||
Bf8 26. Rb8 Bg7 27. Rb5+ Kc6 28. Rb6+ Kd5 29. a5 f5 30. Bb8 Rc8 31. a6 Rxc3
|
||||
32. Rb5+ Kc4 33. Rb7 Bd4 34. Rc7+ Kd3 35. Rxc3+ Kxc3 36. Be5 1-0
|
||||
|
||||
[Event "Bled"]
|
||||
[Site "?"]
|
||||
[Date "1961"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Keres, Paul"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d4 dxe4 7. Qe3 Nbd7
|
||||
8. Nxe4 Nxe4 9. Qxe4 Nf6 10. Qd3 Qd5 11. c4 Qd6 12. Be2 e5 13. d5 e4 14.
|
||||
Qc2 Be7 15. dxc6 Qxc6 16. O-O O-O 17. Be3 Bc5 18. Qc3 b6 19. Rfd1 Rfd8 20.
|
||||
b4 Bxe3 21. fxe3 Qc7 22. Rd4 a5 23. a3 axb4 24. axb4 h5 25. Rad1 Rxd4 26.
|
||||
Qxd4 Qg3 27. Qxb6 Ra2 28. Bf1 h4 29. Qc5 Qf2+ 30. Kh1 g6 31. Qe5 Kg7 32. c5
|
||||
Qxe3 33. c6 Rc2 34. b5 Rc1 35. Rxc1 Qxc1 36. Kg1 e3 37. c7 e2 38. Qxe2 Qxc7
|
||||
39. Qf2 g5 40. b6 Qe5 41. b7 Nd7 42. Qd2 Nb8 43. Be2 Kf6 44. Bf3 Ke6 45.
|
||||
Bg4+ f5 46. Bd1 Kf6 47. Qd8+ Kg6 48. Qg8+ Kh6 49. Qf8+ Kg6 50. Qg8+ Kh6 51.
|
||||
Qf8+ Kg6 52. Qb4 Nc6 53. Qd2 Nd8 54. Bf3 Nxb7 55. Bxb7 Qa1+ 56. Kh2 Qe5+
|
||||
1/2-1/2
|
||||
|
||||
[Event "Bled"]
|
||||
[Site "?"]
|
||||
[Date "1961"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Nd7 5. Nf3 Ngf6 6. Nxf6+ Nxf6 7. Bc4
|
||||
Bf5 8. Qe2 e6 9. Bg5 Bg4 10. O-O-O Be7 11. h3 Bxf3 12. Qxf3 Nd5 13. Bxe7
|
||||
Qxe7 14. Kb1 Rd8 15. Qe4 b5 16. Bd3 a5 17. c3 Qd6 18. g3 b4 19. c4 Nf6 20.
|
||||
Qe5 c5 21. Qg5 h6 22. Qxc5 Qxc5 23. dxc5 Ke7 24. c6 Rd6 25. Rhe1 Rxc6 26.
|
||||
Re5 Ra8 27. Be4 Rd6 28. Bxa8 Rxd1+ 29. Kc2 Rf1 30. Rxa5 Rxf2+ 31. Kb3 Rh2
|
||||
32. c5 Kd8 33. Rb5 Rxh3 34. Rb8+ Kc7 35. Rb7+ Kc6 36. Kc4 1-0
|
||||
|
||||
[Event "Stockholm Interzonal"]
|
||||
[Site "?"]
|
||||
[Date "1962"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Barcza, Gedeon"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 dxe4 4. Nxe4 Nf6 5. Nxf6+ exf6 6. d4 Bd6 7. Bc4
|
||||
O-O 8. O-O Re8 9. Bb3 Nd7 10. Nh4 Nf8 11. Qd3 Bc7 12. Be3 Qe7 13. Nf5 Qe4
|
||||
14. Qxe4 Rxe4 15. Ng3 Re8 16. d5 cxd5 17. Bxd5 Bb6 18. Bxb6 axb6 19. a3 Ra5
|
||||
20. Rad1 Rc5 21. c3 Rc7 22. Bf3 Rd7 23. Rxd7 Nxd7 24. Nf5 Nc5 25. Nd6 Rd8
|
||||
26. Nxc8 Rxc8 27. Rd1 Kf8 28. Rd4 Rc7 29. h3 f5 30. Rb4 Nd7 31. Kf1 Ke7 32.
|
||||
Ke2 Kd8 33. Rb5 g6 34. Ke3 Kc8 35. Kd4 Kb8 36. Kd5 Rc6 37. Kd4 Re6 38. a4
|
||||
Kc7 39. a5 Rd6+ 40. Bd5 Kc8 41. axb6 f6 42. Ke3 Nxb6 43. Bg8 Kc7 44. Rc5+
|
||||
Kb8 45. Bxh7 Nd5+ 46. Kf3 Ne7 47. h4 b6 48. Rb5 Kb7 49. h5 Ka6 50. c4 gxh5
|
||||
51. Bxf5 Rd4 52. b3 Nc6 53. Ke3 Rd8 54. Be4 Na5 55. Bc2 h4 56. Rh5 Re8+ 57.
|
||||
Kd2 Rg8 58. Rxh4 b5 59. Rf4 bxc4 60. bxc4 Rxg2 61. Rxf6+ Ka7 62. Kc3 Rg4
|
||||
63. f4 Nb7 64. Kb4 1-0
|
||||
|
||||
[Event "Varna Olympiad Final"]
|
||||
[Site "?"]
|
||||
[Date "1962"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Donner, Jan H."]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Bf5 5. Ng3 Bg6 6. h4 h6 7. Nf3 Nd7 8.
|
||||
Bd3 Bxd3 9. Qxd3 e6 10. Bf4 Qa5+ 11. Bd2 Qc7 12. c4 Ngf6 13. Bc3 a5 14. O-O
|
||||
Bd6 15. Ne4 Nxe4 16. Qxe4 O-O 17. d5 Rfe8 18. dxc6 bxc6 19. Rad1 Bf8 20.
|
||||
Nd4 Ra6 21. Nf5 Nc5 22. Qe3 Na4 23. Be5 Qa7 24. Nxh6+ gxh6 25. Rd4 f5 26.
|
||||
Rfd1 Nc5 27. Rd8 Qf7 28. Rxe8 Qxe8 29. Bd4 Ne4 30. f3 e5 31. fxe4 exd4 32.
|
||||
Qg3+ Bg7 33. exf5 Qe3+ 34. Qxe3 dxe3 35. Rd8+ Kf7 36. Rd7+ Kf6 37. g4 Bf8
|
||||
38. Kg2 Bc5 39. Rh7 Ke5 40. Kf3 Kd4 41. Rxh6 Rb6 42. b3 a4 43. Re6 axb3 44.
|
||||
axb3 Kd3 0-1
|
||||
|
||||
[Event "USA Championship"]
|
||||
[Site "?"]
|
||||
[Date "1963"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Steinmeyer, Robert H."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Bf5 5. Ng3 Bg6 6. Nf3 Nf6 7. h4 h6 8.
|
||||
Bd3 Bxd3 9. Qxd3 e6 10. Bd2 Nbd7 11. O-O-O Qc7 12. c4 O-O-O 13. Bc3 Qf4+
|
||||
14. Kb1 Nc5 15. Qc2 Nce4 16. Ne5 Nxf2 17. Rdf1 1-0
|
||||
|
||||
[Event "Skopje"]
|
||||
[Site "?"]
|
||||
[Date "1967"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Panov, Vasil"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 dxe4 4. Nxe4 Nf6 5. Nxf6+ exf6 6. Bc4 Bd6 7. O-O
|
||||
O-O 8. d4 Be6 9. Bxe6 fxe6 10. Re1 Re8 11. c4 Na6 12. Bd2 Qd7 13. Bc3 Bb4
|
||||
14. Qb3 Bxc3 15. bxc3 Nc7 16. a4 b6 17. h3 Rab8 18. Re4 a6 19. Qc2 b5 20.
|
||||
axb5 axb5 21. cxb5 cxb5 22. Nd2 Ra8 23. Rae1 Qd5 24. Rh4 Qf5 25. Ne4 e5 26.
|
||||
Re3 h6 27. Rf3 Qh7 28. Nxf6+ gxf6 29. Rg3+ Kh8 30. Rg6 1-0
|
||||
|
||||
[Event "Nathania"]
|
||||
[Site "?"]
|
||||
[Date "1968"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Cagan, Shimon"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. a3 Nbd7 8.
|
||||
g4 Bd6 9. g5 Ng8 10. h4 Ne7 11. h5 Qb6 12. Bh3 O-O-O 13. a4 a5 14. O-O Rhf8
|
||||
15. Kh1 f5 16. Qg2 g6 17. h6 Kb8 18. f4 Rfe8 19. e5 Bc5 20. Qf3 Nc8 21. Bg2
|
||||
Kc7 22. Ne2 Nb8 23. c3 Kd7 24. Bd2 Na6 25. Rfb1 Bf8 26. b4 axb4 27. cxb4
|
||||
Bxb4 28. a5 Qc5 29. d4 Qf8 30. Bxb4 Nxb4 31. Qc3 Na6 32. Rxb7+ Nc7 33. Nc1
|
||||
Re7 34. a6 1-0
|
||||
|
||||
[Event "Nathania"]
|
||||
[Site "?"]
|
||||
[Date "1968"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Czerniak, Moshe"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. Bd3 Nc6 5. c3 Nf6 6. Bf4 g6 7. Nf3 Bg7 8.
|
||||
Nbd2 Nh5 9. Be3 O-O 10. O-O f5 11. Nb3 Qd6 12. Re1 f4 13. Bd2 Bg4 14. Be2
|
||||
Rae8 15. Nc1 Bxf3 16. Bxf3 e5 17. Qb3 exd4 18. Nd3 Rd8 19. c4 dxc4 20.
|
||||
Qxc4+ Kh8 21. Re6 Qb8 22. Rae1 Rc8 23. Bxc6 Rxc6 24. Rxc6 bxc6 25. Qxc6 Qc8
|
||||
26. Qxc8 Rxc8 27. Kf1 Bh6 28. Rc1 Rxc1+ 29. Bxc1 g5 30. b4 Kg8 31. b5 Kf7
|
||||
32. Ba3 Bf8 33. Ne5+ Ke6 34. Bxf8 Kxe5 35. Bc5 Nf6 36. Bxa7 Ne4 37. f3 Nd2+
|
||||
38. Ke2 Nc4 39. b6 Na5 40. b7 Nxb7 41. Kd3 h5 42. Bxd4+ Kd5 43. h3 Nd8 44.
|
||||
a4 Ne6 45. Bb6 g4 46. hxg4 hxg4 47. fxg4 1-0
|
||||
|
||||
[Event "Nathania"]
|
||||
[Site "?"]
|
||||
[Date "1968"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Yanofsky, Daniel A."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. c4 Nf6 5. Nc3 g6 6. Qb3 Bg7 7. cxd5 O-O
|
||||
8. Be2 Na6 9. Bg5 Qb6 10. Qxb6 axb6 11. a3 Rd8 12. Bxf6 Bxf6 13. Rd1 Bf5
|
||||
14. Bc4 Rac8 15. Bb3 b5 16. Nf3 b4 17. axb4 Nxb4 18. Ke2 Bc2 19. Bxc2 Nxc2
|
||||
20. Kd3 Nb4+ 21. Ke4 Rd6 22. Ne5 Bg7 23. g4 f5+ 24. gxf5 gxf5+ 25. Kf4 Rf8
|
||||
26. Rhg1 Nxd5+ 27. Nxd5 Rxd5 28. Nf3 Kh8 29. Rge1 Bf6 30. Ne5 e6 31. h4 Rc8
|
||||
32. Nf7+ Kg7 33. Ng5 Bxg5+ 34. Kxg5 Rc6 35. Re5 Rcd6 36. Rxd5 Rxd5 37. f4
|
||||
Rb5 38. Rd2 Rb3 39. d5 h6+ 40. Kh5 exd5 41. Rxd5 Rxb2 42. Rd7+ Kf6 43. Rd6+
|
||||
Kf7 44. Rxh6 Rg2 45. Rb6 Rg4 46. Rxb7+ Kf6 1/2-1/2
|
||||
|
||||
[Event "Vinkovci"]
|
||||
[Site "?"]
|
||||
[Date "1968"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Hort, Vlastimil"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. Nf3 Nf6 5. c3 Bf5 6. Bb5+ Nbd7 7. Nh4 Bg6
|
||||
8. Bf4 e6 9. Nd2 Nh5 10. Nxg6 hxg6 11. Be3 Bd6 12. g3 a6 13. Bd3 Rc8 14.
|
||||
O-O Nb6 15. a4 Rc7 16. Qb3 Nc8 17. c4 dxc4 18. Nxc4 Nf6 19. Rac1 O-O 20.
|
||||
Bd2 Nd5 21. Be4 Be7 22. Na5 Ncb6 23. Bxd5 Nxd5 24. Nxb7 Qb8 25. Rxc7 Qxc7
|
||||
26. Rc1 Qb8 27. Rc4 Rd8 28. Bc3 Rd7 29. Na5 Qxb3 30. Rc8+ Kh7 31. Nxb3 Nb6
|
||||
32. Rc6 Nxa4 33. Rxa6 Nxc3 34. bxc3 Rc7 35. Nd2 Rxc3 36. Ra7 Rd3 37. Nf1
|
||||
Bf6 38. Rxf7 Rxd4 39. Kg2 g5 40. h3 Kg6 41. Rc7 Ra4 42. Nd2 Rd4 43. Nb3 Rd6
|
||||
44. Nc5 Kf5 45. Kf3 Rb6 46. Rd7 Rc6 47. Ne4 Ra6 48. Rd3 Be7 49. Rb3 Ra3 50.
|
||||
Rxa3 Bxa3 51. g4+ Kg6 52. Ke3 Bc1+ 53. Kd4 Bf4 54. Kc5 Kf7 55. Kb6 Ke8 56.
|
||||
Kc6 Ke7 1/2-1/2
|
||||
|
||||
[Event "Palma de Mallorca"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Hubner, Robert"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d3 d5 3. Nd2 g6 4. g3 Bg7 5. Bg2 e5 6. Ngf3 Ne7 7. O-O O-O 8.
|
||||
Re1 d4 9. a4 c5 10. Nc4 Nbc6 11. c3 Be6 12. cxd4 Bxc4 13. dxc4 exd4 14. e5
|
||||
Qd7 15. h4 d3 16. Bd2 Rad8 17. Bc3 Nb4 18. Nd4 Rfe8 19. e6 fxe6 20. Nxe6
|
||||
Bxc3 21. bxc3 Nc2 22. Nxd8 Rxd8 23. Qd2 Nxa1 24. Rxa1 Kg7 25. Re1 Ng8 26.
|
||||
Bd5 Qxa4 27. Qxd3 Re8 28. Rxe8 Qxe8 29. Bxb7 Nf6 30. Qd6 Qd7 31. Qa6 Qf7
|
||||
32. Qxa7 Ne4 33. f3 Nd6 34. Qxc5 Nxb7 35. Qd4+ Kg8 36. Kf2 Qe7 37. Qd5+ Kf8
|
||||
38. h5 gxh5 39. Qxh5 Nc5 40. Qd5 Kg7 41. Qd4+ Kf7 42. Qd5+ Kg7 43. Qd4+ Kf7
|
||||
44. Qd5+ 1/2-1/2
|
||||
|
||||
[Event "Siegen Olympiad Final"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Hort, Vlastimil"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d3 d5 3. Nd2 g6 4. g3 Bg7 5. Bg2 e5 6. Ngf3 Ne7 7. O-O O-O 8.
|
||||
Re1 Nd7 9. b3 d4 10. Bb2 b5 11. c3 c5 12. Rc1 Bb7 13. cxd4 cxd4 14. Bh3 Nc6
|
||||
15. a3 Re8 16. Qe2 Rc8 17. Rc2 Ne7 18. Rec1 Rxc2 19. Rxc2 Nc6 20. Qd1 Nb6
|
||||
21. Qc1 Qf6 22. Bg2 Rc8 23. h4 Bf8 24. Bh3 Rc7 25. Nh2 Bc8 26. Bf1 Bd7 27.
|
||||
h5 Rc8 28. Be2 Nd8 29. Rxc8 Bxc8 30. Ndf3 Nc6 31. Nh4 b4 32. axb4 Nxb4 33.
|
||||
N4f3 a5 34. Qc7 Qd6 35. Qa7 Ba6 36. Ba3 Nc8 37. Qa8 Qb6 38. Bxb4 Bxb4 39.
|
||||
Qd5 Qc5 40. Qxe5 Qxe5 41. Nxe5 Nd6 42. hxg6 hxg6 43. Kf1 Bb5 44. Nhf3 Bc3
|
||||
45. Ne1 Nb7 46. Bd1 Nc5 47. f3 Kg7 48. Bc2 Kf6 49. Ng4+ Ke7 50. Nf2 Bd7 51.
|
||||
Nd1 Bb4 52. Nb2 Be6 53. Nc4 Bxc4 54. dxc4 Bxe1 55. Kxe1 g5 56. Ke2 Kd6 57.
|
||||
f4 gxf4 58. gxf4 f6 59. Kf3 Ke6 60. Ke2 Kd6 1/2-1/2
|
||||
|
||||
[Event "Siegen Olympiad Prelim"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Ibrahimoglu, Ismet"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d3 d5 3. Nd2 g6 4. Ngf3 Bg7 5. g3 Nf6 6. Bg2 O-O 7. O-O Bg4 8.
|
||||
h3 Bxf3 9. Qxf3 Nbd7 10. Qe2 dxe4 11. dxe4 Qc7 12. a4 Rad8 13. Nb3 b6 14.
|
||||
Be3 c5 15. a5 e5 16. Nd2 Ne8 17. axb6 axb6 18. Nb1 Qb7 19. Nc3 Nc7 20. Nb5
|
||||
Qc6 21. Nxc7 Qxc7 22. Qb5 Ra8 23. c3 Rxa1 24. Rxa1 Rb8 25. Ra6 Bf8 26. Bf1
|
||||
Kg7 27. Qa4 Rb7 28. Bb5 Nb8 29. Ra8 Bd6 30. Qd1 Nc6 31. Qd2 h5 32. Bh6+ Kh7
|
||||
33. Bg5 Rb8 34. Rxb8 Nxb8 35. Bf6 Nc6 36. Qd5 Na7 37. Be8 Kg8 38. Bxf7+
|
||||
Qxf7 39. Qxd6 1-0
|
||||
|
||||
[Event "USSR-World"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. Bd3 Nc6 5. c3 Nf6 6. Bf4 Bg4 7. Qb3 Na5
|
||||
8. Qa4+ Bd7 9. Qc2 e6 10. Nf3 Qb6 11. a4 Rc8 12. Nbd2 Nc6 13. Qb1 Nh5 14.
|
||||
Be3 h6 15. Ne5 Nf6 16. h3 Bd6 17. O-O Kf8 18. f4 Be8 19. Bf2 Qc7 20. Bh4
|
||||
Ng8 21. f5 Nxe5 22. dxe5 Bxe5 23. fxe6 Bf6 24. exf7 Bxf7 25. Nf3 Bxh4 26.
|
||||
Nxh4 Nf6 27. Ng6+ Bxg6 28. Bxg6 Ke7 29. Qf5 Kd8 30. Rae1 Qc5+ 31. Kh1 Rf8
|
||||
32. Qe5 Rc7 33. b4 Qc6 34. c4 dxc4 35. Bf5 Rff7 36. Rd1+ Rfd7 37. Bxd7 Rxd7
|
||||
38. Qb8+ Ke7 39. Rde1+ 1-0
|
||||
|
||||
[Event "USSR-World"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 g6 4. e5 Bg7 5. f4 h5 6. Nf3 Bg4 7. h3 Bxf3 8.
|
||||
Qxf3 e6 9. g3 Qb6 10. Qf2 Ne7 11. Bd3 Nd7 12. Ne2 O-O-O 13. c3 f6 14. b3
|
||||
Nf5 15. Rg1 c5 16. Bxf5 gxf5 17. Be3 Qa6 18. Kf1 cxd4 19. cxd4 Nb8 20. Kg2
|
||||
Nc6 21. Nc1 Rd7 22. Qd2 Qa5 23. Qxa5 Nxa5 24. Nd3 Nc6 25. Rac1 Rc7 26. Rc3
|
||||
b6 27. Rgc1 Kb7 28. Nb4 Rhc8 29. Rxc6 Rxc6 30. Rxc6 Rxc6 31. Nxc6 Kxc6 32.
|
||||
Kf3 1/2-1/2
|
||||
|
||||
[Event "Zabreb"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Marovic, Drazen"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d3 d5 3. Nd2 Nd7 4. Ngf3 Qc7 5. exd5 cxd5 6. d4 g6 7. Bd3 Bg7
|
||||
8. O-O e6 9. Re1 Ne7 10. Nf1 Nc6 11. c3 O-O 12. Bg5 e5 13. Ne3 Nb6 14. dxe5
|
||||
Nxe5 15. Bf4 f6 16. a4 Qf7 17. a5 Nbc4 18. Bxc4 dxc4 19. Bxe5 fxe5 20. Qe2
|
||||
h6 21. Nxc4 Bg4 22. Ncxe5 Bxe5 23. Nxe5 Bxe2 24. Nxf7 Rxf7 25. Rxe2 Rd8 26.
|
||||
Rae1 Rd5 27. b4 Rc7 28. Re3 Kf7 29. h4 Rd2 30. Rf3+ Kg7 31. Re6 Rf7 32.
|
||||
Rxf7+ Kxf7 33. Re5 Rd1+ 34. Kh2 b6 35. axb6 axb6 36. f3 Rd3 37. Rb5 Rxc3
|
||||
38. Rxb6 h5 39. Rb7+ Kf6 40. b5 Rb3 41. b6 Rb4 42. Kg3 Rb2 43. Rb8 Kg7 44.
|
||||
f4 Rb3+ 45. Kf2 Kf6 46. Ke2 Kg7 47. Kd2 Rg3 48. Rc8 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Stockholm"]
|
||||
[Date "1962.??.??"]
|
||||
[Round "4"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Portisch, Lajos"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 dxe4 4. Nxe4 Nd7 5. Bc4 Ngf6 6. Neg5 Nd5 7. d4 h6
|
||||
8. Ne4 N7b6 9. Bb3 Bf5 10. Ng3 Bh7 11. O-O e6 12. Ne5 Nd7 13. c4 N5f6 14.
|
||||
Bf4 Nxe5 15. Bxe5 Bd6 16. Qe2 O-O 17. Rad1 Qe7 18. Bxd6 Qxd6 19. f4 c5 20.
|
||||
Qe5 Qxe5 21. dxe5 Ne4 22. Rd7 Nxg3 23. hxg3 Be4 24. Ba4 Rad8 25. Rfd1 Rxd7
|
||||
26. Rxd7 g5 27. Bd1 Bc6 28. Rd6 Rc8 29. Kf2 Kf8 30. Bf3 Bxf3 31. gxf3 gxf4
|
||||
32. gxf4 Ke7 33. f5 exf5 34. Rxh6 Rd8 35. Ke2 Rg8 36. Kf2 Rd8 37. Ke3 Rd1
|
||||
38. b3 Re1+ 39. Kf4 Re2 40. Kxf5 Rxa2 41. f4 Re2 42. Rh3 Re1 43. Rd3 Rb1
|
||||
44. Re3 Rb2 45. e6 a6 46. exf7+ Kxf7 47. Ke5 Rd2 48. Rc3 b6 49. f5 Rd1 50.
|
||||
Rh3 b5 51. Rh7+ Kg8 52. Rb7 bxc4 53. bxc4 Rd4 54. Ke6 Re4+ 55. Kd5 Rf4 56.
|
||||
Kxc5 Rxf5+ 57. Kd6 Rf6+ 58. Ke5 Rf7 59. Rb6 Rc7 60. Kd5 Kf7 61. Rxa6 Ke7
|
||||
62. Re6+ Kd8 63. Rd6+ Ke7 64. c5 Rc8 65. c6 Rc7 66. Rh6 Kd8 67. Rh8+ Ke7
|
||||
68. Ra8 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Yugoslavia ct"]
|
||||
[Date "1959.??.??"]
|
||||
[Round "2"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Keres, Paul"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Qb6 10. b3 a5 11. a3 Be7 12. Bg2 a4 13. b4 Nbd7 14. O-O c5
|
||||
15. Ra2 O-O 16. bxc5 Bxc5 17. Qe2 e5 18. f4 Rfc8 19. h4 Rc6 20. Bh3 Qc7 21.
|
||||
fxe5 Nxe5 22. Bf4 Bd6 23. h5 Ra5 24. h6 Ng6 25. Qf3 Rh5 26. Bg4 Nxf4 27.
|
||||
Bxh5 N4xh5 28. Kg2 Ng4 29. Nd2 Ne3+ 0-1
|
||||
|
||||
|
9
pgn-extract/test/infiles/fools-mate.pgn
Normal file
9
pgn-extract/test/infiles/fools-mate.pgn
Normal file
@@ -0,0 +1,9 @@
|
||||
[Event "?"]
|
||||
[Site "?"]
|
||||
[Date "????.??.??"]
|
||||
[Round "?"]
|
||||
[White "?"]
|
||||
[Black "?"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. f3 e5 2. g4 Qh4# 0-1
|
1
pgn-extract/test/infiles/fools-mate.txt
Normal file
1
pgn-extract/test/infiles/fools-mate.txt
Normal file
@@ -0,0 +1 @@
|
||||
f3 e5 g4 Qh4 0-1
|
124
pgn-extract/test/infiles/najdorf.pgn
Normal file
124
pgn-extract/test/infiles/najdorf.pgn
Normal file
@@ -0,0 +1,124 @@
|
||||
[Event "Kopavogur International Tournament"]
|
||||
[Site "Kopavogur ICE"]
|
||||
[Date "1994.04.15"]
|
||||
[Round "7"]
|
||||
[White "Arnason Jon L"]
|
||||
[Black "Kristensen Bjarke"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c5 2. Nf3 d6 3. d4 cxd4 4. Nxd4 Nf6 5. Nc3 a6 6. a4 Nc6 7. Bc4 Bd7 8.
|
||||
O-O Rc8 9. Kh1 g6 10. f4 Bg7 11. Nf3 O-O 12. Ba2 b5 13. axb5 axb5 14. Qe1
|
||||
Nb4 15. Bb3 Nxc2 16. Bxc2 b4 17. e5 dxe5 18. fxe5 Ng4 19. Bd2 bxc3 20. Bxc3
|
||||
Bb5 21. Rg1 Bc6 22. Bd1 Qc7 23. Ra5 Rcd8 24. Qg3 Ne3 25. Ba4 Bb7 26. Qf2
|
||||
Rd3 27. Rb1 Ba8 28. Qe2 Ng4 29. Rf1 Re3 30. Qd2 Qc4 31. Qd1 Rd3 32. Qa1
|
||||
Rxf3 33. Rxf3 Bxf3 34. gxf3 Qf4 35. Qg1 Qxf3+ 36. Qg2 Nf2+ 37. Kg1 Nh3+ 38.
|
||||
Kh1 Qe3 39. Bd2 Nf2+ 40. Kg1 Qxd2 41. Qxf2 Qc1+ 42. Qf1 Qe3+ 43. Qf2 Qg5+
|
||||
44. Qg3 Qc1+ 45. Kg2 Rd8 46. Qf3 Qg5+ 47. Qg3 Qf5 0-1
|
||||
|
||||
[Event "Kopavogur International Tournament"]
|
||||
[Site "Kopavogur ICE"]
|
||||
[Date "1994.04.16"]
|
||||
[Round "8"]
|
||||
[White "Bjornsson, Tomas"]
|
||||
[Black "Gretarsson, Andri A"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c5 2. Nf3 d6 3. d4 cxd4 4. Nxd4 Nf6 5. Nc3 a6 6. Bg5 Nbd7 7. Bc4 b5
|
||||
8. Bd5 Nxd5 9. Nxd5 Bb7 10. Nf5 Nf6 11. Bxf6 gxf6 12. Qd4 Rg8 13. g3 Rg6
|
||||
14. Nh4 Rh6 15. Nf5 Rg6 16. Nh4 Rh6 17. Nf5 Rg6 18. Nh4 1/2-1/2
|
||||
|
||||
[Event "Kopavogur International Tournament"]
|
||||
[Site "Kopavogur ICE"]
|
||||
[Date "1994.04.16"]
|
||||
[Round "8"]
|
||||
[White "Vidarsson, Jon G"]
|
||||
[Black "Gislason, Gudmundur"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c5 2. Nf3 d6 3. d4 cxd4 4. Nxd4 Nf6 5. Nc3 a6 6. Be3 e6 7. f3 b5 8.
|
||||
g4 h6 9. Rg1 b4 10. Nce2 e5 11. Nb3 d5 12. Ng3 Bb7 13. h4 d4 14. Bf2 Qc7
|
||||
15. Bd3 Nc6 16. g5 hxg5 17. hxg5 Nd7 18. g6 f6 19. Qe2 Nd8 20. Nf5 Ne6 21.
|
||||
Bc4 Nf4 22. Bf7+ Kd8 23. Qd2 Rh2 24. O-O-O d3 25. Bb6 Qxb6 26. Qxh2 Rc8 27.
|
||||
Rd2 a5 28. Kb1 a4 29. Nc1 dxc2+ 30. Rxc2 Rxc2 31. Kxc2 Nc5 32. Rd1+ Kc7 33.
|
||||
Qd2 Nfe6 34. Kb1 Kb8 35. Nd3 b3 36. Nxc5 Bxc5 37. Ka1 1-0
|
||||
|
||||
[Event "Kopavogur International Tournament"]
|
||||
[Site "Kopavogur ICE"]
|
||||
[Date "1994.04.16"]
|
||||
[Round "8"]
|
||||
[White "Stefansson, Hannes"]
|
||||
[Black "Olafsson, Helgi"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c5 2. Nf3 d6 3. d4 cxd4 4. Nxd4 Nf6 5. Nc3 a6 6. Be3 e6 7. f3 Nbd7 8.
|
||||
g4 h6 9. Qd2 b5 10. O-O-O b4 11. Nce2 d5 12. Nf4 dxe4 13. Ndxe6 fxe6 14.
|
||||
Bc4 Qc7 15. Bxe6 Ne5 16. Bb3 Bd7 17. fxe4 Bc5 18. Bxc5 Qxc5 19. Nd3 Nxd3+
|
||||
20. Qxd3 O-O-O 21. e5 Bb5 22. Qf5+ Nd7 23. Rd5 Qe3+ 24. Kb1 Rhf8 25. Qg6
|
||||
Nc5 26. Qxg7 Nxb3 27. axb3 Bc6 28. Rxd8+ Rxd8 29. Rf1 Be4 30. Qf6 Qe2 31.
|
||||
Qe6+ Rd7 32. Rc1 Kc7 33. h4 a5 34. g5 hxg5 35. hxg5 Rd1 36. Qe7+ Kb6 37.
|
||||
Qe6+ Kc7 38. Qe7+ Kb6 39. Qe6+ Bc6 40. Rxd1 Qxd1+ 41. Ka2 Qxc2 42. Qd6 Qc5
|
||||
43. Qb8+ Bb7 44. g6 a4 45. Qd8+ Ka7 46. Qd7 Kb6 47. Qd8+ Ka6 48. Qd3+ Ka5
|
||||
49. Qd8+ Ka6 50. Qd3+ Ka7 51. Qd7 Kb6 1/2-1/2
|
||||
|
||||
[Event "Kopavogur International Tournament"]
|
||||
[Site "Kopavogur ICE"]
|
||||
[Date "1994.04.15"]
|
||||
[Round "7"]
|
||||
[White "Arnason Jon L"]
|
||||
[Black "Kristensen Bjarke"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c5 2. Nf3 d6 3. d4 cxd4 4. Nxd4 Nf6 5. Nc3 a6 6. a4 Nc6 7. Bc4 Bd7 8.
|
||||
O-O Rc8 9. Kh1 g6 10. f4 Bg7 11. Nf3 O-O 12. Ba2 b5 13. axb5 axb5 14. Qe1
|
||||
Nb4 15. Bb3 Nxc2 16. Bxc2 b4 17. e5 dxe5 18. fxe5 Ng4 19. Bd2 bxc3 20. Bxc3
|
||||
Bb5 21. Rg1 Bc6 22. Bd1 Qc7 23. Ra5 Rcd8 24. Qg3 Ne3 25. Ba4 Bb7 26. Qf2
|
||||
Rd3 27. Rb1 Ba8 28. Qe2 Ng4 29. Rf1 Re3 30. Qd2 Qc4 31. Qd1 Rd3 32. Qa1
|
||||
Rxf3 33. Rxf3 Bxf3 34. gxf3 Qf4 35. Qg1 Qxf3+ 36. Qg2 Nf2+ 37. Kg1 Nh3+ 38.
|
||||
Kh1 Qe3 39. Bd2 Nf2+ 40. Kg1 Qxd2 41. Qxf2 Qc1+ 42. Qf1 Qe3+ 43. Qf2 Qg5+
|
||||
44. Qg3 Qc1+ 45. Kg2 Rd8 46. Qf3 Qg5+ 47. Qg3 Qf5 0-1
|
||||
|
||||
[Event "Kopavogur International Tournament"]
|
||||
[Site "Kopavogur ICE"]
|
||||
[Date "1994.04.16"]
|
||||
[Round "8"]
|
||||
[White "Bjornsson, Tomas"]
|
||||
[Black "Gretarsson, Andri A"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c5 2. Nf3 d6 3. d4 cxd4 4. Nxd4 Nf6 5. Nc3 a6 6. Bg5 Nbd7 7. Bc4 b5
|
||||
8. Bd5 Nxd5 9. Nxd5 Bb7 10. Nf5 Nf6 11. Bxf6 gxf6 12. Qd4 Rg8 13. g3 Rg6
|
||||
14. Nh4 Rh6 15. Nf5 Rg6 16. Nh4 Rh6 17. Nf5 Rg6 18. Nh4 1/2-1/2
|
||||
|
||||
[Event "Kopavogur International Tournament"]
|
||||
[Site "Kopavogur ICE"]
|
||||
[Date "1994.04.16"]
|
||||
[Round "8"]
|
||||
[White "Vidarsson, Jon G"]
|
||||
[Black "Gislason, Gudmundur"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c5 2. Nf3 d6 3. d4 cxd4 4. Nxd4 Nf6 5. Nc3 a6 6. Be3 e6 7. f3 b5 8.
|
||||
g4 h6 9. Rg1 b4 10. Nce2 e5 11. Nb3 d5 12. Ng3 Bb7 13. h4 d4 14. Bf2 Qc7
|
||||
15. Bd3 Nc6 16. g5 hxg5 17. hxg5 Nd7 18. g6 f6 19. Qe2 Nd8 20. Nf5 Ne6 21.
|
||||
Bc4 Nf4 22. Bf7+ Kd8 23. Qd2 Rh2 24. O-O-O d3 25. Bb6 Qxb6 26. Qxh2 Rc8 27.
|
||||
Rd2 a5 28. Kb1 a4 29. Nc1 dxc2+ 30. Rxc2 Rxc2 31. Kxc2 Nc5 32. Rd1+ Kc7 33.
|
||||
Qd2 Nfe6 34. Kb1 Kb8 35. Nd3 b3 36. Nxc5 Bxc5 37. Ka1 1-0
|
||||
|
||||
[Event "Kopavogur International Tournament"]
|
||||
[Site "Kopavogur ICE"]
|
||||
[Date "1994.04.16"]
|
||||
[Round "8"]
|
||||
[White "Stefansson, Hannes"]
|
||||
[Black "Olafsson, Helgi"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c5 2. Nf3 d6 3. d4 cxd4 4. Nxd4 Nf6 5. Nc3 a6 6. Be3 e6 7. f3 Nbd7 8.
|
||||
g4 h6 9. Qd2 b5 10. O-O-O b4 11. Nce2 d5 12. Nf4 dxe4 13. Ndxe6 fxe6 14.
|
||||
Bc4 Qc7 15. Bxe6 Ne5 16. Bb3 Bd7 17. fxe4 Bc5 18. Bxc5 Qxc5 19. Nd3 Nxd3+
|
||||
20. Qxd3 O-O-O 21. e5 Bb5 22. Qf5+ Nd7 23. Rd5 Qe3+ 24. Kb1 Rhf8 25. Qg6
|
||||
Nc5 26. Qxg7 Nxb3 27. axb3 Bc6 28. Rxd8+ Rxd8 29. Rf1 Be4 30. Qf6 Qe2 31.
|
||||
Qe6+ Rd7 32. Rc1 Kc7 33. h4 a5 34. g5 hxg5 35. hxg5 Rd1 36. Qe7+ Kb6 37.
|
||||
Qe6+ Kc7 38. Qe7+ Kb6 39. Qe6+ Bc6 40. Rxd1 Qxd1+ 41. Ka2 Qxc2 42. Qd6 Qc5
|
||||
43. Qb8+ Bb7 44. g6 a4 45. Qd8+ Ka7 46. Qd7 Kb6 47. Qd8+ Ka6 48. Qd3+ Ka5
|
||||
49. Qd8+ Ka6 50. Qd3+ Ka7 51. Qd7 Kb6 1/2-1/2
|
||||
|
2
pgn-extract/test/infiles/nested-comment.pgn
Normal file
2
pgn-extract/test/infiles/nested-comment.pgn
Normal file
@@ -0,0 +1,2 @@
|
||||
e4 { This game contains { a nested comment } which should be
|
||||
handled ok with the --nestedcomment option. } *
|
548
pgn-extract/test/infiles/petrosian.pgn
Normal file
548
pgn-extract/test/infiles/petrosian.pgn
Normal file
@@ -0,0 +1,548 @@
|
||||
[Event "?"]
|
||||
[Site "Sarajevo"]
|
||||
[Date "1972"]
|
||||
[Round "?"]
|
||||
[White "Petrosian, Tigran V."]
|
||||
[Black "Hort"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. Nf3 c5 2. b3 d5 3. e3 Nf6 4. Bb2 e6 5. c4 Nc6 6. cxd5 exd5 7. Be2 Be7 8.
|
||||
O-O O-O 9. d4 Bg4 10. dxc5 Bxc5 11. Nc3 Rc8 12. Rc1 Be7 13. Nd4 Bxe2 14.
|
||||
Ncxe2 Qd7 15. Nf4 Rfd8 16. Qd3 Ne4 17. Nxc6 bxc6 18. Rc2 Bf8 19. Rfc1 Qb7
|
||||
20. Qe2 Re8 21. Qg4 g6 22. Qd1 Bd6 23. Nxd5 Rcd8 24. Rxc6 Qb8 25. f4 Re6
|
||||
26. Qd4 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Buenos Aires m"]
|
||||
[Date "1971"]
|
||||
[Round "6"]
|
||||
[White "Petrosian, Tigran V."]
|
||||
[Black "Fischer, Robert J."]
|
||||
[Result "0-1"]
|
||||
|
||||
1. Nf3 c5 2. b3 d5 3. Bb2 f6 4. c4 d4 5. d3 e5 6. e3 Ne7 7. Be2 Nec6 8.
|
||||
Nbd2 Be7 9. O-O O-O 10. e4 a6 11. Ne1 b5 12. Bg4 Bxg4 13. Qxg4 Qc8 14. Qe2
|
||||
Nd7 15. Nc2 Rb8 16. Rfc1 Qe8 17. Ba3 Bd6 18. Ne1 g6 19. cxb5 axb5 20. Bb2
|
||||
Nb6 21. Nef3 Ra8 22. a3 Na5 23. Qd1 Qf7 24. a4 bxa4 25. bxa4 c4 26. dxc4
|
||||
Nbxc4 27. Nxc4 Nxc4 28. Qe2 Nxb2 29. Qxb2 Rfb8 30. Qa2 Bb4 31. Qxf7+ Kxf7
|
||||
32. Rc7+ Ke6 33. g4 Bc3 34. Ra2 Rc8 35. Rxc8 Rxc8 36. a5 Ra8 37. a6 Ra7 38.
|
||||
Kf1 g5 39. Ke2 Kd6 40. Kd3 Kc5 41. Ng1 Kb5 42. Ne2 Ba5 43. Rb2+ Kxa6 44.
|
||||
Rb1 Rc7 45. Rb2 Be1 46. f3 Ka5 47. Rc2 Rb7 48. Ra2+ Kb5 49. Rb2+ Bb4 50.
|
||||
Ra2 Rc7 51. Ra1 Rc8 52. Ra7 Ba5 53. Rd7 Bb6 54. Rd5+ Bc5 55. Nc1 Ka4 56.
|
||||
Rd7 Bb4 57. Ne2 Kb3 58. Rb7 Ra8 59. Rxh7 Ra1 60. Nxd4+ exd4 61. Kxd4 Rd1+
|
||||
62. Ke3 Bc5+ 63. Ke2 Rh1 64. h4 Kc4 65. h5 Rh2+ 66. Ke1 Kd3 0-1
|
||||
|
||||
[Event "?"]
|
||||
[Site "USSR 26/2"]
|
||||
[Date "1978"]
|
||||
[Round "?"]
|
||||
[White "Petrosian, Tigran V."]
|
||||
[Black "Balashov,Y"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. b3 e5 2. Bb2 Nc6 3. c4 Nf6 4. e3 d5 5. cxd5 Nxd5 6. a3 Bd6 7. Qc2 O-O 8.
|
||||
Nf3 Qe7 9. Bd3 Kh8 10. Be4 Nb6 11. Bxc6 bxc6 12. d3 Bd7 13. Nbd2 f5 14. e4
|
||||
fxe4 15. dxe4 Rf4 16. Qc3 Re8 17. O-O c5 18. Kh1 Bc6 19. Rae1 Nd7 20. Ng1
|
||||
Nf6 21. f3 Nh5 22. g4 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Tilburg 32/3"]
|
||||
[Date "1981"]
|
||||
[Round "?"]
|
||||
[White "Petrosian, Tigran V."]
|
||||
[Black "Sosonko,G"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. c4 e5 2. b3 Nf6 3. Bb2 Nc6 4. e3 Be7 5. a3 O-O 6. Qc2 d5 7. cxd5 Nxd5 8.
|
||||
Nf3 Bf6 9. d3 g6 10. Nbd2 Bg7 11. Rc1 g5 12. Nc4 Qe7 13. b4 a6 14. Nfd2 f5
|
||||
15. Be2 g4 16. Nb3 Kh8 17. Nca5 Nxa5 18. Nxa5 Qf7 19. O-O c6 20. Nc4 Qe7
|
||||
21. Rfe1 Bd7 22. Bf1 Nc7 23. Nb6 Rad8 24. Qc5 Qxc5 25. Rxc5 Ne6 26. Rxe5
|
||||
Bxe5 27. Bxe5+ Kg8 28. d4 Be8 29. Nc4 b5 30. Nd6 Bd7 31. Rc1 Ng5 32. Nb7
|
||||
Rc8 33. Bd3 Ra8 34. Kf1 Be6 35. Bf4 Nf7 36. Ke2 Bd5 37. Bxf5 Ne5 38. Bxe5
|
||||
Rxf5 39. Nd6 Rff8 40. e4 Bc4+ 41. Nxc4 bxc4 42. Rxc4 a5 43. Bd6 Rfe8 44. e5
|
||||
axb4 45. Bxb4 1-0
|
||||
|
||||
[Event "Tilburg Grandmaster Tournament"]
|
||||
[Site "Tilburg, NED"]
|
||||
[Date "1982.09.??"]
|
||||
[Round "2"]
|
||||
[White "Karpov, Anatoly"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nd2 dxe4 4. Nxe4 Nd7 5. Bc4 Ngf6 6. Ng5 e6 7. Qe2 Nb6
|
||||
8. Bb3 a5 9. a3 a4 10. Ba2 h6 11. N5f3 c5 12. c3 Bd7 13. Ne5 cxd4 14. cxd4
|
||||
Be7 15. Ngf3 O-O 16. O-O Be8 17. Bd2 Nbd5 18. Rfc1 Qb6 19. Bc4 Bc6 20. Re1
|
||||
Nc7 21. Nxc6 bxc6 22. Bf4 Ncd5 23. Be5 Rfd8 24. Rad1 Bd6 25. Rd2 Bxe5 26.
|
||||
dxe5 Nd7 27. g3 Nf8 28. Red1 Rd7 29. Qe4 Rb7 30. Rc2 Rab8 31. Rdd2 Ne7 32.
|
||||
Kg2 Qa5 33. h4 Rd7 34. Be2 Rd5 35. Rd4 Rxd4 36. Qxd4 Nd5 37. Rxc6 Qa8 38.
|
||||
Rc4 Qb7 39. Rc2 Nb6 40. Bb5 Ng6 41. Qd6 Qa8 42. Bc6 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow"]
|
||||
[Date "1973.??.??"]
|
||||
[Round "15"]
|
||||
[White "Tal,M"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Nd7 5. Bc4 Ngf6 6. Ng5 e6 7. Qe2 Nb6
|
||||
8. Bb3 a5 9. a4 h6 10. N5f3 c5 11. Bf4 Bd6 12. Be5 O-O 13. O-O-O c4 14.
|
||||
Bxc4 Nxa4 15. Nh3 Nb6 16. g4 a4 17. g5 hxg5 18. Nhxg5 a3 19. b3 Bb4 20.
|
||||
Rdg1 a2 21. Kb2 Nxc4+ 22. Qxc4 Nd5 23. Ne4 f6 24. Bf4 Ba3+ 25. Ka1 Nxf4 26.
|
||||
h4 Rf7 27. Rg4 Qa5 0-1
|
||||
|
||||
[Event "?"]
|
||||
[Site "Tilburg"]
|
||||
[Date "1982.??.??"]
|
||||
[Round "7"]
|
||||
[White "Nunn,John"]
|
||||
[Black "Petrosian,Tigran"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. c4 d5 3. exd5 cxd5 4. cxd5 Nf6 5. Nc3 Nxd5 6. Nf3 Nxc3 7. bxc3
|
||||
g6 8. d4 Bg7 9. Bd3 Nc6 10. O-O O-O 11. Re1 Bg4 12. Be4 Rc8 13. Bg5 Re8 14.
|
||||
Rb1 Qd7 15. h3 Bxf3 16. Bxf3 b6 17. Bg4 f5 18. Be2 h6 19. Bc1 Kh7 20. d5
|
||||
1-0
|
||||
|
||||
[Event "Bled"]
|
||||
[Site "?"]
|
||||
[Date "1961"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Nd7 5. Nf3 Ngf6 6. Nxf6+ Nxf6 7. Bc4
|
||||
Bf5 8. Qe2 e6 9. Bg5 Bg4 10. O-O-O Be7 11. h3 Bxf3 12. Qxf3 Nd5 13. Bxe7
|
||||
Qxe7 14. Kb1 Rd8 15. Qe4 b5 16. Bd3 a5 17. c3 Qd6 18. g3 b4 19. c4 Nf6 20.
|
||||
Qe5 c5 21. Qg5 h6 22. Qxc5 Qxc5 23. dxc5 Ke7 24. c6 Rd6 25. Rhe1 Rxc6 26.
|
||||
Re5 Ra8 27. Be4 Rd6 28. Bxa8 Rxd1+ 29. Kc2 Rf1 30. Rxa5 Rxf2+ 31. Kb3 Rh2
|
||||
32. c5 Kd8 33. Rb5 Rxh3 34. Rb8+ Kc7 35. Rb7+ Kc6 36. Kc4 1-0
|
||||
|
||||
[Event "USSR-World"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. Bd3 Nc6 5. c3 Nf6 6. Bf4 Bg4 7. Qb3 Na5
|
||||
8. Qa4+ Bd7 9. Qc2 e6 10. Nf3 Qb6 11. a4 Rc8 12. Nbd2 Nc6 13. Qb1 Nh5 14.
|
||||
Be3 h6 15. Ne5 Nf6 16. h3 Bd6 17. O-O Kf8 18. f4 Be8 19. Bf2 Qc7 20. Bh4
|
||||
Ng8 21. f5 Nxe5 22. dxe5 Bxe5 23. fxe6 Bf6 24. exf7 Bxf7 25. Nf3 Bxh4 26.
|
||||
Nxh4 Nf6 27. Ng6+ Bxg6 28. Bxg6 Ke7 29. Qf5 Kd8 30. Rae1 Qc5+ 31. Kh1 Rf8
|
||||
32. Qe5 Rc7 33. b4 Qc6 34. c4 dxc4 35. Bf5 Rff7 36. Rd1+ Rfd7 37. Bxd7 Rxd7
|
||||
38. Qb8+ Ke7 39. Rde1+ 1-0
|
||||
|
||||
[Event "USSR-World"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 g6 4. e5 Bg7 5. f4 h5 6. Nf3 Bg4 7. h3 Bxf3 8.
|
||||
Qxf3 e6 9. g3 Qb6 10. Qf2 Ne7 11. Bd3 Nd7 12. Ne2 O-O-O 13. c3 f6 14. b3
|
||||
Nf5 15. Rg1 c5 16. Bxf5 gxf5 17. Be3 Qa6 18. Kf1 cxd4 19. cxd4 Nb8 20. Kg2
|
||||
Nc6 21. Nc1 Rd7 22. Qd2 Qa5 23. Qxa5 Nxa5 24. Nd3 Nc6 25. Rac1 Rc7 26. Rc3
|
||||
b6 27. Rgc1 Kb7 28. Nb4 Rhc8 29. Rxc6 Rxc6 30. Rxc6 Rxc6 31. Nxc6 Kxc6 32.
|
||||
Kf3 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Bled"]
|
||||
[Date "1961.??.??"]
|
||||
[Round "17"]
|
||||
[White "Keres, Paul"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Bf5 5. Ng3 Bg6 6. N1e2 e6 7. h4 h6 8.
|
||||
Nf4 Bh7 9. c3 Nf6 10. Bd3 Bxd3 11. Nxd3 Bd6 12. Qf3 Nbd7 13. Bf4 Bxf4 14.
|
||||
Qxf4 Qb8 15. Qf3 Qd6 16. O-O-O Qd5 17. Qxd5 cxd5 18. f4 Ne4 19. Nxe4 dxe4
|
||||
20. Ne5 Rd8 21. h5 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Piatgorsky Cup"]
|
||||
[Date "1963.??.??"]
|
||||
[Round "1"]
|
||||
[White "Keres, Paul"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Bf5 5. Ng3 Bg6 6. Bc4 e6 7. N1e2 Nf6
|
||||
8. Nf4 Bd6 9. Bb3 Nbd7 10. Qf3 Qc7 11. h4 O-O-O 12. h5 Bf5 13. Nxf5 Qa5+
|
||||
14. c3 Qxf5 15. Qd3 Qxd3 16. Nxd3 h6 17. Rh4 Rhe8 18. Be3 Nd5 19. O-O-O
|
||||
Nxe3 20. fxe3 Nf6 21. Rf1 Re7 22. Nf2 Bg3 23. Rh3 Bd6 24. Bc2 e5 25. Nd3
|
||||
exd4 26. exd4 Re2 27. g4 Rde8 28. Bd1 R2e3 29. Rxe3 Rxe3 30. Rf3 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow-Wch"]
|
||||
[Date "1966.??.??"]
|
||||
[Round "1"]
|
||||
[White "Spassky, Boris"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Bf5 5. Ng3 Bg6 6. h4 h6 7. Nf3 Nd7 8.
|
||||
Bd3 Bxd3 9. Qxd3 Qc7 10. Bd2 e6 11. O-O-O O-O-O 12. c4 Ngf6 13. Kb1 c5 14.
|
||||
Bc3 cxd4 15. Nxd4 a6 16. Nf3 Bc5 17. Qe2 Bd6 18. Ne4 Be7 19. Nxf6 Bxf6 20.
|
||||
Bxf6 Nxf6 21. Ne5 Rxd1+ 22. Rxd1 Rd8 23. Rxd8+ Kxd8 24. Qd3+ Ke7 25. Qd4 h5
|
||||
26. a3 Nd7 27. Nxd7 Qxd7 28. Qc5+ Qd6 29. Qg5+ Ke8 30. Qe3 Qc6 31. Qg3 g6
|
||||
32. b3 Qe4+ 33. Kb2 e5 34. Qe3 Qxg2 35. Qxe5+ Kf8 36. Qh8+ Ke7 37. Qe5+
|
||||
1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow-Wch"]
|
||||
[Date "1966.??.??"]
|
||||
[Round "3"]
|
||||
[White "Spassky, Boris"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. c4 Nf6 5. Nc3 e6 6. Nf3 Be7 7. cxd5 Nxd5
|
||||
8. Bc4 Nf6 9. O-O O-O 10. Qe2 Nc6 11. Be3 Na5 12. Bd3 b6 13. Bg5 Bb7 14.
|
||||
Rad1 Rc8 15. Rfe1 h6 16. Bc1 Bb4 17. Bd2 Bxc3 18. bxc3 Qd5 19. Qf1 Qxa2 20.
|
||||
Ne5 Nb3 21. Re2 Nxd2 22. Rexd2 Qd5 23. c4 Qd6 24. Qe2 Rfd8 25. h3 Nd7 26.
|
||||
Ng4 h5 27. Ne3 g6 28. Ra2 Ra8 29. Qc2 Kg7 30. Be4 Bxe4 31. Qxe4 Nf6 32. Qh4
|
||||
Rd7 33. Rad2 Rad8 34. Rd3 a6 35. Qg5 Ne4 36. Qh4 Nf6 37. Rb3 Qc7 38. d5 Qe5
|
||||
39. Rxb6 exd5 40. Nxd5 Nxd5 41. cxd5 Rxd5 42. Qxd8 Rxd8 43. Rxd8 Qe1+
|
||||
1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow-Wch"]
|
||||
[Date "1966.??.??"]
|
||||
[Round "5"]
|
||||
[White "Spassky, Boris"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. c4 Nf6 5. Nc3 g6 6. Qb3 Bg7 7. cxd5 O-O
|
||||
8. g3 Na6 9. Bg2 Qb6 10. Qxb6 axb6 11. Nge2 Nb4 12. O-O Rd8 13. d6 Rxd6 14.
|
||||
Bf4 Rd7 15. Rfd1 Nbd5 16. Be5 Bh6 17. a3 e6 18. Nxd5 Nxd5 19. Rd3 Bg5 20.
|
||||
Bxd5 exd5 21. h4 Bd8 22. Rc1 Re7 23. Nf4 Be6 24. Rdc3 Bd7 25. Nxd5 Re6 26.
|
||||
Bc7 Kg7 27. Bxd8 Rxd8 28. Ne3 b5 29. d5 Rb6 30. Nc2 h6 31. Nb4 g5 32. hxg5
|
||||
hxg5 33. Kg2 Rf6 34. Re3 Rh8 35. Nd3 Rd6 36. Ne5 Bh3+ 37. Kf3 Rxd5 38. Rc7
|
||||
Be6 39. Rxb7 Rc5 40. Ra7 Bd5+ 41. Kg4 Rc2 42. Kxg5 Rxf2 43. Nd3 Rf3 44.
|
||||
Rae7 Rxe3 45. Rxe3 f6+ 46. Kf4 Kf7 47. Nb4 Bc4 48. Rc3 Rh2 49. b3 Be6 50.
|
||||
Nd3 Ra2 51. Rc7+ Kg6 52. Nc5 Bf7 53. Rb7 Rxa3 54. Rxb5 Ra1 55. Ne4 Rf1+ 56.
|
||||
Ke3 Re1+ 57. Kf3 Rf1+ 58. Ke2 Rb1 59. Nd2 Rg1 60. Kf2 Rc1 61. b4 Rc2 62.
|
||||
Ke3 Rc3+ 63. Kf4 Rd3 64. Nf3 Bd5 65. Nh4+ Kf7 66. Rb8 Rd4+ 67. Ke3 Re4+ 68.
|
||||
Kf2 Ke7 69. Ng6+ Kd7 70. Nf4 Bc6 71. Nd3 Kc7 72. Rf8 Bb5 73. Nf4 Kd7 74.
|
||||
Rf7+ Ke8 75. Rb7 Rxb4 76. Nd5 Rb2+ 77. Ke3 Rb3+ 78. Kf4 Bc4 79. Nxf6+ Kf8
|
||||
1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow-Wch"]
|
||||
[Date "1966.??.??"]
|
||||
[Round "9"]
|
||||
[White "Spassky, Boris"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. c4 Nf6 5. Nc3 e6 6. Nf3 Be7 7. cxd5 Nxd5
|
||||
8. Bd3 Nc6 9. O-O O-O 10. Re1 Bf6 11. Be4 Nce7 12. Qc2 g6 13. Bh6 Bg7 14.
|
||||
Bg5 f6 15. Bd2 Bd7 16. Qb3 Bc6 17. Bxd5 exd5 18. Ne4 Rf7 19. Nc5 Nf5 20. h3
|
||||
Bf8 21. Ne6 Qd7 22. Nxf8 Rfxf8 23. Bb4 Rfe8 24. Rxe8+ Rxe8 25. Re1 Rxe1+
|
||||
26. Bxe1 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow-Wch"]
|
||||
[Date "1966.??.??"]
|
||||
[Round "13"]
|
||||
[White "Spassky, Boris"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Bf5 5. Ng3 Bg6 6. h4 h6 7. Nf3 Nd7 8.
|
||||
h5 Bh7 9. Bd3 Bxd3 10. Qxd3 Qc7 11. Bd2 e6 12. Qe2 Ngf6 13. O-O-O O-O-O 14.
|
||||
Ne5 Nxe5 15. dxe5 Nd7 16. f4 Be7 17. Ne4 Nc5 18. Nc3 f6 19. exf6 Bxf6 20.
|
||||
Qc4 Qb6 21. b4 Na6 22. Ne4 Nc7 23. Rhe1 Rd4 24. Qb3 Qb5 25. c3 Rxe4 26.
|
||||
Rxe4 Qxh5 27. Qc4 Qf5 28. Qe2 h5 29. Be1 Re8 30. g3 a5 31. bxa5 Qxa5 32.
|
||||
Qc2 Qf5 33. Ra4 g5 34. fxg5 Bxg5+ 35. Kb1 Qxc2+ 36. Kxc2 e5 37. Re4 Nd5 38.
|
||||
Bf2 Nf6 39. Ra4 Kc7 40. Bc5 Nd5 41. Re4 b6 42. Bg1 Bd8 43. Rf1 Nf6 44. Re2
|
||||
c5 45. Rf5 Kd6 46. a4 Kd5 47. Kd3 Ng4 48. Rb2 Rh8 49. a5 c4+ 50. Ke2 Ke4
|
||||
51. Rf7 bxa5 52. Rb8 a4 53. Rc8 Bf6 54. Rxc4+ Kf5 55. Ra7 a3 56. Rxa3 Rb8
|
||||
57. Rb4 Rc8 58. c4 Be7 59. c5 e4 60. Ra7 Bf6 61. Rh7 Kg6 62. Rd7 Kf5 63.
|
||||
Rd5+ Be5 64. Rb6 e3 65. Kf3 Nf6 66. Rd3 Rxc5 67. Bxe3 Rc2 68. Rd8 Rc3 69.
|
||||
Ke2 Rc2+ 70. Kd1 Rc3 71. Bf2 Ne4 72. Rf8+ Kg5 73. Rb5 Rd3+ 74. Ke2 Rd5 75.
|
||||
Rxd5 Nc3+ 76. Kf3 Nxd5 77. Ra8 Kf5 78. Ra5 Ke6 79. Be1 Nf6 80. Rb5 Nd5 81.
|
||||
Bd2 Bg7 82. Bc1 Be5 83. Bb2 Bc7 84. Rc5 Bd6 85. Rc1 Ne7 86. Re1+ Kf5 87.
|
||||
Ra1 Nc6 88. Ra6 Be5 89. Rxc6 Bxb2 90. Rc5+ Kg6 91. Kf4 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "URS"]
|
||||
[Date "1966.??.??"]
|
||||
[Round "?"]
|
||||
[White "Tal, Mikhail N."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. c4 Nf6 5. Nc3 e6 6. Nf3 Be7 7. cxd5 Nxd5
|
||||
8. Bc4 O-O 9. O-O Nc6 10. Re1 Bf6 11. Ne4 b6 12. a3 Bb7 13. Qd3 Rc8 14.
|
||||
Nfg5 Bxg5 15. Bxg5 f6 16. Bd2 Qd7 17. Rad1 Nce7 18. Ba2 Rfe8 19. Bb1 Ng6
|
||||
20. Qg3 f5 21. Qd6 Rcd8 22. Qxd7 Rxd7 23. Ng5 Rde7 24. Ba2 h6 25. Nf3 Rc7
|
||||
26. Rc1 Rxc1 27. Rxc1 Rc8 28. Rxc8+ Bxc8 29. h4 Bb7 1/2-1/2
|
||||
|
||||
[Event "Moskva tt"]
|
||||
[Site "?"]
|
||||
[Date "1961.??.??"]
|
||||
[Round "?"]
|
||||
[White "Tal, Mikhail N."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Bf5 5. Ng3 Bg6 6. Nf3 Nd7 7. Bc4 e6
|
||||
8. O-O Ngf6 9. Ng5 h6 10. Nh3 Bd6 11. Nf4 Bxf4 12. Bxf4 Nd5 13. Bc1 Qh4 14.
|
||||
Bd3 Bxd3 15. Qxd3 O-O-O 16. Rd1 N7f6 17. c4 Nc7 18. b4 Rd7 19. Bb2 Rhd8 20.
|
||||
Qe2 Qg4 21. f3 Qg6 22. a4 h5 23. b5 h4 24. bxc6 bxc6 25. Ne4 Nxe4 26. fxe4
|
||||
h3 27. g3 f5 28. e5 c5 29. dxc5 Rxd1+ 30. Rxd1 Rxd1+ 31. Qxd1 Qe8 32. Qd6
|
||||
Kb7 33. c6+ Qxc6 34. Qxc6+ Kxc6 35. Bd4 a5 36. Bc3 Na6 37. Bxa5 Nc5 38. Bb4
|
||||
Nxa4 39. g4 fxg4 40. Kf2 Nb2 41. Kg3 Nxc4 42. Kxg4 Nxe5+ 43. Kxh3 Kd5 44.
|
||||
Kh4 Kc4 45. Bd6 Nf7 46. Bc7 g6 47. Kg4 Kd5 48. h4 Ke4 49. h5 Ne5+ 1/2-1/2
|
||||
|
||||
[Event "URS-ch"]
|
||||
[Site "?"]
|
||||
[Date "1973.??.??"]
|
||||
[Round "?"]
|
||||
[White "Tal, Mikhail N."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Nd7 5. Bc4 Ngf6 6. Ng5 e6 7. Qe2 Nb6
|
||||
8. Bb3 a5 9. a4 h6 10. N5f3 c5 11. Bf4 Bd6 12. Be5 O-O 13. O-O-O c4 14.
|
||||
Bxc4 Nxa4 15. Nh3 Nb6 16. g4 a4 17. g5 hxg5 18. Nhxg5 a3 19. b3 Bb4 20.
|
||||
Rhg1 a2 21. Kb2 Nxc4+ 22. Qxc4 Nd5 23. Ne4 f6 24. Bf4 Ba3+ 25. Ka1 Nxf4 26.
|
||||
h4 Rf7 27. Rg4 Qa5 0-1
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow"]
|
||||
[Date "1973.??.??"]
|
||||
[Round "2"]
|
||||
[White "Petrosian, Tigran V."]
|
||||
[Black "Kuzmin,G"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. c4 Nf6 2. d4 e6 3. Nc3 Bb4 4. e3 c5 5. Bd3 O-O 6. Nf3 d5 7. O-O dxc4 8.
|
||||
Bxc4 a6 9. a3 Ba5 10. dxc5 Bxc3 11. bxc3 Qa5 12. a4 Nbd7 13. c6 bxc6 14.
|
||||
Qc2 c5 15. e4 Qc7 16. Re1 Ng4 17. Kh1 Re8 18. h3 Ngf6 19. e5 Nd5 20. Ng5
|
||||
Nf8 21. f4 Bb7 22. Ne4 Ng6 23. Qf2 Nb6 24. Bf1 Bxe4 25. Rxe4 Qc6 26. Qc2
|
||||
Nd5 27. a5 Red8 28. Kh2 Rab8 29. Rea4 Nge7 30. Bd3 Nf5 31. Bxf5 exf5 32.
|
||||
Qxf5 Nxc3 33. Rc4 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow"]
|
||||
[Date "1973.??.??"]
|
||||
[Round "10"]
|
||||
[White "Petrosian, Tigran V."]
|
||||
[Black "Smyslov,V"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. e3 c5 5. Bd3 b6 6. Ne2 Nc6 7. O-O cxd4 8.
|
||||
exd4 Bb7 9. d5 Ne5 10. Bf4 Nxd3 11. Qxd3 exd5 12. cxd5 O-O 13. a3 Bxc3 14.
|
||||
Nxc3 Re8 15. Bd6 Ng4 16. Qg3 Nh6 17. Rfe1 Nf5 18. Qf4 Qf6 19. Be5 Qg6 20.
|
||||
Qa4 a6 21. Bf4 b5 22. Qb4 Rec8 23. Qe4 h5 24. Qd3 Rc4 25. Re4 Nh4 26. Bg3
|
||||
Rxe4 27. Nxe4 Nxg2 28. Kxg2 h4 29. Rd1 hxg3 30. hxg3 Rc8 31. f3 f5 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Tilburg"]
|
||||
[Date "1982.??.??"]
|
||||
[Round "10"]
|
||||
[White "Petrosian,Tigran"]
|
||||
[Black "Browne,Walter"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nf3 b6 4. Nc3 Bb4 5. e3 O-O 6. Bd3 Bb7 7. O-O d5 8.
|
||||
a3 Bd6 9. cxd5 exd5 10. b4 a6 11. Qb3 Qe7 12. Rb1 Nbd7 13. a4 Ne4 14. Bb2
|
||||
Ndf6 15. b5 a5 16. Rbd1 Nxc3 17. Bxc3 Ne4 18. Bb2 Rad8 19. Ne5 Kh8 20. Qc2
|
||||
f6 21. Nf3 Bc8 22. Ne1 f5 23. g3 Rf6 24. Nf3 Rdf8 25. Ne5 Rh6 26. f3 Ng5
|
||||
27. Qg2 Nh3+ 28. Kh1 g5 29. g4 Qf6 30. Rd2 Rh4 31. Rc2 Qg7 32. gxf5 Bxf5
|
||||
33. Bxf5 Rxf5 34. Bc3 Rh6 35. Ng4 Rh5 36. Be1 Qe7 37. Bg3 Rf7 38. Rfc1 Kg7
|
||||
39. Rc6 Kf8 40. Bxd6 cxd6 41. Qg3 Rh4 42. Qxd6 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Lone"]
|
||||
[Date "1978.??.??"]
|
||||
[Round "?"]
|
||||
[White "Portisch, Lajos"]
|
||||
[Black "Petrosian, Tigran"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. e3 b6 5. Bd3 Bb7 6. Nf3 O-O 7. O-O d5 8.
|
||||
a3 Bd6 9. b4 dxc4 10. Bxc4 Nbd7 11. Bb2 a5 12. b5 e5 13. Re1 e4 14. Nd2 Qe7
|
||||
15. Be2 Rad8 16. Qc2 Rfe8 17. f3 exf3 18. Bxf3 Bxf3 19. Nxf3 Ne4 20. Nxe4
|
||||
Qxe4 21. Qxe4 Rxe4 22. Nd2 Ree8 23. e4 Nc5 24. Nc4 Nxe4 25. Rac1 Bf8 26.
|
||||
Ne5 Nd6 27. a4 f6 28. Nf3 Rxe1+ 29. Nxe1 Rd7 30. Nf3 Nf5 31. Kf2 h5 32. Rc2
|
||||
g5 33. Rc4 Bd6 34. g3 Kf7 35. Ng1 Ne7 36. Ne2 Nd5 37. Bc1 Kg6 38. Rc2 Kf5
|
||||
39. Kf3 g4+ 40. Kf2 Rh7 41. Rd2 h4 42. Kg2 Ke4 43. Rd1 Ne3+ 44. Bxe3 Kxe3
|
||||
45. Nc3 h3+ 0-1
|
||||
|
||||
[Event "?"]
|
||||
[Site "Milano"]
|
||||
[Date "1975.??.??"]
|
||||
[Round "1"]
|
||||
[White "Petrosian, Tigran"]
|
||||
[Black "Karpov, Anatoly"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. e3 O-O 5. Bd3 c5 6. Nf3 d5 7. O-O cxd4 8.
|
||||
exd4 dxc4 9. Bxc4 b6 10. Bg5 Bb7 11. Qe2 Bxc3 12. bxc3 Nbd7 13. Bd3 Qc7 14.
|
||||
c4 Ng4 15. Be4 Bxe4 16. Qxe4 Ngf6 17. Qd3 h6 18. Bxf6 Nxf6 19. a4 Rac8 20.
|
||||
Rfc1 Rfd8 21. h3 e5 22. Nxe5 Qxe5 23. dxe5 Rxd3 24. exf6 Rd4 25. a5 gxf6
|
||||
26. axb6 axb6 27. Rab1 Rcxc4 28. Rxc4 Rxc4 29. Rxb6 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow"]
|
||||
[Date "1971.??.??"]
|
||||
[Round "1"]
|
||||
[White "Petrosian, Tigran"]
|
||||
[Black "Kortchnoi, Viktor"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. Qc2 d5 5. cxd5 exd5 6. a3 Bxc3+ 7. bxc3
|
||||
O-O 8. Bg5 c5 9. e3 Nbd7 10. Bd3 Qa5 11. Ne2 b6 12. O-O Ba6 13. Bxa6 Qxa6
|
||||
14. Bxf6 Nxf6 15. Nf4 Qc4 16. Qa2 Qxa2 17. Rxa2 Rac8 18. a4 Rfd8 19. Rb1
|
||||
Ne4 20. Ne2 Nd6 21. h4 Nc4 22. Nf4 Kf8 23. g4 g6 24. Kg2 h6 25. Rd1 g5 26.
|
||||
hxg5 hxg5 27. Ne2 Nd6 28. Ng3 cxd4 29. Rxd4 Ne4 30. Nxe4 dxe4 31. Rxe4 Rxc3
|
||||
32. a5 Rdc8 33. axb6 axb6 34. Rb2 R3c4 35. Rxc4 Rxc4 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Wch"]
|
||||
[Date "1963.??.??"]
|
||||
[Round "?"]
|
||||
[White "Petrosian, Tigran V."]
|
||||
[Black "Botvinnik, Mikhail"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. Qc2 d5 5. cxd5 exd5 6. Bg5 h6 7. Bxf6 Qxf6
|
||||
8. a3 Bxc3+ 9. Qxc3 c6 10. e3 O-O 11. Ne2 Re8 12. Ng3 g6 13. f3 h5 14. Be2
|
||||
Nd7 15. Kf2 h4 16. Nf1 Nf8 17. Nd2 Re7 18. Rhe1 Bf5 19. h3 Rae8 20. Nf1 Ne6
|
||||
21. Qd2 Ng7 22. Rad1 Nh5 23. Rc1 Qd6 24. Rc3 Ng3 25. Kg1 Nh5 26. Bd1 Re6
|
||||
27. Qf2 Qe7 28. Bb3 g5 29. Bd1 Bg6 30. g4 hxg3 31. Nxg3 Nf4 32. Qh2 c5 33.
|
||||
Qd2 c4 34. Ba4 b5 35. Bc2 Nxh3+ 36. Kf1 Qf6 37. Kg2 Nf4+ 38. exf4 Rxe1 39.
|
||||
fxg5 Qe6 40. f4 Re2+ 0-1
|
||||
|
||||
[Event "?"]
|
||||
[Site "Curacao ct"]
|
||||
[Date "1962.??.??"]
|
||||
[Round "3"]
|
||||
[White "Petrosian, Tigran V."]
|
||||
[Black "Keres, Paul"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. c4 Nf6 2. d4 e6 3. Nf3 b6 4. Nc3 Bb4 5. e3 c5 6. Bd3 d5 7. dxc5 bxc5 8.
|
||||
O-O O-O 9. Ne2 Bb7 10. b3 Nbd7 11. Bb2 Qe7 12. Ng3 g6 13. cxd5 exd5 14. a3
|
||||
Ba5 15. b4 cxb4 16. Qa4 Bb6 17. axb4 Ng4 18. Rfe1 Nde5 19. Nxe5 Nxe5 20.
|
||||
Rad1 Nxd3 21. Rxd3 Rfc8 22. b5 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow-Wch"]
|
||||
[Date "1966.??.??"]
|
||||
[Round "20"]
|
||||
[White "Petrosian, Tigran V."]
|
||||
[Black "Spassky, Boris"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. e3 O-O 5. Bd3 c5 6. Nf3 d5 7. O-O Nc6 8.
|
||||
a3 Bxc3 9. bxc3 dxc4 10. Bxc4 Qc7 11. Bd3 e5 12. Qc2 Bg4 13. Nxe5 Nxe5 14.
|
||||
dxe5 Qxe5 15. f3 Bd7 16. a4 Rfe8 17. e4 c4 18. Be2 Be6 19. Be3 Qc7 20. Rab1
|
||||
Nd7 21. Rb5 b6 22. Rfb1 Qc6 23. Bd4 f6 24. Qa2 Kh8 25. Bf1 h6 26. h3 Rab8
|
||||
27. a5 Rb7 28. axb6 axb6 29. Qf2 Ra8 30. Qb2 Rba7 31. Bxb6 Ra2 32. Qb4 Rc2
|
||||
33. Bf2 Qc7 34. Qe7 Bxh3 35. gxh3 Rxf2 36. Kxf2 Qh2+ 37. Bg2 Ne5 38. Rb8+
|
||||
Rxb8 39. Rxb8+ Kh7 40. Rd8 Ng6 41. Qe6 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow-Wch"]
|
||||
[Date "1969.??.??"]
|
||||
[Round "10"]
|
||||
[White "Petrosian, Tigran V."]
|
||||
[Black "Spassky, Boris"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. e3 O-O 5. Bd3 b6 6. Ne2 d5 7. O-O dxc4 8.
|
||||
Bxc4 Bb7 9. f3 c5 10. a3 cxd4 11. axb4 dxc3 12. Nxc3 Nc6 13. b5 Ne5 14. Be2
|
||||
Qc7 15. e4 Rfd8 16. Qe1 Qc5+ 17. Qf2 Qe7 18. Ra3 Ne8 19. Bf4 Ng6 20. Be3
|
||||
Nd6 21. Rfa1 Nc8 22. Bf1 f5 23. exf5 exf5 24. Ra4 Re8 25. Bd2 Qc5 26. Qxc5
|
||||
bxc5 27. Rc4 Re5 28. Na4 a6 29. Nxc5 axb5 30. Nxb7 Rxa1 31. Rxc8+ Kf7 32.
|
||||
Nd8+ Ke7 33. Nc6+ Kd7 34. Nxe5+ Kxc8 35. Nxg6 hxg6 36. Bc3 Rb1 37. Kf2 b4
|
||||
38. Bxg7 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Milano"]
|
||||
[Date "1975.??.??"]
|
||||
[Round "2"]
|
||||
[White "Ljubojevic, Ljubomir"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. Qc2 d5 5. a3 Be7 6. Nf3 O-O 7. e3 b6 8.
|
||||
cxd5 exd5 9. b4 Re8 10. Bd3 Bb7 11. O-O Bd6 12. Bb2 a6 13. Ne5 c5 14. bxc5
|
||||
bxc5 15. Rab1 Qc7 16. h3 c4 1/2-1/2
|
||||
|
||||
[Event "32nd ol"]
|
||||
[Site "Yerevan ARM"]
|
||||
[Date "1996.09.17"]
|
||||
[Round "02"]
|
||||
[White "Gostisa,L"]
|
||||
[Black "Petrosian,A"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. Nf3 e6 3. g3 d5 4. Bg2 Nbd7 5. O-O b5 6. b3 Bb7 7. c4 bxc4 8.
|
||||
bxc4 dxc4 9. Qa4 c5 10. Ba3 Qc7 11. Qxc4 Rc8 12. Rc1 Qb8 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Belgrade"]
|
||||
[Date "1954.??.??"]
|
||||
[Round "?"]
|
||||
[White "Janosevic"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. c4 e6 5. Nc3 Nf6 6. Bg5 Be7 7. Nf3 O-O 8.
|
||||
Rc1 a6 9. cxd5 exd5 10. Be2 Nc6 11. Ne5 Na5 12. O-O h6 13. Bh4 Bf5 14. Bf3
|
||||
Be6 15. Re1 Nc6 16. Ng6 fxg6 17. Rxe6 g5 18. Bg3 Qd7 19. Re1 Rae8 20. Be5
|
||||
Kh8 21. Qb3 g4 22. Bxd5 Nxd5 23. Nxd5 Bg5 24. Rcd1 Na5 25. Nb6 Qd8 26. Qa4
|
||||
Qxb6 27. Bxg7+ Kxg7 28. Rxe8 Nc6 29. Rxf8 Kxf8 30. d5 Ne5 31. d6 Qxb2 32.
|
||||
d7 Nf7 33. Qxg4 Qxa2 34. Qb4+ Be7 35. d8=Q+ Nxd8 36. Rxd8+ Kf7 37. Qf4+ Kg7
|
||||
38. Qg4+ Kf6 39. Rd1 b5 40. h4 Qe6 41. Qh5 Kg7 42. Rd3 Bd6 43. Qd1 Bc5 44.
|
||||
Rg3+ Kf6 45. Qa1+ Kf5 46. Qb1+ Ke5 47. Rg6 Qf7 48. Qe1+ Kd5 49. Rxa6 Qf4
|
||||
50. Qd1+ Kc4 51. Ra2 Bd4 52. Qe2+ Kb4 53. Qe1+ Kb3 54. Qb1+ Kc4 55. Rc2+
|
||||
Bc3 56. Re2 Bd4 57. Qc2+ Kd5 58. Qb3+ Kc5 59. g3 Qf6 60. Rc2+ Kb6 61. Kg2
|
||||
Qf5 62. Re2 Kc5 63. Qc2+ Qxc2 64. Rxc2+ Kd5 65. f4 b4 66. Kf3 b3 67. Rc1 b2
|
||||
68. Rd1 h5 69. g4 hxg4+ 70. Kxg4 Ke4 71. h5 Be3 72. Rb1 Bc1 73. h6 Bxf4 74.
|
||||
Re1+ 1-0
|
||||
|
||||
[Event "YUG-URS"]
|
||||
[Site "Belgrade"]
|
||||
[Date "1956.??.??"]
|
||||
[Round "?"]
|
||||
[White "Pirc, Vasja"]
|
||||
[Black "Petrosian, Tigran V"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. Nf3 c5 2. c4 Nc6 3. g3 g6 4. Bg2 Bg7 5. O-O Nh6 6. Nc3 O-O 7. d3 d6 8.
|
||||
Bd2 Nf5 9. a3 a6 10. Rb1 Rb8 11. b4 cxb4 12. axb4 b5 13. cxb5 axb5 14. e3
|
||||
e5 15. Qe2 d5 16. Rfc1 Nfe7 17. Be1 h6 18. Nd2 d4 19. Nce4 19...
|
||||
Kh7 20. Nb3 f5 21. Nec5 dxe3 22. fxe3 f4 23. Na5 Rb6 24. Ncb3 Bd7 25. exf4
|
||||
exf4 26. Bf2 fxg3 27. hxg3 Ne5 28. Nb7 Rxb7 29. Bxb7 Bg4 30. Qf1 Nf3+ 31.
|
||||
Bxf3 Rxf3 32. Re1 Nf5 33. Qg2 Qd5 34. Nd2 Nd4 35. Re7 Qd6 36. Re4 h5 37.
|
||||
Re3 Rxe3 38. Bxe3 Ne2+ 39. Kf2 Nc3 40. Re1 Qxd3 41. Qf1 Qd6 42. Kg2 Qxb4
|
||||
43. Qf7 1/2-1/2
|
||||
|
||||
[Event "Bled"]
|
||||
[Site "Bled"]
|
||||
[Date "1961.09.09"]
|
||||
[Round "5"]
|
||||
[White "Germek, Milan"]
|
||||
[Black "Petrosian, Tigran V"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. d4 Nf6 2. c4 d6 3. Nc3 e5 4. dxe5 dxe5 5. Qxd8+ Kxd8 6. Nf3 Nbd7 7. Bg5
|
||||
c6 8. O-O-O Kc7 9. Bh4 Bb4 10. Kc2 Re8 11. Bg3 Nh5 12. Nd2 f5 13. e3 Nxg3
|
||||
14. hxg3 Nf6 15. a3 Bf8 16. Be2 a5 17. Rde1 e4 18. Nb3 a4 19. Nd4
|
||||
19... Re5 20. Kb1 Rc5 21. Rc1 g6 22. Ka1 h5 23. Rhd1 Re5 24. Rd2 Nd7 25.
|
||||
Bd1 Nc5 26. Be2 Be6 27. Kb1 Rd8 28. Rh1 Bf7 29. Rc1 Nd7 30. Ka1 Rc5 31. Nb1
|
||||
Bg7 32. Rdc2 Ra5 33. Rd1 Rh8 34. Nd2 Nc5 35. Kb1 h4 36. g4 f4 37. Nf1 h3
|
||||
38. gxh3 f3 0-1
|
8
pgn-extract/test/infiles/roster.txt
Normal file
8
pgn-extract/test/infiles/roster.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
% Output the tags of the seven tag roster alphabetically.
|
||||
Black
|
||||
Date
|
||||
Event
|
||||
Result
|
||||
Round
|
||||
Site
|
||||
White
|
3
pgn-extract/test/infiles/taglist.txt
Normal file
3
pgn-extract/test/infiles/taglist.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
White "Fischer"
|
||||
Black "Petrosian"
|
||||
Date "1970"
|
27
pgn-extract/test/infiles/test-7.pgn
Normal file
27
pgn-extract/test/infiles/test-7.pgn
Normal file
@@ -0,0 +1,27 @@
|
||||
[Event "?"]
|
||||
[Site "Biel SKA (5)"]
|
||||
[Date "1995.??.??"]
|
||||
[Round "?"]
|
||||
[White "Adianto,U"]
|
||||
[Black "Gelfand,B"]
|
||||
[Result "1-0"]
|
||||
[WhiteElo "2590"]
|
||||
[BlackElo "2685"]
|
||||
[ECO "E63"]
|
||||
[PlyCount "166"]
|
||||
|
||||
1. d4 Nf6 2. c4 g6 3. g3 Bg7 4. Bg2 O-O 5. Nf3 d6 6. O-O Nc6 7. Nc3 a6 8.
|
||||
h3 Bd7 9. e4 e5 10. d5 Nd4 11. Nxd4 exd4 12. Qxd4 Qc8 13. h4 b5 14. cxb5
|
||||
axb5 15. Qb4 Ng4 16. Bf4 Re8 17. Rac1 Qb8 18. Bh3 Qb6 19. Bxg4 Bxg4 20.
|
||||
Qxb5 Reb8 21. Qxb6 Rxb6 22. b3 c5 23. dxc6 Rxc6 24. Nd5 Rxc1 25. Rxc1 Rxa2
|
||||
26. Kg2 Bd4 27. Be3 Bxe3 28. Nxe3 Be6 29. Rb1 Bd7 30. g4 Bb5 31. Kg3 Bd3
|
||||
32. Rd1 Bxe4 33. Rxd6 Rb2 34. Rb6 Kg7 35. g5 h6 36. b4 hxg5 37. hxg5 Kf8
|
||||
38. f3 Bd3 39. Kf4 Ke8 40. Ke5 Re2 41. Kd4 Bb1 42. b5 Rf2 43. Rb8+ Kd7 44.
|
||||
Rb7+ Ke6 45. Rb6+ Kd7 46. Rf6 Rd2+ 47. Kc5 Ba2 48. Nc4 Rg2 49. Rxf7+ Ke6
|
||||
50. Rf4 Rxg5+ 51. Kc6 Bb3 52. Re4+ Kf6 53. Ne3 Be6 54. b6 Bc8 55. Nd5+ Kg7
|
||||
56. Nb4 Rg1 57. Rc4 Re1 58. Kc7 Re8 59. Re4 Rf8 60. Nc6 Ba6 61. Re3 Kh6 62.
|
||||
Ra3 Rf7+ 63. Kd6 Rf6+ 64. Ke7 Rxc6 65. Rxa6 Kh7 66. Kd8 Kh6 67. Ke7 Kh7 68.
|
||||
Kd7 Rf6 69. b7 Rxa6 70. b8=Q Ra5 71. Ke6 Rf5 72. Qg3 Kg7 73. Qg4 Rf6+ 74.
|
||||
Ke5 Rf7 75. Ke4 Kh7 76. Qc8 Kg7 77. Ke3 Rf8 78. Qc3+ Kh7 79. Kf2 Rf5 80.
|
||||
Kg3 Rg5+ 81. Kf4 Rf5+ 82. Kg4 Rf7 83. Qe5 1-0
|
||||
|
18
pgn-extract/test/infiles/test-C.pgn
Normal file
18
pgn-extract/test/infiles/test-C.pgn
Normal file
@@ -0,0 +1,18 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 {Time control} 1/2-1/2
|
||||
|
19
pgn-extract/test/infiles/test-F-text.pgn
Normal file
19
pgn-extract/test/infiles/test-F-text.pgn
Normal file
@@ -0,0 +1,19 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
{ diagram } 28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7
|
||||
31. Kd4 Kd6 32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 {
|
||||
Time control } 1/2-1/2
|
||||
|
18
pgn-extract/test/infiles/test-F.pgn
Normal file
18
pgn-extract/test/infiles/test-F.pgn
Normal file
@@ -0,0 +1,18 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 {Time control} 1/2-1/2
|
||||
|
6
pgn-extract/test/infiles/test-FENPattern.txt
Normal file
6
pgn-extract/test/infiles/test-FENPattern.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
:-t
|
||||
% Find a supported Knight on e4.
|
||||
FENPattern "*/*/*/*/???pN???/???P????/*/*"
|
||||
% Find a supported Knight for White on d4
|
||||
% or Black on d5.
|
||||
FENPatternI "*/*/*/*/???Np???/????P???/*/*" Nd4th
|
9
pgn-extract/test/infiles/test-L1.pgn
Normal file
9
pgn-extract/test/infiles/test-L1.pgn
Normal file
@@ -0,0 +1,9 @@
|
||||
[Event "?"]
|
||||
[Site "?"]
|
||||
[Date "????.??.??"]
|
||||
[Round "?"]
|
||||
[White "?"]
|
||||
[Black "?"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. f3 e5 2. g4 Qh4# 0-1
|
19
pgn-extract/test/infiles/test-L2.pgn
Normal file
19
pgn-extract/test/infiles/test-L2.pgn
Normal file
@@ -0,0 +1,19 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
19
pgn-extract/test/infiles/test-N.pgn
Normal file
19
pgn-extract/test/infiles/test-N.pgn
Normal file
@@ -0,0 +1,19 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
188
pgn-extract/test/infiles/test-P.pgn
Normal file
188
pgn-extract/test/infiles/test-P.pgn
Normal file
@@ -0,0 +1,188 @@
|
||||
[Event "?"]
|
||||
[Site "Wch"]
|
||||
[Date "1960.??.??"]
|
||||
[Round "?"]
|
||||
[White "Botvinnik, Mikhail"]
|
||||
[Black "Tal, M."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. a3 Bxc3+ 5. bxc3 Ne4 6. Qc2 f5 7. Nh3 O-O
|
||||
8. f3 Nf6 9. c5 b6 10. cxb6 cxb6 11. e3 Qc7 12. Bd2 Ne8 13. c4 Ba6 14. Rc1
|
||||
Nd6 15. Qa4 Qc6 16. Qxc6 Nxc6 17. Bb4 Nxb4 18. axb4 Bxc4 19. Bxc4 Rfc8 20.
|
||||
Bxe6+ dxe6 21. Ke2 Kf7 22. Nf4 a5 23. bxa5 bxa5 24. Kd3 a4 25. Rxc8 Rxc8
|
||||
26. Ra1 Nc4 27. Rb1 a3 28. Rb7+ Kf6 29. Ra7 g5 30. Nh5+ Kg6 31. g4 Nb2+ 32.
|
||||
Kd2 Nc4+ 33. Kd3 Nb2+ 34. Kd2 Nc4+ 35. Ke2 Rc6 36. h3 e5 37. dxe5 fxg4 38.
|
||||
hxg4 Nxe5 39. Rxa3 Rc2+ 40. Kf1 Kf7 41. e4 Rd2 42. Ke1 Rg2 43. Rb3 Ke7 44.
|
||||
Ng7 Nxf3+ 45. Rxf3 Rxg4 46. Nf5+ Ke6 47. Ng3 h5 48. Nxh5 Rxe4+ 49. Kf2 Ke5
|
||||
50. Kg3 Rh4 51. Ng7 Rf4 52. Ra3 Rd4 53. Ra6 Rd6 54. Ra7 Rd4 55. Rf7 Rf4 56.
|
||||
Re7+ Kf6 57. Ra7 Re4 58. Nh5+ Kg6 59. Kf3 Rb4 60. Ng3 Rf4+ 61. Ke3 Rf7 62.
|
||||
Ra5 Rf6 63. Ne4 Rf5 64. Ra6+ Kg7 65. Ng3 Re5+ 66. Kd4 Rb5 67. Ke4 Kf7 68.
|
||||
Nf5 Rb4+ 69. Nd4 Rb1 70. Nf3 Rb4+ 71. Nd4 Rb1 72. Nc6 Kg6 73. Ne5+ Kh5 74.
|
||||
Ra5 Re1+ 75. Kf3 Rf1+ 76. Kg3 Rf5 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Wch"]
|
||||
[Date "1960.??.??"]
|
||||
[Round "?"]
|
||||
[White "Botvinnik, Mikhail"]
|
||||
[Black "Tal, M."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. a3 Bxc3+ 5. bxc3 Ne4 6. Qc2 f5 7. Nh3 d6
|
||||
8. f3 Nf6 9. e4 fxe4 10. fxe4 e5 11. Nf2 O-O 12. Be2 c5 13. dxc5 dxc5 14.
|
||||
O-O Nc6 15. Bg5 Qe8 16. Nd1 Qg6 17. Bxf6 Rxf6 18. Ne3 Rxf1+ 19. Rxf1 Be6
|
||||
20. Qd3 Rd8 21. Nd5 Rf8 22. Nc7 Rxf1+ 23. Bxf1 Qf7 24. Qd6 Bc8 25. Na6 Qf4
|
||||
26. Qd5+ Kh8 27. Qxc5 Be6 28. Nc7 Bg8 29. Qf2 Qxe4 30. Ne8 Qg6 31. Qf8 e4
|
||||
32. Nd6 Ne5 33. c5 Nd3 34. Nf5 Ne5 35. Ne7 Qf7 36. Qxf7 Bxf7 37. Kf2 Bc4
|
||||
38. Bxc4 Nxc4 39. c6 bxc6 40. Nxc6 a5 41. a4 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Wch"]
|
||||
[Date "1960.??.??"]
|
||||
[Round "?"]
|
||||
[White "Botvinnik, Mikhail"]
|
||||
[Black "Tal, M."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. a3 Bxc3+ 5. bxc3 Ne4 6. e3 f5 7. Qh5+ g6
|
||||
8. Qh6 d6 9. f3 Nf6 10. e4 e5 11. Bg5 Qe7 12. Bd3 Rf8 13. Ne2 Qf7 14. Qh4
|
||||
fxe4 15. fxe4 Ng4 16. h3 Qf2+ 17. Kd2 Qxh4 18. Bxh4 Nf2 19. Rhf1 Nxd3 20.
|
||||
Rxf8+ Kxf8 21. Kxd3 Be6 22. Ng3 Nd7 23. Nf1 a6 24. Bf2 Kg7 25. Nd2 Rf8 26.
|
||||
Be3 b6 27. Rb1 Nf6 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Wch"]
|
||||
[Date "1960.??.??"]
|
||||
[Round "?"]
|
||||
[White "Botvinnik, Mikhail"]
|
||||
[Black "Tal, M."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. a3 Bxc3+ 5. bxc3 O-O 6. f3 d5 7. cxd5 exd5
|
||||
8. e3 Bf5 9. Ne2 Nbd7 10. Ng3 Bg6 11. Bd3 c5 12. O-O Re8 13. Re1 Qc7 14.
|
||||
Bxg6 hxg6 15. e4 cxd4 16. cxd4 Rac8 17. Bg5 Qc2 18. Bxf6 Qxd1 19. Rexd1
|
||||
Nxf6 20. e5 Nh5 21. Ne2 Rc2 22. Kf1 g5 23. Rdc1 Rec8 24. g3 f6 25. Rxc2
|
||||
Rxc2 26. Rb1 b6 27. Rb5 fxe5 28. dxe5 Rc5 29. Nd4 Kf7 30. Ke2 g6 31. Kd3
|
||||
Ng7 32. Rb1 Ra5 33. Nc2 Ne6 34. Rb4 Rc5 35. h4 gxh4 36. Rxh4 d4 37. Nxd4
|
||||
Rxe5 38. Nxe6 Kxe6 39. a4 Rg5 40. Re4+ Kf6 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Wch"]
|
||||
[Date "1961.??.??"]
|
||||
[Round "?"]
|
||||
[White "Botvinnik, Mikhail"]
|
||||
[Black "Tal, M."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. c4 Nf6 2. Nc3 e6 3. d4 Bb4 4. a3 Bxc3+ 5. bxc3 b6 6. f3 Ba6 7. e4 d5 8.
|
||||
cxd5 Bxf1 9. Kxf1 exd5 10. Bg5 h6 11. Qa4+ c6 12. Bh4 dxe4 13. Re1 g5 14.
|
||||
Bf2 Qe7 15. Ne2 b5 16. Qc2 Qxa3 17. h4 gxh4 18. Bxh4 Nbd7 19. Ng3 O-O-O 20.
|
||||
Nxe4 Rhe8 21. Kf2 Nxe4+ 22. fxe4 f6 23. Ra1 Qe7 24. Rxa7 Qxe4 25. Qxe4 Rxe4
|
||||
26. Ra8+ Nb8 27. Bg3 Kb7 28. Rha1 Rc8 29. R8a7+ Kb6 30. Bxb8 b4 31. Bd6
|
||||
bxc3 32. Bc5+ Kb5 33. R1a4 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Wch"]
|
||||
[Date "1961.??.??"]
|
||||
[Round "?"]
|
||||
[White "Botvinnik, Mikhail"]
|
||||
[Black "Tal, M."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. c4 Nf6 2. Nc3 e6 3. d4 Bb4 4. e3 O-O 5. Bd3 d5 6. a3 dxc4 7. Bxc4 Bd6 8.
|
||||
Nf3 Nc6 9. Nb5 e5 10. Nxd6 Qxd6 11. dxe5 Qxd1+ 12. Kxd1 Ng4 13. Ke2 Ncxe5
|
||||
14. Bd5 c6 15. Be4 Be6 16. Nd2 Rad8 17. h3 Nf6 18. Bc2 Rd7 19. b3 Rfd8 20.
|
||||
Rd1 Nd3 21. Bxd3 Rxd3 22. Bb2 R3d7 23. Bxf6 gxf6 24. b4 Bf5 25. Nb3 Bd3+
|
||||
26. Ke1 b6 27. Rac1 Be4 28. f3 Rxd1+ 29. Rxd1 Rxd1+ 30. Kxd1 Bd5 31. Nd4 c5
|
||||
32. bxc5 bxc5 33. Nb5 a6 34. Nc7 Bc4 35. Ne8 f5 36. h4 Kf8 37. Nd6 Bf1 38.
|
||||
g3 Ke7 39. Nxf5+ Ke6 40. e4 Ke5 41. Kd2 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Wch"]
|
||||
[Date "1961.??.??"]
|
||||
[Round "?"]
|
||||
[White "Botvinnik, Mikhail"]
|
||||
[Black "Tal, M."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. c4 Nf6 2. Nc3 e6 3. d4 Bb4 4. e3 O-O 5. Bd3 d5 6. a3 dxc4 7. Bxc4 Bd6 8.
|
||||
Nf3 Nc6 9. b4 e5 10. Bb2 Bg4 11. d5 Ne7 12. h3 Bd7 13. Ng5 Ng6 14. Ne6 fxe6
|
||||
15. dxe6 Kh8 16. exd7 Qxd7 17. O-O Qf5 18. Nd5 Ng8 19. Qg4 Qc2 20. Qe2 Qf5
|
||||
21. Qg4 Qc2 22. Qe2 Qf5 23. e4 Qd7 24. Rad1 Rad8 25. Qg4 Qe8 26. g3 Nh6 27.
|
||||
Qh5 Ng8 28. Qe2 N6e7 29. Ne3 Nh6 30. Ng4 Nxg4 31. hxg4 Nc6 32. Kg2 Be7 33.
|
||||
Bd5 Nd4 34. Bxd4 exd4 35. Bc4 c5 36. b5 Bf6 37. f4 d3 38. Rxd3 Rxd3 39.
|
||||
Bxd3 Bd4 40. e5 g6 41. Rh1 Kg7 42. Qe4 b6 43. Bc4 1-0
|
||||
|
||||
[Event "WM Moskau"]
|
||||
[Site "?"]
|
||||
[Date "1960.??.??"]
|
||||
[Round "?"]
|
||||
[White "Botvinnik"]
|
||||
[Black "Tal, Mikhail N."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. a3 Bxc3+ 5. bxc3 Ne4 6. Nh3 c5 7. e3 Qa5
|
||||
8. Bd2 cxd4 9. cxd4 Nxd2 10. Qxd2 Qxd2+ 11. Kxd2 b6 12. Bd3 Ba6 13. Rhc1
|
||||
Nc6 14. Rab1 Ke7 15. c5 Bxd3 16. Kxd3 Rab8 17. Rb5 bxc5 18. Rcxc5 a6 19.
|
||||
Rxb8 Rxb8 20. Kc2 Rc8 21. Nf4 d6 22. Rc3 g5 1/2-1/2
|
||||
|
||||
[Event "WM Moskau"]
|
||||
[Site "?"]
|
||||
[Date "1960.??.??"]
|
||||
[Round "?"]
|
||||
[White "Botvinnik"]
|
||||
[Black "Tal, Mikhail N."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. a3 Bxc3+ 5. bxc3 Ne4 6. Qc2 f5 7. Nh3 O-O
|
||||
8. f3 Nf6 9. c5 b6 10. cxb6 cxb6 11. e3 Qc7 12. Bd2 Ne8 13. c4 Ba6 14. Rc1
|
||||
Nd6 15. Qa4 Qc6 16. Qxc6 Nxc6 17. Bb4 Nxb4 18. axb4 Bxc4 19. Bxc4 Rfc8 20.
|
||||
Bxe6+ dxe6 21. Kd2 Kf7 22. Nf4 a5 23. bxa5 bxa5 24. Kd3 a4 25. Rxc8 Rxc8
|
||||
26. Ra1 Nc4 27. Rb1 a3 28. Rb7+ Kf6 29. Ra7 g5 30. Nh5+ Kg6 31. g4 Nb2+ 32.
|
||||
Kd2 Nc4+ 33. Kd3 Nb2+ 34. Kd2 Nc4+ 35. Ke2 Rc6 36. h3 e5 37. dxe5 fxg4 38.
|
||||
hxg4 Nxe5 39. Rxa3 Rc2+ 40. Kf1 Kf7 41. e4 Rd2 42. Ke1 Rg2 43. Rb3 Ke7 44.
|
||||
Ng7 Nxf3+ 45. Rxf3 Rxg4 46. Nf5+ Ke6 47. Ng3 h5 48. Nxh5 Rxe4+ 49. Kf2 Ke5
|
||||
50. Kg3 Rh4 51. Ng7 Rf4 52. Ra3 Rd4 53. Ra6 Rd6 54. Ra7 Rd4 55. Rf7 Rf4 56.
|
||||
Re7+ Kf6 57. Ra7 Re4 58. Nh5+ Kg6 59. Kf3 Rb4 60. Ng3 Rf4+ 61. Ke3 Rf7 62.
|
||||
Ra5 Rf6 63. Ne4 Rf5 64. Ra6+ Kg7 65. Ng3 Re5+ 66. Kd4 Rb5 67. Ke4 Kf7 68.
|
||||
Nf5 Rb4+ 69. Nd4 Rb1 70. Nf3 Rb4+ 71. Nd4 Rb1 72. Nc6 Kg6 73. Ne5+ Kh5 74.
|
||||
Ra5 Re1+ 75. Kf3 Rf1+ 76. Kg3 Rf4 1/2-1/2
|
||||
|
||||
[Event "WM Moskau"]
|
||||
[Site "?"]
|
||||
[Date "1960.??.??"]
|
||||
[Round "?"]
|
||||
[White "Botvinnik"]
|
||||
[Black "Tal, Mikhail N."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. a3 Bxc3+ 5. bxc3 Ne4 6. Qc2 f5 7. Nh3 d6
|
||||
8. f3 Nf6 9. e4 fxe4 10. fxe4 e5 11. Nf2 O-O 12. Be2 c5 13. dxe5 dxe5 14.
|
||||
O-O Nc6 15. Bg5 Qe8 16. Nd1 Qg6 17. Bxf6 Rxf6 18. Ne3 Rxf1+ 19. Rxf1 Be6
|
||||
20. Qd3 Rd8 21. Nd5 Rf8 22. Nc7 Rxf1+ 23. Bxf1 Qf7 24. Qd6 Bc8 25. Na6 Qf4
|
||||
26. Qd5+ Kh8 27. Qxc5 Be6 28. Nc7 Bg8 29. Qf2 Qxe4 30. Ne8 Qg6 31. Qf8 e4
|
||||
32. Nd6 Ne5 33. c5 Nd3 34. Nf5 Ne5 35. Ne7 Qf7 36. Qxf7 Bxf7 37. Kf2 Bc4
|
||||
38. Bxc4 Nxc4 39. c6 bxc6 40. Nxc6 a5 41. a4 1/2-1/2
|
||||
|
||||
[Event "WM Moskau"]
|
||||
[Site "?"]
|
||||
[Date "1961.??.??"]
|
||||
[Round "?"]
|
||||
[White "Botvinnik"]
|
||||
[Black "Tal, Mikhail N."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. c4 Nf6 2. Nc3 e6 3. d4 Bb4 4. e3 O-O 5. Bd3 d5 6. a3 dxc4 7. Bxc4 Bd6 8.
|
||||
Nf3 Nc6 9. b4 e5 10. Bb2 Bg4 11. dxe5 Nxe5 12. Be2 Qe7 13. Nb5 Rfd8 14. Qc2
|
||||
a6 15. Nxd6 cxd6 16. Qd1 Rac8 17. O-O Ne4 18. Nd4 Bxe2 19. Qxe2 Nc4 20.
|
||||
Rac1 d5 21. Qg4 Qd7 22. Qxd7 Rxd7 23. Rc2 Ned6 24. Rd1 Rdd8 25. Nb3 Nxb2
|
||||
26. Rxb2 Nc4 27. Ra2 b6 28. Kf1 f6 29. a4 Ne5 30. b5 Rc3 31. Nd4 Ra8 32.
|
||||
Rda1 a5 33. Rd1 Rac8 34. Nf5 R8c7 35. Rxd5 Kf7 36. Rd1 Ke6 37. Nd4+ Kf7 38.
|
||||
Ke2 R7c4 39. h3 Rb4 40. Nc2 Rbc4 41. Rd2 Ke7 42. Nd4 g6 43. Rd1 Nd7 44.
|
||||
Nc6+ Ke8 45. Rd6 Rc2+ 46. Rxc2 Rxc2+ 47. Kf3 Ra2 48. Re6+ Kf8 49. Rd6 Ke8
|
||||
50. Re6+ Kf8 51. Kg3 Rxa4 52. Re7 Nc5 53. Rxh7 Ne4+ 54. Kh2 Nd6 55. Rh8+
|
||||
Kf7 56. Rb8 Nc4 57. Rc8 Nd2 58. g4 Ra2 59. Rb8 Ne4 60. Rxb6 Rxf2+ 61. Kg1
|
||||
Rb2 62. Nxa5 Nd2 63. Nc6 Nc4 64. Rb7+ Ke6 65. h4 Kd5 66. Rd7+ Kc5 67. Rd3
|
||||
Kxb5 68. Nd4+ Kc5 69. Nf3 Re2 70. h5 gxh5 71. gxh5 Nxe3 72. h6 Rg2+ 73. Kh1
|
||||
Rg3 1/2-1/2
|
||||
|
19
pgn-extract/test/infiles/test-R.pgn
Normal file
19
pgn-extract/test/infiles/test-R.pgn
Normal file
@@ -0,0 +1,19 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
20
pgn-extract/test/infiles/test-Ta.pgn
Normal file
20
pgn-extract/test/infiles/test-Ta.pgn
Normal file
@@ -0,0 +1,20 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
[Annotator "Barnes, David J."]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
18
pgn-extract/test/infiles/test-V.pgn
Normal file
18
pgn-extract/test/infiles/test-V.pgn
Normal file
@@ -0,0 +1,18 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 {Time control} 1/2-1/2
|
||||
|
6
pgn-extract/test/infiles/test-a.txt
Normal file
6
pgn-extract/test/infiles/test-a.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
b2b3 e7e5 c1b2 d7d6 d2d4 e5d4 d1d4 b8c6 d4d2 g8f6 b1c3 c8e6 e2e4 d6d5 e4d5
|
||||
e6d5 d2e3+ f8e7 g1f3 e8g8 f1e2 f8e8 e1c1 e7b4 e3d3 b4c3 b2c3 d8e7 h1e1 f6e4
|
||||
c3b2 a8d8 d3e3 b7b6 e2b5 e7e6 f3d4 c6d4 d1d4 c7c5 d4e4 d5e4 b5e8 d8e8 f2f3
|
||||
e4d5 e3e6 e8e6 e1e6 d5e6 c1d2 g8f8 b2e5 b6b5 e5b8 a7a6 b8a7 c5c4 d2c3 f8e7
|
||||
c3d4 e7d6 a7c5+ d6d7 c5a7 d7d6 a7c5+ d6d7 d4c3 g7g6 c5d4 f7f5 1/2-1/2
|
||||
|
19
pgn-extract/test/infiles/test-addhashcode.pgn
Normal file
19
pgn-extract/test/infiles/test-addhashcode.pgn
Normal file
@@ -0,0 +1,19 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
23
pgn-extract/test/infiles/test-allownullmoves.pgn
Normal file
23
pgn-extract/test/infiles/test-allownullmoves.pgn
Normal file
@@ -0,0 +1,23 @@
|
||||
[Event "?"]
|
||||
[Site "?"]
|
||||
[Date "????.??.??"]
|
||||
[Round "?"]
|
||||
[White "?"]
|
||||
[Black "?"]
|
||||
[Result "1-0"]
|
||||
[SetUp "1"]
|
||||
[FEN "1r5k/q4prp/p4NpQ/P1N1p3/8/3B1R2/1PP3PP/7K w - - 0 31"]
|
||||
|
||||
31. Rh3 -- 32. Qxh7+ Rxh7 33. Rxh7# 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "?"]
|
||||
[Date "????.??.??"]
|
||||
[Round "?"]
|
||||
[White "?"]
|
||||
[Black "?"]
|
||||
[Result "*"]
|
||||
[SetUp "1"]
|
||||
[FEN "4r1k1/2p2p2/5np1/Qp4q1/2p3P1/2B2P2/PP6/K6R w - - 0 1"]
|
||||
|
||||
1. Qxb5 -- (1... Qxb5 2. Bxf6 Re1+ 3. Rxe1 Qc6 4. g5)(1... Qe3 2. Qxe8+) *
|
29
pgn-extract/test/infiles/test-checkmate.pgn
Normal file
29
pgn-extract/test/infiles/test-checkmate.pgn
Normal file
@@ -0,0 +1,29 @@
|
||||
[Event "?"]
|
||||
[Site "?"]
|
||||
[Date "????.??.??"]
|
||||
[Round "?"]
|
||||
[White "?"]
|
||||
[Black "?"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. f3 e5 2. g4 Qh4# 0-1
|
||||
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
93
pgn-extract/test/infiles/test-e.pgn
Normal file
93
pgn-extract/test/infiles/test-e.pgn
Normal file
@@ -0,0 +1,93 @@
|
||||
[Event "?"]
|
||||
[Site "Sarajevo"]
|
||||
[Date "1972"]
|
||||
[Round "?"]
|
||||
[White "Petrosian,T"]
|
||||
[Black "Hort"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. Nf3 c5 2. b3 d5 3. e3 Nf6 4. Bb2 e6 5. c4 Nc6 6. cxd5 exd5 7. Be2 Be7 8.
|
||||
O-O O-O 9. d4 Bg4 10. dxc5 Bxc5 11. Nc3 Rc8 12. Rc1 Be7 13. Nd4 Bxe2 14.
|
||||
Ncxe2 Qd7 15. Nf4 Rfd8 16. Qd3 Ne4 17. Nxc6 bxc6 18. Rc2 Bf8 19. Rfc1 Qb7
|
||||
20. Qe2 Re8 21. Qg4 g6 22. Qd1 Bd6 23. Nxd5 Rcd8 24. Rxc6 Qb8 25. f4 Re6
|
||||
26. Qd4 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Buenos Aires m"]
|
||||
[Date "1971"]
|
||||
[Round "6"]
|
||||
[White "Petrosian,T"]
|
||||
[Black "Fischer,R"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. Nf3 c5 2. b3 d5 3. Bb2 f6 4. c4 d4 5. d3 e5 6. e3 Ne7 7. Be2 Nec6 8.
|
||||
Nbd2 Be7 9. O-O O-O 10. e4 a6 11. Ne1 b5 12. Bg4 Bxg4 13. Qxg4 Qc8 14. Qe2
|
||||
Nd7 15. Nc2 Rb8 16. Rfc1 Qe8 17. Ba3 Bd6 18. Ne1 g6 19. cxb5 axb5 20. Bb2
|
||||
Nb6 21. Nef3 Ra8 22. a3 Na5 23. Qd1 Qf7 24. a4 bxa4 25. bxa4 c4 26. dxc4
|
||||
Nbxc4 27. Nxc4 Nxc4 28. Qe2 Nxb2 29. Qxb2 Rfb8 30. Qa2 Bb4 31. Qxf7+ Kxf7
|
||||
32. Rc7+ Ke6 33. g4 Bc3 34. Ra2 Rc8 35. Rxc8 Rxc8 36. a5 Ra8 37. a6 Ra7 38.
|
||||
Kf1 g5 39. Ke2 Kd6 40. Kd3 Kc5 41. Ng1 Kb5 42. Ne2 Ba5 43. Rb2+ Kxa6 44.
|
||||
Rb1 Rc7 45. Rb2 Be1 46. f3 Ka5 47. Rc2 Rb7 48. Ra2+ Kb5 49. Rb2+ Bb4 50.
|
||||
Ra2 Rc7 51. Ra1 Rc8 52. Ra7 Ba5 53. Rd7 Bb6 54. Rd5+ Bc5 55. Nc1 Ka4 56.
|
||||
Rd7 Bb4 57. Ne2 Kb3 58. Rb7 Ra8 59. Rxh7 Ra1 60. Nxd4+ exd4 61. Kxd4 Rd1+
|
||||
62. Ke3 Bc5+ 63. Ke2 Rh1 64. h4 Kc4 65. h5 Rh2+ 66. Ke1 Kd3 0-1
|
||||
|
||||
[Event "Tilburg Grandmaster Tournament"]
|
||||
[Site "Tilburg, NED"]
|
||||
[Date "1982.09.??"]
|
||||
[Round "2"]
|
||||
[White "Karpov, Anatoly"]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nd2 dxe4 4. Nxe4 Nd7 5. Bc4 Ngf6 6. Ng5 e6 7. Qe2 Nb6
|
||||
8. Bb3 a5 9. a3 a4 10. Ba2 h6 11. N5f3 c5 12. c3 Bd7 13. Ne5 cxd4 14. cxd4
|
||||
Be7 15. Ngf3 O-O 16. O-O Be8 17. Bd2 Nbd5 18. Rfc1 Qb6 19. Bc4 Bc6 20. Re1
|
||||
Nc7 21. Nxc6 bxc6 22. Bf4 Ncd5 23. Be5 Rfd8 24. Rad1 Bd6 25. Rd2 Bxe5 26.
|
||||
dxe5 Nd7 27. g3 Nf8 28. Red1 Rd7 29. Qe4 Rb7 30. Rc2 Rab8 31. Rdd2 Ne7 32.
|
||||
Kg2 Qa5 33. h4 Rd7 34. Be2 Rd5 35. Rd4 Rxd4 36. Qxd4 Nd5 37. Rxc6 Qa8 38.
|
||||
Rc4 Qb7 39. Rc2 Nb6 40. Bb5 Ng6 41. Qd6 Qa8 42. Bc6 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow"]
|
||||
[Date "1973.??.??"]
|
||||
[Round "15"]
|
||||
[White "Tal,M"]
|
||||
[Black "Petrosian,T"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Nd7 5. Bc4 Ngf6 6. Ng5 e6 7. Qe2 Nb6
|
||||
8. Bb3 a5 9. a4 h6 10. N5f3 c5 11. Bf4 Bd6 12. Be5 O-O 13. O-O-O c4 14.
|
||||
Bxc4 Nxa4 15. Nh3 Nb6 16. g4 a4 17. g5 hxg5 18. Nhxg5 a3 19. b3 Bb4 20.
|
||||
Rdg1 a2 21. Kb2 Nxc4+ 22. Qxc4 Nd5 23. Ne4 f6 24. Bf4 Ba3+ 25. Ka1 Nxf4 26.
|
||||
h4 Rf7 27. Rg4 Qa5 0-1
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow"]
|
||||
[Date "1973.??.??"]
|
||||
[Round "2"]
|
||||
[White "Petrosian,T"]
|
||||
[Black "Kuzmin,G"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. c4 Nf6 2. d4 e6 3. Nc3 Bb4 4. e3 c5 5. Bd3 O-O 6. Nf3 d5 7. O-O dxc4 8.
|
||||
Bxc4 a6 9. a3 Ba5 10. dxc5 Bxc3 11. bxc3 Qa5 12. a4 Nbd7 13. c6 bxc6 14.
|
||||
Qc2 c5 15. e4 Qc7 16. Re1 Ng4 17. Kh1 Re8 18. h3 Ngf6 19. e5 Nd5 20. Ng5
|
||||
Nf8 21. f4 Bb7 22. Ne4 Ng6 23. Qf2 Nb6 24. Bf1 Bxe4 25. Rxe4 Qc6 26. Qc2
|
||||
Nd5 27. a5 Red8 28. Kh2 Rab8 29. Rea4 Nge7 30. Bd3 Nf5 31. Bxf5 exf5 32.
|
||||
Qxf5 Nxc3 33. Rc4 1/2-1/2
|
||||
|
||||
[Event "?"]
|
||||
[Site "Moscow"]
|
||||
[Date "1973.??.??"]
|
||||
[Round "10"]
|
||||
[White "Petrosian,T"]
|
||||
[Black "Smyslov,V"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nc3 Bb4 4. e3 c5 5. Bd3 b6 6. Ne2 Nc6 7. O-O cxd4 8.
|
||||
exd4 Bb7 9. d5 Ne5 10. Bf4 Nxd3 11. Qxd3 exd5 12. cxd5 O-O 13. a3 Bxc3 14.
|
||||
Nxc3 Re8 15. Bd6 Ng4 16. Qg3 Nh6 17. Rfe1 Nf5 18. Qf4 Qf6 19. Be5 Qg6 20.
|
||||
Qa4 a6 21. Bf4 b5 22. Qb4 Rec8 23. Qe4 h5 24. Qd3 Rc4 25. Re4 Nh4 26. Bg3
|
||||
Rxe4 27. Nxe4 Nxg2 28. Kxg2 h4 29. Rd1 hxg3 30. hxg3 Rc8 31. f3 f5 1/2-1/2
|
||||
|
9
pgn-extract/test/infiles/test-evaluation.pgn
Normal file
9
pgn-extract/test/infiles/test-evaluation.pgn
Normal file
@@ -0,0 +1,9 @@
|
||||
[Event "?"]
|
||||
[Site "?"]
|
||||
[Date "????.??.??"]
|
||||
[Round "?"]
|
||||
[White "?"]
|
||||
[Black "?"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. f3 e5 2. g4 Qh4# 0-1
|
19
pgn-extract/test/infiles/test-f1.pgn
Normal file
19
pgn-extract/test/infiles/test-f1.pgn
Normal file
@@ -0,0 +1,19 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
9
pgn-extract/test/infiles/test-f2.pgn
Normal file
9
pgn-extract/test/infiles/test-f2.pgn
Normal file
@@ -0,0 +1,9 @@
|
||||
[Event "?"]
|
||||
[Site "?"]
|
||||
[Date "????.??.??"]
|
||||
[Round "?"]
|
||||
[White "?"]
|
||||
[Black "?"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. f3 e5 2. g4 Qh4# 0-1
|
19
pgn-extract/test/infiles/test-fencomments.pgn
Normal file
19
pgn-extract/test/infiles/test-fencomments.pgn
Normal file
@@ -0,0 +1,19 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
63
pgn-extract/test/infiles/test-fifty.pgn
Normal file
63
pgn-extract/test/infiles/test-fifty.pgn
Normal file
@@ -0,0 +1,63 @@
|
||||
[Event "Tilburg Wahls,M"]
|
||||
[Site "Tilburg NED"]
|
||||
[Date "1991.10.25"]
|
||||
[Round "7"]
|
||||
[White "Anatoly Karpov"]
|
||||
[Black "Garry Kasparov"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. d4 Nf6 2. c4 g6 3. Nc3 Bg7 4. e4 d6 5. Nf3 O-O 6. Be2 e5 7. O-O Nc6 8.
|
||||
d5 Ne7 9. Nd2 a5 10. Rb1 Nd7 11. a3 f5 12. b4 Kh8 13. f3 Ng8 14. Qc2 Ngf6
|
||||
15. Nb5 axb4 16. axb4 Nh5 17. g3 Ndf6 18. c5 Bd7 19. Rb3 Nxg3 20. hxg3 Nh5
|
||||
21. f4 exf4 22. c6 bxc6 23. dxc6 Nxg3 24. Rxg3 fxg3 25. cxd7 g2 26. Rf3
|
||||
Qxd7 27. Bb2 fxe4 28. Rxf8+ Rxf8 29. Bxg7+ Qxg7 30. Qxe4 Qf6 31. Nf3 Qf4
|
||||
32. Qe7 Rf7 33. Qe6 Rf6 34. Qe8+ Rf8 35. Qe7 Rf7 36. Qe6 Rf6 37. Qb3 g5 38.
|
||||
Nxc7 g4 39. Nd5 Qc1+ 40. Qd1 Qxd1+ 41. Bxd1 Rf5 42. Ne3 Rf4 43. Ne1 Rxb4
|
||||
44. Bxg4 h5 45. Bf3 d5 46. N3xg2 h4 47. Nd3 Ra4 48. Ngf4 Kg7 49. Kg2 Kf6
|
||||
50. Bxd5 Ra5 51. Bc6 Ra6 52. Bb7 Ra3 53. Be4 Ra4 54. Bd5 Ra5 55. Bc6 Ra6
|
||||
56. Bf3 Kg5 57. Bb7 Ra1 58. Bc8 Ra4 59. Kf3 Rc4 60. Bd7 Kf6 61. Kg4 Rd4 62.
|
||||
Bc6 Rd8 63. Kxh4 Rg8 64. Be4 Rg1 65. Nh5+ Ke6 66. Ng3 Kf6 67. Kg4 Ra1 68.
|
||||
Bd5 Ra5 69. Bf3 Ra1 70. Kf4 Ke6 71. Nc5+ Kd6 72. Nge4+ Ke7 73. Ke5 Rf1 74.
|
||||
Bg4 Rg1 75. Be6 Re1 76. Bc8 Rc1 77. Kd4 Rd1+ 78. Nd3 Kf7 79. Ke3 Ra1 80.
|
||||
Kf4 Ke7 81. Nb4 Rc1 82. Nd5+ Kf7 83. Bd7 Rf1+ 84. Ke5 Ra1 85. Ng5+ Kg6 86.
|
||||
Nf3 Kg7 87. Bg4 Kg6 88. Nf4+ Kg7 89. Nd4 Re1+ 90. Kf5 Rc1 91. Be2 Re1 92.
|
||||
Bh5 Ra1 93. Nfe6+ Kh6 94. Be8 Ra8 95. Bc6 Ra1 96. Kf6 Kh7 97. Ng5+ Kh8 98.
|
||||
Nde6 Ra6 99. Be8 Ra8 100. Bh5 Ra1 101. Bg6 Rf1+ 102. Ke7 Ra1 103. Nf7+ Kg8
|
||||
104. Nh6+ Kh8 105. Nf5 Ra7+ 106. Kf6 Ra1 107. Ne3 Re1 108. Nd5 Rg1 109. Bf5
|
||||
Rf1 110. Ndf4 Ra1 111. Ng6+ Kg8 112. Ne7+ Kh8 113. Ng5 Ra6+ 114. Kf7 Rf6+
|
||||
1/2-1/2
|
||||
|
||||
[Event "ch-ARM"]
|
||||
[Site "Yerevan ARM"]
|
||||
[Date "2001.09.13"]
|
||||
[Round "1"]
|
||||
[White "Smbat Gariginovich Lputian"]
|
||||
[Black "Gevorg Harutjunyan"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. d4 g6 2. c4 Bg7 3. Nc3 Nf6 4. e4 d6 5. Nf3 O-O 6. Be2 e5 7. O-O Nc6 8.
|
||||
d5 Ne7 9. b4 a5 10. bxa5 Rxa5 11. a4 b6 12. Nd2 Ra8 13. Nb3 Nd7 14. a5 Ba6
|
||||
15. axb6 cxb6 16. Bd2 Qb8 17. Ra4 f5 18. Qa1 Bb7 19. Rxa8 Bxa8 20. Qa3 Nc8
|
||||
21. f3 Bb7 22. Rb1 Rf7 23. Nc1 Nc5 24. Nd3 Qc7 25. Nxc5 dxc5 26. Qb2 Bf6
|
||||
27. Nb5 Qe7 28. Bc3 fxe4 29. fxe4 h5 30. Rd1 Bg7 31. d6 Qf6 32. Bf3 Rd7 33.
|
||||
Rf1 Qg5 34. h4 Qe3+ 35. Kh2 Qd3 36. Re1 Qxc4 37. Rd1 Qf7 38. Bxe5 Bc6 39.
|
||||
Bxg7 Qxg7 40. e5 Bxb5 41. Qb3+ Kh7 42. Re1 Na7 43. Kh1 Qf8 44. Qd5 Qd8 45.
|
||||
Qe4 Rg7 46. Qf4 Nc8 47. Bd5 Bd3 48. Be6 Na7 49. Rd1 Be2 50. Rd2 Bb5 51. Qf6
|
||||
Nc6 52. d7 Re7 53. Rd6 c4 54. Bf5 Nxe5 55. Bxg6+ Kg8 56. Bf5 Nf7 57. Qg6+
|
||||
Kf8 58. Rf6 Rxd7 59. Bxd7 Qxd7 60. Rxb6 Qe8 61. Qxh5 Qe1+ 62. Kh2 Be8 63.
|
||||
Qc5+ Kg7 64. Qxc4 Qe5+ 65. g3 Qf5 66. Qd4+ Kh7 67. Rf6 Qc2+ 68. Rf2 Qg6 69.
|
||||
g4 Nh6 70. Kg3 Bf7 71. Rf6 Qb1 72. Qe3 Qb8+ 73. Kh3 Bg6 74. Qe7+ Bf7 75.
|
||||
Rxf7+ Nxf7 76. Qxf7+ Kh8 77. Qf3 Qb1 78. h5 Qe1 79. g5 Qe6+ 80. Kg2 Kg7 81.
|
||||
Qb7+ Kh8 82. Qb8+ Kg7 83. Qc7+ Kh8 84. Qd8+ Kg7 85. Qd4+ Kg8 86. h6 Qe2+
|
||||
87. Kg3 Qe1+ 88. Kg4 Qe2+ 89. Kg3 Qe1+ 90. Qf2 Qe5+ 91. Qf4 Qe1+ 92. Kg2
|
||||
Qe2+ 93. Kh3 Qe6+ 94. Kh4 Qe1+ 95. Kh5 Qe2+ 96. Kh4 Qe1+ 97. Kg4 Qe6+ 98.
|
||||
Qf5 Qe2+ 99. Qf3 Qe6+ 100. Kh4 Qe1+ 101. Kh3 Qe6+ 102. Kg2 Qe5 103. Qb3+
|
||||
Kh8 104. Qg3 Qe2+ 105. Kg1 Qd1+ 106. Kf2 Qd2+ 107. Kf3 Qd3+ 108. Kf4 Qd6+
|
||||
109. Kg4 Qe6+ 110. Kh5 Qe2+ 111. Kh4 Qe4+ 112. Kh3 Qh1+ 113. Kg4 Qe4+ 114.
|
||||
Qf4 Qe6+ 115. Kh4 Qe1+ 116. Kh5 Qe2+ 117. Kg6 Qe8+ 118. Qf7 Qe4+ 119. Qf5
|
||||
Qe8+ 120. Kf6 Qf7+ 121. Ke5 Qe7+ 122. Kf4 Qb4+ 123. Qe4 Qd2+ 124. Kg4 Qd7+
|
||||
125. Kh4 Qf7 126. Qd4+ Kh7 127. Qd3+ Kh8 128. Qc3+ Kh7 129. Qd4 Kg8 130.
|
||||
Qd3 Kh8 131. Kg3 Qc7+ 132. Kg4 Qc8+ 133. Kh4 Qb7 134. Qc3+ Kh7 135. Qd3+
|
||||
Kh8 136. Qd4+ Kh7 137. Kg3 Qb3+ 138. Kh4 Qf7 139. Qe4+ Kh8 140. Kg3 Qc7+
|
||||
141. Qf4 Qf7 142. Qf6+ 1-0
|
||||
|
81
pgn-extract/test/infiles/test-fixresulttags-in.pgn
Normal file
81
pgn-extract/test/infiles/test-fixresulttags-in.pgn
Normal file
@@ -0,0 +1,81 @@
|
||||
[Event "65th ch-ARG w 2013"]
|
||||
[Site "Villa Martelli ARG"]
|
||||
[Date "2013.04.07"]
|
||||
[Round "3.1"]
|
||||
[White "Acosta,Florencia"]
|
||||
[Black "Fernandez,Maria"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c5 2. Nf3 d6 3. d4 cxd4 4. Nxd4 Nf6 5. f3 g6 6. c4 Bg7 7. Nc3 O-O 8.
|
||||
Be2 Nc6 9. Nc2 Be6 10. Be3 Rc8 11. O-O Na5 12. b3 a6 13. Qd2 b5 14. e5 Nd7
|
||||
15. cxb5 Bxe5 16. Bd4 axb5 17. Bxb5 Nc6 18. Rad1 Nxd4 19. Nxd4 Nf6 20. f4
|
||||
Bxd4+ 21. Qxd4 Rxc3 22. Qxc3 Qb6+ 23. Kh1 Qxb5 24. Rfe1 Rc8 25. Qb2 Qf5 26.
|
||||
Rd4 Rc2 27. Qb1 Ng4 28. a4 Nxh2 29. Rde4 Nf3 30. Qxc2 Qh5# 1-0
|
||||
|
||||
[Event "TCh-NED Meesterklasse 2012-13"]
|
||||
[Site "Netherland NED"]
|
||||
[Date "2013.04.06"]
|
||||
[Round "8.5"]
|
||||
[White "Geurink,J"]
|
||||
[Black "Bosch,Je"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 e5 2. Nf3 Nc6 3. Bc4 Be7 4. d3 Nf6 5. O-O d6 6. a4 O-O 7. Re1 Kh8 8.
|
||||
d4 exd4 9. Nxd4 Nxd4 10. Qxd4 Ng4 11. Be2 Ne5 12. Nc3 f5 13. exf5 Bxf5 14.
|
||||
Nd5 Bf6 15. Nxf6 Qxf6 16. Be3 Bxc2 17. f4 Nc6 18. Qxf6 gxf6 19. Bf3 Rae8
|
||||
20. Bf2 Kg7 21. Bh5 Rxe1+ 22. Rxe1 Bxa4 23. Re3 Bc2 24. Rg3+ Kh8 25. Bf3 a6
|
||||
26. Bd5 Bf5 27. Rc3 Bd7 28. Bh4 h5 29. Rg3 Kh7 30. Rb3 Nd8 31. Re3 Bc6 32.
|
||||
Re7+ Kg6 33. Bb3 f5 34. Rxc7 Re8 35. Bxd8 Rxd8 36. Bf7+ Kh6 37. Be6 Be4 38.
|
||||
Kf2 Re8 39. Bf7 Rf8 40. g3 a5 41. Ke3 Ra8 42. Bc4 b5 43. Bxb5 Rb8 44. Bc6
|
||||
Rb3+ 45. Kd4 Rd3+ 46. Kc4 d5+ 47. Kb5 Rb3+ 48. Kxa5 Rxb2 49. Rd7 Rxh2 50.
|
||||
Bxd5 Bxd5 51. Rxd5 Kg6 52. Rd6+ Kf7 53. Kb4 h4 54. gxh4 Rxh4 55. Kc3 Rxf4
|
||||
56. Kd3 Re4 57. Ra6 Re8 58. Rb6 Kg7 59. Ra6 Re4 60. Rb6 Kf7 61. Ra6 Re6 62.
|
||||
Rxe6 Kxe6 63. Ke3 Ke5 64. Kf3 f4 65. Kf2 Ke4 66. Ke2 f3+ 67. Kf2 Kf4 68.
|
||||
Kf1 Kg3 69. Kg1 f2+ 70. Kf1 Kf3 0-1
|
||||
|
||||
[Event "48th Capablanca Open II 2013"]
|
||||
[Site "Havana CUB"]
|
||||
[Date "2013.04.28"]
|
||||
[Round "7.53"]
|
||||
[White "Rodriguez Caballero,M"]
|
||||
[Black "Torres Larco,Denisse"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 e5 2. Nf3 Nc6 3. d4 exd4 4. Nxd4 Nf6 5. Nc3 Bb4 6. Nxc6 bxc6 7. Bd3
|
||||
d5 8. exd5 cxd5 9. O-O O-O 10. Bg5 c6 11. Qf3 Be7 12. Rfe1 Be6 13. h3 Rb8
|
||||
14. Rab1 h6 15. Bf4 Bd6 16. Ne2 c5 17. c3 Qc7 18. Bxh6 gxh6 19. Qxf6 Rb6
|
||||
20. Qxh6 Bf5 21. Qg5+ Bg6 22. Bxg6 Bh2+ 23. Kh1 Rxg6 24. Qxd5 Rd8 25. Qf3
|
||||
Be5 26. Rbd1 Rb8 27. Nc1 c4 28. Rd5 Bf4 29. Ne2 Bh6 30. Ng3 Rxb2 31. Re8+
|
||||
Kh7 32. Rdd8 Bg7 33. Qh5+ Rh6 34. Qf5+ Rg6 35. Rd7 Qc6 36. Ne4 Rxf2 37.
|
||||
Ng5+ Kh6 38. Nxf7+ Kh7 39. Qh5+ Rh6 40. Ng5# 1/2-1/2
|
||||
|
||||
[Event "41st TCh-GRE"]
|
||||
[Site "Rio (Achaia) GRE"]
|
||||
[Date "2013.07.02"]
|
||||
[Round "1.8"]
|
||||
[White "Papakonstantinou,Di1"]
|
||||
[Black "Palaskos,M"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. e5 Nfd7 7. d4 Qb6
|
||||
8. e6 fxe6 9. Qg4 g6 10. Bd3 Bg7 11. Ne2 e5 12. c3 O-O 13. h4 c5 14. h5 e4
|
||||
15. Bc2 e5 16. Bb3 c4 17. Ba4 Nf6 18. Qh4 Nbd7 19. hxg6 hxg6 20. Qg5 Qe6
|
||||
21. Qxg6 Qf7 22. Qg3 exd4 23. cxd4 a6 24. Bh6 b5 25. Bc2 Rac8 26. Nf4 Rc6
|
||||
27. Rh4 Re8 28. Ke2 Nf8 29. Rah1 Re7 30. Bg5 N8h7 31. Bxf6 Rxf6 32. Rxh7
|
||||
Rxf4 33. Rh8# 0-1
|
||||
|
||||
[Event "100th ch-GBR 2013"]
|
||||
[Site "Torquay ENG"]
|
||||
[Date "2013.08.01"]
|
||||
[Round "4.38"]
|
||||
[White "Hegarty,S"]
|
||||
[Black "Armstrong,M"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 e6 2. d4 d5 3. Nc3 Nf6 4. Bg5 Be7 5. e5 Nfd7 6. Bxe7 Qxe7 7. Bd3 a6
|
||||
8. f4 c5 9. Nf3 Nc6 10. dxc5 Nxc5 11. O-O Nxd3 12. cxd3 Bd7 13. d4 O-O 14.
|
||||
Rc1 Rac8 15. Qd3 f6 16. Rce1 f5 17. Kh1 Nd8 18. Rg1 Nf7 19. g4 fxg4 20.
|
||||
Rxg4 Nh6 21. Ng5 Nf5 22. Reg1 Qb4 23. Nxh7 Qxb2 24. Nd1 Qb5 25. Qh3 Kf7 26.
|
||||
Nxf8 Rxf8 27. Ne3 Qd3 28. Qh5+ Kg8 29. Ng2 Qxd4 30. h3 Rc8 31. Qg5 Qd3 32.
|
||||
Kh2 d4 33. Nh4 Rc2+ 34. R4g2 Rc3 35. Qg4 Bc6 36. Nxf5 Bxg2 37. Qxg7#
|
||||
1/2-1/2
|
4
pgn-extract/test/infiles/test-fuzzydepth.pgn
Normal file
4
pgn-extract/test/infiles/test-fuzzydepth.pgn
Normal file
@@ -0,0 +1,4 @@
|
||||
e4 e5 Nf3 Nc6 Bb5 *
|
||||
Nf3 Nc6 e4 e5 { Match game 1 at 4 ply. } Bc4 *
|
||||
e4 e5 Nf3 { Match game 1 at 3 and 4 ply. } Nc6 d4 *
|
||||
e4 e5 Bb5 Nc6 Nf3 { Match game 1 at 5 ply. } *
|
597
pgn-extract/test/infiles/test-hash.pgn
Normal file
597
pgn-extract/test/infiles/test-hash.pgn
Normal file
@@ -0,0 +1,597 @@
|
||||
[Event "Milwaukee Northwestern"]
|
||||
[Site "?"]
|
||||
[Date "1957"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Kampars, N."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 e6 6. d4 Nd7 7. Bd3 dxe4
|
||||
8. Nxe4 Ngf6 9. O-O Nxe4 10. Qxe4 Nf6 11. Qe3 Nd5 12. Qf3 Qf6 13. Qxf6 Nxf6
|
||||
14. Rd1 O-O-O 15. Be3 Nd5 16. Bg5 Be7 17. Bxe7 Nxe7 18. Be4 Nd5 19. g3 Nf6
|
||||
20. Bf3 Kc7 21. Kf1 Rhe8 22. Be2 e5 23. dxe5 Rxe5 24. Bc4 Rxd1+ 25. Rxd1
|
||||
Re7 26. Bb3 Ne4 27. Rd4 Nd6 28. c3 f6 29. Bc2 h6 30. Bd3 Nf7 31. f4 Rd7 32.
|
||||
Rxd7+ Kxd7 33. Kf2 Nd6 34. Kf3 f5 35. Ke3 c5 36. Be2 Ke6 37. Bd3 1/2-1/2
|
||||
|
||||
[Event "US Open"]
|
||||
[Site "?"]
|
||||
[Date "1957"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Addison, William G."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 dxe4 4. Nxe4 Nf6 5. Nxf6+ exf6 6. Bc4 Bd6 7. Qe2+
|
||||
Qe7 8. Qxe7+ Kxe7 9. d4 Bf5 10. Bb3 Re8 11. Be3 Kf8 12. O-O-O Nd7 13. c4
|
||||
Rad8 14. Bc2 Bxc2 15. Kxc2 f5 16. Rhe1 f4 17. Bd2 Nf6 18. Ne5 g5 19. f3 Nh5
|
||||
20. Ng4 Kg7 21. Bc3 Kg6 22. Rxe8 Rxe8 23. c5 Bb8 24. d5 cxd5 25. Rxd5 f5
|
||||
26. Ne5+ Bxe5 27. Rxe5 Nf6 28. Rxe8 Nxe8 29. Be5 Kh5 30. Kd3 g4 31. b4 a6
|
||||
32. a4 gxf3 33. gxf3 Kh4 34. b5 axb5 35. a5 Kh3 36. c6 1-0
|
||||
|
||||
[Event "West Orange Open"]
|
||||
[Site "?"]
|
||||
[Date "1957"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Goldsmith, Julius"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d6 3. d4 Nd7 4. Nf3 e5 5. Bc4 Be7 6. dxe5 Nxe5 7. Nxe5 dxe5
|
||||
8. Qh5 g6 9. Qxe5 Nf6 10. Bg5 Bd7 11. O-O-O O-O 12. Rxd7 Qxd7 13. Bxf6 Bxf6
|
||||
14. Qxf6 Rae8 15. f3 Qc7 16. h4 Qe5 17. Qxe5 Rxe5 18. Rd1 Re7 19. Rd6 Kg7
|
||||
20. a3 f5 21. Kd2 fxe4 22. Nxe4 Rf4 23. h5 gxh5 24. Rd8 h4 25. Rg8+ Kh6 26.
|
||||
Ke3 Rf5 27. Rg4 Rh5 28. Kf2 Rg7 29. Rxg7 Kxg7 30. Bf1 Rd5 31. Bd3 h6 32.
|
||||
Ke3 Rh5 33. Nd6 h3 34. gxh3 Rxh3 35. Nxb7 Rh5 36. b4 Re5+ 37. Kf4 Re7 38.
|
||||
Nd8 c5 39. bxc5 Kf6 40. c6 Rc7 41. Be4 Ke7 42. Nb7 Kf6 43. Nd6 Re7 44. c7
|
||||
1-0
|
||||
|
||||
[Event "Bad Portoroz Interzonal"]
|
||||
[Site "?"]
|
||||
[Date "1958"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Cardoso, Rudolfo T."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 dxe4 4. Nxe4 Bg4 5. h3 Bxf3 6. Qxf3 Nd7 7. Ng5
|
||||
Ngf6 8. Qb3 e6 9. Qxb7 Nd5 10. Ne4 Nb4 11. Kd1 f5 12. c3 Rb8 13. Qxa7 fxe4
|
||||
14. cxb4 Bxb4 15. Qd4 O-O 16. Bc4 Nc5 17. Qxd8 Rbxd8 18. Rf1 Rd4 19. b3
|
||||
Bxd2 20. Ke2 Bxc1 21. Raxc1 Rfd8 22. Rfd1 Kf8 23. Rxd4 Rxd4 24. Rd1 Rxd1
|
||||
25. Kxd1 Ke7 26. Kd2 Kd6 27. Kc3 Nd7 28. Kd4 Nf6 29. a4 c5+ 30. Ke3 g5 31.
|
||||
Be2 Kc6 32. Bc4 e5 33. a5 h6 34. Kd2 h5 35. Ke3 h4 36. Be2 Kb7 37. Bc4 Kc6
|
||||
38. Ke2 Kb7 39. Kd2 Kc6 40. Ke3 Kb7 41. Kd2 Kc7 42. g4 Kc6 43. Kc3 Ne8 44.
|
||||
b4 Nd6 45. Bf1 cxb4+ 46. Kxb4 Nc8 47. Bg2 Kd5 48. a6 Na7 49. Ka5 Kc5 50.
|
||||
Bxe4 Nb5 51. Bg2 Na7 52. Ka4 Nb5 53. Kb3 Kb6 54. Kc4 Kxa6 55. Kd5 Kb6 56.
|
||||
Kxe5 Kc7 57. Kf6 Nc3 58. Kxg5 Nd1 59. f4 Kd6 60. Kxh4 Ke6 61. Kg5 Kf7 62.
|
||||
f5 1-0
|
||||
|
||||
[Event "USA Championship"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Weinstein, Raymond"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Be7 8.
|
||||
Bg2 dxe4 9. dxe4 e5 10. O-O Nbd7 11. Nd1 O-O 12. Ne3 g6 13. Rd1 Qc7 14. Ng4
|
||||
h5 15. Nxf6+ Nxf6 16. Bg5 Nh7 17. Bh6 Rfd8 18. Bf1 Bg5 19. Bxg5 Nxg5 20.
|
||||
Qe3 Qe7 21. h4 Ne6 22. Bc4 b5 23. Bxe6 Qxe6 24. Qc5 Qc4 25. Qxc4 bxc4 26.
|
||||
b3 Rd4 27. Rxd4 exd4 28. Kf1 Re8 29. f3 Re5 30. Rd1 c5 31. c3 dxc3 32. Rc1
|
||||
f5 33. exf5 Rxf5 34. Rxc3 cxb3 35. Rxb3 c4 36. Ra3 Rc5 37. Ke2 c3 38. Kd1
|
||||
c2+ 39. Kc1 a5 40. Rb3 Kg7 41. Rb7+ Kf6 42. Rb6+ Kg7 43. g4 1/2-1/2
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Benko, Pal"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Qb6 10. b3 a5 11. a3 Bxd2+ 12. Nxd2 Qc5 13. Qd1 h5 14. h4
|
||||
Nbd7 15. Bg2 Ng4 16. O-O g5 17. b4 Qe7 18. Nf3 gxh4 19. Nxh4 Nde5 20. Qd2
|
||||
Rg8 21. Qf4 f6 22. bxa5 Rxa5 23. Rfb1 b5 24. Nf3 Ra4 25. Bh3 Nxf3+ 26. Qxf3
|
||||
Kd7 27. Kg2 Qg7 28. Rb4 Rga8 29. Rxa4 Rxa4 30. Bxg4 hxg4 31. Qf4 Ra8 32.
|
||||
Rh1 Rg8 33. a4 bxa4 34. Rb1 e5 35. Rb7+ Kd6 36. Rxg7 exf4 37. Rxg8 f3+ 38.
|
||||
Kh1 Kc5 39. Rb8 1-0
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Keres, Paul"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Qb6 10. b3 Nbd7 11. Bg2 a5 12. a3 Bxd2+ 13. Nxd2 Qc5 14. Qd1
|
||||
h5 15. Nf3 Qc3+ 16. Ke2 Qc5 17. Qd2 Ne5 18. b4 Nxf3 19. Bxf3 Qe5 20. Qf4
|
||||
Nd7 21. Qxe5 Nxe5 22. bxa5 Kd7 23. Rhb1 Kc7 24. Rb4 Rxa5 25. Bg2 g5 26. f4
|
||||
gxf4 27. gxf4 Ng6 28. Kf3 Rg8 29. Bf1 e5 30. fxe5 Nxe5+ 31. Ke2 c5 32. Rb3
|
||||
b6 33. Rab1 Rg6 34. h4 Ra6 35. Bh3 Rg3 36. Bf1 Rg4 37. Bh3 Rxh4 38. Rh1 Ra8
|
||||
39. Rbb1 Rg8 40. Rbf1 Rg3 41. Bf5 Rg2+ 42. Kd1 Rhh2 43. Rxh2 Rxh2 44. Rg1
|
||||
c4 45. dxc4 Nxc4 46. Rg7 Kd6 47. Rxf7 Ne3+ 48. Kc1 Rxc2+ 49. Kb1 Rh2 50.
|
||||
Rd7+ Ke5 51. Re7+ Kf4 52. Rd7 Nd1 53. Kc1 Nc3 54. Bh7 h4 55. Rf7+ Ke3 0-1
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Keres, Paul"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Qb6 10. b3 a5 11. a3 Be7 12. Bg2 a4 13. b4 Nbd7 14. O-O c5
|
||||
15. Ra2 O-O 16. bxc5 Bxc5 17. Qe2 e5 18. f4 Rfc8 19. h4 Rc6 20. Bh3 Qc7 21.
|
||||
fxe5 Nxe5 22. Bf4 Bd6 23. h5 Ra5 24. h6 Ng6 25. Qf3 Rh5 26. Bg4 Nxf4 27.
|
||||
Bxh5 N4xh5 28. g4 Bh2+ 29. Kg2 Nxg4 30. Nd2 Ne3+ 0-1
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Olafsson, Fridrik"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Nf6 4. e5 Ne4 5. Ne2 Qb6 6. d4 c5 7. dxc5 Qxc5 8.
|
||||
Ned4 Nc6 9. Bb5 a6 10. Bxc6+ bxc6 11. O-O Qb6 12. e6 fxe6 13. Bf4 g6 14.
|
||||
Be5 Nf6 15. Ng5 Bh6 16. Ndxe6 Bxg5 17. Nxg5 O-O 18. Qd2 Bf5 19. Rae1 Rad8
|
||||
20. Bc3 Rd7 21. Ne6 Bxe6 22. Rxe6 d4 23. Bb4 Nd5 24. Ba3 Rf7 25. g3 Nc7 26.
|
||||
Re5 Nd5 27. Qd3 Nf6 28. Qc4 Ng4 29. Re6 Qb5 30. Qxb5 axb5 31. Rxc6 Ne5 32.
|
||||
Rc8+ Kg7 33. Bb4 Nf3+ 34. Kg2 e5 35. Rd1 g5 36. Bf8+ Rxf8 37. Rxf8 Kxf8 38.
|
||||
Kxf3 Kf7 39. c3 Ke6 40. cxd4 exd4 41. Ke4 Rf7 42. f3 1-0
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Bxd2+ 10. Nxd2 e5 11. Bg2 c5 12. O-O Nc6 13. Qe2 g5 14. Nf3
|
||||
h6 15. h4 Rg8 16. a3 Qe7 17. hxg5 hxg5 18. Qd2 Nd7 19. c3 O-O-O 20. cxd4
|
||||
exd4 21. b4 Kb8 22. Rfc1 Nce5 23. Nxe5 Qxe5 24. Rc4 Rc8 25. Rac1 g4 26. Qb2
|
||||
Rgd8 27. a4 Qe7 28. Rb1 Ne5 29. Rxc5 Rxc5 30. bxc5 Nxd3 31. Qd2 Nxc5 32.
|
||||
Qf4+ Qc7 33. Qxg4 Nxa4 34. e5 Nc5 35. Qf3 d3 36. Qe3 d2 37. Bf3 Na4 38. Qe4
|
||||
Nc5 39. Qe2 a6 40. Kg2 Ka7 41. Qe3 Rd3 42. Qf4 Qd7 43. Qc4 b6 44. Rd1 a5
|
||||
45. Qf4 Rd4 46. Qh6 b5 47. Qe3 Kb6 48. Qh6+ Ne6 49. Qe3 Ka6 50. Be2 a4 51.
|
||||
Qc3 Kb6 52. Qe3 Nc5 53. Bf3 b4 54. Qh6+ Ne6 55. Qh8 Qd8 56. Qh7 Qd7 57. Qh8
|
||||
b3 58. Qb8+ Ka5 59. Qa8+ Kb5 60. Qb8+ Kc4 61. Qg8 Kc3 62. Bh5 Nd8 63. Bf3
|
||||
a3 64. Qf8 Kb2 65. Qh8 Ne6 66. Qa8 a2 67. Qa5 Qa4 68. Rxd2+ Ka3 0-1
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Bxd2+ 10. Nxd2 e5 11. Bg2 c5 12. O-O Nc6 13. Qe2 Qe7 14. f4
|
||||
O-O-O 15. a3 Ne8 16. b4 cxb4 17. Nc4 f6 18. fxe5 fxe5 19. axb4 Nc7 20. Na5
|
||||
Nb5 21. Nxc6 bxc6 22. Rf2 g6 23. h4 Kb7 24. h5 Qxb4 25. Rf7+ Kb6 26. Qf2 a5
|
||||
27. c4 Nc3 28. Rf1 a4 29. Qf6 Qc5 30. Rxh7 Rdf8 31. Qxg6 Rxf1+ 32. Bxf1
|
||||
Rxh7 33. Qxh7 a3 34. h6 a2 35. Qg8 a1=Q 36. h7 Qd6 37. h8=Q Qa7 38. g4 Kc5
|
||||
39. Qf8 Qae7 40. Qa8 Kb4 41. Qh2 Kb3 42. Qa1 Qa3 43. Qxa3+ Kxa3 44. Qh6 Qf7
|
||||
45. Kg2 Kb3 46. Qd2 Qh7 47. Kg3 Qxe4 48. Qf2 Qh1 1/2-1/2
|
||||
|
||||
[Event "Yugoslavia Candidate Trn"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Smyslov, Vasily V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bh5 5. exd5 cxd5 6. Bb5+ Nc6 7. g4 Bg6
|
||||
8. Ne5 Rc8 9. h4 f6 10. Nxg6 hxg6 11. d4 e6 12. Qd3 Kf7 13. h5 gxh5 14.
|
||||
gxh5 Nge7 15. Be3 Nf5 16. Bxc6 Rxc6 17. Ne2 Qa5+ 18. c3 Qa6 19. Qc2 Bd6 20.
|
||||
Bf4 Bxf4 21. Nxf4 Rh6 22. Qe2 Qxe2+ 23. Kxe2 Rh8 24. Kd3 b5 25. Rhe1 b4 26.
|
||||
cxb4 Rc4 27. Nxe6 Rxh5 28. b3 Rh3+ 29. Kd2 Rcc3 30. Nf4 Rhf3 31. Re2 g5 32.
|
||||
Nxd5 Rcd3+ 33. Kc1 Rxd4 34. Ne3 Nxe3 35. fxe3 Rxb4 36. Kd2 g4 37. Rc1 Rb7
|
||||
38. Rg1 Rd7+ 39. Kc2 f5 40. e4 Kf6 41. exf5 g3 42. Re8 Rg7 43. Rf8+ Ke7 44.
|
||||
Ra8 Kd6 45. Rf8 Rf2+ 46. Kd3 g2 47. f6 Rg3+ 48. Kc4 Ke6 49. Re1+ Kf5 50. f7
|
||||
Rg7 51. Rg1 Kf6 52. a4 Rxf7 1/2-1/2
|
||||
|
||||
[Event "Zurich"]
|
||||
[Site "?"]
|
||||
[Date "1959"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Larsen, Bent"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nf3 d5 3. Nc3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. a3 Bc5 8.
|
||||
Be2 O-O 9. O-O Nbd7 10. Qg3 Bd4 11. Bh6 Ne8 12. Bg5 Ndf6 13. Bf3 Qd6 14.
|
||||
Bf4 Qc5 15. Rab1 dxe4 16. dxe4 e5 17. Bg5 Bxc3 18. bxc3 b5 19. c4 a6 20.
|
||||
Bd2 Qe7 21. Bb4 Nd6 22. Rfd1 Rfd8 23. cxb5 cxb5 24. Rd3 Qe6 25. Rbd1 Nb7
|
||||
26. Bc3 Rxd3 27. cxd3 Re8 28. Kh2 h6 29. d4 Nd6 30. Re1 Nc4 31. dxe5 Nxe5
|
||||
32. Bd1 Ng6 33. e5 Nd5 34. Bb3 Qc6 35. Bb2 Ndf4 36. Rd1 a5 37. Rd6 Qe4 38.
|
||||
Rd7 Ne6 39. Bd5 Qe2 40. Bc3 b4 41. axb4 axb4 42. Bxb4 Qxe5 43. Ba5 Qxg3+
|
||||
44. Kxg3 Re7 45. Rd6 Nef4 46. Bf3 Ne6 47. Bb6 Ne5 48. Bd5 Rd7 49. Rxd7 Nxd7
|
||||
50. Be3 Nf6 51. Bc6 g5 52. Kf3 Kg7 53. Ba4 Nd5 54. Bc1 h5 55. Bb2+ Kh6 56.
|
||||
Bb3 Ndf4 57. Bc2 Ng6 58. Kg3 Nef4 59. Be4 Nh4 60. Bf6 Nhg6 61. Kf3 Nh4+ 62.
|
||||
Kg3 Nhg6 63. Kh2 h4 64. Kg1 Nh5 65. Bc3 Ngf4 66. Kf1 Ng7 67. Bf6 Nfh5 68.
|
||||
Be5 f6 69. Bd6 f5 70. Bf3 Nf4 71. Ke1 Kg6 72. Kd2 Nge6 73. Be5 Nc5 74. Ke3
|
||||
Nce6 75. Bc6 Kf7 76. Kf3 Ke7 77. Bb7 Ng6 78. Bc3 Ngf4 79. Ba6 Nd5 80. Be5
|
||||
Nf6 81. Bd3 g4+ 82. Ke2 Nd7 83. Bh2 gxh3 84. gxh3 Kf6 85. Ke3 Ne5 86. Be2
|
||||
Ng6 87. Bf1 f4+ 88. Kf3 Ne5+ 89. Ke4 Ng5+ 90. Kxf4 Nef3 91. Bg3 hxg3 92.
|
||||
fxg3 1/2-1/2
|
||||
|
||||
[Event "Buenos Aires"]
|
||||
[Site "?"]
|
||||
[Date "1960"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Foguelman, Alberto"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Bf5 5. Ng3 Bg6 6. Nh3 Nf6 7. Nf4 e5
|
||||
8. dxe5 Qxd1+ 9. Kxd1 Ng4 10. Nxg6 hxg6 11. Ne4 Nxe5 12. Be2 f6 13. c3 Nbd7
|
||||
14. Be3 O-O-O 15. Kc2 Nb6 16. h4 Nec4 17. Bf4 Nd5 18. Bg3 Nd6 19. Nxd6+
|
||||
Bxd6 20. Bxd6 Rxd6 21. g3 Kc7 22. c4 Nb4+ 23. Kc3 c5 24. a3 Re8 25. Bf1 Nc6
|
||||
26. Bd3 Ne5 27. Be4 Ng4 28. Bxg6 Re2 29. Rae1 Rxf2 30. Re7+ Kb6 31. Be4 Re2
|
||||
32. Rxb7+ Ka6 33. Re7 Kb6 34. b4 Nf2 35. Rb7+ Ka6 36. b5+ Ka5 37. Rxa7+ Kb6
|
||||
38. Ra6+ Kc7 39. b6+ Rxb6 40. Rxb6 Nxe4+ 41. Kd3 Kxb6 42. Rg1 Rd2+ 43. Kxe4
|
||||
Rd4+ 44. Kf5 Rxc4 45. Re1 Rc3 46. g4 Rf3+ 47. Kg6 Rxa3 48. Kxg7 Rg3 49. Re4
|
||||
f5 50. Re6+ Kb5 51. g5 Rg4 52. g6 Rxh4 53. Kf7 c4 54. g7 Rh7 55. Rg6 c3 56.
|
||||
Kf6 Rxg7 57. Rxg7 Kc4 58. Kxf5 c2 1/2-1/2
|
||||
|
||||
[Event "Buenos Aires"]
|
||||
[Site "?"]
|
||||
[Date "1960"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Ivkov, Boris"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. c4 Nf6 5. Nc3 e6 6. Nf3 Be7 7. c5 O-O 8.
|
||||
b4 b6 9. Bd3 bxc5 10. bxc5 Nc6 11. O-O Bd7 12. h3 Ne8 13. Bf4 Bf6 14. Bb5
|
||||
Nc7 15. Be2 Nxd4 16. Nxd4 e5 17. c6 Be8 18. Bg3 exd4 19. Bxc7 Qxc7 20. Nxd5
|
||||
Qd6 21. Nxf6+ Qxf6 22. c7 Rc8 23. Rc1 Bc6 24. Rc4 Rxc7 25. Bd3 Rd7 26. Qc2
|
||||
Bd5 27. Ra4 g6 28. Qc5 Rfd8 29. Bb5 Rd6 30. Rd1 Be6 31. Bd3 Rd5 32. Qxa7
|
||||
Bxh3 33. Be4 R5d7 34. Qa6 Qxa6 35. Rxa6 Be6 36. a4 d3 37. Rd2 Rd4 38. f3
|
||||
Bd5 39. Bxd5 R8xd5 40. Kf2 Rc4 41. a5 Ra4 42. Rc6 Ra3 43. Rc1 h5 44. Rcd1
|
||||
Kg7 45. a6 g5 46. a7 Rxa7 47. Rxd3 Ra2+ 48. Kg1 Rxd3 49. Rxd3 Kg6 50. Kh2
|
||||
Ra4 51. Rd5 g4 52. fxg4 hxg4 53. g3 Kf6 54. Rd7 Ke5 55. Kg2 f5 56. Rd2 Rc4
|
||||
57. Re2+ Kd4 58. Rf2 Rc5 59. Rf4+ Ke3 60. Kg1 1/2-1/2
|
||||
|
||||
[Event "Leipzig Olympiad Final"]
|
||||
[Site "?"]
|
||||
[Date "1960"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Euwe, Max"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. c4 Nf6 5. Nc3 Nc6 6. Nf3 Bg4 7. cxd5 Nxd5
|
||||
8. Qb3 Bxf3 9. gxf3 e6 10. Qxb7 Nxd4 11. Bb5+ Nxb5 12. Qc6+ Ke7 13. Qxb5
|
||||
Nxc3 14. bxc3 Qd7 15. Rb1 Rd8 16. Be3 Qxb5 17. Rxb5 Rd7 18. Ke2 f6 19. Rd1
|
||||
Rxd1 20. Kxd1 Kd7 21. Rb8 Kc6 22. Bxa7 g5 23. a4 Bg7 24. Rb6+ Kd5 25. Rb7
|
||||
Bf8 26. Rb8 Bg7 27. Rb5+ Kc6 28. Rb6+ Kd5 29. a5 f5 30. Bb8 Rc8 31. a6 Rxc3
|
||||
32. Rb5+ Kc4 33. Rb7 Bd4 34. Rc7+ Kd3 35. Rxc3+ Kxc3 36. Be5 1-0
|
||||
|
||||
[Event "Bled"]
|
||||
[Site "?"]
|
||||
[Date "1961"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Keres, Paul"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d4 dxe4 7. Qe3 Nbd7
|
||||
8. Nxe4 Nxe4 9. Qxe4 Nf6 10. Qd3 Qd5 11. c4 Qd6 12. Be2 e5 13. d5 e4 14.
|
||||
Qc2 Be7 15. dxc6 Qxc6 16. O-O O-O 17. Be3 Bc5 18. Qc3 b6 19. Rfd1 Rfd8 20.
|
||||
b4 Bxe3 21. fxe3 Qc7 22. Rd4 a5 23. a3 axb4 24. axb4 h5 25. Rad1 Rxd4 26.
|
||||
Qxd4 Qg3 27. Qxb6 Ra2 28. Bf1 h4 29. Qc5 Qf2+ 30. Kh1 g6 31. Qe5 Kg7 32. c5
|
||||
Qxe3 33. c6 Rc2 34. b5 Rc1 35. Rxc1 Qxc1 36. Kg1 e3 37. c7 e2 38. Qxe2 Qxc7
|
||||
39. Qf2 g5 40. b6 Qe5 41. b7 Nd7 42. Qd2 Nb8 43. Be2 Kf6 44. Bf3 Ke6 45.
|
||||
Bg4+ f5 46. Bd1 Kf6 47. Qd8+ Kg6 48. Qg8+ Kh6 49. Qf8+ Kg6 50. Qg8+ Kh6 51.
|
||||
Qf8+ Kg6 52. Qb4 Nc6 53. Qd2 Nd8 54. Bf3 Nxb7 55. Bxb7 Qa1+ 56. Kh2 Qe5+
|
||||
1/2-1/2
|
||||
|
||||
[Event "Bled"]
|
||||
[Site "?"]
|
||||
[Date "1961"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Nd7 5. Nf3 Ngf6 6. Nxf6+ Nxf6 7. Bc4
|
||||
Bf5 8. Qe2 e6 9. Bg5 Bg4 10. O-O-O Be7 11. h3 Bxf3 12. Qxf3 Nd5 13. Bxe7
|
||||
Qxe7 14. Kb1 Rd8 15. Qe4 b5 16. Bd3 a5 17. c3 Qd6 18. g3 b4 19. c4 Nf6 20.
|
||||
Qe5 c5 21. Qg5 h6 22. Qxc5 Qxc5 23. dxc5 Ke7 24. c6 Rd6 25. Rhe1 Rxc6 26.
|
||||
Re5 Ra8 27. Be4 Rd6 28. Bxa8 Rxd1+ 29. Kc2 Rf1 30. Rxa5 Rxf2+ 31. Kb3 Rh2
|
||||
32. c5 Kd8 33. Rb5 Rxh3 34. Rb8+ Kc7 35. Rb7+ Kc6 36. Kc4 1-0
|
||||
|
||||
[Event "Stockholm Interzonal"]
|
||||
[Site "?"]
|
||||
[Date "1962"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Barcza, Gedeon"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 dxe4 4. Nxe4 Nf6 5. Nxf6+ exf6 6. d4 Bd6 7. Bc4
|
||||
O-O 8. O-O Re8 9. Bb3 Nd7 10. Nh4 Nf8 11. Qd3 Bc7 12. Be3 Qe7 13. Nf5 Qe4
|
||||
14. Qxe4 Rxe4 15. Ng3 Re8 16. d5 cxd5 17. Bxd5 Bb6 18. Bxb6 axb6 19. a3 Ra5
|
||||
20. Rad1 Rc5 21. c3 Rc7 22. Bf3 Rd7 23. Rxd7 Nxd7 24. Nf5 Nc5 25. Nd6 Rd8
|
||||
26. Nxc8 Rxc8 27. Rd1 Kf8 28. Rd4 Rc7 29. h3 f5 30. Rb4 Nd7 31. Kf1 Ke7 32.
|
||||
Ke2 Kd8 33. Rb5 g6 34. Ke3 Kc8 35. Kd4 Kb8 36. Kd5 Rc6 37. Kd4 Re6 38. a4
|
||||
Kc7 39. a5 Rd6+ 40. Bd5 Kc8 41. axb6 f6 42. Ke3 Nxb6 43. Bg8 Kc7 44. Rc5+
|
||||
Kb8 45. Bxh7 Nd5+ 46. Kf3 Ne7 47. h4 b6 48. Rb5 Kb7 49. h5 Ka6 50. c4 gxh5
|
||||
51. Bxf5 Rd4 52. b3 Nc6 53. Ke3 Rd8 54. Be4 Na5 55. Bc2 h4 56. Rh5 Re8+ 57.
|
||||
Kd2 Rg8 58. Rxh4 b5 59. Rf4 bxc4 60. bxc4 Rxg2 61. Rxf6+ Ka7 62. Kc3 Rg4
|
||||
63. f4 Nb7 64. Kb4 1-0
|
||||
|
||||
[Event "Varna Olympiad Final"]
|
||||
[Site "?"]
|
||||
[Date "1962"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Donner, Jan H."]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Bf5 5. Ng3 Bg6 6. h4 h6 7. Nf3 Nd7 8.
|
||||
Bd3 Bxd3 9. Qxd3 e6 10. Bf4 Qa5+ 11. Bd2 Qc7 12. c4 Ngf6 13. Bc3 a5 14. O-O
|
||||
Bd6 15. Ne4 Nxe4 16. Qxe4 O-O 17. d5 Rfe8 18. dxc6 bxc6 19. Rad1 Bf8 20.
|
||||
Nd4 Ra6 21. Nf5 Nc5 22. Qe3 Na4 23. Be5 Qa7 24. Nxh6+ gxh6 25. Rd4 f5 26.
|
||||
Rfd1 Nc5 27. Rd8 Qf7 28. Rxe8 Qxe8 29. Bd4 Ne4 30. f3 e5 31. fxe4 exd4 32.
|
||||
Qg3+ Bg7 33. exf5 Qe3+ 34. Qxe3 dxe3 35. Rd8+ Kf7 36. Rd7+ Kf6 37. g4 Bf8
|
||||
38. Kg2 Bc5 39. Rh7 Ke5 40. Kf3 Kd4 41. Rxh6 Rb6 42. b3 a4 43. Re6 axb3 44.
|
||||
axb3 Kd3 0-1
|
||||
|
||||
[Event "USA Championship"]
|
||||
[Site "?"]
|
||||
[Date "1963"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Steinmeyer, Robert H."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 dxe4 4. Nxe4 Bf5 5. Ng3 Bg6 6. Nf3 Nf6 7. h4 h6 8.
|
||||
Bd3 Bxd3 9. Qxd3 e6 10. Bd2 Nbd7 11. O-O-O Qc7 12. c4 O-O-O 13. Bc3 Qf4+
|
||||
14. Kb1 Nc5 15. Qc2 Nce4 16. Ne5 Nxf2 17. Rdf1 1-0
|
||||
|
||||
[Event "Skopje"]
|
||||
[Site "?"]
|
||||
[Date "1967"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Panov, Vasil"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 dxe4 4. Nxe4 Nf6 5. Nxf6+ exf6 6. Bc4 Bd6 7. O-O
|
||||
O-O 8. d4 Be6 9. Bxe6 fxe6 10. Re1 Re8 11. c4 Na6 12. Bd2 Qd7 13. Bc3 Bb4
|
||||
14. Qb3 Bxc3 15. bxc3 Nc7 16. a4 b6 17. h3 Rab8 18. Re4 a6 19. Qc2 b5 20.
|
||||
axb5 axb5 21. cxb5 cxb5 22. Nd2 Ra8 23. Rae1 Qd5 24. Rh4 Qf5 25. Ne4 e5 26.
|
||||
Re3 h6 27. Rf3 Qh7 28. Nxf6+ gxf6 29. Rg3+ Kh8 30. Rg6 1-0
|
||||
|
||||
[Event "Nathania"]
|
||||
[Site "?"]
|
||||
[Date "1968"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Cagan, Shimon"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. a3 Nbd7 8.
|
||||
g4 Bd6 9. g5 Ng8 10. h4 Ne7 11. h5 Qb6 12. Bh3 O-O-O 13. a4 a5 14. O-O Rhf8
|
||||
15. Kh1 f5 16. Qg2 g6 17. h6 Kb8 18. f4 Rfe8 19. e5 Bc5 20. Qf3 Nc8 21. Bg2
|
||||
Kc7 22. Ne2 Nb8 23. c3 Kd7 24. Bd2 Na6 25. Rfb1 Bf8 26. b4 axb4 27. cxb4
|
||||
Bxb4 28. a5 Qc5 29. d4 Qf8 30. Bxb4 Nxb4 31. Qc3 Na6 32. Rxb7+ Nc7 33. Nc1
|
||||
Re7 34. a6 1-0
|
||||
|
||||
[Event "Nathania"]
|
||||
[Site "?"]
|
||||
[Date "1968"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Czerniak, Moshe"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. Bd3 Nc6 5. c3 Nf6 6. Bf4 g6 7. Nf3 Bg7 8.
|
||||
Nbd2 Nh5 9. Be3 O-O 10. O-O f5 11. Nb3 Qd6 12. Re1 f4 13. Bd2 Bg4 14. Be2
|
||||
Rae8 15. Nc1 Bxf3 16. Bxf3 e5 17. Qb3 exd4 18. Nd3 Rd8 19. c4 dxc4 20.
|
||||
Qxc4+ Kh8 21. Re6 Qb8 22. Rae1 Rc8 23. Bxc6 Rxc6 24. Rxc6 bxc6 25. Qxc6 Qc8
|
||||
26. Qxc8 Rxc8 27. Kf1 Bh6 28. Rc1 Rxc1+ 29. Bxc1 g5 30. b4 Kg8 31. b5 Kf7
|
||||
32. Ba3 Bf8 33. Ne5+ Ke6 34. Bxf8 Kxe5 35. Bc5 Nf6 36. Bxa7 Ne4 37. f3 Nd2+
|
||||
38. Ke2 Nc4 39. b6 Na5 40. b7 Nxb7 41. Kd3 h5 42. Bxd4+ Kd5 43. h3 Nd8 44.
|
||||
a4 Ne6 45. Bb6 g4 46. hxg4 hxg4 47. fxg4 1-0
|
||||
|
||||
[Event "Nathania"]
|
||||
[Site "?"]
|
||||
[Date "1968"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Yanofsky, Daniel A."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. c4 Nf6 5. Nc3 g6 6. Qb3 Bg7 7. cxd5 O-O
|
||||
8. Be2 Na6 9. Bg5 Qb6 10. Qxb6 axb6 11. a3 Rd8 12. Bxf6 Bxf6 13. Rd1 Bf5
|
||||
14. Bc4 Rac8 15. Bb3 b5 16. Nf3 b4 17. axb4 Nxb4 18. Ke2 Bc2 19. Bxc2 Nxc2
|
||||
20. Kd3 Nb4+ 21. Ke4 Rd6 22. Ne5 Bg7 23. g4 f5+ 24. gxf5 gxf5+ 25. Kf4 Rf8
|
||||
26. Rhg1 Nxd5+ 27. Nxd5 Rxd5 28. Nf3 Kh8 29. Rge1 Bf6 30. Ne5 e6 31. h4 Rc8
|
||||
32. Nf7+ Kg7 33. Ng5 Bxg5+ 34. Kxg5 Rc6 35. Re5 Rcd6 36. Rxd5 Rxd5 37. f4
|
||||
Rb5 38. Rd2 Rb3 39. d5 h6+ 40. Kh5 exd5 41. Rxd5 Rxb2 42. Rd7+ Kf6 43. Rd6+
|
||||
Kf7 44. Rxh6 Rg2 45. Rb6 Rg4 46. Rxb7+ Kf6 1/2-1/2
|
||||
|
||||
[Event "Vinkovci"]
|
||||
[Site "?"]
|
||||
[Date "1968"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Hort, Vlastimil"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. Nf3 Nf6 5. c3 Bf5 6. Bb5+ Nbd7 7. Nh4 Bg6
|
||||
8. Bf4 e6 9. Nd2 Nh5 10. Nxg6 hxg6 11. Be3 Bd6 12. g3 a6 13. Bd3 Rc8 14.
|
||||
O-O Nb6 15. a4 Rc7 16. Qb3 Nc8 17. c4 dxc4 18. Nxc4 Nf6 19. Rac1 O-O 20.
|
||||
Bd2 Nd5 21. Be4 Be7 22. Na5 Ncb6 23. Bxd5 Nxd5 24. Nxb7 Qb8 25. Rxc7 Qxc7
|
||||
26. Rc1 Qb8 27. Rc4 Rd8 28. Bc3 Rd7 29. Na5 Qxb3 30. Rc8+ Kh7 31. Nxb3 Nb6
|
||||
32. Rc6 Nxa4 33. Rxa6 Nxc3 34. bxc3 Rc7 35. Nd2 Rxc3 36. Ra7 Rd3 37. Nf1
|
||||
Bf6 38. Rxf7 Rxd4 39. Kg2 g5 40. h3 Kg6 41. Rc7 Ra4 42. Nd2 Rd4 43. Nb3 Rd6
|
||||
44. Nc5 Kf5 45. Kf3 Rb6 46. Rd7 Rc6 47. Ne4 Ra6 48. Rd3 Be7 49. Rb3 Ra3 50.
|
||||
Rxa3 Bxa3 51. g4+ Kg6 52. Ke3 Bc1+ 53. Kd4 Bf4 54. Kc5 Kf7 55. Kb6 Ke8 56.
|
||||
Kc6 Ke7 1/2-1/2
|
||||
|
||||
[Event "Palma de Mallorca"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Hubner, Robert"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d3 d5 3. Nd2 g6 4. g3 Bg7 5. Bg2 e5 6. Ngf3 Ne7 7. O-O O-O 8.
|
||||
Re1 d4 9. a4 c5 10. Nc4 Nbc6 11. c3 Be6 12. cxd4 Bxc4 13. dxc4 exd4 14. e5
|
||||
Qd7 15. h4 d3 16. Bd2 Rad8 17. Bc3 Nb4 18. Nd4 Rfe8 19. e6 fxe6 20. Nxe6
|
||||
Bxc3 21. bxc3 Nc2 22. Nxd8 Rxd8 23. Qd2 Nxa1 24. Rxa1 Kg7 25. Re1 Ng8 26.
|
||||
Bd5 Qxa4 27. Qxd3 Re8 28. Rxe8 Qxe8 29. Bxb7 Nf6 30. Qd6 Qd7 31. Qa6 Qf7
|
||||
32. Qxa7 Ne4 33. f3 Nd6 34. Qxc5 Nxb7 35. Qd4+ Kg8 36. Kf2 Qe7 37. Qd5+ Kf8
|
||||
38. h5 gxh5 39. Qxh5 Nc5 40. Qd5 Kg7 41. Qd4+ Kf7 42. Qd5+ Kg7 43. Qd4+ Kf7
|
||||
44. Qd5+ 1/2-1/2
|
||||
|
||||
[Event "Siegen Olympiad Final"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Hort, Vlastimil"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d3 d5 3. Nd2 g6 4. g3 Bg7 5. Bg2 e5 6. Ngf3 Ne7 7. O-O O-O 8.
|
||||
Re1 Nd7 9. b3 d4 10. Bb2 b5 11. c3 c5 12. Rc1 Bb7 13. cxd4 cxd4 14. Bh3 Nc6
|
||||
15. a3 Re8 16. Qe2 Rc8 17. Rc2 Ne7 18. Rec1 Rxc2 19. Rxc2 Nc6 20. Qd1 Nb6
|
||||
21. Qc1 Qf6 22. Bg2 Rc8 23. h4 Bf8 24. Bh3 Rc7 25. Nh2 Bc8 26. Bf1 Bd7 27.
|
||||
h5 Rc8 28. Be2 Nd8 29. Rxc8 Bxc8 30. Ndf3 Nc6 31. Nh4 b4 32. axb4 Nxb4 33.
|
||||
N4f3 a5 34. Qc7 Qd6 35. Qa7 Ba6 36. Ba3 Nc8 37. Qa8 Qb6 38. Bxb4 Bxb4 39.
|
||||
Qd5 Qc5 40. Qxe5 Qxe5 41. Nxe5 Nd6 42. hxg6 hxg6 43. Kf1 Bb5 44. Nhf3 Bc3
|
||||
45. Ne1 Nb7 46. Bd1 Nc5 47. f3 Kg7 48. Bc2 Kf6 49. Ng4+ Ke7 50. Nf2 Bd7 51.
|
||||
Nd1 Bb4 52. Nb2 Be6 53. Nc4 Bxc4 54. dxc4 Bxe1 55. Kxe1 g5 56. Ke2 Kd6 57.
|
||||
f4 gxf4 58. gxf4 f6 59. Kf3 Ke6 60. Ke2 Kd6 1/2-1/2
|
||||
|
||||
[Event "Siegen Olympiad Prelim"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Ibrahimoglu, Ismet"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d3 d5 3. Nd2 g6 4. Ngf3 Bg7 5. g3 Nf6 6. Bg2 O-O 7. O-O Bg4 8.
|
||||
h3 Bxf3 9. Qxf3 Nbd7 10. Qe2 dxe4 11. dxe4 Qc7 12. a4 Rad8 13. Nb3 b6 14.
|
||||
Be3 c5 15. a5 e5 16. Nd2 Ne8 17. axb6 axb6 18. Nb1 Qb7 19. Nc3 Nc7 20. Nb5
|
||||
Qc6 21. Nxc7 Qxc7 22. Qb5 Ra8 23. c3 Rxa1 24. Rxa1 Rb8 25. Ra6 Bf8 26. Bf1
|
||||
Kg7 27. Qa4 Rb7 28. Bb5 Nb8 29. Ra8 Bd6 30. Qd1 Nc6 31. Qd2 h5 32. Bh6+ Kh7
|
||||
33. Bg5 Rb8 34. Rxb8 Nxb8 35. Bf6 Nc6 36. Qd5 Na7 37. Be8 Kg8 38. Bxf7+
|
||||
Qxf7 39. Qxd6 1-0
|
||||
|
||||
[Event "USSR-World"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. exd5 cxd5 4. Bd3 Nc6 5. c3 Nf6 6. Bf4 Bg4 7. Qb3 Na5
|
||||
8. Qa4+ Bd7 9. Qc2 e6 10. Nf3 Qb6 11. a4 Rc8 12. Nbd2 Nc6 13. Qb1 Nh5 14.
|
||||
Be3 h6 15. Ne5 Nf6 16. h3 Bd6 17. O-O Kf8 18. f4 Be8 19. Bf2 Qc7 20. Bh4
|
||||
Ng8 21. f5 Nxe5 22. dxe5 Bxe5 23. fxe6 Bf6 24. exf7 Bxf7 25. Nf3 Bxh4 26.
|
||||
Nxh4 Nf6 27. Ng6+ Bxg6 28. Bxg6 Ke7 29. Qf5 Kd8 30. Rae1 Qc5+ 31. Kh1 Rf8
|
||||
32. Qe5 Rc7 33. b4 Qc6 34. c4 dxc4 35. Bf5 Rff7 36. Rd1+ Rfd7 37. Bxd7 Rxd7
|
||||
38. Qb8+ Ke7 39. Rde1+ 1-0
|
||||
|
||||
[Event "USSR-World"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. d4 d5 3. Nc3 g6 4. e5 Bg7 5. f4 h5 6. Nf3 Bg4 7. h3 Bxf3 8.
|
||||
Qxf3 e6 9. g3 Qb6 10. Qf2 Ne7 11. Bd3 Nd7 12. Ne2 O-O-O 13. c3 f6 14. b3
|
||||
Nf5 15. Rg1 c5 16. Bxf5 gxf5 17. Be3 Qa6 18. Kf1 cxd4 19. cxd4 Nb8 20. Kg2
|
||||
Nc6 21. Nc1 Rd7 22. Qd2 Qa5 23. Qxa5 Nxa5 24. Nd3 Nc6 25. Rac1 Rc7 26. Rc3
|
||||
b6 27. Rgc1 Kb7 28. Nb4 Rhc8 29. Rxc6 Rxc6 30. Rxc6 Rxc6 31. Nxc6 Kxc6 32.
|
||||
Kf3 1/2-1/2
|
||||
|
||||
[Event "Zabreb"]
|
||||
[Site "?"]
|
||||
[Date "1970"]
|
||||
[Round "?"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Marovic, Drazen"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. d3 d5 3. Nd2 Nd7 4. Ngf3 Qc7 5. exd5 cxd5 6. d4 g6 7. Bd3 Bg7
|
||||
8. O-O e6 9. Re1 Ne7 10. Nf1 Nc6 11. c3 O-O 12. Bg5 e5 13. Ne3 Nb6 14. dxe5
|
||||
Nxe5 15. Bf4 f6 16. a4 Qf7 17. a5 Nbc4 18. Bxc4 dxc4 19. Bxe5 fxe5 20. Qe2
|
||||
h6 21. Nxc4 Bg4 22. Ncxe5 Bxe5 23. Nxe5 Bxe2 24. Nxf7 Rxf7 25. Rxe2 Rd8 26.
|
||||
Rae1 Rd5 27. b4 Rc7 28. Re3 Kf7 29. h4 Rd2 30. Rf3+ Kg7 31. Re6 Rf7 32.
|
||||
Rxf7+ Kxf7 33. Re5 Rd1+ 34. Kh2 b6 35. axb6 axb6 36. f3 Rd3 37. Rb5 Rxc3
|
||||
38. Rxb6 h5 39. Rb7+ Kf6 40. b5 Rb3 41. b6 Rb4 42. Kg3 Rb2 43. Rb8 Kg7 44.
|
||||
f4 Rb3+ 45. Kf2 Kf6 46. Ke2 Kg7 47. Kd2 Rg3 48. Rc8 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Stockholm"]
|
||||
[Date "1962.??.??"]
|
||||
[Round "4"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Portisch, Lajos"]
|
||||
[Result "1-0"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 dxe4 4. Nxe4 Nd7 5. Bc4 Ngf6 6. Neg5 Nd5 7. d4 h6
|
||||
8. Ne4 N7b6 9. Bb3 Bf5 10. Ng3 Bh7 11. O-O e6 12. Ne5 Nd7 13. c4 N5f6 14.
|
||||
Bf4 Nxe5 15. Bxe5 Bd6 16. Qe2 O-O 17. Rad1 Qe7 18. Bxd6 Qxd6 19. f4 c5 20.
|
||||
Qe5 Qxe5 21. dxe5 Ne4 22. Rd7 Nxg3 23. hxg3 Be4 24. Ba4 Rad8 25. Rfd1 Rxd7
|
||||
26. Rxd7 g5 27. Bd1 Bc6 28. Rd6 Rc8 29. Kf2 Kf8 30. Bf3 Bxf3 31. gxf3 gxf4
|
||||
32. gxf4 Ke7 33. f5 exf5 34. Rxh6 Rd8 35. Ke2 Rg8 36. Kf2 Rd8 37. Ke3 Rd1
|
||||
38. b3 Re1+ 39. Kf4 Re2 40. Kxf5 Rxa2 41. f4 Re2 42. Rh3 Re1 43. Rd3 Rb1
|
||||
44. Re3 Rb2 45. e6 a6 46. exf7+ Kxf7 47. Ke5 Rd2 48. Rc3 b6 49. f5 Rd1 50.
|
||||
Rh3 b5 51. Rh7+ Kg8 52. Rb7 bxc4 53. bxc4 Rd4 54. Ke6 Re4+ 55. Kd5 Rf4 56.
|
||||
Kxc5 Rxf5+ 57. Kd6 Rf6+ 58. Ke5 Rf7 59. Rb6 Rc7 60. Kd5 Kf7 61. Rxa6 Ke7
|
||||
62. Re6+ Kd8 63. Rd6+ Ke7 64. c5 Rc8 65. c6 Rc7 66. Rh6 Kd8 67. Rh8+ Ke7
|
||||
68. Ra8 1-0
|
||||
|
||||
[Event "?"]
|
||||
[Site "Yugoslavia ct"]
|
||||
[Date "1959.??.??"]
|
||||
[Round "2"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Keres, Paul"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Qb6 10. b3 a5 11. a3 Be7 12. Bg2 a4 13. b4 Nbd7 14. O-O c5
|
||||
15. Ra2 O-O 16. bxc5 Bxc5 17. Qe2 e5 18. f4 Rfc8 19. h4 Rc6 20. Bh3 Qc7 21.
|
||||
fxe5 Nxe5 22. Bf4 Bd6 23. h5 Ra5 24. h6 Ng6 25. Qf3 Rh5 26. Bg4 Nxf4 27.
|
||||
Bxh5 N4xh5 28. Kg2 Ng4 29. Nd2 Ne3+ 0-1
|
||||
|
||||
[Event "?"]
|
||||
[Site "Yugoslavia ct"]
|
||||
[Date "1959.??.??"]
|
||||
[Round "3"]
|
||||
[White "Fischer, Robert J."]
|
||||
[Black "Petrosian, Tigran V."]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c6 2. Nc3 d5 3. Nf3 Bg4 4. h3 Bxf3 5. Qxf3 Nf6 6. d3 e6 7. g3 Bb4 8.
|
||||
Bd2 d4 9. Nb1 Bxd2+ 10. Nxd2 e5 11. Bg2 c5 12. O-O Nc6 13. Qe2 Qe7 14. f4
|
||||
O-O-O 15. a3 Ne8 16. b4 cxb4 17. Nc4 f6 18. fxe5 fxe5 19. axb4 Nc7 20. Na5
|
||||
Nb5 21. Nxc6 bxc6 22. Rf2 g6 23. h4 Kb7 24. h5 Qxb4 25. Rf7+ Kb6 26. Qf2 a5
|
||||
27. c4 Nc3 28. Rf1 a4 29. Qf6 Qc5 30. Rxh7 Rdf8 31. Qxg6 Rxh7 32. Qxh7
|
||||
Rxf1+ 33. Bxf1 a3 34. h6 a2 35. Qg8 a1=Q 36. h7 Qd6 37. h8=Q Qa7 38. g4 Kc5
|
||||
39. Qf8 Qae7 40. Qa8 Kb4 41. Qh2 Kb3 42. Qa1 Qa3 43. Qxa3+ Kxa3 44. Qh6 Qf7
|
||||
45. Kg2 Kb3 46. Qd2 Qh7 47. Kg3 Qxe4 48. Qf2 Qh1 1/2-1/2
|
||||
|
11
pgn-extract/test/infiles/test-long-line.pgn
Normal file
11
pgn-extract/test/infiles/test-long-line.pgn
Normal file
@@ -0,0 +1,11 @@
|
||||
[Event "?"]
|
||||
[Site "?"]
|
||||
[Date "????.??.??"]
|
||||
[Round "?"]
|
||||
[White "?"]
|
||||
[Black "?"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. f3 e5 2. g4
|
||||
{ only-a-fool-would-play-this-move-and-only-someone-wanting-to-test-how-the-program-copes-with-very-long-lines-would-type-a-comment-like-this }
|
||||
Qh4# 0-1
|
17
pgn-extract/test/infiles/test-matchplylimit.pgn
Normal file
17
pgn-extract/test/infiles/test-matchplylimit.pgn
Normal file
@@ -0,0 +1,17 @@
|
||||
[Event "Kopavogur International Tournament"]
|
||||
[Site "Kopavogur ICE"]
|
||||
[Date "1994.04.16"]
|
||||
[Round "8"]
|
||||
[White "Stefansson, Hannes"]
|
||||
[Black "Olafsson, Helgi"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
1. e4 c5 2. Nf3 d6 3. d4 cxd4 4. Nxd4 Nf6 5. Nc3 a6 6. Be3 e6 7. f3 Nbd7 8.
|
||||
g4 h6 9. Qd2 b5 10. O-O-O b4 11. Nce2 d5 12. Nf4 dxe4 13. Ndxe6 fxe6 14.
|
||||
Bc4 Qc7 15. Bxe6 Ne5 16. Bb3 Bd7 17. fxe4 Bc5 18. Bxc5 Qxc5 19. Nd3 Nxd3+
|
||||
20. Qxd3 O-O-O 21. e5 Bb5 22. Qf5+ Nd7 23. Rd5 Qe3+ 24. Kb1 Rhf8 25. Qg6
|
||||
Nc5 26. Qxg7 Nxb3 27. axb3 Bc6 28. Rxd8+ Rxd8 29. Rf1 Be4 30. Qf6 Qe2 31.
|
||||
Qe6+ Rd7 32. Rc1 Kc7 33. h4 a5 34. g5 hxg5 35. hxg5 Rd1 36. Qe7+ Kb6 37.
|
||||
Qe6+ Kc7 38. Qe7+ Kb6 39. Qe6+ Bc6 40. Rxd1 Qxd1+ 41. Ka2 Qxc2 42. Qd6 Qc5
|
||||
43. Qb8+ Bb7 44. g6 a4 45. Qd8+ Ka7 46. Qd7 Kb6 47. Qd8+ Ka6 48. Qd3+ Ka5
|
||||
49. Qd8+ Ka6 50. Qd3+ Ka7 51. Qd7 Kb6 1/2-1/2
|
1
pgn-extract/test/infiles/test-nagcomments.pgn
Normal file
1
pgn-extract/test/infiles/test-nagcomments.pgn
Normal file
@@ -0,0 +1 @@
|
||||
b3 { good or bad? } $1 { some think this is good } $2 { while others think it is not } *
|
9
pgn-extract/test/infiles/test-nobadresults.pgn
Normal file
9
pgn-extract/test/infiles/test-nobadresults.pgn
Normal file
@@ -0,0 +1,9 @@
|
||||
[Result "1-0"] e4 *
|
||||
[Result "0-1"] e4 *
|
||||
[Result "1/2-1/2"] e4 *
|
||||
[Result "1-0"] e4 0-1
|
||||
[Result "0-1"] e4 1/2-1/2
|
||||
[Result "1/2-1/2"] e4 1-0
|
||||
[Result "*"] e4 1-0
|
||||
[Result "*"] e4 0-1
|
||||
[Result "*"] e4 1/2-1/2
|
28
pgn-extract/test/infiles/test-nochecks.pgn
Normal file
28
pgn-extract/test/infiles/test-nochecks.pgn
Normal file
@@ -0,0 +1,28 @@
|
||||
[Event "?"]
|
||||
[Site "?"]
|
||||
[Date "????.??.??"]
|
||||
[Round "?"]
|
||||
[White "?"]
|
||||
[Black "?"]
|
||||
[Result "0-1"]
|
||||
|
||||
1. f3 e5 2. g4 Qh4# 0-1
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
18
pgn-extract/test/infiles/test-nomovenumbers.pgn
Normal file
18
pgn-extract/test/infiles/test-nomovenumbers.pgn
Normal file
@@ -0,0 +1,18 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 {Time control} 1/2-1/2
|
||||
|
18
pgn-extract/test/infiles/test-noresults.pgn
Normal file
18
pgn-extract/test/infiles/test-noresults.pgn
Normal file
@@ -0,0 +1,18 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 {Time control} 1/2-1/2
|
||||
|
18
pgn-extract/test/infiles/test-notags.pgn
Normal file
18
pgn-extract/test/infiles/test-notags.pgn
Normal file
@@ -0,0 +1,18 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 {Time control} 1/2-1/2
|
||||
|
6
pgn-extract/test/infiles/test-o.txt
Normal file
6
pgn-extract/test/infiles/test-o.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
b2b3 e7e5 c1b2 d7d6 d2d4 e5d4 d1d4 b8c6 d4d2 g8f6 b1c3 c8e6 e2e4 d6d5 e4d5
|
||||
e6d5 d2e3+ f8e7 g1f3 e8g8 f1e2 f8e8 e1c1 e7b4 e3d3 b4c3 b2c3 d8e7 h1e1 f6e4
|
||||
c3b2 a8d8 d3e3 b7b6 e2b5 e7e6 f3d4 c6d4 d1d4 c7c5 d4e4 d5e4 b5e8 d8e8 f2f3
|
||||
e4d5 e3e6 e8e6 e1e6 d5e6 c1d2 g8f8 b2e5 b6b5 e5b8 a7a6 b8a7 c5c4 d2c3 f8e7
|
||||
c3d4 e7d6 a7c5+ d6d7 c5a7 d7d6 a7c5+ d6d7 d4c3 g7g6 c5d4 f7f5 1/2-1/2
|
||||
|
19
pgn-extract/test/infiles/test-plycount.pgn
Normal file
19
pgn-extract/test/infiles/test-plycount.pgn
Normal file
@@ -0,0 +1,19 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
19
pgn-extract/test/infiles/test-plylimit.pgn
Normal file
19
pgn-extract/test/infiles/test-plylimit.pgn
Normal file
@@ -0,0 +1,19 @@
|
||||
[Event "Dover vs Herne Bay, Minor League"]
|
||||
[Site "Margate Chess Club"]
|
||||
[Date "1994.10.10"]
|
||||
[Round ""]
|
||||
[White "Barnes, David J."]
|
||||
[Black "Horton, Mark"]
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
{ Game played inaccurately by White under extreme time pressure. }
|
||||
|
||||
1. b3 e5 2. Bb2 d6 3. d4 exd4 4. Qxd4 Nc6 5. Qd2 Nf6 6. Nc3 Be6 7. e4 d5 8.
|
||||
exd5 Bxd5 9. Qe3+ Be7 10. Nf3 O-O 11. Be2 Re8 12. O-O-O Bb4 13. Qd3 Bxc3
|
||||
14. Bxc3 Qe7 15. Rhe1 Ne4 16. Bb2 Rad8 17. Qe3 b6 18. Bb5 Qe6 19. Nd4 Nxd4
|
||||
20. Rxd4 c5 21. Rxe4 Bxe4 22. Bxe8 { 2 minutes to time-control at move 36.
|
||||
} 22... Rxe8 23. f3 Bd5 24. Qxe6 Rxe6 25. Rxe6 Bxe6 26. Kd2 Kf8 27. Be5 b5
|
||||
28. Bb8 $2 (28. Bd6+ { wins }) 28... a6 29. Ba7 c4 30. Kc3 Ke7 31. Kd4 Kd6
|
||||
32. Bc5+ Kd7 33. Ba7 Kd6 34. Bc5+ Kd7 35. Kc3 g6 36. Bd4 f5 { Time control.
|
||||
} 1/2-1/2
|
||||
|
41
pgn-extract/test/infiles/test-promotion-in.pgn
Normal file
41
pgn-extract/test/infiles/test-promotion-in.pgn
Normal file
@@ -0,0 +1,41 @@
|
||||
[FEN "7k/3P4/7K/8/8/8/8/8 w - - 6 55"]
|
||||
[SetUp "1"]
|
||||
|
||||
d7d8R 1-0
|
||||
|
||||
[FEN "7k/3P4/7K/8/8/8/8/8 w - - 6 55"]
|
||||
[SetUp "1"]
|
||||
|
||||
d7d8N *
|
||||
|
||||
[FEN "7k/3P4/7K/8/8/8/8/8 w - - 6 55"]
|
||||
[SetUp "1"]
|
||||
|
||||
d7d8B *
|
||||
|
||||
[FEN "7k/3P4/7K/8/8/8/8/8 w - - 6 55"]
|
||||
[SetUp "1"]
|
||||
|
||||
d7d8Q 1-0
|
||||
|
||||
[FEN "7k/3P4/7K/8/8/8/8/8 w - - 6 55"]
|
||||
[SetUp "1"]
|
||||
|
||||
d7d8r 1-0
|
||||
|
||||
[FEN "7k/3P4/7K/8/8/8/8/8 w - - 6 55"]
|
||||
[SetUp "1"]
|
||||
|
||||
d7d8n *
|
||||
|
||||
[FEN "7k/3P4/7K/8/8/8/8/8 w - - 6 55"]
|
||||
[SetUp "1"]
|
||||
|
||||
d7d8b *
|
||||
|
||||
[FEN "7k/3P4/7K/8/8/8/8/8 w - - 6 55"]
|
||||
[SetUp "1"]
|
||||
|
||||
d7d8q 1-0
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user