Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #12, fixes #29.
With the help of God mode #55 , I was able to let the game crash a couple of times for debugging purposes.
While examining the stack traces of multiple panics I found the following:
The function that crashes is
gen_range, however on some occasions it was called bycreate_enemywhile on other occasions it was called by
create_fuel.Both
create_enemyandcreate_fuelcallrng.gen_range(world.map[0].0..world.map[0].1).In our case this range sometimes is empty which means that the program eventually comes to a state where the left border of the river is greater than (at the right side of) the right border.
Possible scenario of reaching such an unlucky state:
Assume that
next_leftborder is at position 13 andnext_rightborder is at position 16 and afterworld.next_left = rng.gen_range(world.next_left.saturating_sub(5)..world.next_left + 5);world.next_right = rng.gen_range(world.next_right - 5..world.next_right + 5);next_leftis at position 17 (original 13 plus 4) andnext_rightis at position 13 (original 16 minus 3).Now,
world.next_right.abs_diff(world.next_left)will evaluate to 4 so the following blockif world.next_right.abs_diff(world.next_left) < 3 { world.next_right += 3; }won't be executed.
At the next iterations
leftandrightwill be adjusted accordingly. So if we are unlucky enough, that state whereleftis at the right side ofrightcan arise and ifcreate_fuelorcreate_enemycallrng.gen_range(world.map[0].0..world.map[0].1)at this specific time, the program will panic.How did I approach this:
after the
next_rightandnext_lefthave been calculated, ifnext_leftis beyondnext_right:if world.next_left >= world.next_rightthen I need to untangle them. However, those cases can arise when we are close to the borders of the screen and thus we must first check whether we have enough space to bring
next_rightat the right side ofnext_left:if world.next_left <= world.maxc - 4(we already know at this point thatnext_leftis greater thannext_right)then move
next_rightat the right side ofnext_left(world.next_right = world.next_left + 3)else(if there is not enough space to bringnext_rightover to the right side ofnext_leftwhile also having a 3 character gap between them)move the
next_leftat the left side of thenext_right(world.next_left = world.next_right - 3;)We know for sure that there is enough space to expand to the left side since there was not enough space to expand at the right side. I did not account for the scenario where there is not enough space on both sides, i.e. very very small terminal width.
Now that they are untangled, the last piece of code:
if world.next_right.abs_diff(world.next_left) < 3 { world.next_right = world.next_left + 3; }ensures the 3 character distance between them.
This last bit is important because even though we create the gap manually in the previous block, that block might not be executed (case of
if world.next_left >= world.next_right== false), i.e. they were not tangled, just too close.This way we know that
next_leftis at the left side ofnext_rightwhile also ensuring they have, at least, a 3 character gap.