Worms -- OOP Redo  2016-01
Worms-Redo Project as a learning vehicle.
worm.cpp
Go to the documentation of this file.
1 
2 /* worm.cpp deals with a single worm */
3 
4 #include "worm.hpp"
5 
6 #define headSeg(wp) (wp->body + wp->nsegs)
7 #define xOf(wp) (headSeg(wp)->x)
8 #define yOf(wp) (headSeg(wp)->y)
9 /*@ nsegs >= 0 && 0 <= direction <= 7 && stomach >= 0 && connected(wp) && */
10 
11 /* Show a single worm. pre: wp != 0. post: It is drawn on passive[]
12  if it is dead. If alive, it is drawn on screen[]. If eaten, not
13  drawn. ; */
14 
16 {
17  if (this->status != EATEN) {
18  ASOG *f = (this->status == ALIVE ? screen : passive);
19  SEGMENT *bp, *hp = headSeg(this);
20  for (bp = this->body + 1; bp <= hp; bp++) {
21  ASOG *g = asog(f, bp->y, bp->x);
22  g->attr = worm_info[this->type].color;
23  g->onec = bp->c;
24  }
25  }
26 }
27 
28 /* It is hungry if its tummy is at least 25% empty. pre: wp != 0;
29  post: Return 1 if worm wp is hungry; otherwise return 0. */
30 
32 {
33  int m = this->stomach;
34  int n = this->nsegs * worm_info[this->type].capacity;
35  return (this->status == ALIVE && 4*m < 3*n);
36 }
37 
38 /* pre: wp != 0 */
39 
41 {
42  if (this->status == ALIVE) {
43  this->status = EATEN;
44  xworms[this->type] --;
45  }
46 }
47 
48 /* pre: this->status == ALIVE; post: if stomach is 0 or less, mark it
49  dead, and send its body to the cemetary. */
50 
52 {
53  if (this->stomach <= 0) {
54  this->status = DEAD;
55  xworms[this->type] --;
56  this->showOneWorm(); // mv the body to passive
57  }
58 }
59 
60 /* Eat a carrot, if available. pre: this->status == ALIVE; post:
61  ...; */
62 
64 {
65  ASOG *sg = asog(passive, yOf(this), xOf(this));
66  if (CARROT == sg->onec) {
67  this->stomach += 2; // food value of one carrot
68  sg->onec = ' ';
69  }
70 }
71 
72 /* Check if any segment of worm wp is at (col, row). Return this
73  segment's number. Recall that body[0] is just an eraser-blank, not
74  really a part of the worm. pre: wp != 0; post: ...; */
75 
76 int Worm::isAt(int row, int col)
77 {
78  SEGMENT *bp = headSeg(this);
79  for (int sn = this->nsegs; sn > 0; sn--, bp--)
80  if ((bp->y == row) && (bp->x == col))
81  return sn;
82 }
83 
84 /* The following two vars should be 'out' parameters (var params), but
85  for ease of understanding, let us declare these as globals. */
86 
89 
90 /* Find a worm that is on the same square as "my" head. pre: me != 0;
91  post: victimSegNum > 0 => victimWormp != 0 and victimWormp's
92  victimSegNum segment is at the same square as the head of me. */
93 
95 {
96  Worm *headWorm = wormArray + hxWorms;
97  victimWormp = 0;
98  victimSegNum = 0;
99  for (Worm * wp = wormArray; wp < headWorm; wp++) {
100  if (wp != this && this->status == ALIVE) {
101  victimSegNum = wp->isAt(yOf(this), xOf(this));
102  if (victimSegNum > 0) {
103  victimWormp = wp;
104  return; // found the victim
105  }
106  }
107  }
108 }
109 
110 /* Copy the body segments. pre: vp != 0 && 0 < vsn <= vp->nsegs;
111  post: old body[vsn+1..end] should become new body[1..new-length];
112  body[0] remains as the eraser-blank */
113 
114 void Worm::shiftBodyDown(Worm * vp, int vsn)
115 {
116  SEGMENT *dp = vp->body + 1; // dp destination, sp source
117  SEGMENT *hp = headSeg(vp);
118  for (SEGMENT *sp = vp->body + vsn + 1; sp <= hp; )
119  *dp++ = *sp++;
120  int tsegs = vp->nsegs;
121  vp->nsegs -= vsn;
122  vp->stomach = vp->stomach / tsegs * vp->nsegs;
123  vp->checkStomach();
124 }
125 
126 /* A scissor-head or cannibal hit the victim at segment number vsn.
127  Slice the victim into two. pre: vp != 0 && 0 < vsn <= vp->nsegs;
128  post: The first one with vp->body[1..vsn-1] and the second one with
129  vp->body[vsn+1..vp->nsegs] as its new body. */
130 
132 {
133  int tsegs = vp->nsegs;
134  Worm *wp = findSlot();
135  if (wp == 0) // could not find a slot
136  return vp;
137 
138  xworms[vp->type]++;
139 
140  *wp = *vp; // bottom-half
141  wp->nsegs = vsn - 1;
142  wp->stomach = vp->stomach / tsegs * wp->nsegs;
143  wp->checkStomach();
144 
145  shiftBodyDown(vp, vsn); // the top-half
146  return wp;
147 }
148 
149 
150 /* Eat whatever you find at the wp's head position. If wp is a
151  cannibal or scissor-head it will also eat a carrot, if available.
152  Update the stomach contents. pre: isHungry(wp) && wp->status ==
153  ALIVE; post: ...; */
154 
155 void Worm::eat()
156 {
157  if (this->type != VEGETARIAN) {
158  this->setVictimWorm();
159  if (victimWormp != 0) {
160  this->stomach += worm_info[victimWormp->type].foodValue;
161  Worm * zp = sliceTheVictim(victimWormp, victimSegNum);
162  if (this->type == CANNIBAL && zp->status == ALIVE) {
163  this->stomach += zp->nsegs * worm_info[zp->type].foodValue;
164  zp->gotEaten();
165  }
166  }
167  }
168  this->eatACarrot();
169 }
170 
171 // dx/dy changes, indexed by DIRECTION; (+0 just to line up)
172 const int dxa[] = { +0, +1, +1, +1, +0, -1, -1, -1 };
173 const int dya[] = { -1, -1, +0, +1, +1, +1, +0, -1 };
174 
175 const int nextTurn[16] = { // experiment with other values
176  0, 0, 0, 0, 0, 0, 0, 0, // think: why 16?
177  1, 1, 1, 7, 7, 7, 2, 6
178 };
179 
180 /* One moment in the life of a worm: crawl by one step using one unit
181  of food, may change direction, eat if hungry, mark as dead if
182  stomach is now empty. */
183 
185 {
186  SEGMENT *hp = headSeg(this);
187  for (SEGMENT * bp = this->body; bp < hp; bp++) // < not <=
188  bp->x = (bp + 1)->x, bp->y = (bp + 1)->y; // crawl
189 
190  int dir = this->direction = (this->direction + nextTurn[random(16)]) % 8;
191  hp->y += dya[dir];
192  hp->x += dxa[dir];
193  if (hp->y < 0) hp->y = asogRows-1;
194  if (hp->x < 0) hp->x = asogCols-1;
195  if (hp->y >= asogRows) hp->y = 0;
196  if (hp->x >= asogCols) hp->x = 0;
197 
198  this->stomach--;
199  if (this->isHungry())
200  this->eat();
201  this->checkStomach();
202 }
203 
204 /* Create a worm. It should be just long enough to carry the phrase
205  sy[]. It is going to crawl out of a random hole. pre: sy != 0;
206  post: ...; */
207 
208 void Worm::createWorm(WormKind type, const char * sy)
209 {
210  Worm *wp = findSlot();
211  if (wp == 0)
212  return; // no room for a new worm
213 
214  int n = wp->nsegs = min(strlen(sy), MAXsegs - 1);
215  wp->stomach = n * worm_info[type].capacity;
216  wp->direction = NORTH;
217  wp->status = ALIVE;
218  wp->type = type;
219 
220  SEGMENT * bp = wp->body;
221  int yy = bp->y = random(asogRows); // birth place of this worm
222  int xx = bp->x = random(asogCols);
223  bp->c = ' '; // works as an "eraser"
224 
225  SEGMENT * hp = headSeg(wp);
226  for (bp++; bp <= hp; bp++) {
227  bp->c = *sy++; // store the phrase s[]
228  bp->x = xx; // worm hangs down in the z-axis
229  bp->y = yy;
230  }
231  xworms[type] ++;
232 }
233 
void gotEaten()
Definition: worm.cpp:40
int color
Definition: worm.hpp:64
void eatACarrot()
Definition: worm.cpp:63
const int nextTurn[16]
Definition: worm.cpp:175
#define CARROT
Definition: worm.hpp:14
int asogRows
Definition: display.cpp:18
Worm * sliceTheVictim(Worm *vp, int vsn)
Definition: worm.cpp:131
int onec
Definition: worms.h:16
#define headSeg(wp)
Definition: worm.cpp:6
Worm * findSlot()
Definition: worms.h:21
Definition: worm.hpp:77
SEGMENT body[MAXsegs]
Definition: worm.hpp:46
int nsegs
Definition: worm.hpp:45
Worm wormArray[]
int asogCols
Definition: display.cpp:18
int direction
Definition: worm.hpp:42
LIFE status
Definition: worm.hpp:44
const int dxa[]
Definition: worm.cpp:172
void shiftBodyDown(Worm *vp, int vsn)
Definition: worm.cpp:114
int hxWorms
void eat()
Definition: worm.cpp:155
Worm * victimWormp
Definition: worm.cpp:87
void setVictimWorm()
Definition: worm.cpp:94
int xworms[]
ASOG passive[MAXrow *MAXcol]
Definition: display.cpp:16
void checkStomach()
Definition: worm.cpp:51
#define MAXsegs
Definition: worm.hpp:17
#define yOf(wp)
Definition: worm.cpp:8
const int dya[]
Definition: worm.cpp:173
int isAt(int row, int col)
Definition: worm.cpp:76
ASOG screen[MAXrow *MAXcol]
Definition: display.cpp:17
void createWorm(WormKind type, const char *sy)
Definition: worm.cpp:208
void live()
Definition: worm.cpp:184
int stomach
Definition: worm.hpp:43
int isHungry()
Definition: worm.cpp:31
int victimSegNum
Definition: worm.cpp:88
#define xOf(wp)
Definition: worm.cpp:7
void showOneWorm()
Definition: worm.cpp:15
WormKind
Definition: worm.hpp:23
#define random(x)
Definition: worm.hpp:10
WormInfo worm_info[]
Definition: worm.hpp:71
char c
Definition: worm.hpp:37
int foodValue
Definition: worm.hpp:66
int attr
Definition: worms.h:17
#define asog(ptr, row, col)
Definition: display.cpp:19
int capacity
Definition: worm.hpp:65
#define min(a, b)
Definition: worm.hpp:12
Definition: worm.hpp:20
WormKind type
Definition: worm.hpp:41