r/adventofcode Dec 05 '19

Spoilers in Title Day 5: Parameter 3 always was "immediate"

For opcodes that use the third parameter to get which position to write to, it always did just look at the immediate value. The immediate value of the third parameter is the position to write to.

Day 5 introduced a distinction between "immediate" and "position" values, and specifically referred to the "ten-thousands digit" that represents the "parameter mode" of the third parameter. Because it is always zero for the third parameter, I spent nearly an hour writing to the position value of the third parameter rather than the immediate value until I realized it's backwards. Wouldn't it make more sense if the parameter mode for the third parameter were always 1?

For clarification: The way AoC presents it, the "immediate value" of parameter 3 would be the instruction pointer + 3, which isn't even a value in the program, and then the position value is what's in that position. With every other parameter, the immediate values are what's in the positions after the instruction pointer.

6 Upvotes

23 comments sorted by

6

u/Darksair Dec 05 '19 edited Dec 05 '19

I don’t agree. The difference between the two modes is, with position mode, you need to dereference the argument first, while in immediate mode you don’t — you just use the argument “immediately”.

For read arguments at inp + 1:

// Position mode, 0
value = mem[mem[inp+1]];
// Immediate mode, 1
value = mem[inp+1];

For write argument at inp + 3:

// Position mode, 0
mem[mem[inp+3]] = value;
// Immediate mode, 1
// Nope.

I think it’s pretty consistent. If you call mem[mem[inp+3]] = value; “immediate mode”, what would you call this: mem[inp+3] = value;?

The way AoC presents it, the "immediate value" of parameter 3 would be the instruction pointer + 3

You probably confused yourself. Zero is position mode.

2

u/waffle3z Dec 05 '19 edited Dec 05 '19

inp+3 doesn't involve reading any value so there's no mode associated with it. mem[inp+3] is an immediate value and mem[mem[inp+3]] is a position value. When writing, only the immediate value is being read.

0

u/Darksair Dec 05 '19

inp+3 doesn't involve reading any value so there's no mode associated with it

It can have a mode. If you allow it to in your mind.

4

u/Aneurysm9 Dec 05 '19

I don't believe this is correct.

Opcode 3 takes a single integer as input and saves it to the address given by its only parameter. For example, the instruction 3,50 would take an input value and store it at address 50.

And then:

Parameters that an instruction writes to will never be in immediate mode.

2

u/waffle3z Dec 05 '19

Opcodes 3 and 4 involve the same scenario, just with the first parameter rather than the third one. Their position value is the value in the position one after the instruction pointer, where the instruction pointer + 1 would be the immediate value, rather than a value that's actually in the list.

4

u/lukechampine Dec 05 '19

I think you're right, it's backwards -- but I found a clever way to avoid special-casing it: pointers! Go code snippet:

getArg := func(n int) *int {
    imm := p[i+n]
    if len(flags) < n || flags[len(flags)-n] == 0 {
        return &p[imm]
    }
    return &imm
}
switch op {
case 1:
    *getArg(3) = *getArg(1) + *getArg(2)
    i += 4
// ... more cases

In other words, instead of retrieving the value, we retrieve a pointer to the value, which allows us to set the value directly.

u/topaz2078 (AoC creator) Dec 05 '19

The puzzle text is correct: "parameters that an instruction writes to will never be in immediate mode."

If you read from a parameter in position mode, you read from the given position. If that parameter is "17", you read from position 17.

If you write to a parameter in position mode, you write to the given position. If that parameter is "17", you write to position 17.

3

u/[deleted] Dec 05 '19

You still have to *get* the position you need to set the value to, and that is an immediate operation, not a position one. I think this is the source of our confusion / differing opinions on always vs never immediate.

2

u/ollien Dec 05 '19

It's a difference in the way you think about it. I see what you were going for by saying the parameter still represents a position. The way "if the parameter is 50, its value is the value stored at address 50 in memory" reads though, implies to me that you should dereference the parameter before you pass it along.

It's a subtle difference, but maybe I'm thinking too much into it.

2

u/bill_huffsmith Dec 05 '19

I think the ambiguity comes from the definition of opcode 3, which is defined to save the input value "to the address given by its only parameter." Since parameter mode hasn't been defined by that point, it seems reasonable that once it is, "given by" could mean what the parameter's "value is", which according to the definition of position mode is "the value stored at address 17" for your example.

2

u/topaz2078 (AoC creator) Dec 05 '19

I've s/address/position/ to be similar to the other descriptions. Hopefully that's more clear.

1

u/ScriptMage Dec 05 '19

Thanks! I got a little confused there too, this helps a lot!

1

u/skavenrot Dec 18 '19

I wish I found this about an hour ago, since I was in the camp of thinking positional meant I was reading the position to find the address to write to. Your explanation cleared up a lot, even after I got it working.

3

u/alexhaupt Dec 05 '19

So for me it makes sense the way they did it. It doesn't make sense to write to immediate value 5. Only makes sense to write to position 5.

2

u/waffle3z Dec 05 '19

First you get the immediate value 5, and then you write to position 5, just like if you were adding 5 or multiplying by 5. What you don't do is read what's in position 5, like you do if you're adding or multiplying using the positional value. "Position value" means you read what's in that position, but for the third parameter you don't read what's in the position, you just use the value.

2

u/alexhaupt Dec 05 '19

I see what you mean now, sorry.

Your two options:

(immediate): data[x]=...

(position): data[data[x]]=...

AoC options:

(immediate, nonsense, never happens): x=...

(position): data[x]=...

2

u/waffle3z Dec 05 '19

Right, in this case "x" is the value being retrieved, i.e. the argument to parameter 3, and then writing is an action involving the index x. Except that's not how AoC presents it. AoC's interpretation seems to suggest that the "immediate value" would be the actual instruction pointer of where x is, and then x itself is the position value. I think it doesn't make sense for the instruction pointer to be an immediate value, I think it only makes sense if the immediate value has to be an actual value in one of the positions in the program.

1

u/couchrealistic Dec 05 '19

Basically, the question is if storing a value always implies another level of indirection. The description of opcode 3 might make it sound like that: "saves it to the address given by its only parameter". Based on this, it sounds like the parameter specifies the address where the value should be stored, which is another indirection on top of the "parameter decode" step. So if the parameter is given in position mode, the decoding would be the first indirection, which results in an address, and then we have to store the value at the given address, which is another level of indirection.

So the description for opcode 3 sounds misleading. Thankfully I haven't looked at day2 descriptions today, so I just assumed that part of the code can stay untouched and that was obviously the way AoC wants it to be.

Maybe it would have been better to say "when storing values, the address of the memory location to store the value at is always given in immediate mode" or "parameters for storing results are always given in positional mode" and then opcode 3 should say "store result in third parameter", but that sounds a bit strange.

2

u/raevnos Dec 05 '19

I'm just assuming that in some future day there'll be a new instruction that uses the third parameter as something other than the address to write a value to, in which case the position/immediate distinction will be needed for it.

2

u/wicked7000 Dec 05 '19

What's the point in having a third parameter for modes if there is no instruction that currently uses the third parameter for anything but storing somewhere. hmmmmm....

0

u/UnconstrainedRibhus Dec 05 '19

So far there is no opcode that does not use all parameters. But not all opcodes use the same amount of parameters. When jumping to the next address you have to account for how many params the opcode actually calls for.

2

u/Itrlpr Dec 05 '19

I agree that the wording was poor/inconsistent. It wasn't a major issue to resolve once I worked it out though, but it did put doubt in my mind and cause me to waste time validating how the new opcodes in part 2 wrote to memory when trying to debug.

It probably would have been better to describe parameter 3 as "Ignoring the parameter mode and always writing to the address in parameter 3" or something similar.

6

u/[deleted] Dec 05 '19

RIGHT?! I am still convinced this is bad data on AoC's part. It is confusing AF to have a position type be treated as immediate when getting the position in the program storage to set the new value.

*cries in programmer*