AwakeMUD icon indicating copy to clipboard operation
AwakeMUD copied to clipboard

Iterator implementation (internal coding algorithms)

Open vitalyo7 opened this issue 5 years ago • 4 comments

There are a lot of places in the code that require to iterate through the list of items, either in the inventory, or in the room, which boils down to having multiple loops in the code. Would it be cleaner to have some sort of smart iterator classes instead? The iteration through room, inventory would be hidden in the iterator implementation, but the resulting code would be something like this.

ItemIterator weaponIterator = Iterator.findWeapons(ch); while(weaponIterator.hasNext()) { obj weapon = weaponIterator.next(); // do something with the weapon }

or

MobIterator visibleCharacters = Iterator.findCharacters(ch, ITERATOR_VISIBLE | ITERATOR_DETECTED); while(visibleCharacters.hasNext()) { struct mobile *mobile = visibleCharacters.next(); // do something with mobile }

The iterators would have to hold the state at the current item in the room, inventory etc, so when the next() is called it iterates through the object of interest

Internally the iterator would likely have a pointer for current_obj, current_mob etc, and also a function pointer to a function that would return true/false if the current object in the search matches the condition.

For example

Iterator.findPlayers(ch) would mean that it would iterate through the room, that ch is in, for each mobile, it would call a func isPlayer(ch), and if it is, then the next call to next() would return that mobile, etc.

This is mostly to clean up the big multilevel loops in the code by an iterator (one while loop), by hiding the iteration logic inside the iterator implementation.

vitalyo7 avatar Jun 20 '19 04:06 vitalyo7

Can you give me an example of a nested loop that this would clean up? Also, how would the iterator handle a scenario where the character is in a vehicle with passengers, but needs a list of the people in the room outside?

luciensadi avatar Jun 20 '19 15:06 luciensadi

Not the best example, but something easy to show

In ACMD(do_reload), line 1436 could probably be replaced by two iterators. Iterator weapon = Iterator.findObj(ch).rule(RULE_OBJ_TYPE, ITEM_GUN_AMMO); for(;weapon.hasNext();weapo.next()) { // Do something with the weapon }

The cleanup here really is that all the if(obj.type = x) type of checks can be moved/hidden inside the iterator logic. Because at the end of the day, we just want to iterate through a list of weapons, and then iterate for list of ammo that matches that weapon. Given how often we check for items that match condition X, it may be cleaner if we put the condition checking and looping logic inside the iterator. This will reduce clutter of the ACMDs by a few lines per loop.

To your second question.

Iterator outsidePeople = Iterator.findCharacters(ch). .ruleRemove(SEARCH_PARAM, SEARCH_IN_HERE) .rule(SEARCH_PARAM, SEARCH_OUTSIDE_VEHICLE)

The iterator logic inside would be similar to the following find_next_search_area $AREA find_next_object $OBJ in search_area check $OBJ for $MATCH_CRITERIA onMatch: set hasNext to true, set next value to $OBJ

since we set the rule not to search inside, and search outside, the find_next_search_area should return outside of the vehicle, if the player is in a vehicle or some place that has an "outside"

then it would search for the next object in that search area

then it would match for any conditions on the object, since we are only searching for characters, the condition is that the obj must be a character (not an item etc)

The iterator should act like a parser/tokenizer, but rathern than parsing strings, it should parse the search space (in the room, characters inventory, items in the shopping, cyberwear installed) for obj that match a certain condition. When iterator is created, it needs to be programmed via rule(X,Y)/removeRule(X,Y) to know how to search, and what is considered a successful find.

vitalyo7 avatar Jun 20 '19 16:06 vitalyo7

I see what you mean, that'd be nice to have.

luciensadi avatar Jun 20 '19 17:06 luciensadi

Adding pseudocode here for discussion purposes.

Search weaponIt = Search .select(TYPE_ITEM) .from(world[ch->in_room].contents) .where() .condition(OBJ_VALUE, 0) .condition(OBJ_WEAR_TYPE, WEAR_WIELD);

Search ammo = Search. .select(TYPE_ITEM) .from(world[ch->in_room].contents) .where() .condition(OBJ_TYPE, OBJ_AMMO)

Search weapon_and_ammo Search .select(OBJ_PAIR) .from(weapon) .join(ammo).on(JOIN_CONDITION, AMMO_WEAPON)

vitalyo7 avatar Jun 20 '19 21:06 vitalyo7