I know how to construct the above triangle using a single symbol.
I do not understand how to change my code to use two symbols.
Your problem may be solved using a number of different solutions...
For the heck of it, here's how I would do it using canvas, to create an image (copied/pasted and adapted an answer I gave to another SO user yesterday...). This solution probably won't fit your needs but then again as Jishnu V S stated, you gave us nothing to help you with.
ps : Yeah, I know, WAY overkill compared to simple html lists... Oh well xD
fiddle
HTML
<canvas id="canvas" width=1000 height=1000></canvas>
JS
var rows = 8,
cols = 1,
size = 64;
var canvas = document.getElementById("canvas");
var surface = canvas.getContext("2d");
//creating tile
function box(img) {
this.xaxis = 64;
this.yaxis = 0;
//Set your image selection logic here...
this.src = (img > 0 ) ? "https://cdn0.iconfinder.com/data/icons/typicons-2/24/times-512.png" : "http://img.freepik.com/free-icon/minus-big-symbol_318-70354.jpg?size=338&ext=jpg";
console.log(img);
}
//creating map
var map =[];
function setMap() {
for (var i = 0; i < rows; i++) {
var arr = [];
map.push(arr);
for (var o = 0; o < cols; o++) {
var selectImg = (i % 2 == 0) ? 0 : 1; //select your image based on row
map[i].push(new box(selectImg));
}
cols = (cols < 8) ? cols + 1 : cols;
}
}
console.log(map)
//rendering map
function render() {
for (var i = 0; i < rows; i++) {
for (var x = 0; x < map[i].length; x++) {
var tile = map[i][x];
tile.xaxis *= x;
tile.yaxis += (i*64);
var img = new Image();
img.onload = (function(x,y) {
return function() {
surface.drawImage(this, x, y, 64, 64);
}
})(tile.xaxis, tile.yaxis);
img.src = tile.src;
}
}
}
setMap();
render();
Related
the thing is i got a JS class and want to create a n-ary method to its prototype (Whisp.prototype.draw) so it won't be instanced over and over again. What my browser console tells me is
Uncaught TypeError: w.draw is not a function
I probably misunderstood something about prototyping in JS, so here is the relevant part of code:
// Random generators
function randomInt(min, max)
{
return Math.floor(Math.random() * (max - min)) + min;
}
// Whisp object + its methods
var WHISP_TURN_CAP = 10, WHISP_WANDER_CAP = 2, WHISP_SIZE = 2,
WHISP_COUNT = 4;
var Whisp = function(position)
{
this.rotation = [];
this.position = position;
for (var i = 0; i < 3; i++)
this.rotation.push(randomInt(-WHISP_TURN_CAP, WHISP_TURN_CAP))
this.rotation.push(1)
}
Whisp.prototype.wander = function()
{
var angle;
for (var i = 0; i < 3; i++)
{
angle = randomInt(-WHISP_WANDER_CAP, WHISP_WANDER_CAP+1);
while (Math.abs(this.rotation[i] + angle) > WHISP_TURN_CAP)
angle = randomInt(-WHISP_WANDER_CAP, WHISP_WANDER_CAP+1);
this.rotation[i] += angle;
this.position = matrixProduct(this.position, i, this.rotation[i]);
}
};
Whisp.prototype.draw = function(center)
{
context.setFill('#60FF55');
context.fillOval(
center[0]+this.position[0]-WHISP_SIZE,
center[1]+this.position[1]-WHISP_SIZE,
center[0]+this.position[0]+WHISP_SIZE,
center[1]+this.position[1]+WHISP_SIZE
);
};
// Generate actual whisps
var whisps = [];
for (var i = 0; i < WHISP_COUNT; i++)
whisps.push(new Whisp([800,400,0,1]));
// Update function (drawing onto canvas)
var canvas = $('#backgroundCanvas')[0], context = canvas.getContext('2d');
function update()
{
for (var w in whisps)
{
w.draw([800,450]);
w.wander();
}
console.log('update();');
window.setTimeout(update, 20);
}
var whisps = [];
for (var i = 0; i < WHISP_COUNT; i++)
whisps.push(new Whisp([800,400,0,1]));
// Update function (drawing onto canvas)
var canvas = $('#backgroundCanvas')[0], context = canvas.getContext('2d');
function update()
{
for (var w in whisps)
{
w.draw([800,450]);
w.wander();
}
console.log('update();');
window.setTimeout(update, 20);
}
update();
all of it encased in $(document).ready(function(){ ... }). Thanks for your answers :).
You should avoid using for ...in with arrays, as it doesn't iterate over undefined indices and doesn't guarantee to iterate the array in order.
See: Why is using "for...in" with array iteration a bad idea?
However the issue here is that w stores the key of the item in the array in:
for (var w in whisps)
{
w.draw([800,450]);
w.wander();
}
Where it should be:
for (var w in whisps)
{
whisps[w].draw([800,450]);
whisps[w].wander();
}
Or even better:
for (var i = 0; i < whisps.length; i++) {
whisps[i].draw([800,450]);
whisps[i].wander();
}
It's also generally faster: Javascript for..in vs for loop performance
I notice you are using canvas so don't care about IE8, in which case Array.prototype.forEach() is another solution which I prefer as it creates a new scope for the iteration:
whisps.forEach(function(w) {
w.draw([800,450]);
w.wander();
});
I'm attempting to emulate an infinite looping chaser on an LED strip with Javascript.
What I'm trying to accomplish:
Only use loops or recursive functions. No fancy JS.
Support any length of LED strip (var ledLength)
Support of multiple chasers
Support any number of LEDs (var ledDepth) with any number
of spaces separating the chasers (var blankDepth)
Loop infinitely
No magic numbers
I have this working for 1 chaser:
$(function(){
var ledLength = 20;
for(var i = 0; i < ledLength; i++) {
$('#led').append($('<div>').addClass('node'));
}
$('#led').css('width', ($('.node').length + 1) * $('.node').last().outerWidth(true));
var colors = ['green', 'red', 'blue'];
// add a "clearing" color
colors.push('black');
var ledDepth = 3;
var blankDepth = 2;
var chaserSize = ledDepth + blankDepth;
var iteration = 0;
var loop = setInterval(animate, 250);
function animate() {
if(iteration == ledLength + ledDepth) iteration = 0;
var offset = iteration < chaserSize ? iteration : chaserSize;
for(var i = 0; i <= offset; i ++) {
var colorOffset = i < ledDepth ? i : ledDepth;
$('.node').eq(iteration-i).css('background', colors[colorOffset]);
}
iteration++;
}
});
Or you can view it on the JSBin.
How would I go about tracking multiple chasers on a strip? Meaning after the initial chaserSize has been created and is moving to the right, another would be created and move long with it and loop infinitely.
Any help in to the right direction would be greatly appreciated.
I decided to take a different approach to this using an array.push method.
Basically, I continue to add points, loop through them all to increase their location, and remove them if their location is greater than the length of the strip.
This works for all LED lengths, chaser sizes (colors + blanks between each chaser).
Code:
$(function(){
// create the strip
var ledLength = 30;
for(var i = 0; i < ledLength; i++) {
$('#led').append($('<div>').addClass('node'));
}
$('#led').css('width', ($('.node').length + 1) * $('.node').last().outerWidth(true));
var points = [];
var colors = ['green', 'red', 'blue', 'pink', 'orange', 'purple'];
var ledDepth = colors.length || 6;
var blankDepth = 2;
var chaserSize = ledDepth + blankDepth;
// push blank nodes on the back of colors array
for(var i = 0; i < blankDepth; i++) {
colors.push('blank');
}
var iteration = 0;
// loop!
var loop = setInterval(animate, 100);
function animate() {
if(points.length) {
for(var i = 0; i < points.length; i++) {
// increase each pin by 1
points[i].pin++;
// remove point if pin is greater than led length
if(points[i].pin > ledLength) {
points.splice(i, 1);
}
}
}
if(iteration < chaserSize) {
points.push({pin: 0, color: colors[iteration]});
}
// draw points
for(var i = 0; i < points.length; i++) {
if(points[i].color == 'blank') { // this if for 'resetting'
$('.node').eq(points[i].pin).css('background', 'black');
} else { // this is for changing color
$('.node').eq(points[i].pin).css('background', points[i].color);
}
}
// iterate before reset
iteration++;
// reset sub-iterator (creator)
if(iteration >= chaserSize) {
iteration = 0;
}
}
});
Or JSBin
How do I generate objects on a map, without them occupying the same space or overlapping on a HTML5 Canvas?
X coordinate is randomly generated, to an extent. I thought checking inside the array to see if it's there already, and the next 20 values after that (to account for the width), with no luck.
var nrOfPlatforms = 14,
platforms = [],
platformWidth = 20,
platformHeight = 20;
var generatePlatforms = function(){
var positiony = 0, type;
for (var i = 0; i < nrOfPlatforms; i++) {
type = ~~(Math.random()*5);
if (type == 0) type = 1;
else type = 0;
var positionx = (Math.random() * 4000) + 500 - (points/100);
var duplicatetest = 21;
for (var d = 0; d < duplicatetest; d++) {
var duplicate = $(jQuery.inArray((positionx + d), platforms));
if (duplicate > 0) {
var duplicateconfirmed = true;
}
}
if (duplicateconfirmed) {
var positionx = positionx + 20;
}
var duplicateconfirmed = false;
platforms[i] = new Platform(positionx,positiony,type);
}
}();
I originally made a cheat fix by having them generate in an area roughly 4000 big, decreasing the odds, but I want to increase the difficulty as the game progresses, by making them appear more together, to make it harder. But then they overlap.
In crude picture form, I want this
....[]....[].....[]..[]..[][]...
not this
......[]...[[]]...[[]]....[]....
I hope that makes sense.
For reference, here is the code before the array check and difficulty, just the cheap distance hack.
var nrOfPlatforms = 14,
platforms = [],
platformWidth = 20,
platformHeight = 20;
var generatePlatforms = function(){
var position = 0, type;
for (var i = 0; i < nrOfPlatforms; i++) {
type = ~~(Math.random()*5);
if (type == 0) type = 1;
else type = 0;
platforms[i] = new Platform((Math.random() * 4000) + 500,position,type);
}
}();
EDIT 1
after some debugging, duplicate is returning as [object Object] instead of the index number, not sure why though
EDIT 2
the problem is the objects are in the array platforms, and x is in the array object, so how can I search inside again ? , that's why it was failing before.
Thanks to firebug and console.log(platforms);
platforms = [Object { image=img, x=1128, y=260, more...}, Object { image=img, x=1640, y=260, more...} etc
You could implement a while loop that tries to insert an object and silently fails if it collides. Then add a counter and exit the while loop after a desired number of successful objects have been placed. If the objects are close together this loop might run longer so you might also want to give it a maximum life span. Or you could implement a 'is it even possible to place z objects on a map of x and y' to prevent it from running forever.
Here is an example of this (demo):
//Fill an array with 20x20 points at random locations without overlap
var platforms = [],
platformSize = 20,
platformWidth = 200,
platformHeight = 200;
function generatePlatforms(k) {
var placed = 0,
maxAttempts = k*10;
while(placed < k && maxAttempts > 0) {
var x = Math.floor(Math.random()*platformWidth),
y = Math.floor(Math.random()*platformHeight),
available = true;
for(var point in platforms) {
if(Math.abs(point.x-x) < platformSize && Math.abs(point.y-y) < platformSize) {
available = false;
break;
}
}
if(available) {
platforms.push({
x: x,
y: y
});
placed += 1;
}
maxAttempts -= 1;
}
}
generatePlatforms(14);
console.log(platforms);
Here's how you would implement a grid-snapped hash: http://jsfiddle.net/tqFuy/1/
var can = document.getElementById("can"),
ctx = can.getContext('2d'),
wid = can.width,
hei = can.height,
numPlatforms = 14,
platWid = 20,
platHei = 20,
platforms = [],
hash = {};
for(var i = 0; i < numPlatforms; i++){
// get x/y values snapped to platform width/height increments
var posX = Math.floor(Math.random()*(wid-platWid)/platWid)*platWid,
posY = Math.floor(Math.random()*(hei-platHei)/platHei)*platHei;
while (hash[posX + 'x' + posY]){
posX = Math.floor(Math.random()*wid/platWid)*platWid;
posY = Math.floor(Math.random()*hei/platHei)*platHei;
}
hash[posX + 'x' + posY] = 1;
platforms.push(new Platform(/* your arguments */));
}
Note that I'm concatenating the x and y values and using that as the hash key. This is to simplify the check, and is only a feasible solution because we are snapping the x/y coordinates to specific increments. The collision check would be more complicated if we weren't snapping.
For large sets (seems unlikely from your criteria), it'd probably be better to use an exclusion method: Generate an array of all possible positions, then for each "platform", pick an item from the array at random, then remove it from the array. This is similar to how you might go about shuffling a deck of cards.
Edit — One thing to note is that numPlatforms <= (wid*hei)/(platWid*platHei) must evaluate to true, otherwise the while loop will never end.
I found the answer on another question ( Searching for objects in JavaScript arrays ) using this bit of code to search the objects in the array
function search(array, value){
var j, k;
for (j = 0; j < array.length; j++) {
for (k in array[j]) {
if (array[j][k] === value) return j;
}
}
}
I also ended up rewriting a bunch of the code to speed it up elsewhere and recycle platforms better.
it works, but downside is I have fewer platforms, as it really starts to slow down. In the end this is what I wanted, but its no longer feasible to do it this way.
var platforms = new Array();
var nrOfPlatforms = 7;
platformWidth = 20,
platformHeight = 20;
var positionx = 0;
var positiony = 0;
var arrayneedle = 0;
var duplicatetest = 21;
function search(array, value){
var j, k;
for (j = 0; j < array.length; j++) {
for (k in array[j]) {
if (array[j][k] === value) return j;
}
}
}
function generatePlatforms(ind){
roughx = Math.round((Math.random() * 2000) + 500);
type = ~~(Math.random()*5);
if (type == 0) type = 1;
else type = 0;
var duplicate = false;
for (var d = 0; d < duplicatetest; d++) {
arrayneedle = roughx + d;
var result = search(platforms, arrayneedle);
if (result >= 0) {
duplicate = true;
}
}
if (duplicate = true) {
positionx = roughx + 20;
}
if (duplicate = false) {
positionx = roughx;
}
platforms[ind] = new Platform(positionx,positiony,type);
}
var generatedplatforms = function(){
for (var i = 0; i < nrOfPlatforms; i++) {
generatePlatforms(i);
};
}();
you go big data, generate all possibilities, store each in an array, shuffle the array,
trim the first X items, this is your non heuristic algorithm.
EDIT: The Problem was in my code, I was not querying the array with the right index.
For anyone looking for an answer for this problem, Karthik Ar answered it right. Thanks for all the comments!
I´m struggling to create an array of unique canvas elements inside a for loop.
It seems as all elements were a copy of the first element created. Im saying this because I need to store this canvas in an array and then access their contexts anytime later.
var _ctxs = new Array();
function createCells()
{
_w = window.innerWidth;
_h = window.innerHeight;
var side = 300;
//set amount of steps
var stepsW = Math.ceil(_w/side) + 1;
var stepsH = Math.ceil(_h/(side/2)) + 1;
console.log("create cells");
for (var i = 0; i < stepsH; i++)
{
var p = (i%2 == 0)?0:side/2;
for (var j = 0; j < stepsW; j++)
{
var _tempCanvas = $('<canvas/>', {id: "i_" + i + "_" + j, width : side, height : side});
_tempCanvas.css({
'position' : 'absolute',
'top' : (i*(side/2)+1) - side/2,
'left' : (j*side + p) + 1 - side/2
});
//var _tempCtx = _tempCanvas[0].getContext('2d');
_ctxs.push(_tempCanvas[0]);
$('body').prepend(_tempCanvas);
k++;
};
};
}
Any Thoughs? Thanks in advance!
Looks working by your code check the array.
$(document).ready(jqueryready);
function jqueryready(){
for (var i = 0; i < 5; i++)
{
for (var j = 0; j < 5; j++)
{
var _tempCanvas = $('<canvas/>', {id: i+""+j, width : 10, height : 10});
console.log(_tempCanvas[0].id);
$('body').prepend(_tempCanvas);
};
}
}
This creates unique id for canvas.
this is my second Javascript/Dom query this evening but this is really quite a different query and thus probably deserves a new topic. My ultimate goal is to create a sliding puzzle game with a 4 x 4 grid. With some help in the other thread I have got the script to show the images in a 4 x 4 grid in a random order, with a shuffle button that again randomizes the images. The images are name image00, 01, 02, 03, 10, 11 etc up to 33 - 33 is my blank image.
Now I want to add commands that say if this image is clicked and it is next to the blank tile (image 33) then swap with the blank image. The only problem is, that I have no idea where to begin. My code so far is below. From what I've seen it would be something along the lines of using the images ID's but I am very new to javascript and haven't been able to find much that has helped me so far. Any help is really appreciated.
<html>
<head>
<title>Shuffle</title>
</head>
<body>
<script language="JavaScript">
<!--
var Pics = [];
var Top = 16;
Pics = new Array();
for(i = 0; i < Top; i++) {
document.write("<img>");
if ((i+1)%4 == 0) {
document.write("<br>");
}
}
function ShuffleArray(a) {
var n = a.length;
for(var i = n - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
function ViewerObj(Image, Pics, i) {
this.Image = Image;
this.Image.style.left = 800;
this.Pics = Pics;
this.Image.id = "ID" + i;
}
function Randomise() {
var i;
ShuffleArray(Pics);
for(i = 0; i < Top; i++) {
Viewers[i].Image.src = Pics[i];
Viewers[i].Image.style.left = 200;
}
}
Viewers = new Array();
var i;
for(var i = 0; i < 4; i++) {
for(var j = 0; j < 4; j++) {
Pics[j + 4*i] = "images/Tree" + (i) + (j) + ".jpg";
}
}
for(i = 0; i < Top; i++) {
document.images[i].src = Pics[i];
document.images[i].style.left = 300;
Viewers[i] = new ViewerObj(document.images[i], Pics, i);
}
//-->
</script>
<h1>Shuffle</h1>
<form>
<input type="button" value="Shuffle" onClick="Randomise();"/>
</form>
</body>
</html>
You should go for jQuery. It will make many things easier.