Turn-based Game Engine and AI Melvin Winstrøm-Møller s072435 Niels Thykier s072425 August 31, 2010 Contents Table of Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . List of Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 4 1 Preface 5 2 Introduction 6 I 8 Assignment specification and analysis 3 Reasoning behind the project 3.1 Introduction to game engines and related considerations . . . 3.2 Types of games . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3 Technical requirements of TN and RTP games . . . . . . . . 3.4 Competitiveness of a new TN game engine . . . . . . . . . . . 3.5 Summary and final assignment description . . . . . . . . . . . 3.6 Potential weaknesses and difficulties of the chosen assignment . . . . . . . . . . . . 9 9 10 11 13 14 15 4 Engine requirements 4.1 Game developer requirements 4.1.1 Graphics . . . . . . . 4.1.2 Game Logic . . . . . . 4.1.3 Multiplayer . . . . . . 4.1.4 AI . . . . . . . . . . . 4.1.5 Resource IO . . . . . . 4.2 Feature requirements . . . . . 5 AI 5.1 5.2 5.3 5.4 requirements Aspects of AI in TN games AI tasks and technologies in AI tools . . . . . . . . . . . AI feature requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 17 19 19 20 21 22 22 . . . . . . . TN games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 24 27 30 31 . . . . . . . 6 Technology . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 1 II Engine 7 Design 7.1 The original implementation 7.2 Event-based system . . . . . 7.3 Graphics system . . . . . . 7.4 Game logic system . . . . . 36 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 37 38 39 39 8 Implementation 8.1 Graphics system . . . . . . . 8.2 Game logic system and AI . . 8.3 Multiplayer system . . . . . . 8.4 Resource IO and management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 41 42 43 44 9 Discussion 45 III 47 AI 10 AI Design 10.1 TN-focused libraries . . . . . 10.1.1 Path finding . . . . . . 10.1.2 Information extraction 10.2 Machine learning . . . . . . . . . . . . . . . . . . . . . . . and analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 49 49 51 52 11 AI Implementation 11.1 Selection of AI methods . . . . . . . . . . . 11.1.1 Path finding . . . . . . . . . . . . . . 11.1.2 Information extraction and analysis 11.1.3 Machine learning . . . . . . . . . . . 11.2 Implementation of AI methods . . . . . . . 11.2.1 Path finding . . . . . . . . . . . . . . 11.2.2 Blocking . . . . . . . . . . . . . . . . 11.2.3 Influence mapping . . . . . . . . . . 11.2.4 Genetic Algorithm . . . . . . . . . . 11.2.5 Case-based Reasoning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 55 56 56 59 62 62 63 64 65 67 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . script engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 71 72 72 73 74 74 75 12 Script Engine 12.1 The idea and outcome . . . . . . 12.2 Script engine design . . . . . . . 12.2.1 Script engine components 12.2.2 Linking scripts . . . . . . 12.3 Lessons learned . . . . . . . . . . 12.3.1 Code analysis . . . . . . . 12.3.2 Debugging scripts and the 13 Discussion 76 2 IV V Conclusion 79 Appendix 82 14 Abbreviations and acronyms 83 Bibliography 85 3 List of Figures 11.1 Influence map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Blue team crushing the red team. . . . . . . . . . . . . . . . . . . 4 65 69 Chapter 1 Preface This thesis is submitted as part of the requirements for obtaining a Bachelor’s Degree at the Technical University of Denmark. The project, which corresponds to 15 ECTS points per author, was carried out at the Department of Informatics and Mathematical Modelling under the supervision of Assistant Professor Henrik Pilegaard in the period from April to August 2010. The background for picking this project was the continuation of a hobby project. Extending the project into a bachelor project both meant that we could be allowed to work on our own project, as well as challenge ourselves in several interesting fields of computer science, including algorithms, multithreading, language design and artificial intelligence. The project was on a scale neither of the authors had experienced before, and the experience of working on such a varied and interesting project have been worth the many hours put into it. As part of making the project come true as well as helping us on our path, we would like to thank our supervisor Henrik Pilegaard for his great humor and our long and fruitful conversations with him, which brought many useful ideas for the project. We would also like to thank the people behind Battle for Wesnoth for putting their graphics under GNU General Public License version 2, which allowed us to reuse the graphics for the game implementation. 5 Chapter 2 Introduction Abstract Game engines have become increasingly important in the development of games as computing resources have increased. However, competing in this market is difficult, as there is an ever increasing number of game engines. This thesis introduces a game engine focused on a game genre not previously supported by engines: turn-based node-based (TN) games. This genre of games cover a large variety of games, including many card and board games, as well as more advanced computer games. Given the special properties of these games, an engine taking advantage of these properties is designed and implemented. As part of the development of the engine, candidate methods for an AI library is tested and implemented. Developing AI is frequently a challenging task, but AI support is frequently rare or lacking in game engines, partly due to the variety of games. Focusing on a specific genre of games, AI methods are chosen and tested in order to determine whether an AI library focused on TN games can successfully support a TN engine. Overview This report describes a bachelor thesis in the field of computer science. The first goal of the thesis was to design and implement a flexible game engine focused on the niche of games classified as both turn-based and nodebased. The second goal was the implementation of several AI libraries and tools to help support the engine, and investigate the value of including AI libraries and tools to the game engine. Structure of the report The first part of the report, introduction, introduces the bachelor thesis and the structure of the report. In part 1, assignment specification and analysis, the background for the as6 signment is described, and the assignment is analysed thoroughly, resulting in a set of requirements for both the engine and the AI methods. Part 1 is concluded by a technology chapter discussing the chosen technology in the project. In part 2, engine, the engine design and implementation are described and discussed. The focus is on the subsystems of the engine and their support of TN games, as well as the overall design goals of separation of concerns. Part 2 is concluded with a discussion on the resulting design and implementation, and presents the fulfilled requirements from part 1. In part 3, AI, the requirements for the different methods are described in the design. The implementation describes and discusses the selections of the methods, and then describes and evaluates their implementation. The design and implementation of the scripting engine is then described and discussed. Part 3 is concluded with a discussion on the AI methods and their usability to TN games and game engines. The report then ends with the conclusion on the results of the thesis. 7 Part I Assignment specification and analysis 8 Chapter 3 Reasoning behind the project This section discusses several aspects of game engines, game types and other issues relevant to the chosen assignment. In the end of the section, the conclusions from the aspects are summed up, and finally a section discusses the potential weaknesses and difficulties of the chosen assignment, and how they may be dealt with. 3.1 Introduction to game engines and related considerations In the early days of game development, the relatively low complexity and cost of developing games combined with the few computer resources available made it undesirable to create engines that enabled code reuse. Instead, it was cheaper and more effective to simply start over for each game, especially as platforms and technologies changed rapidly. For instance, hand-coded assembly code was used to increase performance by taking advantage of each platforms capabilities, and the games often had to be recoded somewhat when porting to new platforms. 1 1 The below links describes how assembly language was and still is used in game creation. Describes how assembly code was used to port a game to the PDP-7. http://www.courses.fas.harvard.edu/˜lib215/reference/history/spacetravel.html Describes how some consoles required assembly. http://www.eidolons-inn.net/tiki-index.php?page=SegaBase+Saturn Discusses the issues with porting games. Includes comments about how assembly code and other platform-specific code is typically minimised http://www.bit-tech.net/gaming/2009/08/18/the-problem-with-porting-games/1 9 As computer resources (such as RAM, CPU, etc.) increased considerably, and long-term technologies were developed2 , game engines became feasible. By abstracting away the underlying details, and reusing many of the different software systems used in the games (such as graphics, logic, sound, network, etc.), several advantages are achieved: • Increased portability • Decreased cost and development time • Decreased complexity and skill requirements These advantages can sometimes come at the cost of flexibility and speed. Often, game engines have to be designed to prioritise between 2 factors: The more specialised the engine, the more assumptions can be made, and the easier it is to achieve high performance using the engine. However, this generally comes at a cost in flexibility. This can help explain why it is not all games today that are developed using game engines - by creating a code base using few or none existing software components, a highly specialised and optimal code base can be created for the game in question. Another motivation is the lack of a game engine for a particular genre of games. While game engines offer many advantages, they are also difficult software systems to develop. Many different subsystems have be developed and interact in an efficient manner, and many design choices must be made. Furthermore, adopting a game engine for future games is a considerable technology investment, both in terms of knowledge of using the engine in the development team, and in the technology of the engine itself. For the engine to be adopted, there have to be considerable advantages attained by using the engine - both in terms of an advantage over developing an engine from scratch, and from using an existing engine. A new game engine needs an edge, such as being specialised for a certain genre of games, for which there are no existing engines that fits very well. 3.2 Types of games One of the genres for games are turn-based, node-based (TN) games. This genre of games are most generally known from board games. They cover traditional games like Chess, Checkers, Nine Men’s Morris, Ludo, etc., more modern games like Space Hulk, Settlers of Catan, Descent, Monopoly, Axis & Allies, etc., and computer games such as Advance Wars, Final Fantasy 2 Examples are the graphics libraries OpenGL and DirectX, which were developed in the start 1990’s, and are still used today. They are often the back-bone in the graphical parts of engines, and are quite portable. OpenGL supports a large number of operating systems and even some consoles 10 Tactics, the Civilization series (and its clones), the Age of Wonders series, Battle for Wesnoth, etc.. The board games can in general be turned into computer games, and often have been. A turn-based game is a game where the game flow is partitioned into welldefined and visible parts, called turns. Reflexes and motion control have little or no importance in these games. Instead, the ability to create tactics and strategies, or to figure out the puzzles the game presents, is generally more important. Whether the time allocated for each turn is unlimited or limited differs, but the time allocated to each turn is generally enough to let the player consider what to do. The alternative to turn-based is real-time, in which the game continues, independent on whether the player acts or not. While in practice all computer games have logic partitioned into small time units, real-time games generally have very small time units. A node-based game is a game in which the board and spaces of the game can be modeled as a graph with nodes. A chess board, a hexagonal board and other, more special boards (such as with varying space sizes) can all be modeled as a graph with nodes. The main alternative to node-based games are position-based games. In these games, spaces and dimensions are represented through positions. A game which is still node-based, even though it may seem position-based, is the real-time strategy (RTS) game Warcraft 2, which features a large grid. While some may consider it position-based, it is considered node-based in this project since its granularity is not small enough to be impractical to represent as nodes in a grid. An example of a position-based game is the RTS game Command and Conquer: Generals. While games are often either turn-based and node-based, or real-time and position-based, games that mix the types exist. In the rest of the report, turnbased, node-based games will be called TN, while the real-time, position-based games will be called RTP. 3.3 Technical requirements of TN and RTP games From a software engineering point of view, the two general types of games described above have different technical requirements. RTP requires the state 11 to be updated constantly and needs constant communication between the game and the player. This place constraints on how much time each component may take to do their tasks. This is unlike TN games, in which several components have a relatively long time to perform their tasks. For instance, AIs in some Chess games may take several seconds or even minutes to compute their moves, and this is accepted by the players. Game logic One very important component is the game logic structure. By game logic is first and foremost meant the code that modifies the game state. It is in the game logic that the game rules are defined, through defining what is possible and what is not. In RTP games, game logic is frequently mixed with other code that handles issues like graphics, AI, etc. This gives fine-grained control and integration between game rules and the rest of the game. In a typical RTP game, a game loop is run, in which small scripts modifies the game state in each step. Typically, many (20-80) steps are run per second. While this fits RTP games well, it makes much less sense for turn-based games, which only needs to modify the game state whenever a player takes an action. AI Another, often important part of a TN game is the AI, which is somewhat different from the AI in RTP games. The AI in RTP games frequently have to meet constant deadlines, because of the need for quick decisions. To help the AI meet these deadlines, the AI is typically run in the same loop as the game logic (sometimes mixed with the game logic). Another option is to execute all or some of the AI in a special AI loop, typically with a lower frequency to give extra time for complex analysis. This makes little sense for turn-based games, since the players makes the choices, and a complete separation of game logic and AI not only helps game designers, it also increases modularity and separation of concerns. Networking Networking is also another important part of many games, RTP as well as TN. RTP games have constant state changes. Keeping the traffic low in RTP games is entirely possibly given the right approach, even in games with a huge game state and frequent game changes 3 . However, these approaches can complicate matters, and turn-based games have much looser constraints (much more time to communicate much less game state, for instance in the form of player actions), making it plausible that a single network subsystem may be able to serve the needs of many simple TN games, or the least common subset of their needs. Summary Given these differences in technical requirements, it seems likely that a properly designed TN game engine will have a considerable advantage 12 over a similar RTP game engine in regards to development of TN games. 3.4 Competitiveness of a new TN game engine The vast majority of game engines supports real-time first and foremost, and we have failed to find any turn-based engines, which were not focused on a specific game. However, we have found multiple requests for turn-based engines. A flexible TN engine would be clearly preferred over RTP engines for TN games, since it would support TN games much better, and it would have little competition from other TN engines, since no or few flexible TN engines exists. A new flexible, TN game engine would therefore have a clear edge over other game engines in regards to development of TN games. AI libraries and tools Many TN games are tactical or strategic in their game play, and it is frequently difficult to implement a proper single-player version of a TN game without a good AI. However, developing a good AI is one of the more time consuming and difficult tasks of developing a game. Supporting AI development through the inclusion of specialised libraries and tools would give the engine an edge. Nevertheless, AI libraries are often difficult to implement, because a considerable part of the AIs written contain game rules, and are therefore specific to a particular game. Still, a genre of games typically contain some of the same AI tasks and solutions. For instance, first-person shooter (FPS) games often employ state machines, and some engines implement direct support for state machine programming 4 . In regards to TN games, a common feature is the graph-based nature of these games, and most of these games would benefit considerably from an AI subsystem handling common tasks on graphs, notably search tasks. AI is also a rapidly developing field, and experimenting with new AI techniques not used in games before could give an edge in the quality of the AIs. It might also help pave the way for the use of these techniques in the game industry. 3 http://www.gamasutra.com/view/feature/3094/1500˙archers˙on˙a˙288˙network˙.php an article describing the networking used in Age of Empires 1, 2 and ”RTS3” (possibly Age of Mythology). The networking only communicates player actions, and the game designers went to great lengths to ensure that the same code would always run the same on multiple computers - for instance, to get random numbers, pseudo-random number generators was used, exchanging the root number between all clients at the start of the game. The process was complicated and was a source of obscure bugs, but made networking feasible 4 UnrealScript, a game engine used for several projects: http://www.unrealtechnology.com/ Manual describing the UnrealScript, including their support for state machine programming 13 3.5 Summary and final assignment description Based on the observations and discussion in the previous sections, we believe that the design and implementation of a TN game engine would make an interesting and valid project. While the game industry and the game engine industry is fiercely competitive, there is a lack of competition in the niche of flexible TN game engines. Combined with the important design differences in the structure of TN and RTP games, it seems possible that such an engine could achieve success, and maybe be the start of a new type of game engines. Furthermore, investigating whether such a type of engine could benefit from an AI library could help increase the advantage of such an engine over traditional game engines when it comes to TN games. We have noticed that while many different game types employ many different AI methods and technologies, TN games share many common traits, most notably the graph-based structure. Revealing which AI techniques are useful could not only be useful to give the engine an edge, but could help guide future engine development. This help includes RTP engines for those AI techniques tested which are not specific to TN games. Given these considerations, we have decided on the following assignment description. Assignment description: 1. Design and implement a flexible TN engine. 2. Investigate several AI techniques as candidate parts of a possible AI subsystem in the engine. As part of the development, we have also decided to implement a game on top of the engine, such as to help the development of the TN engine, as well as to help test and evaluate the AI techniques. To help guide the development, we also have some long-term goals. These are not expected or guaranteed to be fulfilled in the project, or in the near future, but they will be important in regards to guiding the requirements and designs of the game engine. Long-term goals: 1. Create a flexible, TN game engine, which will be used to create at least directly in the language: http://unreal.epicgames.com/UnrealScript.htm 14 one successful game. 2. Make the TN game engine facilitate easier development of turn-based games than starting from scratch or using existing game engines. 3. Attract developers to help the chances of success of the engine. 3.6 Potential weaknesses and difficulties of the chosen assignment While we believe that the chosen project assignment is good, there are some difficulties. Particularly, the disadvantages of a TN game engine against an RTP game engine, and the question of why no one have made a successful TN game engine before. The main disadvantage of a TN game engine against an RTP game engine is the types of games that each engine type can support. If games are split up in regards to turn-based and real-time, and node-based and position-based, it is seen that an RTP engine is considerable more flexible. The type of games the engine types TN and RTP supports: Turn-based Real-time Node-based TN, RTP RTP Position-based RTP RTP Examples of games that are node-based and real-time includes the old RTS games Dune 2 and Warcraft 2, which feature large grids. Examples of games that are position-based and turn-based include Darkwind: War on Wheels and Brotherhood of Battle. While research indicates that the bulk of games fall into the category of either TN or RTP, successful games still occur in the categories of real-time, node-based games, and turn-based, position-based games. Furthermore, games that mix the genres, for instance having one part of the game being TN, and another part being RTP, are only supported by RTP style engines. We believe that this is somewhat of a problem, but not a critical one. There are many successful, pure TN games, and not all players desires a mix of genres. Specifically, there are a group of players that appreciates that fast reflexes are not required to play and enjoy TN games. Mixing the genres might prevent this group of players from enjoying a game. 15 The question of why no one have made a successful TN game engine before might indicate that such an attempt is futile. Two counter-arguments against this claim could be: • There are more RTP games than TN games, and this single fact can explain why RTP engines are the most common type. However, the game market have grown enormously in the last decades, and we believe that the TN game market has grown with it, making the niche market big enough for specialised engines. • Secondly, TN games require less computing resources than RTP games. This might explain why there have been more development in RTP game engines instead of TN game engines. It could also suggest that any TN game engine needs to focus on a design that grant advantages over not using the engine, such as providing AI subsystems useful to TN games, and tailoring the engine design especially well to TN games. 16 Chapter 4 Engine requirements The main source of requirements is the users of the game engine, the game developers. There are some general requirements from these users. Defining and investigating their requirements will be important to the success and usefulness of the engine. The following sections will first discuss the game developers requirements, then the engine design will be discussed, and finally the requirements will be fleshed out. 4.1 Game developer requirements When designing a game engine for game developers, there are some general characteristics that are important for game developers: • Portability • Cost and development time • Complexity and skill requirements From a game engine point of view, these are addressed by focusing on different aspects: • Providing generic subsystems in the engine to handle common tasks, such as graphics, networks, etc. These subsystems should hide difficult and time-consuming aspects of the aforementioned issues. For instance, mul- 17 tiple engines hide which graphics API is used. 1 • Providing (visual) rapid development tools, such as level editors, animation editors, scripting, all often combined in an integrated editor. This both eases and speeds up development. While not necessarily part of the engine, the engine can be specifically tailored to support these tools. 2 • Choosing the right technology. If the technology chosen is platformdependent, neither the engine or its games will be usable on other platforms. While this is done by some game developers, it usually means a considerable decrease in the potential players of the game. See the technology part for more. The second aspect is important, but not necessarily vital. Editors can always be built upon the engine or added, and while they speed up the content creation, it will not make the game run faster, have better graphics, become more stable, etc., apart from the fact that the time saved by editors can be used to improve these aspects. Several engines provide no or few development tools. Considering that the project time is limited, the rapid development tools may not be provided; while they are worth the time, they take a lot of time to implement, and the engine itself has higher priority. Besides, if the engine has a good design, it will be easier to add these tools later, including when the engine is being used. Amongst the subsystems, the pure basics are needed: a way to handle graphics, a way to write game logic and AI code and a User Interface (UI) system. In this vein, the game logic and AI code is especially interesting, because it seems likely that these subsystems can be structured more efficiently for TN games than typical for RTP engines, given the differences in structure of TN and RTP games. A subsystem that is not necessary, but also interesting, is the multiplayer subsystem. Not only is multiplayer often important for TN games, it might also be handled differently in a TN engine, possibly giving the engine another edge over RTP engines. A subsystem which is not strictly necessary, but is important nonetheless, is the resource reading and writing. Such systems are useful when resources like textures, sounds, levels, objects, save games, configuration, etc., needs to be 1 The jMonkeyEngine provides no visual editors, and hides whether JOGL or LWJGL is used. http://www.jmonkeyengine.com/wiki/doku.php/complete˙features˙list The OGRE graphical engine provides no visual editors, and hides whether Direct3D or OpenGL is used. http://www.ogre3d.org/about/features 2 The Unity engine is designed such that it is possible to pause the game, step-wise go through the game, and even edit resources such as textures, sounds and scripts on the fly. http://unity3d.com/unity/features/ 18 handled. A few games can be made that do not need such resources or contain them directly in code. However, resource IO is integral to most games, including those in the TN genre, and developing and testing without resource IO could hide flaws in the engine design. The inclusion of some form of resource reading and writing would therefore be desirable. Below the different subsystems will be discussed. Several factors will be considered when discussing them, such as project time constraints, usefulness, how they maybe differ from their RTP equivalents, etc. 4.1.1 Graphics The graphics subsystem is needed, because it is the main way to communicate output to the players in the vast majority of games, and because it is a major part of the aesthetics of most games. Most graphics systems are split into whether they support 3D or not. While 3D can enhance the game experience a lot, it is not vital, and it can take a lot of work and good design to make a good 3D engine. Besides, it may be possible to integrate the engine with existing 3D engines, such as the jMonkeyEngine, which is based on Java and is primarily a 3D engine. As long as the graphics system is replaceable, implementing a basic 2D system should prove sufficient. Some 2D TN games are not animated, but simply shows the graphics as they are, and updates the graphics immediately once something happens. While this is easy and efficient, it is not optimal for all TN games, and to help ensure that the game engine can properly handle 2D graphics which includes animation, the engine must implement it as well. 4.1.2 Game Logic The game logic system can be written in many ways. In RTP engines, the typical game logic system is that of a step system: perform a number of steps each second, such as 30 times per second. This is a good system in a real-time game, since it handles the need to change the game state continually. In contrast, the game state in turn-based games does not need to change continually, but only when the player takes an action. This means that a turnbased game needs to sort of “stand-by” in an RTP engine, and wait till the player actually acts. In RTP games, where synchronisation is important, the mixing of the game logic, AI, graphics and sound code is quite practical. But in a TN game where such synchronisation is not necessary, such mixing indicates that concerns are not separated. A system where concerns are separated is desirable for multiple reasons. For 19 instance, if the competitiveness of an AI needs to be tested, the graphics and sound would be easy to turn off, if the code is not mixed. However, whether such separation can be achieved can not be answered at this point, since the subsystems are interdependent. For instance, the graphics system needs to access the game state, and needs to be able to react to state changes and player actions. A key difference between TN and RTP games is that RTP games have constantly changing game state, which a TN game does not. For RTP engines, the assumption that the game state changes constantly is typically a part of how game logic is structured and executed. Frequently, a game loop is run in the engine, which executes code that can change the game state. While this fits RTP games very well, it does not fit TN games well. Game state only needs to be changed once the player acts, and changing it at any other time is generally an error. Furthermore, code in the game loop may not take too long to execute, or the game may end up lagging, since the game loop does not only handle game logic, but also graphics and IO. This means that some events may have to be split up or run outside the game loop, indicating a need for some sort of synchronisation. If a game logic system can be implemented, which does not expect the game logic to change the game state constantly, but instead expects that the game logic only changes the game state in reaction to a player action, it would give considerable advantages over RTP engines when writing TN games. It seems easy to implement a logic system which supports reacting to the player; wait until the player acts, and then run the game logic code related to that action. This would make it easier to write TN games, and should therefore be included as a requirement. On the other hand, how to separate concerns is not immediately clear, and should therefore be an optional requirement, because it may not be possible without too much work. 4.1.3 Multiplayer Multiplayer is a great subsystem to have, because it enables playing between multiple players and not just against an AI. Playing against an AI is rarely as interesting and unpredictable as playing against human players, and some games can skip the often difficult challenge of implementing a good AI by implementing multiplayer. Furthermore, the replay value can be increased through the use of multiplayer modes. 3 Nearly all board games are designed to be played by multiple human players, which makes multiplayer an integral part of most computer game translations of such games. Some TN games support hotseat for multiplayer, such as Heroes of Might and Magic 3. Hotseat means that the game is played on the same computer by two or more players, and the “hot seat” refers to the changing of seats between 20 turns. Either hotseat or network multiplayer should be implemented. This would help ensure that the game engine systems supports multiple players at once. Without such a system, a hidden constraint for multiplayer modes may be discovered late in the process. Since TN games do not need to constantly update the state, the loose constraints may allow the design and implementation of a general multiplayer system. If this system is effective enough for the vast majority of TN games, it would make networking considerable easier for developers. Investigating a system which will make multiplayer relatively easy for TN games in general is desirable, but it may take a bit too much time to design and implement properly. 4.1.4 AI The AI system is often important in TN games. There are several facets of an AI system: • Game logic data structures • AI libraries • AI tools In regards to data structures, the main data structure is the graph, represented by nodes connected to each other. Supporting this data structure directly in the game engine makes a lot of sense, because all TN games needs to have nodes. Furthermore, having the same general node structure means that general algorithms can be developed for this data structure. Of course, different games may require different nodes, and the node data structures/algorithms should handle this. AI libraries and tools can be both TN specific and general-purpose. While many engines do not provide these, or provide them for a very specific task (such as path finding in FPS-games), AI is frequently important for TN games as mentioned in an earlier section. Since we have decided to implement several AI techniques, the AI tools and libraries are discussed in their own section. 3 All MMO-games (massively multiplayer online) are meant to be played for years. The RTS game Starcraft, released in 1998, have grown a large community worldwide, and even a professional league, based on its multiplayer. http://en.wikipedia.org/wiki/StarCraft˙professional˙competition 21 4.1.5 Resource IO The resource IO system includes the reading and writing of different game resources. While it is not strictly necessary to have, games often contains many different resources, and incorporating the handling of resources early will make it easier to use and test the engine, such as in the form of test games. 4.2 Feature requirements Given the discussion above, 2 lists of required features have been made. The primary requirements must be met. The secondary requirements include items which would be quite good to have, but may not be possible, for instance due to the time constraints on the project. Primary: 1. Basic 2D graphics system. The game engine must support 2D graphics, including animation. 2. Basic TN game logic system. The game engine must support a game logic system. The system must support TN games at the structure level. 3. Basic multiplayer. The sample game must support either hotseat or network multiplayer. 4. Basic TN AI system. The game logic and AI system must support a flexible, general node data structure, which will make the basis for general algorithms. “Flexible” and “general” means that the data structure and possible algorithms should be customisable to any given game, such that re-implementation of the data structure and general algorithms will not be needed for the vast majority of TN games. Secondary: 1. Implement a basic TN multiplayer system. The implementation of a general multiplayer system, that both serves the vast majority of TN games, and makes multiplayer implementation in games using the engine easy. 2. Support playing over the internet. Support and testing for playing over the internet. Complete support would include a lobby service, such that finding other players would be very easy. 3. Completely separate game logic, graphics and AI code. The complete separation of game logic, graphics and AI code, such that each part in a 22 game can be coded somewhat separately without concern for the others. 4. Basic resource IO system. The system must handle the reading and writing of resources, and must make it easy to organise and find resources in the game. 23 Chapter 5 AI requirements The first part of this section will introduce and discuss AI aspects in the context of TN games. It will then present common tasks and related technologies of TN games. A discussion of the desirable aspects of candidate AI libraries and tools in regards to a TN engine then follows. A special type of AI tool, a domainspecific language focused on supporting AI, is discussed as a candidate to the TN engine. Finally, a list of requirements is presented. 5.1 Aspects of AI in TN games It has been discussed in previous sections why AI in TN games play an important role. This section will focus on different aspects which are important in regards to AI. In the end of this section, the needs that AI libraries and tools need to fulfill will be summarised. An aspect to consider about AIs in games is that the AI code is often specific to one or a few games. There are 2 reasons for this. As a consequence of the different game rules the AI have to solve different goals and tasks. Games sharing game logic concepts, such as graphs, may share some tasks. The second reason is that the code may be optimised for performance. Different games have different task dimensions. For instance, one game handling a few units path finding through a complicated, weighted graph; versus another game handling 30.000+ units real-time path finding through a small and simple graph. Using the code of a game in place for the code of another game may lead to performance issues. As mentioned earlier, this is less of a problem in TN games, where there is 24 generally plenty of time to compute AI tasks. Furthermore, the common data structure, the graph, makes it likely that some tasks are common for many or even the majority of TN games. The premier example is path finding. Of course, the issue of intractability is frequently a problem in AI, even in TN games, and making the general handling of the common tasks effective enough may become an issue. Another aspect to consider is that different requirements can be given to AIs for different games. While some AIs are focused on being as competitive as possible, such as is often the case in the game Chess, other AIs try to be entertaining by not being as competitive as possible. In these games, a good AI can be given faults and random behaviour to ensure that it is more entertaining. As Jonny Ebbert, the lead designer on Dawn of War 2, said1 : Add frailty but avoid stupidity. A.I.s need to make mistakes for the player to exploit from time to time but they shouldn’t look dumb doing it. A.I’s aren’t fun to play if they always trigger their abilities perfectly when they have the chance . . . But they need to stay in the range of competency when they do make ‘mistakes.’ It’s a fine line to walk, but an important line. Randomness Making parts of the AIs decisions random might mean that it becomes more competitive. Some players utilise the fact that some game AIs are fairly or completely predictable to lure the AI into traps. While this is entertaining in some games, it might lead to boredom, since the same, simple strategy/tactic may work every single time. Adding random behaviour can break this tendency. An element that can help create game longevity and re-playability is if the AI can change its behaviour over time, for instance by reacting to different strategies used by the player. While the behaviour may well not be optimal in these cases, it may defeat the player if the player depends on using the same strategy or tactic, i.e. trap, over and over again. Cheating In this report, “cheating” is not defined as letting the AI and the player have different premises, such as the AI having a bigger base in a special mission. Instead it is the hidden changes in rules for the AI that work to its advantage. Cheating AIs are not only common in some games but also encouraged by game developers. To quote the lead designer on Dawn of War 2, Jonny Ebbert2 : 1 http://kotaku.com/5271733/the-three-or-more-or-less-laws-of-gaming-ai 25 Cheat wherever you can. A.I.s are handicapped. They need to cheat from time to time if they’re going to close the gap . . . Never get caught cheating. Nothing ruins the illusion of a good A.I. like seeing how they’re cheating. An example comes from RTS games, in which it is common that the AI is granted resources for free when it needs them, or seeing all of the game state in a game with hidden information. Another reason for cheating can be efficiency. As an example in first-person shooters, letting the computer players ask the engine for the position of the player is much more effective, than having them compute it themselves. While many games accept cheating, some TN games are both challenging to write AI for and is expected not to cheat. Examples are the games Chess and 9 Mens Morris, in which the game state is completely visible. However, cheating can be used together with a well-developed AI to enhance the game experience. A well-developed AI can still be weak, and adding a little cheating can uphold the illusion of no cheating, while still giving a good challenge. Furthermore, a well-developed AI can more easily afford doing deliberate faults, faults that may help make the AI entertaining, if it also cheats. Thus, even TN games that cheat can benefit from AI tools and libraries. Changes to game rules Game AI often contains knowledge collected from human players playing the game. Properly designed, simple game rules can give rise to complex tactics and strategies. An example which can clearly illustrate this is the simulation program Life3 , in which 4 simple rules and an initial setup in a graph can give rise to surprising and complex results. However, the creation of these interesting and complex rules can be difficult to attain for game developers. Constant testing and tweaking may be required to get the desired result. Not only does the game rules have to give rise to complex games, they also have to be entertaining for human players. Apart from the development process, game rules can also be changed once the game is already deployed. This may be done for many reasons, including balancing the difficulty level, leveling out the power level in multiplayer games, or creating a new experience. This occurs frequently, especially in multiplayer games, where a fair fight is expected by players. Another example is variations of known games, such as Chess. The frequent changing of game rules can affect the AI. Since the game AI frequently contains game rules and human experience on how to play, rewriting the AI may be required, and if the AI is dependent on human knowledge to work 2 http://kotaku.com/5271733/the-three-or-more-or-less-laws-of-gaming-ai 3 Also known as Conway’s Game of Life. 26 properly, the game must be tested somewhat before the AI can be updated. AI libraries and tools that facilitate changing the AI quickly or even automatically in response to new game rules will be useful to ensure that the AI is up to date without much work. Summary Given all these aspects, a summary of qualities that can be useful for TN AI libraries and tools can be extracted: • Support for common tasks occurring specifically in TN games, such as path finding and map analysis. • Support for unpredictable behaviour and faults, such as through randomness or changing approach over time. • Support for rapidly reacting to game rule changes, either allowing quick adoption through general libraries and tools, or even automatic adoption. 5.2 AI tasks and technologies in TN games Path finding A main task of any game AI is to analyse the game state and extract useful information. In any TN game, the graph is a major data structure. Moving around pieces is very common, and this often requires path finding of some sort. There exists many different search algorithms for graphs, and implementing one or several of these is likely to benefit the vast majority of TN games. Of course, some TN games, like Chess, benefit less from this searching, because the board can be represented as a grid instead of a graph, and the units move in special ways according to this grid. But this is the exception rather than the rule. Another use of graph searching is the search of more abstract graphs, such as game trees in Chess, where the possible moves from each player is considered. Information extraction and analysis Apart from the task of searching and finding paths, the main game graph can also be investigated in other ways. In TN games, positioning often plays a crucial role. Extracting information based on positioning, such as finding positions according to some criteria, can be very useful in many TN games. Examples include finding the nearest, desirable resource, the strongest enemy that can be taken, a good position for blocking the opponents units, finding the spot for the next base, etc. Even in games such as Nine Mens Morris, it could be a task such as finding places suitable for getting 3 pieces in row without the 27 opponent interfering. While these techniques are not specific to TN games, and also occur in realtime, node-based games, more time for complicated analysis is available in TN games. This means that there is less of a need for algorithms optimised for speed for specific games, and that general algorithms should be reusable for the majority of TN games. Decision making The previously mentioned methods are specific to TN games. Many other information gathering and analysis technologies also exist, which are not specific to TN games. Whether some of these are especially suited to a majority of TN games is unknown to us, but investigating a selection of technologies may uncover their usefulness as AI libraries for TN engines. Once information has been extracted, the AI must decide what to do. While the information extraction can be specific to TN games, the decision making is not, except that the time constraints are less strict than for RTP games. Many different technologies and methods can be used in this section, and there is no general methods or technologies that fit TN games particularly well in general. A general trait for the majority of TN games is that there is an opponent of some kind. It is possible to have TN games that have no opponents, but still use AI. Possible uses of AI in such games include using AI to automate certain tasks for the player. However, such a use appears to be rare. In the following sections, decision making will therefore assume that the tasks include adversaries. Note that TN games do not need to be zero-sum; TN games include examples in which actions are mutually beneficial between players. A few TN games fit a certain area of AI technology related to adversarial search (AS), and it is mentioned here since AS is specific to turn-based games4 . In the note, several games are mentioned use adversarial search. These include Checkers, Othello, Chess, backgammon, Go, etc., all of which are not just turnbased, but also node-based. For these games, the technology used is generally very successful, and could be seen as a candidate library for a TN game engine. However, the technology generally assumes that information is never hidden, and this is a major constraint. Many TN games deal with incomplete information, and this means that the AI library would only be useful for a small amount of TN games. 4 Page 161 and 162 Artificial Intelligence: A Modern Approach, Second edition, Stuart Russell, Peter Norvig. 28 The typical playthrough of a TN game rarely consists of one or two actions. Instead, several actions are taken over the course of a game. Usually, several actions are taken in sequence to fulfill one or more goals. For instance, in Chess, this could simply be to win, or in a more advanced game like Civilization, it could be a sequence of actions trying to establish a new base. Actions would include preparing units fit for the task, finding a suitable site for the base, preparing roads and “terraforming” the landscape, preparing transportation and defence for the units, etc. However, the basic assumption in regards to the games of the TN engine is that games have opponents. This means that any planning must be able to handle opponents trying to prevent the plans. While this situation is common to many types of games, not just TN games, investigating AI technologies handling this could still yield good results, since planning is a difficult and complex problem, especially when combined with adversaries. Machine learning Another aspect of TN AI is utilising domain-specific knowledge (DSK). In typical TN games, DSK is programmed directly into the AI using the AI programmers knowledge of how to play the game. While this can help making the AI competitive, and avoid intractability issues through use of heuristics, it means that changing the game rules causes a need for rewriting the AI to some degree. An AI discipline that may help solve this issue is machine learning. Machine learning depends on the AI repeatedly playing games, learning as it plays, and becoming better over time. Many algorithms and methods relate to this area, such as the genetic algorithm, which can take a set of heuristic values and seek a global optimal solution. While the use of heuristics may not seem clear immediately, it is used in many games to help solve intractability. For instance, in Chess, it is popular to use heuristics when evaluating a game board, instead of having to calculate all possible results that can come from that board and use that as its score, which is intractable for most Chess board situations. One way to use heuristics would be to let the AI find the values for the heuristic itself. If the game rules changes, the AI may be able to adapt to this by learning that the previous used tactics are no longer effective, and finding other tactics that are effective now. Another possible advantage of machine learning is that the AI may exhibit surprising (and competitive) behaviour. This may help the re-playability, since a changing AI gives different challenges over time. It may also help competitiveness, because an AI that can learn might become less predictable and more competitive. It may also let the AI react properly towards traps laid by the player, based on the players assumption that the AI always reacts the same. 29 A disadvantage of the use of machine learning is that it needs players to test against, and using human players is frequently not practical. Furthermore, it takes time to train the AI, and typical machine learning problems can occur. In the example with the genetic algorithm, it may end up finding a “locally optimal” solution, and end up never finding the globally optimal solution. 5.3 AI tools A main purpose of game engines is to decrease the complexity and requirements of development. While the use of libraries and existing components can save time, the libraries frequently have to be used in a way specific to a particular AI. This is especially true in regards to AI, since game rules generally affect the development of AI in many ways. In many game engines, a frequently developed game engine tool is the domainspecific language (DSL), which is often known as “game scripting language” in the game development field. These languages provide several features and language constructs that make game development easier. Frequently, the purpose of the language is to program game logic, which is frequently subject to change both during and after development. However, some script languages provides support for AI development, which can be seen in the UnrealScript language. This language is developed for an RTP engine focusing on first-person shooters, and the well-known use of state machines for programming AI agent behaviour is supported directly in the language via special constructs. Part of the reasoning behind this was that state machine programming in the language of the engine, C++, was unmaintainable, difficult and error-prone. By providing a language with direct support, these problems are handled much better5 . Other AI tools include describing the game rules in a DSL. This effort is often part of the project for general game playing, the goal for creating a single AI which is capable of playing multiple games. The advantages in regards to game rules changing are obvious; the AI does not need to be rewritten. Not only that, once an AI is updated for one game, it may perform better in several games. Effectively, it might cut away the whole cost and time of developing AI for any single game. Several projects have worked with this approach. One project is the Zillions 5 UnrealScript, a game engine used for several projects: http://www.unrealtechnology.com/ Manual describing the UnrealScript, including their support for state machine programming directly in the language: http://unreal.epicgames.com/UnrealScript.htm 30 of Games project, which thousands of games have been written for using their DSL6 . Another project is the General Game Playing project of the Stanford Logic Group, which has featured competitions in which multiple different AIs have to compete for which is the better in many different games (40+ games in the 2007 competition)7 . While such projects are very interesting and incredibly useful for the games they support, the types of games they support is currently very limited. According to the authors of Zillions of Games, the project badly supports hidden information, and simple arithmetic can not be used in the game rules. We believe that at the current AI technology level, these kinds of constraints are necessary in order to have general AIs that perform well. Since the large majority of TN games may be excluded by these constraints, the approach is not practical here, even though the future developments in AI may make it practical. Of the 2 approaches presented above, the first is the practically useful in this project. However, finding common elements of game AIs is not always obvious. A possible way to find these is to look for commonly performed tasks, that may be error-prone, ineffective, etc., and try to abstract them into language constructs. Even without language constructs, an AI DSL would still be of some use. Providing a sandbox, in which AI scripts can not crash the game engine, and provide the ability to program the AI without having to recompile the engine, maybe even programming the AI on the fly, are possible benefits. However, DSLs are not without their disadvantages. Besides taking considerable time to design and implement, they typically require more memory and/or processing power for the same tasks, and they take extra time to learn for game developers. 5.4 AI feature requirements Given the above discussion, 3 parts has been focused on: • TN-focused libraries. • Machine learning libraries. • DSL for AI. 6 http://www.zillions-of-games.com/ 7 http://en.wikipedia.org/wiki/General˙Game˙Playing http://en.wikipedia.org/wiki/Zillions˙of˙Games http://games.stanford.edu/ http://cadia.ru.is/wiki/public:cadiaplayer:main 31 We have chosen to work with TN focused libraries because we believe that it is possible to implement TN-libraries that will be beneficial to the majority of TN games. Furthermore, some libraries are obvious; such as path finding, with a solid basis for general path finding problems. The machine learning libraries were chosen for several reasons. The primary reasons are their advantage in regards to game rules, DSK and replay value. Furthermore, machine learning is useful to TN games in general. While not every game requires them, even abstract TN games such as Chess can take advantage of them. Finally, machine learning is a research field like most AI, and machine learning is still a new theme in game AI. Applying it to TN games may help uncover which techniques are useful to TN games, and which are not. The DSL for AI have been chosen partly because a DSL supporting TN AI is very useful to developers, and partly because designing and implementing a DSL is a challenging and exciting goal. Based on the discussion of the previous sections and the above, 2 lists of requirements have been made. The primary requirements that must be met. The secondary requirements includes items which would be quite good to have, but may not be possible, for instance due to the time constraints on the project. Primary: 1. Graph-based search library. The game engine must provide and test at least one method related to searching in graphs. The method should be somewhat general, being usable in multiple TN games. 2. Machine learning library. The game engine must provide and test at least one method related to machine learning. 3. Graph-based information extraction and analysis. It would be good to utilise the graph-based structure of TN games in regards to information extraction and analysis. At least one method of information extraction and/or analysis should be provided and tested. Secondary: 1. A TN AI domain-specific language should be supported. The language should have at least one TN AI specific language construct. The language should provide better support for AI than the engine language. While the utility of such a language would be great, it is included as a secondary 32 feature due to several factors: implementing a language is a big task which may not be possible given the time constraints; and extracting the specific language constructs may not be possible in the given time. We believe that the primary requirements are attainable within the given time constraints, and that they are interesting and useful. All the libraries should be able to support the majority of TN games, and implementation should not take too long. The secondary requirements are not many, but a scripting language is a big task. Furthermore, the primary requirements can always be extended with more methods. 33 Chapter 6 Technology The programming language chosen for the project is Java. Traditionally, most engines use C or C++ in their engines 1 . Besides being widespread, C++ is a popular choice for making games and game engines due to its speed, its support of abstraction facilities, including object-oriented and generic programming, and its ability to interface and take advantage of hardware directly. In this light, Java may seem as being the suboptimal choice. There are two main reasons for choosing Java: the first being that we are much more familiar with Java than C++, and that using an unfamiliar technology (which is not just the programming language itself, but libraries, coding solutions, development tools, building process, etc.) could have considerable negative impact on the project by having to invest a lot of time in the technology. The second reason is that we believe that Java is well suited for making games. Speed matters a lot in game development, and Java was considerably slower than C++ in its early days. However, the present speed of Java is today on par with C++, and Java is widely supported. Furthermore, the speed at which graphics handling is executed, a major competition point for many games, matters today less and less on the speed of languages, and more on the graphics card, where the major bulk of computation happens. While C++ can interface faster with the graphics card, and interfacing to be done through native calls (to, for instance, C++), 1 http://en.wikipedia.org/wiki/List˙of˙game˙engines the majority of listed open source engines uses C or C++; the well known commercial game engines, Source (http://source.valvesoftware.com/programming.php) and Unreal Engine (http://www.unrealtechnology.com/technology.php), are written in C++ 34 the speed penalty has turned out not to be an obstacle for fast 3D graphics 2 . Another indication of Java being suitable is the emergence of Java based game engines 3 and several successful Java games for the PC, of which some both run directly within the browser and include 3D graphics, only assuming that a JVM is installed4 . Many C++ engines do not support the running of games within a browser. Regarding platform support, Java supports all of the major operating systems, and is widespread on many different phones. However, Java is not supported directly on any of the main gaming consoles (Playstation 3, Xbox 360, and Nintendo Wii), and for game developers wishing to run their games on these consoles, Java is not an option. Finally, Java has little game technology compared to C++. While this may change, given that Java has become a valid alternative for games, the current situation is that C++ provides better support for game development. Overall, Java is a decent technology choice for PC and phone game development. The main issue with Java is the lack of support on the 3 major gaming platforms (Xbox 360, Playstation 3, Wii), and the greater support that games based on C++ enjoy. If game developers wish to develop games for the console, they must avoid Java, and game engines based on Java. We believe that the main market for TN games is the PC, but if it becomes a priority to support the consoles, a possibly expensive and time-consuming technology shift is needed. In the case that another technology than Java is needed, we would recommend C++, considering its great support in regards to game technology, its decent features considering game development, and the support for consoles. However, the relative difficulty of learning and using C++ should be considered. 2 http://jogamp.org/jogl/www/ 3 http://www.jmonkeyengine.com/home/ a popular java game engine 4 Three examples of Java games, featuring 3D graphics, running in the browser: http://www.banghowdy.com/ http://www.tribaltrouble2.com/ http://www.runescape.com/ - (client side in Java) 35 Part II Engine 36 Chapter 7 Design In this chapter we describe some of the important choices in the engine design. 7.1 The original implementation The project started using an existing code base, which had been developed without a lot of consideration to design. This section will briefly describe some of the issues with the original implementation. Separation of concerns In the original implementation, there was little separation of concerns. For instance, the game logic code was intermixed with the graphical code. This design was inspired by RTP engines, where the close integration provides fine-grained control over several subsystems, such as graphics, sound and AI. As described in the analysis, such a close integration is not needed in a TN game engine due to the lack of constant state changing. Several difficulties were experienced with this system. For instance, game logic developers had to understand the graphics system in order to code game logic. Another issue was that replacing the graphics system would be very difficult. This became necessary later in the lifetime of the game engine, and while it might have been possible to write a wrapper around the new graphics system, it would have been a suboptimal solution. Another difficulty was that mixed game logic and graphics code meant that it would be non-trivial to run the game logic code without any graphics being executed. For instance, if a machine learning method was to be used, running any graphics at the same time would be a waste of resources. 37 Internal and external communication All clients shared the same immutable game state. For each move a new game state would be generated, which would be passed to the clients. A design like this greatly complicated things like adding network multiplayer support. The network module would have to either transmit the new state entirely or generate a “state-difference” and transmit that to the client. Neither of these two options are very optimal, specially when they had to be done once per move and not per turn. Another issue was the constant regeneration of the game state. While TN games require less resources than RTP games, their game state can still become large. Constant regeneration of the game state does not scale well in the size of the game state, and this would hurt performance. Using another design for internal communication which scales better is desirable. 7.2 Event-based system In order to improve the engine, we replaced parts of the previous implementation with an event-based system. With this design, the goal is to obtain several aspects that were missing in the previous implementation: • Subsystems that support TN games especially well. • Better separation of concerns. • Better communication. Introduction The event-based system is based around looking at subsystems as clients and the control subsystem as the server. When there is a change in the game state, the engine will emit an event to all clients. Events are first and foremost game logic events, which means that they intend to change the game state. However, other subsystems such as the graphics system can still take advantage of events. For instance, if it receives an event about a unit moving to a new position, it can use this event to animate the move in the GUI. For clients, this changes a number of aspects compared to the old design. First off, the clients now receives a small notification of what changed instead of the entire state. Clients are no longer required to use the same representation of the game state; in fact they now have to maintain their own private copy of the game state if they need such a thing. 38 While this costs extra memory since some clients now have to maintain their own game state, it added the flexibility for clients to examine the state both before and after processing the given event. The other major change is that all clients now receive an event when something changes. Previously they were only informed of the current state when it was “their turn”. This infrastructure is also much better at handling clients that only observe the game. Changes to the subsystems In the following sections, the subsystems that were affected a lot by the change to the event-based system is described below. 7.3 Graphics system The graphics system is mainly used as an interface between the game and the player. In this discussion, the graphics system will not just encompass the drawing part of the system, but also related issues like a graphical user interface, and the IO with the player. This makes the graphics system a considerably more complicated system. A part which is separate from the graphics system, but is commonly included in the graphics system, is the game logic system. The game logic system is needed because the graphics system needs to know the state of the game for several reasons, and using an existing system saves the work of reimplementing a whole system to handle logic just for graphics. An example can help illustrate the practical value of integrating the graphics system with GUI, IO and game logic. Imagine the simple clicking of a unit on the screen. The IO system communicates a click, and this is registered in the graphics control. It is then computed what graphics were clicked, and the corresponding unit in the game logic is retrieved. Now, the GUI is updated with the game state of the unit, such as health left, and possible actions based on the unit is shown. This simple example illustrates the need for a close integration of the aforementioned systems. Of course, it should also be noted that the game logic system does not need to know anything about the graphics, and this important detail means that the same game logic system can serve a game recorder, a graphics system, or an AI player equally well without problems. 7.4 Game logic system The changes to the game logic system is profound. Instead of communicating and sharing game state with all components, it is possible for each component to have their own game state. While this separate concerns nicely, it can also 39 create a scalability problem. If the game state is large, and each (AI) player have their own copy of the game state, the number of game states would be linear in the number of players. However, the game state has to become very large before this can become a problem, and in the worst case, it should be possible to set up AI players to use the same game state. In the case that several human players play a game, the likely that they don’t use the same computer rises with the number of players (hotseat playing is rarely used with more than 2 players), and thus more memory will also be available. Another change that the system can lead to is different game states for different players, assuming that different events can be sent to different players. This is especially relevant for hidden information games. In these games, the players frequently have different information about the world, and therefore also different game states. In games such as Age of Empires 2, each game instance have the complete game state, even though games in general are based on hidden information. The cause of this is due to the need for high-performance networking - by making it possible to run the same simulation on all machines, much less information needs to be transferred. However, this means that a particularly clever player could hack the game and extract this information, allowing the player to see what other players see, counter their strategies immediately, never going into traps, etc., basically cheating. While this may be somewhat difficult, it is still possible, because each game instance have the complete game state. Such cheating is impossible if the game states on each computer really is different. The only way to cheat would then be to watch the network traffic from the server, or compromise the server which would know the whole game state, but this can be seen as considerably more difficult. 40 Chapter 8 Implementation 8.1 Graphics system Drawing systems The graphics system is based on 2D-drawing. In regards to 2D-drawing, there are 2 general methods of drawing. The first is the spritebased drawing, in which images stored as pixels are drawn to the screen. Sprites are a series of images which together forms an animation. The second method is the vector-based drawing, where images stored as vector descriptions are drawn to the screen using vector-drawing libraries. The main differences between the two are that vector-based drawing generally takes up very little space and can be scaled without loss of precision, while sprite-based drawing can contain much greater detail and draws faster, especially with hardware acceleration. Most 2D-games use sprite-based drawing. This is a common choice, since speed is one of the foremost needs when drawing. It is also due to the speed that sprite-based drawing will be used in this project. Time-fraction drawing When drawing in RTP games, the drawing is frequently handled in the main game loop together with the game logic. As discussed before, this mixing of different concerns is accepted in RTP games, since the game state may change constantly, and precise timing is important. This is not the case with a TN game engine. In fact, based on the events that the graphics system receive, the drawing can be completely predicted until the next event is consumed, since the game state only changes when events are received. Based on this, it was decided to try and implement a drawing system based 41 on time fractions. This can be used to implement a system in which the animation speed can change with animations playing smoothly. This is typically not possible in RTP games. For instance, if the animation speed is set to 10 percent, the game loop of the RTP game has to go ten times slower than normal. This means that the frame-rate might drop from 60 frames-per-second to 6 fps. Of course, animation speeds are frequently of little use in RTS games since RTP games generally are designed to go at a very specific pace. TN games do not have this expectation, since the player is really just observing the animation to see what have transpired, not because the player needs to react to what happens. And in this case, if the player is not all that interested in the events, the animation speed can just be turned up until something exciting happens. When tested in the game, the animation speed turned out to be quite useful for the game, and being able to quickly speed through battles until some interesting situation happened helped the debugging of the game. Hardware acceleration During the development of the game, we encountered issues with frame rate obtaining a decent frame rate. This was curious, because only a few hundred images were drawn to the screen every 10 milliseconds. Investigating this, we found that the main culprit was the non-accelerated nature of Java2D. This meant for instance that images containing transparency were drawn much more slowly than images without transparency. Basically, anyone using the engine would be forced to consider such an issue when implementing the drawing of their game. With today’s graphic cards in PCs such issues should not occur. To solve this, we decided to try and add support for hardware acceleration. This was achieved by using JOGL, a binding to OpenGL for Java. With JOGL it was possible to maintain a much more acceptable frame rate. 8.2 Game logic system and AI The main data structure of the game logic system, the node, is designed to be as flexible as possible. While many TN games have a “board” that is generated from a lot of small equal-sized areas, such as a grid made out of squares, a couple of games cannot easily be modeled in that manner. Examples include Risk and Axis & Allies, which consist of a board with different sized subareas. Due to the intend to support as many TN games as possible, it was decided not to assume that the game fields would always be based equal-sized areas. This also affected the kind of node structuring that could be used. Since grids were not an option, the main data structures for consideration was the 42 adjacency list and adjacency matrix representations. However, this choice was trivial. Game graphs in TN games are generally very sparse, and there are very few, if any, TN games that have dense game graphs. Furthermore, adjacency matrices have a high memory cost especially for spare graphs. Based on this, the adjacency list was chosen as the method for storing neighbours. Adding and removing nodes Early in the process it was decided to make the node data structure more efficient through the assumption that no nodes were ever removed or added. This allowed a couple of optimisations in the implementation of the node structures. The reasoning behind the assumption was that there are very few TN games that handles the addition or removal of nodes. Also implementing support for modifying a live graph could have added a considerable amount of needless complexity. However, it turned out that adding and removing nodes were quite useful in regards to game engine tools. Particularly, the map editor is built on top of the game engine using an ad-hoc extension to inform the engine that the graph should be made mutable. This saved a lot of time developing and keeping the editor up to date, since it was a lot easier to reuse parts of the game specific code, when the editor was built on top of the same infrastructure. 8.3 Multiplayer system The event driven design had the positive side effect of greatly simplifying the network implementation. It turned out to be enough just to create a serialization and a deserialization algorithm for the events that allowed them to be transmitted via the network. The event-based approach complicated an unforeseen area, namely waiting until given request to be processed by the game engine; which was first discovered when working on the AI leading to an fragile ad-hoc solution for the issue. One major issue is that a given request can result in multiple events; a possible solution to this could be to add an identifier to all requests and have the engine emit an event using that identifier to signal that the request has been processed or rejected. Alternatively events could be bundled into a set of events related to the request that triggered them. It would still require some identifier linking the request and the events, but it would allow clients to trivially relate all events to the request. Neither of these solutions have been implemented; while either would be a 43 vastly more robust solution than the ad-hoc solution currently implemented, time was invested improving other parts of the engine. 8.4 Resource IO and management The resource management (RM) system was not planned to be a part of the game engine. It was originally written as a part of the script engine to help it locate binary and source files, which were stored in different locations. While preparing the initial demonstration of the game engine, it was discovered that the game and parts of the engine had a lot of assumptions about where to find the resources, such as sprites. To solve this the resource handling system of the script engine was extended and slowly integrated into the rest of the code. The RM system handles the part of finding and reading resources. The method is based on the one used in Neverwinter Nights (NWN), where the game has a predefined list of locations to look for resources. In both this game engine and in NWN if multiple locations have a resource with the same name, the game will use the resource from the location with highest priority. Beyond file system locations, the RM system was extended to support reading resources from zip/jar files, since this was the format used in the demonstrations of the game during the development. Due to its extendible nature, it is possible to add handlers for other containers, such as tar files. There are at least two very likely candidates for improvements to the RM. One would be caching; either of the resource location or the data itself. Currently only the latter is possible and must be done by the resource using code itself. The other improvement would be to add support for writing resources. Currently only the game needs to write resources when creating a new map in the game editor. Nevertheless, if the scripting engine was completed, it might need to compile source scripts into binaries. 44 Chapter 9 Discussion Overall, the event-based system proved very successful for the TN game engine. Utilising this system is recommended to anyone implementing a TN game engine. The separation of concerns was achieved to a high degree. Though the graphics system still uses parts of the game logic system internally. The high degree of separation still gave several advantages. In regards to testing, the AI machine learning methods could be run without any graphics at work due to this separation. The communication was improved a lot by the event-based system, and it created a good alternative to the state-changing game loop employed in RTP games. Since the events can be sent over the internet as well as internally, using the event-based system to implement automatic multiplayer handling is a prospect worth investigating. Development of a flexible TN game engine The primary requirements of designing and implementing game engine systems focused on TN games have all been attained. 1. Basic 2D graphics system. The game engine supports 2D graphics, including animation, as well as a time fraction system and hardware acceleration. 2. Basic TN game logic system. The event-based system helped the game logic system avoid the game loop of RTP games. 3. Basic multiplayer. The sample game supports both hotseat and network multiplayer. 4. Basic TN AI system. The implementation of the node data structure is 45 flexible and can support the vast majority of TN games. The secondary requirements of designing and implementing game engine systems focused on TN games have partly been attained. Requirement number 1, 2 and 3 was only partly implemented. 1. Implement a basic TN multiplayer system. While the event-based system may be utilised to provide such a system, it was not reached within the time constraints in the project. 2. Support playing over the internet. Playing over the internet was only supported partially due to time constraints. In order to play over the internet, ip-address and port number of the host is needed, and no game lobbys exist for the game/engine. 3. Completely separate game logic, graphics and AI code. A high degree of separation was achieved, but it turned out to be impractical to make graphics completely independent of the game logic in practice. However, the game logic system was independent of any other system. Advantages in regards to testing the AI was also achieved, due to the separation. 4. Basic resource IO system. A basic system to handle resources was implemented and used successfully. 46 Part III AI 47 The following chapters will present the design and implementation of the AI libraries and tools, as well as test and evaluate the methods used, and finally discuss the methods. The first chapter, design, will describe and analyse the different requirements given to the different AI techniques. The second chapter, implementation, describes the chosen methods, the reasoning behind choosing them, and their implementation and issues found during the implementation. The third chapter will describe the scripting engine. The final chapter, discussion, will discuss the techniques and their use, reflect on whether further investigation is needed or recommended, and describe other potential techniques that the findings indicate might be useful. It will also discuss the value of adding AI libraries and tools to a TN game engine. 48 Chapter 10 AI Design The purpose of the following sections is to describe and analyse the requirements given to the different AI techniques. A major reason for including the AI libraries and tools is to estimate the usefulness of adding such tools and libraries to a TN game engine. If methods which are suboptimal at providing support to TN games are chosen, it may negatively affect the estimation of the value of such methods in a game engine. To avoid choosing such methods, several aspects and requirements are discussed that must be considered when choosing methods. This section will present this description and analysis. The description and analysis is organised according to their general category: • TN-focused libraries. • Machine learning libraries. • DSL for AI. 10.1 TN-focused libraries 10.1.1 Path finding According to the primary requirements for the AI, at least one method for path finding in graphs must be provided. Furthermore, the method should be as general as possible, to ensure that it is useful for many TN games, and not just a few. Several path finding methods are available for graphs. While this gives a great deal of options, care must be taken, since some of these have special 49 constraints. Special constraints might well mean that the path finding method would only be usable in a few games. To ensure that the chosen path finding method(s) will be widely useful for TN games, the following requirements and aspects were considered when choosing path finding methods. Graphs and edge weights In regards to TN games, the graph model varies a bit. In a lot of TN games, such as Nine Men’s Morris and Axis & Allies, the edge weight is always 1. Sometimes, the edge weight might differ a bit, for instance in the game of Axis & Allies where “land” units cannot go into “sea” nodes, and the reverse with sea units, but this can be handled without requiring weights on the edges. However, many other TN games gives weight to edges between nodes. These include Battle for Wesnoth, Civilisation, Advance Wars, etc., in which not only the path weights are different from 1, but they differ from unit to unit. Supporting different path weights from unit to unit should be supported by any path finding method chosen. Changing edge weights An aspect to consider is that the path weights in a TN game not only depends on the different game pieces, but frequently changes over time. A common example is that game pieces which can move can block for each other. This means that any path finding method should be able to handle changing weights properly. An example of a path find method that might not handle changing weights properly is a method that requires that the shortest paths can be computed once in order for it to be effective computing-wise. Since path weights change, the shortest paths may change as well, and this invalidates the computation of the method. Hidden information Another important aspect is the issue of hidden information. Many TN games contain hidden information, and this is frequently seen as covering parts of the graph. Furthermore, as game pieces are moved on the graph, which part of the graph that is hidden may change. This becomes an issue in several ways. First, the path finding should handle the hidden parts of the graph when calculating a route. Second, when the units move, more of the graph might be revealed, and the path finding method may become ineffective if it has to start over its path finding each time a small part of the graph is revealed. When choosing path finding methods, the aspect of how a method handle hidden and changing information should therefore be considered. 50 Summary In all, it was decided that the following aspects were the guiding ones in regards to choosing which path finding method to implement. 1. Supporting edge weights in the graph. 2. Changing edge weights during the game. 3. Hidden and changing information. 10.1.2 Information extraction and analysis Information extraction and analysis is the field of transforming knowledge about the game state into a form which is easier for the AI to reason about and to decide on. In order to determine which requirements should be given for the methods, the common extraction and analysis tasks for TN games is investigated. Graph-based methods For TN games, the position of the game pieces on the nodes generally plays a big role. A major representation and organisation of knowledge in TN games is the graph. While it is possible that there is methods that does not directly work with nodes but which are still very useful to TN games in general, it seems more likely that methods directly working with graphs will be better suited to TN games. An observation supporting the previous assumption regarding graphs-related methods are more promising is that positioning frequently plays a major role in TN games. Positioning relates to the place at which a game piece is placed in the graph. The importance is seen in the vast majority of TN games. An obvious example is Chess, where the position of the game pieces plays a major role, both at a strategic and tactical level. At the strategic level, protecting the king by position pieces is important, and getting the pawns forward is important, since the late-game may give the victory to the side with pawns closest to the opposing line (since a pawn reaching the final line can become a queen). At the tactical level, the threat which pieces pose to each other, and the king especially, can determine the game. In fact, the game is won when the game pieces are positioned such that the enemy king is checkmate. Given these considerations, only extraction and analysis methods that work with graphs will be chosen. While this might risk preventing the discovery of a non-graph method that somehow supports the vast majority of TN games very well, choosing graph-based methods will give some level of guarantee that the method is in fact useful to the majority of TN games. 51 General application Another consideration is the generality of the method. Some methods may be very useful to a small subset of TN games, but if these methods are not useful at all to the rest of the TN games, the methods will not be worth anything to the majority of the game developers using the engine. For instance, some methods assume both perfect information, full determinism, two-player, etc., and these constraints limit the use of the methods. While it can be difficult to determine whether a method is useful to many or to few TN games, the assumptions the method make can help to easily decide whether it supports many or few. For instance,s if a method assumes that perfect information is available, a lot of complex and interesting TN games using hidden information are excluded. Based on the need for supporting many and not few, only analysis and extraction methods that does not place severe constraints on the types of TN games possible will be considered. Summary In all, it was decided that the following aspects were the guiding ones in regards to choosing which information extraction and analysis methods to implement. 1. Methods that works directly with graphs. 2. No methods with constraints that severely limits the supportable TN games. 10.2 Machine learning The field of machine learning concerns the gathering of information knowledge and using it to improve performance. Related to its use in games, machine learning is often used to let agents learn how to compete better. Machine learning features a vast collection of methods and technologies, and this makes it difficult to choose. This makes it desirable to find requirements and aspects to choose machine learning methods from. The chosen methods of machine learning should be general. This requirement is not trivial to satisfy. Different machine learning methods can be applied to different parts of a game independent of the type of the game. This means that it makes little sense to try to analyse which machine learning methods that are especially useful for TN games. We have looked at several papers that describe experiments regarding the use of machine learning in games [3, 4, 5] as basis for our choice and own experiment. 52 Learning and feedback systems In regards to generality, some might claim that the categorisation of type of feedback for machine learning can help determine which methods are useful for games. According to Russel and Norvig [1, p 650] the 3 types of feedback systems are: • Supervised learning • Reinforcement learning • Unsupervised learning In a supervised learning task a number of problems along with their solution is given. The task is to create a function that maps each problem to the correct solution. An example is the task of determining which images in a set contain buses. A human superviser has marked the bus images. Given this training set, the learning task is to create a function that correctly finds the bus images. The function should be able to correctly determine whether new images contain buses. Reinforcement learning means that the solution to the problem is not known, but that the environment reacts favorably or unfavorably to actions. This may be seen as common to games, in which doing a wrong move can have immediate and strong penalties. For instance, trading a queen for a pawn in Chess usually leads to a much worse position. The final feedback type, unsupervised learning, is a special kind of learning since it never knows whether what it did was correct or wrong. It constitute a class of problems in which the goal is to find patterns in the given data. Based on this, reinforcement learning may be seen as the general type of learning problems for games, including TN games. The issue with this generalisation is that the other types of learning methods still occur in games, and may still be useful. For instance, the supervised learning method is used in a white paper on game AI 1 to try and improve an AI developed for the TN game Go. Other categorisations may be used, but this categorisation is the most useful when determining the nature of the learning problem that the developer faces[1]. Based on these considerations, the learning method will not be chosen based on its type. Instead, it will be considered in regards to implementation and use. Ease of use Another requirement is a less functional one, but still very practical. It is the issue of ease of use. Machine learning is an interesting and advanced field, and it touches on several other fields, such as statistics. This also means that it has its own issues and problems. Part of the idea of provid1 http://doc.utwente.nl/66613/ 53 ing AI libraries is to lessen the implementation time and learning complexity, but machine learning methods that pose problems that is exotic to the regular game developer may cause the method not to be used, except by a minority of game developers. Of course, by implementing such libraries in an engine, and providing plenty of documentation resources, may help against such situations. But simpler machine learning methods are still much more likely to be successful than complicated ones. If a complicated machine learning method is implemented, the implementation should consider ease of use. Summary The following list of aspects have been chosen to guide which machine learning methods to implement. 1. Machine learning methods which have been successfully used in games. 2. Ease of use. 54 Chapter 11 AI Implementation The purpose of this chapter is to describe the chosen methods and the reasoning behind choosing them, as well as describing and justifying their implementation. Furthermore, issues found during the implementation are described and discussed. 11.1 Selection of AI methods This section describes the selection of AI methods and reasons for their selection. Apart from the aspects discussed in AI Design, another important consideration was made regarding the selection of AI methods. While the focus for the selection of methods was based on the design derived from the assignment specification analysis, the development method also affected the design. Basically, the game and its AI players was developed alongside the engine and the AI libraries, and this meant that the AI methods was partly chosen based on what the AI players needed in the game. This have obvious disadvantages, such as the risk for choosing algorithms that are especially suited to that game instead of a more general one, it still carries the advantage of testing the algorithms in a game. AI libraries that are tested using simple simulation tests may not show hidden problems and constraints that occur once they are used in a game. 55 11.1.1 Path finding In regards to the requirements of path finding found in design, the following 3 aspects were determined as being important: 1. Supporting edge weights in the graph. 2. Changing edge weights during the game. 3. Hidden and changing information. A* is a simple, frequently used and well-known path finding algorithm in the game development field, based on Dijkstra’s algorithm. It has a decent running time, and its memory requirements are proportionally to the size of the graph structure in the game, meaning that memory is not likely to be an issue, at least when used for path finding in the game graph. It supports path weights, and it does not support or require precomputation, meaning that it matters little whether or not the edge weights of the graph are changed during the game. While it does not support negative weights, encountering negative weights were deemed to be a very rare case in TN games. However, it does not handle hidden and changing information well. If new information becomes available after it has computed the shortest path, A* must be recompute the path from scratch. The second algorithm considered, D*, is an algorithm used in robotics. The special thing about D* is that it does not assume that everything is known; instead, it computes the shortest paths assuming that unknown territory has no obstacles. When an obstacle in previously unknown territory is revealed, it recomputes the parts of the computation that was effected, and continues. This algorithm is especially suited to robots exploring and the situation is similar to scouting units in TN games with hidden information. Due to time constraints and the simplicity of implementation, A* was chosen. While it does not handle hidden or changing information well, it can still handle it. D* is still an interesting candidate, and investigating its usefulness for TN games is recommended, especially for games with hidden information. 11.1.2 Information extraction and analysis In regards to the requirements of information extraction and analysis found in design, the following 2 aspects were determined as being important: 1. Methods that works directly with graphs. 56 2. No methods with constraints that severely limits the supportable TN games. Blocking Methods that work directly with graphs include the methods related to areas such as labeling, routing (path finding), network flow, sub-graph finding, etc. While it may be difficult to model common tasks in TN games to problems which is handled in one of these areas (apart from routing), we managed to find one task in which one of the areas above gave the solution. During the development of the game, a need for blocking enemy units appeared. When blocking, a primary goal is to use as few units as possible to prevent enemy units from entering some area. This usually means finding the smallest gorges, or making a ring around the target. As an example, this tactic can be used in Battle for Wesnoth to protect a wounded unit or in older Civilization games to keep others out of “your” territory. Blocking as a max-flow min-cut problem This task can be modeled as a problem in network flow, more specifically as a max-flow min-cut problem in which all nodes have a flow capacity of 1. Nodes having flow instead of edges having flow can easily be modeled as edges having flow. In the problem, a source and a sink have to be indicated. A typical modeling in TN games would compare to having the enemy units as the source, and then the area(s)/building(s)/unit(s) to be protected as the sink. Now, a min-cut algorithm will then find the nodes which are the least required to block the enemy completely, since a flow in a node will be equal to having one unit/building occupying that node, and the smallest blocking is equal to a maximum flow in the flow capacity 1 graph. Several algorithms exists for the solution of this graph problem. However, since every single node have a flow capacity of 1, the Ford-Fulkerson (FF) algorithm was a good candidate. The running time of FF is described as: O(E · max(f )), in which E is the number of edges in the graph, and f is the maximum flow in the graph. Two important observations are made. The graphs in TN games are generally sparse, with the number of edges being proportional to the number of nodes. We have no knowledge of a TN game in which the highest number of edges for any nodes become larger than 10. This means that E can be replaced with V (the number of vertices, or in this report, nodes). Second, the maximum flow is, logically, maximum equal to the number of nodes, since each node have flow capacity one. This means that the running time of FF is given as O(V 2 ) in the worst case, which is a very good running time for max-flow problems. 57 Summary Because of this, the FF was implemented and used as a method in the AI library. While other max-flow algorithms may be more effective on graphs with more flow, no tasks requiring more flow have been encountered, and the FF was therefore both adequate and effective regarding the needs. If such tasks is encountered, investigating the other max-flow algorithms is recommended. Influence mapping Another method, more commonly known in regards to games, is the method of influence mapping. In this report, influence mapping is defined as a mapping from each node to some value, typically a real value value. The mapping is obtained by going through each relevant game piece, and propagating their “influence” to their node or the area around them. Whenever influence from two or more game pieces is collected in the same node, some operation is performed on it (frequently it is summed up). Basically, influence mapping is a spatial analysis that tries to show the influence of different aspects in the game. Examples and possibilities There are many options for influence mapping. A typical use in strategic and tactical games is to calculate the extent of one owns units influence against the enemy’s influence. This is simply done by creating 2 influence maps: one for the allied units, and one for the enemy units. In order to get a picture of who influences which area, the maps are simply subtracted, and the difference map is then obtained. Other interesting influence maps can be gained by performing various algebraic functions on influence maps. 1 Grids and graphs While some regard influence maps as being inherent to grids 2 , this is not necessarily the case. In the game Risk 2, which is a TN game with non-grid, irregular size nodes, influence maps are used as a help to the player to analyse the game graph (whether the AI utilises influence mapping is unknown). If it is assumed that the graph is a grid, several methods can be combined with influence mapping, such as cellular automata and several image analysis methods. However, in order to be general and include non-grid TN games, these are not considered. If extra support for grids is desired, these methods are worth looking at, since they make the analysis of influence maps somewhat easier, for instance being able to locate areas of influence. 1 http://gameschoolgems.blogspot.com/2009/12/influence-maps-i.html http://gameschoolgems.blogspot.com/2010/03/influence-maps-ii-practical.html http://www.slideshare.net/mobius.cn/influence-map 2 http://www.slideshare.net/mobius.cn/influence-map 58 Summary Given influence mappings flexibility, and its ability to map properties over to a spatial construct, it is very useful in tactical and strategic games in which space is an important dimension, such as the majority of TN games. However, it is not without its issues. Influence mapping basically generates heuristics: the influence propagated by a game piece has no clear relationship with it, and it can require testing and fine tuning to obtain a good propagation method in different problems. In all, influence mapping can be useful to the majority of TN games. It is also easy to implement, and has been tested in the game development field. Given that they work directly with graphs, it has been decided to include them. 11.1.3 Machine learning In regards to the requirements of machine learning found in design, the following 2 aspects were determined as being important: 1. Machine learning methods which have been successfully used in games. 2. Ease of use. Genetic algorithm The general idea of a genetic algorithm (GA) is to evole a data set in a method similar to the biological evolution process. Each data set is called a “chromosome”, and each data part is called a “gene”. In order to evolve, a population of the chromosomes is needed. These chromosomes are frequently randomly generated. Given the starting chromosomes, the following steps are performed: 1. Selection. Evaluate the fitness of each chromosome. Pick the fittest chromosomes and discard the rest. 2. Reproduction. The surviving chromosomes produce children by being paired off, and new child chromosomes inherit data from each parent. 3. Mutation. For each of the new child chromosomes, mutate genes at random. 4. Kill off the parent chromosomes, and start over with selection. GA, which is a reinforcement learning method, was considered due to its tried and successful use in games by several others 3 [4]. 3 http://www.springerlink.com/content/v9clljnrr4erd4qq/ 59 In regards to games, a typical use of GAs is to optimise a set of heuristics. [4] The evaluation function then consists of whether the generated heuristics in a chromosome lead to winning or losing, or some degree in between. In a TN game where the heuristics to optimise is for the AI player, the evaluation function would consist of playing a game and see how well the AI player performed. Issues regarding fitness evaluation A requirement of the GA is that the evaluation function must return values that the GA can converge on. This can be a problem in games, since games are usually either only a loss, a draw, or a victory. For instance, if a population is evaluated, and the chromosomes all lost their games, the evaluation function will make picking impossible if the only two values returned are ”it lost” and ”it won”. Instead, if the fitness function returns a broad spectrum of values, indicating that some chromosomes lost more than others, the chromosomes that lost less can be picked. This broad spectrum of values can be attained in two ways for games: The first is to implement an estimate of how well the chromosome performed, such as a score, and modify it heavily dependent on victory or loss. While this is effective, the estimate may be wrongly chosen, and such may optimise tendencies that does not lead to better performing chromosomes. The second is to let the games be played repeatedly, and let the randomness sort it out. For instance, if each chromosome is evaluted 50 times, the chromosomes that won the most victories can be regarded as the most fit. While this approach helps ensure that the best performing heuristics are picked, it also means that the evaluation time is much higher, since the games have to be played many more times. Another important issue regarding the fitness evaluation is the frequent requirement of an opponent. While this is not always an issue, it is generally an issue if the heuristics is used to improve the heuristics of an AI player in a TN game. While human opponents may be the most varied and the best players to test against, the need for repeatedly and quickly test games makes it generally impractical to use humans. This means that opponents are needed. Ease of use An important advantage of the GA is that the algorithm itself is completely separate from the evaluation function. This means that the algorithm can be used between several games and fine-tuned, and let the game developers develop the evaluation function. The evaluation function is frequently simple, based on giving the game a score, or repeating the game and basing the score off number of wins out of games played. This means that the algorithm might be easy to implement in an AI library for a game. The only issue that remains is the structure of the chromosomes, which may differ from game to game, and which the algorithm should be able to handle. 60 Summary Based on the above considerations, it has been decided to use the GA. The method is both easy to use and has been successfully used in games. While it has some issues regarding its use in TN games that must be considered, these issues can be dealt with. Case-based reasoning Case-based reasoning (CBR) is a learning method centered around solving current a problem, also called a case. The idea is that the machine will have or through trial and error generate a database of problems, solutions attempts and some measure of how successful the attempt was. When given a new problem, it should extract and adapt a solution based on the previous cases it has encountered. Humans frequently use learning style in their every day life. Consider driving a car; if faced with a Mercedes, most licensed drivers are able to use it, even if they never drove that model before. CBR systems can be implemented in several ways, but the systems commonly includes phases similar to the below: • Match previous cases by finding similar cases to the current case. • Adapt the solution of the most fitting case to the current task. • Learn by recording a new case and store the success of the adapted solution. CBR was considered due to its tried and successful use in research papers concerning games, and its usability in complex environments [3, 5]. CBR is a reinforcement learning method. Decision making A main feature of CBR in games is that it can help make choices. The “solution” of a case can be a move, a tactic or even a strategy. Through its learning mechanisms, CBR learns which solution to choose in a given case. An obvious use to this is the perceived advantage of machine learning, such as when rules are changed. In this situation, CBR can learn anew which strategies, tactics and choices should be chosen in different cases. This also makes it different from GA, since GA does not directly support decision making, but first and foremost the optimisation of heuristics. Another difference is that CBR can adapt to different situations much easier, which improves its decision making. GA seeks a set of heuristics that is good in general, and can not switch between sets of heuristic values depending on the 61 situation. Issues with CBR Some of the main issues with CBR are that it can be difficult to use. Many factors have to be considered: how to retrieve cases, how to adapt solutions, how to learn from new cases, how to maintain the case database, how to represent cases, how to structure solutions, etc. These considerations make CBR a learning method which might be difficult to use and implement properly. Furthermore, the structuring of cases and solutions may be different from game to game, and that makes it harder to implement a general CBR system. Of course, these issues with CBR may make an argument for implementing it in an engine. If it is possible to handle the majority of issues in the engine code, the game programmers will have a considerably easier time utilising CBR. Given that CBR is directly useful in decision making, this makes it an attractive learning method. Summary Given the above considerations, it has been decided to implement CBR. While the method is non-trivial to implement well, implementing it in an engine may save game developers a lot of the issues with it. Furthermore, several sources have described successful use of CBR in games, including TN games. 11.2 Implementation of AI methods This section describes the implementation of AI methods. It briefly covers each implementation and the reasoning behind it, and highlights the interesting aspects of the implementation. The art of testing the method is also described, and any test results are also presented. 11.2.1 Path finding The implementation of A* was fairly trivial. The highlights of it was the extensions given to it, which naturally developed along with the game. A simple extension was the setting of its edge weight function. This meant that different units could use different weight functions when path finding. But in the actual game, there was only one unit type. It turned out that weight functions were still useful, because it both allowed searching for paths which ignored enemy units, allied units, or units in general. Furthermore, since technologies were implemented in the game, some units could end up having a changed 62 weight function. Making it easy to set the weight function made these changes considerably easier. As part of extending it, it was decided to give it a ”stop”-function. This stop-function was given the current node visited and the distance traveled, and decided if the A* algorithm should terminate. With this stop-function, several interesting uses was found. A simple use was to find the nearest nodes of a certain type, such as resource nodes or nodes with enemy units. Another extension to the A* algorithm was to allow it to have multiple sources to start from. While this would not find the shortest paths from each source to each node, it did allow some other useful operations. Consider for instance the issue of finding the number of enemies in a certain search range from a group of allied units. By using A* from the set of the nodes of the allied units, and using a weight function that ignores allies, a stop function could be used to add each enemy found and add it to a set, finally stopping once the search range is reached. In all, the A* algorithm proved effective and useful enough in itself, but its extensibility made it much more flexible and useful. It covered all path finding needs and more. This made A* a very useful algorithm, and it is believed that it will also be useful in an AI library. However, it was not tested on a game with hidden information, and investigating D* for those cases is still recommended. But A* can definitely be recommended for path finding in TN games. 11.2.2 Blocking The implementation of the Ford-Fulkerson algorithm was somewhat trivial. In the first iteration of the game rules, in which “food” was of major importance, the FF was vital in order to decide whether or not it would be possible to circle in and protect more food store than the enemy, such that it would be possible to starve the enemy to death. The use of such a strategy required that areas could be easily defended. The nodes of the games each had their own type, and the “mountain” type could not be passed by any unit. The full blockage from these nodes helped create the easily defendable areas. However, FF had to be run on some part of the graph suspected of being easily defendable and worth defending. In order to handle this requirement, it was decided to split the graph up into smaller areas, based on loose connectivity. For each area, the amount of food in it would be computed, and whether it contained enemies or not was also computed. To find the areas, techniques inspired from image analysis was used, including binary morphology. Since image analysis primarily uses data organised as grids, the methods had to be converted to be usable in general 63 graphs. After each area had been computed, FF could simply be run on it, and the actual number of nodes which needed to be blocked could be found. Based on the number of blocking nodes, the food, and whether enemies was contained in the area, the AI could compute if it was possible to starve the enemy to death, and if so, which areas to occupy with some number of troops. However, once the game rules changed away from food, FF was not used. This was because holding some area became much less important, while aggressive expansion was needed in order to win. Given the right circumstances, FF could still be used, if it would be possible to cut off a majority of the map from the opponent player, but this circumstance was mostly based on speculation. Based on this, several points can be concluded. The first is that FF is useful for a specific set of tasks, primarily blocking. The second conclusion is that techniques from image analysis is a useful future source of investigation for TN games. Image analysis contains many useful and computing-effective techniques and methods for spatial data, especially for grids. While not all methods can be converted to non-grid graphs, some can be converted as described in the use of FF. 11.2.3 Influence mapping The implementation of influence mapping was another trivial implementation. The most interesting aspect of influence mapping was how it was used in the AI. From a general perspective, influence mapping can be used to assist human players by providing a visual analysis of the map. Since influence mapping is a mapping from nodes to values, each node can be highlighted based on the value in the influence map. In the game, influence maps was used this way, partly to help indicate the map, and partly to help debug the influence mapping. In regards to its use in the game AI, influence mapping was used for several purposes. One use was to analyse which part of the map was controlled by which player. The unit influence map was used for this, in which each unit propagated influence. The map was then calculated for each player, and one players map was then subtracted from the other players map. Thus, positive values would indicate which areas was controlled by the player, and negative values would indicate which areas was controlled by the opponent. Another use was to determine how many turns different interesting map features was from each unit. These features could be enemy units, resources and bases. Organising this information in an influence map proved practical, and was used in the AI to weight the desirability of goals: if a feature was far 64 Figure 11.1: Screenshot from the game showing influence mapping. Red means enemy, yellow means allied. away, it was less desirable. Overall, influence mapping proved to be a useful, intuitive and effective method of providing spatial analysis. An issue with influence mapping turned out to be that the values had to be weighted properly, and that goals based on influence mapping gave less control and required more fine tuning. This fine tuning took a considerable time and a large amount of trial-and-error, until the task was given to the genetic algorithm. The implementation time for the GA paid itself back a couple of times in time not wasted on trial-and-error, especially as the AI and the game rules were changed. Based on this, influence mapping is deemed to be a method useful to the majority of TN games, and some of its disadvantages can be handled by machine learning methods such as GA. 11.2.4 Genetic Algorithm In order to keep the GA implementation simple and effective, it was decided to first and foremost support just 1 data type: floating points. While this requirement may seem very limiting, it was determined to satisfy the requirements of the AI, since the GA was primarily used to determine the heuristic weights. The implementation of the GA was somewhat simple. Of note is the evaluation, which was based on a point system. As discussed in the choosing of the GA, the 2 options available for evaluation is the point system and the repeated-games system. In order to avoid needless computation, the repeated-games system was discarded. The point system was used, with a fairly simple point-giving system: 65 1. Massive bonus/penalty for winning/losing. 2. Small bonus/penalty for winning/losing x turns before the end. 3. Small bonus/penalty for having more/less units. 4. Small bonus/penalty for having more/less points. This system proved to be sufficiently advanced to give rise to proper evaluation in the game. The rest of the implementation was not very interesting. The selection part chose a percentage of the best performing and discarded the rest, the reproduction part chose parents at random and chose randomly which gene to pick for each place. Finally, the mutation part added or subtracted a random value to genes at random. The use of the GA was more interesting. The GA help alleviate the problem of fine tuning the heuristics in the AI. Instead of having a game developer giving values to each heuristic based on intuition, and then try to test values by playing through games slowly, the GA made it possible to automatically get decent values for the heuristics. Furthermore, it also helped reveal which heuristics was the most important. In a typical run, the most important heuristics would get sensible values after just a few generations. Instead, some heuristics did not seem to matter much at all, randomly having positive or negative sign even in late generations. Overall, the GA made the heuristics AI player go from losing battles generally to winning them generally. Another interesting effect on the AI was its adaptability against players. In one case, the AI with heuristics went from losing to get some overwhelming victories in just a few generations. When the authors decided to investigate, it turned out that the GA had caused the AI player to utilise a previously unknown strategy, and revealed a flaw in the other AI player: By playing really aggressively and getting units near the enemy base, it became possible for the heuristic AI player to sneak in a troop at an opponent base. This meant that the unit production for the opponent decreased considerably. Since the opponent AI was not programmed to defend its bases, this meant that it would lose based simply on the difference in unit producing capacity. However, this revealed an important issue with the GA. When training, the risk of optimising the heuristic AI player for a single map against a single opponent instead of improving in general became apparent. This was observed, since training in 2 different maps lead to 2 different sets of heuristics. While generally similar, the difference was still an issue. This phenomenon is known as overtraining, which is known to happen for different learning algorithms. Game developers have to be aware of this issue if they use GA. One possible way to handle it is to test the heuristics on a “control set” of maps for each generation: by observing whether the heuristics performance on this set decrease, the GA 66 can be stopped before overtraining begins hurting the performance on maps in general. Overall, GA proved to be a simple, useful and effective learning method for the game implemented. It also turned out that a simple evaluation function was enough to get good performance with the GA. However, care must be taken in order to avoid overtraining. 11.2.5 Case-based Reasoning The system A CBR system can be extended greatly. In order to handle the time constraints, it was decided to implement a very simple CBR system. The main part of the system was the case. In this CBR system, the case consisted of the following: < x1 , x2 , ..., xn , tactic, success, timestried > The values from x1 to xn are the game state features, such as gold, enemy gold, number of units, enemy units, numbers of turn left, etc. These are used to match cases, and to determine if cases are similar enough. The tactic is the solution of the case. The success gives an indication of how successful using this tactic have been so far. The number of times tried indicates how often the case have been matched and its solution used, and is included to help ensure that the AI player is inclined to try out tactics it has not tried a lot. The CBR system in the main AI player support 3 CBR modes: none, retrieval and modify. In the mode none, the CBR system is not used. This is useful for testing and providing the main AI player with an opponent. In the mode retrieval, cases are retrieved from the case base, but the cases are not modified in regards to success and number of times used. In the mode modify, cases are both retrieved and modified once the game has been evaluated. In a typical game with the main AI player using modify against another instance of the main AI player using none, the following process is observed: The player first loads the case base. Then, every fourth turn, cases are retrieved to get a solution for the current situation. It was decided to do this at every fourth turn, since this means that each tactic have time to have some sort of influence on the game. If the tactic was chosen every turn, determining whether the tactic was successful would have been difficult. Furthermore, the success of the game at that point is recorded. Once the game ends, the final success of the game is computed, and each case chosen is modified with the success. The success is based on the success 4 turns after it was chosen, as well as the success of the whole game. The number of tries is also incremented. The success determination is chosen based on two desires for success. The 67 success of the whole game should be considered, because solutions should help lead to winning the game. Secondly, the success of the solution itself should be considered, not the overall success, which can be influenced by other solutions. In an advanced CBR system, case base maintenance is important to ensure that the case base does not grow too large. Using analysis of the existing cases means that cases which are too similar can be merged, thus allowing for more cases in the case base. However, due to time constraints, it was decided not to implement any form of case base maintenance, and instead simply set a limit on the number of cases that may be added. Adding case base maintenance is a useful extension to the CBR system. Retrieval The retrieval of cases is based on the features, success and times tried of a case. The features of the case is used to collect those cases which are similar to the current case. To compare, the features are seen as points in a N-dimensional space, and the similarity is based on the unweighted Euclidean distance between the two points. In the case that one or more cases are considered, the chance for selecting the case is based partly on how many times it has been tried before, and partly on the success. In general, cases that have been tried a low number of times, less than 5, is tried first. If all cases have been tried, the most successful cases are the most likely cases to be chosen. This system encourages exploration. In the case that no similar case is found, a number of new cases having the same features but different solutions is saved in the case base. After considerable testing, the solutions that work better will get a greater success score, and they will be preferred over the less successful solutions. Game playing and testing The two AI players that were available at the time of testing the CBR was the StandardPlayer and the InfluencePlayer. InfluencePlayer differed from StandardPlayer by using GA and CBR, and it used influence mapping to a considerably greater degree than StandardPlayer. In practice, we observed that InfluencePlayer performed considerably better than StandardPlayer. However, an issue was encountered in regards to testing and balancing the game. Making a map that was fair to both players turned out to be a difficult challenge. Since players does not take their turn simultaneously, the player that moves first will get resources first, and thereby get an edge. When trying to balance this by adding more units to the other team, it turned out that the power balance was easily overturned to the other side. Basically, no maps were created that featured winning chances between 40-60 percent for the same AI player playing against itself. This meant that the test had to assume that the AI player either was in a winning position or a losing position. In order 68 Figure 11.2: Blue team crushing the red team. to test its capabilities, the AI player to use the CBR was placed in the losing position. Furthermore, the CBR using AI player was determined to start from scratch. The test tried to determine if the player could learn to win using CBR. The test table is shown below: Games 40 40 40 40 80 Winning percentage 12.5 20 20 35 36.25 Case numbers 0..300 300..1040 1040 1040..1500 1500 Training mode Modify Modify Retrieve Modify Retrieve As is seen from the results, the training of the Influence Player resulted in a rise from winning 12.5 percent of all games to win 36.25 of all games. Given the above tests, we believe that the CBR system works as intended. Issues There were several issues with the CBR method. One issue is that the features chosen can affect the performance of CBR quite heavily. If features are chosen that does not include information relevant in regards to choosing one solution over the other, the CBR system will be unable to learn which solution to choose in the given cases. Furthermore, considerable requirements to features can be given. If features are too complex, the case base will take up too much space, and case matching will become both more complex and require more computing time. The question is then if simple features can be chosen for 69 games and still be effective. Based on the above test results, the conclusion is that it is possible in at least some games. While it may not be possible to grasp every important factor when selecting features, enough relevant features can still be gathered such that learning can happen. This is supported by the results of Aha, Molineaux and Ponsen, which describes how an AI player learned to win given some fairly simple features[3]. 70 Chapter 12 Script Engine We had two reasons for attempting to develop a script engine. We wanted to attempt to write a language that would assisting game developers to write AIs for their games. The other intended use was to provide an easy way to write games for the engine and create “custom content” for such a game. 12.1 The idea and outcome The idea was to create a language with built-in support for AI specific tasks to ease the development, which was superior to a general purpose programming language. Unfortunately late in the development we realised that due to the nature of AI programming, general purpose languages are generally an excellent choice. This is especially true now that more and more imperative programming languages adopt some of the more functional paradigms such as closures. In our experience TN game AI development benefits more from having a strong base library to handle some of the common tasks. It is possible that engines with tight integration between AI and the game itself might benefit from language level support as is the case in the RTP game engine Unreal Engine 1 . In the end we decided to halt the development of the script engine due our revelation and also become writing a script engine takes a lot of time, which would be better spent else where. The basic script engine had been completed and it could support a large 1 http://unreal.epicgames.com/UnrealScript.htm 71 subset of “usual” language features of a general purpose programming or scripting language2 . The big issue was that it had been a stand-alone component, developed independently of the rest of the game engine. To integrate it we would have to not only rewrite parts of the game engine to use the script engine, but at least also write a core library for the scripts to easy interface with the game engine. However, as mentioned other components showed more promise and we decided to work on those instead. Nevertheless, we have made some observations and experiences about writing a script engine, which we have provided below. 12.2 Script engine design This section will describe the setup and some of the choices involved in creating a script engine. 12.2.1 Script engine components A script engine consists of quite a few related components. The exact number of distinct components vary from engine to engine. This particular engine is made up of a compiler, an assembler and a virtual machine (VM). This modularisation is by no means a requirement for a successful setup; especially it is easy to merge the assembler into the compiler or even the VM. In this setup, the compiler will parse the “high level” script language, analyse it, apply a few optimisations on it and output some “script assembly code”. The assembly code is basically an ordered list of instructions that needs to be executed. The assembler translates these instructions into byte-code used by the VM. Execution of the resulting code is done by the VM. Assembler Including the assembler as a separate component had several advantages. The assembly language itself is very close to the actual byte-code and gave a step-by-step recipe of what the VM was going to execute. Secondly, the assembly code being plain text meant that the compiler could output annotations and hints about the assembly instructions. These hints proved quite useful in debugging the compiler without having to support these annotations in the byte-code itself. Another major advantage was that it was possible to implement new bytecode instructions merely by updating the VM and the assembler. Adding support for new things in the compiler was often more complex and updating it 2 A notable exception to this is the lack of support for “global” or “static” variables. 72 all the time slowed down prototyping. In the end the compiler was updated to support assembly code written directly in the script; this gave the best of both worlds, since the prototypes could be written in the high level language to the extend the compiler supported. 12.2.2 Linking scripts It is common for programmers to write libraries or utility code that is used throughout their project and script writers are no exception to this. The question was how to handle this re-usage and there are two well known ways to handle this, which is also used in most operating systems. When linking a program to a library you either link statically or dynamically. With static linking, all the code used by the program is embedded into the program. The other approach is to record the requirement for this library in the program and then when the program is loaded, a runtime linker will also load the library and finalize the linking of the program. Static linking greatly simplifies a lot of things. The library is embedded in the script; this can be exploited to generate simpler byte-code by handling all library parts as if they had been written directly in the script itself. With static linking there is also no need to write a runtime linker; the compile time linker can be handled by having the compiler read the source of the static library, which means the compiler do not need to be able to read the byte-code of libraries in order to generate its output. The advantages of using runtime linking can greatly reduce the size of the binaries as well as the memory footprint. When two scripts use the same library, the price for the library is only paid once with runtime linking. It also makes it possible to cache a heavy used library such as the core script libraries. A complication of using dynamic linking is that when your runtime linker detects it needs a library, it has to have some way of finding said library. For better and worse, when a library is updated the runtime linking will automatically pick up this change. This allows a library to be patched without having to recompile all scripts that use it. On the other hand, an incompatible change will now break all scripts linked to it. Such a change is also likely cause a recompilation to fail against the new library, thus static linked scripts have no benefit here if there is a bug in the old version of the library. While it is possible to mix the styles; that is linking statically against some libraries and dynamically against others we decided to go with pure dynamical linking. The primary argument for dynamic was that it would allow developers to release their library without all the hassle of reminding people to recompile or relink all their scripts to the new version. 73 Consequences To cope with some of the issues with dynamic linking we adopted a Java-like requirement for naming the scripts. At least on Linuxbased systems, shared libraries can have a name (SONAME) different than its file name. The system solves this by having a library cache that maps the SONAME to the file name. Instead of having to create and update such a cache, we decided to make a trivial algorithm for mapping a script name to file name. This is enforced in the runtime linker, which refuses to complete linking if the script it loaded is named differently than expected from its file name. This restricted was inspired by and analogous to file name convention of java and class files in Java. The other issue with dynamic linking is how to handle global writable variables particularly if the VM is expected to allow multiple threads. With static linking it is trivially solvable by embedding all the writable global variables directly into the script itself and have each thread allocate its own copy of these variables. Unfortunately this is much less trivial when the global variables are spread across several libraries. In our setup we never implemented global variables nor constants; the work on the script engine was halted before it became relevant. Nevertheless, were we to resume the development of the script engine, we would need to solve this. The prime candidate solution considered so far, would be to have each thread generate a table where it would keep its global variables. To conserve memory read-only global variables can be stored in the part of the script that is shared between threads; though this may require additional complexity in the byte-code. Please note that the complete list of advantages and disadvantages of either linking style are far beyond the scope of this document; the things listed above were the primary considerations for choosing runtime linking. 12.3 Lessons learned In this section we will shortly describe some of the lessons we learned while implementing the script engine. 12.3.1 Code analysis When parsing a script, the compiler will need to check the semantics of the input. Originally this was implemented as a part of the parser. Nevertheless, the language was based on a context-free grammar; in some cases the compiler lacked the context to decide if the script made sense or not. To solve this most 74 of the checking was deferred till after the parsing. Originally the compiler used its own description of the script to analyse and optimise the output. However, this tree form was inferior to work with and was later replaced with a static single assignment (SSA) based form. SSA was quite an asset when it came to doing simple optimisations. There exist other representations, in this case the choice was heavily influence by both the amount of documentation on SSA available and that GCC 3 adopted it as an internal representation in 2004 4 . Depending on the language type SSA may not be the right choice; particularly compilers for functional languages tend to prefer “continuation-passing style”. 12.3.2 Debugging scripts and the script engine A great issue with working with a script engine is that there are so many points of failure. When the VM reports an error the bug could be in the script, the VM itself, the byte-code generation, the assembler, the compiler or in any mix of the above. To assist in the bug hunting, we had the VM generate a stack trace of the script execution. We had the compiler emit its entire representation of the script as a comment into the assembler; particularly we had a snapshot of the representation before and after its optimisation pass. This before and after view greatly assisted in finding bugs, when the optimisation was too aggressive. Also the compiler could write line numbers for the assembly instructions it wrote; which compensated for the lack of support in the assembler and byte-code to handle instruction to line number mapping in our main development branch. 3 “GNU Compiler Collection” - http://gcc.gnu.org 4 http://gcc.gnu.org/projects/tree-ssa/ 75 Chapter 13 Discussion Several methods related to AI have been implemented and tested. This section will discuss the implemented methods and the results from implementing them. Path finding The A* algorithm turned out to be more extensible than the authors believed. It is generally used in the game development field, and it also seems like an excellent algorithm for TN games. Furthermore, it fulfilled the requirements given to it in the design phase, except for hidden information. Whether A* in practice will handle hidden information well or not will have to be investigated. Another algorithm, D*, may prove useful here. Blocking The implementation of Ford-Fulkerson turned out to be very effective. However, not all TN games have need of blocking, and this methods utility may be decreased by this. Therefore, it is the authors recommendation that such algorithms are not the first priority when implementing an AI libray for a TN game engine. During implementation and use of Ford-Fulkerson, we discovered that the area of image analysis might be useful to TN games. Image analysis concerns itself with spatial analysis of large data sets, frequently organised as grids. Some TN games have graphs that can be modeled as grids, and these games might be able to benefit from these graphs. Other TN games have graphs that cannot be modeled as grids, but some image analysis algorithms can still be changed to fit these graphs. Investigating this area for TN AI is recommended. Influence mapping Influence mapping was used for several different tasks. Furthermore, influence mapping turned out to be trivial to debug, since an in- 76 fluence can be visualised easily. Influence mapping is especially suited to TN games, since nodes can be used for the mapping. Influence mapping is not limited to grid-based games, but some methods that can be used together with influence maps, such as cellular automata, assumes a grid structure. Influence mapping turned out to be useful, and supporting it in a TN AI library is recommended. Genetic Algorithm The Genetic Algorithm proved very useful for automatic setting of heuristics. While some issues occured, specifically with overtraining against one opponent or on one map, these issues did not appear to be considerably noteworthy in the game. An AI player that trained on one map could still perform well on another map. Furthermore, GA is easy to separate into a library, requiring only an evaluation function in regards to use. Supporting GA in any AI game library is recommended. Case-based Reasoning Case-based reasoning is an advanced method, and decent results were gained with it. However, the tuning and implementation of CBR can make it difficult for game developers to use it properly. While further investigation is recommended, easy and general use of CBR may require specialised tools to help handle the complexity, and that makes it a heavy investment for a TN AI library. The method is still very useful, since it can handle decision making well in TN games. For game developers they should ensure that CBR is a good choice before implementing it, and AI library developers should investigate it further before deciding to support it. Testing In regards to the testing methods, it turned out that the changing game rules and having a game under development meant that several different AI methods could be tested. Another advantage was the chance to test the utility of machine learning in regards to changing game rules. It was observed that as not only when the game rules changed, but the AI too, letting machine learning handle the heuristics gave better and faster results than letting game developers tune the systems by hand. On the other hand, not having a game to go on from meant that testing also became more difficult. For instance, the CBR system that was implemented required different tactics. While these tactics were already implemented for Aha, Molineaux and Ponsen[3], no such tactics existed for this game before the CBR systems needed them. In fact, there was no guarantee that the rules of the game allowed multiple tactics, instead of one general tactic which worked all the time. Another issue in regards to testing was that the game logic and game AI was completely separate from multiplayer, graphics, GUI, etc. This resulted in that 77 the machine learning could compute without having to share resources with the aforementioned systems, thus speeding it up. Adding AI tools and libraries to a TN game engine The primary requirements of implementing and testing AI methods in a practical game has all been attained. 1. Graph-based search library. The A* algorithm has been successfully implemented and tested, and results indicate that it can indeed be used in the vast majority of TN games. 2. Machine learning library. Two methods related to machine learning have been successfully implemented and tested. These are Genetic Algorithm and Case-based Reasoning. Especially GA is useful in general. 3. Graph-based information extraction and analysis. Two methods related to graph-based information extraction and analysis have been successfully implemented and tested. These are blocking method and influence mapping. The results indicate that influence mapping will be useful in the vast majority of TN games. Script Engine The original idea of providing language support for AIs proved to be very difficult for this particular game engine. While this has been done with success in other engines such as the Unreal Engine, it is possible that this language level support makes more sense for RTP based games or engines were different components are integrated more tightly. A possibility for further research is looking into well-established TN games and investigate which problems occur. The reasoning for creating the UnrealScript was repeated issues in multiple games with maintainability and errors; the language constructs were aimed at solving these issues. 78 Part IV Conclusion 79 In the project, a game, game engine and AI library have been designed, implemented and tested. Furthermore, a scripting engine have been partly implemented. Game engine The implemented game engine consists of several subsystems. All of these subsystems are geared towards supporting TN game. The most important aspects were the node-based data structure and the separation of concerns. The node-based data structure chosen can support the vast majority of TN games. By designing a general data structure with few assumptions, it was possible to support this wide variety games. The separation of concerns was achieved by implementing an event-based system. This system may not have been effective in a real-time engine, but meant that the different subsystems achieved a degree of separation rarely seen in game engines. AI library The implemented AI library contains two groups of methods for supporting AI: graph-based methods and machine learning methods. 3 of these implemented methods stood out. The A* path finding algorithm turned out to be effective and efficient. The vast majority of TN games can utilise it given the graph structure. However, the ability of A* to handle the important aspect of hidden information was not tested. D* is an algorithm designed to handle hidden information, which were not implemented due to time constraints. It is recommended that future work evaluate D* for TN games, especially if they contain hidden information. The influence mapping method turned out to be flexible and useful at combining spatial information with game specific properties. For instance, estimating which areas were controlled by a given player. The Genetic Algorithm turned out to be both easy to use and effective at optimising heuristics in the AI. An important aspect is that the algorithm is independent of the game domain. Script engine The implementation of an AI domain specific language was not successful. During the development, no aspects of the AI players implementation gave rise to language constructs which would be better than a general purpose language. AI languages have been successfully implemented in other RTP engines, such as the Unreal Engine. Whether such language constructs can be created for TN games is unknown. It is recommended that further research is based on well-established games, since these may provide a better basis for finding issues that can be solved with language constructs. 80 Overall conclusion The two main parts of the project, game engine and AI library, were successfully implemented and tested. Based on the above discussion, it is our opinion that a game engine focused on TN games is not only possible, but desirable as well, since the advantages are considerable. Creating an AI library is recommended as well, but care must be taken for choosing techniques that will be useful for the majority of games. 81 Part V Appendix 82 Chapter 14 Abbreviations and acronyms This section contains a list of abbreviations and acronyms used in the report. • AI - Artificial Intelligence • AS - Adversarial Search • CBR - Case-Based Reasoning • DSK - Domain-Specific Knowledge • DSL - Domain-Specific Language • FF - Ford-Fulkerson, Flow analysis algorithm • GCC - GNU Compiler Collection (http://gcc.gnu.org) • GUI - Graphical User Interface • IO - Input/Output • JVM - Java Virtual Machine • NWN - Neverwinter Nights (http://nwn.bioware.com/) • RM - Resource Management • RT - Real-Time • RTP - Real-Time Position-based 83 • RTS - Real-Time Strategy, A game genre • SSA - Static Single Assignment (form). • TN - Turn and Node-based • UI - User-Interface • VM - Virtual Machine 84 Bibliography [1] Stuart Russell and Peter Norvig, Artificial Intelligence: A Modern Approach. Pearson Education, Inc., International Edition, 2nd Edition 1995, 2003. [2] Jan Niestadt < [email protected] >, http://www.flipcode. com/archives/Implementing˙A˙Scripting˙Engine-Part˙1˙Overview. shtml, Online document / tutorial, 1999. [3] David W. Aha, Matthew Molineaux and Marc Ponsen, Learning to Win: Cased-Based Plan Selection in a Real-Time Strategy Game. Navy Center for Applied Research in Artificial Intelligence, Naval Research Laboratory (Code 5515), Washington, DC 20375, ITT Industries, AES Division, Alexandria, VA 22303, Department of Computer Science and Engineering, Lehigh University, Bethlehem, PA 18015. [4] Ian Watson, Damir Azhar, Ya Chuyang, Wei Pan and Gary Chen, Optimization in Strategy Games: Using Genetic Algorithms to Optimize City Development in FreeCiv. Interim Report, http://www.cs.auckland.ac. nz/research/gameai/projects/GA%20in%20FreeCiv.pdf [5] Tomasz Szczepański and Agnar Aamodt, Case-based reasoning for improved micromanagement in Real-time strategy games. Department of Computer and Information Science, Norwegian University of Science and Technology (NTNU), NO-7491, Trondheim, Norway. www.idi.ntnu.no/˜agnar/ publications/iccbr09-games-ws.pdf 85
© Copyright 2026 Paperzz