Bubbling Beaker Awards (Award #27, June 14 2024)

Just last month I was talking about how useful custom loops are.

A disadvantage to my solution as written is that it’ll only work in the current development version of Inform, thus it’s only of use right now to someone who’s building Inform from source. Otis, however, provided a 9.3/6M62 translation of looping through relations. I just tried it in 10.1, and with just a small modification (removing the final 2 closing right braces) Otis’ solution works there. 10.1-ready code is below for easy copy-pasting.

10.1 version
To repeat for/with/-- (x - nonexisting K variable) running/-- through/in keys of (r - relation of values of kind K to values of kind L) begin -- end loop:
(-
	for ({-my:0} = BlkValueRead({-by-reference:r}, RRV_STORAGE), {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) :
		  {-my:0} >= 0 : {-my:0}--, {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) ) {
		if (BlkValueRead({-by-reference:r}, {-my:1}) & RRF_USED) {
			if (KOVIsBlockValue({-strong-kind:K}))
				BlkValueCopy({-by-reference:x}, BlkValueRead({-by-reference:r}, {-my:1} + 1));
			else
				{-by-reference:x} =  BlkValueRead({-by-reference:r}, {-my:1} + 1);
			if (1) {-block}
-).

To repeat for/with/-- (y - nonexisting L variable) running/-- through/in values of (r - relation of values of kind K to values of kind L) begin – end loop:
(-
for ({-my:0} = BlkValueRead({-by-reference:r}, RRV_STORAGE), {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) :
{-my:0} >= 0 : {-my:0}–, {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) ) {
if (BlkValueRead({-by-reference:r}, {-my:1}) & RRF_USED) {
if (KOVIsBlockValue({-strong-kind:K}))
BlkValueCopy({-by-reference:y}, BlkValueRead({-by-reference:r}, {-my:1} + 2));
else
{-by-reference:y} = BlkValueRead({-by-reference:r}, {-my:1} + 2);
if (1) {-block}
-).

To repeat for/with/-- (x - nonexisting K variable) and (y - nonexisting L variable) running/-- through/in (r - relation of values of kind K to values of kind L) begin – end loop:
(-
for ({-my:0} = BlkValueRead({-by-reference:r}, RRV_STORAGE), {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) :
{-my:0} >= 0 : {-my:0}–, {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) ) {
if (BlkValueRead({-by-reference:r}, {-my:1}) & RRF_USED) {
if (KOVIsBlockValue({-strong-kind:K}))
BlkValueCopy({-by-reference:x}, BlkValueRead({-by-reference:r}, {-my:1} + 1));
else
{-by-reference:x} = BlkValueRead({-by-reference:r}, {-my:1} + 1);
if (KOVIsBlockValue({-strong-kind:K}))
BlkValueCopy({-by-reference:y}, BlkValueRead({-by-reference:r}, {-my:1} + 2));
else
{-by-reference:y} = BlkValueRead({-by-reference:r}, {-my:1} + 2);
if (1) {-block}
-).

Though the 9.3 → 10.1 differences are slight, both have conspicuous differences from my version which makes use of something new in 11.0: an abstraction layer for dealing with kinds conforming to the pointer value type that’s built on top of the block value layer.

A really fundamental data structure with nigh-infinite application is a collection of mappings from X → Y. In Perl or Ruby these are called Hashes. In Python, it’s a dict. A more generic name is “associative array” (which is also what they’re called in PHP). Javascript objects can be employed this way, too, with some effort.

In inform, a one-to-various relation is the closest thing. But, historically, relations have been buggy, and there are undocumented gotchas. For instance, we can refer to the number of things that enclose a person but the number of numbers that boop a text would get a runtime error:

*** Run-time problem P59: You can't implicitly repeat through the values of this kind: a problem arising from a description which started out here [...]

And the absence of an ability to loop through keys and values at once severely limited utility as a hash. I think this is going to change my Inform programming and to decide what relation [...] will pop up a lot going forward.

A week ago, I wrote another novel loop I find useful for looping through the characters of a text, something that is infeasibly slow for all but the shortest of strings with the best way I7 directly offers.

To repeat with/for (c - nonexisting unicode character variable) running/-- through/in chars/characters of/in/for (t - text) begin -- end loop:
(-
  {-my:0} = {t}-->0;
  @push {-my:0};
  {-my:1} = TEXT_TY_Temporarily_Transmute({-by-reference:t});
  @push {-my:1};
  for ( {-my:1} = 0, {c} = BlkValueRead({-by-reference:t}, 0) : {c} : {c} = BlkValueRead({-by-reference:t}, ++{-my:1} ))
    {-block}
   @pull {-my:1};
   @pull {-my:0};
   TEXT_TY_Untransmute({-by-reference:t}, {-my:1}, {-my:0});
-)

(Also in that thread, Zarf posted a setiosys solution akin to previous BBA award #24.)

I will cherish the King of Loopiness title. :laughing:

5 Likes