Methapolis  0.27
 All Classes Namespaces Files Functions Variables Enumerator
TrafficGen.java
Go to the documentation of this file.
1 // This file is part of MicropolisJ.
2 // Copyright (C) 2013 Jason Long
3 // Portions Copyright (C) 1989-2007 Electronic Arts Inc.
4 //
5 // MicropolisJ is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU GPLv3, with additional terms.
7 // See the README file, included in this distribution, for details.
8 
9 package micropolisj.engine;
10 
11 import java.util.*;
12 import static micropolisj.engine.TileConstants.*;
13 
17 class TrafficGen
18 {
19  final Micropolis city;
20  int mapX;
21  int mapY;
22  ZoneType sourceZone;
23 
24  int lastdir;
25  Stack<CityLocation> positions = new Stack<CityLocation>();
26 
27  static final int MAX_TRAFFIC_DISTANCE = 30;
28 
29  public TrafficGen(Micropolis city)
30  {
31  this.city = city;
32  }
33 
34  int makeTraffic()
35  {
36  if (findPerimeterRoad()) //look for road on this zone's perimeter
37  {
38  if (tryDrive()) //attempt to drive somewhere
39  {
40  // success; incr trafdensity
41  setTrafficMem();
42  return 1;
43  }
44 
45  return 0;
46  }
47  else
48  {
49  // no road found
50  return -1;
51  }
52  }
53 
54  void setTrafficMem()
55  {
56  while (!positions.isEmpty())
57  {
58  CityLocation pos = positions.pop();
59  mapX = pos.x;
60  mapY = pos.y;
61  assert city.testBounds(mapX, mapY);
62 
63  // check for road/rail
64  int tile = city.getTile(mapX, mapY);
65  if (tile >= ROADBASE && tile < POWERBASE)
66  {
67  city.addTraffic(mapX, mapY, 50);
68  }
69  }
70  }
71 
72  static final int [] PerimX = { -1, 0, 1, 2, 2, 2, 1, 0,-1, -2,-2,-2 };
73  static final int [] PerimY = { -2,-2,-2, -1, 0, 1, 2, 2, 2, 1, 0,-1 };
74  boolean findPerimeterRoad()
75  {
76  for (int z = 0; z < 12; z++)
77  {
78  int tx = mapX + PerimX[z];
79  int ty = mapY + PerimY[z];
80 
81  if (roadTest(tx, ty))
82  {
83  mapX = tx;
84  mapY = ty;
85  return true;
86  }
87  }
88  return false;
89  }
90 
91  boolean roadTest(int tx, int ty)
92  {
93  if (!city.testBounds(tx, ty)) {
94  return false;
95  }
96 
97  char c = city.getTile(tx, ty);
98 
99  if (c < ROADBASE)
100  return false;
101  else if (c > LASTRAIL)
102  return false;
103  else if (c >= POWERBASE && c < LASTPOWER)
104  return false;
105  else
106  return true;
107  }
108 
109  boolean tryDrive()
110  {
111  lastdir = 5;
112  positions.clear();
113 
114  for (int z = 0; z < MAX_TRAFFIC_DISTANCE; z++) //maximum distance to try
115  {
116  if (tryGo(z))
117  {
118  // got a road
119  if (driveDone())
120  {
121  // destination reached
122  return true;
123  }
124  }
125  else
126  {
127  // deadend, try backing up
128  if (!positions.isEmpty())
129  {
130  positions.pop();
131  z += 3;
132  }
133  else
134  {
135  return false;
136  }
137  }
138  }
139 
140  // gone maxdis
141  return false;
142  }
143 
144  static final int [] DX = { 0, 1, 0, -1 };
145  static final int [] DY = { -1, 0, 1, 0 };
146  boolean tryGo(int z)
147  {
148  // random starting direction
149  int rdir = city.PRNG.nextInt(4);
150 
151  for (int d = rdir; d < rdir + 4; d++)
152  {
153  int realdir = d % 4;
154  if (realdir == lastdir)
155  continue;
156 
157  if (roadTest(mapX + DX[realdir], mapY + DY[realdir]))
158  {
159  mapX += DX[realdir];
160  mapY += DY[realdir];
161  lastdir = (realdir + 2) % 4;
162 
163  if (z % 2 == 1)
164  {
165  // save pos every other move
166  positions.push(new CityLocation(mapX, mapY));
167  }
168 
169  return true;
170  }
171  }
172 
173  return false;
174  }
175 
176  boolean driveDone()
177  {
178  int low, high;
179  switch (sourceZone)
180  {
181  case RESIDENTIAL:
182  low = COMBASE;
183  high = NUCLEAR;
184  break;
185  case COMMERCIAL:
186  low = LHTHR;
187  high = PORT;
188  break;
189  case INDUSTRIAL:
190  low = LHTHR;
191  high = COMBASE;
192  break;
193  default:
194  throw new Error("unreachable");
195  }
196 
197  if (mapY > 0)
198  {
199  int tile = city.getTile(mapX, mapY-1);
200  if (tile >= low && tile <= high)
201  return true;
202  }
203  if (mapX + 1 < city.getWidth())
204  {
205  int tile = city.getTile(mapX + 1, mapY);
206  if (tile >= low && tile <= high)
207  return true;
208  }
209  if (mapY + 1 < city.getHeight())
210  {
211  int tile = city.getTile(mapX, mapY + 1);
212  if (tile >= low && tile <= high)
213  return true;
214  }
215  if (mapX > 0)
216  {
217  int tile = city.getTile(mapX - 1, mapY);
218  if (tile >= low && tile <= high)
219  return true;
220  }
221  return false;
222  }
223 
227  static enum ZoneType
228  {
229  RESIDENTIAL, COMMERCIAL, INDUSTRIAL;
230  }
231 }