Data Structures For Game Programmers

This book will teach you how to create many data structures, ranging from the very simple to the moderately complex.


Ron Penton


978 Pages

54999 Reads

73 Downloads

English

PDF Format

19.6 MB

Game Development

Download PDF format


  • Ron Penton   
  • 978 Pages   
  • 19 Feb 2015
  • Page - 1

    Team LRN read more..

  • Page - 2

    Team LRN read more..

  • Page - 3

    Data Structures for Game Programmers Team LRN read more..

  • Page - 4

    This page intentionally left blank Team LRN read more..

  • Page - 5

    Data Structures Ron Penton TM for Game Programmers Team LRN read more..

  • Page - 6

    © 2003 by Premier Press, a division of Course T echnology. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage or retrieval system without written permission from Premier Press, except for the inclusion of brief quotations in a review. The Premier read more..

  • Page - 7

    To my family, for always being there for me. Team LRN read more..

  • Page - 8

    Acknowledgments Iwould first like to thank my family for putting up with me for the past nine months. Yes, yes, I’ll start cleaning the house now. I would like to thank all of my friends at school: Jim, James, Dan, Scott, Kevin, and Kelvin, for helping me get through all of those boring classes without falling asleep. I would like to thank everyone at work for read more..

  • Page - 9

    About the Author Ron Penton’s lifelong dream has always been to be a game programmer. From the age of 11, when his parents bought him his first game programming book on how to make adventure games, he has always striven to learn the most about how games work and how to create them. Ron is currently finishing up his bachelor’s degree in computer science at the read more..

  • Page - 10

    Contents at a Glance Introduction . . . . . . . . . . . . . . . . xxxii Part One Concepts. . . . . . . . . . . . . . . . . . . . . . . . . 1 Chapter 1 Basic Algorithm Analysis . . . . . . . . . 3 Chapter 2 Templates . . . . . . . . . . . . . . . . . . . 13 Part Two The Basics. . . . . . . . . . read more..

  • Page - 11

    ix Contents at a Glance Chapter 15 Game Trees and Minimax Trees . . . . . 431 Chapter 16 Tying It Together: Trees . . . . . . . . 463 Part Four Graphs . . . . . . . . . . . . . . . . . . . . . . 477 Chapter 17 Graphs . . . . . . . . . . . . . . . . . . . . 479 Chapter 18 Using Graphs for AI: Finite State Machines. . read more..

  • Page - 12

    Contents Letter from the Series Editor . . . . . . . . xxx Introduction. . . . . . . . . . . . . . . . . . . . xxxii Part One Concepts. . . . . . . . . . . . . . . . . . . . . . . . . 1 Chapter 1 Basic Algorithm Analysis . . . . . . . 3 A Quick Lesson on Algorithm Analysis . . . . . . . . . . . . . . . . read more..

  • Page - 13

    xi Contents Problems with Templates. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Visual C++ and Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Under the Hood. . . . . . . . . . . . . . . . . . . . . read more..

  • Page - 14

    xii Contents Application: Using Arrays to Store Game Data . . . . . . . . . . . . . . . . . . . . . . 71 The Monster Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Declaring a Monster Array. . . . . . . . . . . . . . . . . . . . read more..

  • Page - 15

    xiii Contents Application:The Quicksave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 Creating a Player Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 Storing the Players in the Game . . . . . . . . . read more..

  • Page - 16

    xiv Contents Playing the Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 Comparing Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 Comparing Size . . . . . . . . . read more..

  • Page - 17

    xv Contents Size Comparisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Real-World Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 Conclusion . . . . . . . . . read more..

  • Page - 18

    xvi Contents The HashEntry Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 The HashTable Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 Example 8-1: Using the Hash Table. . . read more..

  • Page - 19

    xvii Contents Solving the Puzzle with a Computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 Terminating Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325 Example 10-1: Coding the Algorithm for Real . . . . . . . read more..

  • Page - 20

    xviii Contents Game Demo 11-1: Plotlines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 Using Trees to Store Plotlines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 Playing the Game . . . . . . . . . . . . . . . . . read more..

  • Page - 21

    xix Contents Chapter 13 Binary Search Trees . . . . . . . . 389 What Is a BST? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 Inserting Data into a BST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . read more..

  • Page - 22

    xx Contents The Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419 The Constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419 The Enqueue Function . . read more..

  • Page - 23

    xxi Contents Limited Depth Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 Chapter 16 Tying It Together: Trees . . read more..

  • Page - 24

    xxii Contents The Depth-First Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493 The Breadth-First Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495 A Final Word on Graph Traversals . . . . read more..

  • Page - 25

    xxiii Contents Graphical Demonstration: Conditional Events . . . . . . . . . . . . . . . . . . . . . . 546 Game Demo 18-1: Intruder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547 The Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . read more..

  • Page - 26

    xxiv Contents Part Five Algorithms . . . . . . . . . . . . . . . . . . . . 597 Chapter 20 Sorting Data . . . . . . . . . . . . . . 599 The Simplest Sort: Bubble Sort. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600 Worst-Case Bubble Sort . . . . . . . . . . . . . . . . . . . . . . read more..

  • Page - 27

    xxv Contents Chapter 21 Data Compression. . . . . . . . . . . 645 Why Compress Data? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 646 Data Busses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . read more..

  • Page - 28

    xxvi Contents Adding Three Random Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711 Graphical Demonstration: Random Distribution Graphs . . . . . . . . . . . . . . . . . . . 712 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . read more..

  • Page - 29

    xxvii Contents Conclusion . . . . . . . . . . . . . . . 793 Extra Topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 794 Further Reading and References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 795 Data read more..

  • Page - 30

    xxviii Contents Class Topics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824 Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824 Destructors . . . . . read more..

  • Page - 31

    xxix Contents Setting Up SDL_TTF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 856 Distributing Your Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858 Using SDL . . . . . . . . . . . . . . . . . . . . . read more..

  • Page - 32

    xxx xxx xxx Letter from the Series Editor Letter from the Series Editor Dear reader, I’ve always wanted to write a book on data structures. However, there is simply no way to do the job right unless you use graphics and animation, and that means a lot of work. I personally think that all computer books will be animated, annotated, and interactive within 10 read more..

  • Page - 33

    xxxi xxxi xxxi xxxi Letter from the Series Editor pull this off. On the other hand, if you are a game programmer, then you will greatly appreciate Ron’s insight into applications of various data struc- tures and algorithms for game-related programs. In fact, he came up with some pretty cool applications I hadn’t thought of! So what’s inside? Well, the book starts off read more..

  • Page - 34

    Introduction What is a computer program? When you get down to the lowest level, you can sepa- rate a program into two main sections: the data and the instructions that operate on the data. These two sections of a program are commonly called the data struc- tures and the algorithms. This book will teach you how to create many data structures, ranging from the very read more..

  • Page - 35

    xxxiii Introduction Who Is This Book For? If you’re standing in the bookstore reading this Introduction and wondering, “Is this book good for me?”, then read this section. If you’ve already bought the book, thank you! I am going to assume that you’re reading this book because you want to learn more (unless some diabolical person is forcing you to read this as read more..

  • Page - 36

    xxxiv Introduction understand how it works. These demonstrations all use the Simple DirectMedia Layer (SDL) multimedia library, which I go more into depth on in just a little bit. All of these demonstrations are located in the \demonstrations\ directory on the CD. After that, I show you how to actually code the structure or algorithm in C++. The code for these sections read more..

  • Page - 37

    xxxv Introduction ■ Concepts ■ The Basics ■ Recursion and Trees ■ Graphs ■ Algorithms ■ Appendixes Concepts In this part, I introduce you to some of the concepts used when dealing with data structures and algorithms. You might know some of them, or you might not. ■ Basic Algorithm Analysis—This chapter is a little on the theoretical side, and it read more..

  • Page - 38

    xxxvi Introduction ■ Stacks and Queues—This is the first chapter that doesn’t introduce you to a new structure. Instead, it shows you how to access data in certain ways. ■ Hash Tables—This chapter shows you an advanced method of storing data by using both arrays and linked lists. It is the last structure covered in this part of the book. In addition to read more..

  • Page - 39

    xxxvii Introduction Graphs In this part, I introduce you to the graph data structure, which is another linked data structure that is somewhat like trees. This part of the book is broken down into the following chapters: ■ Graphs—This chapter introduces you to the idea of the graph structure and its many derivatives. Graphs are used all over in game programming. ■ read more..

  • Page - 40

    xxxviii Introduction ■ The Memory Layout of a Computer Program—To understand how to use a computer to its fullest extent, you must know about how it structures its memory. This appendix tells you this information. ■ Introduction to SDL—This is a basic introduction to the Simple DirectMedia Layer library, which the book uses for all of the demonstrations. It also read more..

  • Page - 41

    xxxix Introduction the CD is laid out. Figure I.1 This is the way The Simple Directmedia Layer This is a game programming book, and as such, I had to choose an Application Programming Interface (API) to use that would allow me to graphically demonstrate the data structures and show them to you in real-world demos. At first, I thought I would use DirectDraw, but that read more..

  • Page - 42

    xl Introduction A friend of mine recently introduced me to a very simple API called SDL: The Simple Directmedia Layer. I think that the S part of the title should be emphasized because the API is simple. I was able to make a working SDL program (no, it wasn’t “Hello World”. It’s the Array Demonstration from Chapter 3) in less than an hour after first looking read more..

  • Page - 43

    xli Introduction Artwork Two people provided the artwork used for the demos in this book. First and fore- most, I would like to thank Steve Seator for making all of the person sprites and weapon icons in the game demos. He has an excellent Web site at http://www.spritedomain.net. If you’re interested in his artwork, I urge you to visit the site. The other artist is read more..

  • Page - 44

    This page intentionally left blank Team LRN read more..

  • Page - 45

    PART ONE Concepts Team LRN read more..

  • Page - 46

    1 Basic Algorithm Analysis 2 Templates Team LRN read more..

  • Page - 47

    CHAPTER 1 Basic Algorithm Analysis Team LRN read more..

  • Page - 48

    4 1. Basic Algorithm Analysis Almost any computer science teacher would probably kill me for including this topic as such a small chapter. After all, entire books are dedicated to this subject. But we’re not computer science professors—we’re game programmers! We don’t care about all of this highly mathematical stuff, right? Well, that’s only half right. We should at read more..

  • Page - 49

    5 A Quick Lesson on Algorithm Analysis The function is usually a mathematical formula based on the letters n and c, where n represents the number of data elements in the algorithm and c represents a con- stant number. Imagine having a huge collection of action figures—at least 1,000 of them. But you’re a very sloppy person, and you don’t have them organized in any read more..

  • Page - 50

    6 1. Basic Algorithm Analysis O(Log 2n) Figure 1.2 shows the logarithm base 2 function. In case you don’t know, a loga- rithm function is the inverse of an exponential function. The best way to describe it is this: In a base 2 logarithm, the vertical component is increased by 1 whenever the dataset size is doubled. The log of 1 is 0, the log of 2 is 1, the read more..

  • Page - 51

    7 A Quick Lesson on Algorithm Analysis previous graphs, but compared to some of the more complex functions I discuss next, it is also considered a fairly efficient algorithm class. Figure 1.4 The n log 2n function varies with the size of the data, but has a relatively shallow curve, which makes functions that fall into this category seem efficient. O(n 2 ) This is where read more..

  • Page - 52

    8 1. Basic Algorithm Analysis O(n 3 ) If you thought O(n2) was bad, O(n3) is even worse! Even though the graph looks almost identical to O(n2) (see Figures 1.5 and 1.6), it shoots up at a much higher rate. If it took 20 seconds to perform an algorithm on 1,000 items, it would take 160 seconds for 2,000 items! That’s 8 times longer! Figure 1.6 The n3 function read more..

  • Page - 53

    9 A Quick Lesson on Algorithm Analysis O(2 n n3 n n n) is faster than O(n3). NOTE ) algorithms are actually faster than O( ) algorithms for very small datasets.This has to do with the way an O(2 ) algorithm slopes: It starts out slow, but shoots up quicker than all the other algorithms. For values of that are less than 10, O(2 Comparing the Various Complexities read more..

  • Page - 54

    10 1. Basic Algorithm Analysis single loop on the same number of items. What would the complexity of this algo- rithm be? It is natural to assume that it would be O(n2 + n), but that is incorrect. Remember, when you measure the complexity of an algorithm, you really care only about how it grows as the data size increases. Eventually, the single n term will be read more..

  • Page - 55

    11 Conclusion When you start the program, as shown in Figure 1.8, you see a graph, six check boxes, and four arrows. Figure 1.8 This is a screenshot of the demonstration in action. You can click on any of the check boxes to make a graph appear. You can click any combination at the same time, which enables you to compare the different graphs. The arrows adjust the read more..

  • Page - 56

    This page intentionally left blank Team LRN read more..

  • Page - 57

    CHAPTER 2 Templates Team LRN read more..

  • Page - 58

    14 2. Templates In this chapter, you learn about templates. Templates are a fairly important con- cept in computer programming when you are dealing with data structures because they allow you to easily maintain your code. If you already know about templates, you can safely skip this chapter, but if you are not very good at them (or have never even heard of them), I’d read more..

  • Page - 59

    15 Template Functions Say you want a specific algorithm to work on six different types of datatypes. Without templates, you would have to copy and paste the algorithm six times and manually change the datatypes in each copy! With templates, it is possible to make only one copy of the code and use that one copy over and over again. The algo- rithm on the right-hand read more..

  • Page - 60

    16 2. Templates NOTE Although Chapter 3, “Arrays,” discusses ar rays, I am introducing them a little bit earlier here. If you’re reading this book, you should probably know a little bit about arrays already. However, if you don’t know about them, you may want to skip ahead and read the first part of Chapter 3 and then come back here. 1: int SumIntegers( read more..

  • Page - 61

    17 Template Functions Doing It with Templates C++ comes to the rescue by allowing us to create template functions, which use the same algorithm but operate on different datatypes. The syntax for a template func- tion is such: template< class T > returntype functionname( parameter list ) You first declare that you are creating a template by putting in the template key- read more..

  • Page - 62

    18 2. Templates a template function that calls its foo foo CAUTION It is essential, upon choosing a name for your generic datatype within the template, that you choose one that does not conflict with an existing class name. For example, if you have generic class , but you also have a regular class named , the compil- er won’t like this and will barf error read more..

  • Page - 63

    19 Template Classes 13: // now sum the two arrays using the templated function. 14: cout << “Using Sum, the sum of intarray is: “; 15: cout << Sum( intarray, 10 ) << endl; 16: cout << “Using Sum, the sum of floatarray is: “; 17: cout << Sum( floatarray, 9 ) << endl; 18: } On lines 3 and 4, I declare the two arrays, one of type int and one of type read more..

  • Page - 64

    20 2. Templates the previous section; however, it is based on a class instead. The following classes can be found on the CD in the directory \examples\ch02\02 - Template Classes\) 1: class IntAdder 2: { 3: public: 4: // constructor 5: IntAdder() 6: { 7: m_sum = 0; 8: } 9: // add function 10: void Add( int p_number ) 11: { 12: m_sum += p_number; 13: } 14: // read more..

  • Page - 65

    21 Template Classes 5: FloatAdder() 6: { 7: m_sum = 0.0f; 8: } 9: // add function 10: void Add( float p_number ) 11: { 12: m_sum += p_number; 13: } 14: // get sum function. 15: float Sum() 16: { 17: return m_sum; 18: } 19: private: 20: // sum variable. 21: float m_sum; 22: }; In this class, there are three functions. The constructor clears the m_sum variable, read more..

  • Page - 66

    22 2. Templates So instead of copying the entire class every time you want it to operate on a differ- ent datatype, you can create a templated class that operates on a single generic type, like this: 1: template< class T > 2: class Adder 3: { 4: public: 5: // constructor 6: Adder() 7: { 8: m_sum = 0; 9: } 10: // add function 11: void Add( T p_number ) 12: read more..

  • Page - 67

    23 Template Classes The declaration of a template class instance is almost the same as declaring an instance of a normal class or datatype, except that a template class must have its parameterized types explicitly declared, within the arrow brackets, after the class name. In this example, I created an adder of type int, called intAdder. Here’s how to use the adder class: read more..

  • Page - 68

    24 2. Templates Figure 2.4 shows Example 2-2 in action. This is a Example 2-2. Figure 2.4 screenshot for Multiple Parameterized Types Templates do not have to be based on a single generic datatype. A template class or function can have any number of parameterized types! You declare each type within the arrow brackets as such: template< class one, class two, class three > You read more..

  • Page - 69

    25 Multiple Parameterized Types Figure 2.5 This demonstrates the chaos separating all the different kinds of classes without using templates. Next, I’ll create a template function that determines the average of an array of arbitrary datatypes. (This class can be found on the CD in the directory \examples\ch02\03 - Multiple Parameters\ .) 1: template< class Sumtype, class Averagetype read more..

  • Page - 70

    26 2. Templates Here, you can see this function in action: 1: void main() 2: { 3: int array[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 4: cout << “Average( array, 10 ) = “ << Average( array, 10 ) << endl; 5: cout << “Average( array, 10.0f ) = “ << Average( array, 10.0f ) << endl; 6: } An array of integers is defined on line 3. On lines 4 read more..

  • Page - 71

    27 Using Values as Template Parameters Using Values as Template Parameters Until now, you’ve only seen me using datatypes as parameters for a template func- tion or class. However, you don’t necessarily need to use datatypes as parameters; C++ allows you to use values of a particular datatype. C++ is so flexible that it even allows you to use a value of a generic read more..

  • Page - 72

    28 2. Templates 16: // the array. 17: Datatype m_array[size]; 18: }; On line 1, I declare that I am creating a template that will have one generic datatype, Datatype, and one integer value, size. On lines 6–14, define the Set and Get functions, which set an item in the array or get an item in the array. The most important part of this class declaration is on read more..

  • Page - 73

    29 Using Values as Template Parameters 11: farray15.Set( 3.1415f, 14 ); 12: cout << “iarray5.Get( 0 ) = “ << iarray5.Get( 0 ) << endl; 13: cout << “iarray5.Get( 1 ) = “ << iarray5.Get( 1 ) << endl; 14: cout << “iarray10.Get( 9 ) = “ << iarray10.Get( 9 ) << endl; 15: cout << “iarray10.Get( 4 ) = “ << iarray10.Get( 4 ) << endl; 16: cout read more..

  • Page - 74

    30 2. Templates Using Values of Other Parameterized Types You don’t necessarily need to use a value of a specific datatype as a parameter, how- ever. A value parameter could be of a generic datatype, like so: template< class T, T value> This code declares a template of a generic datatype T, which will also have a value of the same type. This can be useful in read more..

  • Page - 75

    31 Using Values as Template Parameters Now, on line 3, instead of setting the item at the index to the integer value 0, you set it to the specific instance of the zero value for the given class! These changes can easily be made to the previous templated Array class from this section. So how would you declare an instance of the modified Array class? It is the read more..

  • Page - 76

    32 2. Templates As you can see, templates open up a whole new world of possibilities. This is a Example 2-5. Figure 2.9 screenshot of Problems with Templates Templates, like all good things, have a few “gotchas.” Because a template function or class is designed to work with a broad range of datatypes, the number of things you can do with a template is somewhat read more..

  • Page - 77

    33 Problems with Templates The function in this example assumes that datatype T has a function called DoSomething and will work fine if Function is called with ClassOne as a parameter: 1: class ClassOne 2: { 3: public: 4: void DoSomething() 5: { 6: return; 7: } 8: }; But what happens when ClassTwo is passed in? ClassTwo doesn’t have a DoSomething function, but it has read more..

  • Page - 78

    34 2. Templates Visual C++ and Templates Another thing I must warn you about is Microsoft Visual C++ 6.0 ’s method of implementing templates. Templates are a relatively recent addition to the C++ stan- dard, and Microsoft’s implementation of them is not exactly standard. There is one tiny problem with the way MSVC6 handles templates. (In fact, most compilers have the read more..

  • Page - 79

    35 Conclusion The beauty of template implementation is that instead of managing all the copy- ing and pasting yourself, you make the compiler do it instead, allowing you to maintain only one copy of the code. Take a look at the Sum function from earlier, for example. When I compiled the code that called the function, once for an integer array, and once for a float read more..

  • Page - 80

    36 2. Templates It is important that you gain at least a little working knowledge of how templates work because almost all of the data structures in this book use templates. There is one final thing that I feel should be mentioned: Some people love to abuse templates and make really strange-looking code that is almost impossible to read or understand, which is why a read more..

  • Page - 81

    PART TWO The Basics Team LRN read more..

  • Page - 82

    3 4 5 6 7 8 9 Arrays Bitvectors Multi-Dimensional Arrays Linked Lists Stacks and Queues Hash Tables Tying It Together: The Basics Team LRN read more..

  • Page - 83

    CHAPTER 3 Arrays Team LRN read more..

  • Page - 84

    40 3. Arrays Arrays are perhaps the most basic data structures in existence; they have been around since the very first computers. Some of you might already know all there is to know about arrays, and you can safely skip this chapter. Those of you who aren’t so keen as to how arrays work might want to read on, though. In this chapter, you’ll learn ■ What an read more..

  • Page - 85

    41 Graphical Demonstration: Arrays Figure 3.1 Here is a figurative representation of an array. When dealing with arrays, each cell has its own index number. Typically, the very first cell has an index of 0 (zero), but that doesn’t always have to be the case, as you shall see later on. An array is called a linear data structure, as opposed to some of the more read more..

  • Page - 86

    42 3. Arrays When you start the program, you will be greeted with four buttons and a pictorial representation of a ten-cell array. Figure 3.2 is a screenshot of the program in action. Figure 3.2 This is the starting screen for the array demo. Each of the four buttons performs a different function upon the array. I explain them in the following sections. Use the mouse read more..

  • Page - 87

    43 Native C Arrays and Pointers The red X signifies that the contents of the cell are undefined. See the section on resizing arrays later in this chapter. Increasing or Decreasing Array Size These two buttons increase or decrease the array size by one cell. The demo goes through the algorithm step by step and shows you the process that occurs. When an array is read more..

  • Page - 88

    44 3. Arrays access index 10 in this array is considered a fencepost error. If you look at a fence, you’ll see that there are more fenceposts than there are parts of the fence. Figure 3.4 shows how you can easily confuse the number of fence sections and the number of fenceposts. Figure 3.4 There are more fence posts than fence sections.This is the same situation read more..

  • Page - 89

    45 Native C Arrays and Pointers contents of the Figure 3.5 Here are the array after executing the simple 2-line code segment. Cells 0 and 1 both hold 5, but what the heck happened to all the other cells? Why do they hold all those weird num- bers? When you create an array in C/C++, the array is not initialized. So what happens is that the array holds junk, and read more..

  • Page - 90

    46 3. Arrays access violation and results in damaging data. Sometimes it messes up important data and sometimes it doesn’t, but you can never be sure. Bugs of this type are even more deadly because the bug is caused by code that you wouldn’t even suspect of causing the bug in the first place! Another possibility would be that the program just crashes. Either way, read more..

  • Page - 91

    47 Native C Arrays and Pointers Inside an Array The simple answer is that it works because p_array is a pointer. When C/C++ cre- ates an array, it does two things: It makes enough room for the array in memory, and it treats the name of the array as a pointer to the block of memory where the array is stored. So, what you end up with is something like Figure read more..

  • Page - 92

    48 3. Arrays the value at that index. You can replace 5 with any index you want, and the algo- rithm will take the same exact amount of time. Figure 3.7 shows how this algorithm is performed. the data you adding the Figure 3.7 The address of want to access is calculated by starting offset pointer to the size of the data multiplied by the index you want to read more..

  • Page - 93

    49 Native C Arrays and Pointers Example 3-1 Here is the listing of Example 3-1, which demonstrates all of the major concepts of static arrays. It is on the CD in the directory \examples\ch03\01 - Static Arrays\ . void main() { // declare an array with 10 cells. int array1[10]; // declare x int x; // set the first cell to 5, then set the second // cell to the read more..

  • Page - 94

    50 3. Arrays and manage a dynamic array. There are two main ways of creating a dynamic array: By using C’s malloc/calloc (memory allocate and clear allocate) or by using C++’s new. Both malloc and calloc require the inclusion of the malloc.h header file, but new is a built-in language feature and doesn’t need a header. Each method has its strengths and weaknesses, read more..

  • Page - 95

    51 Native C Arrays and Pointers Calloc type-checking malloc NOTE C++ has a new feature called strong . It does not allow you to convert pointers of one type into a pointer of another type unless you explicitly tell it to. NOTE Make sure you always check to see if your calls to return a non- zero value. If it does return 0, then you should take an appropriate read more..

  • Page - 96

    52 3. Arrays New C++ uses a different method of creating dynamic arrays, but the end result is the same. The new operator places all memory it allocates on the heap, just like malloc does. The new operator, however, doesn’t return a void pointer. Instead, it returns a pointer to whichever datatype you request from it, thus removing the requirement to cast the pointer read more..

  • Page - 97

    53 Native C Arrays and Pointers Deleting a Dynamic Array When you are using a static array, it is automatically created for you when it goes in scope and destroyed when it goes out of scope. This is not so with a dynamic array. Because you have to manually create a dynamic array yourself, you also have to man- ually destroy the array as well. If you don’t read more..

  • Page - 98

    54 3. Arrays Delete If you’ve created an array with new, then you must destroy it using the delete key- word. Using delete on an array is different from deleting a normal pointer, how- ever: You must be sure to use the brackets after the keyword, like this: delete[] array; If you don’t use the brackets when you delete an array, delete will only destroy the first read more..

  • Page - 99

    55 Native C Arrays and Pointers There is one little catch, however. The call to realloc might not be able to find enough memory for the new array and thus will return 0. But what happened to the old array, you ask? It’s gone. It was not destroyed, and you now have a memory leak. What happens is that it tries to create enough memory for the new array, and read more..

  • Page - 100

    56 3. Arrays over that memory as well. If this happens, then the function doesn’t even move any data over to a new array, because there is no new array! It just returns a pointer to the same array! As you can imagine, this is really fast. Figure 3.9 shows how a larger array is created using realloc. to realloc to a will be contained Figure 3.9 This shows read more..

  • Page - 101

    57 Native C Arrays and Pointers must resize the array manually. Yes, this is usually a big pain in the butt, but if you encapsulate this functionality into an array class, you almost never need to worry about it. Resizing a dynamic array created with new is a three-step process: 1. Create a new array with the new size. 2 Copy over all possible data. 3. Delete read more..

  • Page - 102

    58 3. Arrays Example 3-2 Here is the code listing for Example 3-2, which demonstrates creating, clearing, resizing, and deleting an array. The code is on the CD in the directory \examples\ch03\02 - Dynamic Arrays\ . void main() { // declare 3 array pointers, and set them to 0. int* array1 = 0; int* array2 = 0; int* array3 = 0; // allocate an array with 10 cells read more..

  • Page - 103

    59 An Array Class and Useful Algorithms // free the third array using delete[] delete[] array3; } Example 3-2 has no output. An Array Class and Useful Algorithms By this point, you have seen how an array works and how to resize them. The ques- tion remains, however, if there is a way to make the process of creating, resizing, and deleting arrays easier. Yes, there read more..

  • Page - 104

    60 3. Arrays 1: Array( int p_size ) 2: { 3: m_array = new Datatype[p_size]; 4: m_size = p_size; 6: } The constructor first allocates enough space for the array using new, and then it makes m_array point to the memory and sets the size of the array. This line of code constructs an integer array to contain 10 cells: Array<int> intarray( 10 ); the Array new NOTE read more..

  • Page - 105

    61 An Array Class and Useful Algorithms 3: Datatype* newarray = new Datatype[p_size]; 4: if( newarray == 0 ) 5: return; 6: int min; 7: if( p_size < m_size ) 8: min = p_size; 9: else 10: min = m_size; 11: int index; 12: for( index = 0; index < min; index++ ) 13: newarray[index] = m_array[index]; 14: m_size = p_size; 15: if( m_array != 0 ) 16: delete[] m_array; read more..

  • Page - 106

    62 3. Arrays The Access Operator I’m well on my way to having a fully functional array class, with one exception: I have yet to add a feature that allows me to access and modify the array contents. I think that one of the coolest features of C++ is its ability to overload operators. In this case, I will overload the offset (square bracket) operator so I can read more..

  • Page - 107

    63 An Array Class and Useful Algorithms Line 1 looks like an ugly mess. Line 2 is nice and pretty, and it is safer to use if the class has built-in bounds checking. The nice thing about the offset operator algorithm I made up is that I can use it to retrieve items within the array too, like this: int temp = intarray[5]; The Conversion Operator Now that read more..

  • Page - 108

    64 3. Arrays int* array3 = new int[16]; // call the function on the three arrays Process( array1 ); Process( array2 ); Process( array3 ); The conversion operator for the Array class automatically treats the class as a stan- dard pointer. This makes the two different ways of representing arrays interchange- able. Inserting an Item Between Two Existing Items One thing I read more..

  • Page - 109

    65 An Array Class and Useful Algorithms 6: m_array[p_index] = p_item; 7: } On line 1, I take two parameters: p_item, which is the item I want to insert into the array, and p_index, the index at which I want to insert p_item. I declare an index variable on line 3, which will count from the end of the array downwards in the for- loop on lines 4 and 5. Why do read more..

  • Page - 110

    66 3. Arrays 1: void Remove( int p_index ) 2: { 3: int index; 4: for( index = p_index + 1; index < m_size; index++ ) 5: m_array[index - 1] = m_array[index]; 6: } This time, the only parameter is the index that you want to remove, p_index. On line 3, I declare an index variable to loop through the array, and I move every item down one index on lines 4 and read more..

  • Page - 111

    67 An Array Class and Useful Algorithms index using the index of the item Figure 3.13 This figure shows how to remove an fast removal algorithm.The last item is moved down into the that is being removed. In the figure, the array contains 9 items and 10 cells. The last cell, although con- ceptually empty, still has a value in it. (Memory has a value in it at all read more..

  • Page - 112

    68 3. Arrays Array<int> intarray( 10 ); Array<float> floatarray( 5 ); // use the access operator to store values. intarray[0] = 10; floatarray[0] = 3.1415f; // use the access operator to retrieve values. int i = intarray[0]; float f = floatarray[0]; // store values at index 1 in both arrays. intarray[1] = 12; floatarray[1] = 6.28f; // insert values between read more..

  • Page - 113

    69 Storing/Loading Arrays on Disk For saving and loading, I will use the standard C file functions (I like them better than C++’s): fopen, fread, fwrite, fclose. If you are unfamiliar with them, please see Appendix A. Luckily, C’s file IO functions operate on arrays! This means that you have to do very little work to read or write an array. I’ll be adding these read more..

  • Page - 114

    70 3. Arrays might fail, so it’s a good idea to check for this. If the file hasn’t been opened, the function returns false. The array is written to disk on line 8 by using fwrite. This function tries to write the entire array to disk by first passing a pointer to the array, and then the size of the items in the array, and then the number of items in read more..

  • Page - 115

    71 Application: Using Arrays to Store Game Data If you could not read in all the items from disk, then the routine returns false. Lastly, it returns true if the function was able to read everything it expected. Considerations for Writing and Reading Files You must take some things into consideration when writing an array of objects to a file. Mainly, you must be sure read more..

  • Page - 116

    72 3. Arrays This section shows you a very simple demonstration game to help you understand how to store objects within a game. I’ll be storing monsters in an array. The Monster Class I begin by first defining the Monster class: class Monster { public: int m_x; int m_y; int m_hitpoints; }; This is a very simplistic monster class—all it has is three variables: The read more..

  • Page - 117

    73 Application: Using Arrays to Store Game Data 1: bool AddMonster() 2: { 3: if( g_monsters == 32 ) 4: return false; 5: g_monsterarray[g_monsters].m_x = rand() % 640; 6: g_monsterarray[g_monsters].m_y = rand() % 480; 7: g_monsterarray[g_monsters].m_hitpoints = 11 + (rand() % 10); 8: g_monsters++; 9: return true; 10: } First, note the return type on line 1. The function returns a read more..

  • Page - 118

    74 3. Arrays needs to copy everything over, and then it needs to delete the old array. This is quite wasteful in terms of speed. So what do you do instead? The most popular approach is to increase the size of the array in “chunks.” Because the array originally carries 32 monsters, when you try to insert the 33 rd monster, you should make enough room for future read more..

  • Page - 119

    75 Application: Using Arrays to Store Game Data The first method uses the Remove function of the array class. It would look like this: void RemoveMonster( int p_index ) { g_monsterarray.Remove( p_index ); g_monsters—; } The game demo won’t use this method, however. The problem with this method is that it takes too long. Sure, in the demo I won’t be creating more read more..

  • Page - 120

    76 3. Arrays 1: void CheckMonsters() 2: { 3: int index = 0; 4: while( index < g_monsters ) 5: { 6: if( g_monsterarray[index].m_hitpoints <= 0 ) 7: RemoveMonster( index ); 8: else 9 : index++; 10: } 11: } On line 3, I declare an index variable. This variable will be used to loop through every index in the g_monsterarray. It is initially set to 0. Lines 4-10 are read more..

  • Page - 121

    77 Analysis of Arrays in Games Figure 3.14 This is a screenshot of the Array Game Demonstration in action. Analysis of Arrays in Games Arrays are the most common data structure. I’ve never seen a complicated program that doesn’t use arrays. Let’s face it, arrays are great to use for several reasons: ■ They are easy to create. ■ They are fast to access. ■ read more..

  • Page - 122

    78 3. Arrays Luckily for us, all processors have a larger memory area almost as fast as the regis- ters called the level 1 cache (L1 cache). This cache is where the computer puts important data that it will need to access often (the actual binary code of each pro- gram is stored in this cache, too). There might be other levels of cache as well, but the most read more..

  • Page - 123

    79 Analysis of Arrays in Games time because it is more efficient to move chunks. When you access a cell of an array, the processor actually loads a chunk of your array into the L1 cache. Say you’re working on a simple system that has a cache of 8 cells and you are accessing a 16-cell array. Figure 3.16 shows the described system. When you access the first cell read more..

  • Page - 124

    80 3. Arrays Try to keep this in mind when working with arrays. After all, if something appears to be too good to be true, it probably is. Resizing Arrays Perhaps the largest problem with arrays is that they are mostly inflexible in size. When you have really large arrays containing mounds of data and all of a sudden you want to resize it, it’s going to take read more..

  • Page - 125

    81 Conclusion on, he learns about the nifty advanced data structures such as linked lists (see Chapter 6, “Linked Lists”). Eventually, though, he ends up using arrays again. Simply put, arrays are the most often used data structures in game programming simply because processors are optimized to process arrays. With the advent of vector processing features in the x86 read more..

  • Page - 126

    This page intentionally left blank Team LRN read more..

  • Page - 127

    CHAPTER 4 Bitvectors Team LRN read more..

  • Page - 128

    84 4. Bitvectors Bitvectors are an important part of optimizing small data items, yet they are so frequently missing from data structures books. Because they are fairly easy to understand, I have included them in this book. Bitvectors have many names, and you might have used something similar before, in which case you can skip this chapter. In this chapter, you will learn read more..

  • Page - 129

    85 Graphical Demonstration: Bitvectors support 32-bit integers, you can easily modify the bitvector class to work on larger or smaller integer sizes. Now, for each index in the array, you should be able to access 32 individual bits. Figure 4.1 bitvector containing 32 Here is a indexes. On most machines, these 32 indexes take up the same amount of room as a single read more..

  • Page - 130

    86 4. Bitvectors The Main Screen When you run the program, you are presented with the main screen, as shown in Figure 4.2. There are two buttons and a long bar containing white or grey boxes. This represents a bitvector that is two cells large, and each cell has 32 bits, giving you a total of 64 bits. White boxes mean that the cell has a value of 0, and read more..

  • Page - 131

    87 Creating a Bitvector Class The Data First, I begin by creating the data members of the class: class Bitvector { protected: unsigned long int* m_array; int m_size; }; You’ll notice that the data members look almost exactly like the ones I used in the Array class (see Chapter 3, “Arrays”), with the exception of the type of m_array. This time, it is an unsigned read more..

  • Page - 132

    88 4. Bitvectors delete[] m_array; m_array = 0; } This deletes the array if it exists. The Resize Algorithm The bitvector resize algorithm is similar to the array resize algorithm, with one exception: Instead of resizing the array to a certain number of integers, I perform a few calculations and resize the vector to the given number of bits. This change allows users of read more..

  • Page - 133

    89 Creating a Bitvector Class is the number of bits required divided by 32. Hence, passing in 32 will result in 1 cell, 64 will result in two cells, and so on. However, if the user passes in a number that is not divisible by 32, I need to do a lit- tle work. If the user passes in 31, for example, 31 divided by 32 will result in 0, because it is an read more..

  • Page - 134

    90 4. Bitvectors The next step is a little tricky. To figure out which bit in the cell you want to access, you need to take the original index and modulo it by 32. Any index from 0–31 modulo 32 will give you the same number, so if you want bit 5, you will need to retrieve the 5th bit of cell 0. What happens when you want to get bit 34? 34 modulo read more..

  • Page - 135

    91 Creating a Bitvector Class So when you take that 1 and binary and it with the given cell, you essentially retrieve the bit in the array at the correct bit-position. However, the result of the binary and isn’t a 1 or a 0. If bit 5 had a 1 in it, then the result of the operation would be 32, or 100000. You need to shift this number back down so that read more..

  • Page - 136

    92 4. Bitvectors For the set function to work (line 6), you shift a 1 into the bit position that you want to set, and you logically or that with the correct cell. This process is demon- strated in Figure 4.4. Figure 4.4 This shows how to set a bit. Note that every bit in the final result is the same except for the one bit that I wanted to set, which read more..

  • Page - 137

    93 Creating a Bitvector Class If you want to convert the algorithm to an integer size different from 32 bits, just change all instances of 32 to the desired bit size. The ClearAll Function There are times when you will want to clear the entire contents of a bitvector quickly, and as you might guess, looping through every bit and clearing it doesn’t seem to be read more..

  • Page - 138

    94 4. Bitvectors 1: void SetAll() 2: { 3: int index; 4: for( index = 0; index < m_size; index++ ) 5: m_array[index] = 0xFFFFFFFF; 6: } If you were to use this algorithm for a different integer size, you would need to replace 0xFFFFFFFF with the hex equivalent for the correct size. 8 bits would be 0xFF, 16 bits would be 0xFFFF, and so on. The WriteFile Function read more..

  • Page - 139

    95 Creating a Bitvector Class 1: bool ReadFile( const char* p_filename ) 2: { 3: FILE* infile = 0; 4: int read = 0; 5: infile = fopen( p_filename, “rb” ); 6: if( infile == 0 ) 7: return false; 8: read = fread( m_array, sizeof(unsigned long int), m_size, infile ); 9: fclose( infile ); 10: if( read != m_size ) 11: return false; 12: return true; 13: } The only read more..

  • Page - 140

    96 4. Bitvectors // set all the bits in the vector to 1 bitv.SetAll(); // resize the bitvector to 48 bits bitv.Resize( 48 ); // get the size of the bitvector. int s = bitv.Size(); // Why is s = 64? Remember, because you are on a 32-bit system, // you can only have multiples of 32. Because you asked for 48 // bits, the resize algorithm had to make read more..

  • Page - 141

    97 Application: The Quicksave also pretty much useless if they don’t have a save feature. What’s the point of play- ing a long and complex game without being able to start up where you left off the last time? Unfortunately, a ton of data usually needs to be stored whenever you save a game. Almost all the time, this data is going to be stored on some kind of read more..

  • Page - 142

    98 4. Bitvectors Storing the Players in the Game For this demonstration, I’ll use my good old friend, the array, to store the players in the game. This is somewhat important for this demonstration because each player in the game is assigned an ID number that corresponds to his index in the array. I’ll also define a bitvector, which will keep track of which read more..

  • Page - 143

    99 Application: The Quicksave On lines 4–10, the algorithm loops through and initializes all the players, giving them 11–20 life, 0–99 money, and 0 experience and making them level 1–5. Lastly, on line 11, I call the SetAll function of the bitvector, setting every item in the vector to 1. The reason I do this is because every player has just been initialized and read more..

  • Page - 144

    100 4. Bitvectors Saving the Player Array to Disk Now, to save the player array to disk, you’re going to need a more complicated algorithm than just saving the entire array to disk. The algorithm you’re going to use is to iterate through the entire array and check the modified flag for each player. If the flag is true, you write the player to the appropriate read more..

  • Page - 145

    101 Application: The Quicksave After that, you write the individual player to file by first getting the player and then using the address-of operator (&) to pass a pointer into fwrite (if you’ll recall, fwrite requires a pointer to the data you want to write). Finally, after all the players have been written, you call the ClearAll function of the g_modifiedstates bitvector, read more..

  • Page - 146

    102 4. Bitvectors Playing the Game When you start the game up, 64 “players” will be shown on the screen, each one with a box around it. The boxes signify that the players haven’t been saved to disk yet, and the boxes will disappear when you press the S key on the keyboard. Clicking on a player will randomize their attributes and cause a box to appear around the read more..

  • Page - 147

    103 Bitfields about saving or sending the states of hundreds of players over a network, that means you’re sending 4 four times as much data that you need to be transmitted. This is obviously a large waste. Luckily, C++ introduces the notion of bitfields, individual integer variables within a class or structure that contain a certain number of bits. Declaring a Bitfield read more..

  • Page - 148

    104 4. Bitvectors Player bob; bob.m_state = 0; bob.m_haskey = 1; From now on, you can do anything you want to the bitfield that you can do with an integer, with one exception: the address-of (&) operator doesn’t work on bitfields. This is because bitfields are not variables; they are just small parts of one larger variable. One cool thing about bitfields is that they can read more..

  • Page - 149

    105 Analysis of Bitvectors and Bitfields in Games NOTE Make sure that you keep all of your bitfields together when you define them.You cannot rely on the compil- er to optimize the structure auto- matically for you. NOTE Also keep in mind that a single bit- field is useless on its own.The reason for this is that most compilers put the bitfields into a padded structure. read more..

  • Page - 150

    106 4. Bitvectors Conclusion In this chapter, you learned how to store bits into a larger integer structure, how to read them back out again, and how to create a class that automates these proce- dures for you. In addition, you learned how to use bitvectors to implement a simple quicksave system. You also learned how to use bitfields as an alternative to bitvectors to read more..

  • Page - 151

    CHAPTER 5 Dimensional Arrays Multi- Team LRN read more..

  • Page - 152

    108 5. Multi-Dimensional Arrays Previously, I’ve only talked about linear array structures—those with only one dimension. This chapter will introduce you to the more complex class of arrays named multi-dimensional arrays. You will find that multi-dimensional arrays are more specific in their nature and cannot be applied to as many situations as regular arrays can be. In this read more..

  • Page - 153

    109 What Is a Multi-Dimensional Array? Now, imagine expanding that universe into two dimensions by adding another axis: height (traditionally called the y axis). Instead of just a line, this time you have a plane, and any point on the plane can have two coordinates instead of just one. And finally, there is the three-dimensional universe, in which the third axis is depth read more..

  • Page - 154

    110 5. Multi-Dimensional Arrays Figure 5.2 This is a two- dimensional array of size (8,8). A two-dimensional array has two dimensions, a length and a height. In Figure 5.2, both of these dimensions are 8 cells, giving us a total of 64 cells. A three-dimensional array uses all three dimensions, as demonstrated by Figure 5.3. As you can see, it’s difficult to represent a read more..

  • Page - 155

    111 Graphical Demonstration Graphical Demonstration The graphical demonstration for this chapter can be found in the directory \demonstrations\ch05\Demo01 - 2D Array\ . Because it is very difficult to represent arrays with more than two dimensions graphically, this demonstration only shows 2D arrays and the algorithm to resize them. Compiling the Demo This demonstration uses the SDLGUI read more..

  • Page - 156

    112 5. Multi-Dimensional Arrays There are two buttons shown on the screen, one that will let you resize the array and one that will let you randomize the number in every cell. The demonstration will show the exact algorithm used to resize a 2D array and will show red Xs in cells whose value is “invalid.” I used this same approach in the Array Graphical read more..

  • Page - 157

    113 Native Multi-Dimensional Arrays due to the fact that their dimensions are multiplied to get the size. For example, even though each dimension in array4d in the previous code segment is only three cells large, the entire array takes up 81 cells. Compare this to array3d, however, in which each dimension is four cells large, yet the entire array only takes up 64 cells. read more..

  • Page - 158

    114 5. Multi-Dimensional Arrays { { 13, 14 }, { 15, 16 } } } }; I do not recommend initializing arrays like this often. As you can see, the definition gets quite messy, and it becomes almost impossible to keep track of all the little brackets. It is not intuitive to initialize arrays with more than two dimensions in code because code is represented on a 2D read more..

  • Page - 159

    115 Native Multi-Dimensional Arrays There is one catch, however: Only the first dimension can be left out. Every other dimension must be explicitly defined. I explain the reasons for this in the section entitled “Inside a Multi-Dimensional Array” later on. For example, this is invalid: int array[][] = { { 1, 2 }, { 3, 4 } }; Even though it is obvious to us that read more..

  • Page - 160

    116 5. Multi-Dimensional Arrays Figure 5.6 This figure shows where the 15 is put within array3d. Inside a Multi-Dimensional Array So how does C++ represent a multi-dimensional array internally? Remember how a normal array works, first of all. You hand it an index, and it figures out the correct place in memory by multiplying the size of an item and adding that to the read more..

  • Page - 161

    117 Native Multi-Dimensional Arrays You see, if you treat each row in the 2D array as a single item, you can view the 2D array as a 1D array of arrays. Figure 5.7 shows how you slide each row out to the right and combine all four rows into a single array. The general formula for converting a 2D coordinate into a 1D coordinate is then: y * width + x read more..

  • Page - 162

    118 5. Multi-Dimensional Arrays The first term, z * width * height, finds which 2D array you want to access first. If z was 2 in a 3 3 3 array, then this would give you 2 * 3 * 3, which is 18. The sec- ond term determines which row within the 2D array you want to access. If y was 1, then you would have 1 * 3, which is 3. Then the third term read more..

  • Page - 163

    119 Native Multi-Dimensional Arrays Passing Multi-Dimensional Arrays to Functions Multi-dimensional arrays can be passed into functions just like normal arrays can. There are several ways to do this. The most popular way is to have the function assume that it will be receiving an array of a specific size, like this: void Function( int p_array2d[4][5], int p_array3d[2][4][2] ); This read more..

  • Page - 164

    120 5. Multi-Dimensional Arrays The same applies to 3D arrays, too, except with 3D arrays, you need to know the width and the height to access any given cell, so you can only pass in 3D arrays with a fixed width and height. void Function1( int p_array[][][] ); void Function2( int p_array[][][5] ); void Function3( int p_array[][4][5] ); Functions 1 and 2 are both read more..

  • Page - 165

    121 Dynamic Multi-Dimensional Arrays int monsters[TYPES][SIZES]; I need to say one more thing about passing arrays into functions. If you pass in an array with a variable dimension size, there is no way for C++ to determine the size of that dimension. With the previous example, if you passed in a 5 3 array to Process, there is really no way for the function to tell read more..

  • Page - 166

    122 5. Multi-Dimensional Arrays The Template Parameters Because you want your class to be able to work with many different types of datatypes, you’ll be making it templated just like the Array class from Chapter 3. The Array2D class only needs one template parameter: the datatype of the items that will be stored in the array, which I’ll call Datatype: template <class read more..

  • Page - 167

    123 Dynamic Multi-Dimensional Arrays The Destructor Remember how the Array class was able to automatically delete the memory of the array for us? You’ll be doing the same exact thing with the Array2D class: 1: ~Array2D() 2: { 3: if( m_array != 0 ) 4: delete[] m_array; 5: m_array = 0; 6: } On line 3 you check to make sure the pointer is valid, just in case it read more..

  • Page - 168

    124 5. Multi-Dimensional Arrays This time, because it is possible to resize two dimensions at the same time (requir- ing the user to only resize one dimension at a time is easier to code, but it is waste- ful in terms of processing power), you need to keep track of only the cells that will exist in both arrays. Figure 5.9 shows which cells need to be copied over read more..

  • Page - 169

    125 Dynamic Multi-Dimensional Arrays 14: { 15: newarray[ t1 + x ] = m_array[ t2 + x ]; 16: } 17: } 18: if( m_array != 0 ) 19: delete[] m_array; 20: m_array = newarray; 21: m_width = p_width; 22: m_height = p_height; 23: } If you look closely, this is nothing more than a 2D extension of the Array::Resize algorithm. On line 3, you allocate the new array and read more..

  • Page - 170

    126 5. Multi-Dimensional Arrays Getting the Size of the Array Because this is a 2D array, there isn’t just one size now; three different sizes can be associated with the array: the number of cells in the array, the width, and the height. The width and the height are easy sizes to retrieve: int Width() { return m_width; } int Height() { return m_height; } These read more..

  • Page - 171

    127 Dynamic Multi-Dimensional Arrays // retrieve the cells that we just set. i = iarray.Get( 4, 4 ); f = farray.Get( 3, 2 ); // get the size of each array. i = iarray.Size(); i = farray.Size(); // fill the integer array with consecutive numbers for( y = 0; y < 5; y++ ) { for( x = 0; x < 5; x++ ) { iarray.Get( x, y ) = y * 5 + read more..

  • Page - 172

    128 5. Multi-Dimensional Arrays m_array = new Datatype[ p_width * p_height * p_depth ]; m_width = p_width; m_height = p_height; m_depth = p_depth; } // destructor ~Array3D() { if( m_array != 0 ) delete[] m_array; m_array = 0; } Datatype& Get( int p_x, int p_y, int p_z ) { return m_array[ (p_z * m_width * m_height) + (p_y * m_width) + p_x ]; } void read more..

  • Page - 173

    129 Dynamic Multi-Dimensional Arrays for( y = 0; y < miny; y++ ) { // precalculate the middle term (y) of the // access algorithm t3 = y * p_width; t4 = y * m_width; for( x = 0; x < minx; x++ ) { // move the data to the new array. newarray[ t1 + t3 + x ] = m_array[ t2 + t4 + x ]; } } } // delete the old array. if( m_array != 0 ) read more..

  • Page - 174

    130 5. Multi-Dimensional Arrays return m_depth; } private: Datatype* m_array; int m_width; int m_height; int m_depth; }; The entire class is virtually identical to Array2D, except that there is a new dimen- sion, the depth, and the Constructor, Get, and Resize functions have been modified to take this into account. Example 5-3 Example 5-3 on the CD is an almost exact copy read more..

  • Page - 175

    131 Application: Using 2D Arrays as Tilemaps iarray.Get( x, y, z ) = (z * 2 * 5) + (y * 2) + (x); } } } // resize the array to make it larger: iarray.Resize( 3, 6, 4 ); // resize the array to make it smaller: iarray.Resize( 2, 2, 2 ); } Application: Using 2D Arrays as Tilemaps This is Game Demonstration 5-1, which you can find on the CD in read more..

  • Page - 176

    132 5. Multi-Dimensional Arrays would have a huge bitmap representing the entire game world. Using tilemaps, you can have your artists draw up a few tiles and then use a map editor to arrange the tiles so that they form a complete picture. See Figure 5.10 for a pictorial represen- tation of both of these methods. Figure 5.10 This is a comparison of the two image read more..

  • Page - 177

    133 Application: Using 2D Arrays as Tilemaps Now, instead of drawing every pixel of the entire map, you only have three differ- ent tiles. Storing the Tilemap In the demo, I will need some way to store the tilemap. Naturally, because this chapter is about multi-dimensional arrays, I’ll use one of those. In this case, a 2D array looks like it is optimal for the read more..

  • Page - 178

    134 5. Multi-Dimensional Arrays Generating the Tilemap Now I need an algorithm to generate the tilemap. For this demo, I’ve used a simple method: Randomization of the grass and snow and a pre-set loop to create the road. First, take a look at the grass and snow: for( y = 0; y < MAPHEIGHT; y++ ) { for( x = 0; x < (MAPWIDTH / 2); x++ ) { g_tilemap.Get( x, y read more..

  • Page - 179

    135 Application: Using 2D Arrays as Tilemaps The last four lines of code place the corner tiles at each corner. Drawing the Tilemap In this demo, you will be using a tilemap drawing algorithm that will draw the tilemap with the upper-left tile being drawn at the given coordinates. 1: void DrawTilemap( int p_x, int p_y ) 2: { 3: int x, y; 4: int bx = p_x; 5: read more..

  • Page - 180

    136 5. Multi-Dimensional Arrays Playing the Game When you launch the game, you are greeted with the tilemap! Hooray! It should look like Figure 5.12. Figure 5.12 Here is a screenshot of Game Demo 5-1. You can use the arrow keys on your keyboard to move the map around. Don’t worry about going off the edges of the map; the algorithm still works fine. Application: read more..

  • Page - 181

    137 Application: Layered Tilemaps If you look at the line separating the snow and the grass tiles from the previous example, you immediately notice that it doesn’t look right. Snow just doesn’t fall in a solid line like that. The easiest solution would be to draw a “transition” tile, in which you would draw some snow on the grass tile to make it look more natural. read more..

  • Page - 182

    138 5. Multi-Dimensional Arrays the tile should be transparent in some places, letting the renderer show some of the tiles underneath. Figure 5.14 shows the bitmap you will use for the second layer. Every pure black pixel on the bitmap is treated as a transparent pixel and won’t be drawn. This means that the grass texture from the base layer will show through the read more..

  • Page - 183

    139 Application: Layered Tilemaps Reinitializing the Tilemap Because the tilemap now has two layers instead of just one, you need to determine which tiles go on which layer. You’ll be using the same half-grass/half-snow design of the previous demo for layer 0 (the base layer). There is absolutely no change in the code except for the addition of the number 0 in the read more..

  • Page - 184

    140 5. Multi-Dimensional Arrays Because the rectangular road path goes over both the snow and the grass, the transparent snow tiles will overlap with the road, which will make it look weird. So you need to clear off the snow tiles that lie on top of the first road. // clear the snow off of the path tiles. g_tilemap.Get( (MAPWIDTH/2) - 1, 2, 1 ) = -1; read more..

  • Page - 185

    141 Application: Layered Tilemaps This time, I’ve added a third looping variable, z. This will loop through each layer of the tilemap. On line 6, I’ve added an index variable, which will be used to cache the bitmap index of the current tile. You will see the reason for it in a little bit. The outermost loop, starting on line 7, loops through each layer, starting read more..

  • Page - 186

    142 5. Multi-Dimensional Arrays Notice how the second road disappears into the snow? That’s the power of layered tilemaps. Comparing Performance There is one important note that I feel I must make about the layered tilemap demo. It will be significantly slower than the single-layer tilemap version. The rea- son for this is because the rendering routine now adds an if read more..

  • Page - 187

    143 Application: Layered Tilemaps Figure 5.16 This is a four-stage pipeline, with five instructions being computed. In the first part, all four stages are empty, and the processor isn’t doing anything. After an instruction is executed, it takes four clock cycles to complete because each stage in the pipeline takes one cycle to complete. When one cycle has passed, the first read more..

  • Page - 188

    144 5. Multi-Dimensional Arrays When you have lots of if statements in your code, the chances that the processor will make a correct guess on the result of the conditional are lowered, and you end up with code that is significantly slower as a result. These problems are very large for processors that have huge pipelines (such as the P4), but don’t cause quite as read more..

  • Page - 189

    145 Conclusion Figure 5.17 This figure shows the order of visitation using two different loops on a 2D array. Conclusion In this chapter, you learned everything a normal human being should know about multi-dimensional arrays, such as how to declare them, initialize them, access their cells, and pass them into functions. You also learned how to encapsulate 2D and 3D arrays read more..

  • Page - 190

    This page intentionally left blank Team LRN read more..

  • Page - 191

    CHAPTER 6 Linked Lists Team LRN read more..

  • Page - 192

    148 6. Linked Lists I’m sure you’ve wished many times when you’ve been programming that you could use a more flexible data structure than an array. Perhaps you’ve wanted to conserve memory or be able to insert and remove data quickly. If so, then the linked list is the answer to your problems. In this chapter, you will learn ■ What a linked list is ■ read more..

  • Page - 193

    149 Singly Linked Lists Figure 6.1 Here is a pictorial representation of a four- node linked list. Each node points to the next node in the list. Because of the way that linked lists are structured, you can easily add or remove nodes at the beginning or the end of a list, or even in the middle of the list. Many different linked list variations exist, but I only read more..

  • Page - 194

    150 6. Linked Lists When the program starts, you are presented with four buttons and a five-node singly linked list. Figure 6.2 shows a screenshot of this scenario. Figure 6.2 Here is a screenshot from the Singly Linked List graphical demonstration. The very first node on the left will be colored red to indicate that it is the current node. In the Chapter 3 array read more..

  • Page - 195

    151 Singly Linked Lists The SListNode Class I call this class the SListNode. It is simple and contains only two data members: template<class Datatype> class SListNode { public: Datatype m_data; SListNode<Datatype>* m_next; }; The first member is m_data, which holds the data that is going to be stored in the node. The second member is m_next, which is a pointer to read more..

  • Page - 196

    152 6. Linked Lists As you can imagine, this method tends to become a little cumbersome. Adding items to the list becomes very difficult as the size increases. Accessing items becomes just as difficult. Because of this, you should find a better way to access the list. The InsertAfter Function First of all, you need a better method of inserting nodes. I’ll build this read more..

  • Page - 197

    153 Singly Linked Lists // create the new node. SListNode<Datatype>* newnode = new SListNode<Datatype>; newnode->m_data = p_data; // make the new node point to the next node. newnode->m_next = m_next; // make the previous node point to the new node m_next = newnode; } The first step is to create a new node and set its data. You then take that new node and make it read more..

  • Page - 198

    154 6. Linked Lists For this simple iteration example, I’ll just use a SListNode pointer as the iterator. This is Example 6-2: // create a new linked list. SListNode<int>* list = new SListNode<int>; list->m_data = 10; // insert 30 and then 20 before that, so the list is 10, 20, 30. list->InsertAfter( 30 ); list->InsertAfter( 20 ); cout << “the list read more..

  • Page - 199

    155 Singly Linked Lists SListNode<Datatype>* m_head; SListNode<Datatype>* m_tail; int m_count; }; So what you end up with is a class that contains three things, as Figure 6.6 depicts: a pointer to the first node in the list, a pointer to the last node in the list, and the total number of nodes in the list. This class will make working with linked lists much read more..

  • Page - 200

    156 6. Linked Lists ~SLinkedList() { // temporary node pointers. SListNode<Datatype>* itr = m_head; SListNode<Datatype>* next; while( itr != 0 ) { // save the pointer to the next node. next = itr->m_next; // delete the current node. delete itr; // make the next node the current node. itr = next; } } This method uses two iterators: itr and next. When read more..

  • Page - 201

    157 Singly Linked Lists m_tail->InsertAfter( p_data ); m_tail = m_tail->m_next; } m_count++; } To append an item to the end of the list, you could simply call InsertAfter on the last node of the list, right? Well, it’s not quite that simple. What happens if there is no last node? This is why the if/else block exists. If m_head is 0, the list is empty and you read more..

  • Page - 202

    158 6. Linked Lists The Prepend Function Now that you can add items to the end of a linked list, wouldn’t it be cool to be able to add items to the beginning? This method is called prepending. void Prepend( Datatype p_data ) { // create the new node. SListNode<Datatype>* newnode = new SListNode<Datatype>; newnode->m_data = p_data; newnode->m_next = m_head; // set the read more..

  • Page - 203

    159 Singly Linked Lists delete m_head; m_head = node; // if the head is null, then you’ve just deleted the only node // in the list. set the tail to 0. if( m_head == 0 ) m_tail = 0; m_count—; } } Figure 6.8 This is the process of adding a new node to the front of a singly linked list. Team LRN read more..

  • Page - 204

    160 6. Linked Lists All you need to do is delete the first node and move the head pointer up to point to the next node in the list. There are two special cases, though. First of all, the list might be empty. In that case, do nothing. In the second case, there might be only one node left in the list. In that case, delete the node and set the head and read more..

  • Page - 205

    161 Singly Linked Lists node = node->m_next; // make the tail point to the node before the // current tail and delete the old tail. m_tail = node; delete node->m_next; node->m_next = 0; } m_count—; } } Figure 6.9 shows the process of removing the tail node. Figure 6.9 This is the process of removing the tail node of a linked list. Note how it is a read more..

  • Page - 206

    162 6. Linked Lists The SListIterator Class Now, to interface with your new SLinkedList class, you should create an iterator class, which automates the iterator functions I covered earlier. This class contains two things: A pointer to the current node and a pointer to the list that the node is in. You’ll see why in a little bit. template<class Datatype> class read more..

  • Page - 207

    163 Singly Linked Lists The Forth Function The Forth function moves the iterator to the next node in the list. void Forth() { if( m_node != 0 ) m_node = m_node->m_next; } The only time this function does nothing is when the current node is 0. When the current node is 0, then this iterator isn’t pointing at anything and is invalid. The Item Function This read more..

  • Page - 208

    164 6. Linked Lists Using Iterators Now that you have the basic functions set, try rewriting Example 6-2 so that you use the SLinkedList and SListIterator classes. This is Example 6-3: // create a new linked list. SLinkedList<int> list; // insert 10, 20 and 30. list.Append( 10 ); list.Append( 20 ); list.Append( 30 ); cout << “the list contains: “; // read more..

  • Page - 209

    165 Singly Linked Lists return; if( p_iterator.m_node != 0 ) { // if the iterator is valid, then insert the node p_iterator.m_node->InsertAfter( p_data ); // if the iterator is the tail node, then // update the tail pointer to point to the // new node. if( p_iterator.m_node == m_tail ) { m_tail = p_iterator.m_node->m_next; } m_count++; } else { read more..

  • Page - 210

    166 6. Linked Lists The Remove Function The Remove function is the most complicated of all of the singly linked list func- tions. The reason for this is because of the nature of a singly linked list node: It only points to the next node. If you want to remove any node within a list, you need to find the previous node first and link that up to the next node read more..

  • Page - 211

    167 Singly Linked Lists m_count—; } The first thing you check is to see if the iterator is valid. If it isn’t, then you just return and don’t do anything. One thing I want to call attention to is the behavior of the iterator. When you inserted a node using an iterator, the iterator stayed pointing to the same node. However, you can’t do that when you read more..

  • Page - 212

    168 6. Linked Lists The algorithm then loops through the list until you find the node prior to the node you want to remove. Remember, you did this with the RemoveTail function as well, because the node doesn’t point back to the prior node. So before you actually delete the node, you move the iterator forward and make it point to the next node in the list. This read more..

  • Page - 213

    169 Doubly Linked Lists In the first code block after the list and the iterator declarations, you append 10, 30, and 40 to the list in that order and print it out. That was simple—you’ve seen the Append function before. In the second code block, you get an iterator and reset it to the beginning of list. At this point, itr should be pointing to 10. Now you call read more..

  • Page - 214

    170 6. Linked Lists Figure 6.11 A four-node doubly linked list is a more complex version of a singly linked list. Each node now has two pointers, instead of just one. Most of the algorithms involving a doubly linked list are very similar to the singly linked versions, so we won’t spend much time discussing them. I’ll mainly go over the important additions or read more..

  • Page - 215

    171 Doubly Linked Lists Figure 6.12 This is a screenshot from the Doubly Linked List Graphical Demonstration. On the left are two new buttons: Back and End. The Back button moves the itera- tor to the previous node in the list, and the End button moves the iterator to the end of the list. On the right is one new button: Insert Before. This button inserts a new read more..

  • Page - 216

    172 6. Linked Lists Figure 6.13 This is a doubly linked list node. Because a doubly linked list node has two pointers, it is a little more complicated to add and remove nodes from the list because there are more pointers to rearrange. Doubly Linked List Algorithms I’ll now briefly cover the most common algorithms used on doubly linked lists: insertion and removal of read more..

  • Page - 217

    173 Doubly Linked Lists Figure 6.14 This is how you insert a node into a doubly linked list. Because you might be inserting a node at the front or the end of the list, the if statements in Steps 4 and 5 are important. If you’re inserting a node at the front of the list, then node L doesn’t exist. The same applies with the end, in which case R doesn’t read more..

  • Page - 218

    174 6. Linked Lists This process is demonstrated in Figure 6.15. Figure 6.15 This is how you remove a mode from a doubly linked list. As you can see, removing a node from a doubly linked list is much easier. Reading and Writing Lists to Disk In Chapter 3, when I showed you how to read and write arrays onto disk, it was nice and easy because C file functions read more..

  • Page - 219

    175 Reading and Writing Lists to Disk Because lists have a variable size, it is often a good idea to store the number of nodes that are being written to the file first. This way, when it comes time to read the list back in, the algorithm first reads the number of nodes stored in the file and then reads all the nodes in. Here is the SaveToDisk function in read more..

  • Page - 220

    176 6. Linked Lists Here is the code: 1: bool ReadFromDisk( char* p_filename ) 2: { 3: FILE* infile = 0; 4: Datatype buffer; 5: int count = 0; 6: infile = fopen( p_filename, “rb” ); 7: if( infile == 0 ) 8: return false; 9: fread( &count, sizeof( int ), 1, infile ); 10: while( count != 0 ) 11: { 12: fread( &buffer, sizeof( Datatype ), read more..

  • Page - 221

    177 Application: Game Inventories Compiling the Demo This demonstration uses the SDLHelpers library that I have developed for the book. For more information about this library, see Appendix B. To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix B. If you create your own project, read more..

  • Page - 222

    178 6. Linked Lists class Item { public: int m_type; int m_weight; }; Adding an Item to the Inventory Whenever the player picks up a new item, you want to add that to the inventory. In this demo, I use an algorithm that randomly generates a weight for a given item type and adds it to the player’s inventory: 1: void AddItem( int p_type ) 2: { 3: Item item; read more..

  • Page - 223

    179 Application: Game Inventories In the demo, you keep track of a current item, and you can only remove the current item. You keep track of it by using an iterator. Whenever you want to remove the item, you pass the iterator into the function: 1: void RemoveItem( DListIterator<Item> p_itr ) 2: { 3: if( p_itr.Valid() ) 4: { 5: g_player.m_currentWeight -= read more..

  • Page - 224

    180 6. Linked Lists The demo is compiled so that you can only hold a weight of 100, so you can add up to 10 items to your inventory if they each weigh 10 units. Table 6.1 lists the commands that are used in the game. Table 6.1 Inventory Demo Controls Action Effect Clicking on icons on bottom Clicking in black box Pressing left arrow key Pressing right arrow read more..

  • Page - 225

    181 Application: Layered Tilemaps Revisited In Chapter 5, “Multi-Dimensional Arrays,” I showed you how to use 3D arrays to represent a layered tilemap. The biggest flaw with that method, however, was that it wasted space for layers that are mostly blank. Using a 2D array of linked lists can solve this problem. For example, say you have an 8 8 map. You want the read more..

  • Page - 226

    182 6. Linked Lists This definition creates a 2D array of singly linked lists. The 2D array has dimensions MAPWIDTH and MAPHEIGHT, which are constants defined in the demo program. As before, each tile will be an integer, which will determine which tile graphic is drawn. > will see the >> NOTE Please take notice of the space between the two brackets. It is read more..

  • Page - 227

    183 Application: Layered Tilemaps Revisited Because you’re using linked lists now, you can’t really draw each layer individually. This time, you loop through each x and y coordinate in the map and draw every layer for the current tile. Here is the algorithm used with linked lists: 1: void DrawTilemap( int p_x, int p_y ) 2: { 3: int x, y; 4: int bx = p_x; 5: int read more..

  • Page - 228

    184 6. Linked Lists Analysis and Comparison of Linked Lists This was a long chapter, but it was packed full of information. You learned about two variations of the linked list data structure and two uses of them in game pro- gramming. You might, however, be surprised to learn that this is nowhere near the end of it. There are many more variations of lists, but most read more..

  • Page - 229

    185 Analysis and Comparison of Linked Lists If the O(n) and O(c) notation doesn’t look familiar, please go back and read Chapter 1, “Basic Algorithm Analysis”; it has all the information you need about algorithm analysis. Basically, O(c) means that the algorithm completes itself quickly and doesn’t depend on the number of items in the array or list. O(n) is slower read more..

  • Page - 230

    186 6. x * s n * 4 n * 8 Linked Lists Table 6.3 Data Structure Overhead Structure Overhead (Bytes) Array Singly Linked List Doubly Linked List x is the number of cells that are unused in an array. s is the size of the data structure in bytes. n is the number of items in the data structure. Just to get an idea of how overhead is measured, let’s read more..

  • Page - 231

    187 Analysis and Comparison of Linked Lists Real-World Issues What I’m going to tell you in this section will probably make you want to hit me— hard. Linked lists in games don’t have many uses if you want to make your game super fast. The reason for this is caching. Remember when I told you in Chapter 3 about how caches work? They load entire chunks of read more..

  • Page - 232

    188 6. Linked Lists For example: Using a linked list to maintain information about the number of bul- lets flying around in a game at any given time is not worthwhile. The lifetime of a bullet is a few frames at most (1/10 of a second?), so you would have to delete it almost immediately after creating it! You’re much better off creating a large array to store read more..

  • Page - 233

    CHAPTER 7 Queues Stacks and Team LRN read more..

  • Page - 234

    190 7. Stacks and Queues The chapters before this one have only been concerned with methods of storing data within a program. This chapter will introduce you to two new abstract structures, which, instead of specifying how data is stored, will specify how data is accessed. They are the stack and the queue data structures. Because these structures are very similar in read more..

  • Page - 235

    191 Stacks Figure 7.1 A stack of dishes.You can only take a dish from the top or place a new dish on top. The dishes on the bottom are not accessible to you. There are only two things that you can do with a stack of dishes: You can put a dish on top of it, and you can take a dish off of the top. With computer stacks, putting something on top of the read more..

  • Page - 236

    192 7. Stacks and Queues Figure 7.2 This figure shows how to push and pop numbers onto and from a stack. Graphical Demonstration: Stacks The graphical demonstration for the stack data structure is on the CD in the direc- tory \demonstrations\cd07\Demo01 – Stacks\ . This demo is quite simple and only has two functions: You can push a number onto the stack or you can read more..

  • Page - 237

    193 Stacks Figure 7.3 Here is a screenshot from the Stack demo. The Stack Functions Table 7.1 shows the functions that the stack classes in this book have. All of the stack classes are on the CD in the \structures\stack.h file. Table 7.1 Stack Functions Name Description Push This places an item on the top of the stack. Pop This removes the item at the top of the read more..

  • Page - 238

    194 7. Stacks and Queues Linked Stacks A linked stack uses a linked list to store the data in the stack. Your linked stack class will be called LStack. To gain the capabilities of the DLinkedList class, your LStack class will inherit it. If you are unfamiliar with inheritance, the first section of Chapter 9, “Tying It Together: The Basics,” discusses inheritance. The read more..

  • Page - 239

    195 Stacks void Push( Datatype p_data ) { Append( p_data ); } The Pop Function To pop an item off the top of the stack, all you need to do is remove the tail of the list: void Pop() { RemoveTail(); } The Top Function Now you need a function that makes it easy to access the top of the stack. This is easy—just return the item that the tail points to: read more..

  • Page - 240

    196 7. Stacks and Queues Using the DLinkedList Functions Because the LStack class inherited the DLinkedList class, you are able to use any instance of a LStack as a DLinkedList as well. This means that you can create itera- tors and iterate through the entire stack like a linked list and even remove items from the middle of the stack. Granted, that is not very read more..

  • Page - 241

    197 Stacks Figure 7.5 You can use an array as a stack by using the lowest index as the bottom of the stack and the higher indexes as the top of the stack. The Constructor Because the Array class constructor requires an integer as a parameter, so does the AStack class. The constructor will also clear the m_top variable to 0 because the ini- tial stack will be read more..

  • Page - 242

    198 7. Stacks and Queues The Push Function Because the m_top index always points at the first empty index, the Push function can simply place the new item into that index. After the item is inserted, the m_top index can be incremented. bool Push( Datatype p_data ) { if( m_size != m_top ) { m_array[m_top] = p_data; m_top++; return true; } return false; } Note that read more..

  • Page - 243

    199 Stacks return m_array[m_top - 1]; } The Count Function The m_top function also tells us how many items are stored in the stack. For exam- ple, if m_top is 0, the first open index is the very first index in the array, which means that the stack is empty. int Count() { return m_top; } Why Use an Arrayed Stack? As you can see, an arrayed stack read more..

  • Page - 244

    200 7. Stacks and Queues During the game, you usually press Escape to bring up an options menu. From this main menu, several options are displayed. Typically, the options allow you to create a new game, save the game, load a new game, or configure game options. Figure 7.6 shows an example of one of these menus. Figure 7.6 This is a sample game main menu that read more..

  • Page - 245

    201 Stacks Now you have several options from this menu: You could press Escape and go back to the main menu or you could choose one of the three options listed, each of which brings up another menu. It turns out that a stack can model a menu system like this quite easily. Every time you go to a sub-menu from an existing menu, the new menu is created and read more..

  • Page - 246

    202 7. Stacks and Queues int m_x; int m_y; int m_w; int m_h; SDL_Color m_color; }; The m_options array holds pointers to strings, and the m_optionsSpawns array holds indexes. For example, if m_options[0] was “Sound Menu” and the sound menu is at index 1 in the g_menus array, then the menu will be initialized like this: menu.m_options[0] = “Sound Menu”; read more..

  • Page - 247

    203 Stacks g_stack.Push( &g_menus[x] ); } Because not all options are valid in every menu, the value 0 is used to denote that an option doesn’t spawn a new menu. The top of the stack is accessed, and if option 0 spawns a new window, the appropriate menu is retrieved and pushed onto the stack. Removing a Menu from the Stack Whenever you go back to a previous read more..

  • Page - 248

    204 7. Stacks and Queues Figure 7.8 shows a screenshot from the demo in action. Figure 7.8 This is a screenshot from the menu game demo. Queues I’m sure that you know what a queue is. If you’ve never heard of the term before, you probably still know what they are. If you’ve ever been to a grocery store, you stand in a queue when you are checked out. read more..

  • Page - 249

    205 Queues Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B. To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix B. If you create your own project, all of the files you read more..

  • Page - 250

    206 7. Stacks and Queues The Queue Functions Table 7.3 shows the functions that the queue classes in this book will have. All queue classes are located on the CD in the \structures\queue.h file. Name Description Enqueue Dequeue Count Table 7.3 Queue Functions Puts a new item at the end of the queue Removes the item at the front of the queue Front Returns the item read more..

  • Page - 251

    207 Queues void Dequeue() { RemoveHead(); } The Front Function Again, because the queue reads the front item instead of the last, the m_tail pointer in the Top function needs to be changed to the m_head pointer. Datatype Front() { return m_head->m_data; } Arrayed Queues Arrayed queues are the most complex implementation of all of the structures I cover in this read more..

  • Page - 252

    208 7. Stacks and Queues Figure 7.11 This is the slow method of dequeuing something by moving everything down by one index to remove the first item. Because you naturally want everything to run as fast as possible, you need to find a faster way to do this. The second method is somewhat simple, but you need a new variable to implement it. Instead of having index read more..

  • Page - 253

    209 Queues Figure 7.13 A full circular queue: The items wrap around the boundary and start at the beginning when you go past the end. The Structure For a circular queue, you need to have two new variables: the index of the front of the queue and the number of items within the queue. template<class Datatype> class AQueue : public Array<Datatype> { public: read more..

  • Page - 254

    210 7. Stacks and Queues The queue calls the Array constructor to tell it the size it wants to be, and the front index and the count variable are both reset to 0 because the queue is empty. AQueues are constructed the same way AStacks are: AQueue<int> queue( 10 ); This creates a queue of integers with a size of 10. The Enqueue Function The Enqueue function is read more..

  • Page - 255

    211 Queues The Dequeue Function The Dequeue function is much simpler. If there are items left in the queue, the front index is incremented by 1. If the front index passes the end of the array, it is reset to 0 again. void Dequeue() { if( m_count > 0 ) { m_count—; m_front++; if( m_front == m_size ) m_front = 0; } } The Front Function The Front read more..

  • Page - 256

    212 7. Stacks and Queues return m_array[ (p_index + m_front) % m_size]; } The code in bold is the important part of the algorithm. Do you notice anything about it? It is almost exactly the same as the code I used to access the end of the array! All I do is add the front index to the index I want and then wrap the result around using the modulo function. read more..

  • Page - 257

    213 Queues In some of these games, it is possible to tell your units to move to one place and then move to another place after they are done making the first move. This is called command queuing. For this demo, you will use a queue to implement the movement of a spaceship fly- ing around the screen. The Player and the Coordinates To make things easier, a simple read more..

  • Page - 258

    214 7. Stacks and Queues Figure 7.14 The figure shows the path of the spaceship. Each pair of coordinates was stored in a queue. Adding a Command to the Queue In the demo, a set of coordinates is added to the players queue whenever the mouse is clicked. Here is how it is accomplished: SDL_GetMouseState( &c.x, &c.y ); g_player.m_queue.Enqueue( c ); The c variable is read more..

  • Page - 259

    215 Queues g_player.m_queue.Dequeue(); if( g_player.m_queue.Count() > 0 ) Calculate(); } This code snippet checks to see if the current position of the spaceship is equal to the position of the current command in the queue. If it is, then the spaceship has completed the movement command, and the command should be removed. After the command is removed, you still have some work read more..

  • Page - 260

    216 7. Stacks and Queues As the figure shows, the ship will follow the line on the screen. The line represents all of the coordinates that are in the queue. Conclusion After reading this chapter, you should see that not all data structures have a specific implementation. As this chapter showed, the stack and the queue data structures really don’t specify how the data read more..

  • Page - 261

    CHAPTER 8 Hash Tables Team LRN read more..

  • Page - 262

    218 8. Hash Tables This chapter covers the most advanced of what I like to call the basic data struc- tures. I must warn you, though; this chapter isn’t very basic. In fact, most peo- ple I know who like computer programming absolutely hate the topics I cover in this chapter. However, I feel that this hatred exists because no one ever teaches this material read more..

  • Page - 263

    219 The Basic Hash Table Player 1: 945,253 Player 2: 433,455 Player 3: 36,549 These numbers are sparse; they are far away from each other. Now what happens when you want to store the players in a data structure so that you can easily access a player by their key? Your first instinct should be to use an array so you can access them quickly, but you will end up read more..

  • Page - 264

    220 8. TIP Hash Tables It is actually more efficient to make your hash table sizes prime numbers. I can’t really explain why this is without going into a whole discussion about dis- crete mathematics, but you should generally try to find a prime number above the desired number of items you store in the table. For example, if I wanted to store 10 items read more..

  • Page - 265

    221 The Basic Hash Table essentially instantaneous. An ideal hash table can search for items in O(c) time, which is a tremendous benefit for fast programs. Collisions One of the major problems with a hash table is that collisions occur frequently for simple tables. For example, try inserting these two players with these keys into the ten-cell table: 143,674 and 645,394. You read more..

  • Page - 266

    222 8. Hash Tables 1 + 4 + 3 + 6 + 7 + 4 = 25 and 6 + 4 + 5 + 3 + 9 + 4 = 31. Because these numbers are larger than the boundaries of the array, you have two options. You may expand the table so that it has 54 cells (the largest number that can be obtained using this method is 9 + 9 + 9 + 9 + 9 + 9 = 54), or you may read more..

  • Page - 267

    223 The Basic Hash Table Hashing Strings There is one more important hash function I want to show you. Besides integers, the other popular datatype that is frequently hashed is strings. The following algo- rithm does a really good job at hashing strings into an integer with very few colli- sions: unsigned long int StringHash( const char* p_string ) { unsigned long int hash read more..

  • Page - 268

    224 8. Hash Tables Multiplying each letter of the string by its index makes the hash function useful because you don’t have the problems that plain digit addition has. You can reverse the string and it will become a totally different hash value. Enhancing the Hash Table Structure There is no perfect hash function. You will probably always end up with read more..

  • Page - 269

    225 Enhancing the Hash Table Structure inefficient. I wouldn’t bother with this kind of collision resolution unless I was absolutely forced to. Quadratic Overflow There are many other methods based on the same idea, such as quadratic overflow collision resolution, where instead of incrementing the index by 1, you increment the index by 1 2 (1) and then 2 2 (4) and then read more..

  • Page - 270

    226 8. Hash Tables Using this method, you don’t have to worry about collisions at all! Whenever two hashes collide, the data is just appended to the back of the list. Searching for Keys If your hash function is efficient and doesn’t cause many collisions, then theoreti- cally you achieve an almost instant search time when searching for data in a hash read more..

  • Page - 271

    227 Graphical Demonstration: Hash Tables In the other chapters of this book, I usually put the graphical demonstrations near the front of the chapter. I felt, however, that I needed to build up to the linked overflow hash table before I showed you a graphical demo. I only showed you the primitive hash table types in order to lead up to the linked table so that you read more..

  • Page - 272

    228 8. Hash Tables The demo shows a 10-cell hash table, the same kind I’ve been using for the entire chapter so far. The hash table is designed to store three-digit integers where each integer is its own key. In reality, the key and the data stored in the table do not have to be the same, but I go into that later. For simplicity, each number stored read more..

  • Page - 273

    229 Implementing a Hash Table DataType m_data; }; The two template parameters are a KeyType and a DataType. The HashTable Class The HashTable class will have the same two template parameters as the HashEntry class. Table 8.2 shows a listing of all the functions the HashTable class will support. Function Name Purpose Constructor hash function. KeyType/DataType couple into the hash read more..

  • Page - 274

    230 8. Hash Tables int m_size; int m_count; Array< DLinkedList< Entry > > m_table; unsigned long int (*m_hash)(KeyType); }; The typedef on Line 5 is there to make your life easier. Without this typedef, you need to type HashEntry<KeyType, DataType> whenever you want to use a HashEntry, which makes the code long and ugly. The typedef condenses this down to just read more..

  • Page - 275

    231 Implementing a Hash Table HashTable( int p_size, unsigned long int (*p_hash)(KeyType) ) : m_table( p_size ) { // set the size, hash function, and count. m_size = p_size; m_hash = p_hash; m_count = 0; } On the second line of code, I use the standard C++ constructor notation to call the constructor of m_table so that it is initialized with the correct size. If you read more..

  • Page - 276

    232 8. Hash Tables The Find Function This function is designed to search the hash table to see if a certain key is in the table. If so, it will return a pointer to the entry structure that the key is in. If not, it will return 0. Entry* Find( KeyType p_key ) { int index = m_hash( p_key ) % m_size; DListIterator<Entry> itr = read more..

  • Page - 277

    233 Implementing a Hash Table int index = m_hash( p_key ) % m_size; DListIterator<Entry> itr = m_table[index].GetIterator(); while( itr.Valid() ) { if( itr.Item().m_key == p_key ) { m_table[index].Remove( itr ); m_count—; return true; } itr.Forth(); } return false; } Example 8-1: Using the Hash Table I’ve put together a simple text-based demo for you to read more..

  • Page - 278

    234 8. Hash Tables The Hash Function The first thing you need to do is create a hash function. For this simple demo, I used a very basic hash function that doesn’t modify the key at all: unsigned long int Hash( int k ) { return k; } So whatever key is passed into the hash function is returned unmodified. Creating the Hash Table Now you need to read more..

  • Page - 279

    235 Application: Using Hash Tables to Store Resources Removing Keys Removing a key is just like searching for one; the program asks you for a key and then tries to remove it: table.Remove( key ); Application: Using Hash Tables to Store Resources This is Game Demonstration 8-1, which can be found on the CD in the directory \demonstrations\ch08\Game01 - Resources\ . Compiling read more..

  • Page - 280

    236 8. Hash Tables The String Class I mentioned before that you cannot easily use strings as the keys with the HashTable class. This was because the built-in string type is char*, which is a pointer, and whenever you used the == operator on a pointer, it would compare the address of the strings and not the contents. The easiest way around this would be read more..

  • Page - 281

    237 Application: Using Hash Tables to Store Resources allows you to compare two strings using the == operator, and it will return true or false. For example: String str1( “hello!” ); String str2( “Hey!” ); if( str1 == str2 ) // strings are equal else // strings are unequal The demo uses a slightly modified StringHash algorithm, which I discussed earlier. The only read more..

  • Page - 282

    238 8. Hash Tables void Find() { String str( g_name ); HashEntry< String, SDL_Surface* >* entry; entry = g_table.Find( str ); if( entry != 0 ) g_resource = entry->m_data; else g_resource = 0; } The g_name variable is a char* that contains the string that is in the text box. The function creates a String and copies the contents of the text box string into read more..

  • Page - 283

    239 Conclusion When the demo starts out, there is a text box in the upper-left corner of the screen and nothing else. You type the name of a resource into the text box and press Enter, and the requested resource will be drawn on the screen. The valid resources for this demo are sky, water, water2, fire, snow, vortex, and stone. Conclusion I hope that you’ve gotten read more..

  • Page - 284

    This page intentionally left blank Team LRN read more..

  • Page - 285

    CHAPTER 9 Tying It Together: The Basics Team LRN read more..

  • Page - 286

    242 9. Tying It Together: The Basics Congratulations! You have just finished reading about all of the basic data struc- tures. Each of the previous chapters introduced you to a new data structure, showed you how it worked, and gave you an example of how it works in computer games. Most of the advanced chapters in this book make use of the structures from this part read more..

  • Page - 287

    243 Storing Data in a Class In programming, classes are nouns, and their functions are verbs. You can take the English sentence: The hero hits the monster! And turn that into code: Hero.Hit( Monster ); This is one aspect of object-oriented programming (OOP). In the past, game developers have typically avoided OOP because early implementations were slow and game developers read more..

  • Page - 288

    244 9. Tying It Together: The Basics Figure 9.1 This is how programmers used to store data globally. With this method, you stored each variable globally, and whenever you wanted to add a new monster or player, you would have to add new variables for each one and find a new name that was available. This isn’t very flexible. After global memory came arrays. Arrays read more..

  • Page - 289

    245 Storing Data in a Class Now you can reference each monster’s statistics by its number in the arrays. But this method also has problems; what happens when you want to add a new variable to the monsters and players? Then you have to find the array declarations and add a new array for each. Enter classes, as seen in Figure 9.3. Figure 9.3 Classes allow you to read more..

  • Page - 290

    246 9. Tying It Together: The Basics Now imagine a simple game where you gain points whenever your health increases and lose points whenever you lose health. While coding the game, you put this sequence of code in all over the place: player.m_health -= damage; player.m_score -= damage; In other places, you put this segment of code: player.m_health += bonus; player.m_score read more..

  • Page - 291

    247 Storing Data in a Class m_score += p_change; } }; The functions that read and write to hidden variables are called accessor func- tions because they access the data. “But that code is so much longer!” says the nay-sayer. Yes, that’s correct. But what would you rather do: spend an extra minute typing out accessor functions or spend an extra few hours tracing read more..

  • Page - 292

    248 9. Tying It Together: The Basics public: int GetHealth() { return m_health; } int GetScore() { return m_score; } int GetSpeed() { return m_speed; } void ChangeHealth( int p_change ) { m_health += p_change; m_score += p_change; m_speed = m_health / 10; } }; The three lines in bold show the differences in this class from the previous version. The speed will read more..

  • Page - 293

    249 Storing Data in a Class Figure 9.4 This is an incomplete inheritance tree of some common living things. Both the vertebrates and the invertebrates inherit from the living things category; that is, they share some of the same aspects. Fish and mammals inherit from the ver- tebrates category, and all fish and mammals share the vertebrate properties: They have backbones. It read more..

  • Page - 294

    250 9. Tying It Together: The Basics This is a game object Figure 9.5 inheritance tree. The Object Class So how does this actually help you program a game? Look at this simple class out- line for the Object class: class Object { public: virtual void Draw() { Draw( g_screen, blank, m_x, m_y ); }; int GetX() { return m_x; }; int GetY() { return m_y; }; int read more..

  • Page - 295

    251 Storing Data in a Class For example, within the game, you will declare an array of objects: Array<Object*> g_objects( OBJECTS ); After this, you will fill the array with objects, but don’t worry about that for now; I show you how in a bit. For now, just assume that the array is full of object pointers. NOTE For reasons that I explain in a bit, you are read more..

  • Page - 296

    252 9. Tying It Together: The Basics Here is how you redefine the Draw function to be pure virtual: virtual void Draw() = 0; The = 0 part is what makes it pure. This says, “This function is empty, but sub- classes will implement it for me.” However, there is one gotcha, which is either good or bad, depending on how you look at it. None of these lines of read more..

  • Page - 297

    253 Storing Data in a Class Memory Layout of a Computer Program,” if you are unfamiliar with how instruc- tion code is stored in a computer.) This is a wasteful approach. The actual code for the functions is never changed, so why should each instance of a class have its own code? Instead, the code is stored in one single place in memory, such as the last box read more..

  • Page - 298

    254 9. Tying It Together: The Basics If you pass by value an Object into a function that wants an Object, there is no prob- lem. This is because the entire Object is placed onto the stack (see Appendix B). However, what happens when you pass an Item into the function, instead of an Object? In that case, the entire Item is copied onto the stack as well, but read more..

  • Page - 299

    255 Storing Data in a Class Now, whenever you create an instance of the Object class, it has one virtual function entry, for the Draw function, and it points to the Object’s drawing code. Whenever you create an Item, it fills in the table entry with a pointer to the Item’s drawing code, as shown in Figure 9.9. Figure 9.9 Each instance of a class points to read more..

  • Page - 300

    256 9. Tying It Together: The Basics The Item Class Now you should think about what kinds of data you want to store in an item class. For demonstration purposes, the only new thing that the Item class will have is a graphic (using the SDL_Surface class—see Appendix C, “Introduction to SDL”). class Item : public Object { protected: SDL_Surface* m_graphic; public: read more..

  • Page - 301

    257 Storing Data in a Class Figure 9.10 shows the relationship between a base class, a publicly inherited class, and some other class or function accessing the other two classes. The child class can access all of the public and protected members of the base, but private mem- bers are hidden. Other classes and functions can access the public members of the child class, read more..

  • Page - 302

    258 9. Tying It Together: The Basics Figure 9.11 This figure shows how classes can access different class members using private inheritance. The child class can access the public and protected members of its parent, but the other unrelated class can only access the public members of the child. External classes do not know about the parent. In private inheritance, the child read more..

  • Page - 303

    259 Storing Data in a Class protected: int m_health; Item* m_inventory[16]; SDL_Surface* m_animation[16]; int m_currentframe; public: Person() { int i; for( i = 0; i < 16; i++ ) { m_animation[i] = 0; } m_currentframe = 0; } int GetHealth() { return m_health; }; void SetHealth( int p_health ) { m_health = p_health; }; Item* GetInventory( int p_index ) { read more..

  • Page - 304

    260 9. Tying It Together: The Basics is easy to set and get, using the two accessor functions near the top, but the inventory array is a little bit more diffi- cult to use. The inventory array is limited to 16 items and has two functions to retrieve or insert items at the various indexes. Keep in mind that this class is just a hypothetical class and not read more..

  • Page - 305

    261 Storing Data in a Class int i; for( i = 0; i < g_objects.Size(); i++ ) { if( g_objects[i] != 0 g_objects[i].Draw(); } This little function draws every single object in the game (if it exists), and it doesn’t care how it is drawn! The Item class and the Person class theoretically draw in two totally different ways, and your renderer doesn’t even care! This read more..

  • Page - 306

    262 9. Tying It Together: The Basics Category field, select C++ Language. Finally, click on the box that says Enable Run- Time Type Information (RTTI). Figure 9.12 Go to the Project menu, and then select the Settings option. Figure 9.13 These are the settings you need to have enabled to use RTTI. Team LRN read more..

  • Page - 307

    263 Storing Data in a Class Now your project is set up to use RTTI, which is what you need to use to tell your compiler that an Object is really a Person. Using RTTI Now, say that you know that the first item in the item array is a Person. This is the “correct” way to convert it into a Person class: Person* p = 0; p = dynamic_cast<Person*>( read more..

  • Page - 308

    264 9. Tying It Together: The Basics This is just the standard C typecasting method; the compiler will treat any object in that array as a Person after this line, even if it isn’t a person! Figure 9.14 shows the representation of the Item and the Person classes in memory. Figure 9.14 This is the memory representation of the two classes. Only the first two read more..

  • Page - 309

    265 Making a Game Person* p = (Person*)g_objects[0]; p.SetHealth( 100 ); This sets up an Item in the first index and then treats it as a Person and modifies the health of the Person. There is one problem: You’re trying to modify data that does- n’t exist! When you modify the health of this fake player, the function changes the data in the place in memory where read more..

  • Page - 310

    266 9. Tying It Together: The Basics The game demo is pretty complex, and it is the largest game demo in the book so far. All of the source code for this entire section is on the CD in the directory \demonstrations\ch09\Game01 - Adventure v1\ . Compiling the Game This game uses the SDLHelpers library that I have developed for the book. For more information about read more..

  • Page - 311

    267 Making a Game It usually helps to draw a diagram so you can visualize the relationship between the objects, like Figure 9.15 shows. Figure 9.15 This is a simple class relationship diagram. The arrows show which classes contain others. At the top of the chain is the map class, which will be the basis of the game. The map is made up of a bunch of cells, and read more..

  • Page - 312

    268 9. Tying It Together: The Basics Until now, the only tile arrangements you have seen in this book are 2D (and 3D) tilemaps (in Chapters 5, “Multi-Dimensional Arrays,” and 6, “Linked Lists”), so it would make sense that this is the kind of tilemap that the game will use. However, I want to show you an example of good data structure design, so when read more..

  • Page - 313

    269 Making a Game they are at in the map (this is thinking ahead; maybe someday you will implement a system where you keep track of an item and where it is on the map). If the item is a weapon, then you need two pieces of data about it: how long it takes between attacks and how much damage it does. Some weapons are lighter than others, so you will be read more..

  • Page - 314

    270 9. Tying It Together: The Basics class Map { protected: Person* m_viewer; public: Map() Person* GetViewer() void SetViewer( Person* p_viewer ) virtual void Draw( SDL_Surface* p_surface, int p_midx, int p_midy ) = 0; virtual bool CanMove( Person* p_person, int p_direction ) = 0; virtual void Move( Person* p_object, int p_direction ) = 0; virtual int GetCellNumber( int p_cell, read more..

  • Page - 315

    271 Making a Game Now, look at the interface of the map. Does it reveal anything about the actual implementation of the map? Does the setup say that you have to use a 2D array for the tilemap? It doesn’t, and that is the beauty of such a system; you can swap out many different kinds of maps and the game engine that uses this map interface will not need read more..

  • Page - 316

    272 9. Tying It Together: The Basics m_cell = 0; } int GetCell() { return m_cell; } void SetCell( int p_cell ) { m_cell = p_cell; } int GetX() { return m_x; } void SetX( int p_x ) { m_x = p_x; } int GetY() { return m_y; } void SetY( int p_y ) { m_y = p_y; } }; The benefit of having a class such as this is that it is easily expandable. Of read more..

  • Page - 317

    273 Making a Game There are functions to determine what type the item is (the game will have hard- coded item types—6 is an axe, for example), the speed and strength of the item (speed is ignored for armor types), the graphic of the item, whether it can block your path, and whether it is armor or not. The Person Interface Last, there is the person interface. You read more..

  • Page - 318

    274 9. Tying It Together: The Basics NOTE Note that the class is defined entirely in-line.That means that the function bodies are all in the .h file. For this listing, I have removed the function bodies, so that you can see all the functions of the class listed in one place easily. So the actual header file does not look like the code listing you see here. read more..

  • Page - 319

    275 Making a Game void SetGraphic( SDL_Surface* p_graphic, int p_direction, int p_frame ); SDL_Surface* GetGraphic(); void SetAttackTime( int p_time ); int GetAttackTime(); void SetMoveTime( int p_time ); int GetMoveTime(); void SetAttackModifier( int p_modifier ); int GetAttackModifier(); All of the previous functions are accessor functions. They are all pretty much self- read more..

  • Page - 320

    276 9. Tying It Together: The Basics Creating an Implementation for the Map Before you go any further, take a look at Figure 9.16. This figure shows an updated class diagram for the game. Figure 9.16 Here is the updated class diagram for the game. This is your game engine interface. The game logic module, which makes these things actually work, will (theoretically) read more..

  • Page - 321

    277 Making a Game This means that if you are moving north (direction 0), you add 0 to the x coordi- nate and -1 to the y coordinate. This is usually accomplished like this: x = x + DIRECTIONTABLE[direction][0]; y = y + DIRECTIONTABLE[direction][1]; The TileCell Class Back in Figure 9.15, there was a Cell class, but somehow while I was designing the overall design, the read more..

  • Page - 322

    278 9. Tying It Together: The Basics The TileMap Class Interface Now that you are focusing on an implementation rather than an interface, you need to start thinking about how you are going to store the data in the map. For the graphics, a 3D array will be used so that you can use some cool layered tilemapping effects. The cells in this array will store the read more..

  • Page - 323

    279 Making a Game int GetCell( int p_x, int p_y ); void LoadFromFile( char* p_filename ); }; There is the constructor, which takes three coordinates: the width, height, and depth of the tilemap. It also takes a pointer to an array of SDL_Surface pointers so the tilemap knows which tiles to draw. Then there is a destructor. This is important because the map keeps track read more..

  • Page - 324

    280 9. Tying It Together: The Basics ~TileMap() { int x, y; for( y = 0; y < m_tilemap.Width(); y++ ) { for( x = 0; x < m_tilemap.Height(); x++ ) { if( m_tilemap.Get( x, y ).m_item != 0 ) delete m_tilemap.Get( x, y ).m_item; if( m_tilemap.Get( x, y ).m_person != 0 ) delete m_tilemap.Get( x, y ).m_person; m_tilemap.Get( x, y ).m_item = 0; m_tilemap.Get( x, read more..

  • Page - 325

    281 Making a Game The file will actually store four layers, like Figure 9.17 shows. Figure 9.17 The map file format is stored as a four- layered 2D array. The first two layers should be familiar to you; they both serve the same functions as they did in the game demo from Chapter 5. The base layer stores all valid tiles, and the second layer stores overlay tiles, read more..

  • Page - 326

    282 9. Tying It Together: The Basics Array2D<int> items( 64, 64 ); Array2D<int> people( 64, 64 ); There are two integers to loop through each tile on the map and two integers that are used to load item and person indexes from the file. The last two variables are 2D arrays, which are only temporary for this function and will be deleted when the function read more..

  • Page - 327

    283 Making a Game person = people.Get( x, y ); if( person != -1 ) { m_tilemap.Get( x, y ).m_person = MakePerson( person, x, y, GetCell( x, y ) ); After it loads the Item, it looks to see if there is a Person in that cell as well. If so, then it calls the MakePerson helper function to create a new Person. However, this doesn’t end here—it goes on: read more..

  • Page - 328

    284 9. Tying It Together: The Basics located in the world. The ox and oy coordinates keep track of how many pixels things in the world space need to be moved over to get into screen space. Figure 9.18 shows an 800 600 screen that is currently viewing a 1024 1024 (-pixel) tilemap. Figure 9.18 This figure depicts the two different coordinate systems: world space read more..

  • Page - 329

    285 Making a Game These lines determine the bounds of the cells that are actually visible on the screen. For example, if the viewer was at (20,16), it would calculate minx to be 20 (400 / 64) 1, which ends up being 13. This means that any cells with an x coordinate less than 13 are not on the screen at all and therefore should not be drawn. The four lines read more..

  • Page - 330

    286 9. Tying It Together: The Basics Even though the figures show the screen moving, keep in mind that you are actually moving around the coordi- nates of the tiles. First, you subtract the number of pixels from the end of the map to the viewer tile, which places the viewer tile at the left side of the screen. Then, to center the viewer on the screen, half of read more..

  • Page - 331

    287 Making a Game variable and then compared to 1, which represents the empty tile. If the tile isn’t empty, then it is drawn on the screen. i = m_tilemap.Get( x, y ).m_item; p = m_tilemap.Get( x, y ).m_person; if( i != 0 ) SDLBlit( i->GetGraphic(), p_surface, px, py ); if( p != 0 ) SDLBlit( p->GetGraphic(), p_surface, px, py ); } } } Finally, the Item and the read more..

  • Page - 332

    288 9. Tying It Together: The Basics if( m_tilemap.Get( newx, newy ).m_item->CanBlock() == true ) return false; } Finally, check to see if an Item is blocking your way. return true; } If the function has reached this point, then you know that nothing is blocking the path into the cell, so it returns true. The Move Function This function physically moves a read more..

  • Page - 333

    289 Making a Game int GetCellNumber( int p_cell, int p_direction ) { int x, y; y = p_cell / m_tiles.Width(); x = p_cell - (y * m_tiles.Width()); x = x + DIRECTIONTABLE[p_direction][0]; y = y + DIRECTIONTABLE[p_direction][1]; The first two lines calculate the x and y coordinates of the current cell number by reversing the algorithm that turns a 2D array coordinate into a read more..

  • Page - 334

    290 9. Tying It Together: The Basics direction = 3; return direction; } This checks the relative x and y coordinates of the two players. If the first player has a greater y value than the second, this means that the first player is to the south and therefore must move north to get closer. The next three blocks follow in the same manner, figuring out which read more..

  • Page - 335

    291 Making a Game { for( f = 0; f < FRAMES; f++ ) { m_graphics[d][f] = 0; } } This loop goes through the graphics array and clears all the graphics. m_lastmove = 0; m_lastattack = 0; m_attackmodifier = 0; } Last, the function clears the timers to 0 and sets the attack modifier to 0 as well. The Destructor The destructor of a Person is very read more..

  • Page - 336

    292 9. Tying It Together: The Basics *this = p_person; } void operator= ( Person& p_person ) { int d, f; m_health = p_person.m_health; m_armor = p_person.m_armor; m_type = p_person.m_type; m_direction = p_person.m_direction; for( d = 0; d < DIRECTIONS; d++ ) { for( f = 0; f < FRAMES; f++ ) { m_graphics[d][f] = p_person.m_graphics[d][f]; } } m_lastattack = read more..

  • Page - 337

    293 Making a Game void SetDirection( int p_direction ) { m_direction = (p_direction + 4) % 4; } First, it adds 4 to the new direction, and then it modulos that by 4. The reason this is done is so that you can do easy turns in the game. For example, if you want the Person to turn left, you just subtract 1 from the direction. Instead of requiring all the read more..

  • Page - 338

    294 9. Tying It Together: The Basics The AddItem Function This function adds an item to the inventory of the player. void AddItem( Item* p_item ) { m_inventory.Append( p_item ); if( m_currentweapon.Valid() == false ) { m_currentweapon.Start(); } } The item is first appended to the end of the inventory list. After that, the function checks to see if the current weapon read more..

  • Page - 339

    295 Making a Game if( m_currentweapon.Valid() ) return m_currentweapon.Item(); return 0; } The function makes sure that the iterator is valid first, and then it returns the item. If the iterator wasn’t valid, then 0 is returned, meaning that the player doesn’t have a current weapon. The GetAttackTime Function When the game wants to know when the last time the player has read more..

  • Page - 340

    296 9. Tying It Together: The Basics This is also a good point to add death detection. If you killed the Person, then you might want something to happen to the current Person, such as gaining experience points. The GetGraphic Function This function retrieves the current graphic of the player, based on the time and the direction he is facing. SDL_Surface* GetGraphic() { read more..

  • Page - 341

    297 Making a Game then the amount of damage done to you is reduced by 80 percent. Then the armor is degraded by the amount of damage. The IsDead Function A person is dead if he has no health: bool IsDead() { return (m_health == 0); } The PickUp Function This is the function that is called whenever a person picks up an item from the map. void PickUp( Item* read more..

  • Page - 342

    298 9. Tying It Together: The Basics Figure 9.20 shows how this is accomplished. Figure 9.20 This shows how the MakePerson function works. It copies a Person out of the template array and returns the new Person. There is an array filled with three Persons, and whenever you ask for a Person of type x, it looks up the Person at index x in the array, copies that read more..

  • Page - 343

    299 Making a Game The MakePerson function is very similar, with one major difference: Person g_persontemplates[16]; Person* MakePerson( int p_type, int p_x, int p_y, int p_cell ) { Person* p = new Person; *p = g_persontemplates[p_type]; p->SetX( p_x ); p->SetY( p_y ); p->SetCell( p_cell ); p->AddItem( MakeItem( 8, 0, 0, 0 ) ); return p; } This function creates a Person, read more..

  • Page - 344

    300 9. Tying It Together: The Basics SDL_Surface* g_people[PEOPLE][DIRECTIONS][FRAMES]; SDL_Surface* g_statusbar; SDL_Surface* g_verticalbar; SDL_Surface* g_youlose; These store the tile graphics, the item graphics, the people graphics, the status bar, another vertical status bar, and the graphic that is displayed when you die. How boring. Map* g_currentmap = 0; Person* g_currentplayer read more..

  • Page - 345

    301 Making a Game } for( x = 0; x < 6; x++ ) { g_itemtemplates[x].SetBlock( true ); } g_itemtemplates[6].SetSpeed( 1500 ); g_itemtemplates[6].SetStrength( 15 ); // ... lots of weapon loading ... g_itemtemplates[12].SetStrength( 30 ); g_itemtemplates[12].SetArmor( true ); // ... more armor loading ... First, the function goes through each item in the template and read more..

  • Page - 346

    302 9. Tying It Together: The Basics The templates for people 1 and 2 are modified, but not person 0. Persons 1 and 2 are made to be much weaker than you are, and slower as well. SetNewMap( “default.map” ); Finally, the map is loaded using the default.map file. This function will be shown later on. The LoadMap Function This function will take a filename, load read more..

  • Page - 347

    303 Making a Game Map* newmap; newmap = LoadMap( p_filename ); The new map is loaded using the LoadMap function. g_peoplecount = 0; for( x = 0; x < newmap->GetNumberOfCells(); x++ ) { if( newmap->GetPerson( x ) != 0 ) { AddPersonToArray( newmap->GetPerson( x ) ); } } Now, the g_peoplecount variable is reset to 0, which means that the global people array read more..

  • Page - 348

    304 9. Tying It Together: The Basics Now on to the more interesting functions! The Artificial Intelligence Artificial Intelligence (AI) hasn’t been dis- cussed at all in this book up until this point. Some of the later chapters (Chapters 15, “Game Trees and Minimax Trees,” and 18, “Using Graphs for AI: Finite State Machines,” specifi- cally) have a lot to do with read more..

  • Page - 349

    305 Making a Game direction = g_currentmap->GetClosestDirection( g_peoplearray[i], g_currentplayer ); This code segment determines which direction the AI needs to move to get closer to the player. dist = Distance( g_peoplearray[i], g_currentplayer ); Then the function calculates the distance from the AI to the player. if( dist > 1.0f && dist <= 6.0f && p_time - read more..

  • Page - 350

    306 9. Tying It Together: The Basics int cell; Item* weapon; Person* person; The person that is passed in is the person that is attacking. The function will deter- mine what he is attacking later. time = SDL_GetTicks(); difference = time - p_person->GetAttackTime(); weapon = p_person->GetCurrentWeapon(); The current time and the amount of time since the person read more..

  • Page - 351

    307 Making a Game { p_person->PickUp( i ); g_currentmap->SetItem( p_person->GetCell(), 0 ); } } The function gets a pointer to the item in the cell that the person is in, and if an item exists, then the person picks it up, and the pointer in the cell is cleared. The CheckForDeadPeople Function Finally, this is the last independent function in the game logic. This read more..

  • Page - 352

    308 9. Tying It Together: The Basics If the dead person isn’t the current player, then an AI was killed. The function saves a pointer to the dead person and then uses the fast remove algorithm from Chapter 3, “Arrays,” to move the last person down into the index of the dead per- son. The function then sets the person pointer in the cell he was in to zero and read more..

  • Page - 353

    309 Making a Game if( direction != -1 ) { g_currentplayer->SetDirection( direction ); g_currentmap->Move( g_currentplayer, direction ); } This checks to see if the user wants to move, so it sets the direction of the player and then moves him in the right direction. if( g_dead == false ) { PerformAI( SDL_GetTicks() ); CheckForDeadPeople(); if( g_cheat == true ) read more..

  • Page - 354

    310 9. Tying It Together: The Basics There are a few commands in this game. First, to move around, you must use the four arrow keys on your keyboard. Whenever you are on top of an item, you can press the Enter key to pick it up. When you are facing an enemy and want to attack him, press the spacebar. Your attack meter on the right of the screen will read more..

  • Page - 355

    311 Making a Game The map editor is Game Demonstration 9-2, which is on the CD in the directory \demonstrations\ch09\Game02 - Map Editor\. Because the map editor’s primary purpose is to load, edit, and store maps, I focus primarily on these areas. The edi- tor has some extra graphics features (such as the mini-map and current-tile high- lighting), but those are included read more..

  • Page - 356

    312 9. Tying It Together: The Basics The Tile Drawing As I have said before, whenever the mouse is moved around, a tile is drawn on the map: SDL_GetMouseState( &x, &y ); x = x / 8; y = y / 8; if( x < g_map.Width() && y < g_map.Height() && g_mousedown == true ) { g_map.Get( x, y, g_currentlayer ) = g_currenttile; } The mouse coordinates read more..

  • Page - 357

    313 Making a Game Loading the Map Loading the map is just as easy as saving the map. void Load() { FILE* f = fopen( g_filename, “rb” ); if( f == 0 ) return; fread( g_map.m_array, g_map.Depth() * g_map.Height() * g_map.Width(), sizeof(int), f ); fclose( f ); } The file is opened and then read into the array so that you can edit it. Using the Editor The read more..

  • Page - 358

    314 9. Tying It Together: The Basics Below the map is the palette of tiles. Only eight tiles can be displayed at a time, so the tiles you can draw are arranged in groups. You can select which group of tiles you want to draw from by using the buttons on the right-hand side of the map. After you select the group you want to draw from, a new palette appears read more..

  • Page - 359

    Recursion PART THREE and Trees Team LRN read more..

  • Page - 360

    10 Recursion 11 Trees 12 Binary Trees 13 Binary Search Trees 14 Priority Queues and Heaps 15 Game Trees and Minimax Trees 16 Tying It Together: Trees Team LRN read more..

  • Page - 361

    CHAPTER 10 Recursion Team LRN read more..

  • Page - 362

    318 10. Recursion Up until now, you’ve only learned about the simple linear data structures. While they are the most common structures out there, they can be limiting sometimes. With this part of the book, I introduce you to some new concepts in data structures: recursive data structures. I have no doubt that the mention of that word has caused some of you to cringe read more..

  • Page - 363

    319 What Is Recursion? examples can be solved easier, faster, and more cleanly using iteration. Iteration is just a fancy way of describing a for-loop. So what kinds of problems are better solved using recursion? As you’ll see in Chapter 20, “Sorting Data,” the fastest sorting algorithm known to us is recursive. You’ll also see countless examples throughout Part III of read more..

  • Page - 364

    320 10. Recursion return 1; } This version of the function isn’t really functional at this point; it only works with a power of 0. Now you want to look at the function and see how it can be represented in terms of itself. Look at the second row in Table 10.1, and see if you can come up with a rela- tion with the first row. If you think about the read more..

  • Page - 365

    321 The Towers of Hanoi pillars are assigned the numbers 1, 2, and 3, and the discs are assigned the letters a, b, and c. Figure 10.1 This is a simple Towers of Hanoi setup with three discs on the first pole. The Rules The goal is to move the discs around so that the tower on Pillar 1 is moved to Pillar 3. There are two rules: ■ A larger disc can read more..

  • Page - 366

    322 10. Recursion Figure 10.2 This figure shows steps 1, 2, and 3. Now take a look at Figure 10.3, which shows Step 4. step 4. Figure 10.3 This figure shows Finally, take a look at Figure 10.4, which shows the last three steps: 5, 6, and 7. Figure 10.4 This figure shows steps 5, 6, and 7. Team LRN read more..

  • Page - 367

    323 The Towers of Hanoi Well, that wasn’t so difficult, was it? What happens when you add a fourth disc to the puzzle, though? Four discs require 15 moves to solve, and it’s more difficult if you don’t know the trick to solving it. Now that you know how the basic puzzle works, though, you can move on to trying to solve it with an algorithm. Solving the read more..

  • Page - 368

    324 10. Recursion Well, that’s easy to say, but the rules say you can only move one disc at a time, right? You can think of moving the top n-1 discs to Pillar 2 as the same problem, just with one less disc! 1. Move the top n-2 discs to Pillar 3. 2. Move the n-1 disk to Pillar 2. 3. Move the n-2 discs from Pillar 3 to 2. Wait a moment for that to read more..

  • Page - 369

    325 The Towers of Hanoi The algorithm recursively moves the top n-1 discs from the starting pillar onto the open pillar, moves the bottom disc from the starting pillar onto the destination pillar, and then moves the top n-1 discs from the open pillar onto the destination pillar. Terminating Conditions The algorithm is missing one thing, though: It doesn’t end. This read more..

  • Page - 370

    326 10. Recursion Instead of actually storing the discs in a data structure somewhere and moving them around, this algorithm just prints out the moves that are made. Here is how you would call the function: Hanoi( 3, 1, 3, 2 ); This says: Move four discs from Pillar 1 onto Pillar 3, where Pillar 2 is empty. Example 10-1 asks you to enter the number of discs you read more..

  • Page - 371

    327 Graphical Demonstration: Towers of Hanoi Graphical Demonstration: Towers of Hanoi Just for fun, I’ve included a little graphical demonstration of the Towers of Hanoi. If you’re interested, it can be found on the CD in the directory \demonstrations\ch10\demo01 - towers of hanoi\ . Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the read more..

  • Page - 372

    328 10. Recursion Table 10.2 shows the commands in the demo. Button Function Reset Table 10.2 Towers of Hanoi Commands This resets the game and moves all the discs back to Pillar 1. Set Delay This sets the number of milliseconds that will pass between disc movements. Solve This causes the demo to solve the puzzle for you. The demo can solve any number of discs read more..

  • Page - 373

    CHAPTER 11 Trees Team LRN read more..

  • Page - 374

    330 11. Trees By now, you should have a solid understanding of the basic data structures, especially linked lists. You should also be fairly comfortable with the concept of recursion. If you’re not entirely confident of these two areas, go back and read Chapter 6, “Linked Lists,” and Chapter 10, “Recursion,” because much of what I show you in this chapter builds upon the read more..

  • Page - 375

    331 What Is a Tree? The tree has several major components. The largest is the trunk, or root, at the bot- tom. Branches come off of the trunk, and they spread out into twigs, which have leaves. The general structure of the tree spreads out from the root. If you think about it, a branch is really nothing but a smaller root, right? So a twig is nothing but a read more..

  • Page - 376

    332 11. Trees Now that you know the terminology of a tree, I can go into a little more detail. A tree, like a linked list, is a node-based structure. The nodes point to the next node in the structure. However, a linked list points to only one node, whereas a tree node can point to any number of children. one child. NOTE You can think of a linked list as a read more..

  • Page - 377

    333 Graphical Demonstration: Trees So what data structure that you know of can easily be expanded to hold any num- ber of items? That’s right, linked lists! So each node will have a linked list where each node in the list points to another tree node. Whew, what a mouthful! Figure 11.4 can better illustrate what is going on in a tree node. Figure 11.4 This is the read more..

  • Page - 378

    334 11. Trees Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B, “The Memory Layout of a Computer Program.” To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix B. If you read more..

  • Page - 379

    335 Graphical Demonstration: Trees One thing that you won’t see in the screenshot is that two of the nodes are colored differently. If you start up the demo, the root node will be colored red (node 29 in Figure 11.5), and the root’s first child will be colored blue (node 1 in Figure 11.5). When you iterate through a tree, you really need two iterators. If you read more..

  • Page - 380

    336 11. Trees There are a lot of commands, and it’s okay if you don’t understand how they work just yet. I’m going to take you through a little tutorial with the demo. TIP If you want to see a cool application of recursion when dealing with trees, take a look at the source code for this demo.The DrawSubTree algorithm is recursive, and it is very simple, read more..

  • Page - 381

    337 Graphical Demonstration: Trees Step 2: Traverse the Tree Now that you have built a basic tree, I want you to traverse the tree by using the buttons on the right side of the screen. 1. Click Child Start. 2. Click Forth. 3. Click Back. 4. Click Child End. 5. Click Back. 6. Click Down. Your red node should now be the middle node on the second level of the read more..

  • Page - 382

    338 11. Step 3. Trees Figure 11.7 This is the tree after Step 4: Play Around Now that you’ve created a neat-looking tree, I want you to play around with the commands—see what you can come up with. The program doesn’t have any lim- its on the number of nodes you can add, but adding too many might make the program run slowly. I want you to get acquainted read more..

  • Page - 383

    339 Building the Tree Class build the tree so that it was nicely contained within a single class and easy to work with, like all of the classes I’ve used previously in the book. This method ended up being more work than it was worth, and it was more complicated to use! So I decided to use an ultra-simplistic approach and create just the node class with very read more..

  • Page - 384

    340 11. Trees The Constructor Here is the code for the constructor: Tree() { m_parent = 0; } I want you to pay attention to the fact that the parent is cleared to 0. Whenever I deal with tree nodes, the node is considered a root node if the parent pointer is 0. Also, note the other cool thing: Because the DLinkedList class already has a con- structor, the read more..

  • Page - 385

    341 Building the Tree Class types, such as the binary search tree (see Chapter 13, “Binary Search Trees”) and heaps (see Chapter 14, “Priority Queues and Heaps”). However, most of the time, you will find that the children of any given node are directly related to its parent. If you remove the parent node, you should also remove the children nodes as well as all read more..

  • Page - 386

    342 11. Trees Look back to Figure 11.8. If you were to delete node b from that tree, this function would first loop through and remove c and d from its child list and then delete c and d. But the act of deleting c and d calls their destructors, which in turn calls Destroy again! If those nodes had any children, they would be deleted, too! This function is read more..

  • Page - 387

    343 The Tree Iterator The Structure The TreeIterator structure is simple; it only has two variables: template<class DataType> class TreeIterator { public: Node* m_node; DListIterator<Node*> m_childitr; }; The first variable is a pointer to the current node, and the second is a DListIterator, which points to the current child in the current node. If you don’t understand read more..

  • Page - 388

    344 11. Trees Say you have a tree node that you want to get an iterator for, like this: Tree<int>* node = new Tree<int>; This node is just a plain integer tree node with no children and no parents. It does- n’t really matter, though; this same method works with any tree node pointer. Now you want to get an iterator to that node, which you can do in one read more..

  • Page - 389

    345 The Tree Iterator void ResetIterator() { if( m_node != 0 ) { m_childitr = m_node->m_children.GetIterator(); } else { m_childitr.m_list = 0; m_childitr.m_node = 0; } } The first part checks to see whether the node is 0. If not, then it resets m_childitr to point to the child list of m_node. If the node is 0, then it is invalid, so you need to make the read more..

  • Page - 390

    346 11. Trees void Up() { if( m_node != 0 ) { m_node = m_node->m_parent; } ResetIterator(); } This function makes sure that the node is valid before it does anything. If so, then it moves the iterator up to the previous node. The Down Function This function is the opposite of Up; it moves the iterator downward to the current child iterator. However, if the read more..

  • Page - 391

    347 Traversing a Tree The functions are AppendChild, PrependChild, InsertChildBefore, InsertChildAfter, RemoveChild, ChildValid, and ChildItem. Notice something about all of these? These functions all correspond to functions within the linked list classes! Because all of these functions directly call linked list iterator functions, there is no need for me to paste them here, either. read more..

  • Page - 392

    348 11. Trees The Preorder Traversal The first method I show you is the preorder traversal. You’ll see why it is called so when you look at the pseudo-code: Preorder( node ) Process( node ) For each child Preorder( child ) end For end Preorder This algorithm accepts a node as a parameter and uses a function named Process. You shouldn’t care what Process does; read more..

  • Page - 393

    349 Traversing a Tree The order in which the nodes are processed is shown in Figure 11.10. Figure 11.10 This is the order in which nodes are processed with Preorder. In a preorder traversal, each subtree is processed before the next subtree is processed. You can see why it is called a preorder search from the algorithm; the current node is processed before the read more..

  • Page - 394

    350 11. Trees On line 4, the p_process function pointer is called on the node. On line 5, an iterator to the child list of the node is retrieved, and the function uses this iterator to loop through each child node and call Preorder on them in lines 6 and 7. Using the Function Pointer Say you have a tree of integers already built, and its name is g_tree. Now, read more..

  • Page - 395

    351 Traversing a Tree If you were to postorder traverse the tree from Figure 11.9, the nodes would be processed in the order shown in Figure 11.11. Figure 11.11 This is the order in which the nodes are processed using the postorder traversal. This time, Postorder is called on the first child of the root, then the first child of that node, so that the first node to read more..

  • Page - 396

    352 11. Trees This demonstration is very simple; it only has three buttons, as shown in Figure 11.12. Figure 11.12 Here is a screenshot from Graphical Demonstration 11-2. The Random Tree button generates a new random tree, as in the previous demo. The other two buttons, Preorder and Postorder, make the demo go into an anima- tion. The demo highlights the nodes using the read more..

  • Page - 397

    353 Game Demo 11-1: Plotlines For years and years, games have been linear with their stories and plots. What does this mean? You start the game and you play around, progressing from level to level, until you beat the game. Figure 11.13 shows how the levels progress throughout the game. Notice that it is a straight line, which is where the term linear comes from. read more..

  • Page - 398

    354 11. Trees Figure 11.14 This is a branching level progression.You can choose which path to take at level 2. Now, whenever you play through the game, you can go with branch a the first time and branch b the second time! It turns out that trees are the ideal structure to store game data like this. You can see how the level progression from Figure 11.14 looks read more..

  • Page - 399

    355 Game Demo 11-1: Plotlines Figure 11.15 Here is the branching plotline for the demo. Declaring the Tree The premise of the demo is simple; when a level is completed, the player has a choice of which level to go to next. This information is stored in a tree: Tree<int>* g_tree; TreeIterator<int> g_itr; The g_tree pointer will always point to the root of the read more..

  • Page - 400

    356 11. Trees node = new Tree<int>; node->m_data = 1; itr.AppendChild( node ); This code shows the addition of level 2a to the tree. The other seven levels of the tree are added in the same fashion; the iterator is moved around and child nodes are appended to the tree to give you the tree in Figure 11.15. Changing Levels Whenever the player “wins” a level in read more..

  • Page - 401

    357 Game Demo 11-1: Plotlines Figure 11.16 This is a screenshot of Level 0. After you have successfully moved your little dude across the screen to the right, the level selection screen appears, as shown in Figure 11.17. Figure 11.17 This is the level selection screen. Team LRN read more..

  • Page - 402

    358 11. Trees You use the mouse to click on one of the tiles to select the next level. That’s pretty much all there is to the demo. Conclusion One thing you should realize about trees is that they are complex structures. They are obviously not suitable for storing any types of data, like arrays and linked lists are, so that makes trees a more specialized read more..

  • Page - 403

    CHAPTER 12 Binary Trees Team LRN read more..

  • Page - 404

    360 12. Binary Trees In the previous chapter, you learned about general trees, which are trees that can have any number of branches per node. Now I’m going to show you the most popular variant of the tree structure: the binary tree. In this chapter, you will learn ■ What a binary tree is ■ Some common traits of binary trees ■ Two common implementations of read more..

  • Page - 405

    361 What Is a Binary Tree? As you can see, there really isn’t much to learn about plain binary trees because they are the simplest of all tree structures. A binary tree can have several traits that general trees cannot have, though. Fullness A binary tree can be full. Because each node can have a maximum of two child nodes, you can fill up a tree so that you read more..

  • Page - 406

    362 12. Binary Trees Figure 12.3 Here is a dense binary tree. Every level is full, except the last level, where the nodes are all packed to the left of the tree. Denseness is an important trait with some variants of binary trees, as you’ll see later on in this chapter and when I teach you about heaps in Chapter 14, “Priority Queues and Heaps.” Balance Even read more..

  • Page - 407

    363 Structure of Binary Trees tree node has two fixed pointers. The fixed pointers either point to the left or right child nodes or contain 0 if the node doesn’t have a child. The structure for these kinds of nodes is shown in Figure 12.4 Figure 12.4 This is a linked binary tree node. The three boxes with arrows coming out of them are all pointers that point read more..

  • Page - 408

    364 12. Binary Trees Figure 12.5 This is a full binary tree where the nodes have been turned into array cells. Pay particular attention to the order in which I numbered the cells. The root starts at index 1 and the numbering goes from left to right all the way down to the last node on the right, 15. Now, imagine if you concatenated all of the cells into an read more..

  • Page - 409

    365 Structure of Binary Trees 2 The total number of cells in a binary tree of a particular depth follows this formula: cells for depth n = 2 n-1. For example, in the four-level tree in Figure 12.5, there are 4 – 1 nodes, or 15. A binary tree with five levels requires 31 nodes. Traversing Arrayed Binary Trees You don’t need iterators to traverse arrayed binary read more..

  • Page - 410

    366 12. Binary Trees Figure 12.7 Here is another binary tree, where a lot of space is wasted. The tree in Figure 12.7 is the same as the tree in Figure 12.5, but the entire subtree starting with index 3 has been removed. Imagine how this tree looks when stored into an array, though. Figure 12.8 shows this. Figure 12.8 This is the tree from Figure 12.7 stored in read more..

  • Page - 411

    367 Graphical Demonstration: Binary Trees Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B, “The Memory Layout of a Computer Program.” To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described read more..

  • Page - 412

    368 12. Command Action none Go Left Go Right Randomize Goto Root Go Up Binary Trees Table 12.1 Binary Tree Demonstration Commands Insert Left Inserts a new node to the left of the current node if there is none Insert Right Inserts a new node to the right of the current node if there is Moves the current node to the left child node Moves the current node to read more..

  • Page - 413

    369 Coding a Binary Tree public: DataType m_data; Node* m_parent; Node* m_left; Node* m_right; }; They are the data, a pointer to the parent, and a pointer to the left and right children. The Constructor The constructor exists to clear the pointers so that they aren’t filled with garbage data when a node is created. BinaryTree() { m_parent = 0; m_left = 0; m_right = read more..

  • Page - 414

    370 12. Binary Trees The Count Function The Count function is only slightly modified from the Tree version; instead of loop- ing through the child list, it calls the Count function on each child of the node. int Count() { int c = 1; if( m_left ) c += m_left->Count(); if( m_right ) c += m_right->Count(); return c; } Note that it checks to see if each child read more..

  • Page - 415

    371 Traversing the Binary Tree Now, the iterator is put to work to create the nodes lower down in the tree: itr = root; itr = itr->m_left; itr->m_left = new BinaryTree<int>; itr->m_left->m_data = 4; itr->m_left->m_parent = itr; itr->m_right = new BinaryTree<int>; itr->m_right->m_data = 5; itr->m_right->m_parent = itr; The iterator is first pointed at the read more..

  • Page - 416

    372 12. Binary Trees The Preorder Traversal The preorder traversal for a binary tree is simple, and it is almost identical to the algorithm used for general trees: Preorder( node ) process( node ) Preorder( node.left ) Preorder( node.right ) End Preorder It is important to note that the left node is processed before the right node; that is the general convention used read more..

  • Page - 417

    373 Traversing the Binary Tree Figure 12.10 This is the order of nodes processed using the inorder traversal. Graphical Demonstration: Binary Tree Traversals This is Graphical Demonstration 12-2, which is located on the CD in the directory \demonstrations\ch12\Demo02 - Binary Tree Traversals\ . Compiling the Demo This demonstration uses the SDLGUI library that I have developed for read more..

  • Page - 418

    374 12. Binary Trees Figure 12.11 Here is a screenshot from the traversal demo. As before, the nodes will be highlighted for 700 milliseconds while they are being processed to show you the order in which they are visited by the algorithms. Application: Parsing This next topic, although it’s a little advanced, is a really neat application of binary trees. The code for read more..

  • Page - 419

    375 Application: Parsing Parsing is the act of breaking up a sentence into easy-to-understand segments. For example, when you read a sentence, your mind mentally parses it into a form that makes sense to you. Take the following sentence, for example: “Bob runs up the hill.” Your mind recog- nizes that sentence, and it has parsed it into several segments. I don’t want read more..

  • Page - 420

    376 12. Binary Trees A scripting system essentially allows you to make very customizable maps for a game. I’m sure you’ve played some of the Quake modules (mods) before. One of my favorites is Team Fortress Classic (TFC ). These mods allow you to drastically change the way the game operates, expanding upon the original game’s capabilities. One of the reasons games read more..

  • Page - 421

    377 Application: Parsing Well, now you’ve got a tree; what do you do with it? You can perform a postorder traversal on the tree to calculate its value! For example, you start at the root node and tell it to return the value of the left node first. The left node just returns 2. Then, you tell the right node to return its value. Because the right node is read more..

  • Page - 422

    378 12. Binary Trees int m_variable; int m_operator; }; This class has a type variable that deter- mines which of the following three vari- ables is valid. If the type of the token is NUMBER, then m_number will hold the number. If the type of the token is VARIABLE, then m_variable will hold the number of the variable (you’ll see how this works in a bit). If the read more..

  • Page - 423

    379 Application: Parsing 4. If the character is a number, read in the rest of the number and create a number token. 5. Place the token into a queue. 6. Repeat. You can find the code in the g12-01.cpp file on the CD if you’re really interested (the Scan function); I have decided not to include it here because it doesn’t have anything to do with trees. The read more..

  • Page - 424

    380 12. Binary Trees Queue.Dequeue else if Queue.First == VARIABLE or NUMBER left = VARIABLE or NUMBER Queue.Dequeue There are three valid token types for the first token of the queue. If the first token is a left parenthesis, then the parenthesis is taken off the queue and the rest of the queue is passed into the parse algorithm again. The result of the read more..

  • Page - 425

    381 Application: Parsing Now that you’ve gotten to this point, there is only one more token to process for the term. Like the first token, the only valid types it can be are variables, numbers, or left parentheses: if Queue.First == LPAREN Queue.Dequeue right = Parse( Queue ) Queue.Dequeue else if Queue.First == VARIABLE or NUMBER right = VARIABLE or NUMBER read more..

  • Page - 426

    382 12. Binary Trees This time, the second parse algorithm strips off the 5 and makes the left node a constant number node. It strips off the star and turns the center node into a multi- plication operator node. Finally, it strips off the c and turns the right node into a constant node. The second parse algorithm then returns the center node up to the first parse read more..

  • Page - 427

    383 Application: Parsing p_queue.Dequeue(); left = ParseArithmetic( p_queue ); // if( p_queue.Front().m_type != RPAREN ) // this is where you would throw an error; // the string is unparsable with our language. p_queue.Dequeue(); break; case VARIABLE: case NUMBER: left = new BinaryTree<Token>; left->m_data = p_queue.Front(); p_queue.Dequeue(); break; // case OPERATOR: // this is read more..

  • Page - 428

    384 12. Binary Trees case VARIABLE: case NUMBER: right = new BinaryTree<Token>; right->m_data = p_queue.Front(); p_queue.Dequeue(); break; // case OPERATOR: // this is where you would throw an error; // the string is unparsable with our language. } center->m_left = left; center->m_right = right; return center; } You can probably see why I didn’t just paste the code read more..

  • Page - 429

    385 Application: Parsing Now, the algorithm uses a switch statement to determine which of the three node types it is: switch( p_tree->m_data.m_type ) { case VARIABLE: return g_vars[p_tree->m_data.m_variable]; break; The first node type is a variable. Because the demo has four valid variables, all four variables are stored in an array, g_vars. The m_variable member of read more..

  • Page - 430

    386 12. Binary Trees return 0.0f; } Last, in case something messed up, 0 is returned at the end. Hopefully nothing did, but it is always safe to do so anyway. Playing the Demo This is the most complex demo in the book so far, so it needs a fair amount of explanation. Figure 12.15 shows a screenshot from the demo in action. Figure 12.15 Here is a screenshot read more..

  • Page - 431

    387 Application: Parsing screen now. The x tree is on the left and the y tree is on the right. This way, you can visually see how your expression was parsed by the system. Next, you want to set up your life variable. You can click on the L box and enter a life value. You cannot modify the T value, though. The Execute button is a toggle that resets the time read more..

  • Page - 432

    388 12. Binary Trees I made these formulas after playing around for a minute; I’m sure you can come up with some even neater ones. For example, you could make the speed of the space- ship depend on the amount of health you have left. The possibilities are endless. Conclusion This chapter turned out to be a lot longer than I expected, mainly due to the extensive read more..

  • Page - 433

    CHAPTER 13 Binary Search Trees Team LRN read more..

  • Page - 434

    390 13. Binary Search Trees Previously, you learned about recursion, general trees, and binary trees. This chapter deals with a variant of the binary tree called a Binary Search Tree (BST). The BST is a structure where recursion is more important in determining how the data is stored rather than how the data is accessed. You’ll see what I mean by this later in the read more..

  • Page - 435

    391 What Is a BST? people in the line of people waiting to be sorted; the computer can’t do that. The computer would need to look at every person in line to find out who is the shortest. Instead, why don’t you do something clever? Pick a midpoint (say, 5 feet, 6 inches) and look at the first person in line. If he/she is below that height, you move him/her read more..

  • Page - 436

    392 13. Binary Search Trees For example, say you have a queue containing this data: 4, 2, 6, 5, 1, 3, 7. The first step is to take off the 4 and insert it as the root node in a BST. Then you take off the 2 and compare it with the 4. Because 2 is less than 4, you insert 2 as the left child of the root. Then you take off 6, which is placed as read more..

  • Page - 437

    393 What Is a BST? the 6. Likewise, the 1 is compared to the 4 and then the 2 and then inserted as the left child of the 2. Figure 13.4 shows these two steps. Figure 13.4 This is how you insert the next two nodes. See if you can figure out where the 3 and the 7 go. Figure 13.5 shows where they are inserted if you’re stumped. Figure 13.5 Finally, this read more..

  • Page - 438

    394 13. Binary Search Trees So, now that you have the final BST in Figure 13.5, see if you can figure out why I’ve partitioned the data like this. Finding Data in a BST Now that the data has been inserted into the tree, how do you search for the data quickly? By using the same algorithm, of course! If you want to search for 3, you compare it with 4, read more..

  • Page - 439

    395 Graphical Demonstration: BSTs Sub-Optimal Trees I admit it: The first BST example I gave you was doctored. I fixed the data so that the tree ends up being full. However, data is usually not organized like that, and it usually produces BSTs that are not optimal. First, let me show you the absolute worst case for inserting data into a BST. Say you have a queue read more..

  • Page - 440

    396 13. Binary Search Trees Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B, “The Memory Layout of a Computer Program.” To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in read more..

  • Page - 441

    397 Coding a BST Clicking either button makes the demo follow a path down the tree, either trying to insert a node or just finding a node. Play around with it and get to know how BSTs work a little better. Coding a BST The code for the Binary Search Tree is located on the CD in the file \structures\BinarySearchTree.h. The Structure The binary search tree uses a read more..

  • Page - 442

    398 13. Binary Search Trees want to search based on another attribute—perhaps how strong the character is. By using a comparison function, this change is easy; you can make a new function that compares the strength of two characters instead of the health. The definition of the comparison function is simple: It takes two parameters of type DataType and returns an integer. read more..

  • Page - 443

    399 Coding a BST The Insert Function Now comes the Insert function. There are two ways you can insert the node into the binary tree; one is recursive, and the other is iterative. The recursive function in this case is pointless because this isn’t really a recursive algorithm. So instead of recursion, I use the iterative algorithm. I split this up into a few segments read more..

  • Page - 444

    400 13. Binary Search Trees step is to check if the left child exists. If not, create a new left child and set current to 0. If it does, then move the current pointer to the left. This next code segment does the same thing, but to the right this time: else { if( current->m_right == 0 ) { current->m_right = new Node( p_data ); current->m_right->m_parent = read more..

  • Page - 445

    401 Coding a BST current = current->m_right; } return 0; } If the data isn’t found in the tree, this function returns 0. Example 13-1: Using the BST Class This is Example 13-1, which demonstrates how to use the BinarySearchTree class with integers. The source code for this example is on the CD in the directory \examples\ch13\01 - Binary Search Trees\ . The read more..

  • Page - 446

    402 13. Binary Search Trees Application: Storing Resources, Revisited This is Game Demonstration 13-1, and you can locate it on the CD in the directory \demonstrations\ch13\Game01 - Resources Revisited\ . Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B. To compile this read more..

  • Page - 447

    403 Application: Storing Resources, Revisited The Comparison Function The next thing that I need to do is to create the comparison function. Because you want to search the tree for string matches, you’ll use the standard C strcmp func- tion to compare the strings. int ResourceCompare( Resource p_left, Resource p_right ) { return strcmp( p_left.m_string, p_right.m_string ); } read more..

  • Page - 448

    404 13. Binary Search Trees After that, you declare a binary tree node pointer, which will hold the node that is returned from the BST’s Find function: BinaryTree<Resource>* node = 0; node = g_tree.Find( res ); Now the BST will compare the dummy resource’s name with the name of the resources in the BST, and if it finds a match, it will return the node read more..

  • Page - 449

    405 Conclusion As before, you enter the name of the resource you want to load into the text box, and it loads the resource for you automatically. The valid resource names are sky, water, water2, snow, fire, vortex, and stone. Conclusion I’m going to be honest with you: Binary Search Trees don’t really do much that a hash table doesn’t do better. Whereas a hash read more..

  • Page - 450

    This page intentionally left blank Team LRN read more..

  • Page - 451

    CHAPTER 14 Queues and Heaps Priority Team LRN read more..

  • Page - 452

    408 14. Priority Queues and Heaps The subjects I introduce you to in this chapter build off of two previous subjects in this book: queues from Chapter 7, “Stacks and Queues,” and binary trees from Chapter 12, “Binary Trees.” The structures in this chapter are used quite often in game programming, but not directly. More often, priority queues and heaps are helper read more..

  • Page - 453

    409 What Is a Priority Queue? Figure 14.1 This is a normal queue. The data would be processed in the order that it was inserted into the queue: first 4, then 2, then 5, and so on. Now, pretend that the number that is being inserted into the queue is its priority value: the higher the number, the higher the priority. Insert the five numbers into a priority read more..

  • Page - 454

    410 14. Priority Queues and Heaps The more important items are placed closer to the front. That’s pretty much all there is to the priority queue concept. Removing items from the priority queue is the same as before; the front item is removed first. There are several ways to implement priority queues. The easiest way is to have a linked list for the queue. Whenever read more..

  • Page - 455

    411 What Is a Heap? tree is, though, because it might be the other child of the root or it might be some- where on the third level of the tree. Why Can a Heap Be a Priority Queue? Because the highest value in a heap is always at the root node, the heap can easily be used as a priority queue. To access the front value in the priority queue, all you read more..

  • Page - 456

    412 14. Priority Queues and Heaps Figure 14.4 This is a four-level heap. The algorithm for inserting an item into the heap is actually quite easy when you understand how it works. Say you want to insert the number 85 into the heap from Figure 14.4. To keep the heap dense, you are going to place it in the first open node on the lowest level, which is the read more..

  • Page - 457

    413 What Is a Heap? Figure 14.6 Then you swap 60 and 85 to make it more like a heap. After the swap, one node is still invalid in the tree: node 80. You need to compare 85 with its parent again and swap them if it is larger. Figure 14.7 shows the tree after the second swap. Figure 14.7 Then swap 85 and 80 to turn the tree into a heap. After the read more..

  • Page - 458

    414 14. Priority Queues and Heaps Because a heap is always dense, it is easy to figure out how long inserting an item takes. On a four-level tree, you make at most three comparisons on an insertion. On a five-level tree, you make at most four comparisons, and so on. Because the number of items in the tree doubles with each new level, yet the number of com- read more..

  • Page - 459

    415 What Is a Heap? a node down the tree is a little more difficult because you have two choices of where to move the node now instead of just one. The choice is an easy one, how- ever. To keep the tree a heap, just move the larger of the two children up. In the example, the 20 at the root is swapped with 80 because 80 is the largest child. The result read more..

  • Page - 460

    416 14. Priority Queues and Heaps NOTE Note that the walk-down algorithm works for any node you want to remove in the heap.You can remove any node, move the last node into its place, and use the walk-down algorithm on it, and it will create a valid heap for you. Because this algorithm always moves the bottommost node, the tree always remains dense, so this read more..

  • Page - 461

    417 * 7 3 6 9 15 4 8 12 31 5 10 15 63 6 12 18 127 7 14 21 Graphical Demonstration: Heaps Table 14.2 Comparisons Made When Inserting and Removing from a Heap Data Size Heap-Insertion Heap-Removal Heap-Total *Remember:The walk-down algorithm performs two comparisons at every level. In a seven-item priority queue, the linked queue clearly wins out because inserting another read more..

  • Page - 462

    418 14. Priority Queues and Heaps This demonstration is fairly simple; there are only three commands. You can enqueue a number into the heap, dequeue the top of the heap, and place a ran- dom number into the text box. Figure 14.11 shows a screenshot from the demo. Figure 14.11 Here is a screenshot from the heap demo. When you insert a node into the heap, it is read more..

  • Page - 463

    419 Coding a Heap Class Because of this, the Heap class will inherit directly from the Array class so that you can use all of the nifty features of an array within the Heap. The Structure The only two things needed in addition to the array variables that are inherited are a variable to keep track of how many items are actually within the heap and a func- tion read more..

  • Page - 464

    420 14. Priority Queues and Heaps The Enqueue Function This is the function that is called whenever an item is inserted into the heap: void Enqueue( DataType p_data ) { m_count++; if( m_count >= m_size ) Resize( m_size * 2 ); m_array[m_count] = p_data; WalkUp( m_count ); } The function takes the data you want to insert as a parameter and increases the count of the read more..

  • Page - 465

    421 Coding a Heap Class 16: } 17: m_array[child] = temp; 18: } The WalkUp function takes an index as a parameter, allowing you to call the func- tion on any cell within the tree. The function then creates two index variables on lines 3 and 4. These variables rep- resent the current child and parent indexes as it walks up the tree. On line 5, the function creates read more..

  • Page - 466

    422 14. Priority Queues and Heaps Instead of moving 11 into where node 9 was, you skip that step and move it directly to the root. Although this example had only trivial savings, much larger trees will be faster. Now, back to the function! On line 6, the function starts a loop that will continue until the parent index is 0, which means that the child index read more..

  • Page - 467

    423 Coding a Heap Class This function will use the same optimization used with the WalkUp function; it stores the data that it is walking down in a temporary variable while nodes are moved up the tree. 1: void WalkDown( int p_index ) 2: { 3: int parent = p_index; 4: int child = p_index * 2; 5: DataType temp = m_array[parent]; 6: while( child < m_count ) 7: { read more..

  • Page - 468

    424 14. Priority Queues and Heaps Figure 14.14 The function must check whether p has only one child. The parent index is pointing to node p, and the child index is pointing to node c. The code on line 8 determines if the right child of p exists. In this example, it doesn’t, so c is automatically assumed to be the larger child of p. If p had two chil- read more..

  • Page - 469

    425 Application: Building Queues Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B. To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix B. If you create your own project, all read more..

  • Page - 470

    426 14. Priority Queues and Heaps The Units As I stated before, the game has three unit types, which are stored in an enumer- ated type: enum UNIT { ATTACKER, WORKER, DEFENDER }; Creating a Factory The Factory class is simple—it has only four variables: class Factory { public: UNIT m_currentUnit; int m_startTime; bool m_working; bool m_functioning; }; The factory knows read more..

  • Page - 471

    427 Application: Building Queues The Heap Because the Heap class is the only (and most efficient) implementation of a priority queue that I’ve shown you, you have to use a heap in the game as a priority queue. Heap<UNIT> g_heap( 64, CompareUnits ); The heap holds UNITs, and it starts off being able to hold 64 of them. Because the Heap class automatically resizes read more..

  • Page - 472

    428 14. Priority Queues and Heaps Starting Construction In the demo, you need to loop through the factories to see if any of them are able to start construction of a new unit. 1: for( x = 0; x < 4; x++ ) 2: { 3: if( g_factories[x].m_working == false && 4: g_factories[x].m_functioning == true && 5: g_heap.m_count > 0 ) 6: { 7: read more..

  • Page - 473

    429 Application: Building Queues 8: } 9: } 10:} The loop goes through all four factories again, this time just checking to see if they are currently producing a unit (line 3). If they are, then it checks to see how long they have been working on the current unit (line 5). This line of code subtracts the time that the factory started working from the current read more..

  • Page - 474

    430 14. Priority Queues and Heaps On the right are four factories, each with a progress bar and a text field saying which unit they are currently building. By clicking on the factory boxes to the left of the progress bars, you can turn the factories on or off. When a factory is turned off, the box will turn red, signifying that it is not functioning. You’ll read more..

  • Page - 475

    CHAPTER 15 and Minimax Game Trees Trees Team LRN read more..

  • Page - 476

    432 15. Game Trees and Minimax Trees Until this point in the book, I have shown you data structures that can be used for any type of game. None of the structures was specific to a certain genre. This chapter introduces you to a data structure that departs from this non-specific nature. Almost all of the game demos and examples in the book so far mimic real-time read more..

  • Page - 477

    433 What Is a Game Tree? Figure 15.1 This is a simple game of Rocks with two piles.The first pile has two rocks, and the second pile has one. In the figure, there are two piles. The first pile has two rocks, and the second pile has only one rock. If you are the first player, you have three choices: ■ Remove one rock from pile 1. ■ Remove two rocks from read more..

  • Page - 478

    434 15. Game Trees and Minimax Trees Figure 15.3 This is the complete game tree, demonstrating every possible move in the game. The game is entirely complete by the time the fourth level is reached—the game can have up to three moves because there were only three rocks. You can also tell from the tree that there are five total outcomes from the game because there read more..

  • Page - 479

    435 What Is a Minimax Tree? The minimax algorithm is a really neat way of transforming a game tree into data that a computer can analyze so it can make an intelligent choice about which move is the best at the moment. The minimax algorithm is designed for two players: Min and Max. The algorithm works like this: Max starts, so he has the dominant position and he read more..

  • Page - 480

    436 15. Game Trees and Minimax Trees The algorithm analyzes all five leaf nodes of the game tree from Figure 15.3. The states where Player 1 (Max) lost are made into a 0, and the states where Player 2 (Min) lost are made into a 1. After that has been completed, the minimax algorithm backtracks through the tree. Whenever it is Min’s turn, she selects the move read more..

  • Page - 481

    437 Graphical Demonstration: Minimax Trees Finally, the root node is evaluated. It has three children, and Max needs to choose the node with the largest value. Because two of the nodes are 0 and only one is 1, Max chooses the node with the 1 in it. What does all this mean? How do you use this information to determine which move Max will make? Because Max chose read more..

  • Page - 482

    438 15. Game Trees and Minimax Trees This is just a simple graphical demonstration that shows you how a few different minimax trees are generated. The demo uses the same game that I showed you pre- viously—the rock pile game. Figure 15.6 shows a screenshot from the demo. Figure 15.6 Here is a screenshot from the demo. Notice the three little boxes at the top. read more..

  • Page - 483

    439 Game States NOTE Note the order in which the program generates the minimax values. Recognize it? It is our old friend, the postorder traversal! You first saw the postorder tra- versal in Chapter 11, “Trees.” The postorder traversal works like this: For each node, it figures out the minimax values for all of its children, picks the min or max value depending on whose read more..

  • Page - 484

    440 15. Game Trees and Minimax Trees A discrete game will have a certain state at any given time. The state of a rock pile game stores how many rocks are in each pile. The state of a tic-tac-toe game stores which boxes are empty, have Xs, or have Os. The state of a chess or checkers game stores the locations of each of the markers on the game board. To read more..

  • Page - 485

    441 Game States If you don’t already know, the object of the game is to get three of your symbols in a row, either horizontally, vertically, or diagonally. The game has nine squares, each of which can contain one of three different things. If you had two squares, there would be a total of nine different states, as shown in Figure 15.9. Figure 15.9 These are the read more..

  • Page - 486

    442 15. Game Trees and Minimax Trees NOTE Note that not every game state is valid for a game of tic-tac-toe. For example, the base 3 number 19,682 converts to 222,222,222, which is a board filled com- pletely with Os. Obviously, this state can never be reached in a real game of tic- tac-toe because X and O alternate turns. So there are actually about half as read more..

  • Page - 487

    443 Application: Rock Piles Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B. To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix B. If you create your own project, all of read more..

  • Page - 488

    444 15. Game Trees and Minimax Trees Figure 15.10 The node pointers point to the game state that the AI should move to next. They are represented by the bold lines. When the minimax algorithm for this game demo goes through the tree and calcu- lates the minimum and maximum values for each node, it also keeps track of the child node that has the min or max read more..

  • Page - 489

    445 Application: Rock Piles The Equivalence Operator The next function is used to determine if two states are equal to each other. bool operator== ( RockState& p_rock ) { int x; for( x = 0; x < PILES; x++ ) { if( m_rocks[x] != p_rock.m_rocks[x] ) return false; } return true; } This function compares the number of rocks in all of the piles in each state, read more..

  • Page - 490

    446 15. Game Trees and Minimax Trees Tree<RockState>* g_tree; RockState g_startingState; Tree<RockState>* g_current = 0; bool g_playing = false; bool g_hint = false; bool g_yourturn = true; bool g_gameOver = false; The variables for the most part should be self-explanatory by their names, but let me go over them just in case. The g_tree variable is a pointer to the game read more..

  • Page - 491

    447 Application: Rock Piles 1: Tree<RockState>* CalculateTree( RockState p_state ) 2: { 3: int i; 4: int rocks; 5: Tree<RockState>* tree = new Tree<RockState>; 6: Tree<RockState>* child = 0; 7: RockState state; 8: TreeIterator<RockState> itr = tree; 9: tree->m_data = p_state; 10: for( i = 0; i < PILES; i++ ) 11: { 12: for( rocks = 1; rocks <= p_state.m_rocks[i]; read more..

  • Page - 492

    448 15. Game Trees and Minimax Trees Now, the function starts generating all the possible states that can be reached from the current state. This is accomplished by using a simple algorithm. Figure 15.11 shows the four states that are generated on a sample state. Figure 15.11 These are the four states that can be reached from the current state. First, the algorithm read more..

  • Page - 493

    449 Application: Rock Piles Generating the MiniMax Tree Now you need a function that will traverse the game tree and fill in the minimax values. I start by showing you the recursive postorder function that calls the mini- max calculation algorithm. void MiniMax( Tree<RockState>* p_tree, bool p_max ) { TreeIterator<RockState> itr = p_tree; for( itr.ChildStart(); itr.ChildValid(); read more..

  • Page - 494

    450 15. Game Trees and Minimax Trees In this simple game, the only states that are evaluated are the ending states of the game, and there can only be two outcomes for those states: Max won or Min won. Therefore, the heuristic function you will be using only generates two different val- ues: 0 or 1. A 0 means that Min has won the game, and a 1 means that read more..

  • Page - 495

    451 Application: Rock Piles p_tree->m_data.m_minimaxValue = Heuristic( p_tree->m_data, p_max ); return; } After the node has been set with its heuristic value, the function just returns. There is no need to do anything else. If the node has children, you need to apply the minimax algorithm to the node. This involves a few things. You need an integer that will keep track read more..

  • Page - 496

    452 15. Game Trees and Minimax Trees while( itr.ChildValid() ) { if( itr.ChildItem().m_minimaxValue < minmax ) { minmax = itr.ChildItem().m_minimaxValue; p_tree->m_data.m_nextState = itr.m_childitr.m_node->m_data; } itr.ChildForth(); } } Both loops are almost identical; one looks for larger values, and the other looks for smaller values. If either loop detects a smaller/larger value read more..

  • Page - 497

    453 Application: Rock Piles 8: for( itr.ChildStart(); itr.ChildValid(); itr.ChildForth() ) 9: { 10: if( itr.ChildItem() == newstate ) 11: { 12: g_current = itr.m_childitr.Item(); 13: return; 14: } 15: } 16:} The function takes two parameters: which pile the player is removing rocks from and how many rocks to remove. On line 3, the function creates a new temporary state read more..

  • Page - 498

    454 15. Game Trees and Minimax Trees NOTE This function has had all the unimportant GUI code stripped from it in the book; don’t be afraid if you notice that there is extra code in the version on the CD. This function was remarkably simple, wasn’t it? Because the minimax tree generation already did all of the work, each node has an m_nextState pointer to the read more..

  • Page - 499

    455 Application: Rock Piles is limited to a total number of 8 rocks. I tried 16, but the minimax tree took a few minutes to generate on my old K6-2 300MHz system, which was too long. After you are done setting up the piles, you click Play! Playing Figure 15.13 shows a screenshot from the playing section of the demo. Figure 15.13 Here is a screenshot while playing read more..

  • Page - 500

    456 15. Game Trees and Minimax Trees You always move first in this game. After you have made your move, it becomes the computer’s turn. Rather than moving immediately, however, the computer waits until you click the Computer button. When you click that button, the computer moves, and it is your turn again. You’ll find that you can win most games by following the read more..

  • Page - 501

    457 More Complex Games The pieces of the game can only capture pieces of the other team by jumping over them. This is really all that you need to know about the game for now. Now, consider the game in Figure 15.15. There are two pieces on the board, and they make the four moves shown in the figure. Figure 15.15 Here are four consecutive moves in a checkers read more..

  • Page - 502

    458 15. Game Trees and Minimax Trees Figure 15.16 Here is a partial game tree for the four checkers moves from Figure 15.15. The states marked with the question marks represent the states that you don’t care about at this point, so they aren’t expanded at all. Note that a regular recursive algorithm will think that both of the nodes marked 1 are different read more..

  • Page - 503

    459 More Complex Games for each next gamestate if HashTable.has( next gamestate ) node.AddChild( HashTable.find( next gamestate ) ) else node.AddChild( CalculateGameTree( next gamestate ) ) HashTable.add( next gamestate ) end if end for return node end function Obviously, this pseudo-code is a lot less complex than any real C++ function you would make. For instance, the part where read more..

  • Page - 504

    460 15. Game Trees and Minimax Trees Limited Depth Games So how in the world would someone implement a minimax algorithm on a chess game? Well, you would use a limited-depth algorithm. These algorithms, instead of generating every possible end state of the game, only look ahead a certain number of moves. The depth that the algorithm looks to is called the ply of read more..

  • Page - 505

    461 Conclusion planned, and judging from the feedback I got from my fellow game programmers, minimax trees aren’t a subject that appeals to the majority of game programmers. I’ve covered the most important aspects of minimax trees, and I’ve shown you enough to finally conclude with a point to this chapter. There are a few complex topics that I have left out, such as read more..

  • Page - 506

    This page intentionally left blank Team LRN read more..

  • Page - 507

    CHAPTER 16 Tying It Together: Trees Team LRN read more..

  • Page - 508

    464 16. Tying It Together: Trees By now, I hope you’ve gotten more of an idea of what trees are and how they are used in game programming. In this chapter, I show you how to use tree- like branching concepts in your game that are similar to the ones used in Game Demonstration 11-1. In this chapter, you will learn ■ How to alter the map format to store read more..

  • Page - 509

    465 Expanding the Game Altering the Map Format The first thing you need to figure out is how you’re going to modify the map for- mat so that it stores information on which map it should load next when one of the exits is entered. For demonstration purposes, I chose to limit the number of exits to three. The map format will stay the same as before, but this read more..

  • Page - 510

    466 16. Tying It Together: Trees An easier way is to assume that the string will have a maximum length and set aside that much space in the file for it. Then, if you ever need to skip around the file, you know exactly how long the data is. The down side is that space is wasted using this method. However, the amount of space the text takes up compared to read more..

  • Page - 511

    467 Expanding the Game Compiling the Demo This demonstration uses the SDLHelpers library that I have developed for the book. For more information about this library, see Appendix B, “The Memory Layout of a Computer Program.” To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix read more..

  • Page - 512

    468 16. Tying It Together: Trees Pretty simple, isn’t it? Then, when items are initialized in the game, if they can be picked up, they have their m_canGet boolean set with the SetGet function. Determining Whether the Item Is an Exit Adding this ability is similar to adding the previous ability: bool m_isExit; void SetExit( bool p_exit ) { m_isExit = p_exit; } read more..

  • Page - 513

    469 Expanding the Game This array defines three strings that are 64 characters long. Whenever you want to access a certain string, all you need to do is this: char* string = m_exits[0]; Then you will have a pointer to the first string in the array. This function handles this for you because the string array is hidden: char* GetExitName( int p_exit ) { return read more..

  • Page - 514

    470 16. Tying It Together: Trees Item* item; DListIterator<Item*> itr = p_person->GetItemIterator(); while( m_inventory.Size() > 0 ) { delete m_inventory.m_head->m_data; m_inventory.RemoveHead(); } The above loop goes through the inventory of the current person and deletes all the items in the inventory. m_currentweapon.Start(); for( itr.Start(); itr.Valid(); itr.Forth() ) read more..

  • Page - 515

    471 Expanding the Game Earlier, I said that the three new items were numbered 14, 15, and 16. These repre- sent the first, second, and third exits. You can’t pick up any of them, so the SetGet function is called and false is passed in. They are all exits, so the SetExit function is called, and true is passed in. Finally, their corresponding exit numbers are set. read more..

  • Page - 516

    472 16. Tying It Together: Trees The changed portions are highlighted in bold: void SetNewMap( char* p_filename ) { int x; Map* newmap; Person* newperson; newmap = LoadMap( p_filename ); newperson = newmap->GetViewer(); g_peoplecount = 0; for( x = 0; x < newmap->GetNumberOfCells(); x++ ) { if( newmap->GetPerson( x ) != 0 ) { AddPersonToArray( newmap->GetPerson( x ) ); read more..

  • Page - 517

    473 Expanding the Game Figure 16.4 Here is a screenshot from the demo. The Map Editor The new version of the map editor is on the CD in the directory \demonstrations\ch16\Game02 - Map Editor\ . The map editor required very few changes to support the vortex tiles. The most complicated part of the code was adding the part that would load and save the names of the read more..

  • Page - 518

    474 16. Tying It Together: Trees Saving the Exits to Disk The Save function is modified so that the following lines of code are added after the map data is stored: fwrite( g_exits[0], 64, sizeof(char), f ); fwrite( g_exits[1], 64, sizeof(char), f ); fwrite( g_exits[2], 64, sizeof(char), f ); These lines of code essentially write the three strings to disk. Reading the read more..

  • Page - 519

    475 Conclusion You’ll notice that there are only four new things on the map: three text boxes and one new button. The new button opens up the Exit palette, which allows you to draw one of the three vortexes. Each one has a different color: red, green, or blue. Whenever the player enters a red vortex, the map name in the red map text box will be loaded. The read more..

  • Page - 520

    This page intentionally left blank Team LRN read more..

  • Page - 521

    PART FOUR Graphs Team LRN read more..

  • Page - 522

    17 18 Machines 19 Graphs Using Graphs for AI: Finite State Tying It Together: Graphs Team LRN read more..

  • Page - 523

    CHAPTER 17 Graphs Team LRN read more..

  • Page - 524

    480 17. Graphs Now that you’ve learned about all of the basic data structures and all of the tree data structures, it’s time to learn about the most complex and flexible data structure in the book, the graph data structure. Graphs are used for all sorts of things, and believe it or not, you used a form of a graph previously in this book. I won’t tell you read more..

  • Page - 525

    481 What Is a Graph? Figure 17.1 This is a linked list. NOTE Figure 17.1 is drawn vertically, unlike the linked lists you have seen before in the book. Don’t worry about it; I did it to illustrate a point. After you learned about linked lists, you moved onto trees in Chapter 11, “Trees.” You learned that a tree is a node-based data structure where each read more..

  • Page - 526

    482 17. Graphs Graphs If you can make a linked list more flexible so that it becomes a tree, you can also do the same thing with a tree. If you take a tree and make it possible for each node in the tree to point to any other node in the tree, you end up with a graph. Figure 17.3 shows a sample graph. Figure 17.3 This is a graph, where any node can read more..

  • Page - 527

    483 Types of Graphs Bi-Directional Graphs The simplest kind of graph is a bi-directional graph. This is a graph in which each arc in the graph points to two nodes. For example, take a look at Figure 17.4. In this graph, node A points to node B, and node B points to node A. You can think of every arc in the graph as a two-way street; you can get from A read more..

  • Page - 528

    484 17. Graphs Figure 17.6 This figure shows you how to simulate a bi- directional graph using a uni-directional graph. This approach to a graph seems a little wasteful because the number of arcs is potentially doubled, but uni-directional graphs give you a little bit more control over the structure than bi-directional graphs. I touch on this more later when I explain how read more..

  • Page - 529

    485 Types of Graphs Tilemaps You should be thinking, “Hey! Didn’t I already learn about tilemaps?” The answer is yes. If you think about it for a moment, you can see that a tilemap is really just a different form of a graph. Figure 17.8 shows a figure of a 4 4 2D tilemap, like you’ve seen before. Figure 17.8 This is a 2D tilemap. Now, take the map read more..

  • Page - 530

    486 17. Graphs As you can see, it is assumed in a tilemap that there is a pathway open from one tile to another. The arcs serve to visualize the paths that are available in a tilemap. If you’re into hex-tile games (many strategy games use hex-tiles), Figure 17.10 shows an example of how to visualize a hex map as a graph. Figure 17.10 This is a hex-tilemap read more..

  • Page - 531

    487 Implementing a Graph Adjacency tables are always square. For example, look back at Figure 17.7, the map of the United States. There are a total of six nodes, so the adjacency table would be a 6 6 array. Figure 17.11 shows the adjacency table for the graph from Figure 17.7 simple: If you want to know the cost to get from city A to city B, you look read more..

  • Page - 532

    488 17. Graphs The first thing you should notice about this method is the wasted space. In a graph with n nodes, you will need n2 cells to store the arc information. There are a total of 5 Bi-directional arcs in the graph, yet you are required to use 36 cells for this information. Another thing you may notice is that this method is really only suited toward read more..

  • Page - 533

    489 Implementing a Graph The way that this method works may not be completely obvious at the first glance, but this is the same exact method I used to store the maps of my very first com- puter game, which was a dungeon text-adventure game. The way it works is this: To see what exits room R has, go down the y axis to that room, and then look at the exits. read more..

  • Page - 534

    490 17. Graphs There are four nodes and three arcs in the graph on the left of the figure, and the right side of the figure shows the internal representation of this graph. There is an array of four nodes, containing the data of the graph, and an array of three arcs. Arc A points to nodes 0 and 1, B points to 1 and 2, and C points to 2 and 3. This read more..

  • Page - 535

    491 Implementing a Graph NOTE My suggestion is this: Don’t store your graphs using the structure I just described in this section. I wanted to show you one bad approach to storing graphs so that you can see how much more efficient other methods are. Uni-Directional Graphs This is the most common form of a linked graph that you will see, as it is very flexi- ble read more..

  • Page - 536

    492 17. Graphs Graphical Demonstration: Graphs This is Graphical Demonstration 17-1, which you can find on the CD in the direc- tory \demonstrations\ch17\Demo01 - Graphs\ . Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B, “The Memory Layout of a Computer Program.” To read more..

  • Page - 537

    493 Graph Traversals The demonstration has four buttons, which you use for adding or removing nodes or arcs from the graph. When you click on the Add Node button, a gray circle appears on your cursor. When you have moved the circle to where you want to put it, click your mouse but- ton. A new node will now be in your graph. When you click on the Remove Node read more..

  • Page - 538

    494 17. Graphs Figure 17.17 A preorder traversal on a tree is the same as a depth-first search on a graph. Each complete path is followed before a new branch is started. First, the root node is processed, and then the algorithm follows one branch from the root node all the way down to the leaf. After that, it backtracks up to the last node with another branch read more..

  • Page - 539

    495 Graph Traversals the algorithm backtracks and looks for the next open path to travel down, which starts on node 4. Because node 4 doesn’t lead anywhere, the algorithm backtracks to 0 again and takes the path starting with node 5. Eventually, the algorithm ends up at node 7, which is where the algorithm becomes different from the preorder traversal algorithm. In a read more..

  • Page - 540

    496 17. Graphs Figure 17.19 shows a graph that has been traversed using the breadth-first search. 7 8 0 3 9 1 6 5 2 12 11 4 10 Figure 17.19 The breadth-first search processes all the nodes that are closest to the starting node first. Notice how the four nodes connecting to node 0 are processed first, and then the nodes connecting to each of those nodes are read more..

  • Page - 541

    497 Graph Traversals Mark( Node ) While( Queue.IsNotEmpty ) Process( Queue.Front ) For Each Child of Queue.Front if NotMarked( Child ) Queue.Enqueue( Child ) Mark( Child ) end if end For Queue.Dequeue() End While End Function As you can see, this function is a little more complex, and it isn’t recursive, either. I’ll have to illustrate this example a little read more..

  • Page - 542

    498 17. Graphs are put into the queue instead of when they are processed. This is a small optimiza- tion that prevents nodes from being placed into the queue more than once. This becomes much more important later on, when I discuss finding paths through huge graphs in Chapter 24. After the while-loop starts, it processes the node in front of the queue. After that, it read more..

  • Page - 543

    499 Graph Traversals into the queue. Finally, all of the rest of the nodes have no children, so they are processed and removed from the queue. Figure 17.22 shows the final order of processing. NOTE Make a special note of this:When node 5 was added to the queue, it was marked but not processed.When node 6 was processed, it only needed to check to see if node 5 was read more..

  • Page - 544

    500 17. Graphs these algorithms have in common is that they process every node that is reachable from a given starting point. In uni-directional graphs, this is important because of the many different one-way routes that can exist in a graph. Using this method, you can easily check to see which nodes are reachable by pro- cessing them or check which nodes are unreachable read more..

  • Page - 545

    501 The Graph Class Figure 17.23 Here is a screenshot from the demo. The Graph Class Now I will show you how to program a linked-node uni-directional weighted graph class. The other graph types (direction tables, adjacency tables, and tilemaps) are simple and need nothing more than a 2D array to implement. However, a flexible linked graph class is a little more difficult read more..

  • Page - 546

    502 17. Graphs GraphNode<NodeType, ArcType>* m_node; ArcType m_weight; }; There isn’t much to explain about this class except that it is flexible enough that you can use any kind of datatype for the weight of the arc. For example, you can use integers or floats or even create a custom weight class to use with this. Most of the time, you’ll probably just use read more..

  • Page - 547

    503 The Graph Class The Functions Like the linked list and tree node classes you’ve seen before, this class needs a few helper functions to make it easier to use. The functions of the graph node class are primarily concerned with adding, finding, and removing arcs from the node, the most common operations. All of these functions are relatively simple. Adding an Arc This read more..

  • Page - 548

    504 17. Graphs The function returns a pointer to the arc, so you can modify it if you want. Also, because it returns a pointer, it can return 0 if the arc you want to find doesn’t exist in the node. The function simply makes a linked list iterator and loops through, checking to see if the arc you want to find is located within the arc list. If so, then read more..

  • Page - 549

    505 The Graph Class Array<Node*> m_nodes; int m_count; }; Again, the arc and the node typedefs are present to make life easy on you, so your code doesn’t end up looking ugly. The graph class only has two variables in it: an array of Node pointers and a count variable. As you can guess, the array holds the nodes in the graph. Because I’m using an array, the read more..

  • Page - 550

    506 17. Graphs ~Graph() { int index; for( index = 0; index < m_nodes.m_size; index++ ) { if( m_nodes[index] != 0 ) delete m_nodes[index]; } } It is just a simple loop that deletes any nodes that are valid. Remember, some nodes in the array may not be valid, so you need to check if they are 0 or not. Adding a Node to the Graph One of the benefits read more..

  • Page - 551

    507 The Graph Class shows a graph before and after you delete a node if you just delete the node and do nothing else. Figure 17.24 Deleting a node without deleting the arcs that point to it can cause large bugs. You can see that all arcs coming out of that node are deleted, but all arcs pointing to the deleted node still exist! The two nodes are now pointing read more..

  • Page - 552

    508 17. Graphs arc = m_nodes[node]->GetArc( m_nodes[p_index] ); if( arc != 0 ) RemoveArc( node, p_index ); } } This goes through every node in the graph. For each node, if it is valid, it checks to see if there is an arc from the current node pointing to the node you want to remove. If there is, then arc will have a pointer to the arc that exists read more..

  • Page - 553

    509 The Graph Class The function adds an arc from index p_from to index p_to with a weight of p_weight. The first thing the function does is make sure that both nodes exist, and if either of them doesn’t exist, the function returns false, for failure. After that, the function checks to see if an arc already exists from the first node to the second. If so, the read more..

  • Page - 554

    510 17. Graphs Clearing All the Marks This function is here to clear all the marks on every node, which you should do before calling the traversal algorithms. void ClearMarks() { int index; for( index = 0; index < m_nodes.m_size; index++ ) { if( m_nodes[index] != 0 ) m_nodes[index]->m_marked = false; } } The function clears the mark on every valid node. Very read more..

  • Page - 555

    511 The Graph Class if( itr.Item().m_node->m_marked == false ) { DepthFirst( itr.Item().m_node, p_process ); } } } This last section creates an iterator and iterates through all the arcs in the current node. If any of the arcs point to a node that isn’t marked, the function recursively calls the DepthFirst function on that node, which is almost the same as the read more..

  • Page - 556

    512 17. Graphs if( itr.Item().m_node->m_marked == false ) { itr.Item().m_node->m_marked = true; queue.Enqueue( itr.Item().m_node ); } } queue.Dequeue(); } } While the queue is not empty, the loop processes the first node on the queue and then adds all non-marked child nodes from the first node onto the queue and marks them. Finally, the first node is dequeued, and the loop read more..

  • Page - 557

    513 Application: Making a Direction-Table Dungeon The array simply stores integers. If you access the array with a certain room and direction, the contents of the array at that index should be the number of the room that the exit leads to, as I showed you previously. The demo has two constant variables, ROOMS and DIRECTIONS, which specify the num- ber of rooms there are read more..

  • Page - 558

    514 17. Graphs You should already know how to read this table; if not, please go back and re-read the section in this chapter where I introduce them to you. If you look at the direction table, I’ve shaded all the invalid entries. All of this data needs to be stored in a 2D array somehow, so I’ve picked an arbitrary value that means, “This exit is read more..

  • Page - 559

    515 Application: Making a Direction-Table Dungeon The Helper Structures I’ve used a few “helper” structures to make this function easier to program, however. The first is a bitvector (see Chapter 4 if you are unfamiliar with bitvectors): Bitvector g_marked( ROOMS ); This bitvector keeps track of which rooms have been marked during the drawing process because there isn’t a specific node read more..

  • Page - 560

    516 17. Graphs After that, it loops through all four directions of the current node: int room; int direction; for( direction = 0; direction < DIRECTIONS; direction++ ) { room = g_map.Get( p_room, direction ); if( room != -1 ) { if( g_marked[room] == false ) { DrawMap( room, p_x + directionarray[direction][0], p_y + directionarray[direction][1] ); } } } } For read more..

  • Page - 561

    517 Application: Making a Direction-Table Dungeon case SDLK_UP: x = 0; break; case SDLK_RIGHT: x = 1; break; case SDLK_DOWN: x = 2; break; case SDLK_LEFT: x = 3; break; } The four keys that change x are the up, right, down, and left arrow keys on the key- board. Each key corresponds to a direction; the up arrow key is direction 0 (north), and so read more..

  • Page - 562

    518 17. Graphs Figure 17.26 Here is a screenshot from the game demo. Application: Portal Engines This is Game Demo 17-2, which can be found on the CD in the directory \demon- strations\ch17\Game02 – Portals\ . Compiling the Demo This demonstration uses the SDLHelpers library that I have developed for the book. For more information about this library, see Appendix B. read more..

  • Page - 563

    First I want to start off by telling you an optimization hint. Most people, when they start programming in 3D (or even 2D), think that they can just throw the and let the clipping and culling algo- This is an inefficient method of render- cient to figure out what the user can see and then tell the video card to only draw that. 519 Application: Portal Engines read more..

  • Page - 564

    520 17. Graphs probably know what a sector is. A sector is simply a room in a level, like Figure 17.27 shows. Figure 17.27 This is a five-sector level. This is a simple overhead view of a level in a game that is separated into five sec- tors. This can very easily be broken down into a graph, as you might guess (this is a chapter about graphs, after all!), read more..

  • Page - 565

    521 Application: Portal Engines Determining Sector Visibility A true portal engine uses a visibility algorithm, which determines which sectors are visible from any given sector and viewpoint. This is a complex algorithm that takes a long time to perfect, and it is somewhat outside of the scope of this book, so I want to show you instead a quick little hack that allows read more..

  • Page - 566

    522 17. Graphs figure would not be processed. If you tell the algorithm to only visit one arc from the center, then it will not process the black nodes or the dark gray nodes. The DLDFS search works exactly like the regular DFS, except that it has one more parameter: DepthFirst( Node, depth ) if depth == 0, then return Process( Node ) Mark( Node ) For Every read more..

  • Page - 567

    523 Application: Portal Engines do and wouldn’t demonstrate much. To my surprise, the demo turned out to be very easy to code, and the result was great! The Sector Class The very first thing you need is a sector class. For this demo, I’m using a very primitive rectangle-based sector class. Even games like DOOM had much more complex sector formats than this. The read more..

  • Page - 568

    524 17. Graphs Each sector is labeled with its sector number. I used graph paper to draw the map and figure out the coordinates of each sector, which I did not include in the figure, because it would be too crowded. In the demo, the graph is declared like this: Graph<Sector, int> g_map( ROOMS ); The ROOMS variable is actually a con- stant declared at the read more..

  • Page - 569

    525 Application: Portal Engines After all of the sectors are added to the map, you need to connect the sectors with their portals (which is really just another name for an arc). From Figure 17.30, you can see that Sector 0 connects to Sectors 1, 2, 4, 5, and 8. Therefore, the code to attach those sectors looks like this: g_map.AddArc( 0, 1, 0 ); g_map.AddArc( 0, read more..

  • Page - 570

    526 17. Graphs itr = p_node->m_arcList.GetIterator(); for( itr.Start(); itr.Valid(); itr.Forth() ) { if( itr.Item().m_node->m_marked == false ) { DrawMap( itr.Item().m_node, p_x, p_y, p_depth - 1, p_col ); } } } The function is a little bit more complex than the pseudo-code I showed you ear- lier, but it isn’t difficult to comprehend. The x and y coordinates passed into read more..

  • Page - 571

    527 Application: Portal Engines Playing the Demo Figure 17.31 shows a screenshot from the demo in action. You are the little red dot in the center of the screen, and you’re supposed to move around the map. I didn’t implement bounds checking, so you can walk off the map into the black void, but please don’t do that. Instead, try to focus on moving around the read more..

  • Page - 572

    528 17. Graphs Conclusion This is a pretty big chapter, but it’s also a pretty big subject. As you can see from all the examples I’ve given you in this chapter, graphs in game programming are almost always used to store map or level information. This isn’t a trivial matter, because maps are a huge part of most games out there; you optimize maps for drawing read more..

  • Page - 573

    CHAPTER 18 Using State Graphs for AI: Finite Machines Team LRN read more..

  • Page - 574

    530 18. Using Graphs for AI: Finite State Machines So far, you’ve only used graphs for one purpose: storing map data in a game. I said that graphs aren’t used for much more in game programming, but there are a few ways to use graphs to simulate artificial intelligence (AI) in a computer. I show you one of the simpler methods, using finite state machines. In read more..

  • Page - 575

    531 What Is a Finite State Machine? Figure 18.1 Here are the four AI states. This should already look suspiciously like a graph to you—a graph with no arcs. Okay, so now what? The AI, when the game starts off, should be in a default state. In this example, you probably want to put your character at a checkpoint and make him guard it by default, so the AI is read more..

  • Page - 576

    532 18. Using Graphs for AI: Finite State Machines Congratulations—you’ve just created your very first finite state machine. In this simple example, there are four states and four events. Combining these states (nodes) and events (arcs) into a graph produces a finite state machine. Here’s how it works: At any given state, whenever an event occurs, if there is an arc leading from the read more..

  • Page - 577

    533 Complex Finite State Machines Complex Finite State Machines If you want your AIs to be smarter, you can create even more complex state machines with more states and more events. Sometimes drawing these complex machines can get a little cumbersome, though. Imagine that you are making a new machine that is more complex and can handle team-based behavior and let the AI read more..

  • Page - 578

    534 18. Using Graphs for AI: Finite State Machines That’s nine different events, much more than the four events from the first exam- ple. Now, put them together and you will probably get something like Figure 18.4. Figure 18.4 Here is a large finite state machine AI. At a first glance, that machine looks incredibly complex, and you’re correct—it is. However, you read more..

  • Page - 579

    535 Implementing a Finite State Machine Implementing a Finite State Machine The best thing about finite state machines is that they are fast. When I say “fast,” I mean “incredibly super-duper fast.” I’ll show you what I mean. To implement a finite state machine, you use a 2D array. Down one side of the array, the states are listed. Down the other side, the read more..

  • Page - 580

    536 18. Using Graphs for AI: Finite State Machines Figure 18.6 Here is the full state transition table. I usually find it easier to leave the cells blank when I’m drawing the tables because it makes them easier to read. Figure 18.7 shows you the state transition table for the machine in Figure 18.4. Figure 18.7 This is the state transition table for the machine read more..

  • Page - 581

    537 Graphical Demonstration: Finite State Machines Graphical Demonstration: Finite State Machines This is Graphical Demonstration 18-01, which can be found on the CD in the direc- tory \demonstrations\ch18\Demo01 – Simple FSM\ . Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B, read more..

  • Page - 582

    538 18. Using Graphs for AI: Finite State Machines Even More Complex Finite State Machines The finite state machines I showed you previously are called pure finite state machines. An entire area of computer science is dedicated to studying finite state machines. I only showed you a very limited form of a finite state machine called a deterministic finite automaton, or a read more..

  • Page - 583

    539 Even More Complex Finite State Machines different action state, the player can be in two different physical states, and 4 2 = 8. Figure 18.9 shows the resulting machine (plus an extra event, Injured). Figure 18.9 Here is the machine from Figure 18.3 with two different physical states. The four states in the top half of the figure represent the player when he has read more..

  • Page - 584

    540 18. Using Graphs for AI: Finite State Machines Now, you should notice something: Three of the states aren’t used. The Finding Health with Good Health state is worthless; why would the AI look for health when he doesn’t need it? Also, the Finding Ammo with Bad Health state is worthless; why would the AI try searching for ammo before he is healed? Same thing read more..

  • Page - 585

    541 Even More Complex Finite State Machines you’re finding ammo, then you have good health and low ammo; and so on. Again, as before, you can customize the machine any way you want to make it work with a specific goal in mind. Conditional Events Now, take one look at the machine from Figure 18.10, and you can see that it is complex. Furthermore, if you’re in read more..

  • Page - 586

    542 18. Using Graphs for AI: Finite State Machines NOTE Please note that by using this system, there is no need for the Low Ammo or Injured events. In the previous system, those events served only to update the current state so that it could “remember” if y ou were injured or had low ammo. Now, these conditions are evaluated when a major state change occurs, read more..

  • Page - 587

    543 Even More Complex Finite State Machines arrays, or an array of 2D arrays. If you remember back to Chapter 5, “Multi- Dimensional Arrays,” this is the same thing as a 3D array! Figure 18.13 shows this. Figure 18.13 This is the finite state machine represented as a 3D array, with 16 combinations. To access which state comes next, you go to the index of the read more..

  • Page - 588

    544 18. Using Graphs for AI: Finite State Machines There is some good news at the end of the tunnel, though. Typically, in a very large game, you’ll have many players following the same AI pattern, so there is no need to have a different machine for every AI; they can all use the same machine. Because the lookup method is very fast, you can also have hundreds read more..

  • Page - 589

    545 Even More Complex Finite State Machines It gets even better for events that aren’t conditional at all. For example, if you cre- ated a suicidal AI bot that would attack any enemy, no matter his health, then you would only need one range for the See Enemy event, 0–100. This method gets very difficult to use with more than one variable, however, which leads us read more..

  • Page - 590

    546 18. Using Graphs for AI: Finite State Machines Wow, isn’t that cool? This method should remind you of something that you saw earlier. Near the end of Chapter 11, “Trees,” I showed you decision trees, which are remarkably similar to this method. This is essentially using a decision tree for each state and event combination, so you would end up with a 2D read more..

  • Page - 591

    547 Game Demo 18-1: Intruder Figure 18.16 This is a screenshot from the demo. Game Demo 18-1: Intruder This is Game Demonstration 18-1. It is located on the CD in the directory \demonstrations\ch18\Game01 - Intruder\ . Compiling the Demo This demonstration uses the SDLHelpers library that I have developed for the book. For more information about this library, see Appendix read more..

  • Page - 592

    548 18. Using Graphs for AI: Finite State Machines So, naturally, you want to create an AI that has more of an emphasis on guarding the entrance of a base. Just to spice things up a little, though, I’m going to have two different types of guard AIs instead of just one! Yeah, how’s that for a deal? The first AI type is called the defender AI, which, as read more..

  • Page - 593

    549 Game Demo 18-1: Intruder Figure 18.17 Here are the machines for the defender and attacker AIs. Study them for a little bit and try to figure out what they do on your own. You can see that the attacker AI looks similar to many of the AIs that I’ve shown you before. When it is guarding the base and it sees an intruder, it immediately starts attacking. If read more..

  • Page - 594

    550 18. Using Graphs for AI: Finite State Machines Out of Range event and will switch into the Finding Base state. This prevents the defender AI from walking outside of the defense zone. The Code Code-wise, this is the most complicated demo in the book so far. The parts dealing with the finite-state-machine logic were the easy parts; the difficult parts were actu- read more..

  • Page - 595

    551 Game Demo 18-1: Intruder NOTE Because of the simple system I’ve implemented, the player can actually move up to 90 pixels per second when moving diagonally. Because this demo isn’t really concerned with movement consistency, I didn’t want to take the extra time to make this algorithm perfect. In other words, don’t worry about it. The AI is a little slower read more..

  • Page - 596

    552 18. Using Graphs for AI: Finite State Machines The AI Class Now I’ll show you the class used to store all of the AIs in the game. class AI { public: AIState m_state; AIType m_type; float m_x, m_y; int m_health; void Init( AIType p_type, float p_x, float p_y, int p_health ) { m_type = p_type; m_x = p_x; m_y = p_y; m_health = p_health; m_state = GUARDING; read more..

  • Page - 597

    553 Game Demo 18-1: Intruder The AIs After that, there are the AIs: AI g_AIs[8]; int g_numAIs = 0; The array of AIs is limited to 8, so there can be at most 8 AIs in the game at any time. The g_numAIs variable keeps track of how many AI’s are actually in the game at any given time. The Player Because this is a simple game demo, it is assumed that there read more..

  • Page - 598

    554 18. Using Graphs for AI: Finite State Machines Finally, there are the timer variables: int g_timer; int g_combattimer; int g_timedelta; The first variable, g_timer, holds the time of the game when the last frame was started. The combat timer keeps track of when the last combat round occurred, and the time delta variable keeps track of how much time has passed since read more..

  • Page - 599

    555 Game Demo 18-1: Intruder g_attacker[GUARDING][SEEINTRUDER][GOODHEALTH] = ATTACKING; g_attacker[GUARDING][SEEINTRUDER][BADHEALTH] = ATTACKING; Using the enumerated values that you defined earlier, this looks very readable, doesn’t it? These lines basically say this: When the attacker machine is in the guard- ing state, sees an intruder, and has good health, move into attack mode. The read more..

  • Page - 600

    556 18. Using Graphs for AI: Finite State Machines g_AIs[p_AI].m_state = g_defender[g_AIs[p_AI].m_state][p_event][health]; } } The function takes the index of the AI that is processing the event and which event has occurred. In the first part of the function, it determines whether the health of the AI is good or bad. After that, the computer determines which machine the AI read more..

  • Page - 601

    557 Game Demo 18-1: Intruder Some of these functions are complex, like the MoveAI function. That function requires some basic knowledge of trigonometry to understand, but unfortunately I have no room to teach trigonometry in this book. Each of these functions is com- mented in detail, so if you are interested in them, you may look at their source on the CD. But for the read more..

  • Page - 602

    558 18. Using Graphs for AI: Finite State Machines g_basey ) <= VISUALZONE ) Event( p_AI, FOUNDBASE ); After that, the AI checks to see if it can see the base. It does this by checking to see if the distance between the AI and the base is less than the VISUALZONE constant. If so, then a FOUNDBASE event is sent to the AI. if( Distance( g_AIs[p_AI].m_x, read more..

  • Page - 603

    559 Game Demo 18-1: Intruder If the AI is not within attacking distance, then the AI moves closer to the player, chasing after him. if( g_AIs[p_AI].m_state == FINDINGBASE ) { MoveAI( p_AI, g_basex, g_basey ); } If the AI is trying to find the base, he moves closer to the base. if( g_AIs[p_AI].m_state == FINDINGHEALTH ) { i = FindClosestHealthPack( g_AIs[p_AI].m_x, read more..

  • Page - 604

    560 18. Using Graphs for AI: Finite State Machines It looks kind of simple for a game demo, but I decided to use simplicity for this one because I wanted you to see the whole game screen at all times. This way, you can mess around and then watch what the AI does in response even if you’re on the other side of the map. Of course, this meant that I read more..

  • Page - 605

    561 Conclusion You saw from the game demo that I had two machines that operated very differ- ently, but they used the same code for every AI! The only difference was the addi- tion of a few arcs to the defender machine to make it head back to the base if it wandered too far away. The topic of real-time AI in computer games is a vast one, and I’ve by no read more..

  • Page - 606

    This page intentionally left blank Team LRN read more..

  • Page - 607

    CHAPTER 19 Tying It Together: Graphs Team LRN read more..

  • Page - 608

    564 19. Tying It Together: Graphs You’ve just finished the part of the book dealing with graphs, so now you want to do something with them. This chapter continues to expand the game demo that I developed in Chapters 9, “Tying It Together: The Basics,” and 16, “Tying It Together: Trees.” As you might guess, this chapter is concerned with adding graph read more..

  • Page - 609

    565 The New Map Format Figure 19.1 Here is a direction- table map. The graphical representation of the map is on the left, but the computer represen- tation of the map is in the table on the right. The table has two variables; the index on the vertical axis represents the room numbers. Each room can have four exits; there are four entries per room, representing the read more..

  • Page - 610

    566 19. Tying It Together: Graphs Chapter 9 where the Map class interface and Object class were designed, you should remember that the Object class maintains x and y coordinates so that objects can find out which direction they should move to get closer to another object. Figure 19.2 shows the structure of a single room entry for this map format. Figure 19.2 This is read more..

  • Page - 611

    567 Game Demonstration 19-1: Adding the New Map Format Figure 19.3 This is the directionmap file format. Game Demonstration 19-1: Adding the New Map Format This section deals with Game Demonstration 19-1. The source code for this chapter is on the CD in the directory \demonstrations\ch19\Game01 - Adventure v3\ , and this is the third version of the adventure game that I read more..

  • Page - 612

    568 19. Tying It Together: Graphs When designing the Map class in Chapter 9, I made some design choices that might not have made sense to you at the time, such as making the map be accessible by cell number and 2D coordinates and making every function virtual. This chapter will show you why I made those choices and why they make the game so flexible. The read more..

  • Page - 613

    569 Game Demonstration 19-1: Adding the New Map Format Also, the class has a constructor, which constructs each cell so that it doesn’t con- tain junk data: DirectionCell() { m_blocked = false; m_item = 0; m_person = 0; m_exits[0] = -1; m_exits[1] = -1; m_exits[2] = -1; m_exits[3] = -1; m_tiles[0] = -1; m_tiles[1] = -1; m_x = -1; m_y = -1; } Note that the exits read more..

  • Page - 614

    570 19. Tying It Together: Graphs The DirectionMap Class As I’ve said before, the DirectionMap class will inherit from the Map class. This means that it needs to implement all of the functions from that class on its own. The great thing about this method is that the game cannot tell the difference between a tilemap and a directionmap. Think about that statement for read more..

  • Page - 615

    571 Game Demonstration 19-1: Adding the New Map Format The DirectionMap Functions The DirectionMap class only has three functions on top of the Map functions: a constructor, a destructor, and the LoadFromFile function. The Constructor The constructor will set the tileset pointer according to its parameter: The LoadFromFile function is not Map RandomMap NOTE part of the class because read more..

  • Page - 616

    572 19. Tying It Together: Graphs The LoadFromFile Function This function will load a directionmap from disk using the same file format you saw in Figure 9.3. void LoadFromFile( char* p_filename ) { int x; int maptype; int cells; MapEntry entry; The function takes a string as the parameter; this is the name of the file that the function will load. The x variable is read more..

  • Page - 617

    573 Game Demonstration 19-1: Adding the New Map Format NOTE Please note that this function will cause a memory leak if a map is already loaded.The array is resized, and if the new map is smaller than the old map, the cells at the end of the map are destroyed, but the cells don’t destroy their con- tents when they are destroyed. Also, when the rooms are loaded read more..

  • Page - 618

    574 19. Tying It Together: Graphs m_rooms[x].m_person = MakePerson( entry.layers[3], entry.x, entry.y, x ); if( entry.layers[3] == 0 ) { SetViewer( m_rooms[x].m_person ); } } The same thing happens with the person in each cell, with one addition. Remember person number 0 is considered the player of the map, so whenever per- son 0 is detected, the function sets the read more..

  • Page - 619

    575 Game Demonstration 19-1: Adding the New Map Format If you use the breadth-first drawing algorithm, then you need a queue to help you draw everything. If you use the depth-first method, then you need a stack or a recursive function, which uses a stack anyway. Because the drawing function will be called often, you want this function to be as fast as possible. read more..

  • Page - 620

    576 19. Tying It Together: Graphs for( z = 0; z < 2; z++ ) { current = m_rooms[i].m_tiles[z]; Now it loops through both layers of the cell and gets the tile number for each layer. if( current != -1 ) { SDLBlit( m_tilebmps[current], p_surface, px, py ); } } If the tile number isn’t –1, then it is a valid tile, and it should be drawn. item read more..

  • Page - 621

    577 Game Demonstration 19-1: Adding the New Map Format if( m_rooms[cell].m_person != 0 ) return false; Then the function checks to see if the cell in that direction is blocked and if a per- son is in that cell. You cannot move into either of those kinds of rooms, so if either of them is true, false is returned. if( m_rooms[cell].m_item != 0 ) { if( read more..

  • Page - 622

    578 19. Tying It Together: Graphs The GetItem and SetItem Functions These functions just get and set an item at a certain cell number. Item* GetItem( int p_cell ) { if( p_cell >= GetNumberOfCells() || p_cell < 0 ) return 0; return m_rooms[p_cell].m_item; } void SetItem( int p_cell, Item* p_item ) { if( p_cell >= GetNumberOfCells() || p_cell < 0 ) return; read more..

  • Page - 623

    579 Game Demonstration 19-1: Adding the New Map Format int GetCellNumber( int p_cell, int p_direction ) { return m_rooms[p_cell].m_exits[p_direction]; } The function first accesses the m_rooms array to get the starting room and then accesses its m_exits array to find out the number of the room in the given direc- tion. The GetNumberOfCells Function This is a pretty simple read more..

  • Page - 624

    580 19. Tying It Together: Graphs Changes to the Game Logic If you look at the kinds of maps that are best represented by a tilemap, you can see that they are usually outdoor maps. That’s because the outdoors is a wide-open area, and a tilemap represents that kind of environment. Indoor environments are a different story, however. Indoor areas are usually small read more..

  • Page - 625

    581 Game Demonstration 19-1: Adding the New Map Format The New LoadMap Function In Chapter 9, I showed you that the game demo will separate the map-loading logic into a function called LoadMap, but I told you that the explanation would have to wait until Chapter 19, “Tying It Together: Graphs.” Well this is Chapter 19, so I sup- pose I should explain it to you. read more..

  • Page - 626

    582 19. Tying It Together: Graphs If the file could not be opened, it returns an empty pointer. fread( &maptype, 1, sizeof(int), f ); fclose( f ); if( maptype == 0 ) { tmap = new TileMap( 64, 64, 2, g_outdoortiles ); tmap->LoadFromFile( p_filename ); return tmap; } else if( maptype == 1 ) { dmap = new DirectionMap( g_dungeontiles ); dmap->LoadFromFile( read more..

  • Page - 627

    583 Converting Old Maps Figure 19.4 Here’s a screenshot of the directionmap level. Note the black blanks in an irregular pattern:This is not possible with a tilemap, but it’s easy to do with a directionmap. Converting Old Maps When I introduced the idea of an ID number in each map file, I said you needed a way to convert an old map produced from the level read more..

  • Page - 628

    584 19. Tying It Together: Graphs After that is the map type variable, which is set to 0 to denote that this is a tilemap. Finally, the file is declared. cout << “Enter a filename: “; cin >> filename; cout << “converting file...”; After that, the filename is requested from the user of the program. f = fopen( filename, “rb” ); fread( mapdata.m_array, read more..

  • Page - 629

    585 The Directionmap Map Editor Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B. To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix B. If you create your own project, all read more..

  • Page - 630

    586 19. Tying It Together: Graphs for( x = 0; x < g_map.Width(); x++ ) { g_map.Get( x, y, 0 ) = -1; g_map.Get( x, y, 1 ) = -1; g_map.Get( x, y, 2 ) = -1; g_map.Get( x, y, 3 ) = -1; } } All four layers of the map are cleared to nothing so that when you start the map editor, the map is completely empty. Setting and Clearing Tiles In a read more..

  • Page - 631

    587 The Directionmap Map Editor When creating a directionmap, all of the cells in the 64 64 grid will be part of the void, and they will be blank. How does the program tell if a cell is part of the map or part of the void, then? This editor uses a simple assumption: If a cell has a base tile (on layer 0), then it is part of the map. If the base read more..

  • Page - 632

    588 19. Tying It Together: Graphs The preceding code segment is somewhat important. Previously, whenever you wanted to clear the tile on a given layer, the g_currentlayer variable was set to the layer that you wanted to clear, and the g_currenttile variable was set to –1. Then, whenever you draw on the map, a –1 is placed into the current layer, and any item that read more..

  • Page - 633

    589 The Directionmap Map Editor for( z = 0; z < 4; z++ ) { for( y = 0; y < g_map.Height(); y++ ) { for( x = 0; x < g_map.Width(); x++ ) { g_map.Get( x, y, z ) = -1; } } } This code segment goes through every cell in the entire map and clears it out to –1. When a new map is loaded, each room is read in from disk and then placed read more..

  • Page - 634

    590 19. Tying It Together: Graphs The entry of each room in the file is read into the entry variable. The x and y vari- ables of each entry tell the editor at which grid position each room should be placed. Then the function loops through each layer of the entry and copies the tile value of the entry into the map grid at the coordinates of the entry. Note read more..

  • Page - 635

    591 The Directionmap Map Editor Again, there is a MapEntry variable, but this time it will be used to save each room to disk instead of loading it. After that is a 2D array called cellnumbers. This array will store the room number of each cell in the grid if it is a valid room. The tilecount variable will be used to keep track of the number of rooms in the read more..

  • Page - 636

    592 19. Tying It Together: Graphs if( g_map.Get( x, y, 0 ) != -1 ) { Now the second and final pass is started. It goes through every cell once again and picks out the cells that have a base tile. entry.x = x; entry.y = y; The x and y coordinates of the current room entry are set to be the same as the coordinates of the room on the 64 64 read more..

  • Page - 637

    593 The Directionmap Map Editor If there is no cell there, then the direction entry is set to –1, which means that there is no exit in that direction. for( z = 0; z < 4; z++ ) { entry.layers[z] = g_map.Get( x, y, z ); } fwrite( &entry, 1, sizeof(MapEntry), f ); } } } The tile numbers of each layer of the entry are set to the same values as the read more..

  • Page - 638

    594 19. Tying It Together: Graphs Figure 19.6 Here is a screenshot from the directionmap dungeon editor. Play around with it, and see what you can do. Upgrading the Tilemap Editor There is one more thing that needs to be done—a very quick edit to the old tilemap editor from Chapter 16 so that it supports the new ID number on tilemaps. This update is so simple read more..

  • Page - 639

    595 Upgrading the Tilemap Editor FILE* f = fopen( g_filename, “wb” ); if( f == 0 ) return; fwrite( &maptype, 1, sizeof(int), f ); fwrite( g_map.m_array, g_map.Depth() * g_map.Height() * g_map.Width(), sizeof(int), f ); fwrite( g_exits[0], 64, sizeof(char), f ); fwrite( g_exits[1], 64, sizeof(char), f ); fwrite( g_exits[2], 64, sizeof(char), f ); fclose( f ); } The code just read more..

  • Page - 640

    596 19. Tying It Together: Graphs Conclusion Hopefully, now you can see how designing your game structures to be flexible at the very beginning can really save you a lot of work later on when you want to add features to the game. Although I could have used tons of other examples to integrate graphs into this chapter, this chapter had two major points I wanted read more..

  • Page - 641

    PART FIVE Algorithms Team LRN read more..

  • Page - 642

    20 Sorting Data 21 Data Compression 22 23 24 Random Numbers Pathfinding Tying It Together: Algorithms Team LRN read more..

  • Page - 643

    CHAPTER 20 Sorting Data Team LRN read more..

  • Page - 644

    600 20. Sorting Data When people teach you how to sort data in a book, they usually either put the information up near the front of the book or spread the information haphazardly throughout the book. I’ve decided to use a different method. Now that you’ve learned about every structure in the book, I feel it is safe to introduce you to some of the more famous read more..

  • Page - 645

    601 The Simplest Sort: Bubble Sort Figure 20.1 This is one pass of the bubble sort. Now that the highest number in the array has been bubbled up to the top of the array, this process is repeated, as shown in Figure 20.2. Figure 20.2 This is the second pass of the bubble sort. Notice that this time fewer swaps occur. This time, the 1 and the 2 are swapped, read more..

  • Page - 646

    602 20. Sorting Data Figure 20.3 Here is the worst- case scenario for a bubble sort. Because a bubble sort is essentially a doubly-nested for-loop, the algorithm is classi- fied as an O(n 2 ) algorithm. All in all, the bubble sort is pretty “dumb.” Graphical Demonstration: Bubble Sort This is Graphical Demonstration 20-1, which can be found on the CD in the direc- tory read more..

  • Page - 647

    603 The Simplest Sort: Bubble Sort Figure 20.4 Here is a screenshot from the demo. Clicking the Randomize button will randomize the bars, and clicking the Sort but- ton will start the sorting animation. This will graphically show you how the bubble sort works. Figure 20.5 shows a screenshot of the same array, sorted. Figure 20.5 Here is the sorted array. Team LRN read more..

  • Page - 648

    604 20. Sorting Data When you’re watching the demo, it is very easy to see how the bubble sort works, because you can see the tallest bars being bubbled up to the end of the array. Coding the Bubble Sort All of the sorting functions found in this chapter can be found on the CD in the file \structures\sorts.h. Even though I don’t expect you to ever use the read more..

  • Page - 649

    605 The Simplest Sort: Bubble Sort So this means that you don’t have to do any calculations in the upper part of the array during each pass because you know that the upper part of the array is already sorted. Psuedo-Code To start with, let me show you the algorithm in psuedo-code: Bubblesort( Array ) int swaps = 1 int top = Array.size - 1 int index while( read more..

  • Page - 650

    606 20. Sorting Data I’ll be using templates and function pointers to make the sorting functions in this book as flexible as possible so that you will never need to program another sorting algorithm after you have programmed these. I’ve used the notion of comparison functions before in Chapters 13, “Binary Search Trees,” and 14, “Priority Queues and Heaps,” and read more..

  • Page - 651

    607 The Simplest Sort: Bubble Sort The p_array variable is a reference to the array that you want to sort, and p_compare is a pointer to the comparison function. The only things that are different from the pseudo-code version is the call to p_compare, instead of a less-than comparison, and the C++ template syntax. Example 20-1 Using the bubblesort algorithm is somewhat read more..

  • Page - 652

    608 20. Sorting Data The final function compares floats and returns a number based on how they compare. value with a if( fabs(l-r) < threshold ) NOTE Most floating point comparison functions are a little more complex than mine here. For example, look at the numbers 1.00001 and 1.00002, which are practically equal for all intents and purposes (except for intensely accurate read more..

  • Page - 653

    609 The Hacked Sort: Heap Sort Wasn’t that easy? You pass in the array you want to sort and the comparison func- tion. The first two sorts sort the arrays in ascending order so that the lowest values are first in the array. The third sort re-sorts the integer array in descending order because the comparison function is reversed. Isn’t that neat? The Hacked Sort: read more..

  • Page - 654

    610 20. Sorting Data Figure 20.7 This is how you treat an array as a binary tree. Note that this is just a conceptual conversion; you really haven’t done anything to the array except look at it differently so you can understand how the algorithm works better. Now you can begin the process of converting the array into a valid heap, which is shown in Figure 20.8. read more..

  • Page - 655

    611 The Hacked Sort: Heap Sort down, so it is swapped with the 6. Finally, you call WalkDown on the 2, and it is walked down to the bottom of the heap. Congratulations, you now have a heap. How do you turn the heap into a sorted array, though? Think about two things. One, you always remove the highest item in the heap, and two, when you remove the top of read more..

  • Page - 656

    612 20. Sorting Data Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B. To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix B. If you create your own project, all of the read more..

  • Page - 657

    613 The Hacked Sort: Heap Sort Figure 20.11 Here is a screenshot of the half-sorted array. The first thing you should notice about this demo is that it is significantly faster than the bubble sort demo (I demonstrate its speed later). The heap sort is a smarter algorithm than the bubble sort; it focuses its efforts into finding the high- est item in the array and read more..

  • Page - 658

    614 20. Sorting Data template<class DataType> void HeapWalkDown( Array<DataType>& p_array, int p_index, int p_maxIndex, int (*p_compare)(DataType, DataType) ) { int parent = p_index; int child = p_index * 2; DataType temp = p_array[parent - 1]; while( child <= p_maxIndex ) { if( child < p_maxIndex ) { if( p_compare( p_array[child - 1], p_array[child] ) < 0 ) { child++; read more..

  • Page - 659

    615 The Hacked Sort: Heap Sort The HeapSort Function Finally, here is the HeapSort function, split into sections so you can understand it better. template<class DataType> void HeapSort( Array<DataType>& p_array, int (*p_compare)(DataType, DataType) ) { int index; int maxIndex = p_array.Size(); int rightindex = maxIndex / 2; The three variables that are used are the index, read more..

  • Page - 660

    616 20. Sorting Data HeapSort( iarray, compareint ); HeapSort( farray, comparefloat ); HeapSort( iarray, compareintreverse ); That’s all there is to it. The Fastest Sort: Quicksort This is the last general-purpose sort that I will go into in depth in this book for a very simple reason: The quicksort is the fastest sort (so it isn’t just a clever name). The quicksort read more..

  • Page - 661

    617 The Fastest Sort: Quicksort Figure 20.12 These are the best- case and worst-case quicksorts. On the top, the pivot that is chosen is the median value in the array. The median value in a bunch of numbers is the number that will fall in the middle of the array when they are sorted. Team LRN read more..

  • Page - 662

    618 20. Sorting Data Statistics Terms Here are a few common terms used in statistics: ■ mean - The mean is the average of a list of numbers, which is simply their sum divided by their quantity. ■ median - The median of a list of numbers is the num- ber that is exactly in the center if the list is sorted. ■ mode - The mode of a list of read more..

  • Page - 663

    619 The Fastest Sort: Quicksort To show you how this works, I have to take you through an example. Figure 20.13 shows the array you want to sort and how the pivot is chosen. In this example, you examine 11, 1, and 5 and choose 5 as the pivot because it is the median value of those three. Figure 20.13 This is how you set up an array for the quicksort, by read more..

  • Page - 664

    620 20. Sorting Data Figure 20.14 Here is the first level of the quicksort algorithm. You can see that the function starts scanning downward, and when it finds the 2, it moves that into the empty cell because it is less than the pivot, 5. Next, it scans upward and moves the 10 into the empty cell because it is greater than the pivot. This process repeats, back read more..

  • Page - 665

    621 The Fastest Sort: Quicksort Figure 20.15 This is the quicksort called on the left half of the first partition. You can see that this little segment is almost sorted now. Just one more call to the Quicksort function should get that little section sorted. NOTE One of the more famous computer scientists, Donald Knuth, recommends that instead of using a quicksort on really read more..

  • Page - 666

    622 20. Sorting Data Again, this demo is just like the previous two, so I’ll just leave you with a pretty screenshot demonstrating the partitioning of the array in Figure 20.16. Figure 20.16 Here is a screenshot from the quicksort demo. As you can see, the first pass of the quicksort has separated the items so that the small items are on the left and the large read more..

  • Page - 667

    623 The Fastest Sort: Quicksort Coding the Quicksort The QuickSort function is very similar to the previous sorting functions because it is templated and makes use of a comparison function. The MedianOfThree Function The first thing you need to do is create a function that will find the median of three values in the array and return the index of the median value. As read more..

  • Page - 668

    624 20. Sorting Data if( p_compare( p_array[mid], p_array[p_first] ) < 0 && p_compare( p_array[mid], p_array[last] ) < 0 ) { if( p_compare( p_array[p_first], p_array[last] ) < 0 ) return p_first; else return last; } By the same logic, the function then tests to see if the middle index is the smallest. If so, then the smaller value of the first and last read more..

  • Page - 669

    625 The Fastest Sort: Quicksort int pivot; int last = p_first + p_size - 1; int mid; int lower = p_first; int higher = last; The first variable is the pivot, which you should already be familiar with. The last index holds the index of the last cell in the current array segment, and the mid index holds the index of the median value of the array. The read more..

  • Page - 670

    626 20. Sorting Data This code segment starts at the higher index and scans downward until it finds a value lower than the pivot or the higher index becomes equal to the lower index. This is important because it deviates from the algorithm I explained in Figure 20.14. If you could just take a moment to look back at that figure, I will show you what is happening. read more..

  • Page - 671

    627 Graphical Demonstration: Race When a value greater than the pivot has been found, it is moved into the higher index, and the lower index is now considered empty. p_array[lower] = pivot; QuickSort( p_array, p_first, lower - p_first, p_compare ); QuickSort( p_array, lower + 1, last - lower, p_compare ); } } Finally, the pivot is placed back into the array at the correct read more..

  • Page - 672

    628 20. Sorting Data Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B. To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix B. If you create your own project, all of the read more..

  • Page - 673

    629 Graphical Demonstration: Race The array on top will be bubble sorted, the array in the middle will be heap sorted, and the array on the bottom will be quicksorted. Care to place any wagers on who will win this race? And they’re off! Figure 20.18 shows a screenshot of the demo when the quicksort completes. Figure 20.18 Here is a screenshot when the quicksort read more..

  • Page - 674

    630 20. Sorting Data Can you believe that? The heap sort, while still being twice as slow as the quicksort, still manages to kick the crap out of the bubble sort! The bubble sort array is still almost entirely unsorted! Play with the demo, and you will see that the quicksort is clearly superior to all the other sorts and that the bubble sort is to be avoided at read more..

  • Page - 675

    631 The Clever Sort: Radix Sort After the entire array is in the bins, the bins are then emptied into the array again, starting at the first bin, so that 10 is put in first, then 72, and so on. After the first step has been completed, you repeat the process, this time using the second digit in the numbers. Figure 20.21 shows the second pass. Figure 20.21 This read more..

  • Page - 676

    632 20. Sorting Data Again, the interface is almost identical to the previous sorting demos, except that there are three sorting buttons this time. Figure 20.22 shows a screenshot. Figure 20.22 Here is a screenshot from the Radix Sort demo. The three different buttons perform the radix sort using three different bases: base 2, base 4, and base 8. In base 2, you only read more..

  • Page - 677

    633 The Clever Sort: Radix Sort So, you can see from the table that the radix sort becomes more efficient with larger bases, but the tradeoff is that the bins require more space with larger bases. The upside is that this algorithm is very fast for large data sets because the algo- rithm essentially runs in O(n) time; much better than the quicksort. The downside is read more..

  • Page - 678

    634 20. Sorting Data void RadixSort2( Array<int>& p_array, int p_passes ) { if( p_array.Size() > RADIXBINSIZE ) return; The radix sort takes the array you want to sort and the number of passes you want to do on it as parameters. The first thing the radix sort does is check to see if the array is larger than the bin size. If it is, then the function exits out read more..

  • Page - 679

    635 The Clever Sort: Radix Sort bincount[0] = bincount[1] = 0; for( index = 0; index < p_array.Size(); index++ ) { binindex = (p_array[index] & radix) >> shift; bins[binindex][bincount[binindex]] = p_array[index]; bincount[binindex]++; } This segment first clears the bin counts and then loops through the array. This is the process where the array is sorted into the bins. read more..

  • Page - 680

    636 20. Sorting Data Base 4 The base-4 radix sort is only slightly different than the base-2 radix sort. Instead of inspecting individual bits, you will now be inspecting pairs of bits. First, the initialization is a little different: static int bins[4][RADIXBINSIZE]; int bincount[4]; int radix = 3; Notice that radix is now 3, which in binary is 11. You want to read more..

  • Page - 681

    637 Other Sorts comparison function at all. Unfortunately, due to the lack of a comparison func- tion, the radix sort is very limited in what it can do. Array<int> array( 16 ); int index; for( index = 0; index < 16; index++ ) { array[index] = rand() % 256; } First fill up an array with 16 values from 0-255 (eight bit values). RadixSort2( array, 8 ); cout read more..

  • Page - 682

    638 20. Sorting Data However, I chose not to show you that sort here because the quicksort is almost always faster and the merge sort requires an extra array in memory to work. It’s really not worth it to learn that sort. There is one more trick I want you to know about, the binary search tree sort. You last encountered BSTs in Chapter 13. Figure 20.23 read more..

  • Page - 683

    639 Application: Depth-Based Games Compiling the Demo This demonstration uses the SDLHelpers library that I have developed for the book. For more information about this library, see Appendix B. To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix B. If you create your own project, read more..

  • Page - 684

    640 20. Sorting Data float x; float y; }; There are four types of players: the hero, the two monsters, and the tree. Okay, technically a tree isn’t a player, but it really doesn’t matter for now. The player also has two coordinates, which determine where it will be drawn on the screen. The Globals The only global variables in the demo related to drawing the read more..

  • Page - 685

    641 Application: Depth-Based Games void InitPlayers() { int index; for( index = 1; index < PLAYERS; index++ ) { g_players[index].type = rand() % 3 + 1; g_players[index].x = rand() % WIDTH - 64; g_players[index].y = rand() % HEIGHT + 64; } for( index = 0; index < PLAYERS; index++ ) { g_sortedplayers[index] = &(g_players[index]); } } It is very important that you read more..

  • Page - 686

    642 20. Sorting Data SDLBlit( g_bmps[p->type], g_window, p->x, p->y - g_bmps[p->type]->h ); } } The y-coordinate manipulation in the call to SDLBlit makes sure that the bitmap is drawn with the y-coordinate referring to the bottom of the bitmap (as opposed to the top of the bitmap, which is how all blitting algorithms work). Don’t worry, all it does is subtract the read more..

  • Page - 687

    643 Conclusion Conclusion There really isn’t much more to say about sorting except this: Use the quicksort. Even if you’re afraid of recursion and you actually believe those people who say that recursion slows things down (they are wrong, by the way), the quicksort does far less work than any other sort in existence. There is one final note that needs to be made. read more..

  • Page - 688

    This page intentionally left blank Team LRN read more..

  • Page - 689

    CHAPTER 21 Data Compression Team LRN read more..

  • Page - 690

    646 21. Data Compression You may not think that data compression is a very important topic in game programming today. After all, we have computers now with up to and some- times more than 1GB of RAM and hard drives with up to 200GB of storage. With DVD-ROMs becoming more common, soon many games will start shipping on them instead of CD-ROMs, giving game developers up read more..

  • Page - 691

    647 Why Compress Data? Data Busses The most pressing concern today is the rapidly widening gap between the speed of the processors in a system and the data bus. Figure 21.1 shows a diagram of the bus between the Graphics Processing Unit (GPU) and the Central Processing Unit (CPU). The GPU is the chip on your video card, and the CPU is the main processor on your read more..

  • Page - 692

    648 21. Data Compression doesn’t need to get the texture from the CPU; it already has the texture in its own memory, and it draws it immediately. Figure 21.2 This shows localized memory sub-systems for each of the processors. Another solution to the problem is what the Microsoft XBox did. They used a uni- fied memory system, which looks like Figure 21.3. Figure 21.3 read more..

  • Page - 693

    649 Run Length Encoding The Internet As a game programmer, you’ve been acquainted with the Internet for a while now, I’m sure. The vast majority of the rest of the world is just learning about it, how- ever, and multi-player gaming is the wave of the future. We saw the releases of the blockbusters Quake 3 and Unreal Tournament a few years ago, and now Massively read more..

  • Page - 694

    650 21. Data Compression Figure 21.5 This is how you convert text into RLE. That’s all there is to the basic theory of RLE. The idea is that some types of data have runs of data that are repeated, and keeping track of the runs is cheaper than keeping track of the actual data. It converts a run of a piece of data into a length and one instance of that read more..

  • Page - 695

    651 Run Length Encoding Figure 21.7 This is a 64 64 pixel bitmap of the letter A. In this bitmap, all of the transparent pixels (the pixels that aren’t drawn) are white, and all the visible pixels are black. Think of the bitmap as a 2D array for a moment. You can see that a lot of the pixels in the bitmap repeat each other, which makes it ideal for RLE read more..

  • Page - 696

    652 21. Data Compression Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B, “The Memory Layout of a Computer Program.” To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix read more..

  • Page - 697

    653 Run Length Encoding The box labeled File size holds the size of the bmp file, in bytes. This information is not compressed in any way. The next box, RLE size, holds the number of runs that will be needed to store the image, using the current length of a run. The final box, byte size, shows the size of the actual RLE when it is compressed. Keep in mind read more..

  • Page - 698

    654 21. Data Compression The program should tell you that the bitmap is 4096 pixels. It should also tell you that it will take 206 runs to store the bitmap using an 8-bit length. Because an 8-bit length takes up 4 bytes per run, this bitmap will take up 824 bytes total to store in RLE form. That’s a nice compression right there because the actual a.bmp file read more..

  • Page - 699

    655 Run Length Encoding I only provided one bitmap that is smaller when you go up to the 16-bit length mode, and that is blank.bmp. This bitmap is a blank white 256 256 image. In 8-bit mode, there are 258 runs in the image, which take up 1,032 bytes. Switch to 16-bit mode, and the runs drop down to 2! In 16-bit mode, this takes up 10 bytes. Now take it read more..

  • Page - 700

    656 21. Data Compression Coding an RLE Compressor and Decompressor The file that contains all the RLE source code in this section is on the CD in the directory \structures\RLE.h. In this section, I take you through creating a generic RLE compressor and decom- pressor. The Structure The structure of the RLE class is simple; it will hold an array of runs. A run is read more..

  • Page - 701

    657 Run Length Encoding public: typedef RLEPair<DataType> Pair; Array<Pair> m_RLE; int m_runs; int m_size; } The RLE class is templated, so you can store any type of data in it. The only limita- tion is that the data type you use should support the comparison operator (==). The class has an array of pairs and keeps track of how many runs are in the array and read more..

  • Page - 702

    658 21. Data Compression int currentrun = 0; int index; The function is very simple and takes an array reference as a parameter. There are two local counting variables, one that keeps track of the current run and one that keeps track of the index in the uncompressed array. m_RLE[0].m_data = p_array[0]; m_RLE[0].m_length = 1; Because the RLE array is always at least read more..

  • Page - 703

    659 Run Length Encoding currentrun++; if( m_RLE.m_size == currentrun ) m_RLE.Resize( currentrun * 2 ); m_RLE[currentrun].m_data = p_array[index]; m_RLE[currentrun].m_length = 1; } If the next item in the uncompressed array is the same as the item in the current run, the function increases the length of the current run. However, it is not that simple. First, the function needs read more..

  • Page - 704

    660 21. Data Compression This function also takes an array reference. The array will be overwritten with the RLE data, so don’t pass in an array of data that you want to keep. If the array is too small, then it is resized so it is large enough to hold the uncom- pressed RLE. int currentrun; int index; int offset = 0; The first variable serves the same purpose read more..

  • Page - 705

    661 Run Length Encoding The SaveData Function Most of the time, you want to compress your data and then store it onto disk some- where, so you want to have a function that can save the data easily. This function will use the standard C++ file I/O functions. If you are unfamiliar with them, please see Chapter 3, “Arrays,” or Appendix A, “A C++ Primer.” void SaveData( read more..

  • Page - 706

    662 21. Data Compression If the RLE array is too small to hold the compressed RLE data, it is resized to hold the data. fread( m_RLE.m_array, sizeof(Pair), m_runs, file ); fclose( file ); } Finally, the compressed RLE data is read into the RLE array, and the file is closed. Example 21-1 This is Example 21-1, which you can find on the CD in the directory read more..

  • Page - 707

    663 Run Length Encoding original.ReadFile( filename ); compressed.Compress( original ); The file is then read in and compressed. strcat( filename, “.rle” ); compressed.SaveData( filename ); Using the strcat function, .rle is added to the end of the file name, and the RLE data is then saved to disk using that file name. cout << “Original File Size: “ << read more..

  • Page - 708

    664 21. Data Compression I’ve provided four test files to use, test1.txt, test2.txt, test3.txt, and test4.txt. Each of these files demonstrates something, so I urge you to open them and see what they look like. The first file contains 26 different letters repeated a random number of times in a row. This file compressed nicely with about a 38:1 compression ratio. Test2.txt read more..

  • Page - 709

    665 Huffman Trees Then the RLE data is loaded from the file and then decompressed into the array. dataname[ strlen(dataname) - 4 ] = 0; uncompressed.WriteFile( dataname ); cout << “Decompressed to “ << dataname << endl; } The last four characters are chopped off of the filename (it is assumed that the file- name will end with the four characters .rle, which is read more..

  • Page - 710

    666 21. Data Compression Figure 21.10 Here is a simple Huffman tree. So what the heck do you do with this? Imagine you have a binary message: 0100111110. Place your finger on the root node of the tree. You read the binary message in, one bit at a time. Whenever you read in a 0, you move your finger to the left child of the current node, and whenever you read more..

  • Page - 711

    667 Huffman Trees Figure 21.12 Here is a larger Huffman tree. This time, the message is: 000 1111 001 001 111 1001 110 000 101 0111 110 0100 0101 1111 110 1000 101 0110 1110. See if you can decode it accurately. SP means “space” and CM means “comma,” by the way. The answer is “hello, how are you?” Pretty simple, isn’t it? Creating a Huffman Tree The read more..

  • Page - 712

    668 21. Data Compression You see, just like RLEs, certain Huffman trees may actually end up making your files bigger. Each Huffman tree is optimized for a certain set of data. The tree in Figure 21.12 was optimized for the phrase “hello, how are you?” Table 21.1 shows the frequency table for that phrase. Character A 1 E 2 H 2 L 2 O 3 R 1 U 1 W 1 Y 1 read more..

  • Page - 713

    669 This is the initial Huffman Trees Figure 21.13 priority queue. I will be referring to the frequency of the nodes as the weight of the nodes from now on. Now comes the actual tree generation algorithm, which is really quite simple: 1. Take the first node off of the priority queue. 2. Take the second node off of the priority queue. 3. Create a new binary read more..

  • Page - 714

    670 21. Data Compression Figures 21.15, 21.16, 21.17, 21.18, and 21.19 show the complete algorithm. The last tree in Figure 21.19 is the same as the tree in Figure 21.12. Figure 21.15 These are the second and third iterations. Team LRN read more..

  • Page - 715

    671 Huffman Trees Figure 21.16 These are the fourth and fifth iterations. Team LRN read more..

  • Page - 716

    672 21. Data Compression Figure 21.17 These are the sixth and seventh iterations. Note how these iterations are the first to combine trees instead of just the single nodes. Team LRN read more..

  • Page - 717

    673 Huffman Trees Figure 21.18 These are the eighth and ninth iterations. Team LRN read more..

  • Page - 718

    674 21. Data Compression Figure 21.19 These are the tenth and eleventh iterations.These are the last two iterations of the algorithm. Graphical Demonstration: Creating a Huffman Tree This is Graphical Demonstration 21-2, which is on the CD in the directory \demon- strations\ch21\Demo02 - Huffman Tree Creation\ . Team LRN read more..

  • Page - 719

    675 Huffman Trees Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B. To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix B. If you create your own project, all of the files read more..

  • Page - 720

    676 21. Data Compression Figure 21.20 shows a screenshot from the demo. Figure 21.20 Here is a screenshot from the demo. Coding a Huffman Tree Class This section takes you through the cod- ing of a Huffman compressor and decompressor class. All of the code is located in the file \structures\huffman.h on the CD. You’ll note that this class builds upon and uses many read more..

  • Page - 721

    677 Huffman Trees template<class DataType> class HuffmanNode { public: DataType m_data; unsigned long int m_code; int m_codeLength; }; Each node has an instance of data in it, m_data, so you know which item the node represents when encoding and decoding. After that, the node has an unsigned long int that stores the actual Huffman code to get to the node. I used this read more..

  • Page - 722

    678 21. Data Compression The Frequency Comparison Function Because you’re using a heap to store the data, you need a comparison function to get the heap to work. If you remember back to an earlier section, the priority queue needs to put the items with the lowest frequency first: template<class DataType> int CompareNodes( BinaryTree< HuffmanFrequency<DataType> >* left, read more..

  • Page - 723

    679 Huffman Trees There are three typedefs, which exist to make your life easier. Instead of referenc- ing a node in the Huffman tree as BinaryTree< HuffmanFrequency< DataType > >, you can just type TreeNode instead. Typedefs, if you haven’t noticed yet, make code easier to write and understand. Bitvector m_compressedData; int m_dataLength; int m_compressedLength; First, there read more..

  • Page - 724

    680 21. Data Compression structure. This way, you don’t need to search the tree for each item you want to compress. The Constructor The constructor sets up the data in the Huffman structure. Huffman() : m_compressedData( 1 ), m_huffmanTree( 1 ), m_lookupTable( MaxValue + 1 ) { m_dataLength = 0; m_compressedLength = 0; m_maxEntry = 0; } It initializes the compressed data read more..

  • Page - 725

    681 Huffman Trees frequencyTable[index] = 0; } for( index = 0; index < p_array.Size(); index++ ) { frequencyTable[ p_array[index] ]++; } The first step is to clear the frequency table directly to all 0s and then calculate the frequency of each item in the array. Whenever an instance of a particular data item is found, its entry in the frequency table is incremented read more..

  • Page - 726

    682 21. Data Compression parent->m_left = left; parent->m_right = right; parent->m_data.m_frequency = left->m_data.m_frequency + right->m_data.m_frequency; heap.Enqueue( parent ); } This is the function that actually calculates the Huffman tree. It takes off the first and second items from the heap and puts them into the left and right node point- ers. It then creates a new read more..

  • Page - 727

    683 Huffman Trees int codeindex; int codelength; unsigned long int code; bool value; There are three looping index values. The index keeps track of the current index in the uncompressed array, the vectorindex keeps track of the current index in the bitvector while it is compressing the data, and the codeindex keeps track of the cur- rent bit in the code for the read more..

  • Page - 728

    684 21. Data Compression 4, “Bitvectors,” or Appendix A if you are unfamiliar with bit-extraction.) After that bit is extracted, it is then set in the bitvector, and the vector index is incremented. m_compressedLength = vectorindex; m_dataLength = p_array.Size(); } Finally, the length in bits of the bitvector and the length in items of the uncom- pressed array are both recorded read more..

  • Page - 729

    685 Huffman Trees The value of the current bit is extracted from the bitvector, and then the tree index is moved down to the correct child node, depending on the value of the bit. Remember back to Chapter 12, when I showed you how to traverse a binary tree when it is an array? To go to the left child, you multiply the index by 2, and to go to the right read more..

  • Page - 730

    686 21. Data Compression This function will save the tree to disk for you. void SaveTree( char* p_name ) { FILE* file = fopen( p_name, “wb” ); First the file is opened in binary writing mode fwrite( &m_maxEntry, sizeof(int), 1, file ); The size of the tree is stored to disk first. fwrite( m_huffmanTree.m_array, sizeof(Node), m_maxEntry, file ); fclose( file ); } And read more..

  • Page - 731

    687 Huffman Trees FILE* file = fopen( p_name, “wb” ); fwrite( &m_dataLength, sizeof(int), 1, file ); fwrite( &m_compressedLength, sizeof(int), 1, file ); The file is again opened for binary writing, and the size of the uncompressed data and the compressed data are both saved into the file. fwrite( m_compressedData.m_array, sizeof(unsigned long int), (m_compressedLength / 32) + 1, read more..

  • Page - 732

    688 21. Data Compression fclose( file ); } Finally, the compressed data is loaded into the bitvector. Converting the Binary Tree to an Array Earlier, I told you that you would be converting the binary tree to an array so you can store it to disk easily. This function and the next one after it are the two func- tions that actually convert the tree into an array. read more..

  • Page - 733

    689 Huffman Trees The maximum entry index is cleared to 0, and then the entire tree has its codes and code lengths set to 0, which means that those nodes are all invalid. Convert( p_tree, 1, 0, 0 ); } Finally, the recursive Convert function is called on the root node. I explain the Convert function in the next section. The Convert Function The previous function, read more..

  • Page - 734

    690 21. Data Compression m_huffmanTree[p_index-1].m_codeLength = p_length; } The first thing the function does is check to see if the current node is a leaf node (it has no children). If so, then it needs to set the max entry variable to the current index, as it is now the maximum entry in the tree array. Remember, the tree might not actually fill up, so this read more..

  • Page - 735

    691 Huffman Trees If there is a right child, the Convert function is called on that child. This time, the index is two times the current index plus one, and the length is incremented again. Because a 1 is added to the end of the current code, the bit setting algorithm is used to add a new bit at the current length of the code (see Chapter 4 or Appendix A read more..

  • Page - 736

    692 21. Data Compression In fact, the entire example is exactly the same, save for these lines: compressed.CalculateTree( original ); compressed.Compress( original ); strcat( filename, “.tree” ); compressed.SaveTree( filename ); filename[ strlen(filename) - 5 ] = 0; strcat( filename, “.huff” ); compressed.SaveData( filename ); The lines in bold are new in this demo; the lines that read more..

  • Page - 737

    693 Data Encryption If you’ve got a hex editor handy, you can open the plasma2.bmp.tree file that was produced and take a look at it; it is almost entirely composed of 0s. This is clearly a waste of space. However, I don’t have the time to show you a better way of storing the trees right now, so I will leave you with this suggestion: RLE compress the tree read more..

  • Page - 738

    694 21. Data Compression Further Topics in Compression This chapter only gives you a very brief glimpse into the world of compression. There are tons of methods out there to compress data. One of the most exciting areas of compression is called fractal compression. A fractal is a geometrical object that exhibits repeating and recurring features. For example, if you look at read more..

  • Page - 739

    695 Conclusion To give you a better example of lossy compression, look at mp3 audio files. On the first level of mp3 compression, the higher frequencies of sound are removed from the sound file. Standard wave files can store very high frequency sounds that most people cannot hear, so the mp3 format removes this information, among other things. Don’t get the impression read more..

  • Page - 740

    This page intentionally left blank Team LRN read more..

  • Page - 741

    CHAPTER 22 Random Numbers Team LRN read more..

  • Page - 742

    698 22. Random Numbers Almost every game out there uses random numbers to simulate things, whether they are attributes, damage, shooting angles, or other elements. Therefore, random number generation is an important topic in game program- ming. If you already know a little about random numbers, you might want to skip the first few sections of this chapter. The last part of read more..

  • Page - 743

    699 Generating Random Integers In real life, a die is a random number gen- erator. You throw it, and it gives you a number from 1 to 6. The great thing about a die is that every side has an equal chance of coming up on top. The chance that you will get a 1 is 1/6, and the chance that you will get a 5 is also 1/6. This feature is known as an even read more..

  • Page - 744

    700 22. Random Numbers The third property is a trait of the C++ rand function. The MSVC6 version of rand repeats itself every 2 billion numbers. This number is called the period of the ran- dom number generator. For example, if you ask it for three random numbers and you get 3, 7, and 2, and then you ask it for 2 billion more numbers, and finally you ask for read more..

  • Page - 745

    701 Generating Random Integers Figure 22.2 Here is a screenshot from Example 22-1. Now run it again. Why does it return the same value? Isn’t it supposed to be ran- dom? Well, not quite. The algorithm that rand uses needs a seed value. A seed value is a special number that is used with linear congruency random num- ber generators that determines where the generator read more..

  • Page - 746

    702 22. TIP Random Numbers If you use a constant seed value every time you run the random generator, you will always get the same sequence of random numbers. Although this might seem like an undesirable effect at first, I prefer this behavior over a true random number generator.This method allows me to debug things very easily because I can use the same seed over read more..

  • Page - 747

    703 Generating Random Integers decimal. Well, that’s great and all—it gives me a huge range—but what if I want a random number between 1 and 6? What do I do then? There are two ways to generate a random number within a specific range. The first method, using modulo, is what has been used in this book up until this point. The other method uses division. Modulo read more..

  • Page - 748

    704 22. Random Numbers On the next line, I call rand and modulo it by the difference, which gives me a ran- dom number in the range of 0 through difference – 1. Now all that is left is to add the minimum value, and I have a random number in the correct range! That was a big leadup to such a small function, wasn’t it? Why This Is a Bad Method The read more..

  • Page - 749

    705 Generating Random Percents number, which is too big for most computers. So just remember not to use this function when you’re generating numbers with a range larger than 131,072. RAND_MAX + 1 in MSVC6 is 15 to rand rand NOTE Although the division in this algorithm at first appears to make the function slower than the modulo function, in reality, it is faster. a read more..

  • Page - 750

    706 22. Random Numbers The most important thing to remember is that you are dealing with floats here, so you need to convert the result from rand into a float and RAND_MAX into a float as well before you do the division, or else the compiler will think you are performing an integer division and return exactly 0 or 1, and nothing else. Generating Random Floats read more..

  • Page - 751

    707 Generating Non-Linear Random Numbers float difference = (p_max - p_min); return (RandomPercent() * difference) + p_min; } You can see that this is almost the same as the RandomRange function. On a test run, I received the following values when I asked for numbers from 1–6: 2.99789, 5.48180, 3.79229, 4.43303, 5.20530, and 1.21805. Generating Non-Linear Random Numbers Up read more..

  • Page - 752

    708 22. Random Numbers Figure 22.4 This is an even distribution graph. Every number has an equal chance of being generated if the random number generator has this distribution. If you take the height example from the previous section in the real world, you will probably end up with a graph that looks like Figure 22.5. See how the number of average-height people far read more..

  • Page - 753

    709 Generating Non-Linear Random Numbers Adding Two Random Numbers Now you need to find a way to generate a non-linear random distribution. Luckily, the easiest way is to add two random numbers. Say you add two random numbers, each of them ranging from 0–4, like this: int x = RandomRange( 0, 4 ) + RandomRange( 0, 4 ); Obviously, x will contain a number from 0–8, read more..

  • Page - 754

    710 22. Result 0 1/25 1 2/25 2 3/25 3 4/25 4 5/25 5 4/25 6 3/25 7 2/25 8 1/25 Random Numbers Table 22.1 Probabilities of Two Random Numbers from 0–4 Probability Percent 4 percent 8 percent 12 percent 16 percent 20 percent 16 percent 12 percent 8 percent 4 percent So, if you put this into a graph, you get a distribution that looks like Figure 22.7. Clearly, read more..

  • Page - 755

    711 Generating Non-Linear Random Numbers Adding Three Random Numbers If you’ve ever played Dungeons & Dragons, you might have wondered why they require you to roll three six-sided dice for your character attributes. The reason is that adding three random numbers gives you a random distribution that is very close to the bell curve. It is difficult to show the outcomes of read more..

  • Page - 756

    712 22. Random Numbers Figure 22.8 This is the distribution graph of adding three random numbers.This looks similar to a bell curve. Graphical Demonstration: Random Distribution Graphs I created a little program that will generate random distribution graphs for you. Figure 22.9 shows a screenshot of the program in action. The source code for this demo is on the CD in the read more..

  • Page - 757

    713 Conclusion Figure 22.9 Here is a screenshot of Graphical Demonstration 22-1. The demonstration works by adding four different random numbers together. On the left side of the screen, there are eight boxes representing the minimum and maximum values of each of the four different ranges. You can click on the boxes and type the numbers you want in them. The only thing read more..

  • Page - 758

    714 22. Random Numbers The Current text box contains the current number. You can move this forward and backward, and the two text boxes to the right will update themselves to show the percent value of the current number. In the example in the screenshot, the chance that the number 0 will be generated is 0.01 percent, and with 1,000 random trials, it was actually read more..

  • Page - 759

    CHAPTER 23 Pathfinding Team LRN read more..

  • Page - 760

    716 23. Pathfinding At last, you have reached the final algorithm in this book: pathfinding. Pathfinding is an important topic in game programming because almost all games use some sort of map system, and they need a method to move the units around on the maps. Be it role-playing games, first-person shooters, real-time strategies, or any other game with a map, they all read more..

  • Page - 761

    717 Basic Pathfinding In a game, you’ll know the coordinates of the goal and the coordinates of the player, too. You can figure out which direction the goal is in and move him toward it. Figure 23.2 shows this. Figure 23.2 The AI is heading toward the goal. The coordinates of the player and the goal are compared, and the computer notices that the goal has a read more..

  • Page - 762

    718 23. Pathfinding This time, you cannot simply move the player toward the goal because he cannot walk through the wall. You must find a better alternative. There are many simple (simple to code, at least) ways to get around this problem, but I don’t want you to spend too much time focusing on them. Random Bouncing This is the most basic method of pathfinding read more..

  • Page - 763

    719 Basic Pathfinding Figure 23.5 This is a map that will cause a random bouncer to become trapped. The random bounce algorithm will never find its way out of the little cove that it is in. Object Tracing Have you ever tried to solve a maze before? There is an old rule that will get you through the maze every time: Follow either the left wall or the right read more..

  • Page - 764

    720 23. Pathfinding Now, imagine you’re the little stick figure and you have to find your way to the square with the cross pattern in it. Although it is pretty easy to eyeball your way through this maze, think about it like a computer for a moment. How would you generate a solution for the maze that a computer would understand that would work every time? read more..

  • Page - 765

    721 Robust Pathfinding Figure 23.8 This shows how to use object tracing to get around an obstacle. While this method seems far more useful than other methods, it is still undesirable in games these days. This is because the algorithm needs to choose which way to go whenever it hits an obstacle, and either way may end up being the longer of the two routes. About half read more..

  • Page - 766

    the previous pointer. It tells each cell which cell pointed to it during the search. I make that clear in a moment. 1. Add the starting cell to the queue. 2. Mark the starting cell. 3. Take the first cell off of the queue. 4. If the cell is the goal, then the algorithm is complete. 5. If any of the children aren’t marked, set their previous pointer to the read more..

  • Page - 767

    723 Robust Pathfinding On the second iteration (see Figure 23.9.B), all eight surrounding cells of the start- ing cell are placed into the queue. The images don’t show it, but the cells are processed in clockwise order, starting with the top-most cell. On the third iteration (see Figure 23.9.C), the next layer of cells is processed, and so on. At the end of the last read more..

  • Page - 768

    724 23. Pathfinding Because of this flaw, the paths that a BFS pathfinder take tend to be more diagonal, because it treats all eight directions as the same length. The paths usually end up being longer and don’t look as good. There are two ways to fix this. Modifying the Visitation Order In the example I showed you previously, the adjacent cells are visited in read more..

  • Page - 769

    725 Robust Pathfinding The top path looks undesirable right away because it goes up and then down again. The bottom path looks much better, as it is just a straight line. The problem with this algorithm is that it sees both paths as being the same length, even though they are clearly not. Although changing the visitation order makes things a little better, there are read more..

  • Page - 770

    726 23. Pathfinding The third grid in Figure 23.14 shows the order in which cells are processed using their actual distance from the center. You can see that the cells are processed in a more radial fashion, so the pattern goes outward in a circle. So what does this mean? It means that this method is somewhat faster than a plain breadth-first search. First of all, read more..

  • Page - 771

    727 Robust Pathfinding Figure 23.15 shows a comparison of these two scenarios. Figure 23.15 Here are the search areas of the two different pathfinders. So which method is better? At a first glance, you can see that the distance-first search has a worse worst case than the breadth-first search, but there is one thing that the BFS neglects: weighted cells. Imagine for a read more..

  • Page - 772

    728 23. Pathfinding Compiling the Demo This demonstration uses the SDLGUI library that I have developed for the book. For more information about this library, see Appendix B, “The Memory Layout of a Computer Program.” To compile this demo, either open up the workspace file in the direc- tory or create your own project using the settings described in Appendix B. If read more..

  • Page - 773

    729 Robust Pathfinding The little guy on the map represents the starting place, and the X marks the goal. When your map is totally set up, click the Go! button, and watch it find your path! It’s a bit slow, isn’t it? Well, to fix that, click the Faster button a few times and watch it fly! If you want it to slow down again, click the Slower button. When read more..

  • Page - 774

    730 23. Pathfinding Play around with the demo a bit to try to get the hang of how the algorithm works. After the path has been found, it is shown with a bold red line. Coding the Distance-First Pathfinder This section will show you how to go about programming a distance-first pathfinder. All of the pathfinding algorithms can be found in the Pathfinding.h file in the read more..

  • Page - 775

    731 Robust Pathfinding The two integers are used as a pointer to point to the previous cell in the path. The last two variables determine if the cell is passable (if it is not, then it has an obstruction in it, like a wall or a tree) and the weight of the cell. The weight is defined as the amount of work it takes to walk into a particular cell. Using the read more..

  • Page - 776

    732 23. Pathfinding return 0; } This function compares the heuristic value of two Coordinates. This is a descending function, so it treats lower heuristic values as if they were actually higher. Again, you will see why this is used when the pathfinding function is described. Clearing the Cells Whenever a pathfinder function is called, the first thing it does is go through read more..

  • Page - 777

    733 Robust Pathfinding float CellDistance( int x1, int y1, int x2, int y2 ) { int dx = x1 - x2; int dy = y1 - y2; dx = dx * dx; dy = dy * dy; return (float)sqrt( (double)dx + (double)dy ); } This function uses the standard mathematical distance formula: distance = square root( dx 2 + dy 2 ), where dx and dy are the distance between the x and the y read more..

  • Page - 778

    734 23. Pathfinding x = x + DIRTABLE[direction][0]; y = y + DIRTABLE[direction][1]; For the second index, 0 means x and 1 means y. const float DISTTABLE[8] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.414214f, 1.414214f, 1.414214f, 1.414214f }; Finally, there is a table that stores the distance from a cell to an adjacent cell. The first four distances (for the N, E, S, and W read more..

  • Page - 779

    735 Robust Pathfinding Next, the queue is defined. Note that the queue isn’t a regular queue, but it is instead a priority queue heap. The heap is defined with a size of QUEUESIZE and the descending coordinate comparison function, which means that coordinates with the smallest heuristic value are always at the top of this queue. ClearCells( p_map ); c.x = p_x; c.y = read more..

  • Page - 780

    736 23. Pathfinding Figure 23.18 Some cells end up in the queue more than once.This is why it is important to mark them when they are removed from the queue the first time. The leftmost grid shows the processing of one cell, and the middle grid shows the processing of the cell above it. Now, if the first cell is processed, all of the dark cells are added to read more..

  • Page - 781

    737 Robust Pathfinding p_map.Get( ax, ay ).m_passable == true && p_map.Get( ax, ay ).m_marked == false ) { This large if statement checks many things. First of all, it checks to see if the adja- cent cell is within the bounds of the map. Sometimes the adjacent coordinates are invalid, so this is important. Then it checks to see if the adjacent cell is passable. read more..

  • Page - 782

    738 23. Pathfinding If the new distance is less than the distance through a different cell, then the func- tion needs to add the cell to the queue again. If the new distance is more than the existing distance, then nothing happens, and the adjacent cell is not added to the queue again. (Why bother looking into that path if a better path has already been found?) read more..

  • Page - 783

    739 Robust Pathfinding } } } } And finally, the adjacent node is added to the queue. That was a very long function, but when you think about it, the function isn’t really very complex. It follows the same basic formula as the 6-line description of the breadth-first search earlier in this chapter. Making a Smarter Pathfinder I want you to try something. Load read more..

  • Page - 784

    740 23. Pathfinding the goal is to your right—go that way! Don’t bother searching to the left, or up, or down!”? Figure 23.20 shows a screenshot of the demo after it has found the path. Pay attention to how much of the map has been searched. Figure 23.20 Almost all of the map is searched using this algorithm. The distance-first pathfinder is neat because it read more..

  • Page - 785

    741 Robust Pathfinding add 1 to the heuristic value. Then it would do the same thing to the y axis. Figure 23.21 shows this. Figure 23.21 This is a smart but simple heuristic. The center cell is the starting point. First, it processes the northern node. Because it gets closer in the y axis but the x axis stays the same, its heuristic is –1. Then the northeast read more..

  • Page - 786

    742 23. Pathfinding Figure 23.22 This is the second iteration of the algorithm. Again, all the surrounding cells have their heuristic values calculated, and the cell that moved the closest to the goal is again the lowest in the queue. This process continues, and the search moves toward the goal in a straight line, not bothering to search elsewhere. Isn’t that simple? read more..

  • Page - 787

    743 Robust Pathfinding Figure 23.23 Here is a screenshot of the demo. You can see that this pathfinding algorithm is smarter than the distance-first algo- rithm in terms of how much time it spends searching. Problems with This Pathfinder There are many problems with this pathfinder. First of all, it doesn’t take into account the weight of each cell, so it will not find read more..

  • Page - 788

    744 23. Pathfinding This is what I call the mutant-4 test—the walls look similar to a disfigured number 4. Note that the player starts off slightly higher than the goal, so the heuristic starts off trying to go south. After messing around in the little area where he started, he finds his way out around the bottom and under the goal. At this point, he is trying read more..

  • Page - 789

    745 Robust Pathfinding if( diff1 > diff2 ) h -= 1.0f; else if( diff1 < diff2 ) h += 1.0f; This is the part that determines the heuristic. If diff1 is greater than diff2, the adjacent cell is closer in the x axis, so 1.0 is subtracted from the heuristic. If, on the other hand, diff1 is less than diff2, then the current cell is closer to the goal on the read more..

  • Page - 790

    746 23. Pathfinding Making a Better Heuristic I want you to try something. Open up Graphical Demonstration 23-2 again and set up the map like in Figure 23.25. Figure 23.25 Set up the demo like this to test out the simple heuristic. Now click the Go! button. You’ll see the search start off toward the goal, which is good. Eventually it will hit the wall, so it read more..

  • Page - 791

    747 Robust Pathfinding Figure 23.26 The complete path went farther than you wanted it to go. That path looks quite dumb, don’t you think? The pathfinder didn’t really know any better, though. So it looks like you need a better pathfinder. To do this, you need to create a better heuristic function. Last time, the function judged each move based on if it got any read more..

  • Page - 792

    748 23. Pathfinding The cell with 5.00 has the lowest value, so it is processed first, creating the map in Figure 23.28. Figure 23.28 Here is the second iteration of the algorithm. Whereas the simpler heuristic treated all moves that moved toward the goal as the same value, this heuristic treats cells that are physically closest to the goal as the best choice. Graphical read more..

  • Page - 793

    749 Robust Pathfinding Figure 23.29 Here is a screenshot of the complex heuristic solving the cove problem. Problems with This Heuristic Unfortunately, this heuristic has problems as well. This one also fails the mutant-4 test and makes the path go around the 4 the long way (see Figure 23.24 for refer- ence). This is because these two pathfinders don’t take into account read more..

  • Page - 794

    750 23. Pathfinding The New Heuristic Function This heuristic function will return the amount of distance from the adjacent cell to the goal. float ComplexHeuristic( int x, int y, int gx, int gy, int dir ) { x = x + DIRTABLE[dir][0]; y = y + DIRTABLE[dir][1]; return CellDistance( x, y, gx, gy ); } The first two lines calculate the coordinates of the adjacent cell, read more..

  • Page - 795

    751 Robust Pathfinding In games, finding the shortest path from any two points is somewhat important. Although it is usually more important to get a faster pathfinder, you also don’t want it doing the stupid things that the simple and complex heuristic pathfinders did. So now you go back to the drawing board and try to make a better heuristic func- tion. You see that read more..

  • Page - 796

    752 23. Pathfinding The second path is dotted. It only takes 2.0 units to get to that cell, so a distance- first pathfinder would prefer this cell over the first one. However, the A* pathfinder estimates that the path from that cell to the goal will take 6.32 units, which means that this cell has a heuristic of 8.32 units. So the first cell is the winner in this read more..

  • Page - 797

    753 Robust Pathfinding c.heuristic = ComplexHeuristic( x, y, p_gx, p_gy, dir ); To turn this into an A* pathfinder, you just need to add one thing to those lines: c.heuristic = ComplexHeuristic( x, y, p_gx, p_gy, dir ) + distance; And that’s it. See, I told you it was easy. Graphical Demonstration: Path Comparisons This is Graphical Demonstration 23-5, which is on the read more..

  • Page - 798

    754 23. Pathfinding Figure 23.33 Here are the four solutions to the Mutant-4 map. At the top left is the distance-first search, at the top right is the simple-heuristic, at the bottom left is the complex-heuristic, and at the bottom right is the A* search. Play around with this program; it will give you a good idea of the strengths and weaknesses of each of the read more..

  • Page - 799

    755 Weighted Maps Figure 23.34 Here is an example map for a tank game. Each of these regions would be weighted differently. The grass and dirt sections would have a weight of, say, 1.0, which is the base weight. Then, the rocks would have a weight of 2.0, which means that the pathfinder will treat moving through one rock tile as the same amount of effort as moving read more..

  • Page - 800

    756 23. Pathfinding Now, Figure 23.36 shows a screenshot of the path taken through that map. Figure 23.36 Here is the path that the pathfinder takes. Study the path for a moment. The path spends as much time as possible in the grassy region first, and then it cuts through a tiny area of rocks. After that, it takes the shortest straight path through the water, read more..

  • Page - 801

    757 Weighted Maps dense forest and most likely to be seen on the paved road. Table 23.2 shows a list- ing of the weights for each terrain type. 4.0 8.0 Grassland 12.0 16.0 20.0 Impassable Table 23.2 Terrain Weights Terrain Weight Dense Forest Light Forest Dirt Road Paved Road Stone Wall To prevent being caught, you would be advised to stay in the forest areas as read more..

  • Page - 802

    758 23. Pathfinding Then there are two sets of coordinates: the goal position and the current position of the player. Finally, there is a boolean, which determines whether the player is moving. Loading and Saving the Map The map is stored on disk, so you can load it up, modify it, and then save it back to disk. Here are the routines that load and save the map read more..

  • Page - 803

    759 Weighted Maps Now, the A* pathfinding algorithm is called on the map, so it will trace a path from the current position to the goal. After this call, the path is stored in the map within the m_lastx and m_lasty variables of each cell. x = g_goalx; y = g_goaly; Now, to convert the path into a list of coordinates, you need to reverse the path on the map read more..

  • Page - 804

    760 23. Pathfinding if( g_xmovement.Count() == 0 ) { g_moving = false; } else { g_currentx = g_xmovement.Top(); g_currenty = g_ymovement.Top(); g_xmovement.Pop(); g_ymovement.Pop(); } If the size of the stacks is zero, then the path has been traced, and the movement is halted. If not, then the current position of the player is updated by getting the next coordinates off the read more..

  • Page - 805

    761 Weighted Maps Press the S key on your keyboard to place the player’s start position where your mouse cursor is pointing (represented by a red square). Press the G button on your keyboard to place the goal on the map (represented by a blue square). To get the player moving, just press the Spacebar on your keyboard, and the player will begin his long trek read more..

  • Page - 806

    762 23. Pathfinding Table 23.4 Keys Key Terrain 0 Dense Forest 1 Light Forest 2 Grass 3 Dirt Road 4 Paved Road 5 Stone Wall Thinking Beyond Tile-Based Pathfinding Lets face it; many games are not tile based. But tile-based pathfinding is so easy that it sometimes ends up deciding what kind of game engine you will use. If, however, you end up creating a game engine read more..

  • Page - 807

    763 Thinking Beyond Tile-Based Pathfinding Figure 23.38 Line pathfinding tries to find a line straight to the goal. Unfortunately, this method doesn’t work for maps with obstacles. Of course, you could use a random bouncer to move around obstacles, but that doesn’t usually work well. Whenever you have an obstacle in a map like this, you could pre-generate a path around read more..

  • Page - 808

    764 23. Pathfinding To optimize this method, perhaps you could also store the lengths of each line in the path and figure out which way around the path is the shortest to get to the other side. Quadtrees Oh, no! Not trees again! Trust me, trees are amazing wonderful structures that can do almost anything, even your laundry. Okay, maybe not your laundry, but read more..

  • Page - 809

    765 Thinking Beyond Tile-Based Pathfinding then you can remove that branch of the tree. When the lowest level is complete, go up to the next level and continue removing nodes, but only if all four branches of each node go down to the same level. Eventually, you will end up with a quadtree that looks like the one in Figure 23.41. Now you have all these nodes that read more..

  • Page - 810

    766 23. Pathfinding Figure 23.42 The dots in this map store item waypoints, and the AIs follow the lines to get to the item they want. Now, all the points are connected together using lines, and a graph is formed. Each of the points on the graph is called a waypoint. When you want to find a path through this map, you get to the closest waypoint and then read more..

  • Page - 811

    767 Conclusion for( all 8 directions ) if( adjacent node not marked ) q.Enqueue( adjacent node ) adjacent node.previous = current end if end for end while end Function Now, to adapt this algorithm to linked graphs, you just need to change one thing. Change this: for( all 8 directions ) To this: for( each linked node ) And the algorithms fit perfectly. Conclusion read more..

  • Page - 812

    This page intentionally left blank Team LRN read more..

  • Page - 813

    CHAPTER 24 Tying It Together: Algorithms Team LRN read more..

  • Page - 814

    770 24. Tying It Together: Algorithms This is it! The final chapter! By now, you should be well acquainted with all of the data structures and algorithms in this book and with the Adventure game that is developed in Chapters 9, “Tying It Together: The Basics,” 16, “Tying It Together: Trees,” and 19, “Tying It Together: Graphs.” This final chapter shows you read more..

  • Page - 815

    771 Making the Enemies Smarter with Pathfinding The AI in the figure will stand there, like a 4-bit calculator, just looking at you. He won’t go and attack you or anything else. The GetClosestDirection function I implemented for those demos was simple, fast, and stupid. It just tried to figure out which direction a person should move in order to get closer to the read more..

  • Page - 816

    772 24. Tying It Together: Algorithms However, when I build the Adventure demo, the player is limited to 4-direction movement; diagonals are not allowed in the demo. Unfortunately, this means that the PathAStar function cannot be reused on this class, and I will need to code a new function that performs the same algorithm. The Consequences of a Bad Design The fact that read more..

  • Page - 817

    773 Making the Enemies Smarter with Pathfinding The Coordinate Class and Comparison Function If you remember the algorithm from Chapter 23, then you also remember that I needed an extra class to store information about the cells that are in the priority queue and their current heuristic value. Also, because the Heap class (which is act- ing like the priority queue) needs to read more..

  • Page - 818

    774 24. Tying It Together: Algorithms int m_lastx; int m_lasty; This data is virtually identical to the data found in the Cell class from \structures\pathfinding.h. Each cell knows if it has been marked, its distance from the starting cell in the map, and the coordinates of the previous cell in the path. If any of this information is unfamiliar to you, please, go read more..

  • Page - 819

    775 Making the Enemies Smarter with Pathfinding y = y + DIRECTIONTABLE[dir][1]; return Distance( x, y, gx, gy ); } The Distance NOTE function is just a small helper function, which you have seen previ- ously in a few demos. The AStar Function Because this algorithm has been discussed in depth in the previous chapter, there really isn’t a need to explain the entire read more..

  • Page - 820

    776 24. Tying It Together: Algorithms When the function starts, the queue should be empty. When the A* pathfinder fin- ishes, there might still be cells in the queue that weren’t emptied out. This line sets the count of the heap to 0, which makes the queue think that it is empty. // clear the cells first. ClearCells(); // enqueue the starting cell in the read more..

  • Page - 821

    777 Making the Enemies Smarter with Pathfinding The previous line is somewhat important. In the PathAStar function from Chapter 23, the pathfinder determined if it could go through a cell solely by accessing an m_passable variable in each cell. Although the TileCell class has a similar variable (m_blocked), the game is generally more complex than the old pathfinder could handle. read more..

  • Page - 822

    778 24. Tying It Together: Algorithms else { // set the links and the distance. m_tilemap.Get( ax, ay ).m_lastx = x; m_tilemap.Get( ax, ay ).m_lasty = y; m_tilemap.Get( ax, ay ).m_distance = distance; // add the cell to the queue. c.x = ax; c.y = ay; c.heuristic = distance + Heuristic( x, y, p_two->GetX(), p_two->GetY(), dir ); queue.Enqueue( c ); } } } } } } The read more..

  • Page - 823

    779 Making the Enemies Smarter with Pathfinding while( x != p_one->GetX() || y != p_one->GetY() ) { lx = x; ly = y; x = m_tilemap.Get( lx, ly ).m_lastx; y = m_tilemap.Get( lx, ly ).m_lasty; Remember, once the A* pathfinder is complete, you need to start at the goal and backtrack through the path. To find out which direction to move, you need to backtrack read more..

  • Page - 824

    780 24. Tying It Together: Algorithms Adding Pathfinding to the DirectionMap Class Adding pathfinding to the DirectionMap class is similar to adding pathfinding to the TileMap class. similar to the NOTE Keep in mind what I said earlier about how you should be careful about duplicat- ing code.The fact that the pathfinder for the directionmap is very one for the tilemap read more..

  • Page - 825

    781 Making the Enemies Smarter with Pathfinding The New Data New data needs to be added to the DirectionCell class to use the A* pathfinder algorithm. The new data is similar to the data added to the TileCell class earlier, with one difference. bool m_marked; float m_distance; int m_lastcell; The two m_lastx and m_lasty variables have been replaced with just one read more..

  • Page - 826

    782 24. Tying It Together: Algorithms The AStar Function This function is almost exactly the same as the AStar function in the TileMap class. When reading through this code, you can go back and compare it with the tilemap version. Note that the x and y coordinate references have been replaced with cell number references. void AStar( Person* p_one, Person* p_two ) { read more..

  • Page - 827

    783 Making the Enemies Smarter with Pathfinding if( cell == p_two->GetCell() ) break; This is somewhat simpler in some parts, like the two lines of code listed previously. You only need to check to see if the cell number of the current cell and the goal cell are equal instead of comparing two sets of coordinates. // loop through each direction. for( dir = 0; read more..

  • Page - 828

    784 24. Tying It Together: Algorithms } else { // set the links and the distance. m_rooms[adjacentcell].m_lastcell = cell; m_rooms[adjacentcell].m_distance = distance; // add the cell to the queue. c.cell = adjacentcell; c.heuristic = distance + Heuristic( adjacentcell, p_two->GetCell() ); queue.Enqueue( c ); } } } } } } Overall, the code for the directionmap read more..

  • Page - 829

    785 Making the Enemies Smarter with Pathfinding cell = p_two->GetCell(); // loop through the path while the current cell // isn’t the goal. while( cell != p_one->GetCell() ) { // save the last cell number. lastcell = cell; // calculate the next cell number. cell = m_rooms[cell].m_lastcell; if( cell == -1 ) { // the path is unreachable, so return a read more..

  • Page - 830

    786 24. Tying It Together: Algorithms Figure 24.2 shows a simple map, which could either be a directionmap or a tilemap. It really doesn’t matter at this point. Figure 24.2 This is the process of the GetClosestCell function.The path is calculated from S to F; after that happens, the function backtracks from F to S. After the call to AStar has completed, the map has read more..

  • Page - 831

    787 Making the Enemies Smarter with Pathfinding To understand what is going on, you need to go and look at the game logic from Chapter 19 (in the file \demonstrations\ch19\Game01 - Adventure v3\g19-01.cpp). Look for the PerformAI function. In that function, you will see these lines of code: for( i = 0; i < g_peoplecount; i++ ) { if( g_peoplearray[i] != g_currentplayer ) { read more..

  • Page - 832

    788 24. Tying It Together: Algorithms Instead of calling this function every frame for every person, you want to call it only when you need a result from it. This requires several modifications. The Person’s Following Status Now that you have a decent pathfinder, you will want the people in the game to act more realistically. For example, in the old version, if you read more..

  • Page - 833

    789 Making the Enemies Smarter with Pathfinding The function starts off in much the same way as it did before by getting the coordi- nates of the player and storing them into x and y and starting a loop that will go through every AI in the game. It changes after that, though: dist = Distance( g_peoplearray[i], g_currentplayer ); if( dist > 10.0f ) { read more..

  • Page - 834

    790 24. Tying It Together: Algorithms if( dist <= 1.0f && p_time - g_peoplearray[i]->GetAttackTime() > g_peoplearray[i]->GetCurrentWeapon()->GetSpeed() ) { direction = g_currentmap->GetClosestDirection( g_peoplearray[i], g_currentplayer ); g_peoplearray[i]->SetDirection( direction ); Attack( g_peoplearray[i] ); } } } } If the distance is less than or equal to one, then the AI is read more..

  • Page - 835

    791 Conclusion each AI only calculates a path once every 750 milliseconds, which is the amount of time before each AI moves around. Overall, the pathfinding in this demo is smart yet efficient because you really aren’t searching a large area (most searches are in an area smaller than 10 cells), and searches don’t happen too often. Playing the Game The game demo read more..

  • Page - 836

    792 24. Tying It Together: Algorithms you’ve learned in this book to a game. You can use stacks to create a menu system in the game, bitvectors to implement a quicksave, queues to store commands for the player, hash tables to store resource data, and so on. You could use binary trees to make a simple scripting system or add a sorting algorithm to the items in read more..

  • Page - 837

    Conclusion Team LRN read more..

  • Page - 838

    794 Conclusion Congratulations! You have just completed the main part of this book! Do you know everything there is to know about data structures and algorithms? Well, of course not; no one does! This book shows you only a tiny fraction of the world of data structures and algo- rithms. Yes, there is a lot of information that you need to absorb to fully under- stand read more..

  • Page - 839

    795 Further Reading and References Further Reading and References When writing this book, I referenced many other books and sources of informa- tion. I must admit, I learned quite a bit about some of the things I wrote about. This just goes to show that we are constantly learning and we should never stop. Data Structure Books When researching the data structures and read more..

  • Page - 840

    796 Conclusion The Art of Computer Programming By Donald Knuth (ISBN 0-201485-41-9) This is actually a set of three books, and it is considered the bible of data structures and algorithms. Again, this is a more academic book, but it contains almost every- thing you will ever want to know about the topics. Effective STL By Scott Meyers (ISBN 0-201749-62-9) This is a great read more..

  • Page - 841

    797 Further Reading and References C++ How to Program By Deitel & Deitel (ISBN 0-130895-71-7) This is a very popular introduction to C++ programming, and it has a lot of infor- mation. Most notable about this book is that it has a large section on the STL, which is great for learning how to use it for the first time. Game Programming Books Of course, I can’t read more..

  • Page - 842

    798 Conclusion Game Scripting Mastery By Alex Varanese (ISBN 1-931841-57-8) This book is all about game scripting. I hinted on this subject a little bit in Chapter 12, with the arithmetic parser game demo. This book will expand upon those con- cepts and give you a great deal of information on game scripting, virtual machines, and all that great stuff. AI Techniques for read more..

  • Page - 843

    PART SIX Appendixes Team LRN read more..

  • Page - 844

    Appendix A Appendix B Appendix C Appendix D A C++ Primer The Memory Layout of a Computer Program Introduction to SDL Introduction to the Standard Template Library Team LRN read more..

  • Page - 845

    APPENDIX A A C++ Primer Team LRN read more..

  • Page - 846

    802 A. A C++ Primer This is an intermediate-level book, and I use some complex features in it. You should probably know most of them, but no one is perfect, and you might have forgotten something. That is why this Appendix is here. If I use something you have forgotten how to use or something you have never learned, this Appendix will give you a little overview read more..

  • Page - 847

    803 Basic Bit Math When you think about a decimal num- ber, what do the digits actually mean? Take the number 1,234 for example. Start from the right. The 4 is in the ones column, so that represents 4 items in the real world. The 3 in the number is in the tens column, which represents 30 items. The 2 in the number is in the hundreds column, and the 1 is read more..

  • Page - 848

    804 A. A C++ Primer Figure A.1 This is an empty binary number.The base value for each cell is written underneath the cell. After that, you need to first find the largest power of two that is smaller than or equal to the number. So if the num- ber was 512, the largest power of two smaller than or equal to that is 512. However, if the number was 511, the read more..

  • Page - 849

    805 Basic Bit Math Computer Storage When dealing with computers, a single bit is usually too small to do anything useful with. So early on, computers bunched bits together in groups. First, they were grouped into bunches of four bits, and these were called nibbles. These could store numbers from 0–15 (remember, 2 4 1 is 16 1, or 15). Although they are more useful read more..

  • Page - 850

    806 A. A C++ Primer Unsigned Signed Bit 0 to 1 -1 to 0* Nibble 0 to 15 -8 to 7 Byte 0 to 255 -128 to 127 0 to 65,535 -32,768 to 32,767 0 to 4,294,967,296 -2,147,483,648 to 2,147,483,647 0 to 18,446,744,073,709,551,616 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 Table A.1 Integer Data Sizes Type Word Double Word Quad Word *Negative bits aren’t really read more..

  • Page - 851

    807 Basic Bit Math Bitwise Math There is an area of math involved with binary numbers called Boolean math, named after its inventor, James Boole. The math operates on bits, and there are four basic Boolean operators: not, and, or, and xor. The first one, not, is a unary operator, which means that it operates on only one bit at a time. The other three are binary read more..

  • Page - 852

    808 A. A C++ Primer Likewise, if you and two integers, the bits in the resulting integer will be the value of the and operator on each of the pairs of bits in the two original integers. Figure A.4 shows how this works. Figure A.4 Here are the four Boolean operators used on bytes in C++. Every bit in the not operation is reversed. The only time any 1s appear read more..

  • Page - 853

    809 Basic Bit Math Bitshifting There is one last topic that I must discuss when dealing with bits: bitshifting. Bitshifting is the act of taking the bits in a number and shifting them all left or right. There are two types of bitshifting: You can either shift left or shift right. The idea behind this is amazingly simple. If you shift a number left, you just take read more..

  • Page - 854

    810 A. A C++ Primer So why would you want to bitshift numbers around? Chapter 4, “Bitvectors,” uses it a lot to gain access to the individual bits in an integer. It turns out that bitshifting is also a very quick way to do some mathematical tricks, such as multiplying and divid - ing by powers of two. Take the following binary number, for example: 1b. Now, read more..

  • Page - 855

    811 Standard C/C++ Functions Used in This Book Standard C/C++ Functions Used in This Book C/C++ is much more than just a programming language. It also comes with a huge collection of built-in functions, a lot of which I use throughout this book. I show you the most popular ones here as a quick reference guide. All of the header files listed in this section come with read more..

  • Page - 856

    812 A. A C++ Primer “Hello!” and streams it into cout, which is just a big buffer that holds characters of text. The endl constant, when streamed into cout, tells the buffer to end the cur- rent line by inserting a newline character and then flushing the buffer. When the buffer is flushed, all of its contents are printed to the screen. If you don’t flush cout read more..

  • Page - 857

    813 Standard C/C++ Functions Used in This Book When you are typing into a console screen, the only time it is flushed is when you press Enter. However, using cin can sometimes give you unexpected results. For example, say you’re executing the previous two lines of code. When the second line is executed, the program stops and waits until the input buffer is flushed. read more..

  • Page - 858

    814 A. A C++ Primer then the variables x and y will contain 10 and 3.1415, respectively. That’s pretty much all you need to know for the input and output functions in this book. File I/O C++ provides a file library called file stream that is just like using cin and cout. However, I don’t really like that method of file I/O, and it is usually much easier read more..

  • Page - 859

    815 Standard C/C++ Functions Used in This Book The list of different modes is listed in Table A.6. Mode Meaning r fopen w a r+ fopen the file does not exist. w+ r+ a+ b* This opens the file in Table A.6 fopen Modes This opens the file for reading.The function will return 0 if the file can- not be found. This opens the file for writing. If a file already read more..

  • Page - 860

    816 A. A C++ Primer NOTE The linefeed/carriage return combination is a holdover from the bad old days when the very first computers were created and they used advanced typewriters to print their output (there weren’t any monitors!).Whenever you wanted to advance to the next line of output, you had to do two things: you had to move the roller so that the paper read more..

  • Page - 861

    817 Standard C/C++ Functions Used in This Book This function is demonstrated in a lot of the chapters in this book, most notably Chapters 3, “Arrays,” 4, “Bitvectors,” and 21, “Data Compression.” Reading from Disk If you want to read data from the disk, you can use the fread function, which has the same interface as fwrite: size_t fread( void* buffer, size_t size, read more..

  • Page - 862

    818 A. A C++ Primer Table A.7 lists most of the popular functions. Function Name Function Purpose abs( int x ) Computes the absolute value of x x y. x. sin( double x ) Computes the sine of x. cos( double x ) Computes the cosine of x. tan( double x ) Computes the tangent of x. asin( double x ) acos( double x ) atan( double x ) exp( double x )* x read more..

  • Page - 863

    819 Standard C/C++ Functions Used in This Book The function takes a pointer to a time_t structure and fills it in with the current time. It also returns the same value, which is kind of redundant. This is why I always pass 0 into the function when- ever it is called. The time_t structure is really just a typedef for an integer. This return value from this function read more..

  • Page - 864

    820 A. A C++ Primer Exceptions and Error Handling Although I don’t use exceptions anywhere in the book, they are mentioned quite a few times in reference to error checking code. Before exceptions came along, you had two basic methods to check for errors in your programs. You could use the ASSERT debug macro, or you could have your functions return an error code. read more..

  • Page - 865

    821 Exceptions and Error Handling Also, you end up with huge gobs of ugly code, 90 percent of which is dedicated to checking for errors: if( function() == error ) // handle error if( anotherfunction() == error ) // handle error if( yetanotherfunction() == error ) // handle error if( thelastfunction() == error ) // handle error If you’ve ever programmed in DirectX, you read more..

  • Page - 866

    822 A. A C++ Primer There are two new keywords defined that deal entirely with exceptions: the try key- word and the catch keyword. When you start a try block, the code inside of the block is monitored for exceptions. If any of the code inside throws an exception, the execution immediately jumps to the catch block, which will then handle the error. The benefits of read more..

  • Page - 867

    823 Why C++? stack unwinding this: Unhandled exception in module blah. NOTE If you don’t have a try block in a function and something it calls causes an excep- tion to be raised, then the exception is passed up along the hierarchy until it is caught or the program exits.This is called (see Appendix B, “The Memory Layout of a Computer Program,” for more read more..

  • Page - 868

    824 A. A C++ Primer ■ C compilers were generally faster than the relatively new C++ compilers. ■ C is a tried-and-true language. ■ C allowed you to interface more efficiently with low-level hardware. ■ C++ is complex. C is much easier to learn. ■ Older games were simple and didn’t need much organization. Look at some recent games, however. Games are no longer read more..

  • Page - 869

    825 Class Topics The compiler automatically creates a default constructor for you, which does absolutely nothing. Take the following class, for example: class Foo { public: int x; }; Now, whenever this class is constructed like this, nothing happens: Foo f1; Foo* f2 = new Foo(); Foo f3 = Foo(); All three of these functions are valid, and the second two make read more..

  • Page - 870

    826 A. A C++ Primer Foo f1; Foo* f2 = new Foo(); Foo f3 = Foo(); Foo f4( 5 ); Foo* f5 = new Foo( 5 ); Foo f6 = Foo( 42 ); The first three methods call the first constructor, and the second two meth- ods call the second constructor. There is another form of syntax used in constructors. Here is an example: constructor lines of f1 and f3 as the read more..

  • Page - 871

    827 Class Topics int* x; }; The class now has a pointer to an integer, and when it is created, a new integer from the free store is allocated and stored into x. (See Appendix B for more infor- mation about the free store.) When the object goes out of scope or is destructed, the destructor is called, and it deletes the integer. Look at the following code: void read more..

  • Page - 872

    828 A. A C++ Primer load the * operator of the Fraction class so that the compiler will automatically call the function whenever it sees one * two. Fraction& operator* ( const Fraction& p_frac ) { Fraction result; result.numerator = numerator * p_frac.numerator; result.denominator = denominator * p_frac.denominator; return result; } Fraction:: operator*. NOTE The operator function, read more..

  • Page - 873

    829 + / % += -= *= /= %= & | ^ &= |= ^= >>= <<= && || ! != == < > <= >= = , ~ [] () -> ->* new delete ++ — -, +, *& and and . Class Topics Table A.8 Operators That Might Be Overloaded -* >> << Some operators have two meanings.They are the , and operators. As unary operators, they don’t have a read more..

  • Page - 874

    830 A. A C++ Primer Bzzzt! Error! The compiler has no idea how to convert a String into a char*, so that last line will cause an error. This can be fixed, and you can tell the compiler how to convert a String into a char* using a conversion operator: operator char* () { return m_string; } The syntax is: operator <typename> (). Because the string in the read more..

  • Page - 875

    831 Class Topics However, there is another meaning to the word: the inline keyword in the C++ lan- guage. When a function uses the inline keyword, it looks like this: inline int Function() { return 50; } The meaning of the word inline here is completely different. In this case, it is telling the compiler that this function is pretty small and should be directly read more..

  • Page - 876

    832 A. A C++ Primer Function Pointers Function pointers are one of those features in C++ that are life savers, but they will also cause you to start cussing at your compiler. The idea of a function pointer is simple: It is simply a pointer that points to a function, rather than a variable. Using function pointers, you can have a variable that keeps track of a read more..

  • Page - 877

    833 Conclusion Then, during the game, all you need to do is this: DrawFunction(); Isn’t that neat? There are a few rules, however. A function pointer has a fixed return type and argument list, so it can only point to functions that have the same return type and argument list. Also, regular function pointers can only point to global functions; they cannot point to read more..

  • Page - 878

    This page intentionally left blank Team LRN read more..

  • Page - 879

    APPENDIX B Computer The Memory Layout of a Program Team LRN read more..

  • Page - 880

    836 B. The Memory Layout of a Computer Program To fully understand how a program works, you must first understand how it is structured. This is one topic that is almost always lacking in computer books, yet I consider it very important. Knowing how a program is structured is essential to understanding how to optimize a program, and this is especially important for game read more..

  • Page - 881

    837 The Code Memory Figure B.1 This is a sample memory layout for a computer that has two programs running. The Code Memory When you write a program in C++, it is just text stored in a .cpp file. The computer has no idea that this is a program. To make this text into a program, you tell your compiler to convert the program into commands that the processor read more..

  • Page - 882

    838 B. The Memory Layout of a Computer Program The Global Memory Everyone is familiar with global memory. It is usually the first place you store data in memory when you first start programming. Each program has its own global memory section (sometimes known as the data segment) where all the global data of a program is stored. Global Variables When you define read more..

  • Page - 883

    839 The Global Memory Figure B.3 This is the file layout of a program that uses g_integer and g_text. All numbers are in hexadecimal.The hexadecimal value 30 is the ASCII equivalent of the character 0, and so on. So the operating system creates the global memory section when it loads a pro- gram, and it loads all the global data from the file and places it into the read more..

  • Page - 884

    840 B. The Memory Layout of a Computer Program The Stack Up until now, the memory sections have been simple and straightforward. The stack in a computer program is probably the most complex part, though. If you are unfamiliar with how a stack works, please familiarize yourself with Chapter 7, “Stacks and Queues,” first. Every program has a stack, but it hasn’t read more..

  • Page - 885

    841 The Stack Figure B.4 The local variable is placed on the current top of the stack. Because this particular stack is empty, it is placed on the bottom. Now, whenever variable is referenced, the computer accesses that particular place on the stack. The neat stuff happens when you call function within itself: A differ- ent version of variable is placed on top of the read more..

  • Page - 886

    842 B. The Memory Layout of a Computer Program When the second function exits, its version of variable is popped off of the stack, and the end result looks exactly like Figure B.4. Parameters Parameters to functions are also placed on the stack. They are pushed onto the stack before the local variables are. Consider the following function: void function( int parameter read more..

  • Page - 887

    843 The Stack Return Values When a function returns a value from a function, it is also placed onto the stack. However, the return value is placed on the stack even before the parameters are placed on the stack. The computer makes space on the stack for the return value, even though the value won’t be filled in until the function returns. Take the following read more..

  • Page - 888

    844 B. The Memory Layout of a Computer Program CAUTION What happens when you try returning a pointer or a reference to a local vari- able or a parameter? You end up with some big bugs! If you try to return a point- er to a local variable, the pointer will not be valid, because the computer pops off the local variables when it returns. So you end up with a read more..

  • Page - 889

    845 Conclusion The other thing you need to worry about is memory leaks. When you allocate mem- ory from the free store and then never delete it, you end up with a memory leak. The computer will think that you’re using the memory, even if you aren’t, and this will cause large prob- lems if the program slowly leaks all of its memory. CAUTION Always delete memory read more..

  • Page - 890

    This page intentionally left blank Team LRN read more..

  • Page - 891

    APPENDIX C to SDL Introduction Team LRN read more..

  • Page - 892

    848 C. Introduction to SDL When I was trying to figure out how to demonstrate the examples for this book, I had originally just planned on making everything use the text-based console. How boring! I quickly realized that I needed to use a graphical API to demonstrate the nifty demonstrations you see throughout the book. I am very familiar with DirectX, but DirectX is a read more..

  • Page - 893

    849 Setting Up SDL 1. Include the source code for the version of SDL that you link with, as well as the full source or object code to your application so that the user can relink your application, 2. Include a written offer, valid for at least three years, to provide the materials listed in option 1, charging no more than the cost of pro- viding this distribution, read more..

  • Page - 894

    850 C. Introduction to SDL Contents Operating System prior to OS X. Operating System X. Table C.1 SDL Files on the CD Directory \Source Code\ This holds all of the source code to SDL in .zip format. \Development Libraries\ This holds all of the files you need to develop SDL applications. \Development Libraries\BeOS\ The development library for BeOS. \Development Libraries\Linux\ read more..

  • Page - 895

    851 Setting Up SDL libraries. For example, I keep mine in the directory D:\programming\SDL\ . You can put yours wherever you want. In that directory, you should have three subdirectories and a bunch of files; it should look like the screenshot in Figure C.1. Figure C.1 Here are the files that should be in your SDL directory. There are three directories, one con- read more..

  • Page - 896

    852 C. Introduction to SDL Options menu. Figure C.2 Here is the Tools, After you choose Tools, Options, click the Directories tab to bring up a screen that looks like Figure C.3. Figure C.3 Here is the Directories tab. Now that you have the window open to the Directories tab, make sure that the Platform drop-down list says Win32 and the Show directories for drop-down read more..

  • Page - 897

    853 Setting Up SDL After you have entered the name, press Enter, make sure your SDL include directory is highlighted, and then click the up-arrow button (next to the X in the figure) until your include directory is at the top of the list. Next, go to the Show directories for drop-down list and select Libraries this time. Now you will add another new directory to the read more..

  • Page - 898

    854 C. Introduction to SDL In this window, enter the name of your project in the Project name box and enter the directory it will be in in the box directly below it. Then select Win32 Application from the list on the left and click OK, and you’re almost there! When the window pops up asking you what kind of project you want to create, select An empty project read more..

  • Page - 899

    855 Setting Up SDL Figure C.6 Here are the code generation settings. Now that you have set the code generation settings, you must do one more thing. Go to the next tab over, Link. Go to the Object/library modules text box and enter the names of the two SDL library files, sdl.lib and sdlmain.lib. Figure C.7 shows this. Figure C.7 Here are the link settings. Now click read more..

  • Page - 900

    856 C. Introduction to SDL Setting Up SDL_TTF Unfortunately, SDL doesn’t have a built-in font library, so you cannot display text unless you build your own font library or use one that someone has already devel- oped. I have chosen the latter method and used the SDL_TTF add-on library. You can always find the newest version of the SDL_TTF library on the SDL Web read more..

  • Page - 901

    857 Setting Up SDL_TTF the same directory where I unzipped the base SDL library: D:\Programming\SDL\ . After you unzip it, your directory should look something like Figure C.8. Figure C.8 Here are the files in your SDL_TTF library directory after unzipping it. After you have done that, you need to set up Visual C++ to recognize your SDL_TTF directory. This is done the read more..

  • Page - 902

    858 C. Introduction to SDL Now Visual C++ recognizes the SDL_TTF library, but you have one more step to do. This next step must be performed for every project you create that uses the SDL_TTF library. Remember how you needed to add the sdl.lib and sdlmain.lib files to your project before? Now you need to add the sdl_ttf.lib file to your project. When your project read more..

  • Page - 903

    859 Using SDL The Structures There are several structures that are used frequently with the SDL_Video compo- nent. First, there is the SDL_Surface, which is really just a bitmap. These structures can hold bitmaps in any format, and the SDL drawing routines will draw them correctly. Then there are SDL_Rects, which are rectangles. These are often used in the draw- ing functions read more..

  • Page - 904

    860 C. Introduction to SDL That’s it! That’s all you need to set up the video component. Didn’t I tell you it was simple? Loading and Drawing Bitmaps If you’ve ever played around with the windows .bmp file format, you know how dif- ficult and awkward it is to work with. Not only is the data stored in BGR format (when almost everyone else uses RGB), but the read more..

  • Page - 905

    861 Using SDL Say, for example, that the bitmap surface is 64 64 pixels. The source rectangle starts at coordinates (0, 0) and has a size of 64 64, which means that the entire surface is going to be drawn. Then, the destination rectangle is set up. This time, its coordinates start at (32, 32), but the size still stays at 64 64. This means that you want read more..

  • Page - 906

    862 C. Introduction to SDL } // handle the game logic here } The SDL_PollEvent function fills in an SDL_Event structure with event information if an event has occurred and returns 1 if there are any events or 0 if there haven’t been any events. So if there were any events, then the function starts handling the input; otherwise, it just processes the game logic read more..

  • Page - 907

    863 Using SDL The function gets the mouse coordinates and stores them into two integers. Note that you must pass pointers into the function because the function physically modi- fies the integers that are passed in. You may also detect what key was pressed or released like this: if( event.key.keysym.sym == SDLK_ESCAPE ) SDL has a whole mess of key defines that you can read more..

  • Page - 908

    864 C. Introduction to SDL The NOTE point size of a font is the vertical size of a font.Traditionally, on paper, there are 72 points per inch vertically. However, every computer system uses a different measure to convert them to actual pixels, so you have to experiment with font sizes to see what is the best one to use. CAUTION Many TrueType font files are read more..

  • Page - 909

    865 The SDLHelpers Library screenshot of the letter C. On the left is a solid font; compare it to the anti-aliased font on the right. Figure C.11 The C on the left is drawn normally.You can easily see the sharp edges on a computer screen.The C on the right is drawn with anti-aliasing; the font blends into the background and makes it easier to read. The blended read more..

  • Page - 910

    866 C. Introduction to SDL So I decided to make my own functions that would automate some of the most common things that I needed to do in SDL. NOTE Because these functions are somewhat long and they don’t have any direct rela- tion to the book besides the fact that they are used in the graphical demos to demonstrate the data structures, I left the source code read more..

  • Page - 911

    867 The SDLFrame Figure C.12 Here is an example of the SDLArrowLine function. In the figure, a line is drawn between two circles. Both pairs of coordinates lie directly in the center of the circles, and the radius variables contain the size of the radius of each circle. The function automatically figures out how far away from the center of the circle it should be read more..

  • Page - 912

    868 C. Introduction to SDL const int HEIGHT = 480; // this is the main window for the framework SDL_Surface* g_window = 0; // main function int main( int argc, char* argv[] ) { // declare coordinates. int x, y; // declare event holder SDL_Event event; // initialize the video system. SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ); // set our at exit read more..

  • Page - 913

    869 The SDLGUI Library // a key was pressed. if( event.key.keysym.sym == SDLK_ESCAPE ) { // if ESC was pressed, quit the program. SDL_Event quit; quit.type = SDL_QUIT; SDL_PushEvent( &quit ); } } } // end event loop. // do all game-related stuff here. // update the entire window. SDL_UpdateRect( g_window, 0, 0, 0, 0 ); } // do game cleanup here // read more..

  • Page - 914

    870 C. Introduction to SDL The GUI class keeps track of every button, label, text box, and check box in the GUI, as well as all the fonts it will use. When you construct one, here is what it looks like: SDLGUI g_gui( 800, 600, 32, WHITE ); This constructs a GUI with a size of 800 600 that can hold a maximum of 32 GUI items (buttons and so on) and has read more..

  • Page - 915

    871 The SDLGUI Library pressed, it will call that function. This allows you to create buttons that will call whatever function you want (as long as it takes no parameters and doesn’t return anything) whenever the button is pressed! The other object types are all similar, with minor differences: void AddCheckbox( int p_x, int p_y, const char* p_up, const char* p_down, read more..

  • Page - 916

    872 C. Introduction to SDL All of these functions create the appropriate classes and add them to the GUI. All four GUI objects inherit from a class called SDLGUIItem. The Drawing Function Wrappers The GUI class doesn’t allow you to easily access the main surface, so I have included a few wrapper functions into it that use the standard SDLHelper drawing functions: Point, read more..

  • Page - 917

    873 The SDLGUI Library Whenever the mouse is pressed, you should call this function: void MouseDown( int p_x, int p_y ); The two parameters are the coordinates of the mouse when the mouse was pressed down. Likewise, there is a command that should be called whenever the mouse button is released: void MouseUp( int p_x, int p_y ); Finally, there is a function that should read more..

  • Page - 918

    874 C. Introduction to SDL This function, when called, will clear the background of the screen to the color that you set in the GUI’s constructor. Then it will go through every item in the GUI and draw each of them onto the screen surface. However, nothing will display on the screen if you only call this function. Therefore, the GUI also has a function that read more..

  • Page - 919

    875 The SDLGUI Library void ClickDown(); void ClickUp(); The next function is called whenever a key is pressed and the item is the one that the GUI is currently focused on: void KeyPress( SDLKey p_key, SDLMod p_mod, Uint16 p_char ); These parameters are the same as in the KeyDown function in the SDLGUI class. Whenever that function is called, it finds out what item read more..

  • Page - 920

    876 C. Introduction to SDL Considering that an item doesn’t know where the surface is, and you might want to draw items on other surfaces in the future anyway, you need to pass the surface in as a parameter. The SDLGUI Items I don’t post how to use any of the specific GUI items here because they aren’t really used directly in the Graphical Demonstrations read more..

  • Page - 921

    877 The SDLGUI Library // create the GUI and set the caption. g_gui = new SDLGUI( WIDTH, HEIGHT, ITEMS, WHITE ); SDL_WM_SetCaption( PROGRAM_NAME, 0); // add your GUI items here. // main message loop. while( 1 ) { // look for an event. if( SDL_PollEvent( &event ) ) { // an event was found. if( event.type == SDL_QUIT ) break; if( event.type == read more..

  • Page - 922

    878 C. Introduction to SDL // tell the GUI that a key was pressed. g_gui->KeyDown( event.key.keysym.sym, event.key.keysym.mod ); } } // end event loop. // do all game-related stuff here. // tell the GUI to redraw itself. g_gui->Draw(); // DO ALL YOUR RENDERING HERE. // tell the GUI to update itself. g_gui->Update(); } // do game cleanup here. // done. return 0; read more..

  • Page - 923

    APPENDIX D to the Standard Introduction Template Library Team LRN read more..

  • Page - 924

    880 D. Introduction to the Standard Template Library This book has three primary goals: ■ To teach you about the various data structures that exist ■ To show you how to code the data structures for yourself so you get hands-on experience seeing how they work ■ To instruct you on applying these data structures directly to computer games Most other data read more..

  • Page - 925

    881 STLPort Microsoft’s first try, after all) of the STL. (Apparently the STL in Microsoft Visual C++ .NET is much better; however, I have not had a chance to test it.) So, most of the time, people like to replace the compiler’s version of STL with a better and more standard version. The most popular of these is STLPort, which is a totally free version of STL read more..

  • Page - 926

    882 D. Introduction to the Standard Template Library actually build the IOStream portion into a compiled library file in order to use it, and quite frankly, that is a very complicated task that I still haven’t figured out how to do yet. So, to disable the IOStream portion, you need to go into the \stlport\ directory and find the file stl_user_config.h. When you find read more..

  • Page - 927

    883 Namespaces STL Equivalent 13 14 priority_queue 15 * 17 * 20 * 20 20 20 * 21 * 21 * 22 Random Number Generation * 23 * 23 Heuristic Pathfinder * deque . Chapter Data Structure/Algorithm Binary Search Tree set/multiset/map/multimap*** Heap Game Tree/Minimax Tree Graph Bubble Sort Heap Sort make_heap/sort_heap Quick Sort sort Radix Sort RLE Compression Huffman Compression read more..

  • Page - 928

    884 D. Introduction to the Standard Template Library Namespaces are a new feature in C++. They allow you to place variables, functions, and classes within a certain space so they don’t cause name collisions. For example, say you accidentally create two functions that do two totally different things, but they both have the same name: DoSomething. Normally, C++ will spit out read more..

  • Page - 929

    885 The Organization of STL Figure D.2 shows how the namespaces are separated from each other. Figure D.2 This is the orientation of namespaces; everything is in the global namespace by default, but putting something in a namespace separates it from the rest of the project. Now, whenever you want to access the function DoSomething from either of the libraries, you can read more..

  • Page - 930

    886 D. Introduction to the Standard Template Library structure as much as possible so that the algorithms are usable on as many data structures as possible. STL achieves this by using iterators extensively; I introduce the concept in Chapter 6, “Linked Lists.” STL has five categories of iterators related in the hierarchy shown in Figure D.3. Figure D.3 This shows the read more..

  • Page - 931

    887 Purpose Input Output tainer to access cells based on an index. The Organization of STL Table D.2 Iterator Categories Category These iterators can only be used to get data from a container. You cannot write data into an input iterator, and they can only move in one direction. These iterators can only write data into a container.You can- not read data from an output read more..

  • Page - 932

    888 D. Introduction to the Standard Template Library No Table D.3 Structure-Algorithm Support Can Structure Use Category Relationship Algorithm? Structure has higher iterator class than algorithm Yes Structure has same iterator class as algorithm Yes Structure has lower iterator class than algorithm STL separates the structures it has into several different categories as well. There read more..

  • Page - 933

    889 Containers Note that the only iterators in the table are bidirectional and random access; there are more classes in the STL that use the different iterator types (mainly IOStreams), but I don’t cover them at all in this book. Containers Every container class has a certain set of functions in STL. Table D.5 shows a listing of what they are and their purpose. read more..

  • Page - 934

    890 D. Introduction to the Standard Template Library Container Functions Function Purpose operator== operator< Determines if the contents of the left rbegin random access operator[I] Returns the element at index I. Table D.6 Forward, Reversible, and Random Access Container Type forward Determines if the contents of two con- tainers are equal and in the same order. forward read more..

  • Page - 935

    891 Containers Function Purpose erase( I ) (but not including E). clear Resizes container so that it contains N items. insert( I, N, D ) Inserts N copies of D into container before iterator I. Removes the item in the container pointed to by iterator I. erase( S, E ) Removes the items starting at iterator S and ending with iterator E Totally erases everything in read more..

  • Page - 936

    892 D. Introduction to the Standard Template Library Chapter 3, “Arrays.” A vector can automatically resize itself when you insert items into it. The STL vector class belongs to the back insertion sequence container category and also the random access container category, so that means it supports all of the functions for those two classes, as well as the sequence and read more..

  • Page - 937

    893 Containers array, so you can move it forward and backward, and dereference it. Also, take a look at the last line, the one that calls sort. The sort algorithm takes two random-access iterators and sorts everything between them, not including the item that the end iterator points to. So you can call the begin and end functions of the vector and pass them into sort, read more..

  • Page - 938

    894 D. Introduction to the Standard Template Library The deque class does not add any new functions, so it is the same as the vector but it is missing the capacity and reserve functions and has access to the front insertion sequence functions push_front and pop_front. Here is some code demonstrating deques: using namespace std; deque<int> d; deque<int>::iterator i; read more..

  • Page - 939

    895 Containers Function Purpose iterator I. unique merge( L ) O(nlog 2n Table D.10 List Functions splice( I, L ) All items inside of list L are removed from L and placed into the current list in front of iterator I. splice( I, L, F ) This removes the item pointed to by iterator F inside of list L and inserts it into the current list before iterator I. splice( read more..

  • Page - 940

    896 D. Introduction to the Standard Template Library l.sort(); // multiply each item by 2: for( i = l.begin(); i != l.end(); ++i ) { (*i) *= 2; } Associative Containers Associative containers differ from the sequence containers. All four of them have bi-directional iterators, but you cannot insert items into an associative container like you can with sequential read more..

  • Page - 941

    897 Containers s.pop(); // pop off 20 i = s.top(); // i should be 10 s.pop(); // pop off 10 // put 10 and 20 into the queue q.push( 10 ); q.push( 20 ); i = q.front(); // i should be 10 q.pop(); // pop off 10 i = q.front(); // i should be 20 q.pop(); Now, both the stack and the queue in this example use a deque as their base, but you can change read more..

  • Page - 942

    898 D. Introduction to the Standard Template Library As you can see from the example, the default implementation of a priority_queue uses vectors, but you can explicitly state that it should use vectors or deques. The priority queue class supports all of the stack functions: push, top, and pop. I guess they used top instead of front because you’re accessing the top of read more..

  • Page - 943

    899 Conclusion b >>= 3; // shift the bitset down by 3 b = ~b; // flip every bit The bitset also has other functions, which make your programs cleaner to read: b.reset(); // clear every bit to 0 b.set(); // sets every bit to 1 b.flip(); // flips every bit b.set( 10 ); // sets bit 10 b.set( 10, 0 ); // clears bit 10 b.reset( 10 ); // clears bit 10 read more..

  • Page - 944

    900 D. Introduction to the Standard Template Library includes documentation on non-standard containers that SGI has added in their version of the STL. The conclusion section of this book also contains a listing of helpful STL books. Team LRN read more..

  • Page - 945

    Index Symbols #define macros, 35 2D arrays. See also arrays data storage, 116-117 defined, 108-110 graphical demonstration, 111-112 initializing, 113 tilemaps, 131-136 3D arrays. See also arrays data storage, 117-118 defined, 108-110 tilemaps, 136-144 4D arrays, 117-118 A A* pathfinding, 750-752 code, 752-753 DirectionMap class, 780-785 graphical demonstration, 752 read more..

  • Page - 946

    902 Index tilemap editor, 310-314 AI class, 552 tilemaps, 275-290 algorithms. See also functions trees Array class, 59-68 game logic, 470-472 asymptotic analysis, 11 Item class, 467-468 doubly linked lists, 172-174 Map class, 468-469 functions, 9-10 map editor, 473-475 graphical demonstration, 10-11 maps, 464, 465-466 linked lists, 184-185 Player class, 469-470 O notation, 4-9 TileMap read more..

  • Page - 947

    903 Index data, 59 free function, 53 destructor, 60 malloc function, 50-51 inserting items, 64-65 memory leaks, 53-55 intarray operator, 62-63 new function, 52 removing items, 65-66 pointers, 53 Resize function, 60-61 realloc function, 54-57 size, 67-68 size, 54-57 Array2D class, 121 functions (templates), 15-16 constructor, 122 graphical demonstration, 41-43 data, 122 inserting, 80 read more..

  • Page - 948

    904 Index Artificial Intelligence. See AI ASM (assembly languages), 243 assembly languages (ASM), 243 ASSERT macro, 820 assignment operator, 344 associative containers, 896 AStack class, 197-199 AStar function, 775-784 asymptotic analysis, 11 attackers (finite state machines), 548 Averagetype data type, 25 AVL BSTs, 395 B bad alloc exception, 61 balance (binary trees), read more..

  • Page - 949

    905 Index constructor, 87 data, 87 destructor, 87-88 ReadFile function, 94-95 Resize function, 88-89 Set function, 91-93 SetAll function, 93-94 WriteFile function, 94 bitvectors analysis, 105 arrays, 98-99 defined, 84-85 graphical demonstration, 85-86 memory caching, 101 saving players, 96-102 bitwise math, 807-808 blue ray DVD, 646 books C++, 796-797 data read more..

  • Page - 950

    906 Index Cell class, 730-731 Array3D, 127-130 CellCoordinate function, 780 arrays, 243-245 CellDistance function, 732-733 parameters, 30-31 Central Processing Unit (CPU), 647-648 AStack, 197-199 Check function, 75-77 BinarySearchTree, 397-401 checkers BinaryTree, 368-371 game trees, 456-459 Bitvector, 86 minimax trees, 442, 456-459 access operator, 89-91 chess, 442 binary and operator, 90-91 read more..

  • Page - 951

    907 Index HashTable, 229-233 Append function, 156-157 Heap, 418-424 constructor, 155 Huffman, 678-691 destructor, 155-156 HuffmanFrequency, 677 encapsulating, 154-155 HuffmanNode, 676-677 InsertAfter function, 152-153 inheritance, 248-260 iterators, 153-154 children, 249 Prepend function, 158 down-casting, 263 RemoveHead function, 158-160 Object class, 260-265 RemoveTail function, 160-161 parents, 249 read more..

  • Page - 952

    908 Index ClearMarks function, 510 Compress function, 682-684 ClickRock function, 452-453 compression. See data compression clipping, 519 compressor (RLE), 656-665 code conditional events binary trees, 368-371 finite state machines, 541-546 parsing, 382-384 graphical demonstration, 546-547 BSTs, 397-401 const keyword, 814 Huffman trees, 677-692 constants (finite state machines), 550-551 memory, read more..

  • Page - 953

    909 Index crashes, memory, 55 CreateLookupTable function, 691 CreateRLE function, 657-659 culling, 519 D data Array class, 59 Array2D class, 122 Bitvector class, 87 BSTs finding, 394 inserting, 391-394 removing, 394 compression. See data compression sorting. See sorts sparse, 218-219 storing 2D arrays, 116-117 3D arrays, 117-118 4D arrays, 117-118 arrays, read more..

  • Page - 954

    910 Index delete operator, 54-57 DirectionMap class, 570-579 deleting dynamic arrays, 53-54 game logic, 580 dense binary trees, 361-362 image sets, 580 dense heaps, 411 LoadFromFile function, 572-574 depth-based sorts, 638-642 LoadMap function, 581, 582 z-buffers, 639 map functions, 574-579 DepthFirst function, 510-511, 522 MapEntry class, 569 depth-first searches, 493-495 playing, 582 read more..

  • Page - 955

    911 Index down-casting, 263 DrawMap function, 514-516 DrawTile function, 587 DrawTilemap function, 135 dungeon direction tables, 512-518 DVD Consortium, 646 dynamic arrays, 49-59 calloc function, 51 deleting, 53-54 exceptions, 52 free function, 53 malloc function, 50-51 memory leaks, 53-55 new function, 52 pointers, 53 realloc function, 54-57 size, 54-57 dynamic read more..

  • Page - 956

    912 Index attackers, 548 AddNode, 506 complex, 533-534 AddTextBox, 871 conditional events, 541-546 algorithms, 9-10 constants, 550-551 Append, 156-157 defenders, 548 AStar, 775-784 DFAs, 538 BreadthFirst, 511-512 enumerations, 551 Bubblesort, 605-609 Event function, 555-556 Calculate, 215 graphical demonstration, 537, 546-547 CalculateMiniMax, 449 implementing, 535-536 CalculateMiniMaxValue, 450-452 read more..

  • Page - 957

    913 Index Count, 195, 199, 370 Height, 125 Tree class, 342 Heuristic, 449-450, 774-775, 781 CreateLookupTable, 691 horizontal, 346 CreateRLE, 657-659 identity, 91 data types, 62 inline, 830-831 Decompress, 684-685 Inorder, 372-373 DepthFirst, 510-511, 522 Insert, 64-65, 399-400 Dequeue, 206-207, 422 singly linked lists, 164-167 Destroy, 341-342 InsertAfter, 152-153 Down, 346 Item, 163 read more..

  • Page - 958

    914 Index Prepend, 158 SDLBox, 867 ProcessAI, 557-559 SDLLine, 866 Push, 194-195, 198 SDLPoint, 866 queues, 206 set, 91 QuickSort, 624-627 Set, 91-93 rand, 700-702, 819 SetAll, 93-94 random integers, 700-702 SetFocus, 872 RandomPercent, 705-706 SetFollow, 788 RandomRange, 704-705 SetFont, 870 RandomRangeF, 706-707 SetLife, 99 RandomRangeModulo, 702-704 SetNewMap, 302-303, 471-472 ReadFile, read more..

  • Page - 959

    915 Index G Game Demos Game Demo 3-1, 71-77 Game Demo 4-1, 96-102 Game Demo 5-1, 131-136 Game Demo 5-2, 136-144 Game Demo 6-1, 176-180 Game Demo 6-2, 180-183 Game Demo 7-1, 199-204 Game Demo 7-2, 212-216 Game Demo 8-1, 235-239 Game Demo 9-1, 266-314 Game Demo 11-1, 352-358 Game Demo 12-1, 386-388 Game Demo 13-1, 402-405 Game Demo 14-1, 424-430 read more..

  • Page - 960

    916 Index Huffman trees, 674-676 minimax trees, 437-439 pathfinding, 753-754 heuristics, 742-744, 748-749 queues, 204-205 quicksorts, 621-622, 627-630 radix sorts, 631-633 Random Distribution Graphs, 712-714 RLE, 651-655 singly linked lists, 149-150 sorts bubble sorts, 602-604 heap sorts, 611- 613 stacks, 192-193 Towers of Hanoi, 327-328 trees, 333-338 traversing, read more..

  • Page - 961

    917 Index heap sorts, 609-611 code, 613-616 graphical demonstration, 611-613 heaps arrayed, 411 defined, 410-411 dense, 411 efficiency, 416-417 graphical demonstration, 417-418 items inserting, 411-414 removing, 414-416 linked, 411 memory, 844-845 walk down algorithm, 414 walk up algorithm, 411 HeapSort function, 615 HeapWalkDown function, 613-614 Height function, 125 read more..

  • Page - 962

    918 Index items (heaps), 64-65, 411-414 nodes (doubly linked lists), 172-173 insertion sorts, 637 instances (template classes), 23 intarray operator, 62-63 integers. See also numbers bitfields. See bitfields data sizes, 805-806 random, 698-699 determinism, 699-700 functions, 700-702 linear congruency, 700 non-constant values, 702 ranges, 702-705 repeating patterns, 699-700 read more..

  • Page - 963

    919 Index node structure, 171-172 ReadFromDisk function, 175-176 removing nodes, 173-174 SaveToDisk function, 174-175 graphs, 480-481 inventories, 176-180 nodes, 148-149 singly linked lists analysis, 169 Append function, 156-157 constructor, 155 destructor, 155-156 encapsulating, 154-155 graphical demonstration, 149-150 Insert function, 164-167 InsertAfter function, 152-153 read more..

  • Page - 964

    920 Index weighted, 754-755 menus (stacks), 199-204 graphical demonstration, 755-756 merge sorts, 637 pathfinding, 758-759 Microsoft XBox data compression, 648 terrain, 756-762 min variable, 61 marking nodes, 495 MiniMax function, 449 Massively Multiplayer Online games, 105 minimax states (tic tac toe), 439-442 math minimax trees bit math, 802-810 base numbers, 441 binary numbers, 802-804 read more..

  • Page - 965

    921 Index initializing, 113-114 non-symmetrical, 114 variable length, 114-115 passing functions, 119-121 performance, 142-144 pipelining, 142-144 size, 144 speed, 142-144 N namespaces (STL), 883-885 naming conventions (STL), 882-883 network graphs, 484 new function, 52 nodes graphs, 482 doubly linked lists inserting, 172-173 removing, 173-174 structure, 171-172 linked read more..

  • Page - 966

    922 Index templates line-based, 762-764 data types, 24-29 object tracing, 719-721 values, 27-32 overview, 716-718 parents (classes), 249 quadtrees, 764-765 ParseArithmetic function, 382-384 random bouncing, 718-719 parsing binary trees, 374-376 speed, 786-790 algorithms, 381-382 waypoints, 765-767 arithmetic expressions, 376-377 weighted maps, 758-759 code, 382-384 patterns (random integers), 699-700 read more..

  • Page - 967

    923 Index postorder traversal, 449 powers (recursion), 319-320 Preorder function, 348-350, 372 Prepend function, 158 priority queues AI, 425 building, 424-430 defined, 408-410 Huffman trees, 668-674 private classes, 246-248 Probability Distribution Graphs, 707-708 ProcessAI function, 557-559 programs, distributing, 858 projects (SDL), 853-855 public classes, 245-246 pure read more..

  • Page - 968

    924 Index ReadFile function, 70-71, 94-95 ReadFromDisk function, 175-176 reading arrays, 70-71 static arrays, 45-46 realloc function, 54-57 recursion AI, 319 algorithms, 319 defined, 318-319 Fibbionacci series, 318 functions, 318 base case, 319 minimax trees, 446-448 powers, 319-320 Towers of Hanoi, 320-328 graphical demonstration, 327-328 trees, 332 recursive read more..

  • Page - 969

    925 Index saving sectors (graphs), 519-522 directionmaps, 590-593 sequence containers, 890-896 players, 96-102 Set function, 91-93 scanning (binary trees), 378-379 set functions, 91 SDL (simple directmedia layer), 848 SetAll function, 93-94 C++, 851-853 SetFocus function, 872 distributing programs, 858 SetFollow function, 788 event handling, 861-863 SetFont function, 870 files, 849-851 SetLife read more..

  • Page - 970

    926 Index linked lists, 185-186 median-of-three, 618 multi-dimensional arrays, 144 performing, 618-621 static arrays, 48 pivots, 616-618 Size function, 67-68 radix, 630-631 Array2D class, 125 base 2, 633-635 sizeof operator, 48 base 4, 636 SListIterator class, 162-163 base 16, 636 SListNode class, 151-152 bin size, 633 Append function, 156-157 code, 633-637 constructor, 155 graphical read more..

  • Page - 971

    927 Index linked, 194-196 memory, 840-844 menus, 199-204 popping, 191 pushing, 191 standard template library. See STL Start function, 162 state transition tables, 535-536 states FSM. See Finite State Machines games, 439-442 static arrays, 43-49 accessing, 44-46 declaring, 43-44 fencepost errors, 44 initializing, 48 passing to functions, 46-48 pointers, 47-48 read more..

  • Page - 972

    928 Index lookup tables, 691 timer (SDL), 863 state transition tables, 535-536 tokenizing (binary trees), 378-379 template keyword, 17 tokens (binary trees), 377-378 templates Top function, 195, 198 classes, 19-24 Towers of Hanoi, 320-328 declaring, 23 graphical demonstration, 327-328 instances, 23 tracing objects, 719-721 documenting, 33 traversals functions, 15-19 graphs, 493 implementing, read more..

  • Page - 973

    929 Index game logic, 470-472 Item class, 467-468 Map class, 468-469 map editor, 473-475 maps, 464-466 Player class, 469-470 TileMap class, 469 binary. See binary trees BSTs. See BSTs building, 347 defined, 330-332 finite state machines, 545-546 game trees. See game trees graphical demonstration, 333-338 graphs, 480-481 heaps. See heaps Huffman. See Huffman read more..

  • Page - 974

    930 Index W-Z walk down algorithm (heaps), 414 walk up algorithm (heaps), 411 WalkDown function, 422-424 WalkUp function, 420-422 wavelets (data compression), 694 waypoints (pathfinding), 765-767 wb mode, 69 Web sites, 798, 881 weighted graphs, 484 weighted maps, 754-755 graphical demonstration, 755-756 pathfinding, 758-759 terrain, 756-762 Width function, 125 WriteFile read more..

  • Page - 975

    Take Your Game to the XTREME! Xtreme Games LLC was founded to help small game developers around the world create and publish their games on the commercial market. Xtreme Games helps younger developers break into the field of game programming by insulating them from complex legal and business issues. Xtreme Games has hundreds of developers around the world, if you’re read more..

  • Page - 976

    “Game programming is without a doubt the most intellectually challenging field of Computer Science in the world. However, we would be fooling ourselves if we said that we are ‘serious’ people! Writing (and reading) a game programming book should be an exciting adventure for both the author and the reader.” —André LaMothe, Series Editor Premier Press, Inc. ™ read more..

  • Page - 977

    Team LRN read more..

  • Page - 978

    License Agreement/Notice of Limited Warranty By opening the sealed disc container in this book, you agree to the following terms and conditions. If, upon reading the following license agreement and notice of limited warranty, you cannot agree to the terms and conditions set forth, return the unused book with unopened disc to the place where you purchased it for a refund. read more..

Write Your Review