I'm looking for a clever way to increment and then decrement a counter variable. I want the counter variable to begin at a low value and increment, towards a higher value. Once it reaches the higher value, the counter decrements until it reaches back to the lower value. Once it reaches the lower value, the counter increments again to the higher value ... I think you get the point.
I am working on a a canvas animation where I'd like to employ some cleverness, without using if
or other conditional tests:
Here is the conditional logic that handles the counter variable:
incrementing = true
foo = ->
length += 1 if incrementing
length -= 1 if not incrementing
incrementing = false if length > 100
incrementing = true if length < 1
Initially, I thought I could use modulo. However, modulo division only resets the counter back to the lower value -- it doesn't decrement the counter once it reaches the top value.
0 % 10 = 0
1 % 10 = 1
2 % 10 = 2
3 % 10 = 3
4 % 10 = 4
5 % 10 = 5
6 % 10 = 6
7 % 10 = 7
8 % 10 = 8
9 % 10 = 9
10 % 10 = 0
11 % 10 = 1
12 % 10 = 2
13 % 10 = 3
I'm sure there has to be a way to do this without using conditional tests. Assuming a bottom value of 0 and a top value of 10, the method should output the following.
? = 0
? = 1
? = 2
? = 3
? = 4
? = 5
? = 6
? = 7
? = 8
? = 9
? = 8
? = 7
? = 6
? = 5
I'm looking for a clever way to increment and then decrement a counter variable. I want the counter variable to begin at a low value and increment, towards a higher value. Once it reaches the higher value, the counter decrements until it reaches back to the lower value. Once it reaches the lower value, the counter increments again to the higher value ... I think you get the point.
I am working on a a canvas animation where I'd like to employ some cleverness, without using if
or other conditional tests:
Here is the conditional logic that handles the counter variable:
incrementing = true
foo = ->
length += 1 if incrementing
length -= 1 if not incrementing
incrementing = false if length > 100
incrementing = true if length < 1
Initially, I thought I could use modulo. However, modulo division only resets the counter back to the lower value -- it doesn't decrement the counter once it reaches the top value.
0 % 10 = 0
1 % 10 = 1
2 % 10 = 2
3 % 10 = 3
4 % 10 = 4
5 % 10 = 5
6 % 10 = 6
7 % 10 = 7
8 % 10 = 8
9 % 10 = 9
10 % 10 = 0
11 % 10 = 1
12 % 10 = 2
13 % 10 = 3
I'm sure there has to be a way to do this without using conditional tests. Assuming a bottom value of 0 and a top value of 10, the method should output the following.
? = 0
? = 1
? = 2
? = 3
? = 4
? = 5
? = 6
? = 7
? = 8
? = 9
? = 8
? = 7
? = 6
? = 5
Share
Improve this question
edited Oct 27, 2014 at 15:27
luk3thomas
asked Oct 27, 2014 at 15:16
luk3thomasluk3thomas
2,6221 gold badge19 silver badges20 bronze badges
1
-
1
+1
for a needing a solution to a total non-problem, purely to make your code more beautiful. This is why we learn CoffeeScript. – Carl Younger Commented Oct 29, 2014 at 15:42
2 Answers
Reset to default 16First let's look at some waves !
Hello waves !
Can you identify the one that matches your needs ?
If you guessed Triangle Wave, you're right !
Triangle wave oscillates with a uniform slope until it hits a min or max, and then the slope is inverted.
Two things to work out here:
- the origin of the function will start in the middle of the wave
- the wave oscillates from
x
to-x
We want to start the output at 0
and only include positive values
function triangle(t, a) {
return Math.abs(((t + a/2) % a) - a/2);
}
Let's try it out
for (var i=0; i<20; i++) {
console.log(i, triangle(i, 10));
}
Output
0 0
1 1
2 2
3 3
4 4
5 5
6 4
7 3
8 2
9 1
10 0
11 1
12 2
13 3
14 4
15 5
16 4
17 3
18 2
19 1
So when we call triangle(i, 10)
the 10
is the "period". This tells us how many steps we want to have in our function before it repeats.
A period of 6
would give us 6 values, 0, 1, 2, 3, 2, 1
A period of 4
would give us 4 values, 0, 1, 2, 1
etc
If you want to go from 0-9
, you would need a period of 20
Here's one:
(x&8)+(x&7)*((~x&8)/4-1)
which will give you
0,1,2,3,4,5,6,7,8,7,6,5,4,3,2,1,0,1,...
Of course there actually is a conditional in there, just hidden as a bitwise operation.
Another possibility is a triangle wave counter:
(x^((x&8)/-8))&7
which does
0,1,2,3,4,5,6,7,7,6,5,4,3,2,1,0,0,...
again there's a hidden conditional that flips the bits when it gets halfway.