Level: Harvest Time

Another level from @gosnat, this time with some peaceful mushroom farming. Harvest a hundred mushrooms in this level with a for-loop in under five lines of code. Please post any adventuring feedback here.

A link to the level since I don’t see it on the list quite yet.

Cool.

It’s a bit annoying though that the victory screen comes immediately after i entered my ‘winning code’. You should be able to watch the mushrooms being collected (cutscene style) to show that you ‘actually won’.

That would make it even cooler.

@JasperDhaene

Thanks for the feedback. I’ve added in the ability to watch the mushrooms being collected.

I tried to have it playback in fast forward, but that’s not quite working at the moment.

Can someone help me with this level? I just cant figure it out

@Sh4d0W
Well, can you post what you’ve tried so far?

Well I tried using a for loop but I cant figure out the logic for this one. I tried if (i == 1) {moveXY} but its just not right.

@Sh4d0W

Well, note that moveXY() requires an x coordinate and a y coordinate. For instance, a call to moveXY(10, 15) would move to an x (horizontal) coordinate of 10 and a y (vertical) coordinate of 15.

Try using the loop iterator variable as your y coordinate.

Yeah I know that but I cant figure it out, how it could be done in less than 5 lines of code.

I was thinking like for each for loop it could move to some X and then Y + 20 or so. But then I would somehow have to move the character to the beginning of a new row.

@Sh4d0W

Well, why don’t you take a step back for a minute and try listing out all of the points that you need to get to for a solution without trying to stay under 5 lines. Do you notice any repetition or patterns? What are the coordinates for the beginning of each row? They should all have something in common, but also something that’s different.

Use the loop iterator to cover the values you need for the different part, and the loop body will cover the part that’s the same every time (plus the loop iterator for the other value).

@gosnat Thank you!. I just needed to think about it for a while. Also I didnt know I could use the properties.

If I can put the code here, this is what I used:

for(var i = 0; i < 5; i++) {
    this.moveXY(this.pos.x, this.pos.y + 45);
    this.moveXY(this.pos.x + 10.5, this.pos.y - 45);
}

The last time the loop runs, the character still moves down even tho all the mushrooms are collected.
I would fix it this way:

for(var i = 0; i < 5; i++) {
    this.moveXY(this.pos.x, this.pos.y + 45);
    if(i < 4) {
        this.moveXY(this.pos.x + 10.5, this.pos.y - 45);
    }
}

Or could it be done better way? Thanks again.

That’s certainly one way to do it. You could also do it by providing absolute coordinates to the moveXY() method rather than relative coordinates.

Yes, thanks… Could this be done better? Except when I would change this.pos.y + 45 to lets say absolute 75.

for(var i=25; i–; this.moveXY(i*2, 25+(i%2)*50));

1 Like

Thanks, even tho I dont understand that one :smiley:

I’ll offer a differing opinion from no_login_found on that one:

All other things being equal (correctness, efficiency, etc), code that’s easy to understand (and therefore harder to mess up by accident) can trump code that’s a little more compact. Now, code that’s way bulkier than it needs to be can be bad, but saving a few keystrokes and producing obtuse code often isn’t enough of an advantage over code that’s clear and easy to read but slightly longer. (emphasis on the slightly)

Now as to what’s going on with no_login_found’s code, there are a few tricks being pulled:

  1. the conditional of the loop is taking advantage of the fact that javascript will treat a value of ‘0’ as being ‘false’. Some languages (C/C++ will allow that as well) allow that, some (like Java) don’t.

  2. The use of a post decrement also means that the value of i is evaluated prior to decrementing (lowering the value by 1).

  3. The i%2 will make it so that all even values of i will skip the adding on of 50 part (since an even number mod 2 is 0). This allows one statement to have two different behaviors depending on whether the current i value is even or odd.

  4. Since the “end of each iteration action” behavior (i–) is actually in the second clause of the for loop, single statement for the loop (this.moveXY()) can be placed in the third clause. Conceptually, that third clause is actually the loop body, but when the compiler unravels this code, it will end up being the same.

A slightly more clear version of this code (that executes pretty much identically) is:

for(var i = 50; i != 0; i = i - 2){
this.moveXY(i, 25);
this.moveXY(i, 75);
}

1 Like

Sure, such code in production is a bad practice, but it may be good for learning… at least for those who want to learn and for whom some unobvious code is a challenge.
Anyways, this level does not give any other challenges even for slightly experienced people.
And it encourages some other bad practices - like hardcoding start/end coordinates as inline literals, or providing essential info in a comments when it shall be provided with the means of language(like constants). Providing those coordinates with getters will be even better. Maybe there shall be some levels that show on real examples why ‘bad practices’ are really bad, like punishing hardcoded coordinates with moving the mushroom field to other place.

1 Like

@no_login_found
Hey, the level stated that compact code was one of the goals, so I shouldn’t rag on you for rising to the challenge. I just didn’t intend for anyone to take it that far.

Do you feel it would be an improvement to have the row/column start/end coordinates available as a property rather than listed in comments? That would be a fairly easy change to make.

The level was not meant to be difficult, and shouldn’t be challenging to those who are already experienced coders.

edit: I’ve added xmin, xmax, ymin and ymax properties to the level. Do people think that helps or hurts the level?

Thanks for your explanation and code gosnat.

for(var i = 50; i != 0; i = i - 2){
this.moveXY(i, 25);
this.moveXY(i, 75);
}

This actually makes sense to me,

I wonder why my JavaScript code
plan()

for (var x = this.xmin; x <= this.xmax; x += 10) {
  for (var y = this.ymin; y <= this.ymax; y += this.ymax-this.ymin) {
    this.moveXY(x, y);
  }
}

works fine for this level, but this ugly JavaScript code
plan()

var x, y, _i, _j, _ref, _ref1, _ref2, _ref3, _ref4;
for (x = _i = _ref = this.xmin, _ref1 = this.xmax; _i <= _ref1; x = _i += 10) {
for (y = _j = _ref2 = this.ymin, _ref3 = this.ymax, _ref4 = this.ymax - this.ymin; _ref4 > 0 ? _j <= _ref3 : _j >= _ref3; y = _j += _ref4) {
this.moveXY(x, y);
}
}

produced by compiler from my CoffeeScript code
plan()

@moveXY x, y for y in [@ymin..@ymax] by @ymax - @ymin  for x in [@xmin..@xmax] by 10

moved the peasant only to (@xmin,@ymin) and he had stopped there.
Then I put to console

this.xmin = 0;
this.ymin = 25;
this.xmax = 50;
this.ymax = 75;
this.moveXY = function(x, y) {
return console.log("(" + x + ", " + y + “)”);
};
var x, y, _i, _j, _ref, _ref1, _ref2, _ref3, _ref4;
for (x = _i = _ref = this.xmin, _ref1 = this.xmax; _i <= _ref1; x = _i += 10) {
for (y = _j = _ref2 = this.ymin, _ref3 = this.ymax, _ref4 = this.ymax - this.ymin; _ref4 > 0 ? _j <= _ref3 : _j >= _ref3; y = _j += _ref4) {
this.moveXY(x,y);
}
}

and output was:

(0, 25)
(0, 75)
(10, 25)
(10, 75)
(20, 25)
(20, 75)
(30, 25)
(30, 75)
(40, 25)
(40, 75)
(50, 25)
(50, 75)

I still don’t understand why the peasant does not want to move further.