diff --git a/LICENSE b/LICENSE
index 733c072..799d59b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,675 +1 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- 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 .
-
-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:
-
- {project} Copyright (C) {year} {fullname}
- 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
- .
-
- 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
-.
-
+Copyleft by Misakamm
diff --git a/dllai/ai.cpp b/dllai/ai.cpp
new file mode 100644
index 0000000..40f230f
--- /dev/null
+++ b/dllai/ai.cpp
@@ -0,0 +1,168 @@
+#include "ai.h"
+
+namespace AI {
+ int Evaluate(const GameField& field, int att, int clear, int depth, int player) {
+ int score = 0;
+ int field_w = field.width(), field_h = field.height();
+ int min_y[32] = {0};
+ struct factor {
+ int hole, h_change, y_factor, h_variance, att, noattclear;
+ } ai_factor_l[3] = {
+ {-50, -5, -10, -10, 40, -30},
+ {-50, -5, -10, -10, 30, -35},
+ {-50, -5, -10, -10, 20, -35},
+ };
+ factor ai_factor;
+ if ( depth > 2 ) ai_factor = ai_factor_l[2];
+ else ai_factor = ai_factor_l[depth];
+
+ // get all columns height
+ {
+ int beg_y = 0;
+ while ( field.row[beg_y] == 0 ) ++beg_y;
+ for ( int x = 0; x < field_w; ++x) {
+ for ( int y = beg_y, ey = field_h + 1; y <= ey; ++y) {
+ if ( field.row[y] & ( 1 << x ) ) {
+ min_y[x] = y;
+ break;
+ }
+ }
+ }
+ }
+ min_y[field_w] = min_y[field_w-2];
+ // find holes
+ {
+ int hole_score = 0;
+ for ( int x = 0; x < field_w; ++x) {
+ for ( int y = min_y[x] + 1; y <= field_h; ++y) {
+ if ( ( field.row[y] & ( 1 << x ) ) == 0) {
+ hole_score += ai_factor.hole;
+ }
+ }
+ }
+ score += hole_score;
+ }
+ // height change
+ {
+ int last = min_y[1];
+ for ( int x = 0; x <= field_w; last = min_y[x], ++x) {
+ int v = min_y[x] - last;
+ int absv = abs(v);
+ score += absv * ai_factor.h_change;
+ }
+ }
+ // variance
+ {
+ int h_variance_score = 0;
+ int avg = 0;
+ {
+ int sum = 0;
+ int sample_cnt = 0;
+ for ( int x = 0; x < field_w; ++x) {
+ avg += min_y[x];
+ }
+ {
+ double h = field_h - (double)avg / field_w;
+ score += int(ai_factor.y_factor * h * h / field_h);
+ }
+ for ( int x = 0; x < field_w; ++x) {
+ int t = avg - min_y[x] * field_w;
+ if ( abs(t) > field_h * field_w / 4 ) {
+ if ( t > 0 ) t = field_h * field_w / 4;
+ else t = -(field_h * field_w / 4);
+ }
+ sum += t * t;
+ ++sample_cnt;
+ }
+ if ( sample_cnt > 0 ) {
+ h_variance_score = sum * ai_factor.h_variance / (sample_cnt * 100);
+ }
+ score += h_variance_score;
+ }
+ }
+ // clear and attack
+ if ( clear > 0 )
+ {
+ if ( depth > 0 ) {
+ score += int( att * ai_factor.att * ((double)att / clear - 0.7) );
+ } else {
+ score += att * ai_factor.att;
+ }
+ if ( att == 0 ) {
+ score += clear * ai_factor.noattclear;
+ }
+ }
+ return score;
+ }
+ int pasteClearAttack(GameField& field, int gemnum, int x, int y, int spin, signed char wallkick_spin, int &att) {
+ wallkick_spin = field.WallKickValue(gemnum, x, y, spin, wallkick_spin);
+ field.paste(x, y, getGem(gemnum, spin));
+ int clear = field.clearLines( wallkick_spin );
+ att = field.getAttack( clear, wallkick_spin );
+ return clear;
+ }
+ MovingSimple AISearch(const GameField& field, Gem cur, bool curCanHold, int x, int y, const std::vector& next
+ , bool canhold, int upcomeAtt, int level, int player
+ , int maxdepth, int* pscore, int lastatt, int lastclear, int depth) {
+
+ std::vector movs;
+ if ( pscore ) *pscore = SCORE_LOSE;
+ GenMoving(field, movs, cur, x, y, false);
+ if ( movs.empty() ) {
+ return MovingSimple();
+ }
+ if ( maxdepth > level ) maxdepth = level;
+
+ MovingSimple best;
+ int maxScore = SCORE_LOSE;
+ for (size_t i = 0; i < movs.size() ; ++i) {
+ GameField newfield = field;
+ int clear, att;
+ clear = pasteClearAttack(newfield, cur.num, movs[i].x, movs[i].y, movs[i].spin, movs[i].wallkick_spin, att);
+ int score = 0;
+ if ( maxdepth > 0 && next.size() > 0) {
+ std::vector newnext( next.begin() + 1, next.end() );
+ AISearch(newfield, next[0], canhold, gem_beg_x, gem_beg_y, newnext, canhold, upcomeAtt, level, player, maxdepth - 1, &score, lastatt + att, lastclear + clear, depth + 1);
+ } else {
+ score += Evaluate(newfield, lastatt + att, lastclear + clear, depth, player);
+ }
+ if ( score > maxScore ) {
+ maxScore = score;
+ best = movs[i];
+ }
+ }
+ int hold_num = field.m_hold;
+ if ( field.m_hold == 0 && ! next.empty()) {
+ hold_num = next[0].num;
+ }
+ if ( canhold && curCanHold && hold_num ) {
+ GenMoving(field, movs, AI::getGem(hold_num, 0), gem_beg_x, gem_beg_y, true);
+ if ( ! movs.empty() ) {
+ for (size_t i = 0; i < movs.size() ; ++i) {
+ GameField newfield = field;
+ int clear, att;
+ clear = pasteClearAttack(newfield, hold_num, movs[i].x, movs[i].y, movs[i].spin, movs[i].wallkick_spin, att);
+ int score = 0;
+ newfield.m_hold = cur.num;
+ if ( maxdepth > 0 && (field.m_hold != 0 && next.size() > 0 || next.size() > 1) ) {
+ if ( field.m_hold == 0 ) {
+ std::vector newnext( next.begin() + 2, next.end() );
+ AISearch(newfield, next[1], canhold, gem_beg_x, gem_beg_y, newnext, canhold, upcomeAtt, level, player, maxdepth - 1, &score, lastatt + att, lastclear + clear, depth + 1);
+ } else {
+ std::vector newnext( next.begin() + 1, next.end() );
+ AISearch(newfield, next[0], canhold, gem_beg_x, gem_beg_y, newnext, canhold, upcomeAtt, level, player, maxdepth - 1, &score, lastatt + att, lastclear + clear, depth + 1);
+ }
+ } else {
+ score += Evaluate(newfield, lastatt + att, lastclear + clear, depth, player);
+ }
+ if ( score > maxScore ) {
+ maxScore = score;
+ best = movs[i];
+ }
+ }
+ }
+ }
+ if ( pscore ) *pscore = maxScore;
+ return best;
+ }
+}
diff --git a/dllai/ai.h b/dllai/ai.h
new file mode 100644
index 0000000..9b36f24
--- /dev/null
+++ b/dllai/ai.h
@@ -0,0 +1,158 @@
+#pragma once
+
+#include "gamefield.h"
+#include
+
+#define AI_MAX_DEPTH 2
+
+namespace AI {
+ struct Moving
+ {
+ enum {
+ MOV_NULL,
+ MOV_L,
+ MOV_R,
+ MOV_LL,
+ MOV_RR,
+ MOV_D,
+ MOV_DD,
+ MOV_LSPIN,
+ MOV_RSPIN,
+ MOV_DROP,
+ MOV_HOLD,
+ MOV_SPIN2,
+ };
+ std::vector movs;
+ int x, y;
+ int score;
+ signed char spin;
+ signed char wallkick_spin;
+ Moving () { wallkick_spin = 0; movs.reserve (16); }
+ Moving ( const Moving & m ) {
+ movs = m.movs;
+ x = m.x;
+ y = m.y;
+ spin = m.spin;
+ score = m.score;
+ wallkick_spin = m.wallkick_spin;
+ }
+ Moving ( const Moving & m, int _spin ) {
+ movs.reserve (16);
+ movs = m.movs;
+ spin = (signed char)_spin;
+ }
+ bool operator < (const Moving& _m) const {
+ return score > _m.score;
+ }
+ bool operator == (const Moving& _m) const {
+ if ( x != _m.x || y != _m.y ) return false;
+ if ( spin != _m.spin ) return false;
+ if ( wallkick_spin != _m.wallkick_spin ) return false;
+ return true;
+ }
+ };
+ struct MovingSimple
+ {
+ enum {
+ MOV_NULL,
+ MOV_L,
+ MOV_R,
+ MOV_LL,
+ MOV_RR,
+ MOV_D,
+ MOV_DD,
+ MOV_LSPIN,
+ MOV_RSPIN,
+ MOV_DROP,
+ MOV_HOLD,
+ MOV_SPIN2,
+ };
+ enum {
+ INVALID_POS = -64,
+ };
+ int x, y;
+ int lastmove;
+ signed char spin;
+ signed char wallkick_spin;
+ bool hold;
+ MovingSimple () { x = INVALID_POS; wallkick_spin = 0; lastmove = MovingSimple::MOV_NULL; }
+ MovingSimple ( const Moving & m ) {
+ x = m.x;
+ y = m.y;
+ spin = m.spin;
+ wallkick_spin = m.wallkick_spin;
+ if (m.movs.empty()) hold = false;
+ else hold = (m.movs[0] == MovingSimple::MOV_HOLD);
+ if (m.movs.empty()) lastmove = MovingSimple::MOV_NULL;
+ else lastmove = m.movs.back();
+ }
+ MovingSimple ( const MovingSimple & m ) {
+ x = m.x;
+ y = m.y;
+ spin = m.spin;
+ wallkick_spin = m.wallkick_spin;
+ hold = m.hold;
+ lastmove = m.lastmove;
+ }
+ MovingSimple ( const MovingSimple & m, int _spin ) {
+ lastmove = m.lastmove;
+ hold = m.hold;
+ spin = (signed char)_spin;
+ }
+ bool operator == (const MovingSimple& _m) const {
+ if ( x != _m.x || y != _m.y ) return false;
+ if ( spin != _m.spin ) return false;
+ if ( lastmove != _m.lastmove ) return false;
+ if ( hold != _m.hold ) return false;
+ if ( wallkick_spin != _m.wallkick_spin ) return false;
+ return true;
+ }
+ };
+ template
+ struct MovList
+ {
+ std::vector queue;
+ //T queue[1024];
+ int beg, end;
+ MovList() {
+ beg = end = 0;
+ }
+ MovList( size_t size ) {
+ beg = end = 0;
+ //queue.resize( size );
+ queue.reserve( size );
+ }
+ void clear() {
+ beg = end = 0;
+ queue.clear();
+ }
+ size_t size() const {
+ return end - beg;
+ }
+ T& back() {
+ return queue[end-1];
+ }
+ void push(const T& mov) {
+ queue.push_back(mov);
+ //queue[end] = mov;
+ ++end;
+ }
+ bool empty () const {
+ return beg == end;
+ }
+ void pop(T& mov) {
+ mov = queue[beg++];
+ }
+ };
+ enum AIScore {
+ SCORE_LOSE = -100000000,
+ };
+ void setComboList( std::vector combolist );
+ int getComboAttack( int combo );
+ void GenMoving(const GameField& field, std::vector & movs, Gem cur, int x, int y, bool hold);
+ void FindPathMoving(const GameField& field, std::vector & movs, Gem cur, int x, int y, bool hold);
+ MovingSimple AISearch(const GameField& field, Gem cur, bool curCanHold, int x, int y, const std::vector& next
+ , bool canHold, int upcomeAtt, int level, int player
+ , int maxdepth = AI_MAX_DEPTH, int* score = NULL, int lastatt = 0, int lastclear = 0, int depth = 0);
+ void setSpin180( bool enable );
+}
diff --git a/dllai/dllai.cpp b/dllai/dllai.cpp
new file mode 100644
index 0000000..fe53809
--- /dev/null
+++ b/dllai/dllai.cpp
@@ -0,0 +1,155 @@
+// dllai.cpp : Defines the exported functions for the DLL application.
+//
+
+#define _CRT_SECURE_NO_WARNINGS
+#include "ai.h"
+#include
+#include
+#include
+#include
+#include "windows.h"
+
+#define DLLEXPORT extern "C" __declspec(dllexport)
+
+char g_result[8][1024];
+AI::MovingSimple last_best[8];
+
+char* result(int player, std::string r)
+{
+ return strcpy( g_result[player], r.c_str() );
+}
+
+// very important value
+#define AI_DLL_VERSION 2
+
+DLLEXPORT
+int AIDllVersion()
+{
+ return AI_DLL_VERSION;
+}
+
+DLLEXPORT
+char* AIName( int level ) {
+ char name[200];
+ if ( level > AI_MAX_DEPTH ) level = AI_MAX_DEPTH;
+ sprintf( name, "LV%d", level);
+ return result( 0, std::string("Baka(9) ") + name );
+}
+
+/*
+all 'char' type is using the characters in ' ITLJZSO'
+
+field data like this:
+00........ -> 0x3
+00.0...... -> 0xb
+00000..... -> 0x1f
+
+b2b: the count of special attack, the first one set b2b=1, but no extra attack. Have extra attacks when b2b>=2
+combo: first clear set combo=1, so the comboTable in toj rule is [0, 0, 0, 1, 1, 2, 2, 3, ...]
+next: array size is 'maxDepth'
+x, y, spin: the active piece's x/y/orientation,
+ x/y is the up-left corner's position of the active piece.
+ see tetris_gem.cpp for the bitmaps.
+curCanHold: indicates whether you can use hold on current move.
+ might be caused by re-think after a hold move.
+canhold: false if hold is completely disabled.
+comboTable: -1 is the end of the table.
+*/
+DLLEXPORT
+char* TetrisAI(int overfield[], int field[], int field_w, int field_h, int b2b, int combo,
+ char next[], char hold, bool curCanHold, char active, int x, int y, int spin,
+ bool canhold, bool can180spin, int upcomeAtt, int comboTable[], int maxDepth, int level, int player)
+{
+ AI::GameField gamefield(field_w, field_h); // always 10 x 22
+ std::vector gemNext;
+ std::map gemMap;
+ // init
+ gemMap[' '] = AI::GEMTYPE_NULL;
+ gemMap['I'] = AI::GEMTYPE_I;
+ gemMap['T'] = AI::GEMTYPE_T;
+ gemMap['L'] = AI::GEMTYPE_L;
+ gemMap['J'] = AI::GEMTYPE_J;
+ gemMap['Z'] = AI::GEMTYPE_Z;
+ gemMap['S'] = AI::GEMTYPE_S;
+ gemMap['O'] = AI::GEMTYPE_O;
+ // gamefield
+ for ( int iy = 0; iy <= field_h; ++iy ) {
+ gamefield.row[iy] = field[iy];
+ }
+ for ( int iy = 0; iy < 8; ++iy ) {
+ gamefield.row[-iy-1] = overfield[iy];
+ }
+ gamefield.m_hold = gemMap[hold];
+ gamefield.b2b = b2b;
+ gamefield.combo = combo;
+ // next
+ for ( int i = 0; i < maxDepth; ++i) {
+ gemNext.push_back( AI::getGem(gemMap[next[i]], 0) );
+ }
+ // combo list
+ for ( int i = 0; i < 100; ++i) {
+ if ( comboTable[i] < 0 ) {
+ AI::setComboList( std::vector(comboTable, comboTable + i - 1) );
+ break;
+ }
+ }
+ // rule
+ AI::setSpin180(can180spin);
+
+ if ( level > AI_MAX_DEPTH ) level = AI_MAX_DEPTH;
+
+ // player is the player number, for randomize or something else, to make different player do the different thing if it is necessary
+ AI::MovingSimple best = AI::AISearch(gamefield, AI::getGem(gemMap[active], spin), curCanHold, x, y, gemNext, canhold, upcomeAtt, level, player);
+
+ // find path
+ AI::Moving mov;
+ if ( best.x != AI::MovingSimple::INVALID_POS ) {
+ int hold_num = gamefield.m_hold;
+ if ( gamefield.m_hold == 0 && ! gemNext.empty()) {
+ hold_num = gemNext[0].num;
+ }
+ std::vector movs;
+ AI::Gem cur;
+ if ( best.hold ) {
+ cur = AI::getGem(hold_num, 0);
+ FindPathMoving(gamefield, movs, cur, AI::gem_beg_x, AI::gem_beg_y, true);
+ } else {
+ cur = AI::getGem(gemMap[active], spin);
+ FindPathMoving(gamefield, movs, cur, x, y, false);
+ }
+ for ( size_t i = 0; i < movs.size(); ++i ) {
+ if ( movs[i].x == best.x && movs[i].y == best.y && movs[i].spin == best.spin ) {
+ if ( cur.num == AI::GEMTYPE_T && movs[i].wallkick_spin >= best.wallkick_spin || cur.num != AI::GEMTYPE_T ) {
+ mov = movs[i];
+ }
+ }
+ }
+ }
+ if ( mov.movs.empty() ) {
+ mov.movs.clear();
+ mov.movs.push_back( AI::Moving::MOV_NULL );
+ mov.movs.push_back( AI::Moving::MOV_DROP );
+ } else {
+ last_best[player] = best;
+ }
+
+ // return
+ std::map outMap;
+ outMap[AI::Moving::MOV_NULL] = ' ';
+ outMap[AI::Moving::MOV_L] = 'l';
+ outMap[AI::Moving::MOV_R] = 'r';
+ outMap[AI::Moving::MOV_LL] = 'L';
+ outMap[AI::Moving::MOV_RR] = 'R';
+ outMap[AI::Moving::MOV_D] = 'd';
+ outMap[AI::Moving::MOV_DD] = 'D';
+ outMap[AI::Moving::MOV_LSPIN] = 'z';
+ outMap[AI::Moving::MOV_SPIN2] = 'x';
+ outMap[AI::Moving::MOV_RSPIN] = 'c';
+ outMap[AI::Moving::MOV_HOLD] = 'v';
+ outMap[AI::Moving::MOV_DROP] = 'V';
+ std::string out;
+ for ( size_t i = 0; i < mov.movs.size(); ++i ) {
+ out.push_back(outMap[mov.movs[i]]);
+ }
+ return result(player, out);
+}
diff --git a/dllai/dllai.vcproj b/dllai/dllai.vcproj
new file mode 100644
index 0000000..2a0012e
--- /dev/null
+++ b/dllai/dllai.vcproj
@@ -0,0 +1,227 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dllai/dllai.vcxproj b/dllai/dllai.vcxproj
new file mode 100644
index 0000000..1010768
--- /dev/null
+++ b/dllai/dllai.vcxproj
@@ -0,0 +1,143 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ XP_Release
+ Win32
+
+
+
+ {AFFA8B7C-EAAA-46F7-92B2-1A1F422B1EF3}
+ Win32Proj
+ dllai
+
+
+
+ DynamicLibrary
+ true
+ v110
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v110
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v110_xp
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)bin\
+
+
+ false
+ $(SolutionDir)bin\
+
+
+ false
+ $(SolutionDir)bin\
+ false
+
+
+
+ NotUsing
+ Level3
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;DLLAI_EXPORTS;%(PreprocessorDefinitions)
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ NotUsing
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;DLLAI_EXPORTS;%(PreprocessorDefinitions)
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level4
+ NotUsing
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;DLLAI_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dllai/dllmain.cpp b/dllai/dllmain.cpp
new file mode 100644
index 0000000..5aaee7c
--- /dev/null
+++ b/dllai/dllmain.cpp
@@ -0,0 +1,37 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "windows.h"
+extern "C" {
+HMODULE g_hModule;
+}
+
+#ifdef _DEBUG
+#include
+#define SHOW_CONSOLE
+#endif
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_hModule = hModule;
+#ifdef SHOW_CONSOLE
+ {
+ AllocConsole();
+ freopen("CONOUT$","w+t",stdout);
+ freopen("CONIN$","r+t",stdin);
+ printf("Debug Begin. Using 'printf' to output debug infomation");
+ }
+#endif
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
diff --git a/dllai/gamefield.h b/dllai/gamefield.h
new file mode 100644
index 0000000..013cb53
--- /dev/null
+++ b/dllai/gamefield.h
@@ -0,0 +1,300 @@
+#pragma once
+#define _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH
+
+#include
+#include "tetris_gem.h"
+#define AI_POOL_MAX_H 50
+
+namespace AI {
+ int getComboAttack( int combo );
+ void setAllSpin(bool allSpin);
+ bool isEnableAllSpin();
+
+ const int gem_add_y = 20;
+ const int gem_beg_x = 3;
+ const int gem_beg_y = 1;
+
+ struct GameField {
+ signed char m_w, m_h;
+ signed short combo;
+ signed short b2b;
+ unsigned long m_w_mask;
+ unsigned long m_row[AI_POOL_MAX_H];
+ int m_hold;
+ unsigned long *row;
+ GameField () {
+ row = &m_row[gem_add_y];
+ }
+ GameField ( const GameField& field ) {
+ row = &m_row[gem_add_y];
+ *this = field;
+ }
+ GameField (int w, int h) {
+ row = &m_row[gem_add_y];
+ reset((signed char)w, (signed char)h);
+ }
+ int width() const { return m_w; }
+ int height() const { return m_h; }
+ void reset (int w, int h) {
+ m_w = (signed char)w;
+ m_h = (signed char)h;
+ combo = 0;
+ b2b = 0;
+ m_hold = 0;
+ m_w_mask = ( 1 << w ) - 1;
+ for (int i = 0; i < AI_POOL_MAX_H; ++i) {
+ m_row[i] = 0;
+ }
+ for (int i = gem_add_y + m_h + 1; i < AI_POOL_MAX_H; ++i) {
+ m_row[i] = (unsigned)-1;
+ }
+ }
+ GameField& operator = (const GameField& field) {
+ memcpy( this, &field, (size_t)&row - (size_t)this );
+ return *this;
+ }
+ bool operator == (const GameField& field) const {
+ if ( m_w != field.m_w || m_h != field.m_h ) return false;
+ for ( int i = 0; i <= m_h + gem_add_y; ++i ) {
+ if ( m_row[i] != field.m_row[i] ) return false;
+ }
+ if ( m_hold != field.m_hold ) return false;
+ if ( combo != field.combo ) return false;
+ if ( b2b != field.b2b ) return false;
+ return true;
+ }
+ inline bool isCollide(int y, const Gem & gem) const {
+ for ( int h = 3; h >= 0; --h ) {
+ if ( y + h > m_h && gem.bitmap[h] ) return true;
+ if ( row[y + h] & gem.bitmap[h] ) return true;
+ }
+ return false;
+ }
+ inline bool isCollide(int x, int y, const Gem & gem) const {
+ Gem _gem = gem;
+ for ( int h = 0; h < 4; ++h ) {
+ if ( x < 0 ) {
+ if (gem.bitmap[h] & ( ( 1 << (-x) ) - 1 ) ) return true;
+ _gem.bitmap[h] >>= -x;
+ } else {
+ if ( (gem.bitmap[h] << x) & ~m_w_mask ) return true;
+ _gem.bitmap[h] <<= x;
+ }
+ if ( y + h > m_h && _gem.bitmap[h] ) return true;
+ if ( row[y + h] & _gem.bitmap[h] ) return true;
+ }
+ return false;
+ }
+ bool wallkickTest(int& x, int& y, const Gem & gem, int spinclockwise) const {
+ static int Iwallkickdata[4][2][4][2] = {
+ { // O
+ { // R
+ { 2, 0},{-1, 0},{ 2,-1},{-1, 2},
+ },
+ { // L
+ { 1, 0},{-2, 0},{ 1, 2},{-2,-1},
+ },
+ },
+ { // L
+ { // O
+ {-1, 0},{ 2, 0},{-1,-2},{ 2, 1},
+ },
+ { // 2
+ { 2, 0},{-1, 0},{ 2,-1},{-1, 2},
+ },
+ },
+ { // 2
+ { // L
+ {-2, 0},{ 1, 0},{-2, 1},{ 1,-2},
+ },
+ { // R
+ {-1, 0},{ 2, 0},{-1,-2},{ 2, 1},
+ },
+ },
+ { // R
+ { // 2
+ { 1, 0},{-2, 0},{ 1, 2},{-2,-1},
+ },
+ { // O
+ {-2, 0},{ 1, 0},{-2, 1},{ 1,-2},
+ },
+ },
+ };
+ static int wallkickdata[4][2][4][2] = {
+ { // O
+ { // R
+ { 1, 0},{ 1, 1},{ 0,-2},{ 1,-2},
+ },
+ { // L
+ {-1, 0},{-1, 1},{ 0,-2},{-1,-2},
+ },
+ },
+ { // L
+ { // O
+ { 1, 0},{ 1,-1},{ 0, 2},{ 1, 2},
+ },
+ { // 2
+ { 1, 0},{ 1,-1},{ 0, 2},{ 1, 2},
+ },
+ },
+ { // 2
+ { // L
+ {-1, 0},{-1, 1},{ 0,-2},{-1,-2},
+ },
+ { // R
+ { 1, 0},{ 1, 1},{ 0,-2},{ 1,-2},
+ },
+ },
+ { // R
+ { // 2
+ {-1, 0},{-1,-1},{ 0, 2},{-1, 2},
+ },
+ { // O
+ {-1, 0},{-1,-1},{ 0, 2},{-1, 2},
+ },
+ },
+ };
+ int (*pdata)[2][4][2] = wallkickdata;
+ if ( gem.num == GEMTYPE_I ) pdata = Iwallkickdata;
+ for ( int itest = 0; itest < 4; ++itest) {
+ int dx = x + pdata[gem.spin][spinclockwise][itest][0];
+ int dy = y + pdata[gem.spin][spinclockwise][itest][1];
+ if ( ! isCollide(dx, dy, gem) ) {
+ x = dx; y = dy;
+ return true;
+ }
+ }
+ return false;
+ }
+ void paste(int x, int y, const Gem & gem) {
+ for ( int h = 0; h < gem.geth(); ++h ) {
+ if (x >= 0)
+ row[y + h] |= gem.bitmap[h] << x;
+ else
+ row[y + h] |= gem.bitmap[h] >> (-x);
+ }
+ }
+ signed char isWallKickSpin(int x, int y, const Gem & gem) const {
+ if ( isEnableAllSpin() ) {
+ if ( isCollide( x - 1, y, gem )
+ && isCollide( x + 1, y, gem )
+ && isCollide( x, y - 1, gem )) {
+ return 1;
+ }
+ } else {
+ if ( gem.num == GEMTYPE_T ) { //T
+ int cnt = 0;
+ if ( x < 0 || (row[y] & (1 << x))) ++cnt;
+ if ( x < 0 || y+2 > m_h || (row[y+2] & (1 << x))) ++cnt;
+ if ( x+2 >= m_w || (row[y] & (1 << (x+2)))) ++cnt;
+ if ( x+2 >= m_w || y+2 > m_h || (row[y+2] & (1 << (x+2)))) ++cnt;
+ if ( cnt >= 3 ) return 1;
+ }
+ }
+ return 0;
+ }
+ signed char WallKickValue(int gem_num, int x, int y, int spin, signed char wallkick_spin) const {
+ if ( ! isWallKickSpin( x, y, getGem(gem_num, spin) ) ) {
+ return wallkick_spin = 0;
+ }
+ if ( isEnableAllSpin() ) {
+ if ( wallkick_spin == 2) {
+ wallkick_spin = 1;
+ Gem g = getGem(gem_num, spin);
+ for ( int dy = 0; dy < 4; ++dy ) { //KOS mini test
+ if ( g.bitmap[dy] == 0 ) continue;
+ if ( ((g.bitmap[dy] << x) | row[y+dy]) == m_w_mask ) continue;
+ wallkick_spin = 2;
+ break;
+ }
+ }
+ } else {
+ if ( wallkick_spin == 2 ) {
+ if ( ! isCollide( x, y, getGem(gem_num, spin^2) ) ) {
+ wallkick_spin = 1; // not t-mini
+ }
+ }
+ }
+ return wallkick_spin;
+ }
+ int clearLines( signed char _wallkick_spin ) {
+ int clearnum = 0;
+ int h2 = m_h;
+ for (int h = m_h; h >= -gem_add_y; --h) {
+ if ( row[h] != m_w_mask) {
+ row[h2--] = row[h];
+ } else {
+ ++ clearnum;
+ }
+ }
+ for (int h = h2; h >= -gem_add_y; --h) {
+ row[h] = 0;
+ }
+ if ( clearnum > 0 ) {
+ ++combo;
+ if ( clearnum == 4 ) {
+ ++b2b;
+ } else if ( _wallkick_spin > 0 ) {
+ ++b2b;
+ } else {
+ b2b = 0;
+ }
+ } else {
+ combo = 0;
+ }
+ return clearnum;
+ }
+ int getAttack( int clearfull, signed char wallkick ) { // wallkick: 0: no spin 1: spin only 2: wallkick
+ int attack = 0;
+ if ( clearfull > 1 ) {
+ if ( clearfull < 4 ) {
+ attack = clearfull - 1;
+ } else {
+ attack = clearfull;
+ if ( b2b > 1 ) attack += 1;
+ }
+ }
+ if ( clearfull > 0 ) {
+ if ( wallkick ) {
+ if ( isEnableAllSpin() ) {
+ attack += clearfull + 1;
+ if ( wallkick == 2 ) { // mini
+ attack -= 1; // mini minus
+ }
+ } else {
+ if ( b2b > 1 ) attack += 1;
+ if ( clearfull == 1 ) {
+ if ( wallkick == 2 ) { // mini
+ attack += 1;
+ } else {
+ attack += 2;
+ }
+ } else {
+ attack += clearfull + 1;
+ }
+ if ( clearfull == 3 ) {
+ if ( b2b > 1 ) attack += 1;
+ }
+ }
+ }
+ attack += getComboAttack( combo );
+ {
+ int i = gem_add_y + m_h;
+ for ( ; i >= 0; --i ) {
+ if ( m_row[i] ) break;
+ }
+ if ( i < 0 ) {
+ attack += 6;
+ }
+ }
+ }
+ return attack;
+ }
+ void addRow( int rowdata ) {
+ for ( int h = -gem_add_y + 1; h <= m_h; ++h ) {
+ row[h-1] = row[h];
+ }
+ row[m_h] = rowdata;
+ }
+ };
+}
diff --git a/dllai/genmove.cpp b/dllai/genmove.cpp
new file mode 100644
index 0000000..8028768
--- /dev/null
+++ b/dllai/genmove.cpp
@@ -0,0 +1,488 @@
+#include "ai.h"
+#define USING_MOV_D 0
+#define GENMOV_W_MASK 15
+#define SWITCH_USING_HEIGHT_OPT
+
+#define _MACRO_CREATE_MOVINGSIMPLE(arg_action_name,arg_wkspin) \
+ MovingSimple nm = m; \
+ nm.x = nx; \
+ nm.y = ny; \
+ nm.spin = ns; \
+ nm.lastmove = Moving::##arg_action_name##; \
+ nm.wallkick_spin = arg_wkspin
+
+#define _MACRO_CREATE_MOVING(arg_action_name,arg_wkspin) \
+ Moving nm = m; \
+ nm.x = nx; \
+ nm.y = ny; \
+ nm.spin = ns; \
+ nm.movs.push_back(Moving::##arg_action_name##); \
+ nm.wallkick_spin = arg_wkspin
+#define _MACRO_HASH_POS(arg_hash_table,arg_prefix) \
+ arg_hash_table[##arg_prefix##y][##arg_prefix##s][##arg_prefix##x & GENMOV_W_MASK]
+
+namespace AI {
+ bool g_spin180 = false;
+ std::vector g_combo_attack;
+ bool g_allSpin = false;
+ bool g_softdrop = true;
+
+ void setSpin180( bool enable ) {
+ g_spin180 = enable;
+ }
+ bool spin180Enable() {
+ return g_spin180;
+ }
+ bool softdropEnable() {
+ return g_softdrop;
+ }
+
+ void setComboList( std::vector combolist ) {
+ g_combo_attack = combolist;
+ }
+ int getComboAttack( int combo ) {
+ if ( g_combo_attack.empty() ) return 0;
+ if ( combo >= (int)g_combo_attack.size() ) return g_combo_attack.back();
+ return g_combo_attack[combo];
+ }
+ void setAllSpin(bool allSpin) {
+ g_allSpin = allSpin;
+ }
+ void setSoftdrop( bool softdrop ) {
+ g_softdrop = softdrop;
+ }
+ bool isEnableAllSpin() {
+ return g_allSpin;
+ }
+
+ void GenMoving(const GameField& field, std::vector & movs, Gem cur, int x, int y, bool hold) {
+ movs.clear();
+ if ( field.isCollide(x, y, getGem(cur.num, cur.spin) ) ) {
+ return ;
+ }
+ char _hash[64][4][GENMOV_W_MASK+1] = {0};
+ char _hash_drop[64][4][GENMOV_W_MASK+1] = {0};
+ char (*hash)[4][GENMOV_W_MASK+1] = &_hash[gem_add_y];
+ char (*hash_drop)[4][GENMOV_W_MASK+1] = &_hash_drop[gem_add_y];
+ MovList q(1024);
+
+#ifdef SWITCH_USING_HEIGHT_OPT
+ // height of every column
+ int field_w = field.width(), field_h = field.height();
+ int min_y[32] = {0};
+ {
+ int beg_y = -5;
+ while ( field.row[beg_y] == 0 ) ++beg_y;
+ for ( int x = 0; x < field_w; ++x ) {
+ for ( int y = beg_y, ey = field_h + 1; y <= ey; ++y ) {
+ if ( field.row[y] & ( 1 << x ) ) {
+ min_y[x] = y;
+ break;
+ }
+ }
+ }
+ }
+#endif
+ {
+ MovingSimple m;
+ m.x = x;
+ m.y = y;
+ m.spin = cur.spin;
+ m.wallkick_spin = 0;
+ if ( hold ) {
+ m.lastmove = MovingSimple::MOV_HOLD;
+ m.hold = true;
+ } else {
+ m.lastmove = MovingSimple::MOV_NULL;
+ m.hold = false;
+ }
+ q.push(m);
+ hash[m.y][m.spin][m.x & GENMOV_W_MASK] = 1;
+ }
+ while ( ! q.empty() ) {
+ MovingSimple m;
+ q.pop(m);
+ if ( m.y < -1 ) continue;
+ if ( m.lastmove == MovingSimple::MOV_DROP ) {
+ movs.push_back(m);
+ continue;
+ }
+
+ if ( m.lastmove != MovingSimple::MOV_DD && m.lastmove != MovingSimple::MOV_D )
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ int wallkick_spin = m.wallkick_spin;
+#ifndef SWITCH_USING_HEIGHT_OPT
+ while ( field.row[ny + cur.geth()] == 0 && ny + cur.geth() <= field.height() ) { // ·Ç¿ÕÆøÐвÅÄÜʹÓõÄÓÅ»¯
+ ++ny; wallkick_spin = 0;
+ }
+ while ( ! field.isCollide(nx, ny + 1, getGem(cur.num, ns) ) ) {
+ if ( !USING_MOV_D && _MACRO_HASH_POS(hash, n) == 0) {
+ _MACRO_HASH_POS(hash, n) = 1;
+ }
+ ++ny; wallkick_spin = 0;
+ }
+#endif
+#ifdef SWITCH_USING_HEIGHT_OPT
+ {
+ int dist_min = 0x7fffffff;
+ for ( int x = 0; x < 4; ++x ) {
+ if ( getGemColH(cur.num, ns, x) ) { // 0 = empty column
+ int dist_cur_col = min_y[nx + x] - (ny + getGemColH(cur.num, ns, x));
+ if ( dist_cur_col < dist_min ) {
+ dist_min = dist_cur_col;
+ }
+ }
+ }
+ if ( dist_min < 0 ) { // underground
+ while ( ! field.isCollide(nx, ny + 1, getGem(cur.num, ns) ) ) {
+ if ( !USING_MOV_D && _MACRO_HASH_POS(hash,n) == 0) {
+ _MACRO_HASH_POS(hash,n) = 1;
+ }
+ ++ny; wallkick_spin = 0;
+ }
+ } else { // under the sun
+ ny = ny + dist_min;
+ if ( dist_min > 0 ) wallkick_spin = 0;
+ for ( int y = m.y + 1; y < ny; ++y ) {
+ if ( !USING_MOV_D && hash[y][ns][nx & GENMOV_W_MASK] == 0) {
+ hash[y][ns][nx & GENMOV_W_MASK] = 1;
+ }
+ }
+ }
+ }
+#endif
+ {
+ int v_spin = ((isEnableAllSpin() || cur.num == GEMTYPE_T)) ? wallkick_spin : 0;
+ if ( (_MACRO_HASH_POS(hash_drop, n) & ( 1 << v_spin)) == 0 )
+ {
+
+ int _nx = nx, _ny = ny, _ns = ns;
+
+ if ( cur.num == GEMTYPE_I || cur.num == GEMTYPE_Z || cur.num == GEMTYPE_S ) {
+ if ( ns == GEMTYPE_T ) {
+ _ny = ny + 1;
+ _ns = 0;
+ }
+ if ( ns == 3 ) {
+ _nx = nx + 1;
+ _ns = 1;
+ }
+ }
+
+ if ( (_MACRO_HASH_POS(hash_drop, _n) & ( 1 << v_spin)) == 0 ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_DROP, wallkick_spin);
+ if ( wallkick_spin ) _MACRO_HASH_POS(hash_drop, _n) |= 1 << wallkick_spin;
+ else _MACRO_HASH_POS(hash_drop, _n) |= 1;
+ q.push(nm);
+ }
+ }
+ if ( softdropEnable() ) // DD
+ {
+ if ( ny != y ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_DD, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ --nx;
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_L, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ if ( m.lastmove != MovingSimple::MOV_L && m.lastmove != MovingSimple::MOV_R
+ && m.lastmove != MovingSimple::MOV_LL && m.lastmove != MovingSimple::MOV_RR )
+ {
+ int nx = m.x - 1, ny = m.y, ns = m.spin;
+ while ( ! field.isCollide(nx - 1, ny, getGem(cur.num, ns) ) ) {
+ --nx;
+ }
+ if ( nx != x && _MACRO_HASH_POS(hash, n) == 0) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_LL, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ ++nx;
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_R, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ if ( m.lastmove != MovingSimple::MOV_L && m.lastmove != MovingSimple::MOV_R
+ && m.lastmove != MovingSimple::MOV_LL && m.lastmove != MovingSimple::MOV_RR )
+ {
+ int nx = m.x + 1, ny = m.y, ns = m.spin;
+ while ( ! field.isCollide(nx + 1, ny, getGem(cur.num, ns) ) ) {
+ ++nx;
+ }
+ if ( nx != x && _MACRO_HASH_POS(hash, n) == 0) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_RR, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+#if USING_MOV_D > 0
+ if ( m.lastmove != MovingSimple::MOV_DD )
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ ++ny;
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_D, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ }
+ }
+#endif
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 1) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_LSPIN, 1);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ } else if ( field.wallkickTest(nx, ny, getGem(cur.num, ns), 0 ) ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0 || cur.num == 2 && _MACRO_HASH_POS(hash, n) != 2 ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_LSPIN, 2);
+ _MACRO_HASH_POS(hash, n) = 2;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 3) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_RSPIN, 1);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ } else if ( field.wallkickTest(nx, ny, getGem(cur.num, ns), 1 ) ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0 || cur.num == 2 && _MACRO_HASH_POS(hash, n) != 2 ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_RSPIN, 2);
+ _MACRO_HASH_POS(hash, n) = 2;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ if ( spin180Enable() && m.lastmove != MovingSimple::MOV_SPIN2 ) // no 180 wallkick only
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 2) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_SPIN2, 1);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void FindPathMoving(const GameField& field, std::vector & movs, Gem cur, int x, int y, bool hold) {
+ movs.clear();
+ if ( field.isCollide(x, y, getGem(cur.num, cur.spin) ) ) {
+ return ;
+ }
+ char _hash[64][4][GENMOV_W_MASK+1] = {0};
+ char _hash_drop[64][4][GENMOV_W_MASK+1] = {0};
+ char (*hash)[4][GENMOV_W_MASK+1] = &_hash[gem_add_y];
+ char (*hash_drop)[4][GENMOV_W_MASK+1] = &_hash_drop[gem_add_y];
+ MovList q(1024);
+ {
+ Moving m;
+ m.x = x;
+ m.y = y;
+ m.spin = cur.spin;
+ m.wallkick_spin = 0;
+ if ( hold ) {
+ m.movs.push_back(Moving::MOV_HOLD);
+ } else {
+ m.movs.push_back(Moving::MOV_NULL);
+ }
+ m.score = 0;
+ q.push(m);
+ hash[m.y][m.spin][m.x & GENMOV_W_MASK] = 1;
+ }
+ while ( ! q.empty() ) {
+ Moving m;
+ q.pop(m);
+ if ( m.y < -1 ) continue;
+ if ( m.movs.back() == Moving::MOV_DROP) {
+ movs.push_back(m);
+ continue;
+ }
+
+ if ( m.movs.back() != Moving::MOV_DD && m.movs.back() != Moving::MOV_D)
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ int wallkick_spin = m.wallkick_spin;
+ //while ( field.row[ny + cur.geth()] == 0 && ny + cur.geth() <= field.height() ) { // ·Ç¿ÕÆøÐвÅÄÜʹÓõÄÓÅ»¯
+ // ++ny; wallkick_spin = 0;
+ //}
+ while ( ! field.isCollide(nx, ny + 1, getGem(cur.num, ns) ) ) {
+ //if ( !USING_MOV_D && _MACRO_HASH_POS(hash, n) == 0) {
+ // _MACRO_HASH_POS(hash, n) = 1;
+ //}
+ ++ny; wallkick_spin = 0;
+ }
+ {
+ int v_spin = ((isEnableAllSpin() || cur.num == GEMTYPE_T)) ? wallkick_spin : 0;
+ if ( (_MACRO_HASH_POS(hash_drop, n) & ( 1 << v_spin)) == 0 )
+ {
+ int _nx = nx, _ny = ny, _ns = ns;
+ if ( (_MACRO_HASH_POS(hash_drop, _n) & ( 1 << v_spin)) == 0 ) {
+ _MACRO_CREATE_MOVING(MOV_DROP, wallkick_spin);
+ if ( wallkick_spin ) _MACRO_HASH_POS(hash_drop, _n) |= 1 << wallkick_spin;
+ else _MACRO_HASH_POS(hash_drop, _n) |= 1;
+ q.push(nm);
+ }
+ }
+ if ( softdropEnable() ) {
+ if ( ny != y ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ _MACRO_CREATE_MOVING(MOV_DD, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ --nx;
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVING(MOV_L, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ if ( m.movs.back() != Moving::MOV_L && m.movs.back() != Moving::MOV_R
+ && m.movs.back() != Moving::MOV_LL && m.movs.back() != Moving::MOV_RR )
+ {
+ int nx = m.x - 1, ny = m.y, ns = m.spin;
+ while ( ! field.isCollide(nx - 1, ny, getGem(cur.num, ns) ) ) {
+ --nx;
+ }
+ if ( nx != x && _MACRO_HASH_POS(hash, n) == 0) {
+ _MACRO_CREATE_MOVING(MOV_LL, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ ++nx;
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVING(MOV_R, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ if ( m.movs.back() != Moving::MOV_L && m.movs.back() != Moving::MOV_R
+ && m.movs.back() != Moving::MOV_LL && m.movs.back() != Moving::MOV_RR )
+ {
+ int nx = m.x + 1, ny = m.y, ns = m.spin;
+ while ( ! field.isCollide(nx + 1, ny, getGem(cur.num, ns) ) ) {
+ ++nx;
+ }
+ if ( nx != x && _MACRO_HASH_POS(hash, n) == 0) {
+ _MACRO_CREATE_MOVING(MOV_RR, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ //if (USING_MOV_D)
+ if ( m.movs.back() != Moving::MOV_DD )
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ ++ny;
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVING(MOV_D, 0);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 1) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ _MACRO_CREATE_MOVING(MOV_LSPIN, 1);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ } else if ( field.wallkickTest(nx, ny, getGem(cur.num, ns), 0 ) ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0 || cur.num == 2 && _MACRO_HASH_POS(hash, n) != 2 ) {
+ _MACRO_CREATE_MOVING(MOV_LSPIN, 2);
+ _MACRO_HASH_POS(hash, n) = 2;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 3) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ _MACRO_CREATE_MOVING(MOV_RSPIN, 1);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ } else if ( field.wallkickTest(nx, ny, getGem(cur.num, ns), 1 ) ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0 || cur.num == 2 && _MACRO_HASH_POS(hash, n) != 2 ) {
+ _MACRO_CREATE_MOVING(MOV_RSPIN, 2);
+ _MACRO_HASH_POS(hash, n) = 2;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ if ( spin180Enable() ) //&& m.movs.back() != Moving::MOV_SPIN2 ) // no 180 wallkick only
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 2) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( _MACRO_HASH_POS(hash, n) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVING(MOV_SPIN2, 1);
+ _MACRO_HASH_POS(hash, n) = 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/dllai/targetver.h b/dllai/targetver.h
new file mode 100644
index 0000000..87c0086
--- /dev/null
+++ b/dllai/targetver.h
@@ -0,0 +1,8 @@
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include
diff --git a/dllai/tetris_gem.cpp b/dllai/tetris_gem.cpp
new file mode 100644
index 0000000..653a3b5
--- /dev/null
+++ b/dllai/tetris_gem.cpp
@@ -0,0 +1,81 @@
+#include "tetris_gem.h"
+
+namespace AI {
+ Gem gems[8][4];
+ int GEM_COL_H[8][4][4];
+
+ class init_obj {
+ public:
+ init_obj() {
+ Gem _gems[8][4] = {
+ {
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0},
+ },
+ { // I 1
+ { 0,15, 0, 0},
+ { 2, 2, 2, 2},
+ { 0, 0,15, 0},
+ { 4, 4, 4, 4},
+ },
+ { // T 2
+ { 2, 7, 0, 0},
+ { 2, 3, 2, 0},
+ { 0, 7, 2, 0},
+ { 2, 6, 2, 0},
+ },
+ { // L 3
+ { 4, 7, 0, 0},
+ { 3, 2, 2, 0},
+ { 0, 7, 1, 0},
+ { 2, 2, 6, 0},
+ },
+ { // J 4
+ { 1, 7, 0, 0},
+ { 2, 2, 3, 0},
+ { 0, 7, 4, 0},
+ { 6, 2, 2, 0},
+ },
+ { // Z 5
+ { 3, 6, 0, 0},
+ { 2, 3, 1, 0},
+ { 0, 3, 6, 0},
+ { 4, 6, 2, 0},
+ },
+ { // S 6
+ { 6, 3, 0, 0},
+ { 1, 3, 2, 0},
+ { 0, 6, 3, 0},
+ { 2, 6, 4, 0},
+ },
+ { // O 7
+ { 6, 6, 0, 0},
+ { 6, 6, 0, 0},
+ { 6, 6, 0, 0},
+ { 6, 6, 0, 0},
+ },
+ };
+ int m[] = {1, 4, 4, 4, 4, 4, 4, 1}; // TOP SRS
+ for ( int n = 0; n < 8; ++n) {
+ for ( int s = 0; s < 4; ++s) {
+ gems[n][s] = _gems[n][s];
+ gems[n][s].num = n;
+ gems[n][s].mod = m[n];
+ gems[n][s].spin = s % m[n];
+ //GEM_COL_H Initialization
+ for ( int x = 0; x < 4; ++x) {
+ GEM_COL_H[n][s][x] = 0;
+ for ( int y = 0; y < 4; ++y) {
+ if(gems[n][s].bitmap[y] & (1 << x)) {
+ GEM_COL_H[n][s][x] = y + 1;
+ //I vertical: 0 4 0 0
+ }
+ }
+ }
+ }
+ }
+ }
+ } _o;
+}
diff --git a/dllai/tetris_gem.h b/dllai/tetris_gem.h
new file mode 100644
index 0000000..34689a1
--- /dev/null
+++ b/dllai/tetris_gem.h
@@ -0,0 +1,34 @@
+#pragma once
+#define _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH
+
+#if _MSC_VER <= 1200
+#define for if (0); else for
+#pragma warning(disable : 4786)
+#endif
+
+namespace AI {
+ enum GemType {
+ GEMTYPE_NULL,
+ GEMTYPE_I,
+ GEMTYPE_T,
+ GEMTYPE_L,
+ GEMTYPE_J,
+ GEMTYPE_Z,
+ GEMTYPE_S,
+ GEMTYPE_O,
+ };
+ struct Gem {
+ unsigned long bitmap[4];
+ int num, spin, mod;
+ int geth() const { return 4; }
+ };
+ inline Gem& getGem( int number, int spin ) {
+ extern Gem gems[8][4];
+ return gems[number][spin];
+ }
+ inline int getGemColH( int number, int spin, int x) {
+ extern int GEM_COL_H[8][4][4];
+ return GEM_COL_H[number][spin][x];
+ }
+
+}
diff --git a/tetris_ai/Profile.cpp b/tetris_ai/Profile.cpp
new file mode 100644
index 0000000..27d305b
--- /dev/null
+++ b/tetris_ai/Profile.cpp
@@ -0,0 +1,19 @@
+#include "Profile.h"
+
+
+CProfile::CProfile(void)
+{
+ char buff[1024];
+ m_errcode = 0;
+ ::GetCurrentDirectoryA(1024, buff);
+ m_path = buff;
+ char back = m_path[m_path.size()-1];
+ if ( back != '\\' && back != '/' ) {
+ m_path += '\\';
+ }
+}
+
+
+CProfile::~CProfile(void)
+{
+}
diff --git a/tetris_ai/Profile.h b/tetris_ai/Profile.h
new file mode 100644
index 0000000..dfbb792
--- /dev/null
+++ b/tetris_ai/Profile.h
@@ -0,0 +1,53 @@
+#pragma once
+#include "windows.h"
+#include
+
+class CProfile
+{
+public:
+ CProfile(void) ;
+ virtual ~CProfile(void);
+ void SetFile( std::string name ) {
+ m_filename = name;
+ }
+ void SetSection( std::string section ) {
+ m_section = section;
+ }
+ int WriteString( std::string key, std::string value ) {
+ return WritePrivateProfileStringA( m_section.c_str(), key.c_str(), value.c_str(), (m_path + m_filename).c_str() );
+ }
+ int WriteInteger( std::string key, int value ) {
+ char buff[1024];
+ sprintf( buff, "%d", value );
+ return WriteString( key, buff );
+ }
+ int ReadString( std::string key, std::string& value ) {
+ char buff[1024];
+ int ret = GetPrivateProfileStringA( m_section.c_str(), key.c_str(), "", buff, 1024, (m_path + m_filename).c_str() );
+ if ( ret > 0 ) value = buff;
+ return ret;
+ }
+ bool IsInteger( std::string key ) {
+ ReadInteger( key );
+ return m_errcode == 0;
+ }
+ int ReadInteger( std::string key ) {
+ std::string s;
+ if ( ReadString( key, s ) > 0 ) {
+ int ret;
+ if ( sscanf( s.c_str(), "%d", &ret ) > 0 ) {
+ m_errcode = 0;
+ return ret;
+ }
+ m_errcode = 1;
+ }
+ m_errcode = 2;
+ return 0;
+ }
+private:
+ int m_errcode;
+ std::string m_path;
+ std::string m_filename;
+ std::string m_section;
+};
+
diff --git a/tetris_ai/Tspin.sln b/tetris_ai/Tspin.sln
new file mode 100644
index 0000000..f99cf13
--- /dev/null
+++ b/tetris_ai/Tspin.sln
@@ -0,0 +1,34 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tspin", "tetris_ai.vcxproj", "{1063E110-F488-4ADA-8632-AB6E53E8BEDD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dllai", "..\dllai\dllai.vcxproj", "{AFFA8B7C-EAAA-46F7-92B2-1A1F422B1EF3}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ XP_Release|Win32 = XP_Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1063E110-F488-4ADA-8632-AB6E53E8BEDD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1063E110-F488-4ADA-8632-AB6E53E8BEDD}.Debug|Win32.Build.0 = Debug|Win32
+ {1063E110-F488-4ADA-8632-AB6E53E8BEDD}.Release|Win32.ActiveCfg = Release|Win32
+ {1063E110-F488-4ADA-8632-AB6E53E8BEDD}.Release|Win32.Build.0 = Release|Win32
+ {1063E110-F488-4ADA-8632-AB6E53E8BEDD}.XP_Release|Win32.ActiveCfg = XP_Release|Win32
+ {1063E110-F488-4ADA-8632-AB6E53E8BEDD}.XP_Release|Win32.Build.0 = XP_Release|Win32
+ {AFFA8B7C-EAAA-46F7-92B2-1A1F422B1EF3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AFFA8B7C-EAAA-46F7-92B2-1A1F422B1EF3}.Debug|Win32.Build.0 = Debug|Win32
+ {AFFA8B7C-EAAA-46F7-92B2-1A1F422B1EF3}.Release|Win32.ActiveCfg = Release|Win32
+ {AFFA8B7C-EAAA-46F7-92B2-1A1F422B1EF3}.Release|Win32.Build.0 = Release|Win32
+ {AFFA8B7C-EAAA-46F7-92B2-1A1F422B1EF3}.XP_Release|Win32.ActiveCfg = XP_Release|Win32
+ {AFFA8B7C-EAAA-46F7-92B2-1A1F422B1EF3}.XP_Release|Win32.Build.0 = XP_Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
+EndGlobal
diff --git a/tetris_ai/Tspin08.rc b/tetris_ai/Tspin08.rc
new file mode 100644
index 0000000..0dbf7a5
--- /dev/null
+++ b/tetris_ai/Tspin08.rc
@@ -0,0 +1,72 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource1.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Chinese (P.R.C.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
+#ifdef _WIN32
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
+#pragma code_page(936)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource1.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON1 ICON "tetris.ico"
+#endif // Chinese (P.R.C.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/tetris_ai/Tspin08.sln b/tetris_ai/Tspin08.sln
new file mode 100644
index 0000000..ddff32c
--- /dev/null
+++ b/tetris_ai/Tspin08.sln
@@ -0,0 +1,29 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tspin08", "Tspin08.vcproj", "{5F5C2F45-C92B-4EAA-A48C-3325B390CA29}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90396E54-F76B-4A1D-9291-720FDA200388} = {90396E54-F76B-4A1D-9291-720FDA200388}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dllai", "..\dllai\dllai.vcproj", "{90396E54-F76B-4A1D-9291-720FDA200388}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5F5C2F45-C92B-4EAA-A48C-3325B390CA29}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5F5C2F45-C92B-4EAA-A48C-3325B390CA29}.Debug|Win32.Build.0 = Debug|Win32
+ {5F5C2F45-C92B-4EAA-A48C-3325B390CA29}.Release|Win32.ActiveCfg = Release|Win32
+ {5F5C2F45-C92B-4EAA-A48C-3325B390CA29}.Release|Win32.Build.0 = Release|Win32
+ {90396E54-F76B-4A1D-9291-720FDA200388}.Debug|Win32.ActiveCfg = Debug|Win32
+ {90396E54-F76B-4A1D-9291-720FDA200388}.Debug|Win32.Build.0 = Debug|Win32
+ {90396E54-F76B-4A1D-9291-720FDA200388}.Release|Win32.ActiveCfg = Release|Win32
+ {90396E54-F76B-4A1D-9291-720FDA200388}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/tetris_ai/Tspin08.vcproj b/tetris_ai/Tspin08.vcproj
new file mode 100644
index 0000000..7763103
--- /dev/null
+++ b/tetris_ai/Tspin08.vcproj
@@ -0,0 +1,283 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tetris_ai/bass.h b/tetris_ai/bass.h
new file mode 100644
index 0000000..163664b
--- /dev/null
+++ b/tetris_ai/bass.h
@@ -0,0 +1,990 @@
+/*
+ BASS 2.4 C/C++ header file
+ Copyright (c) 1999-2013 Un4seen Developments Ltd.
+
+ See the BASS.CHM file for more detailed documentation
+*/
+
+#ifndef BASS_H
+#define BASS_H
+
+#ifdef _WIN32
+#include
+typedef unsigned __int64 QWORD;
+#else
+#include
+#define WINAPI
+#define CALLBACK
+typedef uint8_t BYTE;
+typedef uint16_t WORD;
+typedef uint32_t DWORD;
+typedef uint64_t QWORD;
+#ifndef __OBJC__
+typedef int BOOL;
+#endif
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+#define LOBYTE(a) (BYTE)(a)
+#define HIBYTE(a) (BYTE)((a)>>8)
+#define LOWORD(a) (WORD)(a)
+#define HIWORD(a) (WORD)((a)>>16)
+#define MAKEWORD(a,b) (WORD)(((a)&0xff)|((b)<<8))
+#define MAKELONG(a,b) (DWORD)(((a)&0xffff)|((b)<<16))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BASSVERSION 0x204 // API version
+#define BASSVERSIONTEXT "2.4"
+
+#ifndef BASSDEF
+#define BASSDEF(f) WINAPI f
+#endif
+
+typedef DWORD HMUSIC; // MOD music handle
+typedef DWORD HSAMPLE; // sample handle
+typedef DWORD HCHANNEL; // playing sample's channel handle
+typedef DWORD HSTREAM; // sample stream handle
+typedef DWORD HRECORD; // recording handle
+typedef DWORD HSYNC; // synchronizer handle
+typedef DWORD HDSP; // DSP handle
+typedef DWORD HFX; // DX8 effect handle
+typedef DWORD HPLUGIN; // Plugin handle
+
+// Error codes returned by BASS_ErrorGetCode
+#define BASS_OK 0 // all is OK
+#define BASS_ERROR_MEM 1 // memory error
+#define BASS_ERROR_FILEOPEN 2 // can't open the file
+#define BASS_ERROR_DRIVER 3 // can't find a free/valid driver
+#define BASS_ERROR_BUFLOST 4 // the sample buffer was lost
+#define BASS_ERROR_HANDLE 5 // invalid handle
+#define BASS_ERROR_FORMAT 6 // unsupported sample format
+#define BASS_ERROR_POSITION 7 // invalid position
+#define BASS_ERROR_INIT 8 // BASS_Init has not been successfully called
+#define BASS_ERROR_START 9 // BASS_Start has not been successfully called
+#define BASS_ERROR_ALREADY 14 // already initialized/paused/whatever
+#define BASS_ERROR_NOCHAN 18 // can't get a free channel
+#define BASS_ERROR_ILLTYPE 19 // an illegal type was specified
+#define BASS_ERROR_ILLPARAM 20 // an illegal parameter was specified
+#define BASS_ERROR_NO3D 21 // no 3D support
+#define BASS_ERROR_NOEAX 22 // no EAX support
+#define BASS_ERROR_DEVICE 23 // illegal device number
+#define BASS_ERROR_NOPLAY 24 // not playing
+#define BASS_ERROR_FREQ 25 // illegal sample rate
+#define BASS_ERROR_NOTFILE 27 // the stream is not a file stream
+#define BASS_ERROR_NOHW 29 // no hardware voices available
+#define BASS_ERROR_EMPTY 31 // the MOD music has no sequence data
+#define BASS_ERROR_NONET 32 // no internet connection could be opened
+#define BASS_ERROR_CREATE 33 // couldn't create the file
+#define BASS_ERROR_NOFX 34 // effects are not available
+#define BASS_ERROR_NOTAVAIL 37 // requested data is not available
+#define BASS_ERROR_DECODE 38 // the channel is/isn't a "decoding channel"
+#define BASS_ERROR_DX 39 // a sufficient DirectX version is not installed
+#define BASS_ERROR_TIMEOUT 40 // connection timedout
+#define BASS_ERROR_FILEFORM 41 // unsupported file format
+#define BASS_ERROR_SPEAKER 42 // unavailable speaker
+#define BASS_ERROR_VERSION 43 // invalid BASS version (used by add-ons)
+#define BASS_ERROR_CODEC 44 // codec is not available/supported
+#define BASS_ERROR_ENDED 45 // the channel/file has ended
+#define BASS_ERROR_BUSY 46 // the device is busy
+#define BASS_ERROR_UNKNOWN -1 // some other mystery problem
+
+// BASS_SetConfig options
+#define BASS_CONFIG_BUFFER 0
+#define BASS_CONFIG_UPDATEPERIOD 1
+#define BASS_CONFIG_GVOL_SAMPLE 4
+#define BASS_CONFIG_GVOL_STREAM 5
+#define BASS_CONFIG_GVOL_MUSIC 6
+#define BASS_CONFIG_CURVE_VOL 7
+#define BASS_CONFIG_CURVE_PAN 8
+#define BASS_CONFIG_FLOATDSP 9
+#define BASS_CONFIG_3DALGORITHM 10
+#define BASS_CONFIG_NET_TIMEOUT 11
+#define BASS_CONFIG_NET_BUFFER 12
+#define BASS_CONFIG_PAUSE_NOPLAY 13
+#define BASS_CONFIG_NET_PREBUF 15
+#define BASS_CONFIG_NET_PASSIVE 18
+#define BASS_CONFIG_REC_BUFFER 19
+#define BASS_CONFIG_NET_PLAYLIST 21
+#define BASS_CONFIG_MUSIC_VIRTUAL 22
+#define BASS_CONFIG_VERIFY 23
+#define BASS_CONFIG_UPDATETHREADS 24
+#define BASS_CONFIG_DEV_BUFFER 27
+#define BASS_CONFIG_VISTA_TRUEPOS 30
+#define BASS_CONFIG_IOS_MIXAUDIO 34
+#define BASS_CONFIG_DEV_DEFAULT 36
+#define BASS_CONFIG_NET_READTIMEOUT 37
+#define BASS_CONFIG_VISTA_SPEAKERS 38
+#define BASS_CONFIG_IOS_SPEAKER 39
+#define BASS_CONFIG_HANDLES 41
+#define BASS_CONFIG_UNICODE 42
+#define BASS_CONFIG_SRC 43
+#define BASS_CONFIG_SRC_SAMPLE 44
+#define BASS_CONFIG_ASYNCFILE_BUFFER 45
+#define BASS_CONFIG_OGG_PRESCAN 47
+
+// BASS_SetConfigPtr options
+#define BASS_CONFIG_NET_AGENT 16
+#define BASS_CONFIG_NET_PROXY 17
+#define BASS_CONFIG_IOS_NOTIFY 46
+
+// BASS_Init flags
+#define BASS_DEVICE_8BITS 1 // 8 bit resolution, else 16 bit
+#define BASS_DEVICE_MONO 2 // mono, else stereo
+#define BASS_DEVICE_3D 4 // enable 3D functionality
+#define BASS_DEVICE_LATENCY 0x100 // calculate device latency (BASS_INFO struct)
+#define BASS_DEVICE_CPSPEAKERS 0x400 // detect speakers via Windows control panel
+#define BASS_DEVICE_SPEAKERS 0x800 // force enabling of speaker assignment
+#define BASS_DEVICE_NOSPEAKER 0x1000 // ignore speaker arrangement
+#define BASS_DEVICE_DMIX 0x2000 // use ALSA "dmix" plugin
+#define BASS_DEVICE_FREQ 0x4000 // set device sample rate
+
+// DirectSound interfaces (for use with BASS_GetDSoundObject)
+#define BASS_OBJECT_DS 1 // IDirectSound
+#define BASS_OBJECT_DS3DL 2 // IDirectSound3DListener
+
+// Device info structure
+typedef struct {
+#ifdef _WIN32_WCE
+ const wchar_t *name; // description
+ const wchar_t *driver; // driver
+#else
+ const char *name; // description
+ const char *driver; // driver
+#endif
+ DWORD flags;
+} BASS_DEVICEINFO;
+
+// BASS_DEVICEINFO flags
+#define BASS_DEVICE_ENABLED 1
+#define BASS_DEVICE_DEFAULT 2
+#define BASS_DEVICE_INIT 4
+
+typedef struct {
+ DWORD flags; // device capabilities (DSCAPS_xxx flags)
+ DWORD hwsize; // size of total device hardware memory
+ DWORD hwfree; // size of free device hardware memory
+ DWORD freesam; // number of free sample slots in the hardware
+ DWORD free3d; // number of free 3D sample slots in the hardware
+ DWORD minrate; // min sample rate supported by the hardware
+ DWORD maxrate; // max sample rate supported by the hardware
+ BOOL eax; // device supports EAX? (always FALSE if BASS_DEVICE_3D was not used)
+ DWORD minbuf; // recommended minimum buffer length in ms (requires BASS_DEVICE_LATENCY)
+ DWORD dsver; // DirectSound version
+ DWORD latency; // delay (in ms) before start of playback (requires BASS_DEVICE_LATENCY)
+ DWORD initflags; // BASS_Init "flags" parameter
+ DWORD speakers; // number of speakers available
+ DWORD freq; // current output rate
+} BASS_INFO;
+
+// BASS_INFO flags (from DSOUND.H)
+#define DSCAPS_CONTINUOUSRATE 0x00000010 // supports all sample rates between min/maxrate
+#define DSCAPS_EMULDRIVER 0x00000020 // device does NOT have hardware DirectSound support
+#define DSCAPS_CERTIFIED 0x00000040 // device driver has been certified by Microsoft
+#define DSCAPS_SECONDARYMONO 0x00000100 // mono
+#define DSCAPS_SECONDARYSTEREO 0x00000200 // stereo
+#define DSCAPS_SECONDARY8BIT 0x00000400 // 8 bit
+#define DSCAPS_SECONDARY16BIT 0x00000800 // 16 bit
+
+// Recording device info structure
+typedef struct {
+ DWORD flags; // device capabilities (DSCCAPS_xxx flags)
+ DWORD formats; // supported standard formats (WAVE_FORMAT_xxx flags)
+ DWORD inputs; // number of inputs
+ BOOL singlein; // TRUE = only 1 input can be set at a time
+ DWORD freq; // current input rate
+} BASS_RECORDINFO;
+
+// BASS_RECORDINFO flags (from DSOUND.H)
+#define DSCCAPS_EMULDRIVER DSCAPS_EMULDRIVER // device does NOT have hardware DirectSound recording support
+#define DSCCAPS_CERTIFIED DSCAPS_CERTIFIED // device driver has been certified by Microsoft
+
+// defines for formats field of BASS_RECORDINFO (from MMSYSTEM.H)
+#ifndef WAVE_FORMAT_1M08
+#define WAVE_FORMAT_1M08 0x00000001 /* 11.025 kHz, Mono, 8-bit */
+#define WAVE_FORMAT_1S08 0x00000002 /* 11.025 kHz, Stereo, 8-bit */
+#define WAVE_FORMAT_1M16 0x00000004 /* 11.025 kHz, Mono, 16-bit */
+#define WAVE_FORMAT_1S16 0x00000008 /* 11.025 kHz, Stereo, 16-bit */
+#define WAVE_FORMAT_2M08 0x00000010 /* 22.05 kHz, Mono, 8-bit */
+#define WAVE_FORMAT_2S08 0x00000020 /* 22.05 kHz, Stereo, 8-bit */
+#define WAVE_FORMAT_2M16 0x00000040 /* 22.05 kHz, Mono, 16-bit */
+#define WAVE_FORMAT_2S16 0x00000080 /* 22.05 kHz, Stereo, 16-bit */
+#define WAVE_FORMAT_4M08 0x00000100 /* 44.1 kHz, Mono, 8-bit */
+#define WAVE_FORMAT_4S08 0x00000200 /* 44.1 kHz, Stereo, 8-bit */
+#define WAVE_FORMAT_4M16 0x00000400 /* 44.1 kHz, Mono, 16-bit */
+#define WAVE_FORMAT_4S16 0x00000800 /* 44.1 kHz, Stereo, 16-bit */
+#endif
+
+// Sample info structure
+typedef struct {
+ DWORD freq; // default playback rate
+ float volume; // default volume (0-1)
+ float pan; // default pan (-1=left, 0=middle, 1=right)
+ DWORD flags; // BASS_SAMPLE_xxx flags
+ DWORD length; // length (in bytes)
+ DWORD max; // maximum simultaneous playbacks
+ DWORD origres; // original resolution bits
+ DWORD chans; // number of channels
+ DWORD mingap; // minimum gap (ms) between creating channels
+ DWORD mode3d; // BASS_3DMODE_xxx mode
+ float mindist; // minimum distance
+ float maxdist; // maximum distance
+ DWORD iangle; // angle of inside projection cone
+ DWORD oangle; // angle of outside projection cone
+ float outvol; // delta-volume outside the projection cone
+ DWORD vam; // voice allocation/management flags (BASS_VAM_xxx)
+ DWORD priority; // priority (0=lowest, 0xffffffff=highest)
+} BASS_SAMPLE;
+
+#define BASS_SAMPLE_8BITS 1 // 8 bit
+#define BASS_SAMPLE_FLOAT 256 // 32-bit floating-point
+#define BASS_SAMPLE_MONO 2 // mono
+#define BASS_SAMPLE_LOOP 4 // looped
+#define BASS_SAMPLE_3D 8 // 3D functionality
+#define BASS_SAMPLE_SOFTWARE 16 // not using hardware mixing
+#define BASS_SAMPLE_MUTEMAX 32 // mute at max distance (3D only)
+#define BASS_SAMPLE_VAM 64 // DX7 voice allocation & management
+#define BASS_SAMPLE_FX 128 // old implementation of DX8 effects
+#define BASS_SAMPLE_OVER_VOL 0x10000 // override lowest volume
+#define BASS_SAMPLE_OVER_POS 0x20000 // override longest playing
+#define BASS_SAMPLE_OVER_DIST 0x30000 // override furthest from listener (3D only)
+
+#define BASS_STREAM_PRESCAN 0x20000 // enable pin-point seeking/length (MP3/MP2/MP1)
+#define BASS_MP3_SETPOS BASS_STREAM_PRESCAN
+#define BASS_STREAM_AUTOFREE 0x40000 // automatically free the stream when it stop/ends
+#define BASS_STREAM_RESTRATE 0x80000 // restrict the download rate of internet file streams
+#define BASS_STREAM_BLOCK 0x100000 // download/play internet file stream in small blocks
+#define BASS_STREAM_DECODE 0x200000 // don't play the stream, only decode (BASS_ChannelGetData)
+#define BASS_STREAM_STATUS 0x800000 // give server status info (HTTP/ICY tags) in DOWNLOADPROC
+
+#define BASS_MUSIC_FLOAT BASS_SAMPLE_FLOAT
+#define BASS_MUSIC_MONO BASS_SAMPLE_MONO
+#define BASS_MUSIC_LOOP BASS_SAMPLE_LOOP
+#define BASS_MUSIC_3D BASS_SAMPLE_3D
+#define BASS_MUSIC_FX BASS_SAMPLE_FX
+#define BASS_MUSIC_AUTOFREE BASS_STREAM_AUTOFREE
+#define BASS_MUSIC_DECODE BASS_STREAM_DECODE
+#define BASS_MUSIC_PRESCAN BASS_STREAM_PRESCAN // calculate playback length
+#define BASS_MUSIC_CALCLEN BASS_MUSIC_PRESCAN
+#define BASS_MUSIC_RAMP 0x200 // normal ramping
+#define BASS_MUSIC_RAMPS 0x400 // sensitive ramping
+#define BASS_MUSIC_SURROUND 0x800 // surround sound
+#define BASS_MUSIC_SURROUND2 0x1000 // surround sound (mode 2)
+#define BASS_MUSIC_FT2MOD 0x2000 // play .MOD as FastTracker 2 does
+#define BASS_MUSIC_PT1MOD 0x4000 // play .MOD as ProTracker 1 does
+#define BASS_MUSIC_NONINTER 0x10000 // non-interpolated sample mixing
+#define BASS_MUSIC_SINCINTER 0x800000 // sinc interpolated sample mixing
+#define BASS_MUSIC_POSRESET 0x8000 // stop all notes when moving position
+#define BASS_MUSIC_POSRESETEX 0x400000 // stop all notes and reset bmp/etc when moving position
+#define BASS_MUSIC_STOPBACK 0x80000 // stop the music on a backwards jump effect
+#define BASS_MUSIC_NOSAMPLE 0x100000 // don't load the samples
+
+// Speaker assignment flags
+#define BASS_SPEAKER_FRONT 0x1000000 // front speakers
+#define BASS_SPEAKER_REAR 0x2000000 // rear/side speakers
+#define BASS_SPEAKER_CENLFE 0x3000000 // center & LFE speakers (5.1)
+#define BASS_SPEAKER_REAR2 0x4000000 // rear center speakers (7.1)
+#define BASS_SPEAKER_N(n) ((n)<<24) // n'th pair of speakers (max 15)
+#define BASS_SPEAKER_LEFT 0x10000000 // modifier: left
+#define BASS_SPEAKER_RIGHT 0x20000000 // modifier: right
+#define BASS_SPEAKER_FRONTLEFT BASS_SPEAKER_FRONT|BASS_SPEAKER_LEFT
+#define BASS_SPEAKER_FRONTRIGHT BASS_SPEAKER_FRONT|BASS_SPEAKER_RIGHT
+#define BASS_SPEAKER_REARLEFT BASS_SPEAKER_REAR|BASS_SPEAKER_LEFT
+#define BASS_SPEAKER_REARRIGHT BASS_SPEAKER_REAR|BASS_SPEAKER_RIGHT
+#define BASS_SPEAKER_CENTER BASS_SPEAKER_CENLFE|BASS_SPEAKER_LEFT
+#define BASS_SPEAKER_LFE BASS_SPEAKER_CENLFE|BASS_SPEAKER_RIGHT
+#define BASS_SPEAKER_REAR2LEFT BASS_SPEAKER_REAR2|BASS_SPEAKER_LEFT
+#define BASS_SPEAKER_REAR2RIGHT BASS_SPEAKER_REAR2|BASS_SPEAKER_RIGHT
+
+#define BASS_ASYNCFILE 0x40000000
+#define BASS_UNICODE 0x80000000
+
+#define BASS_RECORD_PAUSE 0x8000 // start recording paused
+
+// DX7 voice allocation & management flags
+#define BASS_VAM_HARDWARE 1
+#define BASS_VAM_SOFTWARE 2
+#define BASS_VAM_TERM_TIME 4
+#define BASS_VAM_TERM_DIST 8
+#define BASS_VAM_TERM_PRIO 16
+
+// Channel info structure
+typedef struct {
+ DWORD freq; // default playback rate
+ DWORD chans; // channels
+ DWORD flags; // BASS_SAMPLE/STREAM/MUSIC/SPEAKER flags
+ DWORD ctype; // type of channel
+ DWORD origres; // original resolution
+ HPLUGIN plugin; // plugin
+ HSAMPLE sample; // sample
+ const char *filename; // filename
+} BASS_CHANNELINFO;
+
+// BASS_CHANNELINFO types
+#define BASS_CTYPE_SAMPLE 1
+#define BASS_CTYPE_RECORD 2
+#define BASS_CTYPE_STREAM 0x10000
+#define BASS_CTYPE_STREAM_OGG 0x10002
+#define BASS_CTYPE_STREAM_MP1 0x10003
+#define BASS_CTYPE_STREAM_MP2 0x10004
+#define BASS_CTYPE_STREAM_MP3 0x10005
+#define BASS_CTYPE_STREAM_AIFF 0x10006
+#define BASS_CTYPE_STREAM_CA 0x10007
+#define BASS_CTYPE_STREAM_MF 0x10008
+#define BASS_CTYPE_STREAM_WAV 0x40000 // WAVE flag, LOWORD=codec
+#define BASS_CTYPE_STREAM_WAV_PCM 0x50001
+#define BASS_CTYPE_STREAM_WAV_FLOAT 0x50003
+#define BASS_CTYPE_MUSIC_MOD 0x20000
+#define BASS_CTYPE_MUSIC_MTM 0x20001
+#define BASS_CTYPE_MUSIC_S3M 0x20002
+#define BASS_CTYPE_MUSIC_XM 0x20003
+#define BASS_CTYPE_MUSIC_IT 0x20004
+#define BASS_CTYPE_MUSIC_MO3 0x00100 // MO3 flag
+
+typedef struct {
+ DWORD ctype; // channel type
+#ifdef _WIN32_WCE
+ const wchar_t *name; // format description
+ const wchar_t *exts; // file extension filter (*.ext1;*.ext2;etc...)
+#else
+ const char *name; // format description
+ const char *exts; // file extension filter (*.ext1;*.ext2;etc...)
+#endif
+} BASS_PLUGINFORM;
+
+typedef struct {
+ DWORD version; // version (same form as BASS_GetVersion)
+ DWORD formatc; // number of formats
+ const BASS_PLUGINFORM *formats; // the array of formats
+} BASS_PLUGININFO;
+
+// 3D vector (for 3D positions/velocities/orientations)
+typedef struct BASS_3DVECTOR {
+#ifdef __cplusplus
+ BASS_3DVECTOR() {};
+ BASS_3DVECTOR(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {};
+#endif
+ float x; // +=right, -=left
+ float y; // +=up, -=down
+ float z; // +=front, -=behind
+} BASS_3DVECTOR;
+
+// 3D channel modes
+#define BASS_3DMODE_NORMAL 0 // normal 3D processing
+#define BASS_3DMODE_RELATIVE 1 // position is relative to the listener
+#define BASS_3DMODE_OFF 2 // no 3D processing
+
+// software 3D mixing algorithms (used with BASS_CONFIG_3DALGORITHM)
+#define BASS_3DALG_DEFAULT 0
+#define BASS_3DALG_OFF 1
+#define BASS_3DALG_FULL 2
+#define BASS_3DALG_LIGHT 3
+
+// EAX environments, use with BASS_SetEAXParameters
+enum
+{
+ EAX_ENVIRONMENT_GENERIC,
+ EAX_ENVIRONMENT_PADDEDCELL,
+ EAX_ENVIRONMENT_ROOM,
+ EAX_ENVIRONMENT_BATHROOM,
+ EAX_ENVIRONMENT_LIVINGROOM,
+ EAX_ENVIRONMENT_STONEROOM,
+ EAX_ENVIRONMENT_AUDITORIUM,
+ EAX_ENVIRONMENT_CONCERTHALL,
+ EAX_ENVIRONMENT_CAVE,
+ EAX_ENVIRONMENT_ARENA,
+ EAX_ENVIRONMENT_HANGAR,
+ EAX_ENVIRONMENT_CARPETEDHALLWAY,
+ EAX_ENVIRONMENT_HALLWAY,
+ EAX_ENVIRONMENT_STONECORRIDOR,
+ EAX_ENVIRONMENT_ALLEY,
+ EAX_ENVIRONMENT_FOREST,
+ EAX_ENVIRONMENT_CITY,
+ EAX_ENVIRONMENT_MOUNTAINS,
+ EAX_ENVIRONMENT_QUARRY,
+ EAX_ENVIRONMENT_PLAIN,
+ EAX_ENVIRONMENT_PARKINGLOT,
+ EAX_ENVIRONMENT_SEWERPIPE,
+ EAX_ENVIRONMENT_UNDERWATER,
+ EAX_ENVIRONMENT_DRUGGED,
+ EAX_ENVIRONMENT_DIZZY,
+ EAX_ENVIRONMENT_PSYCHOTIC,
+
+ EAX_ENVIRONMENT_COUNT // total number of environments
+};
+
+// EAX presets, usage: BASS_SetEAXParameters(EAX_PRESET_xxx)
+#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F
+#define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F
+#define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F
+#define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F
+#define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F
+#define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F
+#define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F
+#define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F
+#define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F
+#define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F
+#define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F
+#define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F
+#define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F
+#define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F
+#define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F
+#define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F
+#define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F
+#define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F
+#define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F
+#define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F
+#define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F
+#define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F
+#define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F
+#define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F
+#define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F
+#define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F
+
+typedef DWORD (CALLBACK STREAMPROC)(HSTREAM handle, void *buffer, DWORD length, void *user);
+/* User stream callback function. NOTE: A stream function should obviously be as quick
+as possible, other streams (and MOD musics) can't be mixed until it's finished.
+handle : The stream that needs writing
+buffer : Buffer to write the samples in
+length : Number of bytes to write
+user : The 'user' parameter value given when calling BASS_StreamCreate
+RETURN : Number of bytes written. Set the BASS_STREAMPROC_END flag to end
+ the stream. */
+
+#define BASS_STREAMPROC_END 0x80000000 // end of user stream flag
+
+// special STREAMPROCs
+#define STREAMPROC_DUMMY (STREAMPROC*)0 // "dummy" stream
+#define STREAMPROC_PUSH (STREAMPROC*)-1 // push stream
+
+// BASS_StreamCreateFileUser file systems
+#define STREAMFILE_NOBUFFER 0
+#define STREAMFILE_BUFFER 1
+#define STREAMFILE_BUFFERPUSH 2
+
+// User file stream callback functions
+typedef void (CALLBACK FILECLOSEPROC)(void *user);
+typedef QWORD (CALLBACK FILELENPROC)(void *user);
+typedef DWORD (CALLBACK FILEREADPROC)(void *buffer, DWORD length, void *user);
+typedef BOOL (CALLBACK FILESEEKPROC)(QWORD offset, void *user);
+
+typedef struct {
+ FILECLOSEPROC *close;
+ FILELENPROC *length;
+ FILEREADPROC *read;
+ FILESEEKPROC *seek;
+} BASS_FILEPROCS;
+
+// BASS_StreamPutFileData options
+#define BASS_FILEDATA_END 0 // end & close the file
+
+// BASS_StreamGetFilePosition modes
+#define BASS_FILEPOS_CURRENT 0
+#define BASS_FILEPOS_DECODE BASS_FILEPOS_CURRENT
+#define BASS_FILEPOS_DOWNLOAD 1
+#define BASS_FILEPOS_END 2
+#define BASS_FILEPOS_START 3
+#define BASS_FILEPOS_CONNECTED 4
+#define BASS_FILEPOS_BUFFER 5
+#define BASS_FILEPOS_SOCKET 6
+
+typedef void (CALLBACK DOWNLOADPROC)(const void *buffer, DWORD length, void *user);
+/* Internet stream download callback function.
+buffer : Buffer containing the downloaded data... NULL=end of download
+length : Number of bytes in the buffer
+user : The 'user' parameter value given when calling BASS_StreamCreateURL */
+
+// BASS_ChannelSetSync types
+#define BASS_SYNC_POS 0
+#define BASS_SYNC_END 2
+#define BASS_SYNC_META 4
+#define BASS_SYNC_SLIDE 5
+#define BASS_SYNC_STALL 6
+#define BASS_SYNC_DOWNLOAD 7
+#define BASS_SYNC_FREE 8
+#define BASS_SYNC_SETPOS 11
+#define BASS_SYNC_MUSICPOS 10
+#define BASS_SYNC_MUSICINST 1
+#define BASS_SYNC_MUSICFX 3
+#define BASS_SYNC_OGG_CHANGE 12
+#define BASS_SYNC_MIXTIME 0x40000000 // FLAG: sync at mixtime, else at playtime
+#define BASS_SYNC_ONETIME 0x80000000 // FLAG: sync only once, else continuously
+
+typedef void (CALLBACK SYNCPROC)(HSYNC handle, DWORD channel, DWORD data, void *user);
+/* Sync callback function. NOTE: a sync callback function should be very
+quick as other syncs can't be processed until it has finished. If the sync
+is a "mixtime" sync, then other streams and MOD musics can't be mixed until
+it's finished either.
+handle : The sync that has occured
+channel: Channel that the sync occured in
+data : Additional data associated with the sync's occurance
+user : The 'user' parameter given when calling BASS_ChannelSetSync */
+
+typedef void (CALLBACK DSPPROC)(HDSP handle, DWORD channel, void *buffer, DWORD length, void *user);
+/* DSP callback function. NOTE: A DSP function should obviously be as quick as
+possible... other DSP functions, streams and MOD musics can not be processed
+until it's finished.
+handle : The DSP handle
+channel: Channel that the DSP is being applied to
+buffer : Buffer to apply the DSP to
+length : Number of bytes in the buffer
+user : The 'user' parameter given when calling BASS_ChannelSetDSP */
+
+typedef BOOL (CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, DWORD length, void *user);
+/* Recording callback function.
+handle : The recording handle
+buffer : Buffer containing the recorded sample data
+length : Number of bytes
+user : The 'user' parameter value given when calling BASS_RecordStart
+RETURN : TRUE = continue recording, FALSE = stop */
+
+// BASS_ChannelIsActive return values
+#define BASS_ACTIVE_STOPPED 0
+#define BASS_ACTIVE_PLAYING 1
+#define BASS_ACTIVE_STALLED 2
+#define BASS_ACTIVE_PAUSED 3
+
+// Channel attributes
+#define BASS_ATTRIB_FREQ 1
+#define BASS_ATTRIB_VOL 2
+#define BASS_ATTRIB_PAN 3
+#define BASS_ATTRIB_EAXMIX 4
+#define BASS_ATTRIB_NOBUFFER 5
+#define BASS_ATTRIB_CPU 7
+#define BASS_ATTRIB_SRC 8
+#define BASS_ATTRIB_MUSIC_AMPLIFY 0x100
+#define BASS_ATTRIB_MUSIC_PANSEP 0x101
+#define BASS_ATTRIB_MUSIC_PSCALER 0x102
+#define BASS_ATTRIB_MUSIC_BPM 0x103
+#define BASS_ATTRIB_MUSIC_SPEED 0x104
+#define BASS_ATTRIB_MUSIC_VOL_GLOBAL 0x105
+#define BASS_ATTRIB_MUSIC_VOL_CHAN 0x200 // + channel #
+#define BASS_ATTRIB_MUSIC_VOL_INST 0x300 // + instrument #
+
+// BASS_ChannelGetData flags
+#define BASS_DATA_AVAILABLE 0 // query how much data is buffered
+#define BASS_DATA_FLOAT 0x40000000 // flag: return floating-point sample data
+#define BASS_DATA_FFT256 0x80000000 // 256 sample FFT
+#define BASS_DATA_FFT512 0x80000001 // 512 FFT
+#define BASS_DATA_FFT1024 0x80000002 // 1024 FFT
+#define BASS_DATA_FFT2048 0x80000003 // 2048 FFT
+#define BASS_DATA_FFT4096 0x80000004 // 4096 FFT
+#define BASS_DATA_FFT8192 0x80000005 // 8192 FFT
+#define BASS_DATA_FFT16384 0x80000006 // 16384 FFT
+#define BASS_DATA_FFT_INDIVIDUAL 0x10 // FFT flag: FFT for each channel, else all combined
+#define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window
+#define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias
+#define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data
+
+// BASS_ChannelGetTags types : what's returned
+#define BASS_TAG_ID3 0 // ID3v1 tags : TAG_ID3 structure
+#define BASS_TAG_ID3V2 1 // ID3v2 tags : variable length block
+#define BASS_TAG_OGG 2 // OGG comments : series of null-terminated UTF-8 strings
+#define BASS_TAG_HTTP 3 // HTTP headers : series of null-terminated ANSI strings
+#define BASS_TAG_ICY 4 // ICY headers : series of null-terminated ANSI strings
+#define BASS_TAG_META 5 // ICY metadata : ANSI string
+#define BASS_TAG_APE 6 // APE tags : series of null-terminated UTF-8 strings
+#define BASS_TAG_MP4 7 // MP4/iTunes metadata : series of null-terminated UTF-8 strings
+#define BASS_TAG_VENDOR 9 // OGG encoder : UTF-8 string
+#define BASS_TAG_LYRICS3 10 // Lyric3v2 tag : ASCII string
+#define BASS_TAG_CA_CODEC 11 // CoreAudio codec info : TAG_CA_CODEC structure
+#define BASS_TAG_MF 13 // Media Foundation tags : series of null-terminated UTF-8 strings
+#define BASS_TAG_WAVEFORMAT 14 // WAVE format : WAVEFORMATEEX structure
+#define BASS_TAG_RIFF_INFO 0x100 // RIFF "INFO" tags : series of null-terminated ANSI strings
+#define BASS_TAG_RIFF_BEXT 0x101 // RIFF/BWF "bext" tags : TAG_BEXT structure
+#define BASS_TAG_RIFF_CART 0x102 // RIFF/BWF "cart" tags : TAG_CART structure
+#define BASS_TAG_RIFF_DISP 0x103 // RIFF "DISP" text tag : ANSI string
+#define BASS_TAG_APE_BINARY 0x1000 // + index #, binary APE tag : TAG_APE_BINARY structure
+#define BASS_TAG_MUSIC_NAME 0x10000 // MOD music name : ANSI string
+#define BASS_TAG_MUSIC_MESSAGE 0x10001 // MOD message : ANSI string
+#define BASS_TAG_MUSIC_ORDERS 0x10002 // MOD order list : BYTE array of pattern numbers
+#define BASS_TAG_MUSIC_INST 0x10100 // + instrument #, MOD instrument name : ANSI string
+#define BASS_TAG_MUSIC_SAMPLE 0x10300 // + sample #, MOD sample name : ANSI string
+
+// ID3v1 tag structure
+typedef struct {
+ char id[3];
+ char title[30];
+ char artist[30];
+ char album[30];
+ char year[4];
+ char comment[30];
+ BYTE genre;
+} TAG_ID3;
+
+// Binary APE tag structure
+typedef struct {
+ const char *key;
+ const void *data;
+ DWORD length;
+} TAG_APE_BINARY;
+
+// BWF "bext" tag structure
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4200)
+#endif
+#pragma pack(push,1)
+typedef struct {
+ char Description[256]; // description
+ char Originator[32]; // name of the originator
+ char OriginatorReference[32]; // reference of the originator
+ char OriginationDate[10]; // date of creation (yyyy-mm-dd)
+ char OriginationTime[8]; // time of creation (hh-mm-ss)
+ QWORD TimeReference; // first sample count since midnight (little-endian)
+ WORD Version; // BWF version (little-endian)
+ BYTE UMID[64]; // SMPTE UMID
+ BYTE Reserved[190];
+#if defined(__GNUC__) && __GNUC__<3
+ char CodingHistory[0]; // history
+#elif 1 // change to 0 if compiler fails the following line
+ char CodingHistory[]; // history
+#else
+ char CodingHistory[1]; // history
+#endif
+} TAG_BEXT;
+#pragma pack(pop)
+
+// BWF "cart" tag structures
+typedef struct
+{
+ DWORD dwUsage; // FOURCC timer usage ID
+ DWORD dwValue; // timer value in samples from head
+} TAG_CART_TIMER;
+
+typedef struct
+{
+ char Version[4]; // version of the data structure
+ char Title[64]; // title of cart audio sequence
+ char Artist[64]; // artist or creator name
+ char CutID[64]; // cut number identification
+ char ClientID[64]; // client identification
+ char Category[64]; // category ID, PSA, NEWS, etc
+ char Classification[64]; // classification or auxiliary key
+ char OutCue[64]; // out cue text
+ char StartDate[10]; // yyyy-mm-dd
+ char StartTime[8]; // hh:mm:ss
+ char EndDate[10]; // yyyy-mm-dd
+ char EndTime[8]; // hh:mm:ss
+ char ProducerAppID[64]; // name of vendor or application
+ char ProducerAppVersion[64]; // version of producer application
+ char UserDef[64]; // user defined text
+ DWORD dwLevelReference; // sample value for 0 dB reference
+ TAG_CART_TIMER PostTimer[8]; // 8 time markers after head
+ char Reserved[276];
+ char URL[1024]; // uniform resource locator
+#if defined(__GNUC__) && __GNUC__<3
+ char TagText[0]; // free form text for scripts or tags
+#elif 1 // change to 0 if compiler fails the following line
+ char TagText[]; // free form text for scripts or tags
+#else
+ char TagText[1]; // free form text for scripts or tags
+#endif
+} TAG_CART;
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// CoreAudio codec info structure
+typedef struct {
+ DWORD ftype; // file format
+ DWORD atype; // audio format
+ const char *name; // description
+} TAG_CA_CODEC;
+
+#ifndef _WAVEFORMATEX_
+#define _WAVEFORMATEX_
+#pragma pack(push,1)
+typedef struct tWAVEFORMATEX
+{
+ WORD wFormatTag;
+ WORD nChannels;
+ DWORD nSamplesPerSec;
+ DWORD nAvgBytesPerSec;
+ WORD nBlockAlign;
+ WORD wBitsPerSample;
+ WORD cbSize;
+} WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX;
+typedef const WAVEFORMATEX *LPCWAVEFORMATEX;
+#pragma pack(pop)
+#endif
+
+// BASS_ChannelGetLength/GetPosition/SetPosition modes
+#define BASS_POS_BYTE 0 // byte position
+#define BASS_POS_MUSIC_ORDER 1 // order.row position, MAKELONG(order,row)
+#define BASS_POS_OGG 3 // OGG bitstream number
+#define BASS_POS_DECODE 0x10000000 // flag: get the decoding (not playing) position
+#define BASS_POS_DECODETO 0x20000000 // flag: decode to the position instead of seeking
+
+// BASS_RecordSetInput flags
+#define BASS_INPUT_OFF 0x10000
+#define BASS_INPUT_ON 0x20000
+
+#define BASS_INPUT_TYPE_MASK 0xff000000
+#define BASS_INPUT_TYPE_UNDEF 0x00000000
+#define BASS_INPUT_TYPE_DIGITAL 0x01000000
+#define BASS_INPUT_TYPE_LINE 0x02000000
+#define BASS_INPUT_TYPE_MIC 0x03000000
+#define BASS_INPUT_TYPE_SYNTH 0x04000000
+#define BASS_INPUT_TYPE_CD 0x05000000
+#define BASS_INPUT_TYPE_PHONE 0x06000000
+#define BASS_INPUT_TYPE_SPEAKER 0x07000000
+#define BASS_INPUT_TYPE_WAVE 0x08000000
+#define BASS_INPUT_TYPE_AUX 0x09000000
+#define BASS_INPUT_TYPE_ANALOG 0x0a000000
+
+// DX8 effect types, use with BASS_ChannelSetFX
+enum
+{
+ BASS_FX_DX8_CHORUS,
+ BASS_FX_DX8_COMPRESSOR,
+ BASS_FX_DX8_DISTORTION,
+ BASS_FX_DX8_ECHO,
+ BASS_FX_DX8_FLANGER,
+ BASS_FX_DX8_GARGLE,
+ BASS_FX_DX8_I3DL2REVERB,
+ BASS_FX_DX8_PARAMEQ,
+ BASS_FX_DX8_REVERB
+};
+
+typedef struct {
+ float fWetDryMix;
+ float fDepth;
+ float fFeedback;
+ float fFrequency;
+ DWORD lWaveform; // 0=triangle, 1=sine
+ float fDelay;
+ DWORD lPhase; // BASS_DX8_PHASE_xxx
+} BASS_DX8_CHORUS;
+
+typedef struct {
+ float fGain;
+ float fAttack;
+ float fRelease;
+ float fThreshold;
+ float fRatio;
+ float fPredelay;
+} BASS_DX8_COMPRESSOR;
+
+typedef struct {
+ float fGain;
+ float fEdge;
+ float fPostEQCenterFrequency;
+ float fPostEQBandwidth;
+ float fPreLowpassCutoff;
+} BASS_DX8_DISTORTION;
+
+typedef struct {
+ float fWetDryMix;
+ float fFeedback;
+ float fLeftDelay;
+ float fRightDelay;
+ BOOL lPanDelay;
+} BASS_DX8_ECHO;
+
+typedef struct {
+ float fWetDryMix;
+ float fDepth;
+ float fFeedback;
+ float fFrequency;
+ DWORD lWaveform; // 0=triangle, 1=sine
+ float fDelay;
+ DWORD lPhase; // BASS_DX8_PHASE_xxx
+} BASS_DX8_FLANGER;
+
+typedef struct {
+ DWORD dwRateHz; // Rate of modulation in hz
+ DWORD dwWaveShape; // 0=triangle, 1=square
+} BASS_DX8_GARGLE;
+
+typedef struct {
+ int lRoom; // [-10000, 0] default: -1000 mB
+ int lRoomHF; // [-10000, 0] default: 0 mB
+ float flRoomRolloffFactor; // [0.0, 10.0] default: 0.0
+ float flDecayTime; // [0.1, 20.0] default: 1.49s
+ float flDecayHFRatio; // [0.1, 2.0] default: 0.83
+ int lReflections; // [-10000, 1000] default: -2602 mB
+ float flReflectionsDelay; // [0.0, 0.3] default: 0.007 s
+ int lReverb; // [-10000, 2000] default: 200 mB
+ float flReverbDelay; // [0.0, 0.1] default: 0.011 s
+ float flDiffusion; // [0.0, 100.0] default: 100.0 %
+ float flDensity; // [0.0, 100.0] default: 100.0 %
+ float flHFReference; // [20.0, 20000.0] default: 5000.0 Hz
+} BASS_DX8_I3DL2REVERB;
+
+typedef struct {
+ float fCenter;
+ float fBandwidth;
+ float fGain;
+} BASS_DX8_PARAMEQ;
+
+typedef struct {
+ float fInGain; // [-96.0,0.0] default: 0.0 dB
+ float fReverbMix; // [-96.0,0.0] default: 0.0 db
+ float fReverbTime; // [0.001,3000.0] default: 1000.0 ms
+ float fHighFreqRTRatio; // [0.001,0.999] default: 0.001
+} BASS_DX8_REVERB;
+
+#define BASS_DX8_PHASE_NEG_180 0
+#define BASS_DX8_PHASE_NEG_90 1
+#define BASS_DX8_PHASE_ZERO 2
+#define BASS_DX8_PHASE_90 3
+#define BASS_DX8_PHASE_180 4
+
+typedef void (CALLBACK IOSNOTIFYPROC)(DWORD status);
+/* iOS notification callback function.
+status : The notification (BASS_IOSNOTIFY_xxx) */
+
+#define BASS_IOSNOTIFY_INTERRUPT 1 // interruption started
+#define BASS_IOSNOTIFY_INTERRUPT_END 2 // interruption ended
+
+BOOL BASSDEF(BASS_SetConfig)(DWORD option, DWORD value);
+DWORD BASSDEF(BASS_GetConfig)(DWORD option);
+BOOL BASSDEF(BASS_SetConfigPtr)(DWORD option, const void *value);
+void *BASSDEF(BASS_GetConfigPtr)(DWORD option);
+DWORD BASSDEF(BASS_GetVersion)();
+int BASSDEF(BASS_ErrorGetCode)();
+BOOL BASSDEF(BASS_GetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info);
+#if defined(_WIN32) && !defined(_WIN32_WCE)
+BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, HWND win, const GUID *dsguid);
+#else
+BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, void *win, void *dsguid);
+#endif
+BOOL BASSDEF(BASS_SetDevice)(DWORD device);
+DWORD BASSDEF(BASS_GetDevice)();
+BOOL BASSDEF(BASS_Free)();
+#if defined(_WIN32) && !defined(_WIN32_WCE)
+void *BASSDEF(BASS_GetDSoundObject)(DWORD object);
+#endif
+BOOL BASSDEF(BASS_GetInfo)(BASS_INFO *info);
+BOOL BASSDEF(BASS_Update)(DWORD length);
+float BASSDEF(BASS_GetCPU)();
+BOOL BASSDEF(BASS_Start)();
+BOOL BASSDEF(BASS_Stop)();
+BOOL BASSDEF(BASS_Pause)();
+BOOL BASSDEF(BASS_SetVolume)(float volume);
+float BASSDEF(BASS_GetVolume)();
+
+HPLUGIN BASSDEF(BASS_PluginLoad)(const char *file, DWORD flags);
+BOOL BASSDEF(BASS_PluginFree)(HPLUGIN handle);
+const BASS_PLUGININFO *BASSDEF(BASS_PluginGetInfo)(HPLUGIN handle);
+
+BOOL BASSDEF(BASS_Set3DFactors)(float distf, float rollf, float doppf);
+BOOL BASSDEF(BASS_Get3DFactors)(float *distf, float *rollf, float *doppf);
+BOOL BASSDEF(BASS_Set3DPosition)(const BASS_3DVECTOR *pos, const BASS_3DVECTOR *vel, const BASS_3DVECTOR *front, const BASS_3DVECTOR *top);
+BOOL BASSDEF(BASS_Get3DPosition)(BASS_3DVECTOR *pos, BASS_3DVECTOR *vel, BASS_3DVECTOR *front, BASS_3DVECTOR *top);
+void BASSDEF(BASS_Apply3D)();
+#if defined(_WIN32) && !defined(_WIN32_WCE)
+BOOL BASSDEF(BASS_SetEAXParameters)(int env, float vol, float decay, float damp);
+BOOL BASSDEF(BASS_GetEAXParameters)(DWORD *env, float *vol, float *decay, float *damp);
+#endif
+
+HMUSIC BASSDEF(BASS_MusicLoad)(BOOL mem, const void *file, QWORD offset, DWORD length, DWORD flags, DWORD freq);
+BOOL BASSDEF(BASS_MusicFree)(HMUSIC handle);
+
+HSAMPLE BASSDEF(BASS_SampleLoad)(BOOL mem, const void *file, QWORD offset, DWORD length, DWORD max, DWORD flags);
+HSAMPLE BASSDEF(BASS_SampleCreate)(DWORD length, DWORD freq, DWORD chans, DWORD max, DWORD flags);
+BOOL BASSDEF(BASS_SampleFree)(HSAMPLE handle);
+BOOL BASSDEF(BASS_SampleSetData)(HSAMPLE handle, const void *buffer);
+BOOL BASSDEF(BASS_SampleGetData)(HSAMPLE handle, void *buffer);
+BOOL BASSDEF(BASS_SampleGetInfo)(HSAMPLE handle, BASS_SAMPLE *info);
+BOOL BASSDEF(BASS_SampleSetInfo)(HSAMPLE handle, const BASS_SAMPLE *info);
+HCHANNEL BASSDEF(BASS_SampleGetChannel)(HSAMPLE handle, BOOL onlynew);
+DWORD BASSDEF(BASS_SampleGetChannels)(HSAMPLE handle, HCHANNEL *channels);
+BOOL BASSDEF(BASS_SampleStop)(HSAMPLE handle);
+
+HSTREAM BASSDEF(BASS_StreamCreate)(DWORD freq, DWORD chans, DWORD flags, STREAMPROC *proc, void *user);
+HSTREAM BASSDEF(BASS_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags);
+HSTREAM BASSDEF(BASS_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user);
+HSTREAM BASSDEF(BASS_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *proc, void *user);
+BOOL BASSDEF(BASS_StreamFree)(HSTREAM handle);
+QWORD BASSDEF(BASS_StreamGetFilePosition)(HSTREAM handle, DWORD mode);
+DWORD BASSDEF(BASS_StreamPutData)(HSTREAM handle, const void *buffer, DWORD length);
+DWORD BASSDEF(BASS_StreamPutFileData)(HSTREAM handle, const void *buffer, DWORD length);
+
+BOOL BASSDEF(BASS_RecordGetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info);
+BOOL BASSDEF(BASS_RecordInit)(int device);
+BOOL BASSDEF(BASS_RecordSetDevice)(DWORD device);
+DWORD BASSDEF(BASS_RecordGetDevice)();
+BOOL BASSDEF(BASS_RecordFree)();
+BOOL BASSDEF(BASS_RecordGetInfo)(BASS_RECORDINFO *info);
+const char *BASSDEF(BASS_RecordGetInputName)(int input);
+BOOL BASSDEF(BASS_RecordSetInput)(int input, DWORD flags, float volume);
+DWORD BASSDEF(BASS_RecordGetInput)(int input, float *volume);
+HRECORD BASSDEF(BASS_RecordStart)(DWORD freq, DWORD chans, DWORD flags, RECORDPROC *proc, void *user);
+
+double BASSDEF(BASS_ChannelBytes2Seconds)(DWORD handle, QWORD pos);
+QWORD BASSDEF(BASS_ChannelSeconds2Bytes)(DWORD handle, double pos);
+DWORD BASSDEF(BASS_ChannelGetDevice)(DWORD handle);
+BOOL BASSDEF(BASS_ChannelSetDevice)(DWORD handle, DWORD device);
+DWORD BASSDEF(BASS_ChannelIsActive)(DWORD handle);
+BOOL BASSDEF(BASS_ChannelGetInfo)(DWORD handle, BASS_CHANNELINFO *info);
+const char *BASSDEF(BASS_ChannelGetTags)(DWORD handle, DWORD tags);
+DWORD BASSDEF(BASS_ChannelFlags)(DWORD handle, DWORD flags, DWORD mask);
+BOOL BASSDEF(BASS_ChannelUpdate)(DWORD handle, DWORD length);
+BOOL BASSDEF(BASS_ChannelLock)(DWORD handle, BOOL lock);
+BOOL BASSDEF(BASS_ChannelPlay)(DWORD handle, BOOL restart);
+BOOL BASSDEF(BASS_ChannelStop)(DWORD handle);
+BOOL BASSDEF(BASS_ChannelPause)(DWORD handle);
+BOOL BASSDEF(BASS_ChannelSetAttribute)(DWORD handle, DWORD attrib, float value);
+BOOL BASSDEF(BASS_ChannelGetAttribute)(DWORD handle, DWORD attrib, float *value);
+BOOL BASSDEF(BASS_ChannelSlideAttribute)(DWORD handle, DWORD attrib, float value, DWORD time);
+BOOL BASSDEF(BASS_ChannelIsSliding)(DWORD handle, DWORD attrib);
+BOOL BASSDEF(BASS_ChannelSet3DAttributes)(DWORD handle, int mode, float min, float max, int iangle, int oangle, float outvol);
+BOOL BASSDEF(BASS_ChannelGet3DAttributes)(DWORD handle, DWORD *mode, float *min, float *max, DWORD *iangle, DWORD *oangle, float *outvol);
+BOOL BASSDEF(BASS_ChannelSet3DPosition)(DWORD handle, const BASS_3DVECTOR *pos, const BASS_3DVECTOR *orient, const BASS_3DVECTOR *vel);
+BOOL BASSDEF(BASS_ChannelGet3DPosition)(DWORD handle, BASS_3DVECTOR *pos, BASS_3DVECTOR *orient, BASS_3DVECTOR *vel);
+QWORD BASSDEF(BASS_ChannelGetLength)(DWORD handle, DWORD mode);
+BOOL BASSDEF(BASS_ChannelSetPosition)(DWORD handle, QWORD pos, DWORD mode);
+QWORD BASSDEF(BASS_ChannelGetPosition)(DWORD handle, DWORD mode);
+DWORD BASSDEF(BASS_ChannelGetLevel)(DWORD handle);
+DWORD BASSDEF(BASS_ChannelGetData)(DWORD handle, void *buffer, DWORD length);
+HSYNC BASSDEF(BASS_ChannelSetSync)(DWORD handle, DWORD type, QWORD param, SYNCPROC *proc, void *user);
+BOOL BASSDEF(BASS_ChannelRemoveSync)(DWORD handle, HSYNC sync);
+HDSP BASSDEF(BASS_ChannelSetDSP)(DWORD handle, DSPPROC *proc, void *user, int priority);
+BOOL BASSDEF(BASS_ChannelRemoveDSP)(DWORD handle, HDSP dsp);
+BOOL BASSDEF(BASS_ChannelSetLink)(DWORD handle, DWORD chan);
+BOOL BASSDEF(BASS_ChannelRemoveLink)(DWORD handle, DWORD chan);
+HFX BASSDEF(BASS_ChannelSetFX)(DWORD handle, DWORD type, int priority);
+BOOL BASSDEF(BASS_ChannelRemoveFX)(DWORD handle, HFX fx);
+
+BOOL BASSDEF(BASS_FXSetParameters)(HFX handle, const void *params);
+BOOL BASSDEF(BASS_FXGetParameters)(HFX handle, void *params);
+BOOL BASSDEF(BASS_FXReset)(HFX handle);
+
+#ifdef __cplusplus
+}
+
+#ifdef _WIN32
+static inline HPLUGIN BASS_PluginLoad(const WCHAR *file, DWORD flags)
+{
+ return BASS_PluginLoad((const char*)file, flags|BASS_UNICODE);
+}
+
+static inline HMUSIC BASS_MusicLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD flags, DWORD freq)
+{
+ return BASS_MusicLoad(mem, (const void*)file, offset, length, flags|BASS_UNICODE, freq);
+}
+
+static inline HSAMPLE BASS_SampleLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD max, DWORD flags)
+{
+ return BASS_SampleLoad(mem, (const void*)file, offset, length, max, flags|BASS_UNICODE);
+}
+
+static inline HSTREAM BASS_StreamCreateFile(BOOL mem, const WCHAR *file, QWORD offset, QWORD length, DWORD flags)
+{
+ return BASS_StreamCreateFile(mem, (const void*)file, offset, length, flags|BASS_UNICODE);
+}
+
+static inline HSTREAM BASS_StreamCreateURL(const WCHAR *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user)
+{
+ return BASS_StreamCreateURL((const char*)url, offset, flags|BASS_UNICODE, proc, user);
+}
+#endif
+#endif
+
+#endif
diff --git a/tetris_ai/bass.lib b/tetris_ai/bass.lib
new file mode 100644
index 0000000..ac5ab1d
Binary files /dev/null and b/tetris_ai/bass.lib differ
diff --git a/tetris_ai/bin/bass.dll b/tetris_ai/bin/bass.dll
new file mode 100644
index 0000000..2dcea83
Binary files /dev/null and b/tetris_ai/bin/bass.dll differ
diff --git a/tetris_ai/bin/misamino.ini b/tetris_ai/bin/misamino.ini
new file mode 100644
index 0000000..60bb480
--- /dev/null
+++ b/tetris_ai/bin/misamino.ini
@@ -0,0 +1,38 @@
+[AI]
+delay=20
+move=5
+4w=0
+
+[AI_P1]
+style=0
+level=4
+PieceMul=1
+dllplugin=plugin/tojai/tojai.dll
+
+[AI_P2]
+style=2
+level=4
+PieceMul=1
+dllplugin=plugin/dllai.dll
+
+[Rule]
+turnbase=1
+KOS_turnbase=0
+spin180=0
+GarbageStyle=0
+GarbageCancel=1
+GarbageBuffer=1
+GarbageBlocking=1
+samesequence=1
+combo_table_style=1
+
+[Player]
+das=8
+softdropdas=3
+softdropdelay=10
+
+[Sound]
+p1sfx=1
+p2sfx=0
+bgm=1
+
diff --git a/tetris_ai/bin/plugin/tojai/lua5.1.dll b/tetris_ai/bin/plugin/tojai/lua5.1.dll
new file mode 100644
index 0000000..b87f3b6
Binary files /dev/null and b/tetris_ai/bin/plugin/tojai/lua5.1.dll differ
diff --git a/tetris_ai/bin/plugin/tojai/setting.txt b/tetris_ai/bin/plugin/tojai/setting.txt
new file mode 100644
index 0000000..c89af5c
--- /dev/null
+++ b/tetris_ai/bin/plugin/tojai/setting.txt
@@ -0,0 +1 @@
+toj_tetris
\ No newline at end of file
diff --git a/tetris_ai/bin/plugin/tojai/toj_aihelp.lua b/tetris_ai/bin/plugin/tojai/toj_aihelp.lua
new file mode 100644
index 0000000..2752caa
--- /dev/null
+++ b/tetris_ai/bin/plugin/tojai/toj_aihelp.lua
@@ -0,0 +1,193 @@
+function Start()
+ SetThinkDepth(0) ;
+-- SetHoldMinDiff(100) ;
+-- SetThinkDelayFrame(10) ;
+-- SetMoveDelayFrame(10) ;
+--
+ SetHoldMinDiff(0) ;
+ SetThinkDelayFrame(0) ;
+ SetMoveDelayFrame(3) ;
+end
+
+
+function End()
+end
+
+function PrepareThink()
+ local height = GetBlockHighest() - (GetHeight() - GetBlockLastHeight()) ;
+end
+
+function EvalField(depth)
+
+ --int x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ -- Intermediate Results
+ local HorizontalTransitions = 0;--°¡·Î·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local FilledLines = 0;
+ local HighestBlock = -1;
+ local VerticalTransitions = 0;--À§·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local BlockedCells = 0;--±¸¸ÛÀÇ À§¸¦ ¸·ÀºÁ¤µµ
+ local Wells = 0; --¾çÂÊ¿¡ ºí·°ÀÌ ÀÖÀ»¶§ ºí·°ÀÇ ±íÀÌ ÆÄÀÎÁ¤µµ
+ local TetrisShape = 0 ;
+ local StartScore = 0 ;
+ local BlockedWells = 0 ; --±¸¸ÛÀ» ¸·Àº ºí·°ÀÇ ³ôÀÌ
+
+ local efield = {} ;
+ local x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ local width, height, startHeight ;
+
+ width = GetWidth() ;
+ --height = GetHeight() ;
+ height = GetBlockLastHeight() ;
+ startHeight = GetHeight()-GetBlockHighest() ;
+
+ HighestBlock = height ;
+
+ --Debug(string.format('HighestBlock(%d)',HighestBlock)) ;
+
+ -- Copy to eField, Calculate HorizontalTransitions, FilledLines and HighestBlock
+ y=height-1 ;
+ i=y ;
+ while(y>=0) do
+ btype=1; full=1; empty=1;
+ x=width-1 ;
+ while (x>=0) do
+ if(0 == GetField(x, y)) then
+ efield[x+i*width]=0;
+ else
+ efield[x+i*width]=1 ;
+ empty = 0 ;
+ end
+
+ if(btype ~= efield[x+i*width]) then
+ btype = efield[x+i*width];
+ full=0;
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+ x = x-1 ;
+ end
+
+ if(0 == full) then
+ i = i-1;
+ else
+ FilledLines = FilledLines + 1 ;
+ end
+
+ if(0 == btype) then
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+
+ if(i < startHeight and empty == 1) then
+ HighestBlock = height-(i+2);
+ break ;
+ end
+
+ y = y-1 ;
+ end
+
+
+ x=0 ;
+ while(x=0) do
+ btype=1; full=1; empty=1;
+ x=width-1 ;
+ while (x>=0) do
+ if(0 == GetField(x, y)) then
+ efield[x+i*width]=0;
+ else
+ efield[x+i*width]=1 ;
+ empty = 0 ;
+ end
+
+ if(btype ~= efield[x+i*width]) then
+ btype = efield[x+i*width];
+ full=0;
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+ x = x-1 ;
+ end
+
+ if(0 == full) then
+ i = i-1;
+ else
+ FilledLines = FilledLines + 1 ;
+ end
+
+ if(0 == btype) then
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+
+ if(i < startHeight and empty == 1) then
+ HighestBlock = height-(i+2);
+ break ;
+ end
+
+ y = y-1 ;
+ end
+
+
+ x=0 ;
+ while(x 0 and FilledLines < 3) then
+ --Debug(string.format('Score : %d, FillLine : %d, height : %d, blockCells : %d', FinalScore, FilledLines, HighestBlock, BlockedCells)) ;
+ -- end
+ --end
+
+-- Debug(string.format('Score(%d), StartScore(%d), HighestBlock(%d), HorizontalTransitions(%d), VerticalTransitions(%d), BlockedCells(%d), Wells(%d), FilledLine(%d), BlockedWells(%d)',
+-- FinalScore,
+-- StartScore,
+-- HighestBlock,
+-- HorizontalTransitions,
+-- VerticalTransitions,
+-- BlockedCells,
+-- Wells,
+-- FilledLines,
+-- BlockedWells
+-- )) ;
+
+
+ return FinalScore;
+
+end
diff --git a/tetris_ai/bin/plugin/tojai/toj_combo.lua b/tetris_ai/bin/plugin/tojai/toj_combo.lua
new file mode 100644
index 0000000..9fa4420
--- /dev/null
+++ b/tetris_ai/bin/plugin/tojai/toj_combo.lua
@@ -0,0 +1,299 @@
+local THINK_STATE_COMBO_BUILD = 0 ;
+local THINK_STATE_BUSY = 1 ;
+local curThinkState_ = THINK_STATE_COMBO_BUILD ;
+local COMBO_BUILD_MAX_HEIGHT = 12 ;
+local WANT_EMPTY = 3 ;
+local COMBO_BUILD_MIN_EVAL = -5000 ;
+
+function Start()
+ SetThinkDepth(0) ;
+-- SetHoldMinDiff(100) ;
+-- SetThinkDelayFrame(10) ;
+-- SetMoveDelayFrame(10) ;
+--
+ SetHoldMinDiff(0) ;
+ SetThinkDelayFrame(0) ;
+ SetMoveDelayFrame(0) ;
+end
+
+function End()
+end
+
+function PrepareThink()
+ local height = GetBlockHighest() - (GetHeight() - GetBlockLastHeight()) ;
+
+ curThinkState_ = THINK_STATE_COMBO_BUILD ;
+
+ local curEval = EvalField() ;
+
+ if(height >= COMBO_BUILD_MAX_HEIGHT or curEval < COMBO_BUILD_MIN_EVAL) then --Æò°¡ Á¡¼ö°¡ 5000ÀÌÇÏ¸é ¾ø¿¡°Ô ¼³Á¤
+ curThinkState_ = THINK_STATE_BUSY ;
+ end
+
+
+ --Debug(string.format('PrepareThink : state(%d), height(%d), curEval(%d)', curThinkState_, height, curEval)) ;
+ --curThinkState_ = THINK_STATE_BUSY ;
+end
+
+function EvalField(depth)
+
+ --int x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ -- Intermediate Results
+ local HorizontalTransitions = 0;--°¡·Î·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local FilledLines = 0;
+ local HighestBlock = -1;
+ local VerticalTransitions = 0;--À§·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local BlockedCells = 0;--±¸¸ÛÀÇ À§¸¦ ¸·ÀºÁ¤µµ
+ local Wells = 0; --¾çÂÊ¿¡ ºí·°ÀÌ ÀÖÀ»¶§ ºí·°ÀÇ ±íÀÌ ÆÄÀÎÁ¤µµ
+ local TetrisShape = 0 ;
+ local StartScore = 0 ;
+ local BlockedWells = 0 ; --±¸¸ÛÀ» ¸·Àº ºí·°ÀÇ ³ôÀÌ
+
+ local efield = {} ;
+ local x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ local width, height, startHeight ;
+
+ width = GetWidth() ;
+ --height = GetHeight() ;
+ height = GetBlockLastHeight() ;
+ startHeight = GetHeight()-GetBlockHighest() ;
+
+ HighestBlock = height ;
+
+ -- Copy to eField, Calculate HorizontalTransitions, FilledLines and HighestBlock
+ y=height-1 ;
+ i=y ;
+ while(y>=0) do
+ btype=1; full=1; empty=1;
+ x=width-1 ;
+ while (x>=0) do
+ if(0 == GetField(x, y)) then
+ efield[x+i*width]=0;
+ else
+ efield[x+i*width]=1 ;
+ empty = 0 ;
+ end
+
+ if(btype ~= efield[x+i*width]) then
+ btype = efield[x+i*width];
+ full=0;
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+ x = x-1 ;
+ end
+
+ if(0 == full) then
+ i = i-1;
+ else
+ FilledLines = FilledLines + 1 ;
+ end
+
+ if(0 == btype) then
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+
+ if(i < startHeight and empty == 1) then
+ HighestBlock = height-(i+2);
+ break ;
+ end
+
+ y = y-1 ;
+ end
+
+
+ x=0 ;
+ while(x= 0 and rpos >= width) then --ºí·°ÀÌ ¾ø´Ù°¡ ´Ù½Ã »ý°Ü³ ÁöÁ¡
+ rpos = j ;
+ end
+ end
+ j = j+1 ;
+ end
+
+-- Debug(string.format('shape : %d(empty:%d, lpos(%d), rpos(%d), x(%d))(%d%d%d%d%d%d%d%d%d%d)',
+-- i,
+-- emptyCnt,
+-- lpos,
+-- rpos,
+-- x,
+-- efield[0+i*width],
+-- efield[1+i*width],
+-- efield[2+i*width],
+-- efield[3+i*width],
+-- efield[4+i*width],
+-- efield[5+i*width],
+-- efield[6+i*width],
+-- efield[7+i*width],
+-- efield[8+i*width],
+-- efield[9+i*width]
+-- )) ;
+
+ if(emptyCnt == WANT_EMPTY and rpos - lpos == WANT_EMPTY and lpos == x) then
+ TetrisShape = TetrisShape + 1 ;
+-- Debug(string.format('tetris shape : %d(empty:%d, lpos(%d), rpos(%d))(%d%d%d%d%d%d%d%d%d%d)',
+-- i,
+-- emptyCnt,
+-- lpos,
+-- rpos,
+-- efield[0+i*width],
+-- efield[1+i*width],
+-- efield[2+i*width],
+-- efield[3+i*width],
+-- efield[4+i*width],
+-- efield[5+i*width],
+-- efield[6+i*width],
+-- efield[7+i*width],
+-- efield[8+i*width],
+-- efield[9+i*width]
+-- )) ;
+ else
+ break ;--¼¼´Â °úÁ¤À» ÁßÁö
+ end
+ i = i + 1 ;
+ end
+ end
+
+
+
+ if(lblock == 1 and rblock == 1) then --Á¿쿡 ºí·°ÀÌ ÀÖÀ»¶§
+ i=y ;
+ while(i 0) then
+ if(comboCnt >= 5) then --5ÄÞº¸ ÀÌ»óÀÌ¸é ´õ °¡ÁßÄ¡¸¦ ÁØ´Ù.
+ StartScore = StartScore + 5000 ;
+ elseif(comboCnt >= 1) then --1ÄÞº¸ ÀÌ»óÀÌ¸é °¡ÁßÄ¡
+ StartScore = StartScore + 2000 ;
+ else --ÄÞº¸°¡ ¾Æ´Ï¸é ÀÚÁ¦ÇÏ°Ô..
+ StartScore = StartScore - 1000 ;
+ end
+ end
+
+
+ FinalScore =
+ StartScore +
+ (-10 * HighestBlock)+
+ (-10 * HorizontalTransitions)+
+ (-10 * VerticalTransitions)+
+ (-1000 * BlockedCells)+
+ (-9 * Wells)+
+ --( 1 * FilledLines)+
+ (100 * TetrisShape)+
+ (-10 * BlockedWells) ;
+ elseif(curThinkState_ == THINK_STATE_BUSY) then
+
+ if(FilledLines > 0) then
+ if(comboCnt >= 5) then --5ÄÞº¸ ÀÌ»óÀÌ¸é ´õ °¡ÁßÄ¡¸¦ ÁØ´Ù.
+ StartScore = StartScore + 5000 ;
+ elseif(comboCnt >= 1) then --1ÄÞº¸ ÀÌ»óÀÌ¸é °¡ÁßÄ¡
+ StartScore = StartScore + 2000 ;
+ end
+ end
+
+ FinalScore =
+ StartScore +
+ (-100 * HighestBlock)
+ +(-100 * HorizontalTransitions)
+ +(-100 * VerticalTransitions)
+ +(-10 * BlockedCells)
+ +(-9 * Wells)
+ +(100 * FilledLines)
+ +(0 * TetrisShape)
+ +(-10 * BlockedWells)
+ ;
+
+ end
+
+
+
+ --if(curThinkState_ == THINK_STATE_COMBO_BUILD) then
+ -- if(FilledLines > 0 and FilledLines < 3) then
+ --Debug(string.format('Score : %d, FillLine : %d, height : %d, blockCells : %d', FinalScore, FilledLines, HighestBlock, BlockedCells)) ;
+ -- end
+ --end
+
+-- Debug(string.format('Score(%d), StartScore(%d), HighestBlock(%d), HorizontalTransitions(%d), VerticalTransitions(%d), BlockedCells(%d), Wells(%d), FilledLine(%d), TetrisShape(%d), BlockedWells(%d)',
+-- FinalScore,
+-- StartScore,
+-- HighestBlock,
+-- HorizontalTransitions,
+-- VerticalTransitions,
+-- BlockedCells,
+-- Wells,
+-- FilledLines,
+-- TetrisShape,
+-- BlockedWells
+-- )) ;
+
+
+ return FinalScore;
+
+end
diff --git a/tetris_ai/bin/plugin/tojai/toj_right.lua b/tetris_ai/bin/plugin/tojai/toj_right.lua
new file mode 100644
index 0000000..9c55d30
--- /dev/null
+++ b/tetris_ai/bin/plugin/tojai/toj_right.lua
@@ -0,0 +1,234 @@
+local THINK_STATE_TETRIS_BUILD = 0 ;
+local THINK_STATE_BUSY = 1 ;
+local TETRIS_BUILD_HEIGHT = 15 ;
+
+curThinkState_ = THINK_STATE_TETRIS_BUILD ;
+
+function Start()
+ SetThinkDepth(0) ;
+-- SetHoldMinDiff(100) ;
+-- SetThinkDelayFrame(10) ;
+-- SetMoveDelayFrame(10) ;
+--
+ SetHoldMinDiff(0) ;
+ SetThinkDelayFrame(0) ;
+ SetMoveDelayFrame(0) ;
+end
+
+function End()
+end
+
+function PrepareThink()
+ local height = GetBlockHighest() - (GetHeight() - GetBlockLastHeight()) ;
+
+ curThinkState_ = THINK_STATE_TETRIS_BUILD ;
+
+ if(height >= TETRIS_BUILD_HEIGHT) then
+ curThinkState_ = THINK_STATE_BUSY ;
+ end
+-- Debug(string.format('PrepareThink : state(%d), height(%d)', curThinkState_, height)) ;
+ --curThinkState_ = THINK_STATE_BUSY ;
+end
+
+function EvalField(depth)
+
+ --int x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ -- Intermediate Results
+ local HorizontalTransitions = 0;--°¡·Î·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local FilledLines = 0;
+ local HighestBlock = -1;
+ local VerticalTransitions = 0;--À§·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local BlockedCells = 0;--±¸¸ÛÀÇ À§¸¦ ¸·ÀºÁ¤µµ
+ local Wells = 0; --¾çÂÊ¿¡ ºí·°ÀÌ ÀÖÀ»¶§ ºí·°ÀÇ ±íÀÌ ÆÄÀÎÁ¤µµ
+ local TetrisShape = 0 ;
+ local StartScore = 0 ;
+ local BlockedWells = 0 ; --±¸¸ÛÀ» ¸·Àº ºí·°ÀÇ ³ôÀÌ
+
+ local efield = {} ;
+ local x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ local width, height, startHeight ;
+
+ width = GetWidth() ;
+ --height = GetHeight() ;
+ height = GetBlockLastHeight() ;
+ startHeight = GetHeight()-GetBlockHighest() ;
+
+ HighestBlock = height ;
+
+ -- Copy to eField, Calculate HorizontalTransitions, FilledLines and HighestBlock
+ y=height-1 ;
+ i=y ;
+ while(y>=0) do
+ btype=1; full=1; empty=1;
+ x=width-1 ;
+ while (x>=0) do
+ if(0 == GetField(x, y)) then
+ efield[x+i*width]=0;
+ else
+ efield[x+i*width]=1 ;
+ empty = 0 ;
+ end
+
+ if(btype ~= efield[x+i*width]) then
+ btype = efield[x+i*width];
+ full=0;
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+ x = x-1 ;
+ end
+
+ if(0 == full) then
+ i = i-1;
+ else
+ FilledLines = FilledLines + 1 ;
+ end
+
+ if(0 == btype) then
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+
+ if(i < startHeight and empty == 1) then
+ HighestBlock = height-(i+2);
+ break ;
+ end
+
+ y = y-1 ;
+ end
+
+
+ x=0 ;
+ while(x 0 and FilledLines < 3) then
+ StartScore = StartScore - 1000 ;
+ elseif(FilledLines == 4) then
+ StartScore = StartScore + 1000 ;
+ elseif(FilledLines == 3) then
+ StartScore = StartScore + 1000 ;
+ end
+ FinalScore =
+ StartScore +
+ (-10 * HighestBlock)+
+ (-10 * HorizontalTransitions)+
+ (-10 * VerticalTransitions)+
+ (-1000 * BlockedCells)+
+ (-9 * Wells)+
+ ( 1 * FilledLines)+
+ (10 * TetrisShape)+
+ (-10 * BlockedWells) ;
+ elseif(curThinkState_ == THINK_STATE_BUSY) then
+ FinalScore =
+ StartScore +
+ (-100 * HighestBlock)
+ +(-100 * HorizontalTransitions)
+ +(-100 * VerticalTransitions)
+ +(-10 * BlockedCells)
+ +(-9 * Wells)
+ +(100 * FilledLines)
+ +(0 * TetrisShape)
+ +(-10 * BlockedWells)
+ ;
+
+ end
+
+
+
+ --if(curThinkState_ == THINK_STATE_TETRIS_BUILD) then
+ -- if(FilledLines > 0 and FilledLines < 3) then
+ --Debug(string.format('Score : %d, FillLine : %d, height : %d, blockCells : %d', FinalScore, FilledLines, HighestBlock, BlockedCells)) ;
+ -- end
+ --end
+
+-- Debug(string.format('Score(%d), StartScore(%d), HighestBlock(%d), HorizontalTransitions(%d), VerticalTransitions(%d), BlockedCells(%d), Wells(%d), FilledLine(%d), TetrisShape(%d), BlockedWells(%d)',
+-- FinalScore,
+-- StartScore,
+-- HighestBlock,
+-- HorizontalTransitions,
+-- VerticalTransitions,
+-- BlockedCells,
+-- Wells,
+-- FilledLines,
+-- TetrisShape,
+-- BlockedWells
+-- )) ;
+
+
+ return FinalScore;
+
+end
diff --git a/tetris_ai/bin/plugin/tojai/toj_tetris.lua b/tetris_ai/bin/plugin/tojai/toj_tetris.lua
new file mode 100644
index 0000000..042f72a
--- /dev/null
+++ b/tetris_ai/bin/plugin/tojai/toj_tetris.lua
@@ -0,0 +1,239 @@
+local THINK_STATE_TETRIS_BUILD = 0 ;
+local THINK_STATE_BUSY = 1 ;
+
+curThinkState_ = THINK_STATE_TETRIS_BUILD ;
+
+function Start()
+ SetThinkDepth(0) ;
+-- SetHoldMinDiff(100) ;
+-- SetThinkDelayFrame(10) ;
+-- SetMoveDelayFrame(10) ;
+--
+ SetHoldMinDiff(0) ;
+ SetThinkDelayFrame(0) ;
+ SetMoveDelayFrame(0) ;
+end
+
+
+function End()
+end
+
+function PrepareThink()
+ local height = GetBlockHighest() - (GetHeight() - GetBlockLastHeight()) ;
+
+ curThinkState_ = THINK_STATE_TETRIS_BUILD ;
+
+ if(height >= 8) then
+ curThinkState_ = THINK_STATE_BUSY ;
+ end
+-- Debug(string.format('PrepareThink : state(%d), height(%d)', curThinkState_, height)) ;
+ --curThinkState_ = THINK_STATE_BUSY ;
+end
+
+function EvalField(depth)
+
+ --int x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ -- Intermediate Results
+ local HorizontalTransitions = 0;--°¡·Î·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local FilledLines = 0;
+ local HighestBlock = -1;
+ local VerticalTransitions = 0;--À§·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local BlockedCells = 0;--±¸¸ÛÀÇ À§¸¦ ¸·ÀºÁ¤µµ
+ local Wells = 0; --¾çÂÊ¿¡ ºí·°ÀÌ ÀÖÀ»¶§ ºí·°ÀÇ ±íÀÌ ÆÄÀÎÁ¤µµ
+ local TetrisShape = 0 ;
+ local StartScore = 0 ;
+ local BlockedWells = 0 ; --±¸¸ÛÀ» ¸·Àº ºí·°ÀÇ ³ôÀÌ
+
+ local efield = {} ;
+ local x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ local width, height, startHeight ;
+
+ width = GetWidth() ;
+ --height = GetHeight() ;
+ height = GetBlockLastHeight() ;
+ startHeight = GetHeight()-GetBlockHighest() ;
+
+ HighestBlock = height ;
+
+ --Debug(string.format('HighestBlock(%d)',HighestBlock)) ;
+
+ -- Copy to eField, Calculate HorizontalTransitions, FilledLines and HighestBlock
+ y=height-1 ;
+ i=y ;
+ while(y>=0) do
+ btype=1; full=1; empty=1;
+ x=width-1 ;
+ while (x>=0) do
+ if(0 == GetField(x, y)) then
+ efield[x+i*width]=0;
+ else
+ efield[x+i*width]=1 ;
+ empty = 0 ;
+ end
+
+ if(btype ~= efield[x+i*width]) then
+ btype = efield[x+i*width];
+ full=0;
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+ x = x-1 ;
+ end
+
+ if(0 == full) then
+ i = i-1;
+ else
+ FilledLines = FilledLines + 1 ;
+ end
+
+ if(0 == btype) then
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+
+ if(i < startHeight and empty == 1) then
+ HighestBlock = height-(i+2);
+ --Debug(string.format('HighestBlock2(%d %d %d)',i, startHeight, HighestBlock)) ;
+ break ;
+ end
+
+ y = y-1 ;
+ end
+
+
+ x=0 ;
+ while(x 0 and FilledLines < 3) then
+ StartScore = StartScore - 1000 ;
+ elseif(FilledLines == 4) then
+ StartScore = StartScore + 1000 ;
+ elseif(FilledLines == 3) then
+ StartScore = StartScore + 1000 ;
+ end
+ FinalScore =
+ StartScore +
+ (-10 * HighestBlock)+
+ (-10 * HorizontalTransitions)+
+ (-10 * VerticalTransitions)+
+ (-1000 * BlockedCells)+
+ (-9 * Wells)+
+ ( 1 * FilledLines)+
+ (10 * TetrisShape)+
+ (-10 * BlockedWells) ;
+ elseif(curThinkState_ == THINK_STATE_BUSY) then
+ FinalScore =
+ StartScore +
+ (-100 * HighestBlock)
+ +(-100 * HorizontalTransitions)
+ +(-100 * VerticalTransitions)
+ +(-10 * BlockedCells)
+ +(-9 * Wells)
+ +(100 * FilledLines)
+ +(0 * TetrisShape)
+ +(-10 * BlockedWells)
+ ;
+
+ end
+
+
+
+ --if(curThinkState_ == THINK_STATE_TETRIS_BUILD) then
+ -- if(FilledLines > 0 and FilledLines < 3) then
+ --Debug(string.format('Score : %d, FillLine : %d, height : %d, blockCells : %d', FinalScore, FilledLines, HighestBlock, BlockedCells)) ;
+ -- end
+ --end
+
+--[[
+ Debug(string.format('Score(%d), StartScore(%d), HighestBlock(%d), HorizontalTransitions(%d), VerticalTransitions(%d), BlockedCells(%d), Wells(%d), FilledLine(%d), TetrisShape(%d), BlockedWells(%d)',
+ FinalScore,
+ StartScore,
+ HighestBlock,
+ HorizontalTransitions,
+ VerticalTransitions,
+ BlockedCells,
+ Wells,
+ FilledLines,
+ TetrisShape,
+ BlockedWells
+ )) ;
+]]--
+
+
+ return FinalScore;
+
+end
diff --git a/tetris_ai/bin/plugin/tojai/toj_tetris_beginner.lua b/tetris_ai/bin/plugin/tojai/toj_tetris_beginner.lua
new file mode 100644
index 0000000..adf56cb
--- /dev/null
+++ b/tetris_ai/bin/plugin/tojai/toj_tetris_beginner.lua
@@ -0,0 +1,236 @@
+local THINK_STATE_TETRIS_BUILD = 0 ;
+local THINK_STATE_BUSY = 1 ;
+
+curThinkState_ = THINK_STATE_TETRIS_BUILD ;
+
+function Start()
+ SetThinkDepth(0) ;
+-- SetHoldMinDiff(100) ;
+-- SetThinkDelayFrame(10) ;
+-- SetMoveDelayFrame(10) ;
+--
+ SetHoldMinDiff(10000) ;
+ SetThinkDelayFrame(0) ;
+ SetMoveDelayFrame(0) ;
+end
+
+
+function End()
+end
+
+function PrepareThink()
+ local height = GetBlockHighest() - (GetHeight() - GetBlockLastHeight()) ;
+
+ curThinkState_ = THINK_STATE_TETRIS_BUILD ;
+
+ if(height >= 8) then
+ curThinkState_ = THINK_STATE_BUSY ;
+ end
+-- Debug(string.format('PrepareThink : state(%d), height(%d)', curThinkState_, height)) ;
+ --curThinkState_ = THINK_STATE_BUSY ;
+end
+
+function EvalField(depth)
+
+ --int x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ -- Intermediate Results
+ local HorizontalTransitions = 0;--°¡·Î·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local FilledLines = 0;
+ local HighestBlock = -1;
+ local VerticalTransitions = 0;--À§·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local BlockedCells = 0;--±¸¸ÛÀÇ À§¸¦ ¸·ÀºÁ¤µµ
+ local Wells = 0; --¾çÂÊ¿¡ ºí·°ÀÌ ÀÖÀ»¶§ ºí·°ÀÇ ±íÀÌ ÆÄÀÎÁ¤µµ
+ local TetrisShape = 0 ;
+ local StartScore = 0 ;
+ local BlockedWells = 0 ; --±¸¸ÛÀ» ¸·Àº ºí·°ÀÇ ³ôÀÌ
+
+ local efield = {} ;
+ local x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ local width, height, startHeight ;
+
+ width = GetWidth() ;
+ --height = GetHeight() ;
+ height = GetBlockLastHeight() ;
+ startHeight = GetHeight()-GetBlockHighest() ;
+
+ HighestBlock = height ;
+
+ --Debug(string.format('HighestBlock(%d)',HighestBlock)) ;
+
+ -- Copy to eField, Calculate HorizontalTransitions, FilledLines and HighestBlock
+ y=height-1 ;
+ i=y ;
+ while(y>=0) do
+ btype=1; full=1; empty=1;
+ x=width-1 ;
+ while (x>=0) do
+ if(0 == GetField(x, y)) then
+ efield[x+i*width]=0;
+ else
+ efield[x+i*width]=1 ;
+ empty = 0 ;
+ end
+
+ if(btype ~= efield[x+i*width]) then
+ btype = efield[x+i*width];
+ full=0;
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+ x = x-1 ;
+ end
+
+ if(0 == full) then
+ i = i-1;
+ else
+ FilledLines = FilledLines + 1 ;
+ end
+
+ if(0 == btype) then
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+
+ if(i < startHeight and empty == 1) then
+ HighestBlock = height-(i+2);
+ break ;
+ end
+
+ y = y-1 ;
+ end
+
+
+ x=0 ;
+ while(x 0 and FilledLines < 3) then
+ StartScore = StartScore - 1000 ;
+ elseif(FilledLines == 4) then
+ StartScore = StartScore + 1000 ;
+ elseif(FilledLines == 3) then
+ StartScore = StartScore + 1000 ;
+ end
+ FinalScore =
+ StartScore +
+ (-10 * HighestBlock)+
+ (-10 * HorizontalTransitions)+
+ (-10 * VerticalTransitions)+
+ --(-1000 * BlockedCells)+
+ --(-9 * Wells)+
+ ( 1 * FilledLines)+
+ (10 * TetrisShape)
+ --+(-10 * BlockedWells) ;
+ elseif(curThinkState_ == THINK_STATE_BUSY) then
+ FinalScore =
+ StartScore +
+ (-10 * HighestBlock)+
+ (-10 * HorizontalTransitions)+
+ (-10 * VerticalTransitions)+
+ --(-1000 * BlockedCells)+
+ --(-9 * Wells)+
+ (1 * FilledLines)+
+ (0 * TetrisShape)
+ --+(-10 * BlockedWells)
+ ;
+
+ end
+
+
+
+ --if(curThinkState_ == THINK_STATE_TETRIS_BUILD) then
+ -- if(FilledLines > 0 and FilledLines < 3) then
+ --Debug(string.format('Score : %d, FillLine : %d, height : %d, blockCells : %d', FinalScore, FilledLines, HighestBlock, BlockedCells)) ;
+ -- end
+ --end
+
+-- Debug(string.format('Score(%d), StartScore(%d), HighestBlock(%d), HorizontalTransitions(%d), VerticalTransitions(%d), BlockedCells(%d), Wells(%d), FilledLine(%d), TetrisShape(%d), BlockedWells(%d)',
+-- FinalScore,
+-- StartScore,
+-- HighestBlock,
+-- HorizontalTransitions,
+-- VerticalTransitions,
+-- BlockedCells,
+-- Wells,
+-- FilledLines,
+-- TetrisShape,
+-- BlockedWells
+-- )) ;
+
+
+ return FinalScore;
+
+end
diff --git a/tetris_ai/bin/plugin/tojai/toj_tspin.lua b/tetris_ai/bin/plugin/tojai/toj_tspin.lua
new file mode 100644
index 0000000..1057f32
--- /dev/null
+++ b/tetris_ai/bin/plugin/tojai/toj_tspin.lua
@@ -0,0 +1,246 @@
+local THINK_STATE_TETRIS_BUILD = 0 ;
+local THINK_STATE_BUSY = 1 ;
+local TRUE = 1 ;
+local FALSE = 0 ;
+
+curThinkState_ = THINK_STATE_TETRIS_BUILD ;
+
+function Start()
+ SetThinkDepth(0) ;
+-- SetHoldMinDiff(100) ;
+-- SetThinkDelayFrame(10) ;
+-- SetMoveDelayFrame(10) ;
+--
+-- SetHoldMinDiff(0) ;
+-- ÀÛÀ¸¸é ÀÛÀ»¼ö·Ï Ȧµå¸¦ ³ë¸²
+ SetHoldMinDiff(500) ;
+ SetThinkDelayFrame(0) ;
+ SetMoveDelayFrame(0) ;
+-- Å©¸é Ŭ¼ö·Ï Ƽ½ºÇÉ À§ÁÖ·Î
+ SetTSpinMinDiff(1000) ;
+ SetEnableTSpin(1) ;
+end
+
+
+function End()
+end
+
+function PrepareThink()
+ local height = GetBlockHighest() - (GetHeight() - GetBlockLastHeight()) ;
+
+ curThinkState_ = THINK_STATE_TETRIS_BUILD ;
+
+ if(height >= 4) then
+ curThinkState_ = THINK_STATE_BUSY ;
+ end
+-- Debug(string.format('PrepareThink : state(%d), height(%d)', curThinkState_, height)) ;
+ --curThinkState_ = THINK_STATE_BUSY ;
+end
+
+function EvalField(depth)
+
+ --int x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ -- Intermediate Results
+ local HorizontalTransitions = 0;--°¡·Î·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local FilledLines = 0;
+ local HighestBlock = -1;
+ local VerticalTransitions = 0;--À§·Î 0 1 0 1 ¹Ýº¹Á¤µµ
+ local BlockedCells = 0;--±¸¸ÛÀÇ À§¸¦ ¸·ÀºÁ¤µµ
+ local Wells = 0; --¾çÂÊ¿¡ ºí·°ÀÌ ÀÖÀ»¶§ ºí·°ÀÇ ±íÀÌ ÆÄÀÎÁ¤µµ
+ local TetrisShape = 0 ;
+ local StartScore = 0 ;
+ local BlockedWells = 0 ; --±¸¸ÛÀ» ¸·Àº ºí·°ÀÇ ³ôÀÌ
+
+ local efield = {} ;
+ local x,y,i,full,empty,btype,well,blocked,lblock,rblock;
+ local width, height, startHeight ;
+
+ width = GetWidth() ;
+ --height = GetHeight() ;
+ height = GetBlockLastHeight() ;
+ startHeight = GetHeight()-GetBlockHighest() ;
+
+ HighestBlock = height ;
+
+ --Debug(string.format('HighestBlock(%d)',HighestBlock)) ;
+
+ -- Copy to eField, Calculate HorizontalTransitions, FilledLines and HighestBlock
+ y=height-1 ;
+ i=y ;
+ while(y>=0) do
+ btype=1; full=1; empty=1;
+ x=width-1 ;
+ while (x>=0) do
+ if(0 == GetField(x, y)) then
+ efield[x+i*width]=0;
+ else
+ efield[x+i*width]=1 ;
+ empty = 0 ;
+ end
+
+ if(btype ~= efield[x+i*width]) then
+ btype = efield[x+i*width];
+ full=0;
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+ x = x-1 ;
+ end
+
+ if(0 == full) then
+ i = i-1;
+ else
+ FilledLines = FilledLines + 1 ;
+ end
+
+ if(0 == btype) then
+ HorizontalTransitions = HorizontalTransitions + 1;
+ end
+
+ if(i < startHeight and empty == 1) then
+ HighestBlock = height-(i+2);
+ break ;
+ end
+
+ y = y-1 ;
+ end
+
+
+ x=0 ;
+ while(x 0 and FilledLines < 3) then
+ StartScore = StartScore - 1000 ;
+ elseif(FilledLines == 4) then
+ StartScore = StartScore + 1000 ;
+ elseif(FilledLines == 3) then
+ StartScore = StartScore + 1000 ;
+ end
+ FinalScore =
+ StartScore +
+ (-10 * HighestBlock)+
+ (-10 * HorizontalTransitions)+
+ (-10 * VerticalTransitions)+
+ (-1000 * BlockedCells)+
+ (-9 * Wells)+
+ ( 1 * FilledLines)+
+ (10 * TetrisShape)+
+ (-10 * BlockedWells) ;
+ elseif(curThinkState_ == THINK_STATE_BUSY) then
+ FinalScore =
+ StartScore +
+ (-100 * HighestBlock)
+ +(-100 * HorizontalTransitions)
+ +(-100 * VerticalTransitions)
+ +(-10 * BlockedCells)
+ +(-9 * Wells)
+ +(100 * FilledLines)
+ +(0 * TetrisShape)
+ +(-10 * BlockedWells)
+ ;
+
+ end
+
+
+
+ --if(curThinkState_ == THINK_STATE_TETRIS_BUILD) then
+ -- if(FilledLines > 0 and FilledLines < 3) then
+ --Debug(string.format('Score : %d, FillLine : %d, height : %d, blockCells : %d', FinalScore, FilledLines, HighestBlock, BlockedCells)) ;
+ -- end
+ --end
+
+-- Debug(string.format('Score(%d), StartScore(%d), HighestBlock(%d), HorizontalTransitions(%d), VerticalTransitions(%d), BlockedCells(%d), Wells(%d), FilledLine(%d), TetrisShape(%d), BlockedWells(%d)',
+-- FinalScore,
+-- StartScore,
+-- HighestBlock,
+-- HorizontalTransitions,
+-- VerticalTransitions,
+-- BlockedCells,
+-- Wells,
+-- FilledLines,
+-- TetrisShape,
+-- BlockedWells
+-- )) ;
+
+
+ return FinalScore;
+
+end
+
+
+
diff --git a/tetris_ai/bin/plugin/tojai/tojai.dll b/tetris_ai/bin/plugin/tojai/tojai.dll
new file mode 100644
index 0000000..86f5558
Binary files /dev/null and b/tetris_ai/bin/plugin/tojai/tojai.dll differ
diff --git a/tetris_ai/ege.h b/tetris_ai/ege.h
new file mode 100644
index 0000000..ae68756
--- /dev/null
+++ b/tetris_ai/ege.h
@@ -0,0 +1,1401 @@
+/*********************************************************
+* EGE (Easy Graphics Engine)
+* FileName ege.h
+* HomePage1 http://misakamm.github.com/xege
+* HomePage2 http://misakamm.bitbucket.org/index.htm
+* HomePage3 http://tcgraphics.sourceforge.net
+* teiba1 http://tieba.baidu.com/f?kw=ege
+* teiba2 http://tieba.baidu.com/f?kw=ege%C4%EF
+* Blog: http://misakamm.com
+* E-Mail: mailto:misakamm[at gmail com]
+*
+* FileName: ege.h
+* ÔÚ VC ÏÂÄ£Äâ Borland BGI »æͼ¿â£¬ÊµÏÖ¼òµ¥µÄ»æͼ֮Ó࣬À©Õ¹Á˽ϸ´ÔӵĻæͼÄÜÁ¦
+*
+* °üº¬²¢Ê¹Óñ¾¿âʱ£¬²»Òª°üº¬conio.hÍ·Îļþ
+* ÕâЩͷÎļþ²»Ó¦¹²´æ£¬·ñÔò¿ÉÄÜ»á±àÒë´íÎó£¬
+* »òÕßgetch±»conio.hÄڵĸ²¸Ç£¨ÓÉ°üº¬´ÎÐò¾ö¶¨£©£¬Çë×¢Òâ
+* ÈçÐè¹²´æ£¬ÇëʹÓöàÎļþ·Ö¿ª°üº¬µÄģʽʹÓã¬
+* ¼´²»ÄÜÒ»¸öcppͬʱ°üº¬£¬µ«¿ÉÒÔ·Ö¿ª°üº¬
+* ʹÓñ¾¿â£¬±ØÐëÓÃC++±àÒ룬¿ÉÖ§³ÖµÄ±àÒëÆ÷£º
+* VC6/VC2008/VC2010/MinGW3.4.5/MinGW4.4.1
+*********************************************************/
+
+/****************************************************************************
+** ×¢ÒâÊÂÏ
+* ¡ïÈç¹ûÐèÒªÏÔʾ¿ØÖÆ̨´°¿Ú£¬ÇëÔÚ°üº¬±¾ÎļþµÄÇ°Ãæ¼ÓÒ»ÐÐdefine SHOW_CONSOLE
+* ¡ïµ÷ÓÃSleepÕâ¸öAPIʱ£¬»òÕßµ÷ÓÃdelay£¬Êµ¼Ê¾ù»áת»¯Îªµ÷ÓÃdelay_ms£¬Èç±ØÐèµ÷ÓÃAPIÇëʹÓÃapi_sleep
+* ¡ïdelay_ms(0)ÄÜ×ÔÐÐÅжÏÓÐûÓиüеıØÒª£¬Á¬Ðø¶à´Îµ«²»´óÁ¿µÄµ÷Óò¢²»»á²úÉúÖ¡ÂʵÄÓ°Ïì
+* ¡ïµ÷ÓÃdelay_ms, delay_fps, getch, getkey, getmouse ʱ£¬´°¿ÚÄÚÈÝ¿ÉÄÜ»á¸üУ¬ÕâЩº¯ÊýÏ൱ÓÚÄÚÖÃÁËdelay_ms(0)£¬
+* Èç¹ûÄãÖ»ÐèÒª¸üд°¿Ú£¬¶ø²»ÏëµÈ´ý£¬¿ÉÒÔÓÃdelay_ms(0)¡£×¢ÒâdelayÖ»ÑÓʱ¶ø²»¸üд°¿Ú
+* ¡ïºÏÀíµØʹÓÃdelay_ms/delay_fpsº¯Êý£¬¿ÉÒÔ¼õÉÙÄãµÄ³ÌÐòÕ¼ÓõÄCPU£¬·ñÔòÒ»¸ö¶¼Ã»Óе÷ÓÃͬʱҲûÓÐgetch/getmouseµÄ»°£¬³ÌÐò½«Õ¼ÂúÒ»¸öCPUµÄʱ¼ä
+****************************************************************************/
+
+#ifndef _EGE_H_
+#define _EGE_H_
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+#pragma once
+#endif
+
+#ifdef _GRAPH_LIB_BUILD_
+#ifndef WINVER
+#define WINVER 0x0400 // Specifies that the minimum required platform is Windows 95/NT4.
+#endif
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0400 // Specifies that the minimum required platform is Windows 95/NT4.
+#endif
+
+#ifndef _WIN32_WINDOWS
+#define _WIN32_WINDOWS 0x0410 // Specifies that the minimum required platform is Windows 98.
+#endif
+#endif
+
+#ifndef __cplusplus
+#error You must use C++ compiler, or you need filename with '.cpp' suffix
+#endif
+
+#if defined(_INC_CONIO) || defined(_CONIO_H_)
+#error can not include "conio.h" before "graphics.h"
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4355)
+#ifndef _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH
+#define _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH
+#endif
+#ifndef _ALLOW_RUNTIME_LIBRARY_MISMATCH
+#define _ALLOW_RUNTIME_LIBRARY_MISMATCH
+#endif
+#endif
+
+#if !defined(_GRAPH_LIB_BUILD_) && !defined(_GRAPH_NO_LIB_)
+ #ifdef _MSC_VER
+ #ifdef _WIN64
+ #if (_MSC_VER >= 1700)
+ #if 0 && defined(_DLL)
+ #pragma comment(lib,"graphics1264d.lib")
+ #else
+ #pragma comment(lib,"graphics1264.lib")
+ #endif
+ #elif (_MSC_VER >= 1600)
+ #if 0 && defined(_DLL)
+ #pragma comment(lib,"graphics1064d.lib")
+ #else
+ #pragma comment(lib,"graphics1064.lib")
+ #endif
+ #elif (_MSC_VER >= 1500)
+ #if 0 && defined(_DLL)
+ #pragma comment(lib,"graphics0864d.lib")
+ #else
+ #pragma comment(lib,"graphics0864.lib")
+ #endif
+ #elif (_MSC_VER > 1200)
+ #pragma comment(lib,"graphics05.lib")
+ #else
+ #pragma comment(lib,"graphics.lib")
+ #endif
+ #else
+ #if (_MSC_VER >= 1700)
+ #if 0 && defined(_DLL)
+ #pragma comment(lib,"graphics12d.lib")
+ #else
+ #pragma comment(lib,"graphics12.lib")
+ #endif
+ #elif (_MSC_VER >= 1600)
+ #if 0 && defined(_DLL)
+ #pragma comment(lib,"graphics10d.lib")
+ #else
+ #pragma comment(lib,"graphics10.lib")
+ #endif
+ #elif (_MSC_VER >= 1500)
+ #if 0 && defined(_DLL)
+ #pragma comment(lib,"graphics08d.lib")
+ #else
+ #pragma comment(lib,"graphics08.lib")
+ #endif
+ #elif (_MSC_VER > 1200)
+ #pragma comment(lib,"graphics05.lib")
+ #else
+ #pragma comment(lib,"graphics.lib")
+ #endif
+ #endif
+ #if _MSC_VER >= 1700
+ #ifdef _DEBUG
+ #else
+ #endif
+ #elif _MSC_VER >= 1600
+ #ifdef _DEBUG
+ #else
+ #endif
+ #elif _MSC_VER > 1200
+ #ifdef _DEBUG
+ //#pragma comment(linker, "/NODEFAULTLIB:MSVCRTD.lib")
+ //#pragma comment(linker, "/NODEFAULTLIB:libcmtd.lib")
+ //#pragma comment(linker, "/NODEFAULTLIB:libcpmtd.lib")
+ #else
+ #endif
+ #else
+ #ifdef _DEBUG
+ //#pragma comment(linker, "/NODEFAULTLIB:MSVCRTD.lib")
+ //#pragma comment(linker, "/NODEFAULTLIB:libcd.lib")
+ //#pragma comment(linker, "/NODEFAULTLIB:libcmtd.lib")
+ //#pragma comment(linker, "/NODEFAULTLIB:libcpmtd.lib")
+ #else
+ //#pragma comment(linker, "/NODEFAULTLIB:MSVCRT.lib")
+ //#pragma comment(linker, "/NODEFAULTLIB:libcmt.lib")
+ //#pragma comment(linker, "/NODEFAULTLIB:libcp.lib")
+ #endif
+ #endif
+ #endif
+#endif
+
+#if !defined(_GRAPH_LIB_BUILD_) && !defined(_GRAPH_NO_LIB_)
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#ifndef _CRT_NON_CONFORMING_SWPRINTFS
+#define _CRT_NON_CONFORMING_SWPRINTFS
+#endif
+
+#ifndef _CRT_NON_CONFORMING_SWPRINTFS
+#define _CRT_NON_CONFORMING_SWPRINTFS
+#endif
+#endif
+
+#include "windows.h"
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(SetWindowLongPtr)
+ #define SetWindowLongPtrW SetWindowLongW
+ #define GetWindowLongPtrW GetWindowLongW
+ #define GWLP_USERDATA GWL_USERDATA
+ #define GWLP_WNDPROC GWL_WNDPROC
+#endif
+
+#if !defined(_GRAPH_LIB_BUILD_) && !defined(_GRAPH_NO_LIB_)
+#if defined(_MSC_VER) && _MSC_VER > 1200
+//#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' ""version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
+#endif
+#endif
+
+
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 0x020A
+#endif
+
+#ifdef _GRAPH_LIB_BUILD_
+#include
+#endif
+
+#ifndef _Cdecl
+#if __STDC__
+#define _Cdecl __cdecl
+#else
+#define _Cdecl __cdecl
+#endif
+#endif
+
+#ifdef _MSC_VER
+ #if defined(_WIN64)
+ #define EGEAPI
+ #else
+ #define EGEAPI _Cdecl
+ #endif
+#else
+ #if defined(__WORDSIZE)
+ #if __WORDSIZE > 32
+ #define EGEAPI
+ #else
+ #define EGEAPI _Cdecl
+ #endif
+ #else
+ #define EGEAPI
+ #endif
+#endif
+
+#ifdef _GRAPH_LIB_BUILD_
+ #define EGE_DEPRECATE(text)
+#else
+ #ifdef _MSC_VER
+ #ifdef _CRT_DEPRECATE_TEXT
+ #define EGE_DEPRECATE(text) _CRT_DEPRECATE_TEXT("This function is deprecated, more info visit http://tcgraphics.sourceforge.net/")
+ #else
+ #define EGE_DEPRECATE(text)
+ #endif
+ #else
+ #define EGE_DEPRECATE(text) __attribute__((deprecated))
+ #endif
+#endif
+
+#define SHOWCONSOLE 1 // ½øÈëͼÐÎģʽʱ£¬±£Áô¿ØÖÆ̨µÄÏÔʾ
+#define RGBTOBGR(color) ((((color) & 0xFF) << 16) | (((color) & 0xFF0000) >> 16) | ((color) & 0xFF00FF00))
+#define EGERGB(r, g, b) ( ((r)<<16) | ((g)<<8) | (b))
+#define EGERGBA(r, g, b, a) ( ((r)<<16) | ((g)<<8) | (b) | ((a)<<24) )
+#define EGEARGB(a, r, g, b) ( ((r)<<16) | ((g)<<8) | (b) | ((a)<<24) )
+#define EGEACOLOR(a, color) ( ((color) & 0xFFFFFF) | ((a)<<24) )
+#define EGECOLORA(color, a) ( ((color) & 0xFFFFFF) | ((a)<<24) )
+#define EGEGET_R(c) ( ((c)>>16) & 0xFF )
+#define EGEGET_G(c) ( ((c)>> 8) & 0xFF )
+#define EGEGET_B(c) ( ((c)) & 0xFF )
+#define EGEGET_A(c) ( ((c)>>24) & 0xFF )
+#define EGEGRAY(gray) ( ((gray)<<16) | ((gray)<<8) | (gray))
+#define EGEGRAYA(gray, a) ( ((gray)<<16) | ((gray)<<8) | (gray) | ((a)<<24) )
+#define EGEAGRAY(a, gray) ( ((gray)<<16) | ((gray)<<8) | (gray) | ((a)<<24) )
+
+namespace ege {
+
+const double PI = 3.1415926535897932384626;
+
+enum graphics_drivers { /* define graphics drivers */
+ DETECT, /* requests autodetection */
+ CGA, MCGA, EGA, EGA64, EGAMONO, IBM8514,/* 1 - 6 */
+ HERCMONO, ATT400, VGA, PC3270, /* 7 - 10 */
+ TRUECOLOR, TRUECOLORSIZE,
+ CURRENT_DRIVER = -1
+};
+
+enum graphics_modes { /* graphics modes for each driver */
+ CGAC0 = 0, /* 320x200 palette 0; 1 page */
+ CGAC1 = 1, /* 320x200 palette 1; 1 page */
+ CGAC2 = 2, /* 320x200 palette 2: 1 page */
+ CGAC3 = 3, /* 320x200 palette 3; 1 page */
+ CGAHI = 4, /* 640x200 1 page */
+ MCGAC0 = 0, /* 320x200 palette 0; 1 page */
+ MCGAC1 = 1, /* 320x200 palette 1; 1 page */
+ MCGAC2 = 2, /* 320x200 palette 2; 1 page */
+ MCGAC3 = 3, /* 320x200 palette 3; 1 page */
+ MCGAMED = 4, /* 640x200 1 page */
+ MCGAHI = 5, /* 640x480 1 page */
+ EGALO = 0, /* 640x200 16 color 4 pages */
+ EGAHI = 1, /* 640x350 16 color 2 pages */
+ EGA64LO = 0, /* 640x200 16 color 1 page */
+ EGA64HI = 1, /* 640x350 4 color 1 page */
+ EGAMONOHI = 0, /* 640x350 64K on card, 1 page - 256K on card, 4 pages */
+ HERCMONOHI = 0, /* 720x348 2 pages */
+ ATT400C0 = 0, /* 320x200 palette 0; 1 page */
+ ATT400C1 = 1, /* 320x200 palette 1; 1 page */
+ ATT400C2 = 2, /* 320x200 palette 2; 1 page */
+ ATT400C3 = 3, /* 320x200 palette 3; 1 page */
+ ATT400MED = 4, /* 640x200 1 page */
+ ATT400HI = 5, /* 640x400 1 page */
+ VGALO = 0, /* 640x200 16 color 4 pages */
+ VGAMED = 1, /* 640x350 16 color 2 pages */
+ VGAHI = 2, /* 640x480 16 color 1 page */
+ PC3270HI = 0, /* 720x350 1 page */
+ IBM8514LO = 0, /* 640x480 256 colors */
+ IBM8514HI = 1 /*1024x768 256 colors */
+};
+
+enum graphics_errors { /* graphresult error return codes */
+ grOk = 0,
+ grNoInitGraph = -1,
+ grNotDetected = -2,
+ grFileNotFound = -3,
+ grInvalidDriver = -4,
+ grNoLoadMem = -5,
+ grNoScanMem = -6,
+ grNoFloodMem = -7,
+ grFontNotFound = -8,
+ grNoFontMem = -9,
+ grInvalidMode = -10,
+ grError = -11, /* generic error */
+ grIOerror = -12,
+ grInvalidFont = -13,
+ grInvalidFontNum = -14,
+ grInvalidVersion = -18,
+ grException = 0x10, /* ege error */
+ grParamError = 0x11,
+ grInvalidRegion = 0x12,
+ grOutOfMemory = 0x13,
+ grNullPointer = 0x14,
+ grAllocError = 0x15,
+ grInvalidMemory = 0xCDCDCDCD,
+};
+
+enum message_event {
+ MSG_EVENT_UP = 0x00,
+ MSG_EVENT_DOWN = 0x01,
+ MSG_EVENT_CLICK = 0x01,
+ MSG_EVENT_DBCLICK = 0x02,
+ MSG_EVENT_MOVE = 0x04,
+ MSG_EVENT_WHEEL = 0x10,
+};
+
+enum message_mouse {
+ MSG_MOUSE_LEFT = 0x01,
+ MSG_MOUSE_RIGHT = 0x02,
+ MSG_MOUSE_MID = 0x04,
+};
+
+// ÑÕÉ«
+enum COLORS {
+ BLACK = 0,
+ BLUE = EGERGB(0, 0, 0xA8),
+ GREEN = EGERGB(0, 0xA8, 0),
+ CYAN = EGERGB(0, 0xA8, 0xA8),
+ RED = EGERGB(0xA8, 0, 0),
+ MAGENTA = EGERGB(0xA8, 0, 0xA8),
+ BROWN = EGERGB(0xA8, 0xA8, 0),
+ LIGHTGRAY = EGERGB(0xA8, 0xA8, 0xA8),
+ DARKGRAY = EGERGB(0x54, 0x54, 0x54),
+ LIGHTBLUE = EGERGB(0x54, 0x54, 0xFC),
+ LIGHTGREEN = EGERGB(0x54, 0xFC, 0x54),
+ LIGHTCYAN = EGERGB(0x54, 0xFC, 0xFC),
+ LIGHTRED = EGERGB(0xFC, 0x54, 0x54),
+ LIGHTMAGENTA = EGERGB(0xFC, 0x54, 0xFC),
+ YELLOW = EGERGB(0xFC, 0xFC, 0x54),
+ WHITE = EGERGB(0xFC, 0xFC, 0xFC),
+};
+
+// Ìî³äģʽ
+enum fill_patterns {/* Fill patterns for get/setfillstyle */
+ EMPTY_FILL, /* fills area in background color */
+ SOLID_FILL, /* fills area in solid fill color */
+ LINE_FILL, /* --- fill */
+ LTSLASH_FILL, /* /// fill */
+ SLASH_FILL, /* /// fill with thick lines */
+ BKSLASH_FILL, /* \\\ fill with thick lines */
+ LTBKSLASH_FILL, /* \\\ fill */
+ HATCH_FILL, /* light hatch fill */
+ XHATCH_FILL, /* heavy cross hatch fill */
+ INTERLEAVE_FILL,/* interleaving line fill */
+ WIDE_DOT_FILL, /* Widely spaced dot fill */
+ CLOSE_DOT_FILL, /* Closely spaced dot fill */
+ USER_FILL /* user defined fill */
+};
+
+enum text_just { /* Horizontal and vertical justification
+ for settextjustify */
+ LEFT_TEXT = 0,
+ CENTER_TEXT = 1,
+ RIGHT_TEXT = 2,
+
+ BOTTOM_TEXT = 0,
+ /* CENTER_TEXT = 1, already defined above */
+ TOP_TEXT = 2
+};
+
+enum line_styles { /* Line styles for get/setlinestyle */
+ SOLID_LINE = PS_SOLID,
+ CENTER_LINE = PS_DASH,
+ DOTTED_LINE = PS_DOT,
+ DASHED_LINE = PS_DASHDOT,
+ NULL_LINE = PS_NULL,
+ USERBIT_LINE = PS_USERSTYLE, /* User defined line style */
+};
+
+enum key_msg_flag {
+ KEYMSG_CHAR_FLAG = 2,
+ KEYMSG_DOWN_FLAG = 1,
+ KEYMSG_UP_FLAG = 1,
+
+ KEYMSG_CHAR = 0x40000,
+ KEYMSG_DOWN = 0x10000,
+ KEYMSG_UP = 0x20000,
+ KEYMSG_FIRSTDOWN = 0x80000,
+};
+
+enum music_state_flag {
+ MUSIC_MODE_NOT_OPEN = 0x0,
+ MUSIC_MODE_NOT_READY = 0x20C,
+ MUSIC_MODE_PAUSE = 0x211,
+ MUSIC_MODE_PLAY = 0x20E,
+ MUSIC_MODE_STOP = 0x20D,
+ MUSIC_MODE_OPEN = 0x212,
+ MUSIC_MODE_SEEK = 0x210,
+};
+
+enum initmode_flag {
+ INIT_NOBORDER = 0x1,
+ INIT_CHILD = 0x2,
+ INIT_TOPMOST = 0x4,
+ INIT_RENDERMANUAL = 0x8,
+ INIT_NOFORCEEXIT = 0x10,
+ INIT_WITHLOGO = 0x100,
+#if defined(_DEBUG) || defined(DEBUG)
+ INIT_DEFAULT = 0x0,
+#else
+ INIT_DEFAULT = INIT_WITHLOGO,
+#endif
+ INIT_ANIMATION = INIT_DEFAULT | INIT_RENDERMANUAL | INIT_NOFORCEEXIT,
+};
+
+enum rendermode_e {
+ RENDER_AUTO,
+ RENDER_MANUAL,
+};
+
+typedef enum key_code_e {
+ key_mouse_l = 0x01,
+ key_mouse_r = 0x02,
+ key_mouse_m = 0x04,
+ key_back = 0x08,
+ key_tab = 0x09,
+ key_enter = 0x0d,
+ key_shift = 0x10,
+ key_control = 0x11,
+ key_menu = 0x12,
+ key_pause = 0x13,
+ key_capslock = 0x14,
+ key_esc = 0x1b,
+ key_space = 0x20,
+
+ key_pageup = 0x21,
+ key_pagedown = 0x22,
+ key_home = 0x23,
+ key_end = 0x24,
+
+ key_left = 0x25,
+ key_up = 0x26,
+ key_right = 0x27,
+ key_down = 0x28,
+
+ key_print = 0x2a,
+ key_snapshot = 0x2c,
+ key_insert = 0x2d,
+ key_delete = 0x2e,
+
+ key_0 = 0x30,
+ key_1 = 0x31,
+ key_2 = 0x32,
+ key_3 = 0x33,
+ key_4 = 0x34,
+ key_5 = 0x35,
+ key_6 = 0x36,
+ key_7 = 0x37,
+ key_8 = 0x38,
+ key_9 = 0x39,
+
+ key_A = 0x41,
+ key_Z = 0x5a,
+ key_win_l = 0x5b,
+ key_win_r = 0x5c,
+
+ key_sleep = 0x5f,
+
+ key_num0 = 0x60,
+ key_num1 = 0x61,
+ key_num2 = 0x62,
+ key_num3 = 0x63,
+ key_num4 = 0x64,
+ key_num5 = 0x65,
+ key_num6 = 0x66,
+ key_num7 = 0x67,
+ key_num8 = 0x68,
+ key_num9 = 0x69,
+
+ key_f1 = 0x70,
+ key_f2 = 0x71,
+ key_f3 = 0x72,
+ key_f4 = 0x73,
+ key_f5 = 0x74,
+ key_f6 = 0x75,
+ key_f7 = 0x76,
+ key_f8 = 0x77,
+ key_f9 = 0x78,
+ key_f10 = 0x79,
+ key_f11 = 0x7a,
+ key_f12 = 0x7b,
+
+ key_numlock = 0x90,
+ key_scrolllock = 0x91,
+
+ key_shift_l = 0xa0,
+ key_shift_r = 0xa1,
+ key_control_l = 0xa2,
+ key_control_r = 0xa3,
+ key_menu_l = 0xa4,
+ key_menu_r = 0xa5,
+
+ key_semicolon = 0xba,
+ key_plus = 0xbb,
+ key_comma = 0xbc,
+ key_minus = 0xbd,
+ key_period = 0xbe,
+ key_slash = 0xbf,
+ key_tilde = 0xc0,
+ key_lbrace = 0xdb,
+ key_backslash = 0xdc,
+ key_rbrace = 0xdd,
+ key_quote = 0xde,
+
+ key_ime_process = 0xe5,
+}key_code_e;
+
+typedef enum key_msg_e {
+ key_msg_down = 1,
+ key_msg_up = 2,
+ key_msg_char = 4,
+}key_msg_e;
+typedef enum key_flag_e {
+ key_flag_shift = 0x100,
+ key_flag_ctrl = 0x200,
+}key_flag_e;
+
+typedef enum mouse_msg_e {
+ mouse_msg_down = 0x10,
+ mouse_msg_up = 0x20,
+ mouse_msg_move = 0x40,
+ mouse_msg_wheel = 0x80,
+}mouse_msg_e;
+typedef enum mouse_flag_e {
+ mouse_flag_left = 1,
+ mouse_flag_right = 2,
+ mouse_flag_mid = 4,
+ mouse_flag_shift = 0x100,
+ mouse_flag_ctrl = 0x200,
+}mouse_flag_e;
+
+typedef enum pattern_type_e {
+ pattern_none = 0,
+ pattern_lineargradient = 1,
+ pattern_pathgradient = 2,
+ pattern_texture = 3,
+}pattern_type_e;
+
+typedef unsigned int color_t;
+
+struct viewporttype {
+ int left;
+ int top;
+ int right;
+ int bottom;
+ int clipflag;
+};
+
+struct textsettingstype {
+ int font;
+ int direction;
+ int charsize;
+ int horiz;
+ int vert;
+};
+
+struct linestyletype {
+ int linestyle;
+ unsigned short upattern;
+ int thickness;
+};
+
+typedef struct key_msg {
+ int key;
+ key_msg_e msg;
+ unsigned int flags;
+}key_msg;
+
+typedef struct mouse_msg {
+ int x;
+ int y;
+ mouse_msg_e msg;
+ unsigned int flags;
+ int wheel;
+ bool is_left() {return (flags & mouse_flag_left) != 0;}
+ bool is_right() {return (flags & mouse_flag_right) != 0;}
+ bool is_mid() {return (flags & mouse_flag_mid) != 0;}
+ bool is_down() {return msg == mouse_msg_down;}
+ bool is_up() {return msg == mouse_msg_up;}
+ bool is_move() {return msg == mouse_msg_move;}
+ bool is_wheel() {return msg == mouse_msg_wheel;}
+}mouse_msg;
+
+typedef struct ege_point {
+ float x;
+ float y;
+}ege_point;
+
+typedef struct ege_rect {
+ float x;
+ float y;
+ float w;
+ float h;
+}ege_rect;
+
+typedef struct ege_colpoint {
+ float x;
+ float y;
+ color_t color;
+}ege_colpoint;
+
+// Êó±êÏûÏ¢
+EGE_DEPRECATE(MOUSEMSG)
+struct MOUSEMSG {
+ UINT uMsg; // µ±Ç°Êó±êÏûÏ¢
+ bool mkCtrl; // Ctrl ¼üÊÇ·ñ°´ÏÂ
+ bool mkShift; // Shift ¼üÊÇ·ñ°´ÏÂ
+ bool mkLButton; // Êó±ê×ó¼üÊÇ·ñ°´ÏÂ
+ bool mkMButton; // Êó±êÖмüÊÇ·ñ°´ÏÂ
+ bool mkRButton; // Êó±êÓÒ¼üÊÇ·ñ°´ÏÂ
+ short x; // µ±Ç°Êó±ê x ×ø±ê
+ short y; // µ±Ç°Êó±ê y ×ø±ê
+ short wheel; // Êó±ê¹öÂÖ¹ö¶¯Öµ(120Ϊ»ùÊý)
+};
+
+struct msg_createwindow {
+ HANDLE hEvent;
+ HWND hwnd;
+ LPCWSTR classname;
+ DWORD style;
+ DWORD exstyle;
+ unsigned id;
+ LPVOID param;
+};
+
+
+// »æͼ»·¾³³õʼ»¯²ÎÊý
+#define INITGRAPH(x, y) struct _initgraph_{_initgraph_(){initgraph(x, y);}\
+ ~_initgraph_(){closegraph();}}_g_initgraph_
+#define INITGRAPH3(x, y, f) struct _initgraph_{_initgraph_(){initgraph(x, y, f);}\
+ ~_initgraph_(){closegraph();}}_g_initgraph_
+
+//ÒôÀÖÀàºê
+#define MUSIC_ERROR 0xFFFFFFFF
+
+
+typedef void (CALLBACK_PROC)();
+typedef int (__stdcall MSG_KEY_PROC )(void*, unsigned, int);
+typedef int (__stdcall MSG_MOUSE_PROC)(void*, unsigned, int, int, int);
+typedef CALLBACK_PROC * LPCALLBACK_PROC;
+typedef MSG_KEY_PROC * LPMSG_KEY_PROC;
+typedef MSG_MOUSE_PROC * LPMSG_MOUSE_PROC;
+
+/*
+×¢Ò⣺ÒÔϺ¯ÊýµÄ×¢Êͺó´ø'###'µÄº¯Êý±íʾδʵÏÖ
+*/
+
+struct VECTOR3D;
+
+// 3d ¼ÆË㸨Öúº¯Êý
+void EGEAPI rotate_point3d_x(VECTOR3D * pt, float r); //»¡¶È£¬ÓÒÊÖ¶¨Ôò
+void EGEAPI rotate_point3d_y(VECTOR3D * pt, float r);
+void EGEAPI rotate_point3d_z(VECTOR3D * pt, float r);
+
+struct VECTOR3D {
+ float x, y, z;
+ VECTOR3D() {
+ x = 0; y = 0; z = 0;
+ }
+ VECTOR3D(float _x, float _y) {
+ x = _x; y = _y; z = 0;
+ }
+ VECTOR3D(float _x, float _y, float _z) {
+ x = _x; y = _y; z = _z;
+ }
+ VECTOR3D& operator = (const VECTOR3D& _fp) {
+ x = _fp.x; y = _fp.y; z = _fp.z;
+ return *this;
+ }
+ VECTOR3D& operator += (const VECTOR3D& _fp);
+ VECTOR3D& operator -= (const VECTOR3D& _fp);
+ VECTOR3D operator + (const VECTOR3D& _fp) const;
+ VECTOR3D operator - (const VECTOR3D& _fp) const;
+ VECTOR3D& operator *= (float f); //Ëõ·Å
+ VECTOR3D operator * (float f) const; //Ëõ·Å
+ float operator * (const VECTOR3D& _fp) const; //µã³Ë
+ VECTOR3D operator & (const VECTOR3D& _fp) const; //²æ³Ë
+ VECTOR3D& operator &= (const VECTOR3D& _fp); //²æ³Ë
+ float GetModule() const;
+ float GetSqrModule() const {
+ return float(x*x + y*y + z*z);
+ }
+ VECTOR3D& SetModule(float m) {
+ float t = m / GetModule();
+ *this *= t;
+ return *this;
+ }
+ VECTOR3D& Rotate(float rad, const VECTOR3D& v); //ÈÆÈÎÒâÖáÐýת£¬ÓÒÊÖ¶¨Ôò£¬radΪ»¡¶È
+ VECTOR3D& Rotate(float rad, float x, float y, float z) {
+ VECTOR3D v(x, y, z);
+ return Rotate(rad, v);
+ }
+ VECTOR3D& Rotate(const VECTOR3D& e, const VECTOR3D& s = VECTOR3D(0.0f, 0.0f, 1.0f)); //´Ósµ½eÖ®¼äµÄ¼Ð½ÇÈ·¶¨Ðýת
+ static float GetAngel(const VECTOR3D& e, const VECTOR3D& s = VECTOR3D(0.0f, 0.0f, 1.0f));
+};
+
+
+class IMAGE;
+typedef IMAGE *PIMAGE;
+
+// »æͼ»·¾³Ïà¹Øº¯Êý
+
+void EGEAPI initgraph(int Width, int Height, int Flag = INIT_DEFAULT); // ³õʼ»¯Í¼Ðλ·¾³
+void EGEAPI initgraph(int* gdriver, int* gmode, char* path); // ¼æÈÝ Borland C++ 3.1 µÄÖØÔØ£¬Ö»Ê¹Óà 640x480x24bit
+void EGEAPI closegraph(); // ¹Ø±ÕͼÐλ·¾³
+bool EGEAPI is_run(); // ÅжÏUIÊÇ·ñÍ˳ö
+void EGEAPI setcaption(LPCSTR caption);
+void EGEAPI setcaption(LPCWSTR caption);
+
+void EGEAPI setrendermode(rendermode_e mode);
+
+// »æͼ»·¾³ÉèÖÃ
+PIMAGE gettarget();
+int settarget(PIMAGE pbuf); // Óà NULL ÉèÖô°¿ÚΪ»æͼĿ±ê
+
+void EGEAPI cleardevice(PIMAGE pimg = NULL); // ÇåÆÁ
+
+void EGEAPI getviewport(int *pleft, int *ptop, int *pright, int *pbottom, int *pclip = 0, PIMAGE pimg = NULL); // »ñÈ¡ÊÓͼÐÅÏ¢
+void EGEAPI setviewport(int left, int top, int right, int bottom, int clip = 1, PIMAGE pimg = NULL); // ÉèÖÃÊÓͼ
+void EGEAPI clearviewport(PIMAGE pimg = NULL); // Çå¿ÕÊÓͼ
+
+EGE_DEPRECATE(setactivepage)
+void EGEAPI setactivepage(int page); // ÉèÖõ±Ç°»æͼҳ£¬¼´»æͼº¯ÊýĬÈϵÄÊä³ö»º³å£¬·¶Î§0-1£¬Ä¬ÈÏΪ0
+EGE_DEPRECATE(setvisualpage)
+void EGEAPI setvisualpage(int page); // ÉèÖõ±Ç°ÏÔʾҳ£¬ÓÃÓÚÉèÖÃÏÔʾµ½´°¿ÚÉϵÄÒ³£¬·¶Î§0-1£¬Ä¬ÈÏΪ0
+EGE_DEPRECATE(swappage)
+void EGEAPI swappage();
+void EGEAPI window_getviewport(struct viewporttype * viewport);
+void EGEAPI window_getviewport(int* left, int* top, int* right, int* bottom);
+void EGEAPI window_setviewport(int left, int top, int right, int bottom);
+
+// »æͼÊôÐÔ
+EGE_DEPRECATE(setactivepage)
+void EGEAPI getlinestyle(int *plinestyle, unsigned short *pupattern = NULL, int *pthickness = NULL, PIMAGE pimg = NULL); // »ñÈ¡µ±Ç°ÏßÐÎ
+void EGEAPI setlinestyle(int linestyle, unsigned short upattern = 0, int thickness = 1, PIMAGE pimg = NULL); // ÉèÖõ±Ç°ÏßÐÎ
+void EGEAPI setlinewidth(float width, PIMAGE pimg = NULL); // ÉèÖõ±Ç°Ïß¿í
+//EGE_DEPRECATE(setactivepage)
+//void getfillstyle(color_t *pcolor, int *ppattern = NULL, PIMAGE pimg = NULL); // »ñÈ¡Ìî³äÀàÐÍ ###
+EGE_DEPRECATE(setactivepage)
+void EGEAPI setfillstyle(int pattern, color_t color, PIMAGE pimg = NULL); // ÉèÖÃÌî³äÀàÐÍ
+
+void EGEAPI setwritemode(int mode, PIMAGE pimg = NULL); // ÉèÖûæͼλ²Ù×÷ģʽ
+
+//void EGEAPI graphdefaults(PIMAGE pimg = NULL); // ÖØÖÃËùÓлæͼÉèÖÃΪĬÈÏÖµ ###
+
+// É«²Êº¯Êý
+color_t EGEAPI getcolor(PIMAGE pimg = NULL); // »ñÈ¡µ±Ç°»æͼǰ¾°É«
+color_t EGEAPI getfillcolor(PIMAGE pimg = NULL); // »ñÈ¡µ±Ç°»æͼÌî³äÉ«
+color_t EGEAPI getbkcolor(PIMAGE pimg = NULL); // »ñÈ¡µ±Ç°»æͼ±³¾°É«
+void EGEAPI setcolor(color_t color, PIMAGE pimg = NULL); // ÉèÖõ±Ç°»æͼǰ¾°É«
+void EGEAPI setfillcolor(color_t color, PIMAGE pimg = NULL); // ÉèÖõ±Ç°»æͼÌî³äÉ«
+void EGEAPI setbkcolor(color_t color, PIMAGE pimg = NULL); // ÉèÖõ±Ç°»æͼ±³¾°É«£¨ÉèÖò¢×ö±³¾°É«ÏñËØÌæ»»£©
+void EGEAPI setbkcolor_f(color_t color, PIMAGE pimg = NULL); // ¿ìËÙÉèÖõ±Ç°»æͼ±³¾°É«£¨Ö»ÉèÖò»»æ»£©
+void EGEAPI setfontbkcolor(color_t color, PIMAGE pimg = NULL); // ÉèÖõ±Ç°ÎÄ×Ö±³¾°É«
+void EGEAPI setbkmode(int iBkMode, PIMAGE pimg = NULL); // ÉèÖñ³¾°»ìºÏģʽ(0=OPAQUE, 1=TRANSPARENT)
+void EGEAPI setinitmode(int mode = INIT_DEFAULT, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT); //ÉèÖóõʼ»¯Ä£Ê½£¬mode=0ΪÆÕͨ£¬1ΪÎޱ߿ò´°¿Ú£¬xyÊdzõʼ´°¿Ú×ø±ê
+int EGEAPI attachHWND(HWND hWnd);
+
+// ¼æÈݺê
+#define RGBtoGRAY rgb2gray
+#define RGBtoHSL rgb2hsl
+#define RGBtoHSV rgb2hsv
+#define HSLtoRGB hsl2rgb
+#define HSVtoRGB hsv2rgb
+
+// ÑÕÉ«Ä£ÐÍת»»º¯Êý
+color_t EGEAPI rgb2gray(color_t rgb);
+void EGEAPI rgb2hsl(color_t rgb, float *H, float *S, float *L);
+void EGEAPI rgb2hsv(color_t rgb, float *H, float *S, float *V);
+color_t EGEAPI hsl2rgb(float H, float S, float L);
+color_t EGEAPI hsv2rgb(float H, float S, float V);
+
+
+// »ù±¾»æͼº¯Êý
+
+color_t EGEAPI getpixel (int x, int y, PIMAGE pimg = NULL); // »ñÈ¡µãµÄÑÕÉ«
+void EGEAPI putpixel (int x, int y, color_t color, PIMAGE pimg = NULL); // »µã
+color_t EGEAPI getpixel_f(int x, int y, PIMAGE pimg = NULL); // »ñÈ¡µãµÄÑÕÉ«
+void EGEAPI putpixel_f(int x, int y, color_t color, PIMAGE pimg = NULL); // »µã
+void EGEAPI putpixels (int nPoint, int* pPoints, PIMAGE pimg = NULL); // ÅúÁ¿»µã
+void EGEAPI putpixels_f(int nPoint, int* pPoints, PIMAGE pimg = NULL); // ÅúÁ¿»µã
+
+void EGEAPI moveto(int x, int y, PIMAGE pimg = NULL); // Òƶ¯µ±Ç°µã(¾ø¶Ô×ø±ê)
+void EGEAPI moverel(int dx, int dy, PIMAGE pimg = NULL); // Òƶ¯µ±Ç°µã(Ïà¶Ô×ø±ê)
+
+void EGEAPI line(int x1, int y1, int x2, int y2, PIMAGE pimg = NULL); // »Ïß
+void EGEAPI linerel(int dx, int dy, PIMAGE pimg = NULL); // »Ïß(ÖÁÏà¶Ô×ø±ê)
+void EGEAPI lineto(int x, int y, PIMAGE pimg = NULL); // »Ïß(ÖÁ¾ø¶Ô×ø±ê)
+void EGEAPI line_f(float x1, float y1, float x2, float y2, PIMAGE pimg = NULL); // »Ïß
+void EGEAPI linerel_f(float dx, float dy, PIMAGE pimg = NULL); // »Ïß(ÖÁÏà¶Ô×ø±ê)
+void EGEAPI lineto_f(float x, float y, PIMAGE pimg = NULL); // »Ïß(ÖÁ¾ø¶Ô×ø±ê)
+
+
+void EGEAPI rectangle(int left, int top, int right, int bottom, PIMAGE pimg = NULL); // »¾ØÐÎ
+
+//void EGEAPI getarccoords(int *px, int *py, int *pxstart, int *pystart, int *pxend, int *pyend, PIMAGE pimg = NULL); // »ñÈ¡Ô²»¡×ø±êÐÅÏ¢ ###
+void EGEAPI arc(int x, int y, int stangle, int endangle, int radius, PIMAGE pimg = NULL); // »Ô²»¡
+void EGEAPI circle(int x, int y, int radius, PIMAGE pimg = NULL); // »Ô²
+void EGEAPI pieslice(int x, int y, int stangle, int endangle, int radius, PIMAGE pimg = NULL); // »Ìî³äÔ²ÉÈÐÎ
+void EGEAPI ellipse(int x, int y, int stangle, int endangle, int xradius, int yradius, PIMAGE pimg = NULL);// »ÍÖÔ²»¡Ïß
+void EGEAPI fillellipse(int x, int y, int xradius, int yradius, PIMAGE pimg = NULL); // »Ìî³äÍÖÔ²
+void EGEAPI sector(int x, int y, int stangle, int endangle, int xradius, int yradius, PIMAGE pimg = NULL); // »Ìî³äÍÖÔ²ÉÈÐÎ
+
+void EGEAPI arcf(float x, float y, float stangle, float endangle, float radius, PIMAGE pimg = NULL); // »Ô²»¡
+void EGEAPI circlef(float x, float y, float radius, PIMAGE pimg = NULL); // »Ô²
+void EGEAPI pieslicef(float x, float y, float stangle, float endangle, float radius, PIMAGE pimg = NULL); // »Ìî³äÔ²ÉÈÐÎ
+void EGEAPI ellipsef(float x, float y, float stangle, float endangle, float xradius, float yradius, PIMAGE pimg = NULL);// »ÍÖÔ²»¡Ïß
+void EGEAPI fillellipsef(float x, float y, float xradius, float yradius, PIMAGE pimg = NULL); // »Ìî³äÍÖÔ²
+void EGEAPI sectorf(float x, float y, float stangle, float endangle, float xradius, float yradius, PIMAGE pimg = NULL); // »Ìî³äÍÖÔ²ÉÈÐÎ
+
+void EGEAPI bar(int left, int top, int right, int bottom, PIMAGE pimg = NULL); // »Îޱ߿òÌî³ä¾ØÐÎ
+void EGEAPI bar3d(int left, int top, int right, int bottom, int depth, int topflag, PIMAGE pimg = NULL); // »Óб߿òÈýάÌî³ä¾ØÐÎ
+
+void EGEAPI drawpoly(int numpoints, const int *polypoints, PIMAGE pimg = NULL); // »¶à±ßÐÎ
+void EGEAPI drawlines(int numlines, const int *polypoints, PIMAGE pimg = NULL); // »¶àÌõ²»Á¬ÐøÏߣ¨À©Õ¹º¯Êý£©
+void EGEAPI drawbezier(int numpoints, const int *polypoints, PIMAGE pimg = NULL); // »bezierÇúÏߣ¨À©Õ¹º¯Êý£©
+void EGEAPI fillpoly(int numpoints, const int *polypoints, PIMAGE pimg = NULL); // »Ìî³äµÄ¶à±ßÐÎ
+void EGEAPI fillpoly_gradient(int numpoints, const ege_colpoint* polypoints, PIMAGE pimg = NULL); // »½¥±äÌî³äµÄ¶à±ßÐÎ
+void EGEAPI floodfill(int x, int y, int border, PIMAGE pimg = NULL); // °´±ß½çÑÕÉ«Ìî³äÇøÓò
+void EGEAPI floodfillsurface(int x, int y, color_t areacolor, PIMAGE pimg = NULL); // °´ÆðʼµãÑÕÉ«Ìî³äÇøÓò
+
+// ¸ß¼¶»æͼº¯Êý£¨´øAA£©
+// ege new_api
+void EGEAPI ege_enable_aa(bool enable, PIMAGE pimg = NULL);
+
+void EGEAPI ege_line(float x1, float y1, float x2, float y2, PIMAGE pimg = NULL);
+void EGEAPI ege_drawpoly(int numpoints, ege_point* polypoints, PIMAGE pimg = NULL);
+void EGEAPI ege_drawcurve(int numpoints, ege_point* polypoints, PIMAGE pimg = NULL);
+void EGEAPI ege_rectangle(float x, float y, float w, float h, PIMAGE pimg = NULL);
+void EGEAPI ege_ellipse(float x, float y, float w, float h, PIMAGE pimg = NULL);
+void EGEAPI ege_pie(float x, float y, float w, float h, float stangle, float sweepAngle, PIMAGE pimg = NULL);
+
+void EGEAPI ege_arc(float x, float y, float w, float h, float stangle, float sweepAngle, PIMAGE pimg = NULL);
+void EGEAPI ege_bezier(int numpoints, ege_point* polypoints, PIMAGE pimg = NULL);
+
+void EGEAPI ege_fillpoly(int numpoints, ege_point* polypoints, PIMAGE pimg = NULL);
+void EGEAPI ege_fillrect(float x, float y, float w, float h, PIMAGE pimg = NULL);
+void EGEAPI ege_fillellipse(float x, float y, float w, float h, PIMAGE pimg = NULL);
+void EGEAPI ege_fillpie(float x, float y, float w, float h, float stangle, float sweepAngle, PIMAGE pimg = NULL);
+
+void EGEAPI ege_setpattern_none(PIMAGE pimg = NULL);
+void EGEAPI ege_setpattern_lineargradient(float x1, float y1, color_t c1, float x2, float y2, color_t c2, PIMAGE pimg = NULL);
+void EGEAPI ege_setpattern_pathgradient(ege_point center, color_t centercolor,
+ int count, ege_point* points, int colcount, color_t* pointscolor, PIMAGE pimg = NULL);
+void EGEAPI ege_setpattern_ellipsegradient(ege_point center, color_t centercolor,
+ float x, float y, float w, float h, color_t color, PIMAGE pimg = NULL);
+void EGEAPI ege_setpattern_texture(PIMAGE srcimg, float x, float y, float w, float h, PIMAGE pimg = NULL);
+
+void EGEAPI ege_setalpha(int alpha, PIMAGE pimg = NULL);
+void EGEAPI ege_gentexture(bool gen, PIMAGE pimg = NULL);
+void EGEAPI ege_puttexture(PIMAGE srcimg, float x, float y, float w, float h, PIMAGE pimg = NULL);
+void EGEAPI ege_puttexture(PIMAGE srcimg, ege_rect dest, PIMAGE pimg = NULL);
+void EGEAPI ege_puttexture(PIMAGE srcimg, ege_rect dest, ege_rect src, PIMAGE pimg = NULL);
+//
+
+//int EGEAPI Begin2d();
+//void EGEAPI EndRender();
+
+//ʱ¼äº¯Êý£¨ÒÔϺ¯Êý²»ÄÜÔÚ¶àÏß³ÌÏÂʹÓã¬Ö»Äܸø»æͼÖ÷Ï̵߳÷Óã©
+void EGEAPI ege_sleep(long ms); // ÖÁÉÙÑÓ³ÙmsºÁÃë
+void EGEAPI delay(long ms); // ÖÁÉÙÑÓ³ÙmsºÁÃë
+void EGEAPI delay_ms(long ms); // ƽ¾ùÑÓ³ÙmsºÁÃë
+void EGEAPI delay_fps(int fps); // ƽ¾ùÑÓ³Ù1000/fpsºÁÃ룬ÓÃÓÚÎȶ¨Ö¡ÂÊ¿ØÖÆ
+void EGEAPI delay_fps(long fps); // ƽ¾ùÑÓ³Ù1000/fpsºÁÃ룬ÓÃÓÚÎȶ¨Ö¡ÂÊ¿ØÖÆ
+void EGEAPI delay_fps(double fps); // ƽ¾ùÑÓ³Ù1000/fpsºÁÃ룬ÓÃÓÚÎȶ¨Ö¡ÂÊ¿ØÖÆ
+void EGEAPI delay_jfps(int fps); // ƽ¾ùÑÓ³Ù1000/fpsºÁÃ룬ÓÃÓÚÎȶ¨Âß¼Ö¡ÂÊ¿ØÖÆ£¬»æͼ´øÌøÖ¡
+void EGEAPI delay_jfps(long fps); // ƽ¾ùÑÓ³Ù1000/fpsºÁÃ룬ÓÃÓÚÎȶ¨Âß¼Ö¡ÂÊ¿ØÖÆ£¬»æͼ´øÌøÖ¡
+void EGEAPI delay_jfps(double fps); // ƽ¾ùÑÓ³Ù1000/fpsºÁÃ룬ÓÃÓÚÎȶ¨Âß¼Ö¡ÂÊ¿ØÖÆ£¬»æͼ´øÌøÖ¡
+// ÒÔϺ¯Êý¿ÉÒÔ¶àÏß³ÌÏÂʹÓ㬷ÇͼÐÎ(worker)Ï̵߳ÄsleepʹÓÃÕâ¸ö
+void EGEAPI api_sleep(long dwMilliseconds);
+double EGEAPI fclock(); // »ñÈ¡ÒÔÃëΪµ¥Î»µÄ¸¡µãʱ¼ä£¬Ö»ÓÃÓÚ¼ÆʱÓ㬾«¶È0.01Ã룬
+
+// ÎÄ×ÖÏà¹Øº¯Êý
+void EGEAPI outtext(LPCSTR textstring, PIMAGE pimg = NULL); // ÔÚµ±Ç°Î»ÖÃÊä³öÎÄ×Ö
+void EGEAPI outtext(LPCWSTR textstring, PIMAGE pimg = NULL); // ÔÚµ±Ç°Î»ÖÃÊä³öÎÄ×Ö
+void EGEAPI outtext(CHAR c, PIMAGE pimg = NULL); // ÔÚµ±Ç°Î»ÖÃÊä³ö×Ö·û
+void EGEAPI outtext(WCHAR c, PIMAGE pimg = NULL); // ÔÚµ±Ç°Î»ÖÃÊä³ö×Ö·û
+void EGEAPI outtextxy(int x, int y, LPCSTR textstring, PIMAGE pimg = NULL); // ÔÚÖ¸¶¨Î»ÖÃÊä³öÎÄ×Ö
+void EGEAPI outtextxy(int x, int y, LPCWSTR textstring, PIMAGE pimg = NULL); // ÔÚÖ¸¶¨Î»ÖÃÊä³öÎÄ×Ö
+void EGEAPI outtextxy(int x, int y, CHAR c, PIMAGE pimg = NULL); // ÔÚÖ¸¶¨Î»ÖÃÊä³ö×Ö·û
+void EGEAPI outtextxy(int x, int y, WCHAR c, PIMAGE pimg = NULL); // ÔÚÖ¸¶¨Î»ÖÃÊä³ö×Ö·û
+void EGEAPI outtextrect(int x, int y, int w, int h, LPCSTR textstring, PIMAGE pimg = NULL); // ÔÚÖ¸¶¨¾ØÐη¶Î§Êä³öÎÄ×Ö
+void EGEAPI outtextrect(int x, int y, int w, int h, LPCWSTR textstring, PIMAGE pimg = NULL); // ÔÚÖ¸¶¨¾ØÐη¶Î§Êä³öÎÄ×Ö
+void EGEAPI xyprintf(int x, int y, LPCSTR fmt, ...); // ÔÚÖ¸¶¨Î»ÖÃÊä³ö¸ñʽ»¯×Ö·û´®£¬Ö¸¶¨»æͼĿ±êµ÷ÓÃsettarget
+void EGEAPI xyprintf(int x, int y, LPCWSTR fmt, ...); // ÔÚÖ¸¶¨Î»ÖÃÊä³ö¸ñʽ»¯×Ö·û´®£¬Ö¸¶¨»æͼĿ±êµ÷ÓÃsettarget
+void EGEAPI rectprintf(int x, int y, int w, int h, LPCSTR fmt, ...); // ÔÚÖ¸¶¨¾ØÐÎÊä³ö¸ñʽ»¯×Ö·û´®£¬Ö¸¶¨»æͼĿ±êµ÷ÓÃsettarget
+void EGEAPI rectprintf(int x, int y, int w, int h, LPCWSTR fmt, ...); // ÔÚÖ¸¶¨¾ØÐÎÊä³ö¸ñʽ»¯×Ö·û´®£¬Ö¸¶¨»æͼĿ±êµ÷ÓÃsettarget
+int EGEAPI textwidth(LPCSTR textstring, PIMAGE pimg = NULL); // »ñÈ¡×Ö·û´®Õ¼ÓõÄÏñËØ¿í
+int EGEAPI textwidth(LPCWSTR textstring, PIMAGE pimg = NULL); // »ñÈ¡×Ö·û´®Õ¼ÓõÄÏñËØ¿í
+int EGEAPI textwidth(CHAR c, PIMAGE pimg = NULL);
+int EGEAPI textwidth(WCHAR c, PIMAGE pimg = NULL);
+int EGEAPI textheight(LPCSTR textstring, PIMAGE pimg = NULL); // »ñÈ¡×Ö·û´®Õ¼ÓõÄÏñËظß
+int EGEAPI textheight(LPCWSTR textstring, PIMAGE pimg = NULL); // »ñÈ¡×Ö·û´®Õ¼ÓõÄÏñËظß
+int EGEAPI textheight(CHAR c, PIMAGE pimg = NULL);
+int EGEAPI textheight(WCHAR c, PIMAGE pimg = NULL);
+void EGEAPI settextjustify(int horiz, int vert, PIMAGE pimg = NULL);
+
+// ÉèÖõ±Ç°×ÖÌåÑùʽ(Ïê¼û°ïÖú)
+// nHeight: ×Ö·ûµÄƽ¾ù¸ß¶È£»
+// nWidth: ×Ö·ûµÄƽ¾ù¿í¶È(0 ±íʾ×ÔÊÊÓ¦)£»
+// lpszFace: ×ÖÌåÃû³Æ£»
+// nEscapement: ×Ö·û´®µÄÊéд½Ç¶È(µ¥Î» 0.1 ¶È)£»
+// nOrientation: ÿ¸ö×Ö·ûµÄÊéд½Ç¶È(µ¥Î» 0.1 ¶È)£»
+// nWeight: ×Ö·ûµÄ±Ê»´Öϸ(0 ±íʾĬÈÏ´Öϸ)£»
+// bItalic: ÊÇ·ñбÌ壻
+// bUnderline: ÊÇ·ñÏ»®Ïߣ»
+// bStrikeOut: ÊÇ·ñɾ³ýÏߣ»
+// fbCharSet: Ö¸¶¨×Ö·û¼¯£»
+// fbOutPrecision: Ö¸¶¨ÎÄ×ÖµÄÊä³ö¾«¶È£»
+// fbClipPrecision: Ö¸¶¨ÎÄ×ֵļô¼¾«¶È£»
+// fbQuality: Ö¸¶¨ÎÄ×ÖµÄÊä³öÖÊÁ¿£»
+// fbPitchAndFamily: Ö¸¶¨ÒÔ³£¹æ·½Ê½ÃèÊö×ÖÌåµÄ×ÖÌåϵÁС£
+void EGEAPI setfont(int nHeight, int nWidth, LPCSTR lpszFace, PIMAGE pimg = NULL);
+void EGEAPI setfont(int nHeight, int nWidth, LPCWSTR lpszFace, PIMAGE pimg = NULL);
+void EGEAPI setfont(int nHeight, int nWidth, LPCSTR lpszFace, int nEscapement, int nOrientation,
+ int nWeight, int bItalic, int bUnderline, int bStrikeOut, PIMAGE pimg = NULL);
+void EGEAPI setfont(int nHeight, int nWidth, LPCWSTR lpszFace, int nEscapement, int nOrientation,
+ int nWeight, int bItalic, int bUnderline, int bStrikeOut, PIMAGE pimg = NULL);
+void EGEAPI setfont(int nHeight, int nWidth, LPCSTR lpszFace, int nEscapement, int nOrientation,
+ int nWeight, int bItalic, int bUnderline, int bStrikeOut, BYTE fbCharSet,
+ BYTE fbOutPrecision, BYTE fbClipPrecision, BYTE fbQuality, BYTE fbPitchAndFamily, PIMAGE pimg = NULL);
+void EGEAPI setfont(int nHeight, int nWidth, LPCWSTR lpszFace, int nEscapement, int nOrientation,
+ int nWeight, int bItalic, int bUnderline, int bStrikeOut, BYTE fbCharSet,
+ BYTE fbOutPrecision, BYTE fbClipPrecision, BYTE fbQuality, BYTE fbPitchAndFamily, PIMAGE pimg = NULL);
+void EGEAPI setfont(const LOGFONTA *font, PIMAGE pimg = NULL); // ÉèÖõ±Ç°×ÖÌåÑùʽ
+void EGEAPI setfont(const LOGFONTW *font, PIMAGE pimg = NULL); // ÉèÖõ±Ç°×ÖÌåÑùʽ
+void EGEAPI getfont(LOGFONTA *font, PIMAGE pimg = NULL); // »ñÈ¡µ±Ç°×ÖÌåÑùʽ
+void EGEAPI getfont(LOGFONTW *font, PIMAGE pimg = NULL); // »ñÈ¡µ±Ç°×ÖÌåÑùʽ
+
+
+//ͼƬº¯Êý
+#define getmaxx getwidth
+#define getmaxy getheight
+
+int EGEAPI getwidth(PIMAGE pimg = NULL); // »ñȡͼƬ¿í¶È
+int EGEAPI getheight(PIMAGE pimg = NULL); // »ñȡͼƬ¸ß¶È
+int EGEAPI getx(PIMAGE pimg = NULL); // »ñÈ¡µ±Ç° x ×ø±ê
+int EGEAPI gety(PIMAGE pimg = NULL); // »ñÈ¡µ±Ç° y ×ø±ê
+
+PIMAGE EGEAPI newimage(); // ´´½¨PIMAGE
+PIMAGE EGEAPI newimage(int width, int height); // ´´½¨PIMAGE
+void EGEAPI delimage(PIMAGE pImg); // ´´½¨PIMAGE
+color_t* EGEAPI getbuffer(PIMAGE pImg);
+
+int EGEAPI resize(PIMAGE pDstImg, int width, int height); //ÖØÉè³ß´ç
+void EGEAPI getimage(PIMAGE pDstImg, int srcX, int srcY, int srcWidth, int srcHeight); // ´ÓÆÁÄ»»ñȡͼÏñ
+void EGEAPI getimage(PIMAGE pDstImg, const PIMAGE pSrcImg, int srcX, int srcY, int srcWidth, int srcHeight); // ´ÓÁíÒ»¸ö PIMAGE ¶ÔÏóÖлñȡͼÏñ
+int EGEAPI getimage(PIMAGE pDstImg, LPCSTR pImgFile, int zoomWidth = 0, int zoomHeight = 0); // ´ÓͼƬÎļþ»ñȡͼÏñ(bmp/jpg/gif/emf/wmf)
+int EGEAPI getimage(PIMAGE pDstImg, LPCWSTR pImgFile, int zoomWidth = 0, int zoomHeight = 0); // ´ÓͼƬÎļþ»ñȡͼÏñ(bmp/jpg/gif/emf/wmf)
+int EGEAPI getimage(PIMAGE pDstImg, LPCSTR pResType, LPCSTR pResName, int zoomWidth = 0, int zoomHeight = 0); // ´Ó×ÊÔ´Îļþ»ñȡͼÏñ(bmp/jpg/gif/emf/wmf)
+int EGEAPI getimage(PIMAGE pDstImg, LPCWSTR pResType, LPCWSTR pResName, int zoomWidth = 0, int zoomHeight = 0); // ´Ó×ÊÔ´Îļþ»ñȡͼÏñ(bmp/jpg/gif/emf/wmf)
+void EGEAPI putimage(int dstX, int dstY, const PIMAGE pSrcImg, DWORD dwRop = SRCCOPY); // »æÖÆͼÏñµ½ÆÁÄ»
+void EGEAPI putimage(int dstX, int dstY, int dstWidth, int dstHeight, const PIMAGE pSrcImg, int srcX, int srcY, DWORD dwRop = SRCCOPY); // »æÖÆͼÏñµ½ÆÁÄ»(Ö¸¶¨¿í¸ß)
+void EGEAPI putimage(int dstX, int dstY, int dstWidth, int dstHeight, const PIMAGE pSrcImg, int srcX, int srcY, int srcWidth, int srcHeight, DWORD dwRop = SRCCOPY); // »æÖÆͼÏñµ½ÆÁÄ»(Ö¸¶¨Ô´¿í¸ßºÍÄ¿±ê¿í¸ß½øÐÐÀÉì)
+void EGEAPI putimage(PIMAGE pDstImg, int dstX, int dstY, const PIMAGE pSrcImg, DWORD dwRop = SRCCOPY); // »æÖÆͼÏñµ½ÁíһͼÏñÖÐ
+void EGEAPI putimage(PIMAGE pDstImg, int dstX, int dstY, int dstWidth, int dstHeight, const PIMAGE pSrcImg, int srcX, int srcY, DWORD dwRop = SRCCOPY); // »æÖÆͼÏñµ½ÁíһͼÏñÖÐ(Ö¸¶¨¿í¸ß)
+void EGEAPI putimage(PIMAGE pDstImg, int dstX, int dstY, int dstWidth, int dstHeight, const PIMAGE pSrcImg, int srcX, int srcY, int srcWidth, int srcHeight, DWORD dwRop = SRCCOPY); // »æÖÆͼÏñµ½ÁíһͼÏñÖÐ(Ö¸¶¨Ô´¿í¸ßºÍÄ¿±ê¿í¸ß½øÐÐÀÉì)
+int EGEAPI saveimage(PIMAGE pimg, LPCSTR filename);
+int EGEAPI saveimage(PIMAGE pimg, LPCWSTR filename);
+int EGEAPI savepng(PIMAGE pimg, LPCSTR filename, int bAlpha = 0);
+int EGEAPI savepng(PIMAGE pimg, LPCWSTR filename, int bAlpha = 0);
+int EGEAPI getimage_pngfile(PIMAGE pimg, LPCSTR filename);
+int EGEAPI getimage_pngfile(PIMAGE pimg, LPCWSTR filename);
+
+int EGEAPI putimage_transparent(
+ PIMAGE imgdest, // handle to dest
+ PIMAGE imgsrc, // handle to source
+ int nXOriginDest, // x-coord of destination upper-left corner
+ int nYOriginDest, // y-coord of destination upper-left corner
+ color_t crTransparent, // color to make transparent
+ int nXOriginSrc = 0, // x-coord of source upper-left corner
+ int nYOriginSrc = 0, // y-coord of source upper-left corner
+ int nWidthSrc = 0, // width of source rectangle
+ int nHeightSrc = 0 // height of source rectangle
+);
+int EGEAPI putimage_alphablend(
+ PIMAGE imgdest, // handle to dest
+ PIMAGE imgsrc, // handle to source
+ int nXOriginDest, // x-coord of destination upper-left corner
+ int nYOriginDest, // y-coord of destination upper-left corner
+ unsigned char alpha, // alpha
+ int nXOriginSrc = 0, // x-coord of source upper-left corner
+ int nYOriginSrc = 0, // y-coord of source upper-left corner
+ int nWidthSrc = 0, // width of source rectangle
+ int nHeightSrc = 0 // height of source rectangle
+);
+int EGEAPI putimage_alphatransparent(
+ PIMAGE imgdest, // handle to dest
+ PIMAGE imgsrc, // handle to source
+ int nXOriginDest, // x-coord of destination upper-left corner
+ int nYOriginDest, // y-coord of destination upper-left corner
+ color_t crTransparent, // color to make transparent
+ unsigned char alpha, // alpha
+ int nXOriginSrc = 0, // x-coord of source upper-left corner
+ int nYOriginSrc = 0, // y-coord of source upper-left corner
+ int nWidthSrc = 0, // width of source rectangle
+ int nHeightSrc = 0 // height of source rectangle
+);
+int EGEAPI putimage_withalpha(
+ PIMAGE imgdest, // handle to dest
+ PIMAGE imgsrc, // handle to source
+ int nXOriginDest, // x-coord of destination upper-left corner
+ int nYOriginDest, // y-coord of destination upper-left corner
+ int nXOriginSrc = 0, // x-coord of source upper-left corner
+ int nYOriginSrc = 0, // y-coord of source upper-left corner
+ int nWidthSrc = 0, // width of source rectangle
+ int nHeightSrc = 0 // height of source rectangle
+);
+int EGEAPI imagefilter_blurring (
+ PIMAGE imgdest, // handle to dest
+ int intensity,
+ int alpha,
+ int nXOriginDest = 0,
+ int nYOriginDest = 0,
+ int nWidthDest = 0,
+ int nHeightDest = 0
+);
+int EGEAPI putimage_rotate(
+ PIMAGE imgdest,
+ PIMAGE imgtexture,
+ int nXOriginDest,
+ int nYOriginDest,
+ float centerx,
+ float centery,
+ float radian,
+ int btransparent = 0, // transparent (1) or not (0)
+ int alpha = -1, // in range[0, 256], alpha== -1 means no alpha
+ int smooth = 0
+);
+
+int EGEAPI putimage_rotatezoom(
+ PIMAGE imgdest,
+ PIMAGE imgtexture,
+ int nXOriginDest,
+ int nYOriginDest,
+ float centerx,
+ float centery,
+ float radian,
+ float zoom,
+ int btransparent = 0, // transparent (1) or not (0)
+ int alpha = -1, // in range[0, 256], alpha== -1 means no alpha
+ int smooth = 0
+);
+
+class PushTarget {
+public:
+ PushTarget() { m_target = gettarget(); }
+ PushTarget(PIMAGE target) { m_target = gettarget(); settarget(target); }
+ ~PushTarget() { settarget(m_target); }
+private:
+ PIMAGE m_target;
+};
+
+#define CTL_PREINIT(classname, parent) struct preinit_obj { \
+ preinit_obj(classname* This, int inheritlevel) { \
+ This->pre_init(inheritlevel); \
+ } \
+ }_preinit_obj; \
+ enum inherit_e { inherit_level_e = parent::inherit_level_e + 1, }; \
+ static void firstinit(ege::egeControlBase* This) { \
+ ((classname*)This)->m_inheritlevel = 1; \
+ } \
+ void pre_init(int inheritlevel) {\
+
+#define CTL_PREINITEND }
+#define CTL_DEFPARAM int inherit = inherit_level_e, ege::egeControlBase* pParent = NULL
+#define CTL_INITBASE(parent) _preinit_obj(this, inherit_level_e), parent(inherit, (ege::egeControlBase*)pParent)
+#define CTL_INIT InitObject iobj(this, inherit_level_e);\
+ ege::PushTarget _pushtarget(buf());
+
+#define EGECTRL_INITEND() }
+
+class egeControlBase
+{
+public:
+ enum ROP {
+ COPY = SRCCOPY,
+ XOR = SRCINVERT,
+ AND = SRCAND,
+ OR = SRCPAINT,
+ };
+ enum blendmode_e {
+ SOLIDCOPY = 0,
+ ALPHABLEND = 1,
+ };
+ enum inherit_e {
+ inherit_level_e = 0,
+ };
+ // ¹¹Ô캯Êý¿ÉÒÔ×Ô¶¨Ò壬µ«Òª°´ÐèҪѡÔñʹ²»Ê¹Óú꣬Ïê¼ûÇ°Ãæ´úÂë»òÕßÎĵµÊ¾Àý´úÂë
+ egeControlBase();
+ egeControlBase(int inherit, egeControlBase* pParent);
+ ~egeControlBase();
+
+ // ÒÔÏÂÐ麯Êý¶¼²»ÒªÖ±½ÓÏ໥µ÷ÓÃ
+ virtual LRESULT onMessage(UINT message, WPARAM wParam, LPARAM lParam) { return 0; }
+ // ÒÔϺ¯ÊýÈç¹û·µ»Ø·Ç0Ôò²»Ïò×ӿؼþ´«µÝ¼üÅÌÊó±êÏûÏ¢
+ virtual int onMouse(int x, int y, int flag) { return 0; }
+ virtual int onKeyDown(int key, int flag) { return 0; }
+ virtual int onKeyUp(int key, int flag) { return 0; }
+ virtual int onKeyChar(int key, int flag) { return 0; }
+ // ÆÁÄ»¸üкó»á±»µ÷Óã¬ÓÃÓÚ¸üÐÂÂß¼
+ virtual int onUpdate() { return 0; }
+ // ÒÔÏÂGetFocusÔÚÒª»ñµÃ½¹µãʱµ÷Ó㬷µ»ØÖµÒ»°ã·µ»Ø0±íʾ»ñÈ¡¼üÅÌÊäÈë½¹µã£¬·µ»Ø·Ç0·ÅÆú»ñµÃÊäÈë½¹µã
+ virtual int onGetFocus() { return 0; }
+ // ʧȥÊäÈë½¹µãʱµ÷ÓÃ
+ virtual void onLostFocus() { }
+ // ÉèÖóߴçÇ°µ÷Óã¬×Ô¶¨ÒåÐÞÕýº¯Êý
+ virtual void onSizing(int *w, int *h) {}
+ // ÏìÓ¦³ß´ç±ä»¯º¯Êý
+ virtual void onSize(int w, int h) {}
+ // Öػ溯Êý£¬¾¡Á¿Ç뻵½pimgÉÏ£¬ÒÔ±ãÄÜ¿ØÖÆ»æ»Ä¿±ê
+ virtual void onDraw(PIMAGE pimg) const {}
+ // ³ß´ç±ä»¯Ê±µ÷Óã¬ÓÃÓÚÖØ»¹ýÂË»º³åÇøÄÚÈÝ
+ virtual void onResetFilter() {
+ setbkcolor(BLACK, m_mainFilter);
+ cleardevice(m_mainFilter);
+ }
+ virtual void onAddChild(egeControlBase* pChild) {}
+ virtual void onDelChild(egeControlBase* pChild) {}
+ virtual void onIdle() {} // ±£Áô½Ó¿Ú£¬Î´ÓÃ
+ // ÕâÀïÒÔÉϵĺ¯Êý¿ÉÒÔ×ÔÐж¨Ò壨עÒâÉùÃ÷ÒªÒ»Ö£¬²»ÒªÂ©µôOnDrawÀïµÄconst£©
+ // ÕâÀïÒÔϵÄpublicº¯Êý¿ÉÒÔµ÷Ó㬲»¿É×Ô¶¨Ò壬ÈκÎÔ¤¶¨Òå±äÁ¿¶¼²»ÒªÖ±½Ó·ÃÎÊ£¬ÇëʹÓÃÔ¤¶¨Ò庯ÊýÀ´¿ØÖÆ
+public:
+ PIMAGE buf() { return m_mainbuf; }
+ PIMAGE filter() { return m_mainFilter; }
+ egeControlBase* parent() { return m_parent; }
+ PIMAGE buf() const { return m_mainbuf; }
+ PIMAGE filter() const { return m_mainFilter; }
+ const egeControlBase* parent() const { return m_parent; }
+
+ void blendmode(int mode) { m_AlphablendMode = mode; }
+ void setrop(int rop) { m_rop = rop; } // ÇëÓÃö¾ÙÀàÐÍROPÀïËù¶¨ÒåµÄ
+
+ void directdraw(bool bdraw) { m_bDirectDraw = (bdraw ? 1 : 0); }
+ bool isdirectdraw() const { return (m_bDirectDraw != 0); }
+ void autoredraw(bool bvisable) { m_bAutoDraw = (m_bAutoDraw ? 1 : 0); }
+ bool isautoredraw() const { return (m_bAutoDraw != 0);}
+ void visable(bool bvisable) { m_bVisable = (bvisable ? 1 : 0); }
+ bool isvisable() const { return (m_bVisable != 0);}
+ void enable(bool benable) { m_bEnable = (benable ? 1 : 0); }
+ bool isenable() const { return (m_bEnable != 0);}
+ void capture(bool bcapture) { m_bCapture = (bcapture ? 1 : 0); }
+ bool iscapture() const { return (m_bCapture != 0); }
+ void capmouse(bool bcapmouse) { m_bCapMouse = (bcapmouse ? 1 : 0); }
+ bool iscapmouse() const { return (m_bCapMouse != 0); }
+ bool isfocus() const { return (m_bInputFocus != 0); }
+ void move(int x, int y) { m_x = x; m_y = y; }
+ void size(int w, int h) {
+ onSizing(&w, &h);
+ m_w = w; m_h = h;
+ resize(m_mainbuf, w, h);
+ resize(m_mainFilter, w, h);
+ onSize(w, h);
+ onResetFilter();
+ }
+ void zorderup();
+ void zorderdown();
+ void zorderset(int z);
+
+ int getx() const { return m_x; }
+ int gety() const { return m_y; }
+ int getw() const { return m_w; }
+ int geth() const { return m_h; }
+ int width() const { return m_w; }
+ int height() const { return m_h; }
+
+ int addchild(egeControlBase* pChild);
+ int delchild(egeControlBase* pChild);
+ void draw(PIMAGE pimg);
+ void update();
+ void mouse(int x, int y, int flag);
+ void keymsgdown(unsigned key, int flag);
+ void keymsgup(unsigned key, int flag);
+ void keymsgchar(unsigned key, int flag);
+ bool operator < (const egeControlBase& pbase) const {
+ if (m_zOrderLayer != pbase.m_zOrderLayer)
+ return m_zOrderLayer < pbase.m_zOrderLayer;
+ if (m_zOrder == pbase.m_zOrder)
+ return this < &pbase;
+ else
+ return m_zOrder < pbase.m_zOrder;
+ }
+protected:
+ int allocId();
+ int allocZorder();
+ class InitObject {
+ public:
+ InitObject(egeControlBase* pThis, int inherit_level);
+ ~InitObject();
+ private:
+ egeControlBase* m_this;
+ int m_inherit_level;
+ };
+ void (* m_preinit_func )(egeControlBase*);
+private:
+ void init(egeControlBase* parent);
+ void fixzorder();
+ void sortzorder();
+#if _MSC_VER <= 1200
+public:
+#endif
+ void initok();
+private:
+ PIMAGE m_mainbuf; // Ö÷»º³å
+ PIMAGE m_mainFilter; // ¹ýÂËÆ÷
+
+private:
+ int m_bVisable; // ÊÇ·ñ¿É¼û
+ int m_bEnable; // ÊÇ·ñ¿É»ñµÃÊäÈ루¼üÅ̺ÍÊó±ê£©
+ int m_bAutoDraw; // ÊÇ·ñ×Ô¶¯»æ»µ½´°¿ÚÉÏ
+ int m_bCapture; // ÊÇ·ñ¿É»ñµÃ¼üÅÌÊäÈë½¹µã
+ int m_bInputFocus; // ÊÇ·ñÒѾ»ñµÃÊäÈë½¹µã
+ int m_bCapMouse; // ÊÇ·ñ²¶×½Êó±ê£¨¼´Ê¹²»ÔÚËùÔÚÇøÓòÄÚ£©
+ int m_zOrderLayer; // Z´ÎÐò²ã£¨Öµ½Ï´óÕßÔÚÇ°£¬Öµ½ÏСÕ߻ᱻÆäËü¿Ø¼þÕÚµ²£©
+ int m_zOrder; // Z´ÎÐò£¨Öµ½Ï´óÕßÔÚÇ°£¬Öµ½ÏСÕ߻ᱻÆäËü¿Ø¼þÕÚµ²£©
+ int m_allocId; // ·ÖÅäid
+ int m_allocZorder; // ·ÖÅäZ´ÎÐò
+
+ egeControlBase* m_parent;
+ static int s_maxchildid; // ÏÂÒ»´Î×ӿؼþ·ÖÅäIDÖµ
+
+#ifdef _GRAPH_LIB_BUILD_
+public:
+#else
+private:
+#endif
+ void* m_childmap; // ×ӿؼþ
+ void* m_childzorder; // ×ӿؼþÅÅÐò
+
+protected:
+ int m_x, m_y; // ×óÉϽÇ×ø±ê
+ int m_w, m_h; // ¿í¸ß
+
+protected:
+ DWORD m_rop; // »ìºÏ·½Ê½
+ int m_AlphablendMode; // »æ»»ìºÏ¹ýÂË·½Ê½
+ int m_bDirectDraw; // ÆôÓÃÖ±½Ó»æ»
+#if _MSC_VER <= 1200
+public:
+#endif
+ int m_inheritlevel; // ¼Ì³Ð²ã´Î
+};
+
+// ÆäËüº¯Êý
+
+HWND EGEAPI getHWnd(); // »ñÈ¡»æͼ´°¿Ú¾ä±ú
+HINSTANCE EGEAPI getHInstance();
+PVOID EGEAPI getProcfunc();
+int EGEAPI getGraphicsVer(); // »ñÈ¡µ±Ç°°æ±¾ ###
+float EGEAPI getfps(); // »ñÈ¡µ±Ç°Ö¡ÂÊ
+
+//Ëæ»úº¯Êý
+void EGEAPI randomize();
+unsigned int EGEAPI random(unsigned int n);
+double EGEAPI randomf();
+
+//¸ß¼¶ÊäÈ뺯Êý
+// title ¶Ô»°¿ò±êÌ⣬ text ¶Ô»°¿òÌáʾÎÄ×Ö£¬ buf½ÓÊÕÊäÈëÊý¾ÝµÄ×Ö·û´®Ö¸Õ룬 lenÖ¸³öbufµÄ×î´ó³¤¶È£¬Ò²Í¬Ê±»áÏÞÖÆÊäÈëÄÚÈݳ¤¶È
+int EGEAPI inputbox_getline(LPCSTR title, LPCSTR text, LPSTR buf, int len); //µ¯³ö¶Ô»°¿ò£¬ÈÃÓû§ÊäÈ룬µ±Ç°³ÌÐòÔËÐÐÔÝÍ££¬·µ»Ø·Ç0±íʾÊäÈëÓÐЧ£¬0ΪÎÞЧ
+int EGEAPI inputbox_getline(LPCWSTR title, LPCWSTR text, LPWSTR buf, int len); //µ¯³ö¶Ô»°¿ò£¬ÈÃÓû§ÊäÈ룬µ±Ç°³ÌÐòÔËÐÐÔÝÍ££¬·µ»Ø·Ç0±íʾÊäÈëÓÐЧ£¬0ΪÎÞЧ
+
+
+//¼üÅÌ´¦Àíº¯Êý
+int EGEAPI kbmsg();
+key_msg EGEAPI getkey();
+EGE_DEPRECATE(getchEx)
+int EGEAPI getchEx(int flag);
+EGE_DEPRECATE(kbhitEx)
+int EGEAPI kbhitEx(int flag);
+int EGEAPI keystate(int key); // »ñµÃ¼üÂëΪkeyµÄ¼ü£¨¼ûkey_code_e£©ÊÇ·ñ°´Ï£¬Èç¹ûkeyʹÓÃÊó±ê°´¼üµÄ¼üÂ룬Ôò»ñµÃµÄÊÇÊó±ê¼ü״̬
+void EGEAPI flushkey(); // Çå¿Õ¼üÅÌÏûÏ¢»º³åÇø
+
+//#ifndef _GRAPH_LIB_BUILD_
+#if !defined(_INC_CONIO) && !defined(_CONIO_H_)
+#define _INC_CONIO
+#define _CONIO_H_
+int EGEAPI getch();
+int EGEAPI kbhit();
+#else
+#define getch getchEx
+#define kbhit kbhitEx
+#endif
+//#endif
+
+//Êó±ê´¦Àíº¯Êý
+int EGEAPI mousemsg(); // ¼ì²éÊÇ·ñ´æÔÚÊó±êÏûÏ¢
+mouse_msg EGEAPI getmouse(); // »ñÈ¡Ò»¸öÊó±êÏûÏ¢¡£Èç¹ûûÓУ¬¾ÍµÈ´ý
+EGE_DEPRECATE(GetMouseMsg)
+MOUSEMSG EGEAPI GetMouseMsg(); // £¨²»ÍƼöʹÓõĺ¯Êý£©»ñÈ¡Ò»¸öÊó±êÏûÏ¢¡£Èç¹ûûÓУ¬¾ÍµÈ´ý
+
+void EGEAPI flushmouse(); // Çå¿ÕÊó±êÏûÏ¢»º³åÇø
+int EGEAPI showmouse(int bShow); // ÉèÖÃÊÇ·ñÏÔʾÊó±ê
+int EGEAPI mousepos(int *x, int *y); // »ñÈ¡µ±Ç°Êó±êλÖÃ
+
+/*
+callback function define as:
+int __stdcall on_msg_key(void* param, unsigned msg, int key);
+msg: see 'enum message_event'
+key: keycode
+return zero means process this message, otherwise means pass it and then process with 'getkey' function
+*/
+//int message_addkeyhandler(void* param, LPMSG_KEY_PROC func); //ÉèÖüüÅ̻ص÷º¯Êý
+/*
+callback function define as:
+int __stdcall on_msg_mouse(void* param, unsigned msg, int key, int x, int y);
+msg: see 'enum message_event'
+key: see 'enum message_mouse', if msg==MSG_EVENT_WHELL, key is a int number that indicates the distance the wheel is rotated, expressed in multiples or divisions of WHEEL_DELTA, which is 120.
+x,y: current mouse (x, y)
+return zero means process this message, otherwise means pass it and then process with 'GetMouseMsg' function
+*/
+//int message_addmousehandler(void* param, LPMSG_MOUSE_PROC func); //ÉèÖÃÊó±ê»Øµ÷º¯Êý
+int EGEAPI SetCloseHandler(LPCALLBACK_PROC func);
+
+
+class MUSIC
+{
+public:
+ MUSIC();
+ virtual ~MUSIC();
+ operator HWND()const{return (HWND)m_dwCallBack;}
+public:
+ int IsOpen() {return (m_DID != MUSIC_ERROR) ? 1 : 0;}
+ DWORD OpenFile(LPCSTR filepath);
+ DWORD OpenFile(LPCWSTR filepath);
+ DWORD Play(DWORD dwFrom=MUSIC_ERROR, DWORD dwTo=MUSIC_ERROR);
+ DWORD Pause();
+ DWORD Seek(DWORD dwTo); //²¥·ÅλÖö¨Î»£¬µ¥Î»Îªms
+ DWORD SetVolume(float value);
+ DWORD Close();
+ DWORD Stop();
+ DWORD GetPosition();
+ DWORD GetLength();
+ // ÒÔϺ¯ÊýGetPlayStatusµÄ·µ»ØֵΪÒÔÏÂÖ®Ò»£¨ÒâÒå¿´ºó׺£©£º
+ // MUSIC_MODE_NOT_OPEN //ûÓÐÕýÈ·´ò¿ª
+ // MUSIC_MODE_NOT_READY //É豸û׼±¸ºÃ £¨½ÏÉÙʹÓã©
+ // MUSIC_MODE_PAUSE //ÔÝÍ£ÖÐ
+ // MUSIC_MODE_PLAY //ÕýÔÚ²¥·Å
+ // MUSIC_MODE_STOP //³É¹¦´ò¿ªºó£¬»òÕß²¥·ÅÍêÊÇÕâ¸ö״̬
+ // MUSIC_MODE_OPEN //´ò¿ªÖÐ £¨½ÏÉÙʹÓã©
+ // MUSIC_MODE_SEEK //¶¨Î»ÖÐ £¨½ÏÉÙʹÓã©
+ DWORD GetPlayStatus();
+private:
+ DWORD m_DID;
+ PVOID m_dwCallBack;
+};
+
+/* ѹËõº¯Êý */
+ /* ѹËõʱdest»º³åÇøÒª±£Ö¤×îС´óСΪsourceLen * 1.001 + 16 */
+ /* µ÷ÓÃcompress/compress2Ç°£¬*destLen±ØÐëÓÐÖµ£¬±íʾdest»º³åÇøµÄ×î´ó´óС£¬·µ»ØʱÕâ¸öÖµ±íʾʵ¼Ê´óС */
+ /* compress2 µÄlevel ´Ó0-9£¬0²»Ñ¹Ëõ£¬9×î´óѹËõ£¬compressº¯ÊýʹÓÃĬÈÏÖµ6 */
+int EGEAPI ege_compress(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen);
+int EGEAPI ege_compress2(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen, int level);
+int EGEAPI ege_uncompress(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen);
+unsigned long EGEAPI ege_uncompress_size(const void *source, unsigned long sourceLen); /* ·µ»Ø0±íʾ´íÎó£¬ÆäËü±íʾ´óС */
+
+} // namespace ege
+
+#ifndef _GRAPH_LIB_BUILD_
+
+#if defined(_MSC_VER) && (defined(HIDE_CONSOLE) || !defined(SHOW_CONSOLE))
+#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )
+#endif
+
+#define Sleep(ms) delay_ms(ms)
+
+#endif
+
+#if !defined(_MSC_VER)
+#define WinMain(...) WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
+#elif defined(_CONSOLE)
+#if (_MSC_VER > 1200)
+#define WinMain(...) main(int argc, char* argv[])
+#else
+#define WinMain main
+#endif
+#endif
+
+#endif
diff --git a/tetris_ai/gamemode.h b/tetris_ai/gamemode.h
new file mode 100644
index 0000000..7eb5350
--- /dev/null
+++ b/tetris_ai/gamemode.h
@@ -0,0 +1,408 @@
+#pragma once
+
+
+#ifndef XP_RELEASE
+
+std::vector genNext(std::vector val, AI::Random& rnd) {
+ for ( size_t i = 0; i < val.size(); ++i) {
+ //int i = rnd.randint(val.size()); {
+ int a = max(2, abs(val[i]) / 2);
+ a = rnd.randint(a + 1);
+ if ( rnd.randint(2) ) {
+ val[i] += a;
+ } else {
+ val[i] -= a;
+ }
+ }
+ return val;
+}
+
+std::vector genNext2(std::vector val1, std::vector val2, int out, AI::Random& rnd) {
+ for ( size_t i = 0; i < val1.size(); ++i) {
+ double center = (val2[i] + val1[i]) / 2.0;
+ double diff = abs(val2[i] - val1[i]) / 2.0;
+ if ( diff < 4 ) diff = rnd.randint(5);
+ double a = 0, b = 0;
+ if ( out ) a = (rnd.randfloat() * diff * 4);
+ else a = (rnd.randfloat() * diff * 2);
+ if ( out ) b = fabs(rnd.randfloat() * val1[i] / 10);
+ if ( rnd.randint(2) ) a = -a, b = -b;
+ val1[i] = (int)floor( center + a + b + 0.5 );
+ }
+ return val1;
+}
+
+class EvE {
+ struct ai_info {
+ AI::AI_Param ai;
+ int score;
+ ai_info () {
+ memset(&ai, 0, sizeof(ai));
+ score = -1;
+ }
+ ai_info( const AI::AI_Param& _ai ) : ai(_ai) {
+ score = -1;
+ }
+ bool operator < (const ai_info& info) const {
+ return score < info.score;
+ }
+ };
+public:
+ EvE() {
+ round = TRAINING_ROUND;
+ nround = 0;
+ state_find_best = false;
+ find_best = false;
+ //find_best = true;
+ m_init = false;
+ }
+ void init(std::deque _ai) {
+ ai = _ai;
+ state_find_best = false;
+ find_best = false;
+ //find_best = true;
+ m_init = false;
+ }
+ ai_info gen(ai_info param, AI::Random& rnd) {
+ std::vector v;
+ int n = sizeof(param) / sizeof(int);
+ for ( int i = 0; i < n; ++i ) {
+ v.push_back(((int*)¶m.ai)[i]);
+ }
+ v = genNext(v, rnd);
+ for ( int i = 0; i < n; ++i ) {
+
+ ((int*)¶m.ai)[i] = v[i];
+ }
+ param.score = -1;
+ return param;
+ }
+ ai_info gen2(ai_info param1, ai_info param2, int out, AI::Random& rnd) {
+ std::vector v1;
+ std::vector v2;
+ int n = sizeof(AI::AI_Param) / sizeof(int);
+ for ( int i = 0; i < n; ++i ) {
+ v1.push_back(((int*)¶m1.ai)[i]);
+ v2.push_back(((int*)¶m2.ai)[i]);
+ }
+ v1 = genNext2(v1, v2, out, rnd);
+ for ( int i = 0; i < n; ++i ) {
+ if ( v1[i] > 99 ) v1[i] = 99; // TODO
+ if ( v1[i] < -99 ) v1[i] = -99;
+
+ ((int*)¶m1.ai)[i] = v1[i];
+ }
+ param1.score = -1;
+ return param1;
+ }
+ bool loadResult(char filename[] = "param.txt") {
+ FILE * fp = fopen(filename, "r");
+ if ( fp ) {
+ int n = sizeof(AI::AI_Param) / sizeof(int);
+ ai.clear();
+ for ( size_t i = 0; ; ++i ) {
+ while ( i >= ai.size() ) {
+ ai_info p;
+ ai.push_back(p);
+ }
+ for ( int j = 0; j < n; ++j ) {
+ fscanf(fp, "%d,", ((int*)&ai[i].ai) + j);
+ }
+ fscanf(fp, "%d", &ai[i].score);
+ if ( feof( fp ) ) {
+ break;
+ }
+ }
+ ai.pop_back();
+ fclose(fp);
+ nround = ai.size() / 2;
+ if ( ai.size() > 0 )
+ return true;
+ else
+ return false;
+ } else {
+ return false;
+ }
+ }
+ void saveResult(char filename[] = "param.txt", bool append = false) {
+ FILE * fp = fopen(filename, (append ? "a": "w") );
+ if ( fp ) {
+ int n = sizeof(AI::AI_Param) / sizeof(int);
+ for ( auto v: ai) {
+ for ( int i = 0; i < n; ++i ) {
+ fprintf(fp, "%4d,", ((int*)&v.ai)[i]);
+ }
+ fprintf(fp, "%4d", v.score);
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, "\n");
+ fclose(fp);
+ }
+ }
+ void newgame(AI::AI_Param& p1, AI::AI_Param& p2, AI::Random& rnd) {
+ if ( --nround < 0 ) {
+ nround = ai.size() / 2;
+ std::random_shuffle( ai.begin(), ai.end() );
+ }
+ /*
+ if ( ai.size() <= 4 ) {
+ saveResult("good.txt");
+ while ( ai.size() < 20 ) {
+ int g = rnd.randint(3);
+ if ( g < 2 ) {
+ int i = rnd.randint(ai.size()-1);
+ ai.push_front( gen2(ai[i], ai[ai.size()-1], g, rnd) );
+ } else {
+ ai.push_front( gen(ai[ai.size()-1], rnd) );
+ }
+ auto it = ai.begin();
+ ++it;
+ std::random_shuffle( it, ai.end() );
+ }
+ } // */
+ /*
+ for ( size_t i = 0; i < ai.size(); ++i ) {
+ if ( ai[0].score == -1 ) break;
+ ai.push_back(ai.front());
+ ai.pop_front();
+ }
+ if ( ai[0].score != -1 ) {
+ std::sort(ai.begin(), ai.end());
+ while ( ai.size() > 5 ) ai.pop_front();
+ saveResult("good.txt");
+ std::vector next;
+ for ( size_t i = 0; i < ai.size(); ++i) {
+ ai[i].score = -1;
+ }
+ for ( size_t i = 0; i < ai.size(); ++i) {
+ for ( size_t j = i + 1; j < ai.size(); ++j) {
+ next.push_back( gen2(ai[i], ai[j], 0, rnd) );
+ next.push_back( gen2(ai[i], ai[j], 1, rnd) );
+ }
+ }
+ for ( auto v: ai) {
+ for ( int i = 0; i < 1; ++ i) {
+ next.push_back( gen(v, rnd) );
+ }
+ }
+ for ( auto v: next) {
+ ai.push_back(v);
+ }
+ for ( size_t i = 0; i < ai.size(); ++i ) {
+ if ( ai[0].score == -1 ) break;
+ ai.push_back(ai.front());
+ ai.pop_front();
+ }
+ }
+ // */
+ //*
+ volatile int ai_size = ai.size();
+ while ( ai_size <= (AI_TRAINING_DEEP == 0 ? AI_TRAINING_0 : AI_TRAINING_2) ) {
+ if ( !find_best ) {
+ best_ai = ai;
+ ai_size = ai.size();
+ }
+ if ( find_best && best_ai.empty() ) {
+ saveResult("good.txt", true);
+ state_find_best = true;
+ best_ai = ai;
+ }
+ if ( !find_best || ai.size() == 1 )
+ {
+ saveResult("best.txt", true);
+ state_find_best = false;
+ ai = best_ai;
+ ai_size = best_ai.size();
+ best_ai.clear();
+
+ std::vector next;
+ int ai_cur_size = ai_size;
+ for ( int i = 0; i < ai_cur_size; ++i) {
+ ai[i].score = -1;
+ for ( int j = i + 1; j < ai_cur_size; ++j) {
+ next.push_back( gen2(ai[i], ai[j], 0, rnd) );
+ next.push_back( gen2(ai[i], ai[j], 1, rnd) );
+ ai_size += 2;
+ }
+ }
+ for ( auto v: ai) {
+ for ( int i = 0; i < 0; ++ i) {
+ next.push_back( gen(v, rnd) );
+ ai_size += 1;
+ }
+ }
+
+ if ( ai.size() == 1 ) {
+ for ( auto v: ai) {
+ for ( int i = 0; i < AI_TRAINING_0; ++ i) {
+ next.push_back( gen(v, rnd) );
+ ai_size += 1;
+ }
+ }
+ }
+
+
+ for ( auto v: next) {
+ ai.push_back(v);
+ }
+ std::random_shuffle( ai.begin(), ai.end() );
+ nround = ai_size / 2;
+ }
+ if ( find_best ) break;
+ }
+ // */
+ p1 = ai[0].ai;
+ p2 = ai[1].ai;
+ //p2 = ai[0].ai;
+ m_p1 = m_p2 = 0;
+ m_p1_score = 0;
+ m_p2_score = 0;
+ m_p2_sqr_score = 0;
+ m_p2_last_pieces = 0;
+ m_p2_att_val = 0;
+ m_p2_seed.clear();
+ for ( int i = 0; i < round; ++i) {
+ m_p2_seed.push_back(rnd.rand());
+ }
+ saveResult();
+ }
+ void result(int p1_win, int p1_score, int p2_win, int p2_score) {
+ ai[0].score = p1_score;
+ ai[1].score = p2_score;
+ if ( !state_find_best && abs(p1_win - p2_win) < (p1_win + p2_win) / 3 ) {
+ ai.push_back(ai.front());
+ ai.pop_front();
+ ai.push_back(ai.front());
+ ai.pop_front();
+ } else if ( p1_win > p2_win ) {
+ ai.push_back(ai.front());
+ ai.pop_front();
+ ai.pop_front();
+ } else if ( p1_win < p2_win ) {
+ ai.pop_front();
+ ai.push_back(ai.front());
+ ai.pop_front();
+ }
+ }
+ void result(int score) {
+ ai[0].score = score;
+ ai.push_back(ai.front());
+ ai.pop_front();
+ }
+ void game(TetrisGame& p1, TetrisGame& p2, AI::Random& rnd) {
+ /*
+ if ( !m_init || !p2.alive() ) {
+ if ( m_init ) {
+ m_p2++;
+ m_p2_score += p2.total_atts;
+ m_p2_sqr_score += p2.total_atts * p2.total_atts;
+ if ( m_p2 >= round ) {
+ double d = 0;
+ d = m_p2_score / (double)m_p2;
+ d *= d;
+ d = m_p2_sqr_score / (double)m_p2 - d;
+ result( int(m_p2_score - sqrt(d) * m_p2) );
+ newgame( p1.m_ai_param, p2.m_ai_param, rnd );
+ }
+ } else {
+ newgame( p1.m_ai_param, p2.m_ai_param, rnd );
+ }
+ p2.reset( m_p2_seed[m_p2] );
+ m_init = true;
+ } else {
+ if ( p2.n_pieces != m_p2_last_pieces ) {
+ m_p2_last_pieces = p2.n_pieces;
+ if ( p2.total_atts < 7 ) {
+ m_p2_att_val += 20;
+ } else if ( p2.total_atts < 11 ) {
+ m_p2_att_val += 20;
+ } else if ( p2.total_atts < 14 ) {
+ m_p2_att_val += 15;
+ } else {
+ m_p2_att_val += 10;
+ }
+ //if ( std::binary_search(attmap, &attmap[23], m_p2_last_pieces) ) {
+ //if ( m_p2_last_pieces % 12 == 0 ) {
+ {
+ if ( p2.total_atts < 7 ) {
+ if ( m_p2_att_val >= 120 * 4 ) {
+ m_p2_att_val -= 120 * 4;
+ p2.acceptAttack ( 3 );
+ }
+ } else {
+ if ( m_p2_att_val >= 120 * 3 ) {
+ m_p2_att_val -= 120 * 3;
+ p2.acceptAttack ( 2 );
+ }
+ }
+ }
+ }
+ }
+ // */
+ //*
+ if ( !m_init ) {
+ newgame( p1.m_ai_param, p2.m_ai_param, rnd );
+ m_init = true;
+ }
+ if ( !p1.alive() || !p2.alive() ) {
+ if ( p1.total_clears > 0 ) {
+ m_p1_score += p1.total_atts * 1000 / p1.total_clears;
+ }
+ if ( p2.total_clears > 0 ) {
+ m_p2_score += p2.total_atts * 1000 / p2.total_clears;
+ }
+ if ( false && p1.total_atts != p2.total_atts ) {
+ if ( p1.total_atts > p2.total_atts ) m_p1++;
+ else m_p2++;
+ } else {
+ if ( p1.alive() ) m_p1++;
+ else m_p2++;
+ }
+
+ if ( (m_p1 + m_p2) % 2 == 0) {
+ if ( m_p1 >= round || m_p2 >= round
+ || m_p1 >= 10 && (m_p1 + 1) / (m_p2 + 1) > 1
+ || m_p2 >= 10 && (m_p2 + 1) / (m_p1 + 1) > 1
+ || abs(m_p1 - m_p2) > round / 3
+ || min(m_p1, m_p2) > round - round / 3
+ ) {
+ result(m_p1, m_p1_score / (m_p1 + m_p2), m_p2, m_p2_score / (m_p1 + m_p2));
+ newgame(p1.m_ai_param, p2.m_ai_param, rnd);
+ }
+ }
+ {
+ unsigned seed = rnd.rand();
+ p1.reset(seed);
+ p2.reset(seed);
+ int pass = rnd.randint( 1024 );
+ for ( int i = 0; i < pass; ++i ) {
+ p1.m_rand.rand();
+ p2.m_rand.rand();
+ }
+ void onGameStart(TetrisGame& tetris, AI::Random& rnd, int index);
+ onGameStart(p1, rnd, 0);
+ onGameStart(p2, rnd, 1);
+ }
+ std::swap(m_p1, m_p2);
+ std::swap(m_p1_score, m_p2_score);
+ std::swap(p1.m_ai_param, p2.m_ai_param);
+ std::swap(p1.n_win, p2.n_win);
+ }
+ // */
+ }
+ volatile int state_find_best;
+ volatile bool find_best;
+ bool m_init;
+ std::deque ai;
+ std::deque best_ai;
+ int round;
+ int nround;
+ int m_p1, m_p2;
+ std::vector m_p2_seed;
+ int m_p1_score;
+ int m_p2_score;
+ int m_p2_sqr_score;
+ int m_p2_last_pieces;
+ int m_p2_att_val;
+};
+#endif
diff --git a/tetris_ai/gamepool.cpp b/tetris_ai/gamepool.cpp
new file mode 100644
index 0000000..75515fd
--- /dev/null
+++ b/tetris_ai/gamepool.cpp
@@ -0,0 +1,42 @@
+#include "gamepool.h"
+#include "random.h"
+
+namespace AI {
+ uint64 hashmap[AI_POOL_MAX_H][32];
+ uint64 qhashmap[AI_POOL_MAX_H][2][32];
+
+ struct initobj {
+ initobj() {
+ void InitHashTable();
+ InitHashTable();
+ }
+ } _init_obj;
+ void InitHashTable() {
+ Random rnd;
+ for ( int y = 0; y < AI_POOL_MAX_H; ++y) {
+ for ( int x = 0; x < 32; ++x) {
+ hashmap[y][x] = ((AI::uint64)rnd.rand() << 32) | rnd.rand();
+ }
+ for ( int x = 0; x < 2; ++x) {
+ for ( int i = 0; i < 32; ++i) {
+ uint64 val = 0;
+ for ( int b = 0; b < 5; ++b ) {
+ if ( i & ( 1 << b ) ) val ^= hashmap[y][x*5+b];
+ }
+ qhashmap[y][x][i] = val;
+ }
+ }
+ }
+ }
+
+ uint64 hash(const GameField & pool) {
+ uint64 ret = 0;
+ for ( int y = AI_POOL_MAX_H - 1; y >= 0; --y ) {
+ if ( pool.m_row[y] == 0 ) break;
+ ret ^= qhashmap[y][0][pool.m_row[y] & 31];
+ ret ^= qhashmap[y][1][(pool.m_row[y] >> 5) & 31];
+ }
+ return ret;
+ }
+
+}
\ No newline at end of file
diff --git a/tetris_ai/gamepool.h b/tetris_ai/gamepool.h
new file mode 100644
index 0000000..c30ee70
--- /dev/null
+++ b/tetris_ai/gamepool.h
@@ -0,0 +1,335 @@
+#pragma once
+#define _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH
+
+#include
+#include "tetris_gem.h"
+#ifdef XP_RELEASE
+#define AI_POOL_MAX_H 50
+#else
+#define AI_POOL_MAX_H 32
+#endif
+
+namespace AI {
+ struct GameField;
+ Gem& getGem( int number, int spin );
+ int getComboAttack( int combo );
+ void setAllSpin(bool allSpin);
+ bool isEnableAllSpin();
+ void setSoftdrop( bool softdrop );
+ bool softdropEnable();
+ typedef __int64 uint64;
+ void InitHashTable();
+ uint64 hash(const GameField & pool);
+#ifdef XP_RELEASE
+ const int gem_add_y = 20;
+#else
+ const int gem_add_y = 6;
+#endif
+ const int gem_beg_x = 3;
+ const int gem_beg_y = 1;
+
+ struct GameField {
+ signed char m_w, m_h;
+ signed short combo;
+ signed char b2b;
+ unsigned long m_w_mask;
+ unsigned long m_row[AI_POOL_MAX_H];
+ int m_hold;
+ int m_pc_att;
+ uint64 hashval;
+ unsigned long *row;
+ GameField () {
+ row = &m_row[gem_add_y];
+ }
+ GameField ( const GameField& field ) {
+ row = &m_row[gem_add_y];
+ *this = field;
+ }
+ GameField (signed char w, signed char h) {
+ row = &m_row[gem_add_y];
+ reset(w, h);
+ }
+ int width() const { return m_w; }
+ int height() const { return m_h; }
+ void reset (signed char w, signed char h) {
+ m_w = w;
+ m_h = h;
+ combo = 0;
+ b2b = 0;
+ m_hold = 0;
+#ifdef XP_RELEASE
+ m_pc_att = 6;
+#else
+ m_pc_att = 10;
+#endif
+ m_w_mask = ( 1 << w ) - 1;
+ for (int i = 0; i < AI_POOL_MAX_H; ++i) {
+ m_row[i] = 0;
+ }
+ for (int i = gem_add_y + m_h + 1; i < AI_POOL_MAX_H; ++i) {
+ m_row[i] = (unsigned)-1;
+ }
+ }
+ GameField& operator = (const GameField& field) {
+ memcpy( this, &field, (size_t)&row - (size_t)this );
+ row = m_row + ( field.row - field.m_row );
+ return *this;
+ }
+ bool operator == (const GameField& field) const {
+ if ( m_w != field.m_w || m_h != field.m_h ) return false;
+ if ( m_hold != field.m_hold ) return false;
+ if ( combo != field.combo ) return false;
+ if ( b2b != field.b2b ) return false;
+ if ( row - m_row != field.row - field.m_row ) return false;
+ for ( int i = 0; i <= m_h + gem_add_y; ++i ) {
+ if ( m_row[i] != field.m_row[i] ) return false;
+ }
+ return true;
+ }
+ //__forceinline
+ inline
+ bool isCollide(int y, const Gem & gem) const {
+ for ( int h = 3; h >= 0; --h ) {
+ if ( y + h > m_h && gem.bitmap[h] ) return true;
+ if ( row[y + h] & gem.bitmap[h] ) return true;
+ }
+ return false;
+ }
+ //__forceinline
+ inline
+ bool isCollide(int x, int y, const Gem & gem) const {
+ Gem _gem = gem;
+ for ( int h = 0; h < 4; ++h ) {
+ if ( x < 0 ) {
+ if (gem.bitmap[h] & ( ( 1 << (-x) ) - 1 ) ) return true;
+ _gem.bitmap[h] >>= -x;
+ } else {
+ if ( (gem.bitmap[h] << x) & ~m_w_mask ) return true;
+ _gem.bitmap[h] <<= x;
+ }
+ if ( y + h > m_h && _gem.bitmap[h] ) return true;
+ if ( row[y + h] & _gem.bitmap[h] ) return true;
+ }
+ return false; //isCollide(y, _gem);
+ }
+ bool wallkickTest(int& x, int& y, const Gem & gem, int spinclockwise) const {
+ static int Iwallkickdata[4][2][4][2] = {
+ { // O
+ { // R
+ { 2, 0},{-1, 0},{ 2,-1},{-1, 2},
+ },
+ { // L
+ { 1, 0},{-2, 0},{ 1, 2},{-2,-1},
+ },
+ },
+ { // L
+ { // O
+ {-1, 0},{ 2, 0},{-1,-2},{ 2, 1},
+ },
+ { // 2
+ { 2, 0},{-1, 0},{ 2,-1},{-1, 2},
+ },
+ },
+ { // 2
+ { // L
+ {-2, 0},{ 1, 0},{-2, 1},{ 1,-2},
+ },
+ { // R
+ {-1, 0},{ 2, 0},{-1,-2},{ 2, 1},
+ },
+ },
+ { // R
+ { // 2
+ { 1, 0},{-2, 0},{ 1, 2},{-2,-1},
+ },
+ { // O
+ {-2, 0},{ 1, 0},{-2, 1},{ 1,-2},
+ },
+ },
+ };
+ static int wallkickdata[4][2][4][2] = {
+ { // O
+ { // R
+ { 1, 0},{ 1, 1},{ 0,-2},{ 1,-2},
+ },
+ { // L
+ {-1, 0},{-1, 1},{ 0,-2},{-1,-2},
+ },
+ },
+ { // L
+ { // O
+ { 1, 0},{ 1,-1},{ 0, 2},{ 1, 2},
+ },
+ { // 2
+ { 1, 0},{ 1,-1},{ 0, 2},{ 1, 2},
+ },
+ },
+ { // 2
+ { // L
+ {-1, 0},{-1, 1},{ 0,-2},{-1,-2},
+ },
+ { // R
+ { 1, 0},{ 1, 1},{ 0,-2},{ 1,-2},
+ },
+ },
+ { // R
+ { // 2
+ {-1, 0},{-1,-1},{ 0, 2},{-1, 2},
+ },
+ { // O
+ {-1, 0},{-1,-1},{ 0, 2},{-1, 2},
+ },
+ },
+ };
+ int (*pdata)[2][4][2] = wallkickdata;
+ if ( gem.num == 1 ) pdata = Iwallkickdata;
+ for ( int itest = 0; itest < 4; ++itest) {
+ int dx = x + pdata[gem.spin][spinclockwise][itest][0];
+ int dy = y + pdata[gem.spin][spinclockwise][itest][1];
+ if ( ! isCollide(dx, dy, gem) ) {
+ x = dx; y = dy;
+ return true;
+ }
+ }
+ return false;
+ }
+ void paste(int x, int y, const Gem & gem) {
+ for ( int h = 0; h < gem.geth(); ++h ) {
+ if (x >= 0)
+ row[y + h] |= gem.bitmap[h] << x;
+ else
+ row[y + h] |= gem.bitmap[h] >> (-x);
+ }
+ }
+ signed char isWallKickSpin(int x, int y, const Gem & gem) const {
+ if ( isEnableAllSpin() ) {
+ if ( isCollide( x - 1, y, gem )
+ && isCollide( x + 1, y, gem )
+ && isCollide( x, y - 1, gem )) {
+ return 1;
+ }
+ } else {
+ if ( gem.num == 2 ) { //T
+ int cnt = 0;
+ if ( x < 0 || (row[y] & (1 << x))) ++cnt;
+ if ( x < 0 || y+2 > m_h || (row[y+2] & (1 << x))) ++cnt;
+ if ( x+2 >= m_w || (row[y] & (1 << (x+2)))) ++cnt;
+ if ( x+2 >= m_w || y+2 > m_h || (row[y+2] & (1 << (x+2)))) ++cnt;
+ if ( cnt >= 3 ) return 1;
+ }
+ }
+ return 0;
+ }
+ signed char WallKickValue(int gem_num, int x, int y, int spin, signed char wallkick_spin) const {
+ if ( ! isWallKickSpin( x, y, getGem(gem_num, spin) ) ) {
+ return wallkick_spin = 0;
+ }
+ if ( isEnableAllSpin() ) {
+ if ( wallkick_spin == 2) {
+ wallkick_spin = 1;
+ Gem g = getGem(gem_num, spin);
+ for ( int dy = 0; dy < 4; ++dy ) { //KOS mini test
+ if ( g.bitmap[dy] == 0 ) continue;
+ if ( ((g.bitmap[dy] << x) | row[y+dy]) == m_w_mask ) continue;
+ wallkick_spin = 2;
+ break;
+ }
+ }
+ } else {
+ if ( wallkick_spin == 2 ) {
+ if ( ! isCollide( x, y, getGem(gem_num, spin^2) ) ) {
+ wallkick_spin = 1; // not t-mini
+ }
+ }
+ }
+ return wallkick_spin;
+ }
+ int clearLines( signed char _wallkick_spin ) {
+ int clearnum = 0;
+ int h2 = m_h;
+ for (int h = m_h; h >= -gem_add_y; --h) {
+ if ( row[h] != m_w_mask) {
+ row[h2--] = row[h];
+ } else {
+ ++ clearnum;
+ }
+ }
+ for (int h = h2; h >= -gem_add_y; --h) {
+ row[h] = 0;
+ }
+ if ( clearnum > 0 ) {
+ ++combo;
+ if ( clearnum == 4 ) {
+ ++b2b;
+ } else if ( _wallkick_spin > 0 ) {
+ ++b2b;
+ } else {
+ b2b = 0;
+ }
+ } else {
+ combo = 0;
+ }
+ hashval = hash(*this);
+ return clearnum;
+ }
+ int getPCAttack() const {
+ return m_pc_att;
+ }
+ int getAttack( int clearfull, signed char wallkick ) {
+ int attack = 0;
+ if ( clearfull > 1 ) {
+ if ( clearfull < 4 ) {
+ attack = clearfull - 1;
+ } else {
+ attack = clearfull;
+ if ( b2b > 1 ) attack += 1;
+ }
+ }
+ if ( clearfull > 0 ) {
+ if ( wallkick ) {
+ if ( isEnableAllSpin() ) {
+ attack += clearfull + 1;
+ if ( wallkick == 2 ) { // mini
+ attack -= 1; // mini minus
+ }
+ } else {
+ if ( b2b > 1 ) attack += 1;
+ if ( clearfull == 1 ) {
+ if ( wallkick == 2 ) { // mini
+ attack += 1;
+ } else {
+ attack += 2;
+ }
+ } else {
+ attack += clearfull + 1;
+ }
+ if ( clearfull == 3 ) {
+ if ( b2b > 1 ) attack += 1;
+ }
+ }
+ }
+ attack += getComboAttack( combo );
+ {
+ int i = gem_add_y + m_h;
+ for ( ; i >= 0; --i ) {
+ if ( m_row[i] ) break;
+ }
+ if ( i < 0 ) {
+ attack += m_pc_att; // pc
+ }
+ }
+ }
+ return attack;
+ }
+ void addRow( int rowdata ) {
+ for ( int h = -gem_add_y + 1; h <= m_h; ++h ) {
+ row[h-1] = row[h];
+ }
+ row[m_h] = rowdata;
+ }
+ void minusRow( int lines ) {
+ //row += lines;
+ //m_h -= lines;
+ }
+ };
+}
diff --git a/tetris_ai/genmove.cpp b/tetris_ai/genmove.cpp
new file mode 100644
index 0000000..3d3169c
--- /dev/null
+++ b/tetris_ai/genmove.cpp
@@ -0,0 +1,715 @@
+#include "tetris_ai.h"
+#include
+#define USING_MOV_D 0
+#define GENMOV_W_MASK 15
+#define SWITCH_USING_HEIGHT_OPT
+
+#define _MACRO_CREATE_MOVINGSIMPLE(arg_action_name,arg_wkspin) \
+ MovingSimple nm = m; \
+ nm.x = nx; \
+ nm.y = ny; \
+ nm.spin = ns; \
+ nm.lastmove = Moving::##arg_action_name##; \
+ nm.wallkick_spin = arg_wkspin
+
+#define _MACRO_CREATE_MOVING(arg_action_name,arg_wkspin) \
+ Moving nm = m; \
+ nm.x = nx; \
+ nm.y = ny; \
+ nm.spin = ns; \
+ nm.movs.push_back(Moving::##arg_action_name##); \
+ nm.wallkick_spin = arg_wkspin
+#define _MACRO_HASH_POS(arg_hash_table,arg_prefix) \
+ arg_hash_table[##arg_prefix##y][##arg_prefix##s][##arg_prefix##x & GENMOV_W_MASK]
+
+namespace AI {
+ bool g_spin180 = false;
+ std::vector g_combo_attack;
+ bool g_allSpin = false;
+ bool g_softdrop = true;
+ //bool g_softdrop = false;
+
+ void setSpin180( bool enable ) {
+ g_spin180 = enable;
+ }
+ bool spin180Enable() {
+ return g_spin180;
+ }
+
+ void setComboList( std::vector combolist ) {
+ g_combo_attack = combolist;
+ }
+ int getComboAttack( int combo ) {
+ if ( g_combo_attack.empty() ) return 0;
+ if ( combo >= (int)g_combo_attack.size() ) return g_combo_attack.back();
+ return g_combo_attack[combo];
+ }
+ void setAllSpin(bool allSpin) {
+ g_allSpin = allSpin;
+ }
+ bool isEnableAllSpin() {
+ return g_allSpin;
+ }
+ void setSoftdrop( bool softdrop ) {
+ g_softdrop = softdrop;
+ }
+ bool softdropEnable() {
+ return g_softdrop;
+ }
+ //enum {
+ // MOV_SCORE_DROP = 1,
+ // MOV_SCORE_LR = 10,
+ // MOV_SCORE_LR2 = 19,
+ // MOV_SCORE_LLRR = 100,
+ // MOV_SCORE_D = 1000,
+ // MOV_SCORE_DD = 3000,
+ // MOV_SCORE_SPIN = 20,
+ //};
+ enum {
+ MOV_SCORE_DROP = 1,
+ MOV_SCORE_LR = 80,
+ MOV_SCORE_LR2 = 200,
+ MOV_SCORE_LLRR = 100,
+ MOV_SCORE_D = 1000,
+ MOV_SCORE_DD = 3000,
+ MOV_SCORE_SPIN = 150,
+ };
+
+ void GenMoving(const GameField& field, std::vector & movs, Gem cur, int x, int y, bool hold) {
+ assert( cur.num != 0 );
+ movs.clear();
+ if ( field.isCollide(x, y, getGem(cur.num, cur.spin) ) ) {
+ return ;
+ }
+ //if ( field.isCollide(x, y + 1, getGem(cur.num, cur.spin) ) ) {
+ // return ;
+ //}
+ char _hash[64][4][GENMOV_W_MASK+1] = {0};
+ char _hash_drop[64][4][GENMOV_W_MASK+1] = {0};
+ char (*hash)[4][GENMOV_W_MASK+1] = &_hash[gem_add_y];
+ char (*hash_drop)[4][GENMOV_W_MASK+1] = &_hash_drop[gem_add_y];
+ MovList q(1024);
+
+#ifdef SWITCH_USING_HEIGHT_OPT
+ // height of every column
+ int field_w = field.width(), field_h = field.height();
+ int min_y[32] = {0};
+ {
+ int beg_y = -5;
+ while ( field.row[beg_y] == 0 ) ++beg_y;
+ for ( int x = 0; x < field_w; ++x ) {
+ for ( int y = beg_y, ey = field_h + 1; y <= ey; ++y ) {
+ if ( field.row[y] & ( 1 << x ) ) {
+ min_y[x] = y;
+ break;
+ }
+ }
+ }
+ }
+#endif
+ if ( 1 || field.row[y+3] & field.m_w_mask ) // ·Ç¿ÕÆøÐеĻ°
+ {
+ MovingSimple m;
+ m.x = x;
+ m.y = y;
+ m.spin = cur.spin;
+ m.wallkick_spin = 0;
+ if ( hold ) {
+ m.lastmove = MovingSimple::MOV_HOLD;
+ m.hold = true;
+ } else {
+ m.lastmove = MovingSimple::MOV_NULL;
+ m.hold = false;
+ }
+ q.push(m);
+ hash[m.y][m.spin][m.x & GENMOV_W_MASK] = 1;
+ }
+ else
+ {
+ for ( int spin = 0; spin < 4; ++spin )
+ {
+ int ns = (cur.spin + spin) % cur.mod;
+ int dx = 0;
+ for ( ; ; ++dx )
+ {
+ MovingSimple m;
+ int nx = x + dx, ny = y;
+ if ( field.isCollide(nx, ny, getGem(cur.num, ns) ) )
+ break;
+ m.x = nx;
+ m.y = ny;
+ m.spin = ns;
+ m.wallkick_spin = 0;
+ int dist_min = 0x7fffffff;
+ for ( int x = 0; x < 4; ++x ) {
+ if ( getGemColH(cur.num, ns, x) ) { // 0 = empty column
+ int dist_cur_col = min_y[nx + x] - (ny + getGemColH(cur.num, ns, x));
+ if ( dist_cur_col < dist_min ) {
+ dist_min = dist_cur_col;
+ }
+ }
+ }
+ if ( dist_min < 0 ) { // underground
+ while ( ! field.isCollide(nx, ny + 1, getGem(cur.num, ns) ) ) {
+ if ( !USING_MOV_D && (_MACRO_HASH_POS(hash,n) & 1) == 0) {
+ _MACRO_HASH_POS(hash,n) |= 1;
+ }
+ ++ny; //wallkick_spin = 0;
+ }
+ } else { // under the sun
+ ny = ny + dist_min;
+ //if ( dist_min > 0 ) wallkick_spin = 0;
+ //for ( int y = m.y + 1; y < ny; ++y ) {
+ // if ( !USING_MOV_D && (hash[y][ns][nx & GENMOV_W_MASK] & 1) == 0) {
+ // hash[y][ns][nx & GENMOV_W_MASK] |= 1;
+ // }
+ //}
+ }
+ m.y = ny;
+ m.lastmove = MovingSimple::MOV_NULL;
+ if ( hold ) {
+ m.hold = true;
+ } else {
+ m.hold = false;
+ }
+ q.push(m);
+ _MACRO_HASH_POS(hash,n) = 1;
+ //hash[ny][ns][nx & GENMOV_W_MASK] |= 1;
+ }
+ if ( dx > 0 )
+ for ( dx = -1; ; --dx )
+ {
+ MovingSimple m;
+ int nx = x + dx, ny = y;
+ if ( field.isCollide(nx, ny, getGem(cur.num, ns) ) )
+ break;
+ m.x = nx;
+ m.y = y;
+ m.spin = ns;
+ m.wallkick_spin = 0;
+ int dist_min = 0x7fffffff;
+ for ( int x = 0; x < 4; ++x ) {
+ if ( getGemColH(cur.num, ns, x) ) { // 0 = empty column
+ int dist_cur_col = min_y[nx + x] - (ny + getGemColH(cur.num, ns, x));
+ if ( dist_cur_col < dist_min ) {
+ dist_min = dist_cur_col;
+ }
+ }
+ }
+ if ( dist_min < 0 ) { // underground
+ while ( ! field.isCollide(nx, ny + 1, getGem(cur.num, ns) ) ) {
+ if ( !USING_MOV_D && (_MACRO_HASH_POS(hash,n) & 1) == 0) {
+ _MACRO_HASH_POS(hash,n) = 1;
+ }
+ ++ny; //wallkick_spin = 0;
+ }
+ } else { // under the sun
+ ny = ny + dist_min;
+ //if ( dist_min > 0 ) wallkick_spin = 0;
+ //for ( int y = m.y + 1; y < ny; ++y ) {
+ // if ( !USING_MOV_D && (hash[y][ns][nx & GENMOV_W_MASK] & 1) == 0) {
+ // hash[y][ns][nx & GENMOV_W_MASK] |= 1;
+ // }
+ //}
+ }
+ m.y = ny;
+ m.lastmove = MovingSimple::MOV_NULL;
+ if ( hold ) {
+ m.hold = true;
+ } else {
+ m.hold = false;
+ }
+ q.push(m);
+ _MACRO_HASH_POS(hash,n) = 1;
+ //hash[ny][ns][nx & GENMOV_W_MASK] |= 1;
+ }
+ }
+ }
+ while ( ! q.empty() ) {
+ MovingSimple m;
+ q.pop(m);
+ //if ( m.y < -1 ) continue;
+ if ( m.lastmove == MovingSimple::MOV_DROP ) {
+ if ( getGemMaxH(cur.num, m.spin) + m.y <= 2 ) //lockout
+ continue;
+ movs.push_back(m);
+ continue;
+ }
+
+ if ( m.lastmove != MovingSimple::MOV_DD && m.lastmove != MovingSimple::MOV_D )
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ int wallkick_spin = m.wallkick_spin;
+#ifndef SWITCH_USING_HEIGHT_OPT
+ while ( field.row[ny + cur.geth()] == 0 && ny + cur.geth() <= field.height() ) { // ·Ç¿ÕÆøÐвÅÄÜʹÓõÄÓÅ»¯
+ ++ny; wallkick_spin = 0;
+ }
+ while ( ! field.isCollide(nx, ny + 1, getGem(cur.num, ns) ) ) {
+ if ( !USING_MOV_D && ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ _MACRO_HASH_POS(hash, n) |= 1;
+ }
+ ++ny; wallkick_spin = 0;
+ }
+#endif
+#ifdef SWITCH_USING_HEIGHT_OPT
+ {
+ int dist_min = 0x7fffffff;
+ for ( int x = 0; x < 4; ++x ) {
+ if ( getGemColH(cur.num, ns, x) ) { // 0 = empty column
+ int dist_cur_col = min_y[nx + x] - (ny + getGemColH(cur.num, ns, x));
+ if ( dist_cur_col < dist_min ) {
+ dist_min = dist_cur_col;
+ }
+ }
+ }
+ if ( dist_min < 0 ) { // underground
+ while ( ! field.isCollide(nx, ny + 1, getGem(cur.num, ns) ) ) {
+ if ( !USING_MOV_D && (_MACRO_HASH_POS(hash,n) & 1) == 0) {
+ _MACRO_HASH_POS(hash,n) |= 1;
+ }
+ ++ny; wallkick_spin = 0;
+ }
+ } else { // under the sun
+ ny = ny + dist_min;
+ if ( dist_min > 0 ) wallkick_spin = 0;
+ for ( int y = m.y + 1; y < ny; ++y ) {
+ if ( !USING_MOV_D && (hash[y][ns][nx & GENMOV_W_MASK] & 1) == 0) {
+ hash[y][ns][nx & GENMOV_W_MASK] |= 1;
+ }
+ }
+ }
+ }
+#endif
+ {
+ int v_spin = (isEnableAllSpin() || cur.num == GEMTYPE_T) ? wallkick_spin : 0;
+ if ( (_MACRO_HASH_POS(hash_drop, n) & ( 1 << v_spin)) == 0 )
+ {
+
+ int _nx = nx, _ny = ny, _ns = ns;
+
+ //if ( cur.num == GEMTYPE_I || cur.num == GEMTYPE_Z || cur.num == GEMTYPE_S ) {
+ // if ( ns == 2 ) {
+ // _ny = ny + 1;
+ // _ns = 0;
+ // }
+ // if ( ns == 3 ) {
+ // _nx = nx + 1;
+ // _ns = 1;
+ // }
+ //}
+
+ //if ( (_MACRO_HASH_POS(hash_drop, _n) & ( 1 << v_spin)) == 0 )
+ {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_DROP, v_spin);
+ _MACRO_HASH_POS(hash_drop, _n) |= 1 << v_spin;
+ q.push(nm);
+ }
+ }
+ if ( softdropEnable() ) // DD
+ {
+ if ( ny != y ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_DD, 0);
+ _MACRO_HASH_POS(hash, n) |= 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ --nx;
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_L, 0);
+ _MACRO_HASH_POS(hash, n) |= 1;
+ q.push(nm);
+ if ( m.lastmove != MovingSimple::MOV_L && m.lastmove != MovingSimple::MOV_R
+ && m.lastmove != MovingSimple::MOV_LL && m.lastmove != MovingSimple::MOV_RR )
+ {
+ int nx = m.x - 1, ny = m.y, ns = m.spin;
+ while ( ! field.isCollide(nx - 1, ny, getGem(cur.num, ns) ) ) {
+ --nx;
+ }
+ if ( nx != x && ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_LL, 0);
+ _MACRO_HASH_POS(hash, n) |= 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ ++nx;
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_R, 0);
+ _MACRO_HASH_POS(hash, n) |= 1;
+ q.push(nm);
+ if ( m.lastmove != MovingSimple::MOV_L && m.lastmove != MovingSimple::MOV_R
+ && m.lastmove != MovingSimple::MOV_LL && m.lastmove != MovingSimple::MOV_RR )
+ {
+ int nx = m.x + 1, ny = m.y, ns = m.spin;
+ while ( ! field.isCollide(nx + 1, ny, getGem(cur.num, ns) ) ) {
+ ++nx;
+ }
+ if ( nx != x && ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_RR, 0);
+ _MACRO_HASH_POS(hash, n) |= 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+#if USING_MOV_D > 0
+ if ( m.lastmove != MovingSimple::MOV_DD )
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ ++ny;
+ MovingSimple nm = m;
+ while ( field.row[ny + cur.geth()] == 0 && ny + cur.geth() <= field.height() ) { // ·Ç¿ÕÆøÐвÅÄÜʹÓõÄÓÅ»¯
+ ++ny;
+ nm.lastmove = MovingSimple::MOV_D;
+ }
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_D, 0);
+ _MACRO_HASH_POS(hash, n) |= 1;
+ q.push(nm);
+ }
+ }
+ }
+#endif
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 1) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( (isEnableAllSpin() || cur.num == GEMTYPE_T) ) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & ( 1 << 1 ) ) == 0 ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_LSPIN, 1);
+ _MACRO_HASH_POS(hash, n) |= 1 << 1;
+ q.push(nm);
+ }
+ } else if ( field.wallkickTest(nx, ny, getGem(cur.num, ns), 0 ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & ( 1 << 2 ) ) == 0 ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_LSPIN, 2);
+ _MACRO_HASH_POS(hash, n) |= 1 << 2;
+ q.push(nm);
+ }
+ }
+ } else {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) )
+ || field.wallkickTest(nx, ny, getGem(cur.num, ns), 0 ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0 ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_LSPIN, 0);
+ _MACRO_HASH_POS(hash, n) |= 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 3) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( (isEnableAllSpin() || cur.num == GEMTYPE_T) ) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & ( 1 << 1 ) ) == 0 ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_RSPIN, 1);
+ _MACRO_HASH_POS(hash, n) |= 1 << 1;
+ q.push(nm);
+ }
+ } else if ( field.wallkickTest(nx, ny, getGem(cur.num, ns), 1 ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & ( 1 << 2 ) ) == 0 ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_RSPIN, 2);
+ _MACRO_HASH_POS(hash, n) |= 1 << 2;
+ q.push(nm);
+ }
+ }
+ } else {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) )
+ || field.wallkickTest(nx, ny, getGem(cur.num, ns), 1 ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0 ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_RSPIN, 0);
+ _MACRO_HASH_POS(hash, n) |= 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ if ( spin180Enable() && m.lastmove != MovingSimple::MOV_SPIN2 ) // no 180 wallkick only
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 2) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVINGSIMPLE(MOV_SPIN2, 1);
+ _MACRO_HASH_POS(hash, n) |= 1;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void FindPathMoving(const GameField& field, std::vector & movs, Gem cur, int x, int y, bool hold) {
+ movs.clear();
+ if ( field.isCollide(x, y, getGem(cur.num, cur.spin) ) ) {
+ return ;
+ }
+ char _hash[64][4][GENMOV_W_MASK+1] = {0};
+ char _hash_drop[64][4][GENMOV_W_MASK+1] = {0};
+ char (*hash)[4][GENMOV_W_MASK+1] = &_hash[gem_add_y];
+ char (*hash_drop)[4][GENMOV_W_MASK+1] = &_hash_drop[gem_add_y];
+ MovQueue q(1024);
+ {
+ Moving m;
+ m.x = x;
+ m.y = y;
+ m.spin = cur.spin;
+ m.wallkick_spin = 0;
+ if ( hold ) {
+ m.movs.push_back(Moving::MOV_HOLD);
+ } else {
+ m.movs.push_back(Moving::MOV_NULL);
+ }
+ m.score = 0;
+ q.push(m);
+ //hash[m.y][m.spin][m.x & GENMOV_W_MASK] = 1;
+ }
+ while ( ! q.empty() ) {
+ Moving m;
+ q.pop(m);
+ if ( m.movs.back() == Moving::MOV_DROP) {
+ movs.push_back(m);
+ continue;
+ }
+ {
+ if ( (isEnableAllSpin() || cur.num == GEMTYPE_T) ) {
+ if ( hash[m.y][m.spin][m.x & GENMOV_W_MASK] & ( 1 << m.wallkick_spin ) )
+ continue;
+ hash[m.y][m.spin][m.x & GENMOV_W_MASK] |= 1 << m.wallkick_spin;
+ } else {
+ if ( hash[m.y][m.spin][m.x & GENMOV_W_MASK] & 1 )
+ continue;
+ hash[m.y][m.spin][m.x & GENMOV_W_MASK] |= 1;
+ }
+ }
+
+ if ( m.movs.back() != Moving::MOV_DD && m.movs.back() != Moving::MOV_D)
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ int wallkick_spin = m.wallkick_spin;
+ //while ( field.row[ny + cur.geth()] == 0 && ny + cur.geth() <= field.height() ) { // ·Ç¿ÕÆøÐвÅÄÜʹÓõÄÓÅ»¯
+ // ++ny; wallkick_spin = 0;
+ //}
+ while ( ! field.isCollide(nx, ny + 1, getGem(cur.num, ns) ) ) {
+ //if ( !USING_MOV_D && ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ // _MACRO_HASH_POS(hash, n) |= 1;
+ //}
+ ++ny; wallkick_spin = 0;
+ }
+ {
+ int v_spin = (isEnableAllSpin() || cur.num == GEMTYPE_T) ? wallkick_spin : 0;
+ if ( (_MACRO_HASH_POS(hash_drop, n) & ( 1 << v_spin )) == 0 )
+ {
+ int _nx = nx, _ny = ny, _ns = ns;
+ //if ( (_MACRO_HASH_POS(hash_drop, _n) & ( 1 << v_spin)) == 0 )
+ {
+ _MACRO_CREATE_MOVING(MOV_DROP, v_spin);
+ _MACRO_HASH_POS(hash_drop, _n) |= 1 << v_spin;
+ q.push(nm);
+ }
+ }
+ if ( softdropEnable() ) {
+ if ( ny != y ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ _MACRO_CREATE_MOVING(MOV_DD, 0);
+ //_MACRO_HASH_POS(hash, n) |= 1;
+ nm.score += MOV_SCORE_DD - nm.movs.size();
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ --nx;
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVING(MOV_L, 0);
+ //_MACRO_HASH_POS(hash, n) = 1;
+ if ( m.movs.back() != Moving::MOV_L )
+ nm.score += MOV_SCORE_LR;
+ else
+ nm.score += MOV_SCORE_LR2;
+ q.push(nm);
+ if ( m.movs.back() != Moving::MOV_L && m.movs.back() != Moving::MOV_R
+ && m.movs.back() != Moving::MOV_LL && m.movs.back() != Moving::MOV_RR )
+ {
+ int nx = m.x - 1, ny = m.y, ns = m.spin;
+ while ( ! field.isCollide(nx - 1, ny, getGem(cur.num, ns) ) ) {
+ --nx;
+ }
+ if ( nx != x && ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ _MACRO_CREATE_MOVING(MOV_LL, 0);
+ //_MACRO_HASH_POS(hash, n) |= 1;
+ nm.score += MOV_SCORE_LLRR;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ ++nx;
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVING(MOV_R, 0);
+ //_MACRO_HASH_POS(hash, n) |= 1;
+ if ( m.movs.back() != Moving::MOV_R )
+ nm.score += MOV_SCORE_LR;
+ else
+ nm.score += MOV_SCORE_LR2;
+ q.push(nm);
+ if ( m.movs.back() != Moving::MOV_L && m.movs.back() != Moving::MOV_R
+ && m.movs.back() != Moving::MOV_LL && m.movs.back() != Moving::MOV_RR )
+ {
+ int nx = m.x + 1, ny = m.y, ns = m.spin;
+ while ( ! field.isCollide(nx + 1, ny, getGem(cur.num, ns) ) ) {
+ ++nx;
+ }
+ if ( nx != x && ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ _MACRO_CREATE_MOVING(MOV_RR, 0);
+ //_MACRO_HASH_POS(hash, n) |= 1;
+ nm.score += MOV_SCORE_LLRR;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ //if (USING_MOV_D)
+ if ( m.movs.back() != Moving::MOV_DD )
+ {
+ int nx = m.x, ny = m.y, ns = m.spin;
+ ++ny;
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVING(MOV_D, 0);
+ //_MACRO_HASH_POS(hash, n) |= 1;
+ nm.score += MOV_SCORE_D;
+ q.push(nm);
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 1) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( (isEnableAllSpin() || cur.num == GEMTYPE_T) ) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & ( 1 << 1 ) ) == 0 ) {
+ _MACRO_CREATE_MOVING(MOV_LSPIN, 1);
+ //_MACRO_HASH_POS(hash, n) |= 1 << 1;
+ if ( m.movs.back() != Moving::MOV_LSPIN )
+ nm.score += MOV_SCORE_LR;
+ else
+ nm.score += MOV_SCORE_SPIN;
+ q.push(nm);
+ }
+ } else if ( field.wallkickTest(nx, ny, getGem(cur.num, ns), 0 ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & ( 1 << 2 ) ) == 0 ) {
+ _MACRO_CREATE_MOVING(MOV_LSPIN, 2);
+ //_MACRO_HASH_POS(hash, n) |= 1 << 2;
+ if ( m.movs.back() != Moving::MOV_LSPIN )
+ nm.score += MOV_SCORE_LR;
+ else
+ nm.score += MOV_SCORE_SPIN;
+ q.push(nm);
+ }
+ }
+ } else {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) )
+ || field.wallkickTest(nx, ny, getGem(cur.num, ns), 0 ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0 ) {
+ _MACRO_CREATE_MOVING(MOV_LSPIN, 0);
+ //_MACRO_HASH_POS(hash, n) |= 1;
+ if ( m.movs.back() != Moving::MOV_LSPIN )
+ nm.score += MOV_SCORE_LR;
+ else
+ nm.score += MOV_SCORE_SPIN;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 3) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( (isEnableAllSpin() || cur.num == GEMTYPE_T) ) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & ( 1 << 1 ) ) == 0 ) {
+ _MACRO_CREATE_MOVING(MOV_RSPIN, 1);
+ //_MACRO_HASH_POS(hash, n) |= 1 << 1;
+ if ( m.movs.back() != Moving::MOV_RSPIN )
+ nm.score += MOV_SCORE_LR;
+ else
+ nm.score += MOV_SCORE_SPIN;
+ q.push(nm);
+ }
+ } else if ( field.wallkickTest(nx, ny, getGem(cur.num, ns), 1 ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & ( 1 << 2 ) ) == 0 ) {
+ _MACRO_CREATE_MOVING(MOV_RSPIN, 2);
+ //_MACRO_HASH_POS(hash, n) |= 1 << 2;
+ if ( m.movs.back() != Moving::MOV_RSPIN )
+ nm.score += MOV_SCORE_LR;
+ else
+ nm.score += MOV_SCORE_SPIN;
+ q.push(nm);
+ }
+ }
+ } else {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) )
+ || field.wallkickTest(nx, ny, getGem(cur.num, ns), 1 ) ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0 ) {
+ _MACRO_CREATE_MOVING(MOV_RSPIN, 0);
+ //_MACRO_HASH_POS(hash, n) |= 1;
+ if ( m.movs.back() != Moving::MOV_RSPIN )
+ nm.score += MOV_SCORE_LR;
+ else
+ nm.score += MOV_SCORE_SPIN;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ if ( spin180Enable() ) //&& m.movs.back() != Moving::MOV_SPIN2 ) // no 180 wallkick only
+ {
+ int nx = m.x, ny = m.y, ns = (m.spin + 2) % cur.mod;
+ if ( ns != m.spin ) {
+ if ( ( _MACRO_HASH_POS(hash, n) & 1 ) == 0) {
+ if ( ! field.isCollide(nx, ny, getGem(cur.num, ns) ) ) {
+ _MACRO_CREATE_MOVING(MOV_SPIN2, 1);
+ //_MACRO_HASH_POS(hash, n) |= 1;
+ if ( m.movs.back() != Moving::MOV_SPIN2 )
+ nm.score += MOV_SCORE_LR;
+ else
+ nm.score += MOV_SCORE_SPIN;
+ q.push(nm);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tetris_ai/graphics.h b/tetris_ai/graphics.h
new file mode 100644
index 0000000..e0feb86
--- /dev/null
+++ b/tetris_ai/graphics.h
@@ -0,0 +1,46 @@
+/*********************************************************
+* EGE (Easy Graphics Engine)
+* FileName graphics.h
+* HomePage1 http://misakamm.github.com/xege
+* HomePage2 http://misakamm.bitbucket.org/index.htm
+* HomePage3 http://tcgraphics.sourceforge.net
+* teiba1 http://tieba.baidu.com/f?kw=ege
+* teiba2 http://tieba.baidu.com/f?kw=ege%C4%EF
+* Blog: http://misakamm.com
+* E-Mail: mailto:misakamm[at gmail com]
+*
+* FileName: graphics.h
+* ÔÚ VC ÏÂÄ£Äâ Borland BGI »æͼ¿â£¬ÊµÏÖ¼òµ¥µÄ»æͼ֮Ó࣬À©Õ¹Á˽ϸ´ÔӵĻæͼÄÜÁ¦
+*
+* °üº¬²¢Ê¹Óñ¾¿âʱ£¬²»Òª°üº¬conio.hÍ·Îļþ
+* ÕâЩͷÎļþ²»Ó¦¹²´æ£¬·ñÔò¿ÉÄÜ»á±àÒë´íÎó£¬
+* »òÕßgetch±»conio.hÄڵĸ²¸Ç£¨ÓÉ°üº¬´ÎÐò¾ö¶¨£©£¬Çë×¢Òâ
+* ÈçÐè¹²´æ£¬ÇëʹÓöàÎļþ·Ö¿ª°üº¬µÄģʽʹÓã¬
+* ¼´²»ÄÜÒ»¸öcppͬʱ°üº¬£¬µ«¿ÉÒÔ·Ö¿ª°üº¬
+* ʹÓñ¾¿â£¬±ØÐëÓÃC++±àÒ룬¿ÉÖ§³ÖµÄ±àÒëÆ÷£º
+* VC6/VC2008/VC2010/MinGW3.4.5/MinGW4.4.1
+*********************************************************/
+
+/****************************************************************************
+** ×¢ÒâÊÂÏ
+* ¡ïÈç¹ûÐèÒªÏÔʾ¿ØÖÆ̨´°¿Ú£¬ÇëÔÚ°üº¬±¾ÎļþµÄÇ°Ãæ¼ÓÒ»ÐÐdefine SHOW_CONSOLE
+* ¡ïµ÷ÓÃSleepÕâ¸öAPIʱ£¬»òÕßµ÷ÓÃdelay£¬Êµ¼Ê¾ù»áת»¯Îªµ÷ÓÃdelay_ms£¬Èç±ØÐèµ÷ÓÃAPIÇëʹÓÃapi_sleep
+* ¡ïdelay_ms(0)ÄÜ×ÔÐÐÅжÏÓÐûÓиüеıØÒª£¬Á¬Ðø¶à´Îµ«²»´óÁ¿µÄµ÷Óò¢²»»á²úÉúÖ¡ÂʵÄÓ°Ïì
+* ¡ïµ÷ÓÃdelay_ms, delay_fps, getch, GetMouseMsg ʱ£¬´°¿ÚÄÚÈÝ¿ÉÄÜ»á¸üУ¬ÕâЩº¯ÊýÏ൱ÓÚÄÚÖÃÁËdelay_ms(0)£¬
+* Èç¹ûÄãÖ»ÐèÒª¸üд°¿Ú£¬¶ø²»ÏëµÈ´ý£¬¿ÉÒÔÓÃdelay_ms(0),Sleep(0)»òÕßdelay(0)
+* ¡ïÈç¹ûÄãʹÓÃÁËËø¶¨Ä£Ê½»æͼ£¬ÄÇ¿ÉÒÔʹÓÃWindowFlush´úÌædelay(0)£¬µ«²»ÄÜ´úÌæ·Ç0µÄdelay
+* ¡ïºÏÀíµØʹÓÃdelayº¯Êý£¬¿ÉÒÔ¼õÉÙÄãµÄ³ÌÐòÕ¼ÓõÄCPU£¬·ñÔòÒ»¸ödelay¶¼Ã»Óе÷ÓõĻ°£¬³ÌÐò½«Õ¼ÂúÒ»¸öCPUµÄʱ¼ä
+* ¡ïsetfillstyleº¯ÊýµÄ×Ô¶¨ÒåÌî³äģʽδʵÏÖ£¬µ«Ò»°ãÓ¦ÓÃ×ã¹»
+****************************************************************************/
+
+#ifndef _GRAPHICS_H_
+#define _GRAPHICS_H_
+
+#ifndef __cplusplus
+#error You must use C++ compiler, or you need filename with '.cpp' suffix
+#endif
+
+#include "ege.h"
+using namespace ege;
+
+#endif
diff --git a/tetris_ai/graphics08.lib b/tetris_ai/graphics08.lib
new file mode 100644
index 0000000..2a27e86
Binary files /dev/null and b/tetris_ai/graphics08.lib differ
diff --git a/tetris_ai/graphics12.lib b/tetris_ai/graphics12.lib
new file mode 100644
index 0000000..a630e94
Binary files /dev/null and b/tetris_ai/graphics12.lib differ
diff --git a/tetris_ai/main.cpp b/tetris_ai/main.cpp
new file mode 100644
index 0000000..b9d126f
--- /dev/null
+++ b/tetris_ai/main.cpp
@@ -0,0 +1,1499 @@
+#define _CRT_SECURE_NO_WARNINGS
+#define _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH
+
+#include "tetrisgame.h"
+#include "gamemode.h"
+
+#include "graphics.h"
+
+#include "profile.h"
+#include
+
+
+PIMAGE colorCell( int w, int h, color_t normal, color_t lt, color_t rb ) {
+ PIMAGE img;
+ img = newimage(w, h);
+ setbkcolor(normal, img);
+ setcolor(lt, img);
+ line(0, 0, w, 0, img);
+ line(0, h, 0, 0, img);
+ line(1, 1, w, 1, img);
+ line(1, 1, 1, h, img);
+ setcolor(rb, img);
+ line(w - 1, 0, w - 1, h - 1, img);
+ line(0, h - 1, w, h - 1, img);
+ line(w - 2, h - 2, w - 2, 0, img);
+ line(w - 2, h - 2, 0, h - 2, img);
+ return img;
+}
+
+/*
+float gemColor[8] = { // QQTetris
+ 0.0f,
+ 0.0f,
+ 300.0f,
+ 90.0f,
+ 180.0f,
+ 60.0f,
+ 210.0f,
+ 140.0f,
+};
+/*/
+float gemColor[8] = { // TOP
+ 0.0f,
+ 180.0f,
+ 300.0f,
+ 30.0f,
+ 210.0f,
+ 0.0f,
+ 140.0f,
+ 60.0f,
+};
+//*/
+
+float gemColorS = 0.7f;
+
+void tetris_draw_next(const TetrisGame& tetris, PIMAGE* gem) {
+ setcolor(EGERGB(0x40, 0xa0, 0x40));
+ for ( int i = 1; i <= 1; ++i ) {
+ int bx = int(tetris.m_base.x + 5);
+ int by = int(tetris.m_base.y + tetris.m_size.y * 1);
+ rectangle(bx - i,
+ by - i,
+ int(bx + tetris.m_size.x * 4) + i,
+ int(by + tetris.m_size.y * 3) + i
+ );
+ }
+ outtextxy(int(tetris.m_base.x + 5), int(tetris.m_base.y), "HOLD");
+ if ( tetris.m_pool.m_hold > 0 ) {
+ AI::Gem hold = AI::getGem( tetris.m_pool.m_hold, 0 );
+ for ( int y = 0; y < 4; ++y) {
+ for ( int x = 0; x < 4; ++x) {
+ if ( hold.bitmap[y] & ( 1 << x ) ) {
+ int bx = int(tetris.m_base.x + 5 + tetris.m_size.x * x);
+ int by = int(tetris.m_base.y + tetris.m_size.y * (y + 1));
+ if ( tetris.m_pool.m_hold > 1 && tetris.m_pool.m_hold < 7 ) {
+ bx += int(tetris.m_size.x / 2);
+ }
+ if ( tetris.m_pool.m_hold > 1 ) {
+ by += int(tetris.m_size.y / 2);
+ }
+ putimage(bx, by, gem[tetris.m_pool.m_hold]);
+ }
+ }
+ }
+ }
+ setcolor(EGERGB(0x40, 0x40, 0xff));
+ xyprintf(int(tetris.m_base.x + tetris.m_size.x * (tetris.poolw() + 5) + tetris.m_size.x / 2), int(tetris.m_base.y),
+ "NEXT %3d", (tetris.n_pieces - (tetris.m_pool.m_hold == AI::GEMTYPE_NULL)) - 1);
+ for ( int i = 1; i <= 1; ++i ) {
+ int bx = int(tetris.m_base.x + tetris.m_size.x * (tetris.poolw() + 5) + tetris.m_size.x / 2);
+ int by = int(tetris.m_base.y + tetris.m_size.y * 1 );
+ rectangle(bx - i,
+ by - i,
+ int(bx + tetris.m_size.x * 4) + i,
+ int(by + tetris.m_size.y * 3 * DISPLAY_NEXT_NUM) + i
+ );
+ }
+ for ( int n = 0; n < DISPLAY_NEXT_NUM; ++n) {
+ for ( int y = 0; y < 4; ++y) {
+ for ( int x = 0; x < 4; ++x) {
+ if (tetris.getNextGemCell(n, x, y)) {
+ int bx = int(tetris.m_base.x + tetris.m_size.x * (tetris.poolw() + 5) + tetris.m_size.x * x + tetris.m_size.x / 2);
+ int by = int(tetris.m_base.y + tetris.m_size.y * (y + 1 + n * 3));
+ if ( tetris.m_next[n].num > 1 && tetris.m_next[n].num < 7 ) {
+ bx += int(tetris.m_size.x / 2);
+ }
+ if ( tetris.m_next[n].num > 1 ) {
+ by += int(tetris.m_size.y / 2);
+ }
+ putimage(bx, by, gem[tetris.m_next[n].num]);
+ }
+ }
+ }
+ }
+}
+
+void tetris_draw(const TetrisGame& tetris, bool showAttackLine, bool showGrid) {
+ static PIMAGE pool_gem[9] = {0}, pool_gem_dark[9] = {0};
+ PIMAGE* gem = pool_gem_dark;
+ if ( pool_gem[1] == NULL ) {
+ for ( int i = 1; i < 8; ++i ) {
+ pool_gem[i] = colorCell((int)tetris.m_size.x, (int)tetris.m_size.y,
+ hsv2rgb(gemColor[i], gemColorS, 0.6f),
+ hsv2rgb(gemColor[i], gemColorS, 0.9f),
+ hsv2rgb(gemColor[i], gemColorS, 0.4f));
+ }
+ pool_gem[8] = colorCell((int)tetris.m_size.x, (int)tetris.m_size.y,
+ EGERGB(0x80,0x80,0x80), EGERGB(0xb0,0xb0,0xb0), EGERGB(0x60,0x60,0x60));
+ for ( int i = 1; i < 8; ++i ) {
+ pool_gem_dark[i] = colorCell((int)tetris.m_size.x, (int)tetris.m_size.y,
+ hsv2rgb(gemColor[i], gemColorS, 0.3f),
+ hsv2rgb(gemColor[i], gemColorS, 0.45f),
+ hsv2rgb(gemColor[i], gemColorS, 0.2f));
+ }
+ pool_gem_dark[8] = colorCell((int)tetris.m_size.x, (int)tetris.m_size.y,
+ EGERGB(0x40,0x40,0x40), EGERGB(0x50,0x50,0x50), EGERGB(0x30,0x30,0x30));
+ }
+ setbkmode(TRANSPARENT);
+ tetris_draw_next(tetris, pool_gem);
+ if ( tetris.alive() ) {
+ gem = pool_gem;
+ }
+ int base_y = int(tetris.m_base.y - tetris.m_size.y);
+ int min_y[32];
+ if ( showGrid ) {
+ setcolor(EGERGB(0x20, 0x20, 0x20));
+ for ( int x = 1; x < tetris.poolw(); ++x) {
+ int bx = int(tetris.m_base.x + tetris.m_size.x * (x + 5));
+ int by = int(base_y + tetris.m_size.y * 3);
+ line_f( bx, by - 5, bx, by + (int)(tetris.m_size.y * (tetris.poolh() - 2)) );
+ line_f( bx-1, by - 5, bx-1, by + (int)(tetris.m_size.y * (tetris.poolh() - 2)) );
+ }
+ for ( int y = 3; y <= tetris.poolh(); ++y) {
+ int bx = int(tetris.m_base.x + tetris.m_size.x * (5));
+ int by = int(base_y + tetris.m_size.y * y);
+ line_f( bx, by, bx + (int)(tetris.m_size.x * tetris.poolw()), by);
+ line_f( bx, by-1, bx + (int)(tetris.m_size.x * tetris.poolw()), by-1);
+ }
+ }
+ for ( int x = 0; x < tetris.poolw(); ++x) {
+ min_y[x] = tetris.poolh() + 1;
+ for ( int y = 0; y <= tetris.poolh(); ++y) {
+ if (tetris.getPoolCell(x, y)) {
+ int bx = int(tetris.m_base.x + tetris.m_size.x * (x + 5));
+ int by = int(base_y + tetris.m_size.y * y);
+ if ( y == 2 ) putimage(bx, by + (int)tetris.m_size.y - 5, (int)tetris.m_size.x, 5, gem[tetris.getPoolCell(x, y)], 0, (int)tetris.m_size.y - 5);
+ else if ( y > 2 ) putimage(bx, by, gem[tetris.getPoolCell(x, y)]);
+ min_y[x] = min( min_y[x], y );
+ }
+ }
+ }
+
+ setcolor(EGERGB(0xa0, 0x0, 0x80));
+ for ( int i = 1; i <= 3; ++i ) {
+ rectangle(int(tetris.m_base.x + tetris.m_size.x * (5)) - i,
+ int(tetris.m_base.y + tetris.m_size.y * 2) - 5 - i,
+ int(tetris.m_base.x + tetris.m_size.x * (tetris.poolw() + 5)) + i,
+ int(tetris.m_base.y + tetris.m_size.y * (tetris.poolh())) + i
+ );
+ }
+
+ if ( tetris.alive() && tetris.m_cur.num ) {
+ int dy = 0;
+ if ( ! tetris.m_pool.isCollide( tetris.m_cur_x, tetris.m_cur_y + dy, tetris.m_cur ) ) {
+ while ( ! tetris.m_pool.isCollide( tetris.m_cur_x, tetris.m_cur_y + dy + 1, tetris.m_cur ) ) {
+ ++dy;
+ }
+ }
+ if ( dy > 0 ) {
+ //setlinewidth(3);
+ setfillcolor( hsv2rgb(gemColor[tetris.m_cur.num], gemColorS, 0.6f) );
+ //setcolor(EGERGB(0xcf, 0x4f, 0xcf));
+ for ( int y = 0; y < 4; ++y) {
+ for ( int x = 0; x < 4; ++x) {
+ if ( y + dy + tetris.cury() <= 2 ) continue;
+ if (tetris.getCurGemCell(x, y)) {
+ int bx = int(tetris.m_base.x + tetris.m_size.x * (x + tetris.curx() + 5));
+ int by = int(base_y + tetris.m_size.y * (y + dy + tetris.cury()));
+ int bw = tetris.m_size.x;
+ int bh = tetris.m_size.y;
+ //putimage(bx, by, pool_gem_dark[tetris.m_cur.num]);
+ if ( x == 0 || tetris.getCurGemCell(x-1, y) == 0 ) { //L
+ bar( bx, by, bx + 3, by + bh );
+ }
+ if ( y == 0 || tetris.getCurGemCell(x, y-1) == 0 ) { //T
+ bar( bx, by, bx + bw, by + 3 );
+ }
+ if ( x == 3 || tetris.getCurGemCell(x+1, y) == 0 ) { //R
+ bar( bx + bw - 3, by, bx + bw, by + bh );
+ }
+ if ( y == 3 || tetris.getCurGemCell(x, y+1) == 0 ) { //B
+ bar( bx, by + bh - 3, bx + bw, by + bh);
+ }
+ bar( bx, by, bx + 3, by + 3 );
+ bar( bx + bw - 3, by, bx + bw, by + 3 );
+ bar( bx + bw - 3, by + bh - 3, bx + bw, by + bh );
+ bar( bx, by + bh - 3, bx + 3, by + bh );
+ }
+ }
+ }
+ //setlinewidth(1);
+ }
+ }
+
+ for ( int y = 0; y < 4; ++y) {
+ for ( int x = 0; x < 4; ++x) {
+ if ( tetris.cury() + y <= 1 ) continue;
+ if ( tetris.getCurGemCell(x, y) ) {
+ int bx = int(tetris.m_base.x + tetris.m_size.x * (x + tetris.curx() + 5));
+ int by = int(base_y + tetris.m_size.y * (y + tetris.cury()));
+ if ( tetris.cury() + y == 2 ) {
+ putimage(bx, by + (int)tetris.m_size.y - 5, (int)tetris.m_size.x, 5, pool_gem[tetris.m_cur.num], 0, (int)tetris.m_size.y - 5);
+ } else {
+ putimage(bx, by, pool_gem[tetris.m_cur.num]);
+ }
+ }
+ }
+ }
+ if ( ! tetris.accept_atts.empty() ) {
+ int atts = 0;
+ for ( std::vector::const_iterator it = tetris.accept_atts.begin(); it != tetris.accept_atts.end(); ++it ) {
+ atts += *it;
+ }
+
+ setfillcolor(hsv2rgb(0.0f, 1.0f, 1.0f));
+ int bx = int(tetris.m_base.x + tetris.m_size.x * (4)) + tetris.m_size.x / 2;
+ int by = int(base_y + tetris.m_size.y * (tetris.poolh() + 1) );
+ bar(bx,
+ by - (int)tetris.m_size.y * atts,
+ bx + (int)tetris.m_size.x / 2,
+ by);
+ if ( showAttackLine ) {
+ setcolor (EGERGB(0x80, 0x0, 0x0));
+ setlinestyle( DOTTED_LINE );
+ int lastbx = -1, lastby = 0;
+ for ( int x = 0; x < tetris.poolw(); ++x) {
+ int y = min_y[x];
+ int bx = int(tetris.m_base.x + tetris.m_size.x * (x + 5));
+ int by = int(base_y + tetris.m_size.y * (y - atts));
+ if ( lastbx != -1 && lastby != by ) {
+ line( lastbx, lastby, bx, by);
+ }
+ line( bx, by, bx + (int)tetris.m_size.x, by);
+ lastbx = bx + (int)tetris.m_size.x;
+ lastby = by;
+ }
+ setlinestyle( SOLID_LINE );
+ }
+ }
+ {
+ setcolor (EGERGB(0xa0, 0xa0, 0xa0));
+ int combo = tetris.m_pool.combo;
+ if ( combo > 0 ) combo--;
+ //xyprintf(int(tetris.m_base.x + tetris.m_size.x * (5)), int(tetris.m_base.y + tetris.m_size.y * ( tetris.poolh() + 0 ) + 1 ),
+ // "Win %2d Att %2d Combo %d/%d/%d", tetris.n_win, tetris.total_atts, combo, tetris.m_max_combo, tetris.last_max_combo);
+ double apl = 0, app = 0, pps = 0, apm = 0;
+ if ( tetris.total_clears > 0 ) {
+ apl = double(tetris.total_atts)/tetris.total_clears;
+ }
+ if ( tetris.n_pieces > 0 ) {
+ app = double(tetris.total_atts)/tetris.n_pieces;
+ }
+ if ( tetris.m_drop_frame > 0 ) {
+ pps = (tetris.n_pieces - 1) * 60.0 / tetris.m_drop_frame;
+ }
+ if ( tetris.m_drop_frame > 0 ) {
+ apm = tetris.total_atts * 60.0 * 60.0 / tetris.m_drop_frame;
+ }
+ rectprintf(
+ //int(tetris.m_base.x + tetris.m_size.x * (5+tetris.poolw())) + 1,
+ //int(tetris.m_base.y + tetris.m_size.y * ( tetris.poolh() - 5 ) ),
+ int(tetris.m_base.x) + 2,
+ int(tetris.m_base.y + tetris.m_size.y * ( 4 ) + 1 ),
+ 200,
+ 400,
+#ifdef XP_RELEASE
+ "Win %4d\nPPS %.2f\nAPM %4.1f\nAtt %4d\nSent %3d\nRecv %3d\nAPL %.2f\nAPP %.3f\nCombo %2d\nClear %2d\nCbA %4d\nB2B %4d\nT0 %5d\nT1 %5d\nT2 %5d\nT3 %5d\n1 %6d\n2 %6d\n3 %6d\n4 %6d\n",
+ tetris.n_win, pps, apm, tetris.total_atts, tetris.total_sent, tetris.total_accept_atts, apl, app, tetris.m_max_combo,
+ tetris.m_clear_info.total_pc, tetris.m_clear_info.total_cb_att, tetris.m_clear_info.total_b2b,
+ tetris.m_clear_info.t[0], tetris.m_clear_info.t[1], tetris.m_clear_info.t[2], tetris.m_clear_info.t[3],
+ tetris.m_clear_info.normal[1], tetris.m_clear_info.normal[2], tetris.m_clear_info.normal[3],tetris.m_clear_info.normal[4]
+#else
+ "Win %4d\nPPS %.2f\nAPM %4.1f\nAtt %4d\nSent %3d\nRecv %3d\nAPL %.2f\nAPP %.3f\nCombo %2d\nClear %2d\nCbA %4d\nB2B %4d\nT0 %5d\nT1 %5d\nT2 %5d\nT3 %5d\n1 %6d\n2 %6d\n3 %6d\n4 %6d\n",
+ tetris.n_win, pps, apm, tetris.total_atts, tetris.total_sent, tetris.total_accept_atts, apl, app, tetris.m_max_combo,
+ tetris.m_clear_info.total_pc, tetris.m_clear_info.total_cb_att, tetris.m_clear_info.total_b2b,
+ tetris.m_clear_info.t[0], tetris.m_clear_info.t[1], tetris.m_clear_info.t[2], tetris.m_clear_info.t[3],
+ tetris.m_clear_info.normal[1], tetris.m_clear_info.normal[2], tetris.m_clear_info.normal[3],tetris.m_clear_info.normal[4]
+#endif
+ );
+ }
+ if ( tetris.m_clear_info.attack > 0 ) {
+ std::string info;
+ char str[128];
+ int att = tetris.m_clear_info.attack;
+ int b2b = tetris.m_clear_info.b2b > 1;
+ int combo = tetris.m_clear_info.combo;
+ int wallkick_spin = tetris.m_clear_info.wallkick_spin;
+ {
+ sprintf(str, "+%d ", att);
+ info += str;
+ }
+ att -= b2b;
+ att -= AI::getComboAttack( combo );
+ if ( tetris.m_clear_info.pc ) {
+ att -= 6;
+ }
+
+ if ( wallkick_spin ) {
+ char gemMap[] = " ITLJZSO";
+ if ( wallkick_spin == 2 && (AI::isEnableAllSpin() || tetris.m_clear_info.clears == 1) ) {
+ //if ( wallkick_spin == 2 ) {
+ sprintf(str, "%c-mini ", gemMap[tetris.m_clear_info.gem_num]);
+ info += str;
+ } else {
+ sprintf(str, "%c-spin%d ", gemMap[tetris.m_clear_info.gem_num], tetris.m_clear_info.clears);
+ info += str;
+ }
+ } else if ( tetris.m_clear_info.gem_num == 1 && tetris.m_clear_info.clears == 4 ) {
+ sprintf(str, "Quadruple ");
+ info += str;
+ } else if ( tetris.m_clear_info.clears == 3 ) {
+ sprintf(str, "Triple ");
+ info += str;
+ } else if ( tetris.m_clear_info.clears == 2 ) {
+ sprintf(str, "Double ");
+ info += str;
+ }
+ if ( b2b ) {
+ sprintf(str, "b2b ");
+ info += str;
+ }
+ if ( combo > 1 ) {
+ sprintf(str, "combo%d ", combo-1);
+ info += str;
+ }
+ if ( tetris.m_clear_info.pc ) {
+ sprintf(str, "Clear! ");
+ info += str;
+ }
+ setcolor (EGERGB(0x00, 0xA0, 0xff));
+ xyprintf(int(tetris.m_base.x + tetris.m_size.x * (5)), int(tetris.m_base.y + tetris.m_size.y * ( tetris.poolh() + 0 ) + 1 ),
+ info.c_str() );
+ tetris.m_att_info = info;
+ } else {
+ setcolor (EGERGB(0x40, 0x40, 0x40));
+ xyprintf(int(tetris.m_base.x + tetris.m_size.x * (5)), int(tetris.m_base.y + tetris.m_size.y * ( tetris.poolh() + 0 ) + 1 ),
+ tetris.m_att_info.c_str() );
+ }
+ setcolor (EGERGB(0xa0, 0xa0, 0xa0));
+ if ( ! tetris.alive() ) {
+ xyprintf(0, 0, "Press F2 to restart a new game. Press F12 to config your controls");
+ }
+ {
+ int w = textwidth(tetris.m_name.c_str());
+ if ( tetris.pTetrisAI ) setcolor(EGERGB(0xa0, 0x0, 0xff));
+ xyprintf(int(tetris.m_base.x + tetris.m_size.x * ( 5 + tetris.poolw() / 2 )) - w / 2, int(tetris.m_base.y + tetris.m_size.y * 0 ),
+ "%s", tetris.m_name.c_str() );
+ }
+}
+
+void setkeyScene( int player_keys[] ) {
+ cleardevice();
+ while ( kbmsg() ) getkey();
+ const char* name[] = {
+ "move left",
+ "move right",
+ "soft drop",
+ "counterclockwise",
+ "clockwise",
+ "hold",
+ "hard drop",
+ "180rotate",
+ };
+ int t_player_keys[16];
+ for ( int i = 0; i < 8; ++i ) {
+ for ( t_player_keys[i] = 0; is_run() && t_player_keys[i] == 0; delay_fps(60) ) {
+ if ( kbmsg() ) {
+ key_msg k = getkey();
+ if ( k.key == key_esc ) {
+ return ;
+ }
+ if ( k.msg == key_msg_down ) {
+ t_player_keys[i] = k.key;
+ }
+ }
+ cleardevice();
+ xyprintf(0, 0, "press a key for %s (ESC to cancel & return)", name[i]);
+ }
+ }
+ for ( int i = 0; i < 8; ++i ) {
+ player_keys[i] = t_player_keys[i];
+ }
+}
+
+void loadKeySetting( int player_keys[] ) {
+ FILE* fp = fopen("misamino.cfg", "r");
+ if ( fp ) {
+ for ( int i = 0; i < 8; ++i) {
+ fscanf(fp, "%d", &player_keys[i]);
+ }
+ fclose(fp);
+ }
+}
+
+void saveKeySetting( int player_keys[] ) {
+ FILE* fp = fopen("misamino.cfg", "w");
+ if ( fp ) {
+ for ( int i = 0; i < 8; ++i) {
+ fprintf(fp, " %d", player_keys[i]);
+ }
+ fprintf(fp, "\n");
+ fclose(fp);
+ }
+}
+
+void onGameStart(TetrisGame& tetris, AI::Random& rnd, int index) {
+ if ( GAMEMODE_4W ) {
+ static int hole_index;
+ for ( int j = 0; j < 39; ++j) {
+ int v = ~(15 << 3) & tetris.m_pool.m_w_mask;
+ tetris.addRow(v);
+ }
+ if ( index == 0 ) {
+ hole_index = rnd.randint(4);
+ }
+ tetris.addRow((((1 << tetris.m_pool.m_w) - 1) & ~(1<<(hole_index + AI::gem_beg_x))) & tetris.m_pool.m_w_mask);
+ }
+#if !defined( XP_RELEASE ) //|| P1_AI
+ if ( index == 0 ) tetris.addRow(15);
+ else tetris.addRow(15 << 6);
+#endif
+ if (0)
+ {
+ char n[] = "ITSOJLITZJISOTZ";
+ std::map gemMap;
+ gemMap[' '] = AI::GEMTYPE_NULL;
+ gemMap['I'] = AI::GEMTYPE_I;
+ gemMap['T'] = AI::GEMTYPE_T;
+ gemMap['L'] = AI::GEMTYPE_L;
+ gemMap['J'] = AI::GEMTYPE_J;
+ gemMap['Z'] = AI::GEMTYPE_Z;
+ gemMap['S'] = AI::GEMTYPE_S;
+ gemMap['O'] = AI::GEMTYPE_O;
+ for ( int k = 0; n[k]; ++k ) {
+ tetris.m_next[k] = AI::getGem(gemMap[n[k]], 0);
+ }
+ tetris.m_pool.m_hold = gemMap['L'];
+ }
+ if (0)
+ {
+ int m[22][10] = {
+ {0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ {1, 1, 1, 1, 1, 0, 0, 1, 1, 0},
+ {1, 1, 1, 1, 1, 0, 0, 0, 1, 0},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ };
+ for ( int j = 0; j < 22; ++j) {
+ int v = 0;
+ for ( int k = 0; k < 10; ++k ) {
+ if ( m[j][k] ) v |= 1 << k;
+ }
+ tetris.addRow(v);
+ }
+ tetris.m_next[0] = AI::getGem(AI::GEMTYPE_L, 0);
+ tetris.m_next[1] = AI::getGem(AI::GEMTYPE_Z, 0);
+ tetris.m_next[2] = AI::getGem(AI::GEMTYPE_T, 0);
+ tetris.m_next[3] = AI::getGem(AI::GEMTYPE_S, 0);
+ tetris.m_next[4] = AI::getGem(AI::GEMTYPE_I, 0);
+ }
+}
+struct tetris_ai {
+ int style;
+ int level;
+ int PieceMul;
+ std::string plugin;
+ tetris_ai() {
+ style = 2;
+ level = 4;
+ PieceMul = 0;
+ plugin = "dllai.dll";
+ }
+};
+
+struct tetris_rule {
+ int turnbase;
+ int garbage;
+ int spin180;
+ int GarbageCancel;
+ int GarbageBuffer;
+ int GarbageBlocking;
+ int combo_table_style;
+ int samesequence;
+ int turn;
+ tetris_rule() {
+ turnbase = 1;
+ garbage = 0;
+ spin180 = 0;
+ GarbageCancel = 1;
+ GarbageBuffer = 1;
+ GarbageBlocking = 1;
+ combo_table_style = 0;
+ samesequence = 1;
+ turn = 1;
+ }
+};
+struct tetris_player {
+ int tojsoftdrop;
+ int das;
+ int softdropdelay;
+ int softdropdas;
+ int sound_p1;
+ int sound_p2;
+ int sound_bgm;
+ tetris_player() {
+ tojsoftdrop = 1;
+ das = 8;
+ softdropdelay = 10;
+ softdropdas = 10;
+ sound_p1 = 1;
+ sound_p2 = 0;
+ sound_bgm = 1;
+ }
+};
+
+void loadAI(CProfile& config, tetris_ai ai[]) {
+ for ( int i = 0; i < 2; ++i ) {
+ if ( i == 0 ) config.SetSection( "AI_P1" );
+ else config.SetSection( "AI_P2" );
+ if ( config.IsInteger( "style" ) ) {
+ ai[i].style = config.ReadInteger( "style" );
+ if ( i != 0 && ai[i].style == 0 ) ai[i].style = 2;
+ }
+ if ( config.IsInteger( "level" ) ) {
+ ai[i].level = config.ReadInteger( "level" );
+ if ( ai[i].level < 0 ) ai[i].level = 0;
+ if ( ai[i].level > 10 ) ai[i].level = 10;
+ }
+ if ( config.IsInteger( "PieceMul" ) ) {
+ ai[i].PieceMul = config.ReadInteger( "PieceMul" );
+ if ( ai[i].PieceMul <= 0 ) ai[i].PieceMul = 1;
+ }
+ config.ReadString( "dllplugin", ai[i].plugin );
+ }
+}
+void loadRule(CProfile& config, tetris_rule& rule) {
+ config.SetSection( "Rule" );
+ if ( config.IsInteger( "turnbase" ) ) {
+ rule.turnbase = config.ReadInteger( "turnbase" );
+ }
+ if ( config.IsInteger( "KOS_turnbase" ) ) {
+ int kos_turnbase = config.ReadInteger( "KOS_turnbase" );
+ if ( kos_turnbase ) rule.turn = 7;
+ }
+ if ( config.IsInteger( "spin180" ) ) {
+ rule.spin180 = config.ReadInteger( "spin180" );
+ AI::setSpin180( rule.spin180 );
+ }
+ if ( config.IsInteger( "GarbageStyle" ) ) {
+ rule.garbage = config.ReadInteger( "GarbageStyle" );
+ }
+ if ( config.IsInteger( "GarbageCancel" ) ) {
+ rule.GarbageCancel = config.ReadInteger( "GarbageCancel" );
+ }
+ if ( config.IsInteger( "GarbageBuffer" ) ) {
+ rule.GarbageBuffer = config.ReadInteger( "GarbageBuffer" );
+ }
+ if ( config.IsInteger( "GarbageBlocking" ) ) {
+ rule.GarbageBlocking = config.ReadInteger( "GarbageBlocking" );
+ }
+ if ( config.IsInteger( "samesequence" ) ) {
+ rule.samesequence = config.ReadInteger( "samesequence" );
+ }
+ if ( config.IsInteger( "combo_table_style" ) ) {
+ rule.combo_table_style = config.ReadInteger( "combo_table_style" );
+ }
+}
+void loadPlayerSetting(CProfile& config, tetris_player& player) {
+ config.SetSection( "Player" );
+ if ( config.IsInteger( "tojsoftdrop" ) ) {
+ player.tojsoftdrop = config.ReadInteger( "tojsoftdrop" );
+ }
+ if ( config.IsInteger( "das" ) ) {
+ player.das = config.ReadInteger( "das" );
+ if ( player.das < 0 ) player.das = 0;
+ }
+ if ( config.IsInteger( "softdropdas" ) ) {
+ player.softdropdas = config.ReadInteger( "softdropdas" );
+ if ( player.softdropdas < 0 ) player.softdropdas = 0;
+ }
+ if ( config.IsInteger( "softdropdelay" ) ) {
+ player.softdropdelay = config.ReadInteger( "softdropdelay" );
+ if ( player.softdropdelay < 0 ) player.softdropdelay = 0;
+ }
+ config.SetSection( "Sound" );
+ if ( config.IsInteger( "p1sfx" ) ) {
+ player.sound_p1 = config.ReadInteger( "p1sfx" );
+ }
+ if ( config.IsInteger( "p2sfx" ) ) {
+ player.sound_p2 = config.ReadInteger( "p2sfx" );
+ }
+ if ( config.IsInteger( "bgm" ) ) {
+ player.sound_bgm = config.ReadInteger( "bgm" );
+ }
+}
+
+std::string getpath( std::string path ) {
+ for ( int i = path.size() - 1; path[i] != '/' && path[i] != '\\'; --i) path[i] = 0;
+ return path.c_str();
+}
+
+void mainscene() {
+ tetris_rule rule;
+ tetris_player player;
+ tetris_ai ai[2];
+ int ai_first_delay = 30;
+ int ai_move_delay = 20;
+ int ai_4w = 1;
+
+
+ bool showAttackLine = true;
+ bool showGrid = true;
+ int game_pause = 0;
+
+ CProfile config;
+#if !defined( XP_RELEASE ) || P1_AI || !PUBLIC_VERSION
+ config.SetFile( "tetris_ai.ini" );
+#else
+ config.SetFile( "misamino.ini" );
+#endif
+ if ( 0 )
+ {
+ config.SetSection( "AI" );
+ config.WriteInteger( "level", 6 );
+ config.WriteInteger( "depth", 6 );
+ config.SetSection( "Rule" );
+ config.WriteInteger( "garbage", 0 );
+ }
+ else
+ {
+ config.SetSection( "AI" );
+ if ( config.IsInteger( "delay" ) ) {
+ ai_first_delay = config.ReadInteger( "delay" );
+ if ( ai_first_delay < 0 ) ai_first_delay = 0;
+ }
+ if ( config.IsInteger( "move" ) ) {
+ ai_move_delay = config.ReadInteger( "move" );
+ if ( ai_move_delay < 0 ) ai_move_delay = 0;
+ }
+ if ( config.IsInteger( "4w" ) ) {
+ ai_4w = config.ReadInteger( "4w" );
+ }
+
+ loadAI(config, ai);
+ loadRule(config, rule);
+ loadPlayerSetting(config, player);
+
+ if ( rule.turn != 1 ) {
+ ai[0].PieceMul = ai[1].PieceMul = 1;
+ }
+ }
+
+ setfont(18, 0, "Courier New", 0, 0, 100, 0, 0, 0 );
+ int players_num = 2;
+ std::vector tetris(players_num);
+ AI::Random rnd( (unsigned) time( 0 ) );
+ int player_keys[8] = {
+ key_left,
+ key_right,
+ key_down,
+ 'Z',
+ 'C',
+ 'V',
+ key_space,
+ 'X'
+ };
+ loadKeySetting( player_keys );
+#ifndef XP_RELEASE
+ EvE eve;
+ //eve.loadResult();
+ if ( ! eve.loadResult() )
+ {
+ //std::deque _p;
+ //_p.push_back(tetris[0].m_ai_param);
+ //eve.init( _p );
+ eve.ai.push_back(tetris[0].m_ai_param);
+ }
+#endif
+#ifdef XP_RELEASE
+ int ai_eve = 0;
+ int ai_search_height_deep = DISPLAY_NEXT_NUM > 6 ? 6 : DISPLAY_NEXT_NUM;
+ int player_stratagy_mode = !AI_SHOW;
+ int mainloop_times = 1;
+ int normal_delay = 1;
+#else
+ int ai_eve = 1;
+ int ai_search_height_deep = AI_TRAINING_DEEP;
+ int player_stratagy_mode = 1;
+ int mainloop_times = ( AI_TRAINING_DEEP == 0 ? 1000 : (AI_TRAINING_SLOW ? 2 : 50) );
+ int normal_delay = 1;
+#endif
+#if AI_SHOW == 0
+ int player_accept_attack = 1;
+ int player_begin_attack = 0; //17;
+#else
+ int player_accept_attack = 0;
+ int player_begin_attack = 0; //17;
+#endif
+ //int ai_search_normal_deep = 0;
+ int ai_mov_time = ( ai_eve | (1&&ai[0].style) ?
+ (AI_TRAINING_SLOW ? 12 : 0)
+ : (
+ (AI_SHOW ) ? ( GAMEMODE_4W ? 2: 16 ) : ( PLAYER_WAIT ? 2 : 10 ) )
+ );
+ ai_mov_time /= 2; // fps=60
+ int ai_mov_time_base = 13; // ʵ¼ÊÖµÓÉai_mov_time¾ö¶¨£¬³õʼֵ²»ÓùÜ
+
+ int player_key_state[8] = {0};
+ int player_last_key = 0;
+
+ std::string game_info;
+ int game_info_time = 0;
+ tetris[0].m_name = "Human";
+ GameSound::ins().loadSFX( );
+ if ( player.sound_bgm ) GameSound::ins().loadBGM_wait( rnd );
+ if ( player.sound_p1 ) tetris[0].soundon( true );
+ if ( player.sound_p2 ) tetris[1].soundon( true );
+
+ {
+ typedef int (*AIDllVersion_t)();
+ AIDllVersion_t pAIDllVersion = NULL;
+ char path[MAX_PATH];
+ ::GetCurrentDirectoryA(MAX_PATH, path);
+ for ( int i = 0; i < players_num; ++i ) {
+ if ( ai[i].style == -1 )
+ {
+ ::SetCurrentDirectoryA( (getpath(std::string(path) + "/" + ai[i].plugin)).c_str() );
+ HMODULE hModule = ::LoadLibraryA(ai[i].plugin.c_str());
+ if ( hModule ) {
+ pAIDllVersion = (AIDllVersion_t)GetProcAddress(hModule, "AIDllVersion");
+ if ( pAIDllVersion && pAIDllVersion() == AI_DLL_VERSION ) {
+ tetris[i].pAIName = (AI::AIName_t)GetProcAddress(hModule, "AIName");
+ tetris[i].pTetrisAI = (AI::TetrisAI_t)GetProcAddress(hModule, "TetrisAI");
+ }
+ }
+ }
+ }
+ ::SetCurrentDirectoryA(path);
+ }
+
+ if ( 1 )
+ {
+ AI::AI_Param param = {
+// 47, 26, 70, 4, 46, 16, 26, 21, 7, 31, 14, 17, 69, 11, 53, 300
+
+// 33, 25, 57, 19, 37, 11, 33, 10, 9, 38, 12, 13, 63, 11, 51, 300
+// 37, 24, 50, 29, 53, 15, 26, 12, 13, 36, 11, 7, 69, 12, 53, 300
+// 36, 25, 50, 20, 55, 15, 28, 12, 15, 36, 12, 10, 70, 12, 53, 300
+
+// 40, 15, 50, 20, 56, 16, 17, 12, 7, 55, 99, 23, 78, 16, 67, 300
+// 37, 16, 51, 18, 50, 16, 32, 11, 5, 32, 99, 21, 68, 8, 41, 0 //lv1 s lv2 b
+// 26, 18, 46, 30, 53, 22, 29, 17, 9, 33, 3, 11, 84, 6, 50, -16 //lv1 b lv2 a
+// 28, 21, 57, 28, 48, 17, 18, 12, 8, 29, 17, 22, 78, 10, 65, -10 //lv2 c
+
+// 21, 20, 66, 40, 27, 22, 48, 26, 8, 71, 13, 24, 92, 7, 69, 300 // a
+// 19, 24, 99, 35, 24, 20, 52, 30, 9, 77, 13, 32, 91, 9, 69, 83 // b
+// 19, 22, 87, 37, 16, 13, 42, 19, 6, 73, 10, 33, 93, 5, 73, 83 // b+
+// 21, 24, 54, 33, 23, 24, 36, 16, 8, 70, 12, 25, 73, 8, 67, 92 // c
+// 23, 20, 66, 36, 24, 21, 46, 27, 14, 77, 15, 32, 93, 5, 67, 85 // s
+// 20, 21, 71, 35, 16, 22, 44, 20, 6, 79, 9, 28, 74, 4, 67, 82 // s
+
+// 49, 18, 76, 33, 39, 27, 32, 25, 22, 99, 41, 29, 96, 14, 60, 300 //s
+// 31, 17, 69, 32, 21, 27, 49, 24, 18, 99, 78, 28, 99, 8, 62, 91 //c
+// 52, 19, 69, 34, 35, 30, 34, 20, 17, 89, 37, 31, 83, 9, 55, 97 //c
+// 53, 16, 73, 33, 26, 28, 30, 22, 22, 79, 18, 28, 93, 5, 63, 95 //a
+// 60, 16, 72, 35, 29, 30, 41, 20, 20, 79, 55, 22, 97, 4, 60, 95 // b
+// 40, 13, 80, 37, 16, 24, 38, 19, 21, 67, 99, 24, 96, 6, 42, 83 // a
+
+// 49, 18, 76, 40, 39, 27, 32, 50, 22, 99, 0, 29, 96, 14, 60, 300 //s ogn
+
+// 45, 28, 84, 21, 35, 27, 56, 30, 9, 64, 13, 18, 97, 11, 29, 300 // cmp
+// 43, 16, 80, 20, 38, 26, 53, 30, 3, 70, -17, 19, 96, 18, 30, 300 // b
+// 40, 18, 97, 25, 39, 18, 59, 30, 4, 64, -9, 17, 97, 17, 31, 300 // b+
+// 39, 28, 94, 24, 42, 23, 56, 31, 5, 78, -8, 14, 96, 13, 33, 300 //b
+// 38, 21, 94, 28, 48, 25, 54, 34, 8, 88, -21, 19, 80, 31, 32, 300 //a
+// 43, 27, 87, 34, 50, 32, 68, 26, -10, 83, -2, 14, 89, 6, 27, 300 //a
+// 40, 20, 98, 13, 35, 22, 63, 29, 5, 68, -11, 15, 98, 14, 32, 300 //b
+
+// 48, 27, 88, 25, 34, 23, 52, 26, 3, 63, -14, 19, 34, 5, 33, 300 // a+
+// 47, 27, 92, 31, 38, 28, 52, 29, 5, 61, -6, 25, 92, 9, 33, 300 // b
+// 50, 26, 84, 29, 46, 25, 35, 29, 0, 68, -14, 17, 99, 3, 40, 300 // b-
+// 37, 30, 95, 34, 32, 26, 44, 33, 11, 56, -11, 22, 37, 12, 35, 300 // a
+// 44, 32, 96, 28, 42, 24, 49, 25, -6, 58, 17, 20, 51, 10, 32, 300 // s
+// 48, 27, 97, 22, 41, 29, 53, 27, 3, 60, -10, 19, 42, 6, 31, 300 // a+
+
+//new param
+
+// 41, 13, 99, 28, 42, 32, 47, 24, 6, 61, 19, 30, 41, 12, 27, 300 // b
+// 41, 25, 91, 28, 41, 26, 54, 31, 7, 43, 16, 35, 8, 12, 24, 300 // b
+// 35, 5, 98, 26, 43, 32, 52, 18, 16, 57, 24, 22, 38, 10, 28, 300 // b
+// 41, 13, 98, 27, 45, 24, 51, 28, 13, 65, 27, 21, 39, 13, 39, 300 // s
+// 39, 15, 99, 26, 41, 28, 50, 26, 8, 68, 23, 22, 36, 14, 28, 300 // a
+// 36, 20, 99, 27, 41, 32, 28, 24, 11, 56, 26, 24, 43, 14, 27, 300 //s
+
+//*
+// 41, 13, 99, 25, 46, 27, 49, 27, 9, 73, 23, 26, 25, 9, 42, 300 // a
+// 44, 13, 98, 31, 51, 30, 53, 27, 16, 56, 29, 27, 34, 16, 24, 300 // s
+// 39, 13, 98, 29, 30, 34, 54, 28, 18, 58, 20, 28, 35, 11, 33, 300 // s-
+// 36, 11, 90, 29, 31, 34, 52, 22, 20, 66, 26, 26, 38, 11, 30, 300 // a
+// 34, 29, 97, 35, 24, 23, 55, 27, 14, 75, 19, 41, 32, 0, 46, 300 // a
+// 39, 12, 98, 30, 32, 27, 55, 25, 15, 68, 22, 25, 30, 9, 33, 300 // s-
+//*/
+// 46, 10, 99, 86, 80, 29, 30, 24, -22, 71, 50, 36, 47, 37, 44, 83 // a
+// 74, 39, 88, 99, 57, 33, 30, 23, -14, 73, 60, 43, 58, 39, 38, 96 // a
+// 46, 38, 96, 98, 63, 37, 28, 26, -17, 69, 64, 43, 45, 42, 42, 99 // s
+// 68, 34, 99, 99, 75, 38, 33, 20, -16, 80, 56, 31, 61, 36, 43, 88
+// 42, 48, 99, 95, 63, 27, -2, 29, -22, 60, 54, 31, 57, 38, 37, 99 // b
+// 70, 30, 96, 99, 73, 41, 41, 18, -20, 82, 51, 35, 55, 50, 41, 89 // a
+// 36, 30, 71, 67, 72, 48, 22, 16, 34, 60, 0, 34, 46, 35, 16, 33 //test
+// 31, 43, 78, 80, 63, 46, 48, 14, 0, 99, 59, 24, 29, 30, 33, 7 //test2
+// 77, 42, 92, 98, 98, 28, 1, 19, -1, 75, 52, 50, 99, 27, 49, 65 //test3
+// 70, 16, 99, 50, 95, 33, 21, 29, 38, 98, 10, 54, 91, 26, 42, 65
+ 13, 9, 17, 10, 29, 25, 39, 2, 12, 19, 7, 24, 21, 16, 14, 19, 200
+
+ };
+ tetris[0].m_ai_param = param;
+ //ai_level_p1 = 4; ai_level_p2 = 4;
+ }
+ for ( int i = 0; i < players_num; ++i) {
+ if ( ai[i].level <= 0 ) {
+ AI::AI_Param param[2] = {
+// 82, 69, 99, 61, 81, 36, 35, 22, 11, 71, 21, 6, 51, 90, 37, -999
+// 21, 20, 66, 40, 27, 22, 48, 26, 8, 71, 13, 24, 92, 7, 69, 999
+// 49, 18, 76, 33, 39, 27, 32, 25, 22, 99, 41, 29, 96, 14, 60, 999
+ {
+
+// 43, 47, 84, 62, 60, 47, 53, 21, 2, 98, 85, 13, 21, 37, 38, 0
+// 47, 66, 86, 66, -79, 42, 38, 23, -3, 95, 74, 13, 27, 36, 37, 0
+// 45, 61, 99, 49, 63, 40, 42, 31, -27, 88, 80, 28, 28, 41, 33, 0
+// 58, 61, 90, 82, 19, 27, 44, 17, -4, 75, 47, 20, 38, 32, 41, 0
+ 47, 62, 94, 90, 11, 35, 48, 19, -21, 78, 64, 20, 42, 42, 39, 300
+// 48, 65, 84, 59, -75, 39, 43, 23, -17, 92, 64, 20, 29, 37, 36, 0
+
+ },
+ {
+
+// 43, 47, 84, 62, 60, 47, 53, 21, 2, 98, 85, 13, 21, 37, 38, 0
+// 47, 66, 86, 66, -79, 42, 38, 23, -3, 95, 74, 13, 27, 36, 37, 0
+// 45, 61, 99, 49, 63, 40, 42, 31, -27, 88, 80, 28, 28, 41, 33, 0 // a
+// 58, 61, 90, 82, 19, 27, 44, 17, -4, 75, 47, 20, 38, 32, 41, 0 // b
+// 47, 62, 94, 90, 11, 35, 48, 19, -21, 78, 64, 20, 42, 42, 39, 0 // s
+// 48, 65, 84, 59, -75, 39, 43, 23, -17, 92, 64, 20, 29, 37, 36, 0 // s
+ 71, 12, 78, 52, 96, 37, 14, 24, 40, 99, 44, 49, 93, 25, 44, 380
+ }
+};
+ tetris[i].m_ai_param = param[i];
+ }
+ }
+ std::string ai_name[2] = {"T-spin AI", "T-spin AI"};
+ for ( int i = 0; i < players_num; ++i) {
+ if ( ai[i].style == 1 ) {
+ ai_name[i] = "T-spin+ AI";
+ } else if ( ai[i].style == 2 ) {
+ AI::setAIsettings(i, "hash", 0);
+ //
+ } else if ( ai[i].style == 3 ) {
+ tetris[i].m_ai_param.tspin = tetris[i].m_ai_param.tspin3 = -300;
+ tetris[i].m_ai_param.clear_useless_factor *= 0.8;
+ ai_name[i] = "Ren AI";
+ } else if ( ai[i].style == 4 ) {
+ tetris[i].hold = false;
+ tetris[i].m_ai_param.clear_useless_factor *= 0.7;
+ ai_name[i] = "non-Hold";
+ // no 4w
+ tetris[i].m_ai_param.strategy_4w = 0;
+ AI::setAIsettings(i, "4w", 0);
+ } else if ( ai[i].style != -1 ) { //if ( ai[i].style == 5 ) {
+ AI::AI_Param param[2] = {
+ {49, 918, 176, 33,-300, -0, 0, 25, 22, 99, 41,-300, 0, 14, 290, 0}, // defence AI
+ {21, 920, 66, 40,-300, -2, 0, 26, 8, 71, 13,-300, 0, 7, 269, 0},
+ };
+ AI::setAIsettings(i, "combo", 0);
+ tetris[i].m_ai_param = param[i];
+ ai_name[i] = "Downstack";
+ }
+ }
+ for ( int i = 0; i < players_num; ++i) {
+ if ( ai[i].style || i > 0 )
+ {
+ char name[200];
+ sprintf( name, "%s LV%d", ai_name[i].c_str(), ai[i].level);
+ tetris[i].m_name = name;
+ }
+ if ( tetris[i].pAIName ) {
+ tetris[i].m_name = tetris[i].pAIName(ai[i].level);
+ }
+ if ( ! ai_4w || ai_eve || ai[i].level < 6 ) {
+ tetris[i].m_ai_param.strategy_4w = 0;
+ }
+ if ( tetris[i].m_ai_param.strategy_4w > 0 ) {
+ AI::setAIsettings(i, "4w", 1);
+ }
+ }
+ if ( rule.combo_table_style == 0 )
+ {
+ int a[] = {0,0,0,1,1,2};
+ AI::setComboList( std::vector(a, a + sizeof(a)/sizeof(*a)) );
+ for ( int i = 0; i < players_num; ++i) {
+ tetris[i].m_ai_param.strategy_4w = 0;
+ AI::setAIsettings(i, "4w", 0);
+ }
+ }
+ else if ( rule.combo_table_style == 1 )
+ {
+ int a[] = {0,0,0,1,1,2,2,3,3,4,4,4,5};
+ AI::setComboList( std::vector(a, a + sizeof(a)/sizeof(*a)) );
+ }
+ else if ( rule.combo_table_style == 2 )
+ {
+ int a[] = {0,0,0,1,1,1,2,2,3,3,4,4,4,5};
+ AI::setComboList( std::vector(a, a + sizeof(a)/sizeof(*a)) );
+ }
+ else
+ {
+ int a[] = {0,0,0,1,1,2};
+ AI::setComboList( std::vector(a, a + sizeof(a)/sizeof(*a)) );
+ }
+ if ( rule.GarbageBlocking == 0 || rule.GarbageBuffer == 0 || rule.GarbageCancel == 0 ) {
+ for ( int i = 0; i < players_num; ++i) {
+ tetris[i].m_ai_param.strategy_4w = 0;
+ AI::setAIsettings(i, "4w", 0);
+ }
+ }
+#ifdef XP_RELEASE
+ tetris[0].m_state = AI::Tetris::STATE_OVER;
+ tetris[1].m_state = AI::Tetris::STATE_OVER;
+#endif
+ if ( player.sound_p1 && player.sound_p2 ) {
+ tetris[0].m_lr = 1;
+ tetris[1].m_lr = 2;
+ }
+ GameSound::ins().setVolume( 0.5f );
+
+ {
+ int seed = (unsigned)time(0), pass = rnd.randint(1024);
+ for ( int i = 0; i < players_num; ++i ) {
+ tetris[i].m_base = AI::point(i * 400, 30);
+ //tetris[i].reset( seed ^ ((!rule.samesequence) * i * 255), pass );
+ //if ( ai_eve )
+ //tetris[i].reset( (unsigned)time(0) + ::GetTickCount() * i );
+ /*
+ int m[20][12] = {
+ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
+ {1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1},
+ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
+ {1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1},
+ {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ };
+ for ( int j = 0; j < 18; ++j) {
+ int v = 0;
+ for ( int k = 0; k < 12; ++k ) {
+ if ( m[j][k] ) v |= 1 << k;
+ }
+ tetris[i].addrow(v);
+ }
+ tetris[i].m_next[0] = AI::getGem(2, 0);
+ */
+ /*
+ int m[22][10] = {
+ {0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ {1, 1, 1, 1, 1, 0, 0, 1, 1, 0},
+ {1, 1, 1, 1, 1, 0, 0, 0, 1, 0},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ };
+ for ( int j = 0; j < 22; ++j) {
+ int v = 0;
+ for ( int k = 0; k < 10; ++k ) {
+ if ( m[j][k] ) v |= 1 << k;
+ }
+ tetris[i].addRow(v);
+ }
+ tetris[i].m_next[0] = AI::getGem(AI::GEMTYPE_L, 0);
+ tetris[i].m_next[1] = AI::getGem(AI::GEMTYPE_Z, 0);
+ tetris[i].m_next[2] = AI::getGem(AI::GEMTYPE_T, 0);
+ tetris[i].m_next[3] = AI::getGem(AI::GEMTYPE_S, 0);
+ tetris[i].m_next[4] = AI::getGem(AI::GEMTYPE_I, 0);
+ // */
+ //onGameStart( tetris[i], rnd, i );
+ //tetris[i].acceptAttack(player_begin_attack);
+ }
+ }
+ double ai_time = 0;
+ int lastGameState = -1;
+ for ( ; is_run() ; normal_delay ? delay_fps(60) : delay_ms(0) ) {
+ for ( int jf = 0; jf < mainloop_times; ++jf) {
+#ifndef XP_RELEASE
+ if ( AI_TRAINING_SLOW == 0 ) {
+ for ( int i = 0; i < players_num; ++i ) {
+ while ( tetris[i].ai_movs_flag != -1 ) {
+ ::Sleep(1);
+ }
+ }
+ }
+ if ( ai_eve ) {
+ eve.game(tetris[0], tetris[1], rnd);
+ }
+#endif
+ if ( tetris[0].alive() && tetris[1].alive() ) {
+ lastGameState = 0;
+ } else {
+ if ( lastGameState == 0 ) {
+ if ( tetris[1].alive() ) {
+ tetris[0].ko();
+ tetris[1].n_win++;
+ } else {
+ tetris[1].ko();
+ tetris[0].n_win++;
+ }
+ //GameSound::ins().stopBGM();
+ if ( player.sound_bgm ) GameSound::ins().loadBGM_wait( rnd );
+ }
+ lastGameState = -1;
+ }
+ if ( ! ai_eve ) {
+ while ( kbmsg() ) {
+ key_msg k = getkey();
+ if ( k.msg == key_msg_down && k.key == key_pause ) {
+ game_pause = ! game_pause;
+ }
+ if ( game_pause ) {
+ continue;
+ }
+ if ( player_stratagy_mode && rule.turnbase
+ && (PLAYER_WAIT || rule.turn > 1)
+ && k.msg == key_msg_down
+ && (tetris[0].n_pieces - 1) / rule.turn > (tetris[1].n_pieces - 1) / rule.turn )
+ {
+ bool match = false;
+ for ( int i = 0; i < 8; ++i ) {
+ if ( k.key == player_keys[i] ) match = true;
+ }
+ player_key_state[0] = 0;
+ player_key_state[1] = 0;
+ player_key_state[2] = 0;
+ if ( match ) continue;
+ }
+ if ( k.msg == key_msg_up ) {
+ for ( int i = 0; i < 8; ++i ) {
+ if ( player_key_state[i] && (k.key == player_keys[i] ) ) {
+ player_key_state[i] = 0;
+ }
+ }
+ }
+ if ( k.msg != key_msg_down ) continue;
+ //if ( k.key != player_last_key ) {
+ // player_key_state[0] = 0;
+ // player_key_state[1] = 0;
+ // player_key_state[2] = 0;
+ // player_last_key = k.key;
+ //}
+ if ( k.key == player_keys[0] && player_key_state[0] == 0 ) {
+ tetris[0].tryXMove(-1);
+ player_key_state[0] = 1;
+ player_key_state[1] = 0;
+ //player_key_state[2] = 0;
+ }
+ if ( k.key == player_keys[1] && player_key_state[1] == 0 ) {
+ tetris[0].tryXMove( 1);
+ player_key_state[0] = 0;
+ player_key_state[1] = 1;
+ //player_key_state[2] = 0;
+ }
+ if ( k.key == player_keys[2] && player_key_state[2] == 0 ) {
+ tetris[0].tryYMove( 1);
+ //while ( tetris[0].tryYMove( 1) );
+ //player_key_state[0] = 0;
+ //player_key_state[1] = 0;
+ player_key_state[2] = 1;
+ }
+ if ( k.key == player_keys[3] && player_key_state[3] == 0 ) {
+ tetris[0].trySpin( 1);
+ player_key_state[3] = 1;
+ }
+ if ( k.key == player_keys[4] && player_key_state[4] == 0 ) {
+ tetris[0].trySpin( 3);
+ player_key_state[4] = 1;
+ }
+ if ( k.key == player_keys[5] && player_key_state[5] == 0 ) {
+ tetris[0].tryHold();
+ player_key_state[5] = 1;
+ }
+ if ( k.key == player_keys[6] && player_key_state[6] == 0 ) {
+ tetris[0].drop();
+ //player_key_state[0] = !!player_key_state[0];
+ //player_key_state[1] = !!player_key_state[1];
+ //player_key_state[2] = !!player_key_state[2];
+ player_key_state[6] = 1;
+ }
+ if ( k.key == player_keys[7] && player_key_state[7] == 0 && AI::spin180Enable() ) {
+ tetris[0].trySpin180();
+ player_key_state[7] = 1;
+ }
+ if ( k.key == key_f2 ) {
+ if ( !tetris[0].alive() || !tetris[1].alive() || tetris[0].n_pieces <= 20 ) {
+ int seed = (unsigned)time(0), pass = rnd.randint(1024);
+ for ( int i = 0; i < players_num; ++i ) {
+ tetris[i].reset( seed ^ ((!rule.samesequence) * i * 255), pass );
+ //tetris[i].reset( (unsigned)time(0) + ::GetTickCount() * i );
+ onGameStart( tetris[i], rnd, i );
+ tetris[i].acceptAttack(player_begin_attack);
+ }
+ if ( player.sound_bgm ) GameSound::ins().loadBGM( rnd );
+ }
+ }
+ if ( k.key == key_f12 ) {
+ setkeyScene( player_keys );
+ for ( int i = 0; i < 7; ++i)
+ player_key_state[i] = 0;
+ }
+ if ( k.key == key_f3 ) {
+ showAttackLine = !showAttackLine;
+ }
+ if ( k.key == key_f4 ) {
+ showGrid = !showGrid;
+ }
+ if ( k.key == key_f5 || k.key == key_f6 ) {
+ char str[64];
+ if ( k.key == key_f5 ) GameSound::ins().setVolumeAdd(-0.05f) ;
+ if ( k.key == key_f6 ) GameSound::ins().setVolumeAdd(+0.05f);
+ sprintf_s( str, 64, "%d %%", int(GameSound::ins().getVolume() * 100 + 0.5) );
+ game_info = "set volume = ";
+ game_info += str;
+ game_info_time = 240;
+ }
+ if ( PUBLIC_VERSION == 0 ) {
+ if ( k.key == key_f9 ) {
+ tetris[1].accept_atts.push_back(1);
+ }
+ }
+ }
+ if ( game_pause ) continue;
+ for (int i = 0; i < 3; ++i) {
+ if ( player_key_state[i] > 0) {
+ ++player_key_state[i];
+ if ( i == 2 ) player_key_state[i] += 9;
+ if ( player.tojsoftdrop && i == 2 ) {
+ while ( player_key_state[i] > (player.softdropdas + 1) * 10 ) {
+ bool move = tetris[0].tryYMove( 1);
+ if ( ! move && player.softdropdelay <= 0) break;
+ player_key_state[i] -= player.softdropdelay;
+ }
+ } else if ( player_key_state[i] > player.das + 1 ) {
+ if ( i == 0 ) {
+ tetris[0].tryXXMove(-1);
+ } else if ( i == 1 ) {
+ tetris[0].tryXXMove( 1) ;
+ } else if ( i == 2 ) {
+ tetris[0].tryYYMove( 1) ;
+ }
+ }
+ }
+ }
+ }
+ for ( int i = 0; i < players_num; ++i ) {
+ if ( tetris[i].game() ) { // ÓÎÏ·Ö´ÐУ¬Èç¹û¶ªÏ·µ»Øtrue
+ tetris[i].env_change = 1;
+ tetris[i].n_pieces += 1;
+
+ int att = tetris[i].m_attack;
+ int clearLines = tetris[i].m_clearLines;
+#ifndef XP_RELEASE
+ if ( tetris[i].total_atts >= 200 && tetris[i].total_atts - tetris[1 - i].total_atts > 20 ) {
+ tetris[1 - i].m_state = AI::Tetris::STATE_OVER;
+ } else if ( tetris[i].total_atts >= 400 ) {
+ if ( (double)tetris[i].total_atts / tetris[i].total_clears > (double)tetris[1 - i].total_atts / tetris[1 - i].total_clears ) {
+ tetris[1 - i].m_state = AI::Tetris::STATE_OVER;
+ }
+ }
+#endif
+ tetris[i].total_clears += clearLines;
+ tetris[i].m_clearLines = 0;
+ tetris[i].m_attack = 0;
+ tetris[i].clearSFX( );
+ if ( att > 0 ) { // Á½Ðй¥»÷
+ tetris[i].total_atts += att;
+ if ( rule.GarbageCancel ) {
+ while ( att > 0 && ! tetris[i].accept_atts.empty() ) {
+ int m = min( att, tetris[i].accept_atts[0]);
+ att -= m;
+ tetris[i].accept_atts[0] -= m;
+ if ( tetris[i].accept_atts[0] <= 0 ) {
+ tetris[i].accept_atts.erase( tetris[i].accept_atts.begin() );
+ }
+ }
+ }
+ if ( att > 0 ) {
+ for ( int j = 0; j < players_num; ++j ) {
+ if ( i == j ) continue;
+ if ( rule.GarbageBuffer ) {
+ tetris[j].accept_atts.push_back( att );
+ tetris[i].total_sent += att;
+ if ( rule.turnbase ) tetris[j].env_change = 2;
+ } else {
+ if ( player_accept_attack )
+ tetris[j].acceptAttack( att );
+ if ( rule.turnbase ) tetris[j].env_change = 2;
+ }
+ }
+ }
+ }
+
+ if ( player_accept_attack && ( rule.GarbageBlocking == 0 || clearLines == 0) ) {
+ while ( ! tetris[i].accept_atts.empty() ) {
+ if ( rule.garbage == 0 ) {
+ tetris[i].acceptAttack( *tetris[i].accept_atts.begin() );
+ } else if ( rule.garbage == 1 ) {
+ for ( int n = *tetris[i].accept_atts.begin(); n > 0; n-= 2 ) {
+ if ( n >= 2 ) tetris[i].acceptAttack( 2 );
+ else tetris[i].acceptAttack( 1 );
+ }
+ } else { //if ( rule.garbage == 2 ) {
+ for ( int n = *tetris[i].accept_atts.begin(); n > 0; --n ) {
+ tetris[i].acceptAttack( 1 );
+ }
+ }
+ tetris[i].accept_atts.erase( tetris[i].accept_atts.begin() );
+ }
+ }
+ }
+ if ( tetris[i].env_change && tetris[i].ai_movs_flag == -1) { // AI ¼ÆËã
+ if ( (ai_eve || ai[i].style) && tetris[i].alive() ) {
+ //if ( i != 0 && tetris[i].alive() ) {
+ std::vector next;
+ for ( int j = 0; j < 32; ++j)
+ next.push_back(tetris[i].m_next[j]);
+ double beg = (double)::GetTickCount() / 1000;
+ int deep = ai_search_height_deep;
+ int upcomeAtt = 0;
+ for ( int j = 0; j < tetris[i].accept_atts.size(); ++j ) {
+ upcomeAtt += tetris[i].accept_atts[j];
+ }
+ int level = ai[i].level;
+ //if ( tetris[i].m_pool.row[6] ) {
+ // deep = ai_search_height_deep;
+ //}
+ if ( i == 1 && rule.turn == 1 && rule.turnbase && level > 9 ) { // ·À2P±»³¬Ô½Ì«¶à
+ if ( tetris[0].n_pieces * ai[1].PieceMul - tetris[i].n_pieces * ai[0].PieceMul > 2 ) {
+ level = 9;
+ }
+ }
+ bool canhold = tetris[i].hold;
+
+ if ( tetris[i].pTetrisAI ) {
+ AI::RunAIDll(tetris[i].pTetrisAI, tetris[i].ai_movs, tetris[i].ai_movs_flag, tetris[i].m_ai_param, tetris[i].m_pool, tetris[i].m_hold,
+ tetris[i].m_cur,
+ tetris[i].m_cur_x, tetris[i].m_cur_y, next, canhold, upcomeAtt,
+ deep, tetris[i].ai_last_deep, level, i);
+ } else {
+ AI::RunAI(tetris[i].ai_movs, tetris[i].ai_movs_flag, tetris[i].m_ai_param, tetris[i].m_pool, tetris[i].m_hold,
+ tetris[i].m_cur,
+ tetris[i].m_cur_x, tetris[i].m_cur_y, next, canhold, upcomeAtt,
+ deep, tetris[i].ai_last_deep, level, i);
+#if 1 && !defined(XP_RELEASE)
+ while ( tetris[i].ai_movs_flag != -1 ) ::Sleep(1);
+#endif
+ }
+ ai_time = (double)::GetTickCount() / 1000 - beg;
+ if ( rule.turnbase && ai[0].style == 0 ) {
+ if ( rule.turn == 1 && tetris[0].n_pieces * ai[1].PieceMul - tetris[i].n_pieces * ai[0].PieceMul > 1 ) {
+ ai_mov_time_base = ai_mov_time / 4;
+ } else {
+ ai_mov_time_base = ai_mov_time;
+ }
+ tetris[i].ai_delay = ai_mov_time_base + ai_mov_time_base / 3;
+ } else {
+ tetris[i].ai_delay = ai_first_delay;
+ }
+ if ( tetris[i].env_change == 2 ) { // ±»¹¥»÷¾Í°´Òѵȴýʱ¼ä¼õÉÙ˼Ë÷µÈ´ý
+ tetris[i].ai_delay = max(0, tetris[i].ai_delay - tetris[i].m_piecedelay);
+ }
+ }
+ tetris[i].env_change = 0;
+ }
+ }
+ for ( int i = 0; i < players_num; ++i ) { // 100 garbage buffer get lost
+ if ( ! tetris[i].alive() ) continue;
+ int total = 0;
+ for ( int j = 0; j < tetris[i].accept_atts.size(); ++j ) {
+ total += tetris[i].accept_atts[j];
+ }
+ if ( total >= 100 * 1 ) { // TODO
+ tetris[i].m_state = AI::Tetris::STATE_OVER;
+ }
+ }
+ for ( int i = 0; i < players_num; ++i ) {
+ if ( tetris[i].ai_delay > 0 ) --tetris[i].ai_delay;
+ if ( player_stratagy_mode ) {
+ if ( i != 0 && tetris[0].n_pieces == 1 ) continue;
+ if ( rule.turnbase ) {
+ if ( i == 0 && (tetris[0].n_pieces - 1) * ai[1].PieceMul / rule.turn > (tetris[1].n_pieces - 1) * ai[0].PieceMul / rule.turn ) continue;
+ if ( i != 0 && (tetris[1].n_pieces - 1) * ai[0].PieceMul / rule.turn >= (tetris[0].n_pieces - 1) * ai[1].PieceMul / rule.turn ) continue;
+ } else {
+ if ( i == 0 && !tetris[1].alive() ) continue;
+ if ( i != 0 && !tetris[0].alive() ) continue;
+ }
+ }
+ //if ( tetris[i].mov_llrr ) {
+ // if (0) ;
+ // else if (tetris[i].mov_llrr == AI::Moving::MOV_LL) {if ( ! tetris[i].tryXMove(-1) ) tetris[i].mov_llrr = 0;}
+ // else if (tetris[i].mov_llrr == AI::Moving::MOV_RR) {if ( ! tetris[i].tryXMove( 1) ) tetris[i].mov_llrr = 0;}
+ //} else
+ {
+ do
+ {
+ if ( tetris[i].ai_delay > 0 ) ;
+ else if ( tetris[i].ai_movs_flag == -1 && ! tetris[i].ai_movs.movs.empty() ){
+ if ( rule.turnbase && ai[0].style == 0 ) {
+ tetris[i].ai_delay = ai_mov_time_base;
+ } else {
+ tetris[i].ai_delay = ai_move_delay;
+ }
+ int mov = tetris[i].ai_movs.movs[0];
+ if ( tetris[i].ai_movs.movs.size() > 1 ) {
+ int next_mov = tetris[i].ai_movs.movs[1];
+ if ( mov != next_mov ) tetris[i].ai_delay = tetris[i].ai_delay * 8 / 12;
+ }
+ tetris[i].ai_movs.movs.erase( tetris[i].ai_movs.movs.begin() );
+ if (0) ;
+ else if (mov == AI::Moving::MOV_L) tetris[i].tryXMove(-1);
+ else if (mov == AI::Moving::MOV_R) tetris[i].tryXMove( 1);
+ else if (mov == AI::Moving::MOV_D) tetris[i].tryYMove( 1);
+ else if (mov == AI::Moving::MOV_LSPIN) tetris[i].trySpin(1);
+ else if (mov == AI::Moving::MOV_RSPIN) tetris[i].trySpin(3);
+ else if (mov == AI::Moving::MOV_LL) { tetris[i].tryXXMove(-1); } //{ tetris[i].mov_llrr = AI::Moving::MOV_LL; }
+ else if (mov == AI::Moving::MOV_RR) { tetris[i].tryXXMove( 1); } //{ tetris[i].mov_llrr = AI::Moving::MOV_RR; }
+ else if (mov == AI::Moving::MOV_DD) tetris[i].tryYYMove( 1) ;
+ else if (mov == AI::Moving::MOV_DROP) tetris[i].drop();
+ else if (mov == AI::Moving::MOV_HOLD) {
+ tetris[i].tryHold();
+ } else if (mov == AI::Moving::MOV_SPIN2) {
+ if ( AI::spin180Enable() ) {
+ tetris[i].trySpin180();
+ }
+ } else if (mov == AI::Moving::MOV_REFRESH) {
+ tetris[i].env_change = 1;
+ }
+ }
+ } while ( tetris[i].ai_movs_flag == -1 && tetris[i].ai_delay == 0 && !tetris[i].ai_movs.movs.empty() );
+ }
+ }
+ if ( ! ai_eve ) break;
+ }
+ cleardevice();
+ for (std::vector::iterator it = tetris.begin();
+ it != tetris.end();
+ ++it) {
+ tetris_draw(*it, showAttackLine, showGrid);
+ }
+ //if(0)
+ if ( ! PUBLIC_VERSION )
+ {
+ for ( int i = 0; i < players_num; ++i ) {
+ setcolor(EGERGB(0x0, 0xa0, 0x0));
+ //xyprintf(0,0, "%.3f", ai_time * 1000);
+ xyprintf((int)tetris[i].m_base.x, (int)(tetris[i].m_base.y - tetris[i].m_size.y), "d = %d", tetris[i].ai_last_deep);
+ }
+ }
+ if ( game_info_time > 0 ) {
+ --game_info_time;
+ xyprintf( 0, getheight() - textheight("I"), "%s", game_info.c_str());
+ }
+#ifndef XP_RELEASE
+ if ( ai_eve ) {
+ double d = 0;
+ if ( eve.m_p2 > 0 ) {
+ d = eve.m_p2_score / (double)eve.m_p2;
+ d *= d;
+ d = eve.m_p2_sqr_score / (double)eve.m_p2 - d;
+ d = eve.m_p2_score / (double)eve.m_p2 - sqrt(d);
+ }
+ if ( (eve.m_p1 + eve.m_p2) % 2 == 0)
+ xyprintf(0, 0, "(%d) %d : %d", eve.ai.size(), eve.m_p2, eve.m_p1);
+ else
+ xyprintf(0, 0, "(%d) %d : %d", eve.ai.size(), eve.m_p1, eve.m_p2);
+ //xyprintf(0, 0, "%.2f %d %d", d * eve.round, eve.m_p2, eve.m_p2_score + tetris[1].total_atts);
+ }
+#endif
+ {
+ char buff[16];
+ sprintf(buff, "%.2ffps", getfps());
+ outtextxy(getwidth() - textwidth(buff), 0, buff);
+ }
+ }
+ saveKeySetting( player_keys );
+}
+
+void CenterWindow(HWND hWnd)
+{
+ HWND hParentOrOwner;
+ RECT rc, rc2;
+ int x,y;
+ if ( (hParentOrOwner = GetParent(hWnd)) == NULL )
+ {
+ SystemParametersInfo(SPI_GETWORKAREA,0,&rc,0);
+ }
+ else
+ {
+ GetClientRect(hParentOrOwner, &rc);
+ }
+ GetWindowRect(hWnd, &rc2);
+ x = ((rc.right-rc.left) - (rc2.right-rc2.left)) / 2 +rc.left;
+ y = ((rc.bottom-rc.top) - (rc2.bottom-rc2.top)) / 2 +rc.top;
+ SetWindowPos(hWnd,HWND_TOP,x, y,0, 0,SWP_NOSIZE);
+}
+
+int main () {
+#if PUBLIC_VERSION == 0
+ setinitmode(INIT_ANIMATION & ~INIT_WITHLOGO);
+#else
+ setinitmode(INIT_ANIMATION);
+#endif
+ initgraph(800, 500);
+ //CenterWindow( getHWnd() );
+#if PUBLIC_VERSION == 0
+ setcaption("Tetris AI Demo");
+#else
+ setcaption("MisaMino V1.4.5 ---- by Misakamm ( misakamm.com )");
+#endif
+ mainscene();
+ return 0;
+}
diff --git a/tetris_ai/random.h b/tetris_ai/random.h
new file mode 100644
index 0000000..9a93943
--- /dev/null
+++ b/tetris_ai/random.h
@@ -0,0 +1,183 @@
+#pragma once
+//#include
+
+//************************************************************************
+// This is a slightly modified version of Equamen mersenne twister.
+//
+// Copyright (C) 2009 Chipset
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//************************************************************************
+
+// Original Coyright (c) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura
+//
+// Functions for MT19937, with initialization improved 2002/2/10.
+// Coded by Takuji Nishimura and Makoto Matsumoto.
+// This is a faster version by taking Shawn Cokus's optimization,
+// Matthe Bellew's simplification, Isaku Wada's real version.
+// C++ version by Lyell Haynes (Equamen)
+
+namespace AI {
+
+const int N = 624;
+const int M = 397;
+
+typedef unsigned __int32 uint32;
+
+class mtrandom {
+public:
+ mtrandom() : left(1) { init(); }
+ mtrandom(const mtrandom& m) {
+ for ( int i = 0; i < N; ++i) {
+ state[i] = m.state[i];
+ }
+ left = m.left;
+ next = state + (m.next - m.state);
+ }
+
+ explicit mtrandom(uint32 seed) : left(1) { init(seed); }
+
+ mtrandom(uint32* init_key, int key_length) : left(1) {
+ int i = 1, j = 0;
+ int k = N > key_length ? N : key_length;
+ init();
+ for(; k; --k) {
+ state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525UL)) + init_key[j] + j; // non linear
+ state[i] &= 4294967295UL; // for WORDSIZE > 32 machines
+ ++i;
+ ++j;
+ if(i >= N) {
+ state[0] = state[N - 1];
+ i = 1;
+ }
+ if(j >= key_length)
+ j = 0;
+ }
+
+ for(k = N - 1; k; --k) {
+ state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941UL)) - i; // non linear
+ state[i] &= 4294967295UL; // for WORDSIZE > 32 machines
+ ++i;
+ if(i >= N) {
+ state[0] = state[N - 1];
+ i = 1;
+ }
+ }
+
+ state[0] = 2147483648UL; // MSB is 1; assuring non-zero initial array
+ }
+
+ void reset(uint32 rs) {
+ init(rs);
+ next_state();
+ }
+
+ uint32 rand() {
+ uint32 y;
+ if(0 == --left)
+ next_state();
+ y = *next++;
+ // Tempering
+ y ^= (y >> 11);
+ y ^= (y << 7) & 0x9d2c5680UL;
+ y ^= (y << 15) & 0xefc60000UL;
+ y ^= (y >> 18);
+ return y;
+ }
+
+ double real() { return (double)rand() / ((double)(unsigned long)(-1L) + 1); }
+
+ // generates a random number on [0,1) with 53-bit resolution
+ double res53() {
+ uint32 a = rand() >> 5, b = rand() >> 6;
+ return (a * 67108864.0 + b) / 9007199254740992.0;
+ }
+
+private:
+ void init(uint32 seed = 19650218UL) {
+ state[0] = seed & 4294967295UL;
+ for(int j = 1; j < N; ++j) {
+ state[j] = (1812433253UL * (state[j - 1] ^ (state[j - 1] >> 30)) + j);
+ // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
+ // In the previous versions, MSBs of the seed affect
+ // only MSBs of the array state[].
+ // 2002/01/09 modified by Makoto Matsumoto
+ state[j] &= 4294967295UL; // for >32 bit machines
+ }
+ }
+
+ void next_state() {
+ uint32* p = state;
+ int i;
+
+ for(i = N - M + 1; --i; ++p)
+ *p = (p[M] ^ twist(p[0], p[1]));
+
+ for(i = M; --i; ++p)
+ *p = (p[M - N] ^ twist(p[0], p[1]));
+ *p = p[M - N] ^ twist(p[0], state[0]);
+ left = N;
+ next = state;
+ }
+
+ uint32 mixbits(uint32 u, uint32 v) const {
+ return (u & 2147483648UL) | (v & 2147483647UL);
+ }
+
+ uint32 twist(uint32 u, uint32 v) const {
+ return ((mixbits(u, v) >> 1) ^ (v & 1UL ? 2567483615UL : 0UL));
+ }
+
+ uint32 state[N];
+ uint32 left;
+ uint32* next;
+};
+
+/*
+class mtrand_help {
+ static mtrandom r;
+public:
+ mtrand_help() {}
+ void operator()(uint32 s) { r.reset(s); }
+ uint32 operator()() const { return r.rand(); }
+ double operator()(double) { return r.real(); }
+};
+mtrandom mtrand_help:: r;
+
+extern void mtsrand(uint32 s) { mtrand_help()(s); }
+extern uint32 mtirand() { return mtrand_help()(); }
+extern double mtdrand() { return mtrand_help()(1.0); }
+*/
+
+class Random {
+public:
+ Random( unsigned _seed = 0 ) {
+ seed(_seed);
+ }
+ void seed( unsigned seed ) {
+ r.reset( seed );
+ }
+ uint32 rand() {
+ return r.rand();
+ }
+ int randint( uint32 maxnum ) {
+ return int(randfloat() * maxnum);
+ }
+ double randfloat () {
+ return r.real();
+ }
+private:
+ mtrandom r;
+};
+
+}
diff --git a/tetris_ai/resource.h b/tetris_ai/resource.h
new file mode 100644
index 0000000..773db42
Binary files /dev/null and b/tetris_ai/resource.h differ
diff --git a/tetris_ai/resource1.h b/tetris_ai/resource1.h
new file mode 100644
index 0000000..0e9756c
--- /dev/null
+++ b/tetris_ai/resource1.h
@@ -0,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Tspin08.rc
+//
+#define IDI_ICON1 101
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/tetris_ai/sound.h b/tetris_ai/sound.h
new file mode 100644
index 0000000..832e5df
--- /dev/null
+++ b/tetris_ai/sound.h
@@ -0,0 +1,182 @@
+#pragma once
+
+#include "bass.h"
+#pragma comment(lib, "bass.lib")
+#include
+
+class GameSound {
+protected:
+ GameSound() {
+ mVolume = 0.5f;
+ mBgmVolume = 0.3f;
+ BASS_Init(-1,44100,0,0,NULL);
+ }
+ ~GameSound() {
+ }
+public:
+ class sound {
+ public:
+ sound( ) {
+ for ( int i = 0; i < 16; ++i)
+ m[i] = NULL;
+ mOpen = false;
+ mIndex = 0;
+ mMax = 1;
+ }
+ ~sound() {
+ for ( int i = 0; i < 16; ++i) {
+ if ( m[i] ) {
+ BASS_StreamFree(m[i]);
+ m[i] = NULL;
+ }
+ }
+ BASS_Free();
+ }
+ int open( float * volume, const char* path, int nMax = 2, int loop = 0 ) {
+ mVolume = volume;
+ if ( m[0] ) {
+ for ( int i = 0; i < 16; ++i) {
+ if ( m[i] ) {
+ BASS_StreamFree(m[i]);
+ m[i] = NULL;
+ }
+ }
+ }
+ m[0] = BASS_StreamCreateFile(FALSE, path, 0, 0, loop?BASS_SAMPLE_LOOP:0);
+ int ret = m[0];
+ mMax = nMax;
+ for ( int i = 1; i < mMax; ++i) {
+ m[i] = BASS_StreamCreateFile(FALSE, path, 0, 0, loop?BASS_SAMPLE_LOOP:0);
+ }
+ mOpen = ret != 0;
+ return ret;
+ }
+ bool isOpen() {
+ return mOpen;
+ }
+ int play( int lr = 0) {
+ mIndex = (mIndex+1) % mMax;
+ //m[mIndex]->Stop();
+ setVolume( *mVolume );
+ if ( lr == 1 ) {
+ BASS_ChannelSetAttribute(m[mIndex], BASS_ATTRIB_PAN, -0.7);
+ } else if ( lr == 2 ){
+ BASS_ChannelSetAttribute(m[mIndex], BASS_ATTRIB_PAN, 0.7);
+ }
+ return BASS_ChannelPlay(m[mIndex], TRUE);
+ }
+ int stop() {
+ return BASS_ChannelStop(m[mIndex]);
+ }
+ void setVolume( float volume ) {
+ if ( m[mIndex] ) {
+ BASS_ChannelSetAttribute( m[mIndex], BASS_ATTRIB_VOL, volume );
+ }
+ }
+ private:
+ HSTREAM m[16];
+ int mIndex;
+ int mMax;
+ bool mOpen;
+ float * mVolume;
+ };
+ static GameSound& ins() {
+ static GameSound gamesound;
+ return gamesound;
+ }
+ void loadSFX () {
+#if !defined(XP_RELEASE)
+ return;
+#endif
+ std::string basePath = "sound/sfx/default/";
+ mSFX_ko.open(&mVolume, (basePath + "sfx_ko.wav").c_str());
+ mSFX_gameover.open(&mVolume, (basePath + "sfx_gameover.wav").c_str());
+ mSFX_pc.open(&mVolume, (basePath + "sfx_perfectclear.wav").c_str());
+ mSFX_move.open(&mVolume, (basePath + "sfx_move.wav").c_str(), 4);
+ mSFX_hold.open(&mVolume, (basePath + "sfx_hold.wav").c_str());
+ mSFX_rotate.open(&mVolume, (basePath + "sfx_rotate.wav").c_str());
+ mSFX_softdrop.open(&mVolume, (basePath + "sfx_softdrop.wav").c_str(), 8);
+ mSFX_harddrop.open(&mVolume, (basePath + "sfx_harddrop.wav").c_str());
+ mSFX_lockdown.open(&mVolume, (basePath + "sfx_lockdown.wav").c_str());
+ mSFX_lineattack.open(&mVolume, (basePath + "sfx_lineattack.wav").c_str());
+ mSFX_clears[0].open(&mVolume, (basePath + "sfx_single.wav").c_str());
+ mSFX_clears[1].open(&mVolume, (basePath + "sfx_double.wav").c_str());
+ mSFX_clears[2].open(&mVolume, (basePath + "sfx_triple.wav").c_str());
+ mSFX_clears[3].open(&mVolume, (basePath + "sfx_tetris.wav").c_str());
+ mSFX_b2b_tetris.open(&mVolume, (basePath + "sfx_b2b_tetris.wav").c_str());
+ for ( int i = 0; i < 20; ++i) {
+ char name[16];
+ sprintf( name, "sfx_combo%d.wav", i + 1);
+ mSFX_combo[i].open(&mVolume, (basePath + name).c_str());
+ }
+ mSFX_tspin[0].open(&mVolume, (basePath + "sfx_tspin_mini.wav").c_str());
+ mSFX_tspin[1].open(&mVolume, (basePath + "sfx_tspin_single.wav").c_str());
+ mSFX_tspin[2].open(&mVolume, (basePath + "sfx_tspin_double.wav").c_str());
+ mSFX_tspin[3].open(&mVolume, (basePath + "sfx_tspin_triple.wav").c_str());
+ mSFX_b2b_tspin[0].open(&mVolume, (basePath + "sfx_b2b_tspin_mini.wav").c_str());
+ mSFX_b2b_tspin[1].open(&mVolume, (basePath + "sfx_b2b_tspin_single.wav").c_str());
+ mSFX_b2b_tspin[2].open(&mVolume, (basePath + "sfx_b2b_tspin_double.wav").c_str());
+ mSFX_b2b_tspin[3].open(&mVolume, (basePath + "sfx_b2b_tspin_triple.wav").c_str());
+ }
+ void loadBGM_wait( AI::Random& rnd ) {
+ std::string basePath = "sound/music/default/";
+ int n = rnd.randint(2);
+ if ( n == 0 ) {
+ mbgm.open(&mBgmVolume, (basePath + "waiting1.ogg").c_str(), 1, 1);
+ } else {
+ mbgm.open(&mBgmVolume, (basePath + "waiting2.ogg").c_str(), 1, 1);
+ }
+ mbgm.play();
+ }
+ void loadBGM( AI::Random& rnd ) {
+ std::string basePath = "sound/music/default/";
+ int n = rnd.randint(3);
+ if ( n == 0 ) {
+ mbgm.open(&mBgmVolume, (basePath + "bgm_01.ogg").c_str(), 1, 1);
+ } else if ( n == 1 ) {
+ mbgm.open(&mBgmVolume, (basePath + "bgm_02.ogg").c_str(), 1, 1);
+ } else if ( n == 2 ) {
+ mbgm.open(&mBgmVolume, (basePath + "bgm_03.ogg").c_str(), 1, 1);
+ }
+ mbgm.play();
+ }
+ void stopBGM() {
+ mbgm.stop();
+ }
+ void setVolume( float volume ) {
+ mVolume = volume;
+ if ( mVolume < 0.0 ) mVolume = 0;
+ if ( mVolume > 1.0 ) mVolume = 1.0f;
+ mBgmVolume = mVolume * 0.6f;
+ mbgm.setVolume(mBgmVolume);
+ }
+ void setVolumeAdd( float add ) {
+ mVolume += add;
+ if ( mVolume < 0.0 ) mVolume = 0;
+ if ( mVolume > 1.0 ) mVolume = 1.0f;
+ mBgmVolume = mVolume * 0.6f;
+ mbgm.setVolume(mBgmVolume);
+ }
+ float getVolume() const {
+ return mVolume;
+ }
+public:
+ sound mSFX_move;
+ sound mSFX_hold;
+ sound mSFX_rotate;
+ sound mSFX_softdrop;
+ sound mSFX_harddrop;
+ sound mSFX_lockdown;
+ sound mSFX_lineattack;
+ sound mSFX_clears[4];
+ sound mSFX_combo[20];
+ sound mSFX_tspin[4];
+ sound mSFX_b2b_tspin[4];
+ sound mSFX_b2b_tetris;
+ sound mSFX_ko;
+ sound mSFX_gameover;
+ sound mSFX_pc;
+ sound mbgm;
+ float mVolume;
+ float mBgmVolume;
+};
diff --git a/tetris_ai/tetris.h b/tetris_ai/tetris.h
new file mode 100644
index 0000000..8682a0b
--- /dev/null
+++ b/tetris_ai/tetris.h
@@ -0,0 +1,412 @@
+#pragma once
+#include "gamepool.h"
+#include "random.h"
+#include "tetris_ai.h"
+
+namespace AI {
+
+ struct point {
+ float x;
+ float y;
+ point() : x(0), y(0) {}
+ point(float _x, float _y) : x(_x), y(_y) {}
+ point(int _x, int _y)
+ : x(static_cast(_x))
+ , y(static_cast(_y))
+ {}
+ };
+
+ class Tetris {
+ public:
+ enum {
+ STATE_INIT,
+ STATE_READY,
+ STATE_MOVING,
+ STATE_PASTED,
+ STATE_OVER,
+ };
+ struct clear_info {
+ int gem_num;
+ int clears;
+ int attack;
+ int b2b;
+ int combo;
+ int pc;
+ signed char wallkick_spin;
+ int total_pc;
+ int total_b2b;
+ int total_cb_att;
+ int t[4];
+ int normal[5];
+ void reset( int _gem_num ) {
+ memset(this, 0, sizeof(*this));
+ gem_num = _gem_num;
+ }
+ void newgem( int _gem_num ) {
+ gem_num = _gem_num;
+ clears = 0;
+ attack = 0;
+ b2b = 0;
+ combo = 0;
+ pc = 0;
+ wallkick_spin = 0;
+ }
+ };
+ Tetris() : m_pool( 10, 20 ) {
+ m_state = STATE_INIT;
+ reset ( 0, 10, 20 );
+ }
+ void genNext() {
+ int m[] = {1,2,3,4,5,6,7};
+ int s[7];
+ int v = m_rand.randint(5040);
+ int mod = 5040 / 7;
+ for ( int i = 6; i > 0; --i ) {
+ s[6-i] = m[v / mod];
+ for ( int j = v / mod; j < 6; ++j) {
+ m[j] = m[j+1];
+ }
+ v %= mod;
+ mod /= i;
+ }
+ s[6] = m[0];
+ for ( int i = 0; i < 7; ++i ) {
+ m_next[ m_next_num + i] = AI::getGem( s[i], 0);
+ }
+ m_next_num += 7;
+ }
+ void reset (unsigned seed, signed char w, signed char h) {
+ m_pool.reset( w, h );
+ m_rand.seed( seed );
+ m_next_num = 0;
+ while ( m_next_num < 100 ) genNext();
+ //for ( int i = 0; i < 32; ++i ) {
+ // m_next[i] = AI::getGem( m_rand.randint(7) + 1, 0);
+ //}
+ m_state = STATE_READY;
+ m_cur = AI::getGem(0, 0);
+ m_cur_x = AI::gem_beg_x;
+ m_cur_y = AI::gem_beg_y;
+ m_curnum = 0;
+ m_clearLines = 0;
+ m_attack = 0;
+ m_max_combo = 0;
+ m_frames = 0;
+ m_drop_frame = 0;
+ m_clear_info.reset( 0 );
+ memset( m_color_pool, 0, sizeof( m_color_pool ) );
+ }
+ bool tryXMove(int dx) {
+ if ( m_state != STATE_MOVING ) return false;
+ if (m_pool.isCollide(m_cur_x + dx, m_cur_y, m_cur))
+ return false;
+ m_cur_x += dx;
+ wallkick_spin = 0;
+ return true;
+ }
+ bool tryYMove(int dy) {
+ if ( m_state != STATE_MOVING ) return false;
+ if (m_pool.isCollide(m_cur_x, m_cur_y + dy, m_cur))
+ return false;
+ m_cur_y += dy;
+ wallkick_spin = 0;
+ return true;
+ }
+ bool trySpin(int dSpin) {
+ if ( m_state != STATE_MOVING ) return false;
+ AI::Gem gem = AI::getGem(m_cur.num, (m_cur.spin + dSpin + 4) % 4);
+ if (m_pool.isCollide(m_cur_x, m_cur_y, gem)) {
+ int spin = 1;
+ if ( dSpin == 1 ) spin = 0;
+ if ( m_pool.wallkickTest(m_cur_x, m_cur_y, gem, spin) ) {
+ m_cur = gem;
+ wallkick_spin = 2;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ m_cur = gem;
+ wallkick_spin = 1;
+ return true;
+ }
+ bool trySpin180() {
+ if ( m_state != STATE_MOVING ) return false;
+ AI::Gem gem = AI::getGem(m_cur.num, (m_cur.spin + 2) % 4);
+ if (m_pool.isCollide(m_cur_x, m_cur_y, gem)) {
+ return false;
+ }
+ m_cur = gem;
+ wallkick_spin = 1;
+ return true;
+ }
+ bool tryHold() {
+ if ( m_state != STATE_MOVING ) return false;
+ if ( m_hold ) return false;
+ m_hold = true;
+ int hold = m_pool.m_hold;
+ m_pool.m_hold = m_cur.num;
+ if ( hold == 0 ) {
+ m_cur_x = AI::gem_beg_x;
+ m_cur_y = AI::gem_beg_y;
+ m_cur = AI::getGem(m_next[0].num, 0);
+ removeNext();
+ } else {
+ m_cur_x = AI::gem_beg_x;
+ m_cur_y = AI::gem_beg_y;
+ m_cur = AI::getGem(hold, 0);
+ }
+ if ( m_pool.isCollide(m_cur_x, m_cur_y, m_cur)) {
+ m_state = STATE_OVER;
+ return true;
+ }
+ return true;
+ }
+ void paste() {
+ for ( int y = 0; y < 4; ++y ) {
+ for ( int x = 0; x < 4; ++x ) {
+ if ( m_cur.bitmap[y] & ( 1 << x ) ) {
+ m_color_pool[m_cur_y + y + 32][m_cur_x + x] = m_cur.num;
+ }
+ }
+ }
+ }
+ bool drop () {
+ if ( m_state != STATE_MOVING ) return false;
+ m_clear_info.newgem( m_cur.num );
+ while ( tryYMove( 1 ) );
+ wallkick_spin = m_pool.WallKickValue(m_cur.num, m_cur_x, m_cur_y, m_cur.spin, wallkick_spin);
+ m_pool.paste( m_cur_x, m_cur_y, m_cur );
+ paste();
+ m_drop_frame = m_frames;
+ m_cur = AI::getGem( 0, 0);
+ m_state = STATE_PASTED;
+ return true;
+ }
+ void color_pool_clearLines() {
+ int dy = 63;
+ for ( int y = dy; y >= 0; --y ) {
+ int x = 0;
+ for ( ; x < poolw(); ++x ) {
+ if ( m_color_pool[y][x] == 0 ) break;
+ }
+ if ( x < poolw() ) {
+ if ( dy != y ) {
+ for (x = 0 ; x < poolw(); ++x ) {
+ m_color_pool[dy][x] = m_color_pool[y][x];
+ }
+ }
+ --dy;
+ }
+ }
+ for ( ; dy >= 0; --dy ) {
+ for (int x = 0 ; x < poolw(); ++x ) {
+ m_color_pool[dy][x] = 0;
+ }
+ }
+ }
+ void clearLines () {
+ if ( m_state != STATE_PASTED ) return;
+ m_clearLines = m_pool.clearLines( wallkick_spin );
+ color_pool_clearLines();
+ m_attack = m_pool.getAttack( m_clearLines, wallkick_spin );
+ m_max_combo = std::max(m_max_combo, m_pool.combo - 1);
+
+ m_clear_info.clears = m_clearLines;
+ m_clear_info.attack = m_attack;
+ m_clear_info.b2b = m_pool.b2b;
+ m_clear_info.combo = m_pool.combo;
+ m_clear_info.wallkick_spin = wallkick_spin;
+ m_clear_info.total_cb_att += getComboAttack( m_pool.combo );
+ if ( m_clear_info.b2b > 1 && m_attack > 0 )
+ {
+ ++m_clear_info.total_b2b;
+ }
+ {
+ int i = gem_add_y + m_pool.height();
+ for ( ; i >= 0; --i ) {
+ if ( m_pool.m_row[i] ) break;
+ }
+ if ( i < 0 ) {
+ m_clear_info.pc = 1;
+ ++m_clear_info.total_pc;
+ }
+ }
+ int special = 0;
+ //if ( m_clear_info.gem_num == 1 && m_clearLines >= 4 )
+ //{
+ // special = 1;
+ // m_clear_info.normal[4] += 1;
+ //}
+ if ( m_attack > 0 )
+ {
+ if ( m_clear_info.wallkick_spin ) {
+ special = 1;
+ //if ( m_clear_info.gem_num == 2 )
+ {
+ if ( wallkick_spin == 2 && (AI::isEnableAllSpin() || m_clear_info.clears == 1) ) {
+ //if ( m_clear_info.wallkick_spin == 2 ) {
+ ++m_clear_info.t[0];
+ } else {
+ ++m_clear_info.t[m_clear_info.clears];
+ }
+ }
+ }
+ //if ( m_clear_info.gem_num == 2 )
+ //{
+ // int att = m_attack;
+ // att -= m_pool.b2b > 1;
+ // att -= getComboAttack( m_pool.combo );
+ // if ( m_clear_info.pc ) {
+ // att -= 6;
+ // }
+ // if ( att / m_clear_info.clears >= 2 ) { // T1T2T3
+ // special = 1;
+ // ++m_clear_info.t[m_clear_info.clears];
+ // } else if ( m_clear_info.clears == 2 ) { // double
+ // //++m_clear_info.normal[2];
+ // } else if ( m_clear_info.clears == 1 && att == 1 ) { // T0
+ // special = 1;
+ // ++m_clear_info.t[0];
+ // }
+ //}
+ }
+ if ( m_clearLines > 0 && special == 0 )
+ {
+ ++m_clear_info.normal[m_clearLines];
+ }
+
+ m_state = STATE_READY;
+ }
+ void addRow( int att ) {
+ {
+ for ( int y = 1; y < 64; ++y ) {
+ for (int x = 0 ; x < poolw(); ++x ) {
+ m_color_pool[y-1][x] = m_color_pool[y][x];
+ }
+ }
+ for (int x = 0 ; x < poolw(); ++x ) {
+ if ( att & ( 1 << x ) ) {
+ m_color_pool[poolh() + 32][x] = 8;
+ } else {
+ m_color_pool[poolh() + 32][x] = 0;
+ }
+ }
+ }
+ m_pool.addRow( att );
+ if ( m_cur_y > 1 ) {
+ m_cur_y -= 1;
+ }
+ if ( m_pool.m_row[0] ) {
+ m_state = STATE_OVER;
+ }
+ }
+ void setRow( int y, int att ) {
+ {
+ for (int x = 0 ; x < poolw(); ++x ) {
+ if ( att & ( 1 << x ) ) {
+ m_color_pool[y + 32][x] = 8;
+ } else {
+ m_color_pool[y + 32][x] = 0;
+ }
+ }
+ }
+ m_pool.row[y] = att;
+ }
+ void removeNext() {
+ for (int i = 1; i < m_next_num; ++i) {
+ m_next[i - 1] = m_next[i];
+ }
+ --m_next_num;
+ while ( m_next_num < 100 ) genNext();
+ //m_next[15] = AI::getGem( m_rand.randint(7) + 1, 0);
+ }
+ bool newpiece() {
+ if ( m_state != STATE_READY ) return false;
+ m_cur_x = AI::gem_beg_x;
+ m_cur_y = AI::gem_beg_y;
+ ++m_curnum;
+ m_cur = m_next[0];
+ m_hold = false;
+ wallkick_spin = 0;
+ removeNext();
+ //if ( m_pool.row[0] || m_pool.row[1] || m_pool.isCollide(m_cur_x, m_cur_y, m_cur)) {
+ if ( m_pool.isCollide(m_cur_x, m_cur_y, m_cur) ) {
+ m_state = STATE_OVER;
+ return true;
+ }
+ m_state = STATE_MOVING;
+ return true;
+ }
+ bool game() {
+ ++m_frames;
+ switch (m_state) {
+ case STATE_MOVING:
+ {
+ }
+ break;
+ case STATE_PASTED:
+ {
+ clearLines();
+ }
+ case STATE_READY:
+ {
+ return newpiece();
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+ int poolw() const {
+ return m_pool.width();
+ }
+ int poolh() const {
+ return m_pool.height();
+ }
+ int curx() const {
+ return m_cur_x;
+ }
+ int cury() const {
+ return m_cur_y;
+ }
+ int getCurGemCell(int x, int y) const {
+ if ( m_cur.bitmap[y] & ( 1 << x ) ) return 1;
+ return 0;
+ }
+ int getNextGemCell(int next, int x, int y) const {
+ if ( m_next[next].bitmap[y] & ( 1 << x ) ) return 1;
+ return 0;
+ }
+ int getPoolCell(int x, int y) const {
+ return m_color_pool[y+32][x];
+ //if ( m_pool.row[y + 1] & ( 1 << x) ) return 1;
+ return 0;
+ }
+ bool alive () const {
+ return m_state != STATE_OVER;
+ }
+ public:
+ int m_state;
+ public:
+ Random m_rand;
+ AI::GameField m_pool;
+ AI::Gem m_cur;
+ int m_color_pool[64][32];
+ int m_hold;
+ int m_cur_x, m_cur_y;
+ int m_curnum;
+ signed char wallkick_spin;
+ AI::Gem m_next[128];
+ int m_next_num;
+ point m_base, m_size;
+ int m_clearLines;
+ int m_attack;
+ int m_max_combo;
+ int m_frames;
+ int m_drop_frame;
+ clear_info m_clear_info;
+ };
+
+}
diff --git a/tetris_ai/tetris.ico b/tetris_ai/tetris.ico
new file mode 100644
index 0000000..ff211c2
Binary files /dev/null and b/tetris_ai/tetris.ico differ
diff --git a/tetris_ai/tetris_ai.cpp b/tetris_ai/tetris_ai.cpp
new file mode 100644
index 0000000..716fc85
--- /dev/null
+++ b/tetris_ai/tetris_ai.cpp
@@ -0,0 +1,1898 @@
+#include "tetris_ai.h"
+#include
+#include
+#include
+#include
+
+#include "tetris_setting.h"
+#include
+
+#define GENMOV_W_MASK 15
+#define GEN_MOV_NO_PUSH 0
+
+namespace AI {
+ enum {
+ MOV_SCORE_DROP = 1,
+ MOV_SCORE_LR = 10,
+ MOV_SCORE_LR2 = 30,
+ MOV_SCORE_LLRR = 20,
+ MOV_SCORE_D = 50,
+ MOV_SCORE_DD = 100,
+ MOV_SCORE_SPIN = 50,
+ };
+
+ struct _ai_settings {
+ bool hash;
+ bool combo;
+ bool strategy_4w;
+ _ai_settings() {
+ hash = true;
+ combo = true;
+ strategy_4w = false;
+ }
+ } ai_settings[2];
+
+ void setAIsettings(int player, const char* key, int val) {
+ if ( strcmp(key, "hash") == 0 ) {
+ ai_settings[player].hash = val;
+ } else if ( strcmp(key, "combo") == 0 ) {
+ ai_settings[player].combo = val;
+ } else if ( strcmp(key, "4w") == 0 ) {
+ ai_settings[player].strategy_4w = val;
+ }
+ }
+
+ int Evaluate( int &clearScore, const AI_Param& ai_param, const GameField& last_pool, const GameField& pool, int cur_num,
+ int curdepth,
+ int total_clear_att, int total_clears, int clear_att, int clears, signed char wallkick_spin,
+ int lastCombo, int t_dis, int upcomeAtt
+ ) {
+ int score = 0;
+ // ²â¸ß¶È
+ //int last_min_y[32] = {0};
+ int min_y[32] = {0};
+ int emptys[32] = {0};
+ int maxy_index = 31, maxy_cnt = 0;
+ int maxy_flat_cnt = 0; // ×ƽ̨
+ int miny_val = 31;
+ int total_hole = 0;
+ int beg_y = -5;
+ const int pool_w = pool.width(), pool_h = pool.height();
+ //last_min_y[31] = -1;
+ min_y[31] = -1;
+ {
+ //while ( last_pool.row[beg_y] == 0 ) ++beg_y;
+ //for ( int x = 0; x < pool_w; ++x) {
+ // for ( int y = beg_y, ey = pool_h + 1; y <= ey; ++y) { // ÒªÓе×Ðб£»¤£¨pool.h£©£¬·ñÔò»á¹Ò
+ // if ( last_pool.row[y] & ( 1 << x ) ) {
+ // last_min_y[x] = y;
+ // break;
+ // }
+ // }
+ //}
+ beg_y = -5;
+ while ( pool.row[beg_y] == 0 ) ++beg_y;
+ for ( int x = 0; x < pool_w; ++x) {
+ for ( int y = beg_y, ey = pool_h + 1; y <= ey; ++y) { // ÒªÓе×Ðб£»¤£¨pool.h£©£¬·ñÔò»á¹Ò
+ if ( pool.row[y] & ( 1 << x ) ) {
+ min_y[x] = y;
+ miny_val = std::min(miny_val, y);
+ if ( y > min_y[maxy_index]) {
+ maxy_index = x;
+ maxy_cnt = 0;
+ } else if ( y == min_y[maxy_index]) {
+ ++maxy_cnt;
+ }
+ break;
+ }
+ }
+ }
+ int transitions = 0;
+ for ( int y = beg_y; y <= pool_h; ++y) {
+ int last = 1; //pool.row[y] & 1;
+ if ( pool.row[y] > 0 ) {
+ for ( int x = 0; x < pool_w; ++x) {
+ if ( pool.row[y] & ( 1 << x ) ) {
+ if ( last == 0 ) ++transitions;
+ last = 1;
+ } else {
+ if ( last == 1 ) ++transitions;
+ last = 0;
+ ++emptys[y];
+ }
+ }
+ } else {
+ emptys[y] = pool_w;
+ }
+ transitions += !last;
+ }
+ score += ai_param.v_transitions * transitions / 10;
+ }
+ min_y[pool_w] = min_y[pool_w-2];
+ //last_min_y[pool_w] = last_min_y[pool_w-2];
+
+ if ( pool.m_hold == GEMTYPE_I ) {
+ score -= ai_param.hold_I;
+ }
+ if ( pool.m_hold == GEMTYPE_T ) {
+ score -= ai_param.hold_T;
+ }
+ if ( maxy_cnt > 0 ) {
+ int ybeg = min_y[maxy_index];
+ unsigned rowdata = pool.row[ybeg-1];
+ int empty = ~rowdata & pool.m_w_mask;
+ for ( int b = maxy_index; b < pool_w; ++b ) {
+ if ( ybeg != min_y[b] ) continue;
+ int cnt = 1;
+ for ( int b1 = b + 1; empty & ( 1 << b1); ++b1) ++cnt;
+ if ( maxy_flat_cnt < cnt ) {
+ maxy_flat_cnt = cnt;
+ maxy_index = b;
+ }
+ }
+ }
+ // ¶´µÄÊýÁ¿
+ int x_holes[32] = {0}; // ˮƽ·½Ïò¶´µÄÊýÁ¿
+ int y_holes[32] = {0}; // ´¹Ö±·½Ïò¶´µÄÊýÁ¿
+ int x_op_holes[32] = {0}; // ˮƽ·½Ïò¶´µÄÊýÁ¿
+ //int last_pool_hole_score;
+ int pool_hole_score;
+ int pool_total_cell = 0;
+ //{ // last_pool
+ // int x_holes[32] = {0}; // ˮƽ·½Ïò¶´µÄÊýÁ¿
+ // int x_op_holes[32] = {0}; // ˮƽ·½Ïò¶´µÄÊýÁ¿
+ // int first_hole_y[32] = {0}; // ´¹Ö±·½Ïò×î½üµÄ¶´µÄy
+ // int hole_score = 0;
+ // const GameField& _pool = last_pool;
+ // for ( int x = 0; x < pool_w; ++x) {
+ // int last = 0, next;
+ // first_hole_y[x] = pool_h + 1;
+ // for ( int y = last_min_y[x] + 1; y <= pool_h; ++y, last = next) {
+ // if ( ( _pool.row[y] & ( 1 << x ) ) == 0) {
+ // next = 1;
+ // if ( x > 1 ) {
+ // if (last_min_y[x-1] > y && last_min_y[x-2] > y) {
+ // if ( last == 0) {
+ // hole_score += ai_param.open_hole;
+ // if ( y >= 0 ) ++x_op_holes[y];
+ // continue;
+ // }
+ // }
+ // }
+ // if ( x < pool_w - 2 ) {
+ // if (last_min_y[x+1] > y && last_min_y[x+2] > y) {
+ // if ( last == 0) {
+ // hole_score += ai_param.open_hole;
+ // if ( y >= 0 ) ++x_op_holes[y];
+ // continue;
+ // }
+ // }
+ // }
+ // if ( y >= 0 ) ++x_holes[y];
+ // if ( first_hole_y[x] > pool_h ) {
+ // first_hole_y[x] = y;
+ // }
+ // if ( last ) {
+ // hole_score += ai_param.hole / 4;
+ // } else {
+ // //score += (y - min_y[x]) * ai_param.hole_dis;
+ // //if ( x_holes[y] > 2 ) {
+ // // hole_score += ai_param.hole / 4;
+ // //} else
+ // if ( x_holes[y] >= 2 ) {
+ // hole_score += ai_param.hole * x_holes[y];
+ // } else {
+ // hole_score += ai_param.hole * 2;
+ // }
+ // }
+ // } else {
+ // next = 0;
+ // }
+ // }
+ // }
+ // //if(1)
+ // for ( int y = 0; y <= pool_h; ++y) {
+ // if ( x_holes[y] > 0 ) {
+ // hole_score += ai_param.hole_dis * (pool_h - y + 1);
+ // //int min_dis = pool_h;
+ // //for ( int x = 0; x < pool_w; ++x) {
+ // // if ( first_hole_y[x] == y ) {
+ // // min_dis = std::min(min_dis, y - min_y[x]);
+ // // }
+ // //}
+ // //if ( min_dis == 1 ) {
+ // // bool fill = true;
+ // // for ( int i = y - min_dis; i < y ; ++i ) {
+ // // int empty = ~pool.row[i] & pool.m_w_mask;
+ // // if ( empty & ( empty - 1) ) {
+ // // fill = false;
+ // // break;
+ // // }
+ // // }
+ // // if ( fill ) {
+ // // score -= ai_param.hole_dis;
+ // // }
+ // //}
+ // break;
+ // }
+ // }
+ // //for ( int y = 0; y <= pool_h; ++y) {
+ // // if ( x_holes[y] ) score += ai_param.has_hole_row;
+ // //}
+ // last_pool_hole_score = hole_score;
+ //}
+ { // pool
+ int first_hole_y[32] = {0}; // ´¹Ö±·½Ïò×î½üµÄ¶´µÄy
+ int x_renholes[32] = {0}; // ´¹Ö±Á¬Ðø¶´µÄÊýÁ¿
+ double hole_score = 0;
+ const GameField& _pool = pool;
+ for ( int x = 0; x < pool_w; ++x) {
+ for ( int y = min_y[x]; y <= pool_h; ++y ) {
+ if ( ( _pool.row[y] & ( 1 << x ) ) == 0 ) {
+ pool_total_cell++;
+ }
+ }
+ }
+ for ( int x = 0; x < pool_w; ++x) {
+ int last = 0, next;
+ first_hole_y[x] = pool_h + 1;
+ for ( int y = std::min(min_y[x] + 1, std::max(min_y[x-1] + 6, min_y[x+1] + 6)); y <= pool_h; ++y, last = next) {
+ if ( ( _pool.row[y] & ( 1 << x ) ) == 0 ) { //_pool.row[y] &&
+ double factor = ( y < 20 ? ( 1 + (20 - y) / 20.0 * 2 ) : 1.0);
+ y_holes[x]++;
+ next = 1;
+ if ( softdropEnable() ) {
+ if ( x > 1 ) {
+ if (min_y[x-1] > y && min_y[x-2] > y) {
+ //if ( last == 0) {
+ hole_score += ai_param.open_hole * factor;
+ if ( y >= 0 ) ++x_op_holes[y];
+ continue;
+ //}
+ }
+ }
+ if ( x < pool_w - 2 ) {
+ if (min_y[x+1] > y && min_y[x+2] > y) {
+ //if ( last == 0) {
+ hole_score += ai_param.open_hole * factor;
+ if ( y >= 0 ) ++x_op_holes[y];
+ continue;
+ //}
+ }
+ }
+ }
+ if ( y >= 0 ) ++x_holes[y];
+ if ( first_hole_y[x] > pool_h ) {
+ first_hole_y[x] = y;
+ }
+ int hs = 0;
+ if ( last ) {
+ hs += ai_param.hole / 2;
+ if ( y >= 0 ) ++x_renholes[y];
+ } else {
+ hs += ai_param.hole * 2;
+ }
+ {
+ //if ( x_holes[y] == 2 ) {
+ // hs -= ai_param.hole;
+ //} else if ( x_holes[y] >= 3 ){
+ // hs -= ai_param.hole * 2;
+ //}
+ ++total_hole;
+ }
+ hole_score += hs * factor;
+ } else {
+ next = 0;
+ }
+ }
+ }
+ //for ( int y = 0; y <= pool_h; ++y) {
+ // if ( x_holes[y] > 1 ) {
+ // int n = x_holes[y] - x_renholes[y];
+ // int hs = 0;
+ // if ( n == 2 )
+ // hs = ai_param.hole + x_renholes[y] * ai_param.hole / 2;
+ // else if ( n > 2 )
+ // hs = (n - 2) * ai_param.hole * 2 + x_renholes[y] * ai_param.hole / 2;
+ // hole_score -= hs * ( y < 10 ? ( 1 + (10 - y) / 10.0 * 2 ) : 1.0);
+ // score -= ai_param.v_transitions * x_holes[y] / 10;
+ // }
+ //}
+ for ( int y = 0; y <= pool_h; ++y) {
+ if ( x_holes[y] > 0 ) {
+ score += ai_param.hole_dis * (pool_h - y + 1);
+ break;
+ }
+ }
+ if(1)
+ if ( ai_param.hole_dis_factor ) {
+ for ( int y = 0, cnt = 5, index = -1; y <= pool_h; ++y) {
+ if ( x_holes[y] > 0 ) {
+ if ( cnt > 0 ) --cnt, ++index;
+ else break;
+ for ( int x = 0; x <= pool_w; ++x) {
+ if ( ( _pool.row[y] & ( 1 << x ) ) == 0) {
+ int h = y - min_y[x];
+ if ( h > 4 - index ) h = 4 + (h - (4 - index)) * cnt / 4;
+ //if ( h > 4 ) h = 4;
+ if ( h > 0 ) {
+ if ( ( _pool.row[y - 1] & ( 1 << x ) ) != 0) {
+ score += ai_param.hole_dis_factor * h * cnt / 5 / 2;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if(1)
+ if ( ai_param.hole_dis_factor2 ) {
+ int miny = pool_h;
+ for ( int y = 0, cnt = 0; y <= pool_h; ++y) {
+ if ( x_holes[y] > 0 ) {
+ if ( cnt < 4 ) ++cnt;
+ else break;
+ for ( int x = 0; x <= pool_w; ++x) {
+ if ( ( _pool.row[y] & ( 1 << x ) ) == 0) {
+ int vy = min_y[x] + cnt * 1;
+ if ( vy < miny ) miny = vy;
+ }
+ }
+ }
+ }
+ for ( int x = 0; x <= pool_w; ++x) {
+ int vy = min_y[x] + 6;
+ if ( vy < miny ) miny = vy;
+ }
+ double total_emptys = 0;
+ for ( int y = miny; y <= pool_h; ++y ) {
+ total_emptys += emptys[y] * ( y < 10 ? (10 + 10 - y ) / 10.0 : 1);
+ }
+ score += ai_param.hole_dis_factor2 * total_emptys / 4;
+ //score += ai_param.hole_dis_factor2 * (pool_h - miny);
+ //int h = 0;
+ //h = min_y[maxy_index] - miny - 1;
+ //if ( h > 0 )
+ // score += ai_param.hole_dis_factor2 * h;
+ //for ( int x = 0; x <= pool_w; ++x) {
+ // h += min_y[x] - miny;
+ //}
+ //if ( h > 0 )
+ // score += ai_param.hole_dis_factor2 * h * 2 / pool_w;
+ }
+ //for ( int y = 0; y <= pool_h; ++y) {
+ // if ( x_holes[y] ) score += ai_param.has_hole_row;
+ //}
+ pool_hole_score = hole_score;
+ }
+ score += pool_hole_score;
+#ifdef XP_RELEASE
+ // È«Ïû
+ if ( 0 ) //&& pool.getPCAttack() > 8 )
+ {
+ if ( beg_y > pool_h )
+ {
+ //score -= 1000;
+ clearScore -= (2000 * pool.combo - curdepth * 50) * 1.0;
+ }
+ else if ( pool_total_cell % 2 == 0 && beg_y > pool_h - 10 && total_hole < 2 )
+ {
+ int h_hole[32] = {0};
+ const GameField& _pool = pool;
+ int top_y = beg_y, hole_add = 0, height;
+ if ( pool_total_cell % 4 ) top_y -= 1;
+ //if ( x_holes[beg_y+1] > 0 ) top_y -= 2;
+ //if ( top_y > pool_h - 2 ) top_y -= 2;
+ height = pool_h + 1 - top_y;
+ if ( height < 3 ) height += 2;
+ for ( int x = 0; x < pool_w; ++x) {
+ h_hole[x] = min_y[x] - top_y + y_holes[x];
+ }
+
+ int last_cnt = 0, pc = 1, finish = 0, h4 = 0, cnt1 = 0, total_cnt = 0;
+ for ( int x = 0; x < pool_w; ++x) {
+ total_cnt += h_hole[x];
+ }
+ for ( int x = 0; x < pool_w; ++x) {
+ if ( h_hole[x] == 0 ) {
+ if ( last_cnt % 4 != 0 ) {
+ //pc = 0;
+ top_y -= 2;
+ height += 2;
+ x = -1;
+ last_cnt = 0, finish = 0, h4 = 0, cnt1 = 0, total_cnt += pool_w * 2;
+ {
+ for ( int x = 0; x < pool_w; ++x) {
+ h_hole[x] += 2;
+ }
+ }
+ }
+ else if ( last_cnt <= 0 || last_cnt >= total_cnt - 0 ) finish++;
+ else ++h4;
+ } else {
+ if ( min_y[x] == top_y + 1 ) {
+ ++cnt1;
+ }
+ last_cnt += h_hole[x];
+ }
+ }
+ //if ( pc && ( height <= 4 || last_cnt < height * 6 ) ) {
+ if ( pc && ( (total_cnt) / 4 * 0.8 + total_clear_att < pool.getPCAttack() ) ) { //&& last_cnt < 30 ) {
+ //if ( beg_y > pool_h - 4 ) score -= 500 * 2;
+ //int s = 1000 * 5 + finish * 400 - h4 * 10 - (height + total_clears) * 800 - cnt1 * 20;
+ //int s = (50 + finish * 10 + h4 * 1 - (height + total_clears) * 10 - cnt1 * 2) * 2.0;
+ int s = (30 + finish * 2 + h4 * 1 - (height /*+ total_clears * 2*/) * 3 /*- cnt1 * 2 */) * 1.0;
+ //int s = 100 * 2 + finish * 3 - h4 * 1 - (height + total_clears) * 10 - cnt1 * 2;
+ //score -= 1000 * 4 + finish * 100 - last_cnt * 30 - cnt1 * 50;
+ //score -= 500 * 4 + finish * 100 - last_cnt * 30 - cnt1 * 50 - curdepth * 100;
+ if ( s > 0 )
+ score -= s;
+ }
+ }
+ }
+#endif
+ // ¸ß¶È²î
+ {
+ //int n_maxy_index = maxy_index;
+ //if ( maxy_cnt != 0 ) n_maxy_index = -9;
+
+ int last = min_y[1];
+ for ( int x = 0; x <= pool_w; last = min_y[x], ++x) {
+ int v = min_y[x] - last;
+ if ( x == maxy_index ) {
+ x += maxy_flat_cnt;
+ continue;
+ }
+ int absv = abs(v);
+ if ( x + 1 == maxy_index && v > 0 || x - 2 == maxy_index && v < 0 ) ; //
+ else score += absv * ai_param.h_factor;
+ }
+ }
+ // ƽµØ
+ /*
+ {
+ int last = -1, len = 0;
+ for ( int x = 0; x <= pool_w; ++x) {
+ if ( last == min_y[x] ) {
+ ++len;
+ } else {
+ if ( len > 0 && len < 4) {
+ score -= ((len - 1) / 3 + 1) * ai_param.flat_factor;
+ }
+ len = 0;
+ last = min_y[x];
+ }
+ }
+ if ( len > 0 && len < 4) {
+ score -= ((len - 1) / 3 + 1) * ai_param.flat_factor;
+ }
+ }
+ */
+ int center = 10; // °ÚÂ¥¾¯½äÏß
+ double warning_factor = 1;
+ int h_variance_score = 0;
+ // Ëã·½²î
+ {
+ int avg = 0;
+ {
+ int sum = 0;
+ int sample_cnt = 0;
+ for ( int x = 0; x < pool_w; ++x) {
+ avg += min_y[x];
+ }
+ if (0)
+ {
+ double h = pool_h - (double)avg / pool_w;
+ score += int(ai_param.miny_factor * h * h / pool_h);
+ }
+ else
+ {
+ int h = std::min(std::min(min_y[gem_beg_x], min_y[gem_beg_x+1]), std::min(min_y[gem_beg_x+2], min_y[gem_beg_x+3]));
+ if ( h < 8 )
+ {
+ score += int(ai_param.miny_factor * ( 8 - h ) * 2);
+ }
+ }
+ if (1)
+ {
+ if ( avg < pool_w * center ) {
+ warning_factor = 0.0 + (double)avg / pool_w / center / 1;
+ }
+ }
+ // Æ«²îÖµ
+ {
+ int dif_sum = 0;
+ for ( int x = 0; x < pool_w; ++x) {
+ dif_sum += abs( min_y[x] * pool_w - avg );
+ }
+ score += ai_param.dif_factor * dif_sum / pool_w / pool_w;
+ }
+ }
+ // ¹¥»÷¼ÆËã
+ {
+ int s = 0;
+ int t_att = total_clear_att;
+ double t_clear = total_clears; //+ total_clears / 4.0;
+ if ( pool.b2b ) s -= 5; // b2b score
+ if ( t_clear > 0 ) {
+ s -= int( ((ai_param.clear_efficient) * ( t_att ) ) );
+ }
+ {
+ //if ( t_clear > t_att ) {
+ //int warning_factor = 0.5 + (double)avg / pool_w / center / 2;
+ s += int( warning_factor * t_clear * ai_param.clear_useless_factor);
+ //}
+ }
+ int cs = 0;
+ if ( cur_num == GEMTYPE_T && wallkick_spin && clears > 0 && ai_param.tspin > 0 ) { // TÏû¸½¼Ó·Ö£¬Òª±ÈT1/T2ÐÎ×´»ù±¾·Ö´óÒ»
+ s -= ai_param.hold_T;
+ if ( clears >= 3 ) {
+ if ( clear_att >= clears * 2 ) { // T3
+ cs -= int( warning_factor * (ai_param.tspin3 * 8 ) + ai_param.hole * 2 );
+ }
+ } else if ( clears >= 2 ) {
+ if ( clear_att >= clears * 2 ) { // T2
+ cs -= int( warning_factor * (ai_param.tspin * 5 + ai_param.open_hole / 2) );
+ }
+ } else if ( wallkick_spin == 1 ) { // T1
+ cs -= int( warning_factor * (ai_param.tspin * 1 + ai_param.open_hole / 2) );
+ } else if ( wallkick_spin == 2 ) { // Tmini
+ cs -= int( warning_factor * (ai_param.tspin / 2) );
+ }
+ }
+ clearScore += cs;
+#ifdef XP_RELEASE
+ if (1)
+ if ( clears > 0 && upcomeAtt >= 4 && ai_param.upcomeAtt > 0 ) {
+ int cur_s = 0;
+ cur_s -= int( ((ai_param.clear_efficient) * ( clear_att ) ) )
+ - int( warning_factor * clears * ai_param.clear_useless_factor);
+ if ( avg - (12 + upcomeAtt) * pool_w > 0 && cur_s + cs < 0 )
+ s -= (cur_s + cs) * ( avg - (12 + upcomeAtt) * pool_w ) * ai_param.upcomeAtt / pool_w / 10 / 20;
+ //if ( upcomeAtt >= 4 ) {
+ // if ( total_hole < 4 && avg - upcomeAtt * pool_w >= 8 * pool_w ) {
+ // s = s - s * ( 4 - total_hole ) * ai_param.upcomeAtt / 40;
+ // }
+ //}
+ }
+#endif
+ score += s;
+ }
+ //if ( clears ) {
+ // int center = 10; // °ÚÂ¥¾¯½äÏß
+ // double factor = 1;
+ // if ( avg < pool_w * center ) {
+ // factor = (double)avg / pool_w / center;
+ // }
+ // int s = 0;
+ // if ( pool_hole_score < last_pool_hole_score ) {
+ // s -= int( factor * (ai_param.clear_efficient * ( clear_att ) * ( clear_att ) / clears) );
+ // //s -= ai_param.open_hole;
+ // if ( clear_att >= 4 ) {
+ // if ( clear_att >= clears * 2 ) { // T2/T3
+ // clearScore -= int( factor * (ai_param.tspin * 4 + ai_param.open_hole + ai_param.clear_efficient * ( clear_att ) ) );
+ // s -= ai_param.hold_T;
+ // }
+ // }
+ // if ( clears > clear_att ) {
+ // s += int( factor * (ai_param.clear_efficient * ( clears - clear_att ) / 2 ) );
+ // }
+ // } else if ( pool_hole_score == last_pool_hole_score ) {
+ // s -= int( factor * (ai_param.clear_efficient * ( clear_att ) * ( clear_att ) / clears) );
+ // if ( clear_att >= 4 ) {
+ // if ( clear_att >= clears * 2 ) { // T2/T3
+ // clearScore -= int( factor * (ai_param.tspin * 4 + ai_param.open_hole + ai_param.clear_efficient * ( clear_att ) ) );
+ // s -= ai_param.hold_T;
+ // }
+ // } else if ( clear_att >= clears ) {
+ // if ( clear_att >= clears * 2 ) {
+ // if ( clears == 1 ) { // T1
+ // //s += int( factor * (ai_param.clear_efficient * ( clear_att ) / clears) );
+ // }
+ // }
+ // } else if ( avg < 8 * pool_w ) {
+ // //s += int(ai_param.hole * ( clears - clear_att ) * factor / 2 );
+ // if ( clears > clear_att ) {
+ // s += int( factor * (ai_param.clear_efficient * ( clears - clear_att ) / 2 ) );
+ // }
+ // } else if ( total_hole >= 1 || min_y[maxy_index] < pool_h - 4 ) {
+ // if ( clears > clear_att ) {
+ // s += int( factor * (ai_param.clear_efficient * ( clears - clear_att ) * 2 ) );
+ // }
+ // //if ( clear_att == 0 ) {
+ // // s += int( factor * (ai_param.hole * ( clears - clear_att ) ) / 3 );
+ // //}
+ // } else {
+ // if ( clears > clear_att ) {
+ // s += int( factor * (ai_param.clear_efficient * ( clears - clear_att ) * 4) );
+ // }
+ // //if ( clear_att == 0 ) {
+ // // s += int( factor * (ai_param.hole * ( clears - clear_att ) ) / 3 );
+ // //}
+ // }
+ // } else {
+ // s -= int( factor * (ai_param.clear_efficient * ( clear_att ) / clears) );
+ // if ( clears > clear_att ) {
+ // s += int( factor * (ai_param.clear_efficient * ( clears - clear_att ) * 4 ) );
+ // }
+ // }
+ // if ( pool.combo > 2 )
+ // {
+ // int combo = pool.combo - 2;
+ // //clearScore -= combo * combo * ai_param.combo_factor;
+ // }
+ // score += s;
+ //}
+ }
+
+ // ÌØÊâÐÎ×´Åж¨
+
+ // ¼ÆËã¿É¹¥»÷£¨TetrisºÍT2£©
+ //int t2_x[32] = {0};
+ if ( maxy_cnt == 0 )
+ {
+ //if ( maxy_index == 0 || maxy_index == pool_w - 1 ) {
+ // score += ai_param.att_col_sel_side;
+ //}
+ int ybeg = 0;
+ if ( softdropEnable() && maxy_index > 0 && maxy_index < pool_w - 1 && ai_param.tspin > 0 ) { // T1/T2»ù±¾ÐÎ×´·Ö
+ ybeg = std::max( min_y[maxy_index - 1], min_y[maxy_index + 1] );
+ if ( min_y[maxy_index - 1] == min_y[maxy_index + 1]
+ && x_holes[ybeg] == 0 && x_holes[ybeg-1] == 0
+ && x_op_holes[ybeg] == 0 && x_op_holes[ybeg-1] == 0
+ )
+ { // T×¼±¸
+ int cnt = 0;
+ if ( maxy_index > 1 && min_y[maxy_index - 2] >= min_y[maxy_index - 1] - 2 ) ++cnt;
+ if ( maxy_index < pool_w - 2 && min_y[maxy_index + 2] >= min_y[maxy_index + 1] - 2 ) ++cnt;
+ if ( cnt > 0 )
+ {
+ score -= int(warning_factor * ai_param.tspin);
+ if ( (~pool.row[ybeg] & pool.m_w_mask) == (1 << maxy_index) ) { // T1»ù´¡
+ score -= int(warning_factor * ai_param.tspin);
+ if ( (~pool.row[ybeg - 1] & pool.m_w_mask) == (7 << (maxy_index-1) ) ) { // ¿ÉT2ÍêÃÀ¿Ó
+ score -= int( warning_factor * (ai_param.tspin * cnt) );
+ }
+ }
+ }
+ } else if ( ybeg <= 6 && ybeg - t_dis > 1 || ybeg > 6 ) {
+ int row_data = pool.row[ybeg - 1];
+ if ( (row_data & ( 1 << (maxy_index-1) ) ) == 0 && (row_data & ( 1 << (maxy_index+1) ) ) == 0 // ¿ÓµÄ×óÓÒΪ¿Õ
+ && x_holes[ybeg] == 0 && x_holes[ybeg-1] == 0 // ÆäËüλÖÃÎÞ¶´
+ && x_op_holes[ybeg] == 0 && x_op_holes[ybeg-1] <= 1
+ )
+ {
+ // T¿ÓÐÎ×´
+ if ( ( pool.row[ybeg] & (1 << (maxy_index-1)) ) && ( pool.row[ybeg] & (1 << (maxy_index+1)) ) ) { // ¿ÓµÄÏÂÃæÁ½¿é´æÔÚ
+ if ( !!( pool.row[ybeg-2] & (1 << (maxy_index-1)) ) + !!( pool.row[ybeg-2] & (1 << (maxy_index+1)) ) == 1 ) { // ¿ÓµÄÉÏÃæµÄ¿é´æÔÚ
+ double s = 0;
+ //t2_x[maxy_index] = ybeg;
+ double factor = ybeg > 6 ? 0.5 : 1 - t_dis / 6.0 * 0.5;
+ if ( warning_factor < 1 )
+ factor = ybeg > 6 ? 1.0 / 5 : 1 / (1 + t_dis / 3.0);
+ s += ai_param.open_hole;
+ if ( (~pool.row[ybeg] & pool.m_w_mask) == (1 << maxy_index) ) { // ¿ÉT1
+ s += ai_param.tspin + ai_param.tspin * 1 * factor;
+ if ( (~row_data & pool.m_w_mask) == (7 << (maxy_index-1) ) ) { // ¿ÉT2ÍêÃÀ¿Ó
+ s += ai_param.tspin * 3 * factor;
+ // s -= ai_param.tspin * 3 / factor / 1;
+ }
+ } else {
+ s += ai_param.tspin * 1 + ai_param.tspin * 2 * factor / 2 ;
+ }
+ score -= int( warning_factor * s );
+ }
+ }
+ }
+ }
+ } else {
+ if ( maxy_index == 0 ) {
+ ybeg = min_y[maxy_index + 1];
+ } else {
+ ybeg = min_y[maxy_index - 1];
+ }
+ }
+ int readatt = 0;
+ int last = pool.row[ybeg];
+ for ( int y = ybeg; y <= pool_h; ++y ) {
+ if ( last != pool.row[y] ) break;
+ int row_data = ~pool.row[y] & pool.m_w_mask;
+ if ( (row_data & (row_data - 1)) != 0 ) break;
+ ++readatt;
+ }
+ if ( readatt > 4 ) readatt = 4;
+ //score -= readatt * ai_param.readyatt;
+
+ }
+ // T3 ÐÎ×´Åж¨
+ //3001
+ //2000
+ // 1101
+ // 1x01
+ // 1101
+ //
+ // 1003
+ // 0002
+ //1011
+ //10x1
+ //1011
+ if ( softdropEnable() && ai_param.tspin3 > 0 )
+ {
+ for ( int y = 3; y < pool_h; ++y ) {
+ if ( x_holes[y] == 0 ) continue;
+ for ( int x = 1; x < pool_w - 1; ++x ) {
+ if ( ( pool.row[y + 1] & ( 1 << x ) ) == 0 || ( pool.row[y + 1] & ( 1 << x ) ) == 0 ) {
+ continue; // ÉÏÏÂÎÞ¶´
+ }
+ int row_y[5];
+ for ( int i = 0; i < 5; ++i ) {
+ row_y[i] = ( (pool.row[y - 3 + i] | (3 << pool_w)) << 2 ) | 3;
+ }
+ if ( ( (row_y[3] >> (x + 1)) & ( 7 ) ) == 1 /*100*/ ) { // ÉÏͼÇé¿ö
+ if ( x == pool_w - 2 ) continue;
+ //if ( t2_x[x+1] == y ) continue; // ÅųýT2¿Ó
+ // ËùÓпյĵط½ÏÈÆ¥Åä
+ if ( ( (row_y[2] >> (x + 1)) & ( 7 ) ) != 3 /*110*/
+ //|| ( (row_y[4] >> (x + 1)) & ( 15 ) ) != 11 /*1101*/
+ || ( (row_y[4] >> (x + 1)) & ( 13 ) ) != 9 /*1011mask=1001*/
+ || ( (row_y[1] >> (x + 1)) & ( 7 ) ) != 0 /*000*/
+ //|| ( (row_y[0] >> (x + 1)) & ( 3 ) ) != 0 /*00*/
+ ) {
+ continue;
+ }
+ if ( min_y[x] != y - 1 || min_y[x-1] != y - 1 ) {
+ continue;
+ }
+ if ( ( row_y[0] & ( 1 << (x) ) ) == 0 && ( row_y[1] & ( 1 << (x) ) ) ) {
+ continue; // ¸ß´¦×ª½Ç
+ }
+ if ( min_y[x + 1] > y ) { // ¶´Åж¨
+ if ( x_holes[y - 1] > 0 || x_holes[y + 1] > 0 || x_holes[y] > 1
+ || x_op_holes[y - 1] > 0 || x_op_holes[y + 1] > 0 || x_op_holes[y] > 0)
+ {
+ continue;
+ }
+ } else {
+ if ( x_holes[y - 1] > 1 || x_holes[y + 1] > 1 || x_holes[y] > 2
+ || x_op_holes[y - 1] > 0 || x_op_holes[y + 1] > 0 || x_op_holes[y] > 0)
+ {
+ continue;
+ }
+ }
+ if ( ( (row_y[0] >> (x + 3)) & ( 1 ) ) == 0 && y - min_y[x + 2] > 3 ) continue;
+ int s = 0;
+ //tp3 * 1
+ s -= int( warning_factor * ai_param.tspin3 );// + int( warning_factor * ( ai_param.tspin * 4 + ai_param.open_hole ) );
+ score += s;
+ if ( y <= pool_h - 3 && ( pool.row[y + 3] & ( 1 << x ) ) == 0 ) {
+ int r = ~pool.row[y + 3] & pool.m_w_mask;
+ if ( ( r & ( r - 1 ) ) == 0 ) {
+ score -= int( warning_factor * (ai_param.tspin * 4 + ai_param.open_hole) );
+ }
+ }
+ //int full = 0;
+ {
+ int e = ~(pool.row[y + 1] | (1<> (x+1) ) & ( 7 ) ) == 4 /*001*/ ) { // ¾µÏñÇé¿ö
+ if ( x == 1 ) continue;
+ //if ( t2_x[x-1] == y ) continue; // ÅųýT2¿Ó
+ // ËùÓпյĵط½ÏÈÆ¥Åä
+ if ( ( (row_y[2] >> (x+1)) & ( 7 ) ) != 6 /*011*/
+ //|| ( (row_y[4] >> (x)) & ( 15 ) ) != 13 /*1011*/
+ || ( (row_y[4] >> (x)) & ( 11 ) ) != 9 /*1101mask=1001*/
+ || ( (row_y[1] >> (x + 1)) & ( 7 ) ) != 0 /*000*/
+ //|| ( (row_y[0] >> (x + 1)) & ( 3 ) ) != 0 /*00*/
+ ) {
+ continue;
+ }
+ if ( min_y[x] != y - 1 || min_y[x+1] != y - 1 ) {
+ continue;
+ }
+ if ( ( row_y[0] & ( 1 << (x + 4) ) ) == 0 && ( row_y[1] & ( 1 << (x + 4) ) ) ) {
+ continue; // ¸ß´¦×ª½Ç
+ }
+ if ( min_y[x - 1] > y ) { // ¶´Åж¨
+ if ( x_holes[y - 1] > 0 || x_holes[y + 1] > 0 || x_holes[y] > 1
+ || x_op_holes[y - 1] > 0 || x_op_holes[y + 1] > 0 || x_op_holes[y] > 0)
+ {
+ continue;
+ }
+ } else {
+ if ( x_holes[y - 1] > 1 || x_holes[y + 1] > 1 || x_holes[y] > 2
+ || x_op_holes[y - 1] > 0 || x_op_holes[y + 1] > 0 || x_op_holes[y] > 0)
+ {
+ continue;
+ }
+ }
+ if ( ( (row_y[0] >> (x + 1)) & ( 1 ) ) == 0 && y - min_y[x - 2] > 3 ) continue;
+ int s = 0;
+ // tp3 * 1
+ s -= int( warning_factor * ai_param.tspin3 );// + int( warning_factor * ( ai_param.tspin * 4 + ai_param.open_hole ) );
+ score += s;
+ if ( y <= pool_h - 3 && ( pool.row[y + 3] & ( 1 << x ) ) == 0 ) {
+ int r = ~pool.row[y + 3] & pool.m_w_mask;
+ if ( ( r & ( r - 1 ) ) == 0 ) {
+ score -= int( warning_factor * (ai_param.tspin * 4 + ai_param.open_hole) );
+ }
+ }
+ //int full = 0;
+ {
+ int e = ~(pool.row[y + 1] | (1< 0 && total_clears < 1 ) //&& lastCombo < 1 && pool.combo < 1 )
+ {
+ int maxy_4w = min_y[3];
+ maxy_4w = std::max(maxy_4w, min_y[4] );
+ maxy_4w = std::max(maxy_4w, min_y[5] );
+ maxy_4w = std::max(maxy_4w, min_y[6] );
+ int maxy_4w_combo = min_y[0];
+ maxy_4w_combo = std::max(maxy_4w_combo, min_y[1] );
+ maxy_4w_combo = std::max(maxy_4w_combo, min_y[2] );
+ maxy_4w_combo = std::max(maxy_4w_combo, min_y[pool_w-3] );
+ maxy_4w_combo = std::max(maxy_4w_combo, min_y[pool_w-2] );
+ maxy_4w_combo = std::max(maxy_4w_combo, min_y[pool_w-1] );
+ if ( (min_y[4] < min_y[3] && min_y[4] <= min_y[5])
+ || (min_y[5] < min_y[6] && min_y[5] <= min_y[4]) )
+ {
+ maxy_4w = -10;
+ } else
+ for ( int x = 0; x < pool_w; ++x ) {
+ if ( min_y[x] > maxy_4w ) {
+ maxy_4w = -10;
+ break;
+ }
+ }
+ while ( maxy_4w > 0 ) {
+ //if ( abs( min_y[0] - min_y[1] ) > 4 ) { maxy_4w = -10; break; }
+ //if ( abs( min_y[1] - min_y[2] ) > 4 ) { maxy_4w = -10; break; }
+ //if ( abs( min_y[pool_w-1] - min_y[pool_w-2] ) > 4 ) { maxy_4w = -10; break; }
+ //if ( abs( min_y[pool_w-2] - min_y[pool_w-3] ) > 4 ) { maxy_4w = -10; break; }
+ //if ( abs( min_y[2] - min_y[pool_w-3] ) > 7 ) { maxy_4w = -10; break; }
+ //int avg = (min_y[0] + min_y[1] + min_y[2] + min_y[pool_w-1] + min_y[pool_w-2] + min_y[pool_w-3]) / 6;
+ if ( (pool_h - maxy_4w) * 2 >= maxy_4w - maxy_4w_combo ) {
+ maxy_4w = -10;
+ break;
+ }
+ break;
+ }
+ if ( maxy_4w <= pool_h - 4 ) { // Èç¹ûÓг¬¹ý4¹¥»÷ÐоͲ»´î
+ maxy_4w = -10;
+ }
+ //if ( maxy_4w - maxy_4w_combo > 15 ) { // Èç¹ûÓг¬¹ý10Ô¤±¸ÐоͲ»´î
+ // maxy_4w = -10;
+ //}
+ if ( maxy_4w - maxy_4w_combo < 9 && pool_hole_score > ai_param.hole * (maxy_4w - maxy_4w_combo) / 2 ) {
+ maxy_4w = -10;
+ }
+
+ if ( maxy_4w > 8 ) {
+ bool has_hole = false;
+ for ( int y = maxy_4w - 1; y >= 0; --y ) {
+ if ( x_holes[y] || x_op_holes[y] ) {
+ has_hole = true;
+ break;
+ }
+ }
+ if ( ! has_hole && maxy_4w < pool_h ) {
+ if ( x_holes[maxy_4w]>1 || x_op_holes[maxy_4w]>1 ) {
+ has_hole = true;
+ }
+ }
+
+ if ( ! has_hole )
+ {
+ int sum = maxy_4w - min_y[3];
+ sum += maxy_4w - min_y[4];
+ sum += maxy_4w - min_y[5];
+ sum += maxy_4w - min_y[6];
+ int s = 0;
+ if ( sum == 3 || sum == 0 || sum == 4 ) //{ // - (pool_h - maxy_4w) - clears * lastCombo * 2
+ {
+ int hv = (maxy_4w - maxy_4w_combo + 1) * 1 + pool.combo;
+ s += ai_param.strategy_4w * ( hv ) + (ai_param.hole * 2 + ai_param.tspin * 4);
+ if ( sum > 0 ) {
+ s -= ai_param.strategy_4w / 3;
+ }
+ }
+ if ( s > 0 ) {
+ score -= s;
+ }
+ //if ( pool_h * 4 + 4 + x_holes[pool_h] + x_op_holes[pool_h] - min_y[0] - min_y[1] - min_y[2] - min_y[3] <= 4 ) {
+ // score -= 800 + (ai_param.hole * 2 + ai_param.tspin * 4);
+ //} else if ( pool_h * 4 + 4 + x_holes[pool_h] + x_op_holes[pool_h] - min_y[pool_w - 4] - min_y[pool_w - 3] - min_y[pool_w - 2] - min_y[pool_w - 1] <= 4 ) {
+ // score -= 800 + (ai_param.hole * 2 + ai_param.tspin * 4);
+ //}
+ }
+ }
+ }
+ // ÀÛ»ý·Ö
+ score += clearScore;
+ return score;
+ }
+ struct MovsState {
+ MovingSimple first;
+ GameField pool_last;
+ int att, clear;
+ signed short max_combo, max_att, combo;
+ signed short player, upcomeAtt;
+ MovsState() { upcomeAtt = max_combo = combo = att = clear = 0; }
+ bool operator < (const MovsState& m) const {
+#if 0
+ {
+ if ( max_combo > (combo - 1) * 32 && m.max_combo > (m.combo - 1) * 32 ) {
+ if ( att > 8 || m.att > 8 ) {
+ if ( abs(first.score - m.first.score) < 400 ) {
+ if ( att != m.att )
+ return att < m.att;
+ } else {
+ return first < m.first;
+ }
+ }
+ }
+ if ( ( max_combo > 6 * 32 || m.max_combo > 6 * 32 ) ) {
+ if ( max_combo != m.max_combo ) {
+ return max_combo < m.max_combo;
+ }
+ }
+ if ( ai_settings[player].strategy_4w )
+ if ( ( combo > 3 * 32 || m.combo > 3 * 32 ) ) {
+ if ( combo != m.combo ) {
+ return combo < m.combo;
+ }
+ }
+ }
+ //if (0)
+ if ( (pool_last.combo > 3 * 32 || m.pool_last.combo > 3 * 32) && pool_last.combo != m.pool_last.combo) {
+ return pool_last.combo < m.pool_last.combo;
+ }
+#else
+ //if ( abs(first.score - m.first.score) >= 900 ) {
+ // return first < m.first;
+ //}
+ //if ( (max_att >= 6 || m.max_att >= 6) && abs(max_att - m.max_att) >= 2 ) {
+ // return max_att < m.max_att;
+ //}
+ //else
+ if ( ai_settings[player].strategy_4w )
+ {
+ if ( ( max_combo > 6 * 32 || m.max_combo > 6 * 32 ) ) {
+ if ( max_combo != m.max_combo ) {
+ return max_combo < m.max_combo;
+ }
+ }
+ if ( (combo >= 32 * 3 || m.combo >= 32 * 3) && combo != m.combo) {
+ return combo < m.combo;
+ }
+ }
+ else
+ {
+ if ( ai_settings[player].combo ) {
+ if ( ( max_combo > 6 * 32 || m.max_combo > 6 * 32 ) ) {
+ if ( max_combo != m.max_combo ) {
+ return max_combo < m.max_combo;
+ }
+ }
+ if ( max_combo > combo && m.max_combo > m.combo && (m.max_combo > 4 * 32 || max_combo > 4 * 32) ) {
+ if ( (combo <= 2 * 32 && m.combo <= 2 * 32) ) {
+ if ( abs(first.score - m.first.score) < 1000 ) {
+ if ( att != m.att )
+ return att < m.att;
+ } else {
+ return first < m.first;
+ }
+ }
+ }
+ ////if ( ai_settings[player].strategy_4w ) {
+ // if ( ( combo > 3 * 32 || m.combo > 3 * 32 ) ) {
+ // if ( combo != m.combo ) {
+ // return combo < m.combo;
+ // }
+ // }
+ //}
+ }
+ //if (0)
+ //if ( (pool_last.combo > 32 || m.pool_last.combo > 32 ) )
+ //{
+ // int m1 = (max_combo!=pool_last.combo ? std::max(max_combo - 32 * 2, 0) * 2 : 0 ) + pool_last.combo;
+ // int m2 = (m.max_combo!=m.pool_last.combo ? std::max(m.max_combo - 32 * 2, 0) * 2 : 0 ) + m.pool_last.combo;
+ // if ( m1 != m2 ) {
+ // return m1 < m2;
+ // }
+ //}
+ if ( (combo > 32 * 2 || m.combo > 32 * 2) && combo != m.combo) {
+ return combo < m.combo;
+ }
+ }
+ //if ( (pool_last.combo > 1 || m.pool_last.combo > 1) && pool_last.combo != m.pool_last.combo) {
+ // return pool_last.combo < m.pool_last.combo;
+ //}
+#endif
+ return first < m.first;
+ }
+ };
+ struct GameState{
+ uint64 hash;
+ signed short hold, att, clear, combo, b2b;
+ GameState(uint64 _hash
+ ,signed short _hold
+ ,signed short _att
+ ,signed short _clear
+ ,signed short _combo
+ ,signed short _b2b
+ )
+ :hash(_hash)
+ ,hold(_hold)
+ ,att(_att)
+ ,combo(_combo)
+ ,b2b(_b2b)
+ {
+ }
+ bool operator < ( const GameState& gs) const {
+ if ( hash != gs.hash ) return hash < gs.hash;
+ if ( hold != gs.hold ) return hold < gs.hold;
+ if ( att != gs.att ) return att < gs.att;
+ if ( clear != gs.clear ) return clear < gs.clear;
+ if ( combo != gs.combo ) return combo < gs.combo;
+ if ( b2b != gs.b2b ) return b2b < gs.b2b;
+ return false;
+ }
+ bool operator == ( const GameState& gs) const {
+ if ( hash != gs.hash ) return false;
+ if ( hold != gs.hold ) return false;
+ if ( att != gs.att ) return false;
+ if ( clear != gs.clear ) return false;
+ if ( combo != gs.combo ) return false;
+ if ( b2b != gs.b2b ) return false;
+ return true;
+ };
+ };
+#define BEG_ADD_Y 1
+ MovingSimple AISearch(AI_Param ai_param, const GameField& pool, int hold, Gem cur, int x, int y, const std::vector& next, bool canhold, int upcomeAtt, int maxDeep, int & searchDeep, int level, int player) {
+ assert( cur.num != 0 );
+ typedef std::vector MovingList;
+ MovingList movs;
+ MovQueue que(16384);
+ MovQueue que2(16384);
+ movs.reserve(128);
+ int search_nodes = 0;
+ const int combo_step_max = 32;
+ searchDeep = 0;
+ upcomeAtt = std::min(upcomeAtt, pool.height() - gem_beg_y - 1);
+ if ( pool.combo > 0 && (pool.row[10] || pool.combo > 1) ) ai_param.strategy_4w = 0;
+ if ( ai_param.hole < 0 ) ai_param.hole = 0;
+ ai_param.hole += ai_param.open_hole;
+#if AI_WEAK_VERSION || defined(XP_RELEASE)
+ int ai_level_map[] = {
+ 4000, //LV0 search all
+ 4000, //LV1 search all
+ 4000,
+ 4000,
+ 4000, //lv4
+ 5000,
+ 6000,
+ 8000, //LV7
+ 16000,
+ 32000,
+ 64000,
+ };
+ int max_search_nodes = ai_level_map[level];
+ //if ( AI_SHOW && GAMEMODE_4W ) max_search_nodes *= 2;
+ if ( level <= 0 ) maxDeep = 0;
+ else if ( level <= 6 ) maxDeep = std::min(level, 6); // TODO: max deep
+ //else maxDeep = level;
+#else
+ int max_search_nodes = 4000;
+#endif
+ int next_add = 0;
+ if ( pool.m_hold == 0 ) {
+ next_add = 1;
+ if ( next.empty() ) {
+ return MovingSimple();
+ }
+ }
+
+ {
+ const GameField& _pool = pool;
+ int t_dis = 14;
+ if ( _pool.m_hold != GEMTYPE_T ) {
+ for ( size_t i = 0; i < next.size(); ++i ) {
+ if ( next[i].num == GEMTYPE_T ) {
+ t_dis = i;
+ break;
+ }
+ }
+ } else {
+ t_dis = 0;
+ }
+ GenMoving(_pool, movs, cur, x, y, 0);
+ for (MovingList::iterator it = movs.begin(); it != movs.end(); ++it) {
+ ++search_nodes;
+ MovsState &ms = que.append();
+ ms.pool_last = _pool;
+ signed char wallkick_spin = it->wallkick_spin;
+ wallkick_spin = ms.pool_last.WallKickValue(cur.num, (*it).x, (*it).y, (*it).spin, wallkick_spin);
+ ms.pool_last.paste((*it).x, (*it).y, getGem(cur.num, (*it).spin));
+ int clear = ms.pool_last.clearLines( wallkick_spin );
+ int att = ms.pool_last.getAttack( clear, wallkick_spin );
+ ms.player = player;
+ ms.clear = clear;
+ ms.att = att;
+ if ( clear > 0 ) {
+ ms.combo = _pool.combo * combo_step_max + combo_step_max;// + 1 - clear;
+ ms.upcomeAtt = std::max(0, upcomeAtt - att);
+ } else {
+ ms.combo = 0;
+ ms.upcomeAtt = -upcomeAtt;
+ ms.pool_last.minusRow(upcomeAtt);
+ }
+ ms.max_att = att;
+ ms.max_combo = ms.combo; //ms_last.max_combo + getComboAttack( ms.pool_last.combo );
+ ms.first = *it;
+ ms.first.score2 = 0;
+ ms.first.score = Evaluate(ms.first.score2, ai_param, pool, ms.pool_last, cur.num, 0, ms.att, ms.clear, att, clear, wallkick_spin, _pool.combo, t_dis, upcomeAtt);
+ if ( wallkick_spin == 0 && it->wallkick_spin ) ms.first.score += 1;
+ que.push_back();
+ }
+ }
+ if ( canhold && ! hold &&
+ (
+ pool.m_hold == 0
+ && !next.empty() && ! pool.isCollide(gem_beg_x, gem_beg_y, getGem( next[0].num, 0 ) )
+ || ! pool.isCollide(gem_beg_x, gem_beg_y, getGem( pool.m_hold, 0 ) )
+ )
+ )
+ {
+ int cur_num;
+ if ( pool.m_hold ) {
+ cur_num = pool.m_hold;
+ } else {
+ cur_num = next[0].num;
+ }
+ if ( cur_num != cur.num ) {
+ GameField _pool = pool;
+ _pool.m_hold = cur.num;
+ int t_dis = 14;
+ if ( _pool.m_hold != GEMTYPE_T ) {
+ for ( size_t i = 0; i + next_add < next.size(); ++i ) {
+ if ( next[i + next_add].num == GEMTYPE_T ) {
+ t_dis = i;
+ break;
+ }
+ }
+ } else {
+ t_dis = 0;
+ }
+ int x = gem_beg_x, y = gem_beg_y;
+ Gem cur = getGem( cur_num, 0 );
+ GenMoving(_pool, movs, cur, x, y, 1);
+ for (MovingList::iterator it = movs.begin(); it != movs.end(); ++it) {
+ ++search_nodes;
+ MovsState &ms = que.append();
+ ms.pool_last = _pool;
+ signed char wallkick_spin = it->wallkick_spin;
+ wallkick_spin = ms.pool_last.WallKickValue(cur_num, (*it).x, (*it).y, (*it).spin, wallkick_spin);
+ ms.pool_last.paste((*it).x, (*it).y, getGem(cur_num, (*it).spin));
+ int clear = ms.pool_last.clearLines( wallkick_spin );
+ int att = ms.pool_last.getAttack( clear, wallkick_spin );
+ ms.player = player;
+ ms.clear = clear;
+ ms.att = att;
+ if ( clear > 0 ) {
+ ms.combo = _pool.combo * combo_step_max + combo_step_max;// + 1 - clear;
+ ms.upcomeAtt = std::max(0, upcomeAtt - att);
+ } else {
+ ms.combo = 0;
+ ms.upcomeAtt = -upcomeAtt;
+ ms.pool_last.minusRow(upcomeAtt);
+ }
+ ms.max_att = att;
+ ms.max_combo = ms.combo; //ms_last.max_combo + getComboAttack( ms.pool_last.combo );
+ ms.first = *it;
+ ms.first.score2 = 0;
+ ms.first.score = Evaluate(ms.first.score2, ai_param, pool, ms.pool_last, cur.num, 0, ms.att, ms.clear, att, clear, wallkick_spin, _pool.combo, t_dis, upcomeAtt);
+ if ( wallkick_spin == 0 && it->wallkick_spin ) ms.first.score += 1;
+ que.push_back();
+ }
+ }
+ }
+ if ( que.empty() ) {
+ return MovingSimple();
+ }
+ int sw_map1[16][8] = {
+ {999, 4, 2, 2, 2, 2, 2, 2},
+ {999, 4, 4, 2, 2, 2, 2, 2},
+ { 50, 999, 4, 2, 2, 2, 2, 2},
+ { 20, 40, 999, 4, 2, 2, 2, 2},
+ { 15, 30, 20, 999, 2, 2, 2, 2}, // 4
+ { 13, 25, 15, 12, 999, 2, 2, 2},
+ { 14, 27, 17, 14, 20, 999, 3, 2},
+ //{ 15, 27, 17, 15, 20, 999, 3, 2},
+ //{ 20, 30, 20, 20, 20, 100, 999, 999},
+ { 20, 30, 25, 20, 20, 100, 999, 999}, // 7
+ { 25, 60, 50, 40, 40, 40, 500, 999},
+ //{ 30, 50, 40, 30, 30, 25, 25, 20},
+ //{ 30, 150, 130, 130, 110, 100, 100, 80},
+ { 30, 90, 75, 60, 60, 60, 60, 9999}, // 9
+ //{ 50, 720, 720, 480, 480, 480, 480, 480}, // 9 PC
+ //{ 30, 90, 80, 60, 60, 60, 60, 60},
+ { 30, 240, 200, 200, 180, 160, 160, 9999}, // 10
+ };
+ int sw_map2[16][8] = {
+ {999, 999, 999, 999, 999, 999, 999, 999},
+ { 60, 60, 999, 999, 999, 999, 999, 999},
+ { 40, 40, 40, 999, 999, 999, 999, 999},
+ { 30, 60, 60, 60, 999, 999, 999, 999},
+ { 25, 45, 30, 30, 30, 999, 999, 999}, // 4
+ { 25, 35, 35, 30, 30, 30, 999, 999},
+ { 25, 35, 35, 35, 30, 25, 25, 999},
+ { 25, 45, 40, 30, 30, 30, 30, 30}, // 7
+ { 25, 90, 80, 60, 50, 50, 50, 50},
+ //{ 30, 220, 200, 200, 160, 150, 150, 120},
+ { 30, 150, 130, 100, 80, 80, 50, 50}, // 9
+ //{ 30, 150, 130, 130, 130, 130, 130, 130}, // 9 PC
+ { 30, 300, 200, 180, 120, 100, 80, 80}, // 10
+ //{ 30, 400, 400, 300, 300, 300, 300, 200}, // 10
+ };
+ int sw_map3[16][8] = {
+ {999, 999, 999, 999, 999, 999, 999, 999},
+ { 60, 60, 999, 999, 999, 999, 999, 999},
+ { 40, 40, 40, 999, 999, 999, 999, 999},
+ { 30, 60, 60, 60, 999, 999, 999, 999},
+ { 25, 45, 30, 30, 30, 999, 999, 999}, // 4
+ { 25, 35, 35, 30, 30, 30, 999, 999},
+ { 25, 35, 35, 35, 30, 25, 25, 999},
+ { 25, 45, 40, 30, 30, 30, 30, 30}, // 7
+ { 25, 90, 80, 60, 50, 40, 30, 30},
+ //{ 30, 220, 200, 200, 160, 150, 150, 120},
+ { 30, 120, 100, 80, 70, 60, 50, 40}, // 9
+ //{ 30, 150, 130, 130, 130, 130, 130, 130}, // 9 PC
+ { 30, 240, 200, 160, 120, 90, 70, 60}, // 10
+ };
+ MovQueue * pq_last = &que2, * pq = &que;
+ searchDeep = 1;
+ for ( int depth = 0; search_nodes < max_search_nodes && depth < maxDeep; searchDeep = ++depth ) { //d < maxDeep
+ std::swap(pq_last, pq);
+#if defined(XP_RELEASE)
+ int (*sw_map)[8] = sw_map1;
+ if ( ai_settings[player].hash ) {
+ sw_map = sw_map2;
+ //if ( ai_param.strategy_4w > 0 ) {
+ // sw_map = sw_map3;
+ //}
+ }
+ int search_base_width = sw_map[level][0];// - sw_map[level][0] / 6;
+ int search_wide = 1000;
+ if ( depth > 7 ) search_wide = sw_map[level][7];
+ else search_wide = sw_map[level][depth];
+#else
+ int sw_map[16][8] = {
+ {15, 30, 20, 15, 10, 10, 10, 10},
+ };
+ int search_wide = 0;
+ if ( depth > 7 ) search_wide = sw_map[0][7];
+ else search_wide = sw_map[0][depth];
+ int search_base_width = sw_map[0][0];;
+#endif
+ //int seach_select_best = (level <= 3 ? 1000 : (std::min(search_wide, 30) ) );
+ int seach_select_best = std::min(search_wide - search_wide / 4, search_base_width);
+ if ( level <= 3 ) {
+ seach_select_best = search_wide - search_wide / 4;
+ }
+ if ( seach_select_best < search_base_width ) {
+ seach_select_best = std::min(search_base_width, std::max(15, search_wide) );
+ }
+ pq->clear();
+ int max_combo = 3;
+ int max_search_score = pq_last->back().first.score;
+ {
+ for ( int s = pq_last->size(), i = s / 2; i < s; ++i ) {
+ max_search_score = std::max( max_search_score, pq_last->queue[i].first.score );
+ }
+ max_search_score = (max_search_score * 2 + pq_last->front().first.score) / 3;
+ }
+ std::set gsSet;
+ for ( int pqmax_size = (int)pq_last->size(),
+ pq_size = (int)pq_last->size(),
+ stop_size = std::max(0, (int)pq_size - search_wide);
+ pq_size > stop_size;
+
+ --pq_size, pq_last->dec_size())
+ {
+
+ if ( pq_size > 1 ) pq_last->pop_back();
+
+ const MovsState &ms_last = pq_last->back();
+ if ( pq_size != pqmax_size && ms_last.first.score > 50000000 ) { // ³¬¸ß·Ö¼ôÖ¦
+ break;
+ }
+ if ( search_nodes >= max_search_nodes ) {
+ //MovsState ms_last = pq_last->back();
+ pq->push(ms_last);
+ continue;
+ }
+ max_combo = std::max( max_combo, (int)ms_last.pool_last.combo );
+ if (0)
+ if ( pq_size != pqmax_size ) { // ³¬¸ßcomboºóµÄÎÞcombo¼ôÖ¦
+ if ( ms_last.pool_last.combo > 0 && max_combo > 5 && ms_last.pool_last.combo < max_combo - 1 ) {
+ break;
+ }
+ //if ( ms_last.pool_last.combo > 0 && max_combo > 3 ) {
+ // if ( max_combo - ms_last.pool_last.combo != 0 && max_combo - ms_last.pool_last.combo <= 1 ) {
+ // break;
+ // }
+ //}
+ }
+ if (0)
+ if ( depth > 0 && maxDeep > 2 && ms_last.first.score > max_search_score ) {
+ if ( pq_size + 2 < pqmax_size ) {
+ break;
+ }
+ }
+ if ( ai_settings[player].hash )
+ {
+ GameState gs(ms_last.pool_last.hashval, ms_last.pool_last.m_hold, ms_last.att, ms_last.clear, ms_last.combo, ms_last.pool_last.b2b);
+ if ( gsSet.find(gs) == gsSet.end() ) {
+ gsSet.insert(gs);
+ } else {
+ continue;
+ }
+ }
+ int hold = 0;
+ //if ( !ms_last.first.movs.empty() && ms_last.first.movs[0] == Moving::MOV_HOLD ) hold = 1;
+ if ( !ms_last.first.hold ) hold = 1;
+ int t_dis = 14;
+ int d_pos = depth;
+ if ( next_add && ms_last.pool_last.m_hold ) d_pos = depth + 1;
+ if ( d_pos >= next.size() ) {
+ pq->push(ms_last);
+ continue;
+ }
+ int cur_num = next[d_pos].num;
+ if ( ms_last.pool_last.m_hold != GEMTYPE_T ) {
+ for ( size_t i = 0; d_pos + 1 + i < next.size(); ++i ) {
+ if ( next[d_pos + 1 + i].num == GEMTYPE_T ) {
+ t_dis = i;
+ break;
+ }
+ }
+ } else {
+ t_dis = 0;
+ }
+ if ( BEG_ADD_Y && ms_last.upcomeAtt < 0 )
+ GenMoving(ms_last.pool_last, movs, getGem( cur_num, 0 ), AI::gem_beg_x, AI::gem_beg_y - ms_last.upcomeAtt, 0 );
+ else
+ GenMoving(ms_last.pool_last, movs, getGem( cur_num, 0 ), AI::gem_beg_x, AI::gem_beg_y, 0 );
+ if ( movs.empty() ) {
+ MovsState ms = ms_last;
+ ms.first.score += 100000000;
+ pq->push(ms);
+ continue; // ³öÏ־͹ҵĻ°Ê¹ÓÃholdµÄÇé¿ö²»ÄÜÅÜ
+ } else {
+ MovQueue p(movs.size());
+ for (size_t i = 0; i < movs.size() ; ++i) {
+ ++search_nodes;
+ MovsState &ms = p.append();
+ {
+ ms.first = ms_last.first;
+ ms.pool_last = ms_last.pool_last;
+ signed char wallkick_spin = movs[i].wallkick_spin;
+ wallkick_spin = ms.pool_last.WallKickValue(cur_num, movs[i].x, movs[i].y, movs[i].spin, wallkick_spin);
+ ms.pool_last.paste(movs[i].x, movs[i].y, getGem(cur_num, movs[i].spin));
+ int clear = ms.pool_last.clearLines( wallkick_spin );
+ int att = ms.pool_last.getAttack( clear, wallkick_spin );
+ ms.player = player;
+ ms.clear = clear + ms_last.clear;
+ ms.att = att + ms_last.att;
+ ms.upcomeAtt = ms_last.upcomeAtt;
+ if ( clear > 0 ) {
+ ms.combo = ms_last.combo + combo_step_max + 1 - clear;
+ if ( ms_last.upcomeAtt > 0 )
+ ms.upcomeAtt = std::max(0, ms_last.upcomeAtt - att);
+ } else {
+ ms.combo = 0;
+ if ( ms_last.upcomeAtt > 0 ) {
+ ms.upcomeAtt = -ms_last.upcomeAtt;
+ ms.pool_last.minusRow(ms_last.upcomeAtt);
+ }
+ }
+ ms.max_att = std::max((int)ms_last.max_att, ms_last.att + att);
+ ms.max_combo = std::max(ms_last.max_combo, ms.combo); //ms_last.max_combo + getComboAttack( ms.pool_last.combo );
+ ms.first.score2 = ms_last.first.score2;
+ ms.first.score = Evaluate(ms.first.score2, ai_param,
+ pool,
+ ms.pool_last, cur_num, depth + 1, ms.att, ms.clear, att, clear, wallkick_spin, ms_last.pool_last.combo, t_dis, ms_last.upcomeAtt);
+ if ( wallkick_spin == 0 && movs[i].wallkick_spin ) ms.first.score += 1;
+ }
+ p.push_back();
+ }
+ for ( int i = 0; i < seach_select_best && ! p.empty(); ++i) {
+ pq->push(p.front());
+ p.pop_back();
+ p.dec_size();
+ }
+ }
+ if ( canhold && depth + next_add < next.size())
+ {
+ MovsState ms_last = pq_last->back();
+ //int cur_num = ms_last.pool_last.m_hold;
+ int cur_num;
+ int d_pos = depth + next_add;
+ if ( ms_last.pool_last.m_hold != next[d_pos].num ) {
+ if ( ms_last.pool_last.m_hold ) {
+ cur_num = ms_last.pool_last.m_hold;
+ } else {
+ cur_num = next[d_pos].num;
+ }
+ ms_last.pool_last.m_hold = next[d_pos].num;
+ if ( ms_last.pool_last.m_hold != GEMTYPE_T ) {
+ t_dis -= next_add;
+ if ( t_dis < 0 ) {
+ for ( size_t i = 0; d_pos + 1 + i < next.size(); ++i ) {
+ if ( next[i + 1 + d_pos].num == GEMTYPE_T ) {
+ t_dis = i;
+ break;
+ }
+ }
+ }
+ } else {
+ t_dis = 0;
+ }
+ if ( BEG_ADD_Y && ms_last.upcomeAtt < 0 )
+ GenMoving(ms_last.pool_last, movs, getGem( cur_num, 0 ), AI::gem_beg_x, AI::gem_beg_y - ms_last.upcomeAtt, 1 );
+ else
+ GenMoving(ms_last.pool_last, movs, getGem( cur_num, 0 ), AI::gem_beg_x, AI::gem_beg_y, 1 );
+ if ( movs.empty() ) {
+ MovsState ms = ms_last;
+ ms.first.score += 100000000;
+ pq->push(ms);
+ } else {
+ MovQueue p(movs.size());
+ for (size_t i = 0; i < movs.size() ; ++i) {
+ ++search_nodes;
+ MovsState &ms = p.append();
+ {
+ ms.first = ms_last.first;
+ ms.pool_last = ms_last.pool_last;
+ signed char wallkick_spin = movs[i].wallkick_spin;
+ wallkick_spin = ms.pool_last.WallKickValue(cur_num, movs[i].x, movs[i].y, movs[i].spin, wallkick_spin);
+ ms.pool_last.paste(movs[i].x, movs[i].y, getGem(cur_num, movs[i].spin));
+ int clear = ms.pool_last.clearLines( wallkick_spin );
+ int att = ms.pool_last.getAttack( clear, wallkick_spin );
+ ms.player = player;
+ ms.clear = clear + ms_last.clear;
+ ms.att = att + ms_last.att;
+ ms.upcomeAtt = ms_last.upcomeAtt;
+ if ( clear > 0 ) {
+ ms.combo = ms_last.combo + combo_step_max + 1 - clear;
+ if ( ms_last.upcomeAtt > 0 )
+ ms.upcomeAtt = std::max(0, ms_last.upcomeAtt - att);
+ } else {
+ ms.combo = 0;
+ if ( ms_last.upcomeAtt > 0 ) {
+ ms.upcomeAtt = -ms_last.upcomeAtt;
+ ms.pool_last.minusRow(ms_last.upcomeAtt);
+ }
+ }
+ ms.max_att = std::max((int)ms_last.max_att, ms_last.att + att);
+ ms.max_combo = std::max(ms_last.max_combo, ms.combo); //ms_last.max_combo + getComboAttack( ms.pool_last.combo );
+ ms.first.score2 = ms_last.first.score2;
+ ms.first.score = Evaluate(ms.first.score2, ai_param,
+ pool,
+ ms.pool_last, cur_num, depth + 1, ms.att, ms.clear, att, clear, wallkick_spin, ms_last.pool_last.combo, t_dis, ms_last.upcomeAtt);
+ if ( wallkick_spin == 0 && movs[i].wallkick_spin ) ms.first.score += 1;
+ }
+ p.push_back();
+ }
+ for ( int i = 0; i < seach_select_best && ! p.empty(); ++i) {
+ pq->push(p.front());
+ p.pop_back();
+ p.dec_size();
+ }
+ }
+ }
+ }
+ }
+ if ( pq->empty() ) {
+ return MovingSimple();
+ }
+ }
+ //if (0)
+ if ( ai_settings[player].hash && canhold && search_nodes < max_search_nodes ) { // extra search
+ std::swap(pq_last, pq);
+ pq->clear();
+ int depth = searchDeep - 1;
+#if defined(XP_RELEASE)
+ int (*sw_map)[8] = sw_map1;
+ if ( ai_settings[player].hash )
+ sw_map = sw_map2;
+ int search_base_width = sw_map[level][0];// - sw_map[level][0] / 6;
+ int search_wide = 1000;
+ if ( depth > 7 ) search_wide = sw_map[level][7];
+ else search_wide = sw_map[level][depth];
+#else
+ int search_wide = (depth < 2 ? 20 : 20);
+ int search_base_width = 20;
+#endif
+ //int seach_select_best = (level <= 3 ? 1000 : (std::min(search_wide, 30) ) );
+ int seach_select_best = std::min(search_wide - search_wide / 4, search_base_width);
+ if ( level <= 3 ) {
+ seach_select_best = search_wide - search_wide / 4;
+ }
+ if ( seach_select_best < search_base_width ) {
+ seach_select_best = std::min(search_base_width, std::max(15, search_wide) );
+ }
+
+ std::set gsSet;
+ for ( int pqmax_size = (int)pq_last->size(),
+ pq_size = (int)pq_last->size(),
+ stop_size = std::max(0, (int)pq_size - search_wide);
+ pq_size > stop_size;
+
+ --pq_size, pq_last->dec_size())
+ {
+
+ if ( pq_size > 1 ) pq_last->pop_back();
+
+ const MovsState &ms_last = pq_last->back();
+ if ( pq_size != pqmax_size && ms_last.first.score > 50000000 ) { // ³¬¸ß·Ö¼ôÖ¦
+ break;
+ }
+ pq->push(ms_last);
+ if ( search_nodes >= max_search_nodes ) {
+ continue;
+ }
+ //max_combo = std::max( max_combo, (int)ms_last.pool_last.combo );
+ {
+ GameState gs(ms_last.pool_last.hashval, ms_last.pool_last.m_hold, ms_last.att, ms_last.clear, ms_last.combo, ms_last.pool_last.b2b);
+ if ( gsSet.find(gs) == gsSet.end() ) {
+ gsSet.insert(gs);
+ } else {
+ continue;
+ }
+ }
+ //if ( !ms_last.first.movs.empty() && ms_last.first.movs[0] == Moving::MOV_HOLD ) hold = 1;
+ if ( !ms_last.first.hold ) {
+ continue;
+ }
+ int t_dis = 14;
+ int d_pos = depth + next_add;
+ int cur_num = ms_last.pool_last.m_hold;
+ for ( size_t i = 0; d_pos + 1 + i < next.size(); ++i ) {
+ if ( next[d_pos + 1 + i].num == GEMTYPE_T ) {
+ t_dis = i;
+ break;
+ }
+ }
+ if ( BEG_ADD_Y && ms_last.upcomeAtt < 0 )
+ GenMoving(ms_last.pool_last, movs, getGem( cur_num, 0 ), AI::gem_beg_x, AI::gem_beg_y - ms_last.upcomeAtt, 0 );
+ else
+ GenMoving(ms_last.pool_last, movs, getGem( cur_num, 0 ), AI::gem_beg_x, AI::gem_beg_y, 0 );
+ if ( movs.empty() ) {
+ MovsState ms = ms_last;
+ ms.first.score += 100000000;
+ pq->push(ms);
+ } else {
+ MovQueue p;
+ for (size_t i = 0; i < movs.size() ; ++i) {
+ ++search_nodes;
+ MovsState &ms = p.append();
+ {
+ ms.first = ms_last.first;
+ ms.pool_last = ms_last.pool_last;
+ signed char wallkick_spin = movs[i].wallkick_spin;
+ wallkick_spin = ms.pool_last.WallKickValue(cur_num, movs[i].x, movs[i].y, movs[i].spin, wallkick_spin);
+ ms.pool_last.paste(movs[i].x, movs[i].y, getGem(cur_num, movs[i].spin));
+ int clear = ms.pool_last.clearLines( wallkick_spin );
+ int att = ms.pool_last.getAttack( clear, wallkick_spin );
+ ms.player = player;
+ ms.clear = clear + ms_last.clear;
+ ms.att = att + ms_last.att;
+ ms.upcomeAtt = ms_last.upcomeAtt;
+ if ( clear > 0 ) {
+ ms.combo = ms_last.combo + combo_step_max + 1 - clear;
+ if ( ms_last.upcomeAtt > 0 )
+ ms.upcomeAtt = std::max(0, ms_last.upcomeAtt - att);
+ } else {
+ ms.combo = 0;
+ if ( ms_last.upcomeAtt > 0 ) {
+ ms.upcomeAtt = -ms_last.upcomeAtt;
+ ms.pool_last.minusRow(ms_last.upcomeAtt);
+ }
+ }
+ ms.max_att = std::max((int)ms_last.max_att, ms_last.att + att);
+ ms.max_combo = std::max(ms_last.max_combo, ms.combo); //ms_last.max_combo + getComboAttack( ms.pool_last.combo );
+ ms.first.score2 = ms_last.first.score2;
+ ms.first.score = Evaluate(ms.first.score2, ai_param,
+ pool,
+ ms.pool_last, cur_num, depth + 1, ms.att, ms.clear, att, clear, wallkick_spin, ms_last.pool_last.combo, t_dis, ms_last.upcomeAtt);
+ }
+ p.push_back();
+ }
+ for ( int i = 0; i < seach_select_best && ! p.empty(); ++i) {
+ pq->push(p.front());
+ p.pop_back();
+ p.dec_size();
+ }
+ }
+ }
+ if ( pq->empty() ) {
+ return MovingSimple();
+ }
+ }
+ {
+ MovsState m, c;
+ std::swap(pq_last, pq);
+ pq_last->pop(m);
+ if ( ! GAMEMODE_4W ) {
+ while ( ! pq_last->empty() ) {
+ pq_last->pop(c);
+ if ( m.first.score > c.first.score ) {
+ m = c;
+ }
+ }
+ }
+ return m.first;
+ }
+ }
+ struct AI_THREAD_PARAM {
+ TetrisAI_t func;
+ Moving* ret_mov;
+ int* flag;
+ AI_Param ai_param;
+ GameField pool;
+ int hold;
+ Gem cur;
+ int x;
+ int y;
+ std::vector next;
+ bool canhold;
+ int upcomeAtt;
+ int maxDeep;
+ int *searchDeep;
+ int level;
+ int player;
+ AI_THREAD_PARAM(TetrisAI_t _func, Moving& _ret_mov, int& _flag, const AI_Param& _ai_param, const GameField& _pool, int _hold, Gem _cur, int _x, int _y, const std::vector& _next, bool _canhold, int _upcomeAtt, int _maxDeep, int & _searchDeep, int _level, int _player) {
+ func = _func;
+ ret_mov = &_ret_mov;
+ flag = &_flag;
+ ai_param = _ai_param;
+ pool = _pool;
+ hold = _hold;
+ cur = _cur;
+ x = _x;
+ y = _y;
+ next = _next;
+ canhold = _canhold;
+ upcomeAtt = _upcomeAtt;
+ maxDeep = _maxDeep;
+ searchDeep = &_searchDeep;
+ level = _level;
+ player = _player;
+ }
+ ~AI_THREAD_PARAM() {
+ }
+ };
+ void AI_Thread( void* lpParam ) {
+ AI_THREAD_PARAM* p = (AI_THREAD_PARAM*)lpParam;
+ int searchDeep = 0;
+ *p->flag = 1;
+
+ AI::MovingSimple best = AISearch(p->ai_param, p->pool, p->hold, p->cur, p->x, p->y, p->next, p->canhold, p->upcomeAtt, p->maxDeep, searchDeep, p->level, p->player);
+ AI::Moving mov;
+ const AI::GameField &gamefield = p->pool;
+ std::vector &gemNext = p->next;
+ mov.movs.push_back(Moving::MOV_DROP);
+ if ( best.x != AI::MovingSimple::INVALID_POS ) { // find path
+ int hold_num = gamefield.m_hold;
+ if ( gamefield.m_hold == 0 && ! gemNext.empty()) {
+ hold_num = gemNext[0].num;
+ }
+ std::vector movs;
+ AI::Gem cur;
+ if ( best.hold ) {
+ cur = AI::getGem(hold_num, 0);
+ FindPathMoving(gamefield, movs, cur, AI::gem_beg_x, AI::gem_beg_y, true);
+ } else {
+ cur = p->cur;
+ FindPathMoving(gamefield, movs, cur, p->x, p->y, false);
+ }
+ for ( size_t i = 0; i < movs.size(); ++i ) {
+ if ( movs[i].x == best.x && movs[i].y == best.y && movs[i].spin == best.spin ) {
+ if ( (isEnableAllSpin() || cur.num == GEMTYPE_T) ) {
+ if ( movs[i].wallkick_spin == best.wallkick_spin ) {
+ mov = movs[i];
+ break;
+ }
+ } else {
+ mov = movs[i];
+ break;
+ }
+ } else if ( cur.num == GEMTYPE_I || cur.num == GEMTYPE_Z || cur.num == GEMTYPE_S ) {
+ if ( (best.spin + 2 ) % 4 == movs[i].spin ) {
+ if ( best.spin == 0 ) {
+ if ( movs[i].x == best.x && movs[i].y == best.y - 1 ) {
+ mov = movs[i];
+ break;
+ }
+ } else if ( best.spin == 1 ) {
+ if ( movs[i].x == best.x - 1 && movs[i].y == best.y ) {
+ mov = movs[i];
+ break;
+ }
+ } else if ( best.spin == 2 ) {
+ if ( movs[i].x == best.x && movs[i].y == best.y + 1 ) {
+ mov = movs[i];
+ break;
+ }
+ } else if ( best.spin == 3 ) {
+ if ( movs[i].x == best.x + 1 && movs[i].y == best.y ) {
+ mov = movs[i];
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ if ( mov.movs.empty() ) {
+ mov.movs.clear();
+ mov.movs.push_back( AI::Moving::MOV_NULL );
+ mov.movs.push_back( AI::Moving::MOV_DROP );
+ }
+ *p->ret_mov = mov;
+
+ *p->searchDeep = searchDeep;
+ *p->flag = -1;
+ delete p;
+ _endthread();
+ }
+ int RunAI(Moving& ret_mov, int& flag, const AI_Param& ai_param, const GameField& pool, int hold, Gem cur, int x, int y, const std::vector& next, bool canhold, int upcomeAtt, int maxDeep, int & searchDeep, int level, int player) {
+ flag = 0;
+ _beginthread(AI_Thread, 0, new AI_THREAD_PARAM(NULL, ret_mov, flag, ai_param, pool, hold, cur, x, y, next, canhold, upcomeAtt, maxDeep, searchDeep, level, player) );
+ return 0;
+ }
+ void AI_Thread_Dll( void* lpParam ) {
+ AI_THREAD_PARAM* p = (AI_THREAD_PARAM*)lpParam;
+ *p->flag = 1;
+ {
+ extern std::vector g_combo_attack;
+ const GameField& gamefield = p->pool;
+ int overfield[32];
+ int field[32];
+ char next[32];
+ int comboTable[32];
+ char gemMap[] = " ITLJZSO";
+ for ( int iy = 0; iy <= gamefield.height(); ++iy ) {
+ field[iy] = gamefield.row[iy];
+ }
+ for ( int iy = 0; iy < 16; ++iy ) {
+ overfield[iy] = gamefield.row[-iy-1];
+ }
+ if ( p->maxDeep > 6 ) p->maxDeep = 6;
+ for ( int i = 0; i < p->maxDeep; ++i ) {
+ next[i] = gemMap[p->next[i].num];
+ }
+ for ( int i = 0; i < g_combo_attack.size(); ++i ) {
+ comboTable[i] = g_combo_attack[i];
+ if ( i + 1 == g_combo_attack.size() ) comboTable[i+1] = -1;
+ }
+
+ char* pOutStr = p->func(overfield, field, gamefield.width(), gamefield.height(), gamefield.b2b, gamefield.combo,
+ next, gemMap[gamefield.m_hold], !p->hold, gemMap[p->cur.num], p->x, p->y, p->cur.spin,
+ true, spin180Enable(), p->upcomeAtt, comboTable, p->maxDeep, p->level, p->player);
+
+ std::map outMap;
+ outMap[' '] = AI::Moving::MOV_NULL;
+ outMap['l'] = AI::Moving::MOV_L;
+ outMap['r'] = AI::Moving::MOV_R;
+ outMap['L'] = AI::Moving::MOV_LL;
+ outMap['R'] = AI::Moving::MOV_RR;
+ outMap['d'] = AI::Moving::MOV_D;
+ outMap['D'] = AI::Moving::MOV_DD;
+ outMap['z'] = AI::Moving::MOV_LSPIN;
+ outMap['x'] = AI::Moving::MOV_SPIN2;
+ outMap['c'] = AI::Moving::MOV_RSPIN;
+ outMap['v'] = AI::Moving::MOV_HOLD;
+ outMap['V'] = AI::Moving::MOV_DROP;
+ AI::Moving mov;
+ for ( ; *pOutStr; ++pOutStr ) {
+ mov.movs.push_back( outMap[*pOutStr] );
+ }
+ *p->ret_mov = mov;
+ }
+ *p->flag = -1;
+ delete p;
+ _endthread();
+ }
+ int RunAIDll(TetrisAI_t func, Moving& ret_mov, int& flag, const AI_Param& ai_param, const GameField& pool, int hold, Gem cur, int x, int y, const std::vector& next, bool canhold, int upcomeAtt, int maxDeep, int & searchDeep, int level, int player) {
+ flag = 0;
+ _beginthread(AI_Thread_Dll, 0, new AI_THREAD_PARAM(func, ret_mov, flag, ai_param, pool, hold, cur, x, y, next, canhold, upcomeAtt, maxDeep, searchDeep, level, player) );
+ return 0;
+ }
+
+}
diff --git a/tetris_ai/tetris_ai.h b/tetris_ai/tetris_ai.h
new file mode 100644
index 0000000..58945f0
--- /dev/null
+++ b/tetris_ai/tetris_ai.h
@@ -0,0 +1,250 @@
+#pragma once
+#define _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH
+
+#include "gamepool.h"
+
+#include
+#include
+
+namespace AI {
+ struct Moving
+ {
+ enum {
+ MOV_NULL,
+ MOV_L,
+ MOV_R,
+ MOV_LL,
+ MOV_RR,
+ MOV_D,
+ MOV_DD,
+ MOV_LSPIN,
+ MOV_RSPIN,
+ MOV_DROP,
+ MOV_HOLD,
+ MOV_SPIN2,
+ MOV_REFRESH,
+ };
+ std::vector movs;
+ int x, y;
+ int score, score2;
+ signed char spin;
+ signed char wallkick_spin;
+ Moving () { wallkick_spin = 0; movs.reserve (16); }
+ Moving ( const Moving & m ) {
+ //movs.reserve (16);
+ movs = m.movs;
+ x = m.x;
+ y = m.y;
+ spin = m.spin;
+ score = m.score;
+ score2 = m.score2;
+ wallkick_spin = m.wallkick_spin;
+ }
+ Moving ( const Moving & m, int _spin ) {
+ movs.reserve (16);
+ movs = m.movs;
+ spin = _spin;
+ }
+ bool operator < (const Moving& _m) const {
+ return score > _m.score;
+ }
+ bool operator == (const Moving& _m) const {
+ if ( x != _m.x || y != _m.y ) return false;
+ if ( spin != _m.spin ) return false;
+ if ( wallkick_spin != _m.wallkick_spin ) return false;
+ return true;
+ }
+ };
+ struct MovingSimple
+ {
+ enum {
+ MOV_NULL,
+ MOV_L,
+ MOV_R,
+ MOV_LL,
+ MOV_RR,
+ MOV_D,
+ MOV_DD,
+ MOV_LSPIN,
+ MOV_RSPIN,
+ MOV_DROP,
+ MOV_HOLD,
+ MOV_SPIN2,
+ MOV_REFRESH,
+ };
+ enum {
+ INVALID_POS = -64,
+ };
+ int x, y;
+ int lastmove;
+ int score, score2;
+ signed char spin;
+ signed char wallkick_spin;
+ bool hold;
+ MovingSimple () { x = INVALID_POS; wallkick_spin = 0; lastmove = MovingSimple::MOV_NULL; }
+ MovingSimple ( const Moving & m ) {
+ x = m.x;
+ y = m.y;
+ spin = m.spin;
+ score = m.score;
+ score2 = m.score2;
+ wallkick_spin = m.wallkick_spin;
+ if (m.movs.empty()) hold = false;
+ else hold = (m.movs[0] == MovingSimple::MOV_HOLD);
+ if (m.movs.empty()) lastmove = MovingSimple::MOV_NULL;
+ else lastmove = m.movs.back();
+ }
+ MovingSimple ( const MovingSimple & m ) {
+ x = m.x;
+ y = m.y;
+ spin = m.spin;
+ score = m.score;
+ score2 = m.score2;
+ wallkick_spin = m.wallkick_spin;
+ hold = m.hold;
+ lastmove = m.lastmove;
+ }
+ MovingSimple ( const MovingSimple & m, int _spin ) {
+ lastmove = m.lastmove;
+ hold = m.hold;
+ spin = (signed char)_spin;
+ }
+ bool operator == (const MovingSimple& _m) const {
+ if ( x != _m.x || y != _m.y ) return false;
+ if ( spin != _m.spin ) return false;
+ if ( lastmove != _m.lastmove ) return false;
+ if ( hold != _m.hold ) return false;
+ if ( wallkick_spin != _m.wallkick_spin ) return false;
+ return true;
+ }
+ bool operator < (const MovingSimple& _m) const {
+ return score > _m.score;
+ }
+ };
+ template
+ struct MovList
+ {
+ std::vector queue;
+ //T queue[1024];
+ int beg, end;
+ MovList() {
+ beg = end = 0;
+ }
+ MovList( size_t size ) {
+ beg = end = 0;
+ //queue.resize( size );
+ queue.reserve( size );
+ }
+ void clear() {
+ beg = end = 0;
+ queue.clear();
+ }
+ size_t size() const {
+ return end - beg;
+ }
+ T& back() {
+ return queue[end-1];
+ }
+ void push(const T& mov) {
+ queue.push_back(mov);
+ //queue[end] = mov;
+ ++end;
+ }
+ bool empty () const {
+ return beg == end;
+ }
+ void pop(T& mov) {
+ mov = queue[beg++];
+ }
+ };
+ template
+ struct MovQueue
+ {
+ std::vector queue;
+ //GameField pool;
+ MovQueue() {
+ }
+ MovQueue( size_t size ) {
+ queue.reserve( size );
+ }
+ void clear() {
+ queue.clear();
+ }
+ size_t size() const {
+ return queue.size();
+ }
+ T& front() {
+ return queue.front();
+ }
+ T& back() {
+ return queue.back();
+ }
+ T& append() {
+ queue.push_back(T());
+ return back();
+ }
+ void push_back() {
+ std::push_heap(queue.begin(), queue.end());
+ }
+ void pop_back() {
+ std::pop_heap(queue.begin(), queue.end());
+ }
+ void dec_size() {
+ queue.pop_back();
+ }
+ void push(const T& mov) {
+ queue.push_back(mov);
+ std::push_heap(queue.begin(), queue.end());
+ }
+ bool empty () const {
+ return queue.empty();
+ }
+ void pop(T& mov) {
+ std::pop_heap(queue.begin(), queue.end());
+ mov = queue.back();
+ queue.pop_back();
+ }
+ void sort () {
+ std::sort( queue.begin(), queue.end() );
+ }
+ };
+ struct AI_Param {
+ int miny_factor; // ×î¸ß¸ß¶È·Ö
+ int hole; // -¶´·Ö
+ int open_hole; // -¿ª·Å¶´£¬¿ÉÄܲå¿é
+ int v_transitions; // -ˮƽת»»ÏµÊý
+ int tspin3; // T3»ù±¾·Ö
+
+ int clear_efficient; // ÏûÐÐЧÂÊϵÊý
+ int upcomeAtt; // -Ô¤±¸¹¥»÷»ù±¾ÏµÊý
+ int h_factor; // -¸ß¶È²îϵÊý
+ int hole_dis_factor2; // -¶´¾àÀëϵÊý
+ int hole_dis; // -¶´µÄ¾àÀë·Ö
+ //int flat_factor; // ƽֱϵÊý
+
+ int hole_dis_factor; // -¶´¾àÀëϵÊý
+ int tspin; // tspinϵÊý
+ int hold_T; // hold TºÍIϵÊý
+ int hold_I; // hold TºÍIϵÊý
+ int clear_useless_factor; // ÎÞЧÐÐϵÊý
+ //int ready_combo; // Á¬»÷Ô¤±¸·Öx
+
+ int dif_factor; //Æ«²îÖµ
+ int strategy_4w;
+ };
+ typedef char* (*AIName_t)( int level );
+ typedef char* (*TetrisAI_t)(int overfield[], int field[], int field_w, int field_h, int b2b, int combo,
+ char next[], char hold, bool curCanHold, char active, int x, int y, int spin,
+ bool canhold, bool can180spin, int upcomeAtt, int comboTable[], int maxDepth, int level, int player);
+ void setComboList( std::vector combolist );
+ int getComboAttack( int combo );
+ void setSpin180( bool enable );
+ bool spin180Enable();
+ void setAIsettings(int player, const char* key, int val);
+
+ void GenMoving(const GameField& field, std::vector & movs, Gem cur, int x, int y, bool hold);
+ void FindPathMoving(const GameField& field, std::vector & movs, Gem cur, int x, int y, bool hold);
+ MovingSimple AISearch(AI_Param ai_param, const GameField& pool, int hold, Gem cur, int x, int y, const std::vector& next, bool canhold, int upcomeAtt, int maxDeep, int & searchDeep, int level);
+ int RunAI(Moving& ret_mov, int& flag, const AI_Param& ai_param, const GameField& pool, int hold, Gem cur, int x, int y, const std::vector& next, bool canhold, int upcomeAtt, int maxDeep, int & searchDeep, int level, int player);
+ int RunAIDll(TetrisAI_t func, Moving& ret_mov, int& flag, const AI_Param& ai_param, const GameField& pool, int hold, Gem cur, int x, int y, const std::vector& next, bool canhold, int upcomeAtt, int maxDeep, int & searchDeep, int level, int player);
+}
diff --git a/tetris_ai/tetris_ai.rc b/tetris_ai/tetris_ai.rc
new file mode 100644
index 0000000..2f79488
Binary files /dev/null and b/tetris_ai/tetris_ai.rc differ
diff --git a/tetris_ai/tetris_ai.vcxproj b/tetris_ai/tetris_ai.vcxproj
new file mode 100644
index 0000000..d01c77d
--- /dev/null
+++ b/tetris_ai/tetris_ai.vcxproj
@@ -0,0 +1,151 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ XP_Release
+ Win32
+
+
+
+ {1063E110-F488-4ADA-8632-AB6E53E8BEDD}
+ Win32Proj
+ tetris_ai
+ Tspin
+
+
+
+ Application
+ true
+ v110
+ Unicode
+
+
+ Application
+ false
+ v110
+ true
+ Unicode
+
+
+ Application
+ false
+ v110_xp
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+ false
+ false
+ $(SolutionDir)bin\
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDebug
+
+
+ Console
+ true
+
+
+
+
+ Level3
+
+
+ Disabled
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ Console
+ true
+ true
+ true
+ false
+
+
+
+
+ Level4
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;XP_RELEASE;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+ true
+ $(OutDir)$(TargetName)$(TargetExt)
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tetris_ai/tetris_ai.vcxproj.filters b/tetris_ai/tetris_ai.vcxproj.filters
new file mode 100644
index 0000000..5445c3a
--- /dev/null
+++ b/tetris_ai/tetris_ai.vcxproj.filters
@@ -0,0 +1,91 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {40211445-1d4c-4629-b0b9-18328834d457}
+
+
+ {0c137e9e-d41e-4606-b80a-1bb4e4dd5d6c}
+
+
+ {65aa26b2-db4a-4b7d-bb1d-869316f81f01}
+
+
+
+
+ Source Files
+
+
+ ai
+
+
+ Source Files
+
+
+ ai
+
+
+ Source Files
+
+
+ ai
+
+
+
+
+ ai
+
+
+ ai
+
+
+ util
+
+
+ ai
+
+
+ ai
+
+
+ Header Files
+
+
+ tetris
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Resource Files
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/tetris_ai/tetris_gem.cpp b/tetris_ai/tetris_gem.cpp
new file mode 100644
index 0000000..648fca3
--- /dev/null
+++ b/tetris_ai/tetris_gem.cpp
@@ -0,0 +1,129 @@
+#include "tetris_gem.h"
+
+namespace AI {
+ Gem gems[8][4];
+ int GEM_COL_H[8][4][4];
+ int GEM_MAXH[8][4];
+
+ class init_obj {
+ public:
+ init_obj() {
+ Gem _gems[8][4] = {
+ {
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0},
+ },
+ /* //QQTetris
+ { // I
+ { 0,15, 0, 0},
+ { 4, 4, 4, 4},
+ { 0,15, 0, 0},
+ { 4, 4, 4, 4},
+ },
+ { // T
+ { 0, 7, 2, 0},
+ { 2, 6, 2, 0},
+ { 2, 7, 0, 0},
+ { 2, 3, 2, 0},
+ },
+ { // L
+ { 3, 2, 2, 0},
+ { 0, 7, 1, 0},
+ { 2, 2, 6, 0},
+ { 4, 7, 0, 0},
+ },
+ { // J
+ { 6, 2, 2, 0},
+ { 1, 7, 0, 0},
+ { 2, 2, 3, 0},
+ { 0, 7, 4, 0},
+ },
+ { // O
+ { 6, 6, 0, 0},
+ { 6, 6, 0, 0},
+ { 6, 6, 0, 0},
+ { 6, 6, 0, 0},
+ },
+ { // Z
+ { 3, 6, 0, 0},
+ { 4, 6, 2, 0},
+ { 3, 6, 0, 0},
+ { 4, 6, 2, 0},
+ },
+ { // S
+ { 6, 3, 0, 0},
+ { 2, 6, 4, 0},
+ { 6, 3, 0, 0},
+ { 2, 6, 4, 0},
+ },
+ */
+ { // I 1
+ { 0,15, 0, 0},
+ { 2, 2, 2, 2},
+ { 0, 0,15, 0},
+ { 4, 4, 4, 4},
+ },
+ { // T 2
+ { 2, 7, 0, 0},
+ { 2, 3, 2, 0},
+ { 0, 7, 2, 0},
+ { 2, 6, 2, 0},
+ },
+ { // L 3
+ { 4, 7, 0, 0},
+ { 3, 2, 2, 0},
+ { 0, 7, 1, 0},
+ { 2, 2, 6, 0},
+ },
+ { // J 4
+ { 1, 7, 0, 0},
+ { 2, 2, 3, 0},
+ { 0, 7, 4, 0},
+ { 6, 2, 2, 0},
+ },
+ { // Z 5
+ { 3, 6, 0, 0},
+ { 2, 3, 1, 0},
+ { 0, 3, 6, 0},
+ { 4, 6, 2, 0},
+ },
+ { // S 6
+ { 6, 3, 0, 0},
+ { 1, 3, 2, 0},
+ { 0, 6, 3, 0},
+ { 2, 6, 4, 0},
+ },
+ { // O 7
+ { 6, 6, 0, 0},
+ { 6, 6, 0, 0},
+ { 6, 6, 0, 0},
+ { 6, 6, 0, 0},
+ },
+ };
+ //int m[] = {1, 2, 4, 4, 4, 1, 2, 2}; // QQTetris
+ int m[] = {1, 4, 4, 4, 4, 4, 4, 1}; // TOP SRS
+ for ( int n = 0; n < 8; ++n) {
+ for ( int s = 0; s < 4; ++s) {
+ gems[n][s] = _gems[n][s];
+ gems[n][s].num = n;
+ gems[n][s].mod = m[n];
+ gems[n][s].spin = s % m[n];
+ //GEM_COL_H Initialization
+ GEM_MAXH[n][s] = 0;
+ for ( int x = 0; x < 4; ++x) {
+ GEM_COL_H[n][s][x] = 0;
+ for ( int y = 0; y < 4; ++y) {
+ if(gems[n][s].bitmap[y] & (1 << x)) {
+ GEM_COL_H[n][s][x] = y + 1;
+ if ( GEM_MAXH[n][s] < y ) GEM_MAXH[n][s] = y;
+ //I vertical: 0 4 0 0
+ }
+ }
+ }
+ }
+ }
+ }
+ } _o;
+}
diff --git a/tetris_ai/tetris_gem.h b/tetris_ai/tetris_gem.h
new file mode 100644
index 0000000..3078704
--- /dev/null
+++ b/tetris_ai/tetris_gem.h
@@ -0,0 +1,32 @@
+#pragma once
+#define _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH
+
+namespace AI {
+ enum GemType {
+ GEMTYPE_NULL,
+ GEMTYPE_I,
+ GEMTYPE_T,
+ GEMTYPE_L,
+ GEMTYPE_J,
+ GEMTYPE_Z,
+ GEMTYPE_S,
+ GEMTYPE_O,
+ };
+ struct Gem {
+ unsigned long bitmap[4];
+ int num, spin, mod;
+ int geth() const { return 4; }
+ };
+ inline Gem& getGem( int number, int spin ) {
+ extern Gem gems[8][4];
+ return gems[number][spin];
+ }
+ inline int getGemColH( int number, int spin, int x) {
+ extern int GEM_COL_H[8][4][4];
+ return GEM_COL_H[number][spin][x];
+ }
+ inline int getGemMaxH( int number, int spin) {
+ extern int GEM_MAXH[8][4];
+ return GEM_MAXH[number][spin];
+ }
+}
diff --git a/tetris_ai/tetris_setting.h b/tetris_ai/tetris_setting.h
new file mode 100644
index 0000000..2359b20
--- /dev/null
+++ b/tetris_ai/tetris_setting.h
@@ -0,0 +1,26 @@
+#ifdef XP_RELEASE
+#define PUBLIC_VERSION 1 // ·¢²¼Ä£Ê½
+#define GAMEMODE_4W 0 // 4wģʽ
+#define PLAYER_WAIT 0 // Íæ¼ÒµÈ´ýAI˼¿¼£¬Èç¹ûÐèÒªµÄ»°
+#define AI_TRAINING_SLOW 1
+#define USE4W 1
+#else
+#define PUBLIC_VERSION 0
+#define GAMEMODE_4W 0
+#define PLAYER_WAIT 0
+#define AI_TRAINING_SLOW 1 // ѵÁ·Ä£Ê½ÂýËÙÑÝʾ
+#define USE4W 0
+#endif
+#define ATTACK_MODE 1 // À¬»øÐУº0¿ÕÆø 1TOP 2»ðÆ´
+#define AI_SHOW 0 // ²»Ï໥¹¥»÷£¬Î§¹ÛAI
+#define DISPLAY_NEXT_NUM 6 // ÏÔʾnext¸öÊý
+#if AI_TRAINING_SLOW
+#define AI_TRAINING_DEEP 16
+#else
+#define AI_TRAINING_DEEP 6 // ѵÁ·AI˼¿¼Éî¶È
+#endif
+#define TRAINING_ROUND 20
+#define AI_TRAINING_0 9
+#define AI_TRAINING_2 6
+
+#define AI_DLL_VERSION 2 // dll°æ±¾
diff --git a/tetris_ai/tetrisgame.h b/tetris_ai/tetrisgame.h
new file mode 100644
index 0000000..ce979b3
--- /dev/null
+++ b/tetris_ai/tetrisgame.h
@@ -0,0 +1,335 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include "tetris.h"
+#include "tetris_ai.h"
+#include "random.h"
+
+#include "sound.h"
+
+#include "tetris_setting.h"
+
+class TetrisGame : public AI::Tetris {
+public:
+ TetrisGame() {
+ m_base = AI::point(0, 30);
+ m_size = AI::point(20, 20);
+ hold = true;
+ ai_movs_flag = -1;
+ reset((unsigned)time(0));
+ ai_delay = 0;
+ mov_llrr = 0;
+ env_change = 0;
+ n_win = 0;
+ last_max_combo = 0;
+ mSFXon = false;
+ m_lr = 0;
+ pAIName = NULL;
+ pTetrisAI = NULL;
+ AI::AI_Param param = {
+
+// 18, 37, 11, 12, 9, 2, -30, -36, -14, 0, 8, -2, 9,
+// 21, 30, -4, 9, 0, 5, -22, -6, -12, 9, 4, -3, 14
+// 16, 29, 7, 7, 50, 6, -23, -24, -4, 9, 6, 60, 13
+// 16, 29, 7, 7, 50, 6, -23, -24, -4, 9, 6, 60, 7
+// 21, 21, 19, 12, 10, 7, -17, -2, -3, 6, 9, 15, 15
+// 19, 32, 14, 13, 3, 22, -18, -15, -14, 11, 11, 5, 33
+// 21, 30, 15, 13, 5, -2, -15, -20, -14, 9, 7, 4, 25
+// 21, 30, 15, 13, 5, -2, -15, -20, -14, 9, 7, 30, 25
+// 17, 34, 28, 20, 57, 3, -10, 29, -72, 17, 10, 50, 27
+
+// 9, 14, 7, 9, 9, 11, 11, 5, 13, 2, 8, 10, 13
+// 8, 13, 11, 7, 7, 12, 6, 2, 12, 3, 10, 12, 18
+// 8, 13, 11, 7, 7, 12, 6, 2, 12, 3, 10, 12, 18, 18
+// 7, 29, 16, 13, 11, 19, 7, 7, 20, 6, 14, 13, 13, 13
+// 12, 14, 8, 15, 8, 14, 8, 4, 19, 2, 14, 10, 11, 11
+// 21, 27, 15, 6, 40, 8, 20, 6, 7, -6, 3, 16, 8, 8
+// 19, 27, 14, 5, 17, 12, 19, 5, 11, -2, 3, 13, 10, 14
+// 13, 53, 45, 17, 15, 11, 12, 5, 7, 4, 8, 17, 18, 3
+// 17, 26, 18, 1, 9, 12, 16, 4, 16, -4, 11, 7, 11, 14
+// 19, 25, 20, 6, 23, 13, 12, 3, 14, 5, 13, 10, 13, 26
+// 11, 27, 21, 3, 28, 10, 17, 5, 20, -2, 11, 15, 31, 11
+// 8, 26, 16, 5, 23, 12, 7, 5, 8, -8, 14, 15, 9, 18 // APL ¸ß
+// 8, 26, 21, 7, 21, 12, 5, 5, 1, -3, 13, 11, 11, 4
+// 13, 28, 21, 14, 25, 11, 21, 6, 8, -3, 13, 24, 31, 1
+// 8, 26, 21, 7, 21, 12, 5, 5, 1, -3, 13, 11, 11, 4
+// 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10,
+// 8, 22, 12, 9, 11, 6, 7, 5, 15, 2, 8, 7, 10, 16
+// 12, 29, 22, 13, 28, 11, 17, 7, 20, -1, 15, 13, 26, 17
+// 9, 28, 24, 10, 13, 12, 3, 3, 14, -3, 11, 28, 26, 9
+// 8, 26, 21, 7, 21, 12, 5, 5, 20, -3, 13, 21, 11, 4
+// 8, 38, 18, 13, -14, 19, 7, 4, 14, -15, 9, 19, 16, -3
+// 5, 38, 20, 5, 8, 39, 7, 8, -13, -5, 4, 24, 7, -20
+// 36, 34, 50, 8, 12, 12, 7, 10, 2, 6, 11, 10, 9, 6 // ÍÚÍÚ»ú
+// 22, 36, 56, 17, 17, 29, 6, 6, 6, 7, 18, 13, 8, 21
+// 3, 34, 38, 12, 20, 16, 10, 7, 10, 10, 14, 35, 12, 0
+// 26, 35, 45, 14, -2, 10, 6, 7, 4, 8, 13, 14, 8, 1
+// 27, 43, 52, 9, 53, 8, 13, 11, 3, 0, 18, 11, 17, 20
+// 32, 43, 60, 9, 8, 24, 13, 8, 2, 7, 20, 10, 13, 21
+// 28, 41, 63, 8, 30, 9, 12, 10, -5, 6, 15, 9, 20, 21
+// 43, 43, 64, 21, 43, 12, 10, 16, 20, 22, 0, 17, 57, 12
+// 28, 41, 69, 28, 0, 16, 34, 12, 4, 21, 3, 0, 20, 14, 50
+// 28, 41, 69, 28, 0, 16, 34, 12, 4, 21, 3, 12, 20, 14, 50, 1000
+// 40, 32, 76, 16, 41, 17, 13, 21, 10, 21, 3, 21, 70, 17, 54
+// 28, 41, 69, 28, 51, 16, 34, 12, 4, 21, 3, 12, 20, 14, 50, 0
+// 47, 26, 70, 4, 46, 16, 26, 21, 7, 31, 14, 17, 69, 1, 43, 300
+// 34, 18, 61, 9, 39, 13, 22, 13, -9, 38, 9, 15, 64, 9, 36, 300
+
+// 47, 26, 70, 4, 46, 16, 26, 21, 7, 31, 14, 17, 69, 11, 53, 300
+
+// 33, 25, 57, 19, 37, 11, 33, 10, 9, 38, 12, 13, 63, 11, 51, 300
+// 37, 24, 50, 29, 53, 15, 26, 12, 13, 36, 11, 7, 69, 12, 53, 300
+// 36, 25, 50, 20, 55, 15, 28, 12, 15, 36, 12, 10, 70, 12, 53, 300
+// 40, 15, 50, 20, 56, 16, 17, 12, 7, 55, 99, 23, 78, 16, 67, 300 // 1.4.1
+// 21, 20, 66, 40, 27, 22, 48, 26, 8, 71, 13, 24, 92, 7, 69, 300
+// 49, 18, 76, 33, 39, 27, 32, 25, 22, 99, 41, 29, 96, 14, 60, 300 //1.4.3
+
+// 40, 27, 65, 22, 37, 18, 66, 28, 9, 32, 4, 16, 93, 10, 27, 300,
+
+// 45, 28, 84, 21, 35, 27, 56, 30, 9, 64, 13, 18, 97, 11, 29, 300 //1.4.4
+// 40, 20, 98, 13, 35, 22, 63, 29, 5, 68, 11, 15, 98, 14, 32, 300
+// 44, 32, 96, 28, 42, 24, 49, 25, -6, 58, 17, 20, 51, 10, 32, 300
+// 36, 20, 99, 27, 41, 32, 28, 24, 11, 56, 26, 24, 43, 14, 27, 300 //1.4.4
+// 44, 13, 98, 31, 51, 30, 53, 27, 16, 56, 29, 27, 34, 16, 24, 300
+
+// 36, 30, 71, 67, 72, 48, 22, 16, 34, 60, 0, 34, 46, 35, 16, 33 // test
+// 61, 33, 87, 52, 85, 30, 30, 28, 2, 71, 55, 51, 98, 35, 57, 60 // test
+//70, 16, 99, 50, 95, 33, 21, 29, 38, 98, 10, 54, 91, 26, 42, 65
+//45, 28, 84, 11, 35, 27, 26, 30, 39, 64, 13, 18, 97, 11, 29, 300 //1.4.4
+//13, 9, 17, 10, 29, 25, 39, 2, 12, 19, 7, 24, 21, 16, 14, 19, 20
+ 26, 0, 20, 17, 45, 41, -8, 9, 10, 27, 15, 20, 19, 11, 44, 4, 300//,1183
+
+ };
+ if ( GAMEMODE_4W ) {
+ //param.h_variance = 0;
+ param.tspin = 0;
+ param.tspin3 = 0;
+ }
+ m_ai_param = param;
+ }
+ void reset ( unsigned seed, unsigned pass = 0 ) {
+ while ( ai_movs_flag != -1 ) ::Sleep(1);
+ last_max_combo = m_max_combo;
+ AI::Tetris::reset(seed, 10, 22);
+ m_randatt.seed( seed );
+ for ( unsigned i = 0; i < pass; ++i ) m_randatt.rand();
+ ai_delay = 0;
+ mov_llrr = 0;
+ env_change = 0;
+ ai_movs.movs.clear();
+ n_pieces = 0;
+ ai_last_deep = 0;
+ ai_movs_flag = -1;
+ accept_atts.clear();
+ m_last_hole_x = -1;
+ total_clears = 0;
+ total_atts = 0;
+ total_sent = 0;
+ total_accept_atts = 0;
+ m_ko = 0;
+ m_att_info = "";
+ }
+ bool tryXMove(int dx) {
+ bool ret = Tetris::tryXMove( dx );
+ if ( mSFXon && ret ) {
+ GameSound::ins().mSFX_move.play( m_lr );
+ }
+ return ret;
+ }
+ bool tryXXMove(int dx) {
+ bool ret = Tetris::tryXMove( dx );
+ while ( Tetris::tryXMove(dx) ) ;
+ if ( mSFXon && ret ) {
+ GameSound::ins().mSFX_move.play( m_lr );
+ }
+ return ret;
+ }
+ bool tryYMove(int dy) {
+ bool ret = Tetris::tryYMove( dy );
+ if ( mSFXon && ret ) {
+ GameSound::ins().mSFX_softdrop.play( m_lr );
+ }
+ return ret;
+ }
+ bool tryYYMove(int dy) {
+ bool ret = Tetris::tryYMove( dy );
+ while ( Tetris::tryYMove(dy) ) ;
+ if ( mSFXon && ret ) {
+ GameSound::ins().mSFX_softdrop.play( m_lr );
+ }
+ return ret;
+ }
+ bool trySpin(int dSpin) {
+ bool ret = Tetris::trySpin( dSpin );
+ if ( mSFXon && ret ) {
+ GameSound::ins().mSFX_rotate.play( m_lr );
+ }
+ return ret;
+ }
+ bool trySpin180() {
+ bool ret = Tetris::trySpin180( );
+ if ( mSFXon && ret ) {
+ GameSound::ins().mSFX_rotate.play( m_lr );
+ }
+ return ret;
+ }
+ bool tryHold() {
+ bool ret = Tetris::tryHold( );
+ if ( mSFXon && ret ) {
+ GameSound::ins().mSFX_hold.play( m_lr );
+ }
+ return ret;
+ }
+ bool drop() {
+ bool ret = Tetris::drop( );
+ if ( mSFXon && ret ) {
+ GameSound::ins().mSFX_lockdown.play( m_lr );
+ }
+ return ret;
+ }
+ void clearSFX( ) {
+ if ( m_clear_info.clears <= 0 || ! mSFXon ) return ;
+ int att = m_clear_info.attack;
+ int b2b = m_clear_info.b2b > 1;
+ int combo = m_clear_info.combo;
+ att -= b2b;
+ att -= AI::getComboAttack( combo );
+ if ( m_clear_info.pc ) {
+ att -= 6;
+ if ( GameSound::ins().mSFX_pc.isOpen() )
+ GameSound::ins().mSFX_pc.play( m_lr );
+ }
+ if ( combo > 1 ) {
+ int i = 0;
+ for ( ; i < combo - 1 && i < 20; ++i) {
+ if ( ! GameSound::ins().mSFX_combo[i].isOpen() ) break;
+ }
+ if ( --i >= 0 ) {
+ if ( GameSound::ins().mSFX_combo[i].isOpen() ) GameSound::ins().mSFX_combo[i].play( m_lr );
+ }
+ }
+ if ( m_clear_info.wallkick_spin && att > 0 ) {
+ if ( m_clear_info.wallkick_spin == 2 && (AI::isEnableAllSpin() || m_clear_info.clears == 1) ) {
+ if ( b2b ) {
+ GameSound::sound& m = GameSound::ins().mSFX_b2b_tspin[0];
+ if (m.isOpen()) m.play( m_lr );
+ } else {
+ GameSound::sound& m = GameSound::ins().mSFX_tspin[0];
+ if (m.isOpen()) m.play( m_lr );
+ }
+ } else {
+ if ( b2b ) {
+ GameSound::sound& m = GameSound::ins().mSFX_b2b_tspin[m_clear_info.clears];
+ if (m.isOpen()) m.play( m_lr );
+ } else {
+ GameSound::sound& m = GameSound::ins().mSFX_tspin[m_clear_info.clears];
+ if (m.isOpen()) m.play( m_lr );
+ }
+ }
+ } else if ( m_clear_info.clears > 0 ) {
+ if ( b2b ) {
+ GameSound::sound& m = GameSound::ins().mSFX_b2b_tetris;
+ if (m.isOpen()) m.play( m_lr );
+ } else {
+ GameSound::sound& m = GameSound::ins().mSFX_clears[m_clear_info.clears - 1];
+ if (m.isOpen()) m.play( m_lr );
+ }
+ }
+ }
+ bool ko () {
+ if ( mSFXon ) {
+ if ( m_ko ) {
+ if ( GameSound::ins().mSFX_ko.isOpen() ) {
+ GameSound::ins().mSFX_ko.play();
+ return true;
+ }
+ } else {
+ if ( GameSound::ins().mSFX_gameover.isOpen() ) {
+ GameSound::ins().mSFX_gameover.play();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ void acceptAttackSFX() {
+ if ( mSFXon && GameSound::ins().mSFX_lineattack.isOpen() ) {
+ GameSound::ins().mSFX_lineattack.play( m_lr );
+ }
+ }
+ void acceptAttack(int n) {
+ int att[2] = {0};
+ for ( int i = 0; i < 32; i += 2) {
+ att[0] |= 1 << i;
+ }
+ att[0] &= m_pool.m_w_mask;
+ att[1] = ~att[0] & m_pool.m_w_mask;
+
+ int rowdata = m_randatt.randint( m_pool.m_w );
+ while ( m_last_hole_x == rowdata ) {
+ rowdata = m_randatt.randint( m_pool.m_w );
+ }
+ m_last_hole_x = rowdata;
+ rowdata = ~( 1 << rowdata ) & m_pool.m_w_mask;
+ for ( ; n > 0; --n ) {
+ if ( ATTACK_MODE == 0 ) addRow( 0 ); // ¿ÕÆøÐÐ
+ if ( ATTACK_MODE == 1 ) addRow( rowdata ); // TOPÐÐ
+ if ( ATTACK_MODE == 2 ) addRow( att[n&1] ); // »ðÆ´ÐÐ
+ ++total_accept_atts;
+ }
+ if ( alive() ) {
+ if ( m_pool.isCollide(m_cur_x, m_cur_y, m_cur) ) {
+ m_state = STATE_OVER;
+ m_ko = 1;
+ }
+ }
+ }
+ bool game() {
+ bool ret = AI::Tetris::game();
+ if ( ret ) m_piecedelay = 0;
+ else ++m_piecedelay;
+ if ( GAMEMODE_4W && AI_SHOW ) {
+ if ( m_clearLines > 0 ) {
+ for ( int i = 1; i <= m_clearLines; ++i) {
+ setRow( poolh() - 40 + i,
+ ~(15 << 3) & m_pool.m_w_mask );
+ }
+ }
+ }
+ return ret;
+ }
+ void soundon( bool on ) {
+ mSFXon = on;
+ }
+public:
+ bool hold;
+ AI::Moving ai_movs;
+ int ai_movs_flag;
+ int ai_last_deep;
+ int ai_delay;
+ AI::AIName_t pAIName;
+ AI::TetrisAI_t pTetrisAI;
+ int mov_llrr;
+ int env_change;
+ int n_pieces;
+ std::vector accept_atts;
+ int m_last_hole_x;
+ int n_win;
+ int total_clears;
+ int total_atts;
+ int total_sent;
+ int total_accept_atts;
+ int last_max_combo;
+ int m_ko;
+ int m_lr; // 3dÒôЧ¿ªÆô
+ int m_piecedelay;
+ AI::Random m_randatt;
+ AI::AI_Param m_ai_param;
+ std::string m_name;
+ bool mSFXon;
+ mutable std::string m_att_info;
+};