Euler Challenge 349: Javascript: Code works but is too slow - javascript

I've been trying to code a solution to project Euler's problem 349 in javascript (I know this is a less than ideal language for this). The problem is basically Langtons ant but with 10^18 moves. A full description of the challenge can be seen here . I managed to get some working code where I use a array as the grid of squares. If a value in the array is 1 then its black, if its 0, its white. Now the problem with this code is it is much too slow, it takes about 28 seconds to calculate 1 million moves. Any ideas on how I might go about optimizing this code?
var grid = [];
for (i = 0; i < 1000000; i++) {
grid.push(0);
}
var sum = 0;
var orientation = 0;
var position = (grid.length / 2);
var rowLength = Math.sqrt(1000000);
var mover = function() {
switch (orientation) {
case -360:
position += 1;
break;
case -270:
position += rowLength;
break;
case -180:
position -= 1;
break;
case -90:
position -= rowLength;
break;
case 0:
position += 1;
break;
case 90:
position += rowLength;
break;
case 180:
position -= 1;
break;
case 270:
position -= rowLength;
break;
case 360:
position += 1;
break;
default:
alert("fault in clockwise switch");
}
};
var check = function() {
for (i = 0; i < grid.length; i++) { //counts all blacks (1's)
if (grid[i]) {
sum += 1;
}
}
};
var movement = function() {
for (i = 0; i < 1000000; i++) { // end condition of i is number of steps
if (grid[position]) //if it lands on a black
{
grid[position] = 0;
if (orientation === 360) { //keeps orientation below 360
orientation = 0;
}
orientation += 90; //90 degree clockwise turn
mover();
} else if (!grid[position]) { //if it lands on a white
if (!grid[position]) {
if (orientation === -360) {
orientation = 0;
}
grid[position] = 1;
orientation -= 90;
mover();
}
}
}
};
movement();
check();
console.log(position);
console.log(sum);

Langtons's ant eventually falls into a pattern and builds a "highway". You don't need to actually run for 10^18 iterations to identify this pattern and use it to predict the number of black squares at any future time.

Related

How can you make canvas shapes move faster without them desyncing?

So, i've coded this canvas animation and I would like the shape to move faster though when doing so the shapes desync.
When I increment the values show below, so that the shapes would faster, they do so but eventually move away from eachother and desync.
if (this.dir[i][j] === 'downright') { //go down and right
this.boxLines[i][j].y += 1;
this.boxLines[i][j].x += 1;
}
if (this.dir[i][j] === 'downleft') { //go down and left
this.boxLines[i][j].y += 1;
this.boxLines[i][j].x -= 1;
}
if (this.dir[i][j] === 'upright') { //go up and right
this.boxLines[i][j].y -= 1;
this.boxLines[i][j].x += 1;
}
if (this.dir[i][j] === 'upleft') { //go up and left
this.boxLines[i][j].y -= 1;
this.boxLines[i][j].x -= 1;
}
Any way to fix that or could i go about it some other way?
Link to jsfiddle: https://jsfiddle.net/frankpettersson/nqmy3fkd/7/

moving svg box with js

This is a svg box which can move using arrow keys.
I want this box to stop when the arrows are realeased, and to continue moving accordingly to the key presed.
This app uses svg, js, and jquery.
I have looked and have found no answer. Please help the cause.
$(function() {
var y = 4;
var x = 4;
var n;
var move;
$(document).keydown(function(e) {
switch(e.which) {
case 37: // left
move = setInterval(move_left, .1);
break;
case 38: // up
move = setInterval(move_up, .1);
break;
case 39: // right
move = setInterval(move_right, .1);
break;
case 40: // down
move = setInterval(move_down, .1);
break;
default:
return;
}
e.preventDefault();
});
function move_left() {
$("#block_green").attr({
x: x
});
x--;
}
function move_up() {
$("#block_green").attr({
y: y
});
y--;
}
function move_right() {
$("#block_green").attr({
x: x
});
x++;
}
function move_down() {
$("#block_green").attr({
y: y
});
y++;
}
}
});
body {
margin: 0;
overflow: hidden;
}
svg {
background-color: black;
width: 100vw;
height: 100vh;
}
#block_green {
fill: black;
stroke: #00ff00;
stroke-width: .5px;
}
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<svg>
<rect x="4" y="4" width="80" height="60" id="block_green"/>
</svg>
</body>
</html>
The code doesn't seem to work here, so you may want to visit http://codepen.io/julian-a-avar/pen/PqZvxp to see it in action, and you may want to check an editor, because as I said before, The preview doesn't seem to work here!!!
I would make the loop seperate and set variables that determine which keys are pressed.
Use keydown to set the variables to true and keyup to set the variables back to false.
Something similar to this:
$(function() {
var y = 4;
var x = 4;
var n;
var move;
var leftPressed = false;
var rightPressed = false;
var downPressed = false;
var upPressed = false;
setInterval(function(){
if(leftPressed){
move_left();
}else if(rightPressed){
move_right();
}
if(upPressed){
move_up();
}else if(downPressed){
move_down();
}
},.01)
$(document).keydown(function(e) {
switch(e.which) {
case 37: // left
leftPressed = true;
break;
case 38: // up
upPressed = true;
break;
case 39: // right
rightPressed =true;
break;
case 40: // down
downPressed = true;
break;
default:
return;
}
e.preventDefault();
});
$(document).keyup(function(e) {
switch(e.which) {
case 37: // left
leftPressed = false;
break;
case 38: // up
upPressed = false;
break;
case 39: // right
rightPressed =false;
break;
case 40: // down
downPressed = false;
break;
default:
return;
}
e.preventDefault();
});
function move_left() {
$("#block_green").attr({
x: x
});
x--;
}
function move_up() {
$("#block_green").attr({
y: y
});
y--;
}
function move_right() {
$("#block_green").attr({
x: x
});
x++;
}
function move_down() {
$("#block_green").attr({
y: y
});
y++;
}
});
Notice setInterval is just checking the variables to determine which methods to call to move the box.
Here is a codepen with an example
Question 2
How to adjust the speed of the moving block?
One way to adjust the speed is to set a variable that determines how much x or y changes with each pass in setInterval. So make another variable n and setting that value higher makes the block move faster and lower makes it move slower.
Additionally, you asked if there are ways to shorten up the code. There are probably numerous ways that code could be improved if you get creative. Below I've provided an example with the variable n and provided one way you could shorten up the code. Instead of having variables for every key pressed just have two variables for the horizontal and vertical axis:
$(function() {
var y = 4;
var x = 4;
var n = 1;
var move;
var xDirection = 0;
var yDirection = 0;
setInterval(function(){
x = x + (xDirection * n);
y = y + (yDirection * n);
$("#block_green").attr({
y: y,
x: x
});
},.01)
$(document).keydown(function(e) {
xDirection = e.which == 37 ? -1 : xDirection;
xDirection = e.which == 39 ? 1 : xDirection;
yDirection = e.which == 38 ? -1 : yDirection;
yDirection = e.which == 40 ? 1 : yDirection;
e.preventDefault();
});
$(document).keyup(function(e) {
xDirection = e.which == 37 ? 0 : xDirection;
xDirection = e.which == 39 ? 0 : xDirection;
yDirection = e.which == 38 ? 0 : yDirection;
yDirection = e.which == 40 ? 0 : yDirection;
e.preventDefault();
});
});
And here is another codepen of the changes
Also i'd recommend looking into some basic game algos (like 80's arcade games, ie Space Invaders, etc) They will have this kind of game logic.
If you're interested, this video on vimeo is pretty cool and a good example of this kind of dev, developer creating space invaders real time in javascript

JS - moving an image horizontally after a period of time

Everything was going smoothly until now. I want to have this hor() function reverse after 20 seconds. The original hor() function grabs an image offscreen and moves it horizontally from the left to the center of the page. I'd like to create a function that does the opposite after 20 seconds. The "after 20 seconds" part is giving me the most grief. If you could show me what a new function would look like or an 'else' addition to the current function that would be great. Thanks.
<script language="JavaScript" type="text/JavaScript">
var x = -500;
var y = 100;
function hor(val) {
if (x <= 500){
x = x + val;
document.getElementById("pos").style.left = x + "px";
setTimeout("hor(5)", 10);
}
}
</script>
<style type="text/css">
<!--
#pos {
position: absolute;
left: -500px;
top: 100px;
z-index: 0;
}
</style>
<body onLoad="setTimeout('hor(5)',5000)">
<div id="pos">
<img src="image.jpg">
</div>
Perhaps you could try changing the script to this:
// Define variables
var x = -500,
y = 100,
direction = 1;
// Function which moves "pos" element
function hor(val) {
// Move by specified value multiplied by direction
x += val * direction;
if(x > 500){
x = 500;
// Reverse direction
direction = -1;
} else if(x < -500){
x = -500;
// Reverse direction, once again
direction = 1;
}
// Move element
document.getElementById("pos").style.left = x + "px";
// Continue loop
setTimeout("hor("+val+")", 10);
}
This code will continue moving the pos element by the specified value until x greater than 500, at which point it will switch direction, then continue until x reaches -500, and so on.
EDIT:
This code will fix that issue with 20 seconds (I had thought that the 500 pixel thing computed to 20 seconds, lol).
// Define variables
var x = -500,
y = 100,
direction = 1;
firstCall = true;
timeElapsed = 0;
// Function which moves "pos" element
function hor(val) {
// Don't let the first call count!
if(!firstCall)timeElapsed += 10;
else firstCall = false;
if(timeElapsed >= 2000){
// Reverse direction
direction *= -1;
timeElapsed = 0;
}
// Move by specified value multiplied by direction
x += val * direction;
// Move element
document.getElementById("pos").style.left = x + "px";
// Continue loop
setTimeout("hor("+val+")", 10);
}
Try this. Here the img is moved horizontally and after sometime it is reverted back to its original position.
<script>
var x = -500;
var y = 100;
var op;
function hor(val) {
if (x <= 500 && x>=-500) {
x = x + val;
document.getElementById("pos").style.left = x + "px";
setTimeout(function(){hor(val);},10);
}
}
$(document).ready(function(){
setTimeout(function(){hor(5);},1000);
setInterval(function(){
setTimeout(function(){hor(-5);},1000);
},2000);
});
</script>
I have changed the timings for testing purpose only, you can change it back.

gravity inside html5 canvas

I'm trying to do a copy of the original super mario game using html5 canvas just for fun and to learn more about the canvas tool and it's animation but i am stuck at making Mario do it's jump here is my jsfiddle : http://jsfiddle.net/2tLCk/1/
how should i fix my up function to make mario jump and return back to the ground like in this website http://blog.nihilogic.dk/ i tried to understand it's code but i couldn't ?
if (keydown.up) {
vy += gravity;
character.CurentPos = 11;
character.x += character.speed;
character.y += vy;
}
Here's a jumping Mario http://jsfiddle.net/2tLCk/22/.
If jumping is 1 - going up. If jumping is 2 - going down.
if(jumping){
if(jumping == 1) {
if(character.y > 140) character.y -= gravity;
else jumping = 2;
} else if(jumping == 2) {
if(character.y < 184) character.y += gravity;
else{
character.y = 184;
jumping = false;
character.CurentPos = 6;
}
}
}else if(keydown.up) {
jumping = 1;
character.CurentPos = 11;
}
And you would probably want to use this https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame instead of setInterval().
You basically want the gravitiy to be always active, not only when pushing the down key.
When jumping (key up) you have to add to vy. Like this:
if(keydown.up) {
vy += -2;
}
vy += gravity;
if(character.y > 184) { // simple collision detection for ground floor
vy = 0;
character.y = 184;
}
//character.CurentPos = 11;
//character.x += character.speed;
character.y += vy;
see http://jsfiddle.net/pjQb3/
I would do something like this:
// Global forces
character.vy += gravity;
// User input
if (keydown.up) {
character.vy += -2;
}
// Final location
if (character.y + character.vy >= 184) {
// Update player location.
character.y += character.vy;
} else {
// Player was about to move past ground so place player directly on ground
// and reset velocity.
character.y = 184;
character.vy = 0;
}

wierd function behavior on osX with google chrome browser

This text area is an auto expanding text area that stops expanding when it is the height of 4 lines.
mac problem http://dl.dropbox.com/u/8196173/mac_problem.PNG windows version http://dl.dropbox.com/u/8196173/windows_version.PNG
So the one on the left is how the text box is getting displayed on mac with Google chrome and the one on the right is how it is getting displayed on windows. The windows version is the correct one. For some reason chrome on mac does not add the same amount of height to the text area each time it expands which means that it ends up smaller and hence the extra space at the bottom. But for the life of me I don't know why it would behave like this just because its on a different OS.
I can include code if people really want it but its almost a hundred lines (there are other things being moved on the page when this expands) and I honestly don't see how it could be the code since it works on windows and only exhibits the odd behavior on osX.
Edit: this is happening inside of a chrome extension in case that makes a difference.
var temp = 0;
//function that actually handles the resizing
function resize() {
temp = text.style.height;
text.style.height = 18;
text.style.height = text.scrollHeight + 'px';
var styledef = window.getComputedStyle(text);
pixelMargin = parseInt(styledef.marginTop, 10);
num = parseInt(container.style.height, 10);
re_num = parseInt(reply_container.style.marginTop, 10);
var temp_num = parseInt(temp, 10);
text_height = parseInt(text.style.height, 10);
if(temp_num == 0) { //if nothing has been done in the text area do this
temp = text.style.height;
} else if(text_height == 18) { //else if the text area is only one line do this
text.style.marginTop = '3';
reply_container.style.marginTop = '0px';
container.style.height = '364px';
container.scrollTop = container.scrollHeight;
} else if(temp_num < text_height) { //else the box is getting bigger
if(text_height <= 66 ) {
pixelMargin -= 15;
num -= 16;
re_num += 16;
conversation_scroll_pos += 16;
text.style.marginTop = pixelMargin.toString() + 'px';
container.style.height = num.toString() + 'px';
reply_container.style.marginTop = re_num.toString() + 'px';
container.scrollTop = container.scrollHeight;
temp = text.style.height;
} else if(text_height >= 66 && temp_num > 20) { //case where the box has reached its max height and the user is still typing
temp = text.style.height;
} else if(text_height > 66 && pixelMargin == 3) { //edge case to handle cuting and pasting into the box
text.style.marginTop = '-42px';
reply_container.style.marginTop = '48px';
container.style.height = '316px';
container.scrollTop = container.scrollHeight;
temp = text.style.height;
}
} else if(temp_num > text_height) { //else the box is getting smaller
if(pixelMargin < 3 && pixelMargin >= -45 && text_height < 66) {
pixelMargin += 15;
num += 16;
re_num -= 16;
text.style.marginTop = pixelMargin.toString() + 'px';
container.style.height = num.toString() + 'px';
reply_container.style.marginTop = re_num.toString() + 'px';
temp = text.style.height;
}
}
}

Categories