Im writing a js simple simon game and im clueless on how to do it.
I know that :
I need to create two arrays, and a level(score) variable
A randomly generated number from 1 to 4 (inclusive) needs to be added
to the first array, When one of four buttons is pressed, the value
of it is added to the second array, if the second array is not the
same size or bigger than the first array. Each time a value is added
to the second array, check that the value is equal to the value in
the same position in the first array, if not, clear both arrays, and
set levelvar to 1, and alert "gameover" This means if you get one
wrong, you cannot continue. If the length of the second array
matches the level variable, add a random number to array one, clear
array two, increment levelvar.
But, I am clueless in aspect to the code.
My Jsfiddle :http://jsfiddle.net/jbWcG/2/
JS:
var x = []
var y = []
var levelvar = 1
document.getElementById("test").onclick= function() {
document.getElementById("test").innerHTML=x
};
document.getElementById("button1").onclick= function() {
x.push("Red")
};
document.getElementById("button2").onclick= function() {
x.push("Green")
};
document.getElementById("button3").onclick= function() {
x.push("Yellow")
};
document.getElementById("button4").onclick= function() {
x.push("Blue")
};
HTML:
<button id="button1">Red</button><br />
<button id="button2">Green</button><br />
<button id="button3">Yellow</button><br />
<button id="button4">Blue</button><br />
<p id="test">Click To see What you have clicked</p>
How would I make a two arrays see if a certain value is the same?
Lets say, that the generated array is : [1,2,3,4,1,2,3]
and i am at position 5 and i press 2, how would i check that the two numbers match?
Thanks in advance
The easiest way to check one at a time that position i of your array is x is
if (gen_arr[i] == x) {
// matches
} else {
// doesn't match
}
So if you conceptualize the flow of your game, you're going to want to, at each button press:
somehow keep track of which index they are on (maybe have a counter that increments with each button press)
checks if gen_arr[i] == x (and displays game over if it doesn't).
Alternatively, instead of keeping track of which index, you can call gen_array.shift() to get the first item in gen_array AND delete it from the array, in a flow kind of like this:
var gen_array = [1,2,3,4,1];
function press_button(button_pressed) {
var supposed_to_be = gen_array.shift();
// at this point, on the first call,
// supposed_to_be = 1, and gen_array = [2,3,4,1]
if (supposed_to_be != button_pressed) {
// game over!
} else {
// you survive for now!
if (gen_array.length() == 0) {
// gen_array is empty, they made it through the entire array
// game is won!
}
}
}
While that represents the general "what to check" at every step, using this verbatim is not recommended as it quickly leads to an unstructured game.
I recommend looking into things called "game state" diagrams, which are basically flow charts which have every "state" of the game -- which in your case, includes at least
"displaying" the pattern
waiting for button press
checking if button press is correct
game over
game won
And from each state, draw arrows on "how" to transition from one state to the next. You can do a google search to see examples.
Once you have a good game state diagram/flow chart, it's easier to break down your program into specific chunks and organize it better ... and you can usually then see exactly what you need to code and what is missing/what is not missing.
Related
I am new to JavaScript. I use it to write some scripts for Adobe Illustrator.
In this script I take a selection of items, and sub-select them by some user definded values (xPointMin, xPointMax, etc.). The loop below is the main part of the function.
My problem is that this loop is terribly slow. It takes several sec. to run a selection of 50 items.
I already tried the following:
run the loop without any if-condition inside. This is fast.
run the loop with only one if-condition inside. This is as fast as with all if-conditions.
Does someone know why it is so slow or can some just make it faster.
// xArray... are extracted vales from the Selection (xSel)
// xPointMin, xPointmax, xLengthMin, xLengthMay, xAreaMin, and xAreaMax are user defined values
for (var i in xSel) { // xSel is a list of selected items
var xTF = true; // xTF is temporary variable
// points // this will check if the given value (xArrayPoint) is within the requirements
if (xArrayPoint[i] <= xPointMin || xArrayPoint[i] >= xPointMax) {
xTF = false; // if so it sets the temporary variable to false
}
//length // same as in the first check, however we are testing the length
if (xArrayLength[i] <= xLengthMin || xArrayLength[i] >= xLengthMax) {
xTF = false
}
//area // same as in the first check, however this time we are testing area
if (xArrayArea[i] <= xAreaMin || xArrayArea[i] >= xAreaMax) {
xTF = false
}
xSel[i].selected = xTF; // changes the original value
}
}
The following code could save you a lot of time for you
array1.forEach(i =>
xSel[i].selected = !(
xArrayPoint[i] <= xPointMin || xArrayPoint[i] >= xPointMax ||
xArrayLength[i] <= xLengthMin || xArrayLength[i] >= xLengthMax ||
xArrayArea[i] <= xAreaMin || xArrayArea[i] >= xAreaMax
)
);
Let's look at what we have done over here. We did two major changes
Choosing forEach over traditional for: ForEach is considered to be faster than traditional for loops as they don't require re-initialization at every iteration.
Simplifying the multiple if conditions to a single assignment statement: As all the conditions are under OR operands, tt doesn't have to go through every condition if the first condition is truestrong text
If the loop is small, you won't see why it takes so long, but the conditionals won't make much sense, for example:
if (xArrayPoint [i] <= xPointMin || xArrayPoint [i]> = xPointMax)
This is clearly true, either one value is greater than another or it is less than or equal to another, there are only these 3 possibilities, its ifs are equivalent to if (true).
Something that may make a difference (but I'm not sure about that in javascript) is to create variables inside a loop, maybe that will be expensive in terms of processing in having to allocate space in memory to save this data.
Something that optimizes a lot in search of values in variables for example is the binary search algorithm, which is something very simple.
Say for example that you want to search for a certain value within an array, the idea of the binary search is based on first placing these values in ascending order and comparing the value you are comparing with the intermediate value of that array, if its value is for example higher than the intermediate value (smaller is the same idea) it will compare with the average value that is between the highest value of the array and the average value of the array, that is, it will divide the array in two until it finds the value sought.
I'm using P5.js to make a connect 4 game that I later want to use to make some training data for a ML project. I'm just currently working on making some logic. In a separate file, (separate just so I can test ideas) I have it so you hit a number 1-7 as a row number, and then it will color in your spot on the board. I'm using the logic system to know how far down the colored block needs to go. I have some arrays corresponding to the columns, and for testing purposes, I have 4 columns of 3 down. A 1 represents somewhere a piece is, and a 0 is an open space. When in a column, I use a for loop to iterate through, and if i is a 1, and i-1 is a 0, change i-1 to be a 1. This effectively simulates the gravity of dropping a piece down. The problem is, when I run console.log, both before and after my logic, it gives my the same result, but it's the post logic result. I don't know why it won't log the correct pre-logic array. My code is:
row = [2];
nums = [
[0,0,0],
[0,0,1],
[0,1,1],
[1,1,1]
]
console.log(nums[row])
//console.log(nums[row].length - 1)
for (i = 0; i<= ((nums[row].length) - 1); i++) {
//console.log(nums[row])
// console.log(i)
if ((nums[row][i]) == 1 && nums[row][i-1] == 0) {
nums[row][i-1] = 1
}
/*console.log(nums[row][i])*/
}
console.log(nums[row])
Before I run the logic, it shoud log [0,1,1] and after it should be [1,1,1]. Instead, any time I run it on a row that gets changed, it logs the output twice. I don't know why it isn't logging the array before it gets changed first. Any help would be great!
Yes, this can be annoying, and you should read certainly read the linked comment. But for a quick/dirty solution, you can use a function like the following:
function console_log(o)
console.log(JSON.parse(JSON.stringify(o)))
}
then call console_log(nums[row]) instead of console.log(nums[row])
I'm trying to modify the script from jsPsych library for linguistic and psychology experiment, here is a code which shows images in row and than user can answer.
You can set the time for how long the images will be visible, but only in group (=same time for every image), but I need to show the last and the one before last image different time. Couldanybody help me how to achieve that?
var animate_interval = setInterval(function() {
display_element.html(""); // clear everything
animate_frame++;
//zobrazeny vsechny obrazky
if (animate_frame == trial.stims.length) {
animate_frame = 0;
reps++;
// check if reps complete //
if (trial.sequence_reps != -1 && reps >= trial.sequence_reps) {
// done with animation
showAnimation = false;
}
}
// ... parts of plugin, showing answers and so on.
},
3000); // <---------------- how to change this value for the last and one before lastelement?
I don't know if this is enought to help me, but if not, ask me I will try to do the best. Thanks a lot in advance!
It is possible to use setInterval to show images using different intervals of time. Consider the following:
The control system shows images 1,2,…n-2 using the same interval of time, and shows images n-1,n using another interval of time (“setInterval”, 2015). Figure 1 is a process model of the control system in terms of a Petri Net. For the PDF version of this reply, it is an interactive Petri Net.
Figure 1
The mark for P_1 (m_1) is equivalent to the variable animate_frame. If m_1=0 then no image is shown. If m_1=1 then the first image is shown. If m_1=2 then the second image is shown. And so on. If a total of ten images will be shown, then the initial values are〖 m〗_0=8,〖 m〗_1=0, and〖 m〗_2=2.m_0 is used to control the use of the first interval of time. m_2 is used to control the use of the second interval of time. m_1 is used to show the image.
There are two execution or run logics:
The first execution or run logic (rn1) uses the first interval of time (e.g. one second). It shows images 1 to n-1. After showing image n-1 it removes the interval object, and schedules a new interval object for the second logic of execution.
The second execution or run logic (rn2) uses the second interval of time (e.g. four seconds). It shows the last image and then removes the last image from the display.
There are three ways to show the images. The first method (T_0) combines the display of the next image with incrementing m_1 by 1 and decrementing m_(0 )by 1. The second method (T_1) combines the display of the next image with incrementing m_1 by 1 and decrementing m_2 by 1. The third method (T_2) shows a blank space, removes the last image. At any given instant, none or just one of the computation logic T_0,T_1 and T_2 can occur. When none of the computation logics can occur, the execution logic ends; in other words, the interval object is cleared (e.g. clearInterval()).
Using the Petri Net in Figure 1 as a guide, the computer program for the control system may be organized as follows:
rn1
if (m_0≥1) {
// T_0
m_0=m_0-1
m_1=m_1+1
// update image using plugin API
} else if ((m_0==0) && (m_2≥1)) {
// T_1
m_2=m_2-1
m_1=m_1+1
// update image using plugin API
clearInterval(ai);
ai=setInterval(rn2,4000);
} else
clearInterval(ai);
rn2
if (m_2≥1) {
// T_1
m_2=m_2-1
m_1=m_1+1
// update image using plugin API
} else if (m_2==10) {
// T_2
m_1=m_1-1
// hide image using plugin API
} else
clearInterval(ai);
To start the control system:
ai=startInterval(rn1,1000);
Then rn1 will eventually call on st2, and rn2 will eventually end the process. If additional computations are needed (such as display_element.html("")) add them to rn1 and rn2.
References
“setInterval, different intervals for last and one before the last element (jsPsych)” (2015). Stack Overflow. Retrieved on Nov. 5, 2015 from setInterval, different intervals for last and one before last element (jsPsych).
Instead of setInterval, you can chain setTimeout callbacks. This will allow you to manipulate the delay between each function call. Here's how I would structure your function, and then implement the logic to determine delays for the final two tests.
var showImage = function(currTest, lastTest) {
display_element.html(""); // clear everything
animate_frame++;
//zobrazeny vsechny obrazky
if (animate_frame == trial.stims.length) {
animate_frame = 0;
reps++;
// check if reps complete //
if (trial.sequence_reps != -1 && reps >= trial.sequence_reps) {
// done with animation
showAnimation = false;
}
}
// ... parts of plugin, showing answers and so on.
// create a wrapper function so we can pass params to showImage
var wrapper = function() {
showImage(currTest + 1, lastTest);
}
if (currTest === lastTest) {
setTimeout(wrapper, your_other_desired_delay);
} else if (currTest - 1 === lastTest) {
setTimeout(wrapper, your_desired_delay);
} else if (currTest < lastTest) {
setTimeout(wrapper, standard_delay);
}
}
showImage(0, trials.length);
I'm basically trying to make a game that involves a grid. Here's what I have so far (it'll help to see the game before I explain what I need to happen):
Javascript (see jsfiddle for html):
var score = 0;
var points = function(val, box) {
var noise = Math.round(Math.round(0.1*val*Math.random()*2) - 0.1*val);
score = score + (val + noise);
var square = document.getElementById(box);
square.innerHTML = val + noise;
square.style.display='block';
setTimeout(function() {
square.style.display='none';
}, 400);
document.getElementById("out").innerHTML = score;
}
http://jsfiddle.net/stefvhuynh/aTQW5/1/
The four red squares at the bottom left of the grid needs to be the starting point in the game. When you click on one of those boxes, you can then travel along the grid by clicking adjacent boxes. Basically, I need to make it so that the player can only travel up, down, left, and right from the box that they just clicked on. I don't want the points function to be invoked when the player clicks on a box that they're not supposed to click on.
Additionally, I need to make it so that the player can't click on another box until 400 ms have elapsed.
I'm relatively new to programming so any help at all would be great. I would also appreciate tips on how to make the program more efficient, if there's a way to do that.
General idea:
I'd suggest having a similar id for all your boxes, such as box_x_y, and storing a list of strings, let's say allowedSquares.
You would then be able to write a function which, upon clicking on a box, would check if it's id is in allowedSquares, and if it is, call points(val, box) then update the contents of allowedSquares to reflect the change of position.
The point of using a standard id convention for all your boxes is that you could write getPosition(box) and getBox(intX, intY) that would parse the id strings to return you the box position, or vice-versa.
You can even make the updateAllowedSquares(clickedBox) function change the color of adjacent boxes to show they're allowed next steps.
EDIT: Some example code:
Disclaimer: these are not the code lines you're looking for.
This is only a starting kit for you, which assumes a 3x3 grid with a single-square bottom right starting position. You will have to adapt this code a bit. Also, I predict something will go wrong concerning going out of bounds. I'll let you think with this a bit, as I prefer giving food for thoughts over complete solutions in those cases...
var allowedSquares = ["box_2_2"]; // Initial list
function decodePositionFromID(boxId) {
return boxId.split("_").slice(1,2);
}
function getIDfromXY(x, y) {
return "box_" + x + "_" + y;
}
function updateAllowedSquaresList(boxID) {
// 1 - We clear the array.
allowedSquares.length = 0;
// 2 - We get the adjacent boxes IDs.
var xyArray = decodePositionFromID(boxId);
var upperBoxID = getIDfromXY(xyArray[0], xyArray[1]-1);
// Rince, repeat, and add some gameboard boundaries checks.
// 3 - We add the new IDs to the list.
allowedSquares.push(upperBoxID, ...);
}
function boxClick(val, boxID) {
// We check if the box is a valid square to play.
if (allowedSquares.indexOf(boxID) != -1) {
points(val, boxID);
updateAllowedSquaresList(boxID);
}
}
Basically, I'm getting an infinite loop and maybe I'm working too hard but I can't see why.
Context:
I'm using a carousel (Bootstrap's). The contents of the carousel is generated and pushed into one carousel slide, then the goal is to take the contents and split it up into multiple slides if the number of items inside surpass a certain pre-defined max-length property (5). I got this working fine for a specific use case of the carousel (a table being spread across the multiple slides if there are more than 5 table rows), but it's not generic enough. What happened is that the JS would take the overflown table rows (i.e. of index 5 and up), create a new slide from a harcoded HTML string in the function (a slide div containing all the markup for the table yet empty) and push those extra rows into it.
To make it more generic, I've decided to use classes like carousel_common_list and carousel_common_item which would be applied to the tbody and trs in the case I've explained. Then, I've to handle the template in a decoupled way. What I've tried to do is, take a clone of the original sole slide, empty the carousel_common_list and push any overflown carousel_common_items into it, and so on. But I get an infinite loop.
Code
What I've called a slide so far is called an item in the code (to match Bootstrap's carousel's item class for slides).
var carousels = $('div.carousel'),
carouselCommonListClass = 'carousel_common_list',
carouselCommonItemClass = 'carousel_common_item',
items_per_slide = 5;
$.each(carousels, function (index, element) {//for each carousel
var $carousel = carousels.eq(index),
$items = $carousel.find('.item');
var getItemTemplate = function ($item) {
$copy = $item.clone();//take the html, create a new element from it (not added to DOM)
$copy.find('.' + carouselCommonListClass).empty();
$copy.removeClass('active');
return $copy;
}
var splitUpItem = function ($item, $itemTemplate) {
var $bigList = $item.find('.' + carouselCommonListClass), group;
while ((group = $bigList.find('.' + carouselCommonItemClass + ':gt(' + (items_per_slide - 1 ) + ')').remove()).length) {
var $newItem = $itemTemplate;
$newItem.find('.' + carouselCommonListClass).prepend(group);
$newItem.insertAfter($item);
splitUpItem($newItem, $itemTemplate);//infintely called
}
}
//foreach item
$.each($items, function (item_index, item_element) {//for each slide, in each carousel
var $item = $items.eq(item_index);
splitUpItem($item, getItemTemplate($item));
});
});
FYI, this works like expected when the line marked with //infintely called is commented out; i.e. splits one oversized slide into one slide of items_per_slide length and another slide (which could be over items_per_slide in length if the original sole slide was over items_per_slide * 2 in length.
Also, I took this answer and modified it for the contents of splitUpItem().
Note:
I know it's not the most usable or accessible solution to split tables, lists, etc. over multiple slides like I am, but if you've a better idea answer my open question on that.
You're not getting an infinite loop per se, in that you're not infinitely stuck in the same while loop. As you mention, when you remove the //infinitely called line you're fine. The first pass through that while loop, the length you compute will equal the number of items (with gt:(4)) in all the lists in $item. You then remove all those items, so the next pass through will have that number equal to 0. This will always be the behaviour of that loop, so it really doesn't need to be a loop, but that's not the main problem.
The problem is that it's a recursive call. And the only guard you have against making the recursive call infinite is the condition in your while loop, but that condition will always be met the first pass through. In fact, if $item has 5 lists, each with 3 items with gt:(4), then $newItem will have 5 lists, each with 5 x 3 = 15 items. So when splitUpItem gets called on $newItem, the condition in your while loop will again first be non-zero. And then it'll get called again, and that number will be 5 x 15 = 75. And so on. In other words, you're recursively calling this function, and your guard against this call being made infinitely many times is to check that some number is 0, but the number there will actually grow exponentially with each recursive call of splitUpItem.
Hope that answers your question about why it's "infinitely looping." Gotta get to work, but I'll try to suggest a better way to split up the slides tomorrow if no one else has by then.