# Dodgems: A longer exercise

We'll now try to simulate fairground dodgems using what we know so far. Our dodgems will be circular, and our arena square. To make things more interesting we'll have 3 teams of dodgems with different sizes, speeds and colours.

Direction will be in degrees (going clockwise from 'north'). The coordinate system will have (0,0) bottom left.

We'll start by setting some constants and creating some enumerated types.

```const float PI = 3.14159;
const int arena_size =400; // side of arena in pixels
const int turn_amount=20;  // how much direction can change by each time

enum Team {Green, Red, Blue};
enum Direction {NWDirection, NEDirection, SEDirection, SWDirection};
enum Turn {Left, Straight, Right};
```

Now to write some little routines. None of them will be more than 10 lines or so. You may like to test them as you go along.

## Arithmetic Routines

Write the following routines. You can assume that you have a `random()` routine that returns an integer in the range 0 to `2^31-1`.

```//Convert radians to degrees

float dtor(int degrees);

//Return a number in the range 1 to 'maximum' inclusive
int random_integer(int maximum);
```

## Geometric Routines

```//Return the distance between x1,y1 and x2,y2
int distance (int x1, int x2, int y1, int y2);

// Given the direction of the dodgem, determine the quadrant direction

// Given coordinates, determine which quadrant the dodgem is in

// Given coordinates, use which_quadrant and atan to calculate
// the angle of the radius out to the dodgem

// calculate the change in x and y for the proposed movement
void get_movement(int speed, int direction, int &x_offset, int &y_offset);
```

## Graphics Routines

C++ doesn't have any graphics routines. CUED people can use the Vogle Library to create the following routines (about 40 lines of code). If you don't have vogle, you'll need to write the following routines using whatever graphics available.

```void initialise_graphics(); // create a window, and arena outline
// and suitable scale factors
void draw_circle(int x,int  y, int radius, Team t); //use t to select color
void undraw_circle(int x,int  y, int radius);
void wait_for_key(); // wait for a key to be pressed before removing window
```

## Decision Routine

```// Decide which way - if any - to turn. Don't bother turning if
// the dodgem is less than 'turn_amount' from the ideal direction
Turn which_way(int ideal_direction, int current_direction);
```

## Creating the Dodgem class

We have all the subsidary routines. Here's a workable class definition

```class dodgem {
private:
int x;
int y;
int speed;
int max_speed;
string name; // name of driver
Team team;
void check_wall_collision();
int best_direction();
void draw();

public:

// Constructor
dodgem(Team t, string driver);
int current_direction;
int score;
int getx() { return x;}
int gety() { return y;}
Team getteam()  { return team;}
string getname() {return name;}
void print();
void move();
void undraw();
};
```

Most of the class functions provide public access to private values. `draw()` and `undraw()` call `draw_circle` and `undraw_circle`. `print()` displays diagnostic information. You can write these inline now. The other class functions might best be placed outside the main class definition - e.g. write `dodgem::move() { ... }` etc.

The constructor function fills in the `team` and `name` fields. Use `switch(t)` to set `radius` and `max_speed` fields - values in the range 5 to 15 should be ok. Set `score` to 0 and `speed` to `max_speed`. `x`, `y` and `current_direction` can be initialised using the `random_integer` integer routine. Don't worry for the moment about dodgems being created on top of others, but do create them so that they don't project over the arena's edge. Finish the constructor by calling `draw()`.

`check_wall_collision()` uses the current coordinates to determine whether the dodgem has crashed against a wall. If there's a collision, set `x` or `y` so that the dodgem is just touching the wall, and set the `current_direction` perpendicular to the wall, towards the center. Write it now.

`best_direction()` calculates the way the dodgem would like to go if it could turn that far. For the moment just try to circle clockwise, but if the dodgem is partly outside the inscribed circle of the arena, try to head towards the centre.

`move()` calls `best_direction()` then `which_way()` to decide how to change the `current_direction`. The dodgem is then removed from the screen and new coordinates calculated. `check_wall_collision()` is called, then the dodgem redrawn.

## Putting it all together

The main routine is going to initialise the randomiser (using `srandom(time(0))` and graphics, create some dodgems, then for 100 time intervals move each dodgem in turn, checking each time to see if the dodgem has crashed into another. If the dodgem crashes into another team's dodgem, the latter is eliminated and the first dodgem gains a point. If a dodgem crashes into a fellow team member the former loses a point and is shoved 90 degrees clockwise.

At the end the scores of the remaining dodgems are printed out and `wait_for_key()` called.

If you store the dodgems in a `list<dodgem>` then its easy to add, remove and loop through them.

And that's it! you can develop this simulation if you want, changing the direction and speed to make the dodgems more predatory, and making the dodgems bounce off walls.

• © Cambridge University, Engineering Department, Trumpington Street, Cambridge CB2 1PZ, UK (map)
Tel: +44 1223 332600, Fax: +44 1223 332662
Contact: helpdesk