Design Pattern Examples
Overview of object-oriented design patterns
Visitor_Shop.c
Go to the documentation of this file.
1
6
7#include <stdio.h>
8#include <memory.h>
9
11
12#include "Visitor_Village.h"
13
26{
27 bool success = false;
28
29 if (list != NULL && output != NULL)
30 {
31 for (size_t index = 0; index < list->strings_count; index++)
32 {
33 if (index != 0)
34 {
35 success = DynamicString_Append(output, ", ");
36 if (!success)
37 {
38 printf(" Error! Out of memory condition appending ',' to list of strings being concatenated into a single string!\n");
39 break;
40 }
41 }
42 success = DynamicString_Append(output, list->strings[index]);
43 if (!success)
44 {
45 printf(" Error! Out of memory condition appending a string to list of strings being concatenated into a single string!\n");
46 break;
47 }
48 }
49 }
50
51 return success;
52}
53
61static bool Shop_DoesShopSellItem(Visitor_Shop* shop, const char* item)
62{
63 bool doesSell = false;
64
65 if (shop != NULL)
66 {
67 int foundIndex = MapOfStrings_Find(&shop->IngredientsForItems, item);
68 doesSell = foundIndex != -1;
69 }
70
71 return doesSell;
72}
73
74
82static bool Shop_IsItemInStock(Visitor_Shop* shop, const char* item)
83{
84 bool inStock = false;
85
86 if (shop != NULL && item != NULL)
87 {
88 int foundIndex = MapOfInt_Find(&shop->Inventory, item);
89 if (foundIndex != -1)
90 {
91 inStock = shop->Inventory.entries[foundIndex].value > 0;
92 }
93 }
94
95 return inStock;
96}
97
98
107static bool Shop_AddItemToInventory(Visitor_Shop* shop, const char* item)
108{
109 bool success = false;
110
111 if (shop != NULL && item != NULL)
112 {
113 int foundIndex = MapOfInt_Find(&shop->Inventory, item);
114 if (foundIndex != -1)
115 {
116 shop->Inventory.entries[foundIndex].value++;
117 success = true;
118 }
119 else
120 {
121 success = MapOfInt_Add(&shop->Inventory, item, 1);
122 if (!success)
123 {
124 printf(" Error! Out of memory condition adding an item to a shop's inventory!\n");
125 }
126 }
127 }
128
129 return success;
130}
131
132
133//-----------------------------------------------------------------------------
134//-----------------------------------------------------------------------------
135
136
138// Shop_Create()
140Visitor_Shop* Shop_Create(const char* name, const char* address, struct Village* village)
141{
142 Visitor_Shop* shop = NULL;
143
144 if (name != NULL && address != NULL && village != NULL)
145 {
146 shop = calloc(1, sizeof(Visitor_Shop));
147 if (shop != NULL)
148 {
149 shop->Name = name;
150 shop->Address = address;
151 shop->Village = village;
154 }
155 }
156
157 return shop;
158}
159
161// Shop_Destroy()
164{
165 if (shop != NULL)
166 {
169 }
170}
171
172
173
175// Shop_PlaceOrder()
178{
180
181 if (itemsToOrder != NULL && shop != NULL)
182 {
183 ConstStringList outOfStockItems = { 0 };
184 ConstStringList itemsInThisShop = { 0 };
185
186 bool success = false;
187
188 for (size_t index = 0; index < itemsToOrder->strings_count; index++)
189 {
190 const char* item = itemsToOrder->strings[index];
191 if (Shop_DoesShopSellItem(shop, item))
192 {
193 if (!Shop_IsItemInStock(shop, item))
194 {
195 success = ConstStringList_AddString(&outOfStockItems, item);
196 if (!success)
197 {
198 printf(" Error! Out of memory condition adding ingredient to out of stock item list!\n");
199 break;
200 }
201 }
202 success = ConstStringList_AddString(&itemsInThisShop, item);
203 if (!success)
204 {
205 printf(" Error! Out of memory condition adding ingredient to local list of items sold by a store!\n");
206 break;
207 }
208 }
209 }
210
211 if (success)
212 {
213 if (itemsInThisShop.strings_count != 0)
214 {
215 DynamicString output = { 0 };
216 success = _StringizeStringList(&itemsInThisShop, &output);
217 if (success)
218 {
219 printf(" %s: Received an order for %s.\n",
220 shop->Name, output.string);
222 }
223 DynamicString_Clear(&output);
224 }
225 else
226 {
228 }
229
230 }
231
232 if (success)
233 {
234 if (outOfStockItems.strings_count != 0)
235 {
236 for (size_t index = 0; index < outOfStockItems.strings_count; index++)
237 {
238 const char* ingredient = outOfStockItems.strings[index];
239 int ingredientIndex = MapOfStrings_Find(&shop->IngredientsForItems, ingredient);
240 if (ingredientIndex != -1 && shop->IngredientsForItems.entries[ingredientIndex].value->strings_count != 0)
241 {
242 printf(" %s: %s out of stock, ordering ingredients to make more...\n",
243 shop->Name, ingredient);
244 OrderVisitor visitor = { 0 };
245 success = ConstStringList_AddStrings(&visitor.ItemsToOrder, shop->IngredientsForItems.entries[ingredientIndex].value->strings, shop->IngredientsForItems.entries[ingredientIndex].value->strings_count);
246 if (!success)
247 {
248 printf(" Error! Out of memory creating order for out of stock items!\n");
249 break;
250 }
251 success = Village_VisitShop(shop->Village, &visitor);
252 if (!success)
253 {
254 printf(" Error! Failed to visit shops for out of stock items, probably an out of memory condition!\n");
255 OrderVisitor_Clear(&visitor);
256 break;
257 }
259 {
260 // verify the ingredients received matches the ingredients needed.
261 // only then add 1 to the inventory.
262 success = Shop_AddItemToInventory(shop, ingredient);
263 if (!success)
264 {
265 OrderVisitor_Clear(&visitor);
266 break;
267 }
268 }
269 else
270 {
271 DynamicString ingredients_list;
272 DynamicString_Initialize(&ingredients_list);
273 DynamicString received_items_list;
274 DynamicString_Initialize(&received_items_list);
275
276 success = _StringizeStringList(shop->IngredientsForItems.entries[ingredientIndex].value, &ingredients_list);
277 if (!success)
278 {
279 printf(" Error! Out of memory creating string list of needed ingredients!\n");
280 OrderVisitor_Clear(&visitor);
281 break;
282 }
283 success = _StringizeStringList(&visitor.ItemsReceived, &received_items_list);
284 if (!success)
285 {
286 DynamicString_Clear(&ingredients_list);
287 printf(" Error! Out of memory creating string list of received items!\n");
288 OrderVisitor_Clear(&visitor);
289 break;
290 }
291 printf(" %s: Error! Ordered %s but only received %s.\n",
292 shop->Name, ingredients_list.string,
293 received_items_list.string);
294
295 DynamicString_Clear(&received_items_list);
296 DynamicString_Clear(&ingredients_list);
297 }
298 OrderVisitor_Clear(&visitor);
299 }
300 else
301 {
302 // The ordered item has no ingredients so the
303 // ordered item will be magically added to inventory
304 printf(" %s: %s out of stock, making...\n",
305 shop->Name, ingredient);
306 success = Shop_AddItemToInventory(shop, ingredient);
307 if (!success)
308 {
309 break;
310 }
311 }
312 }
313 }
314 }
315 if (!success)
316 {
317 response = PlaceOrderResponse_Error;
318 }
319
320 ConstStringList_Clear(&outOfStockItems);
321 ConstStringList_Clear(&itemsInThisShop);
322 }
323
324 return response;
325}
326
327
329// Shop_PickupOrder()
331bool Shop_PickupOrder(Visitor_Shop* shop, ConstStringList* items, ConstStringList* itemsToBePickedUp)
332{
333 bool success = false;
334
335 if (items != NULL && itemsToBePickedUp != NULL && shop != NULL)
336 {
337 for (size_t index = 0; index < items->strings_count; index++)
338 {
339 const char* item = items->strings[index];
340 // If this shop sells the item and the item is in stock then
341 if (Shop_DoesShopSellItem(shop, item))
342 {
343 if (Shop_IsItemInStock(shop, item))
344 {
345 success = ConstStringList_AddString(itemsToBePickedUp, item);
346 if (!success)
347 {
348 printf(" Error! Out of memory adding item to list of items to be picked up!\n");
349 break;
350 }
351 }
352 else
353 {
354 printf(" Error! %s: Item %s is not in the inventory when it should be.\n",
355 shop->Name, item);
356 }
357 }
358 }
359
360 if (itemsToBePickedUp->strings_count != 0)
361 {
362 // Reduce inventory for the ordered items
363 DynamicString output = { 0 };
364 ConstStringList itemsReceivedFromThisShop;
365 ConstStringList_Initialize(&itemsReceivedFromThisShop);
366 for (size_t index = 0; index < itemsToBePickedUp->strings_count; index++)
367 {
368 const char* itemToBePickedUp = itemsToBePickedUp->strings[index];
369 if (Shop_DoesShopSellItem(shop, itemToBePickedUp))
370 {
371 int inventoryIndex = MapOfInt_Find(&shop->Inventory, itemToBePickedUp);
372 if (inventoryIndex != -1)
373 {
374 shop->Inventory.entries[inventoryIndex].value--;
375 success = ConstStringList_AddString(&itemsReceivedFromThisShop, itemToBePickedUp);
376 if (!success)
377 {
378 printf(" Error! Out of memory adding item to list of items to be picked up from shop %s!\n",
379 shop->Name);
380 break;
381 }
382 }
383 }
384 }
385 if (success)
386 {
387 success = _StringizeStringList(&itemsReceivedFromThisShop, &output);
388 if (success)
389 {
390 printf(" %s: Order picked up for %s.\n", shop->Name, output.string);
391 }
392 else
393 {
394 printf(" Error! Out of memory creating list of strings for items received from shop %s!\n",
395 shop->Name);
396 }
397 }
398 DynamicString_Clear(&output);
399 ConstStringList_Clear(&itemsReceivedFromThisShop);
400 }
401
402 }
403 return success;
404}
void OrderVisitor_Clear(OrderVisitor *visitor)
Clear the specified OrderVisitor object, freeing up any memory that it was using. The resulting objec...
bool Shop_PickupOrder(Visitor_Shop *shop, ConstStringList *items, ConstStringList *itemsToBePickedUp)
Pick up the items sold by this shop (assumes the items were ordered already). Basically,...
Definition: Visitor_Shop.c:331
void Shop_Destroy(Visitor_Shop *shop)
Destroy an instance of the Visitor_Shop structure, freeing up any memory that may have been allocated...
Definition: Visitor_Shop.c:163
Visitor_Shop * Shop_Create(const char *name, const char *address, struct Village *village)
Creates a new instance of a Visitor_Shop structure, and initializes it with the given name,...
Definition: Visitor_Shop.c:140
static bool Shop_DoesShopSellItem(Visitor_Shop *shop, const char *item)
Determine if the given Visitor_Shop object sells the specified item.
Definition: Visitor_Shop.c:61
static bool Shop_AddItemToInventory(Visitor_Shop *shop, const char *item)
Add the specified item to the given Visitor_Shop object's inventory.
Definition: Visitor_Shop.c:107
static bool _StringizeStringList(ConstStringList *list, DynamicString *output)
Convert a string list to a comma-delimited string. Useful for displaying the list.
Definition: Visitor_Shop.c:25
PlaceOrderReponse Shop_PlaceOrder(Visitor_Shop *shop, ConstStringList *itemsToOrder)
Visit the specified Visitor_Shop object to try to place an order as described in the OrderVisitor obj...
Definition: Visitor_Shop.c:177
static bool Shop_IsItemInStock(Visitor_Shop *shop, const char *item)
Determine if given Visitor_Shop object has the specified item in stock.
Definition: Visitor_Shop.c:82
bool Village_VisitShop(Village *village, OrderVisitor *visitor)
Visit all shops in the given Village object to find the ingredients specified in the OrderVisitor obj...
PlaceOrderReponse
Represents the possible responses from the Shop_PlaceOrder() function.
@ PlaceOrderResponse_OrderIgnored
Order was ignored.
@ PlaceOrderResponse_Error
There was an error placing the order, likely an out of memory condition.
@ PlaceOrderResponse_OrderAccepted
Order was accepted.
void ConstStringList_Initialize(ConstStringList *stringList)
Initialize the given string list.
bool ConstStringList_AddStrings(ConstStringList *stringList, const char **strings, size_t numStrings)
Add an array of strings to the given string list.
bool ConstStringList_AreListsEqual(ConstStringList *left, ConstStringList *right)
Compare two strings lists to determine if they have the same contents.
bool ConstStringList_AddString(ConstStringList *stringList, const char *string)
Add a string to the given string list.
void ConstStringList_Clear(ConstStringList *stringList)
Clear the specified string list. The strings in the list are left alone, but the list itself is delet...
Declaration of the Visitor_Village class used in the Visitor Pattern.
void DynamicString_Clear(DynamicString *string)
Clear a DynamicString object, releasing any allocated memory. Resets to an empty string.
Definition: dynamicstring.c:27
void DynamicString_Initialize(DynamicString *string)
Initialize a DynamicString object to an empty string.
Definition: dynamicstring.c:15
bool DynamicString_Append(DynamicString *string, const char *s)
Append the specified string to the DynamicString object.
Definition: dynamicstring.c:39
Declaration of the DynamicString structure and supporting functions to work with dynamic strings.
void MapOfInt_Clear(MapOfInt *map)
Clear the given MapOfInt object, releasing all memory associated with it. Leaves the object in an ini...
Definition: mapofint.c:28
void MapOfInt_Initialize(MapOfInt *map)
Initialize the given MapOfInt structure so it is ready for use.
Definition: mapofint.c:16
bool MapOfInt_Add(MapOfInt *map, const char *key, int value)
Add a key/value association to the given MapOfInt object. The MapOfInt object takes ownership of the ...
Definition: mapofint.c:40
int MapOfInt_Find(MapOfInt *map, const char *key)
Find the specified key in the given MapOfInt object, returning an index into the object.
Definition: mapofint.c:72
void MapOfStrings_Initialize(MapOfStrings *map)
Initialize the given MapOfStrings structure so it is ready for use.
Definition: mapofstrings.c:16
void MapOfStrings_Clear(MapOfStrings *map)
Clear the given MapOfStrings object, releasing all memory associated with it. Leaves the object in an...
Definition: mapofstrings.c:28
int MapOfStrings_Find(MapOfStrings *map, const char *key)
Find the specified key in the given MapOfStrings object, returning an index into the object.
Definition: mapofstrings.c:105
Represents a list of pointers to zero-terminated strings that are to remain constant and never delete...
size_t strings_count
Number of strings in the strings list.
const char ** strings
Pointer to an array of zero-terminated string pointers. These strings are constant and will not be du...
Represents a string that can be grown dynamically.
Definition: dynamicstring.h:16
char * string
The string that can grow.
Definition: dynamicstring.h:17
int value
The integer value.
Definition: mapofint.h:18
MapOfIntEntry * entries
Definition: mapofint.h:28
ConstStringList * value
The "value" that is a ConstStringList object.
MapOfStringsEntry * entries
List of MapOfStringsEntry for each mapping.
Represents a visitor used for ordering items from various shops. The user starts with an instance of ...
ConstStringList ItemsToOrder
Items to be ordered from any shop that sells the item.
ConstStringList ItemsReceived
List of items received from an order/pickup process.
Represents a collection of shops that can be visited.
Represents a shop in the village that can be visited.
const char * Name
Name of shop. Borrowed pointer.
const char * Address
Address of shop. Borrowed pointer.
MapOfInt Inventory
Maps ingredient to number of that ingredient in the shop.
struct Village * Village
Village this shop is in. Borrowed pointer.
MapOfStrings IngredientsForItems
Maps ingredient to list of items need for ingredient.