let story = 'Last weekend, I took literally the most beautiful bike ride of my life. The route is called "The 9W to Nyack" and it actually stretches all the way from Riverside Park in Manhattan to South Nyack, New Jersey. It\'s really an adventure from beginning to end! It is a 48 mile loop and it basically took me an entire day. I stopped at Riverbank State Park to take some extremely artsy photos. It was a short stop, though, because I had a really long way left to go. After a quick photo op at the very popular Little Red Lighthouse, I began my trek across the George Washington Bridge into New Jersey. The GW is actually very long - 4,760 feet! I was already very tired by the time I got to the other side. An hour later, I reached Greenbrook Nature Sanctuary, an extremely beautiful park along the coast of the Hudson. Something that was very surprising to me was that near the end of the route you actually cross back into New York! At this point, you are very close to the end.';
const storyWords = story.split(" ");
//console.log(storywords.length);
let overusedWords = ['really', 'very', 'basically'];
let WoolReally = 0;
let WoolVery = 0;
let WoolBasically = 0;
for(x of storyWords) {
if (x === 'really'){
WoolReally++;
}
else if (x === 'very'){
WoolVery++;
}
else if (x === 'basically'){
WoolBasically ++;
}
}
console.log("Really was counted " + WoolReally + " times.");
console.log("Very was counted " + WoolVery + " times.");
console.log("Basically was counted " + WoolBasically + " times.");
Please can you help me try figure out how to dynamically check if a sentence includes any values that another variable includes and count that value.
let story = 'Last weekend, I took literally the most beautiful bike ride of my life. The route is called "The 9W to Nyack" and it actually stretches all the way from Riverside Park in Manhattan to South Nyack, New Jersey. It\'s really an adventure from beginning to end! It is a 48 mile loop and it basically took me an entire day. I stopped at Riverbank State Park to take some extremely artsy photos. It was a short stop, though, because I had a really long way left to go. After a quick photo op at the very popular Little Red Lighthouse, I began my trek across the George Washington Bridge into New Jersey. The GW is actually very long - 4,760 feet! I was already very tired by the time I got to the other side. An hour later, I reached Greenbrook Nature Sanctuary, an extremely beautiful park along the coast of the Hudson. Something that was very surprising to me was that near the end of the route you actually cross back into New York! At this point, you are very close to the end.';
const storyWords = story.split(" ");
//console.log(storywords.length);
let overusedWords = ['really', 'very', 'basically'];
let WoolReally = 0;
let WoolVery = 0;
let WoolBasically = 0;
for(x of storyWords) {
if (x === 'really'){
WoolReally++;
}
else if (x === 'very'){
WoolVery++;
}
else if (x === 'basically'){
WoolBasically ++;
}
}
console.log("Really was counted " + WoolReally + " times.");
console.log("Very was counted " + WoolVery + " times.");
console.log("Basically was counted " + WoolBasically + " times.");
You can see that I have had to create a singular variable for each of the words that are part of the string for variable - overUsedWords in order to be able to count them in the loop and if else statement. There must be a way to beaten this up so I don't have to do it with
let WoolReally = 0;
let WoolVery = 0;
let WoolBasically = 0;
Let me know what you think. I do apologise if this is super simple stuff. I'm just learning
can create a counts object from the overusedWords array using array reduce
let story = 'Last weekend, I took literally the most beautiful bike ride of my life. The route is called "The 9W to Nyack" and it actually stretches all the way from Riverside Park in Manhattan to South Nyack, New Jersey. It\'s really an adventure from beginning to end! It is a 48 mile loop and it basically took me an entire day. I stopped at Riverbank State Park to take some extremely artsy photos. It was a short stop, though, because I had a really long way left to go. After a quick photo op at the very popular Little Red Lighthouse, I began my trek across the George Washington Bridge into New Jersey. The GW is actually very long - 4,760 feet! I was already very tired by the time I got to the other side. An hour later, I reached Greenbrook Nature Sanctuary, an extremely beautiful park along the coast of the Hudson. Something that was very surprising to me was that near the end of the route you actually cross back into New York! At this point, you are very close to the end.';
const storyWords = story.split(" ");
let overusedWords = ['really', 'very', 'basically'];
let counts = overusedWords.reduce((acc,curr) => {
acc[curr] = storyWords.filter(x => x===curr).length;
return acc;
},{})
console.log(counts)
console.log(counts['very'])
console.log(counts['really'])
let story = 'Last weekend, I took literally the most beautiful bike ride of my life. The route is called "The 9W to Nyack" and it actually stretches all the way from Riverside Park in Manhattan to South Nyack, New Jersey. It\'s really an adventure from beginning to end! It is a 48 mile loop and it basically took me an entire day. I stopped at Riverbank State Park to take some extremely artsy photos. It was a short stop, though, because I had a really long way left to go. After a quick photo op at the very popular Little Red Lighthouse, I began my trek across the George Washington Bridge into New Jersey. The GW is actually very long - 4,760 feet! I was already very tired by the time I got to the other side. An hour later, I reached Greenbrook Nature Sanctuary, an extremely beautiful park along the coast of the Hudson. Something that was very surprising to me was that near the end of the route you actually cross back into New York! At this point, you are very close to the end.';
const storyWords = story.split(" ");
let overusedWords = ['really', 'very', 'basically'];
for(let word of overusedWords){
let wordCount = storyWords.filter((storyWord) => {return storyWord === word;}).length
console.log("The word '"+word+"' has been used "+wordCount+ " times" );
}
In this way you are simply filtering the list of the word obtained by the splitting of the story for each of the word inside your overusedWord list and returning the count of them. In this way if you want to add further words you just have to add them into your 'overusedWord' array and it will continue to work.
Create an object with three properties:
const obj = {
WoolReally: 0,
WoolVery: 0,
WoolBasically: 0
}
Update the object in the loop
for(x of storyWords) {
if (x === 'really'){
obj.WoolReally += 1
}
else if (x === 'very'){
obj.WoolVery += 1;
}
else if (x === 'basically'){
obj.WoolBasically += 1;
}
}
for(let i in obj){
console.log(`${i} has been counted ${obj.i} times`);
}
Lore:
Now that my chemistry class has gone past memorizing equations and whatnot and begun with, example, balancing chemical equations. I could sit down all day long balancing equations, but as programming is my passion I would love to get a program working for me to solve these. This is more or less a pet-project and more for fun rather than giving me an edge in chemistry class. But the more I dwelt into it the more complex it became.
I don't really know how to begin this crusade and have instead worked on the parser and data set, which is in pretty good set to have my head wrapped around it right.
Question:
What I don't know is how to utilize matrices to solve equations (balance equations to conserve mass*) and convert that into whole numbers valid in chemistry.
Code/objects:
class Element {
constructor(name,quantity) {
this.name = name;
this.quantity = quantity;
if (this.quantity == 0) {
this.quantity = 1;
}
}
}
class Molecule {
constructor() {
this.elements = [];
this.multiplier = 1;
}
addElement(newEl) {
this.elements.push(newEl);
}
list() {
this.elements.forEach(el => {
console.log(el.name,el.quantity);
});
}
getMultiplier() {
return this.multiplier;
}
getElements() {
var a = [];
this.elements.forEach(el => {
a.push([el.name,el.quantity*this.multiplier]);
});
return a;
}
}
Code/data structure:
printFormula(moleculeList);
for (var i=0;i<moleculeList[0].length;i++) {
console.log("Mol "+(i+1))
moleculeList[0][i].list();
}
console.log("==>");
for (var i=0;i<moleculeList[1].length;i++) {
console.log("Mol "+(i+1))
moleculeList[1][i].list();
}
Code/output:
'C6H14 + O2 ==> CO2 + H2O'
Mol 1
C 6
H 14
Mol 2
O 2
==>
Mol 1
C 1
O 2
Mol 2
H 2
O 1
I am a chemist and have exactly zero familiarity with Javascript so as to explain it in detail. But the method is fairly simple to show by hand. This link nails it down in a clean manner.
The only reason why I am linking to it without going through the steps in detail is because Stackoverflow does not have LaTeX math in order to make the text easy to follow, so I think you'll benefit better from the text in the link.
Also, I don't think this is a full answer, but I do not have enough reputation to put this on a comment, where it belongs.
I think the hardest bit is finding/coding the appropriate subroutine for row-echelon reduction of the matrix in step-5. But I also believe that there is a vast number of algorithms appropriate for doing that which you can find in the internet. Very handily, this very website has a question related to just that with a python code to sweeten the deal.
I hope this helps you at least wrap your head around it enough to implement the code you need.
Cheers
I was just wondering how I could search and compare two string object and check if either contains a matching string.
I have an associative array containing terms and explanations.
I also have this array broken into two objects "keys"(keys showing the key of the associative array) and "values"(values showing the value of each key in array).
I have another associative array containing a dish and its explanation.
I have split the dish's description into separate words put them into an object.
What I would like to do now is check for every word in descsplit search the TermList and return explanation of term found if found.
eg. free-range is contained in dish explanation, check if there is a match for free-range in TermList and return the value(explanation) of free-range.
Any help would be greatly appreciated, Thanks.
var TermList= {
'Al dente' : 'Al dente : Pasta cooked until just firm. From the Italian "to the tooth." ',
'Bake' : 'Bake: To cook food in an oven, surrounded with dry heat; called roasting when applied to meat or poultry.',
'Barbecue' : 'Barbecue: To cook foods on a rack or a spit over coals.',
'Baste' : 'Baste: To moisten food for added flavor and to prevent drying out while cooking.',
'Batter' : 'Batter: An uncooked pourable mixture usually made up of flour, a liquid, and other ingredients.',
'Beat' : 'Beat: To stir rapidly to make a mixture smooth, using a whisk, spoon, or mixer.',
'Blanch' : 'Blanch: To cook briefly in boiling water to seal in flavor and color; usually used for vegetables or fruit, to prepare for freezing, and to ease skin removal.',
'Blend' : 'Blend: To thoroughly combine 2 or more ingredients, either by hand with a whisk or spoon, or with a mixer.',
'Boil': 'Boil: To cook in bubbling water that has reached 100 degrees Celcius.',
'Bone' : 'Bone: To remove bones from poultry, meat, or fish.',
'Bouquet garni' : 'Bouquet garni: A tied bundle of herbs, usually parsley, thyme, and bay leaves, that is added to flavor soups, stews, and sauces but removed before serving.',
'Braise' : 'Braise: To cook first by browning, then gently simmering in a small amount of liquid over low heat in a covered pan until tender.',
'Bread': 'Bread: To coat with crumbs or cornmeal before cooking.',
'Free-range': 'Free-range: (Of livestock, especially poultry) kept in natural conditions, with freedom of movement/ (Of eggs) produced by free-range poultry.'
};
var values = []; // Creating an object for the values of the terms in TermList
var keys = []; // Creating an object for the keys of the terms in TermList
//function to assign the keys of terms to object keys.
function showkey() {
for (var key in TermList) {
if (TermList.hasOwnProperty(key)) {
keys.push(key);
}
}
//function that shows the value of each key in TermList.
function showValue(){
for( var value in TermList){
values.push(TermList[value]);
}
showkey();
showValue();
var DishList={
"Chicken and Stuffing Sandwich": "Chicken and Stuffing Sandwich: Succulent Sandwich made from free-range chicken and fresh breadcrumbs mixed with mayonnaise",
"Eggs Benedict": "Poached eggs served with spinach and hollandaise sauce"
};
var descsplit = [];
function SplitDesc() {
for (var value in DishList) {
descsplit.push(DishList[value].split(/[\s.,?!:]+/)); // Splits the values of the key up in Dishlist, and puts them into array.Also makes them avoid punctuations while splitting.
}
}
SplitDesc();
//For every word in descsplit search the TermList and return explanation of term found if found
Not tested fully, but this may work
var TermList= {
'Al dente' : 'Al dente : Pasta cooked until just firm. From the Italian "to the tooth." ',
'Bake' : 'Bake: To cook food in an oven, surrounded with dry heat; called roasting when applied to meat or poultry.',
'Barbecue' : 'Barbecue: To cook foods on a rack or a spit over coals.',
'Baste' : 'Baste: To moisten food for added flavor and to prevent drying out while cooking.',
'Batter' : 'Batter: An uncooked pourable mixture usually made up of flour, a liquid, and other ingredients.',
'Beat' : 'Beat: To stir rapidly to make a mixture smooth, using a whisk, spoon, or mixer.',
'Blanch' : 'Blanch: To cook briefly in boiling water to seal in flavor and color; usually used for vegetables or fruit, to prepare for freezing, and to ease skin removal.',
'Blend' : 'Blend: To thoroughly combine 2 or more ingredients, either by hand with a whisk or spoon, or with a mixer.',
'Boil': 'Boil: To cook in bubbling water that has reached 100 degrees Celcius.',
'Bone' : 'Bone: To remove bones from poultry, meat, or fish.',
'Bouquet garni' : 'Bouquet garni: A tied bundle of herbs, usually parsley, thyme, and bay leaves, that is added to flavor soups, stews, and sauces but removed before serving.',
'Braise' : 'Braise: To cook first by browning, then gently simmering in a small amount of liquid over low heat in a covered pan until tender.',
'Bread': 'Bread: To coat with crumbs or cornmeal before cooking.',
'Free-range': 'Free-range: (Of livestock, especially poultry) kept in natural conditions, with freedom of movement/ (Of eggs) produced by free-range poultry.'
};
var DishList={
"Chicken and Stuffing Sandwich": "Chicken and Stuffing Sandwich: Succulent Sandwich made from free-range chicken and fresh breadcrumbs mixed with mayonnaise",
"Eggs Benedict": "Poached eggs served with spinach and hollandaise sauce"
};
var keys = Object.keys(TermList);
for(var key in DishList){
var val = DishList[key];
for(var iIndex=0;iIndex<keys.length ;iIndex++){
var term = keys[iIndex];
var regx = new RegExp('\\b'+term+'\\b',"gi");
var found = null;
while((found = regx.exec(val))!=null){
console.log('Found term "'+ term+ '" at index '+found.index);
}
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
SOLVED!! (look at my last edit)
I want to make an army fight of 20.000 vs 20.000 units on canvas. So, for every unit data is:
{
'id' => 17854,
'x' => 1488,
'y' => 1269,
'team' => 'red',
'health' => 10,
'target' => [1486, 1271]
}
And i would to see this fight in real time (25 frames per second).
If i generate 1 frame with Json and save on file, it is 2.5mb size (40k such units with this data).
1 second(25 frames) = 62.5 mb file size. And the fight could last about 30 minutes, so it should use 112gb. This is bad. If i would make the file as binary data, it should take 27 times less place, or 4gb for 30 mins. That's still bad. 2 hrs movie takes 700mb.
I need to save many fights on server. Real players should make their armies and fight each other, so i need the fights to be saved. Every fight is unique, because every damage of every unit is random 0~10 and after unit kills an enemy, it regenerates 1 health. I'm doing calculations with PHP and saving files on server. All 40.000 units are on one screen, all can be visible at once, i want it like that. For now, units are single 2x2 pixel cubes, red and blue teams, its easy to load for javascript.
But, to generate file with PHP i need about 1 hour. That's another problem. Because for every frame i need to iterate these 40.000 units (for updating x/y, searching for nearby enemies or friends, then for doing damage and returning target or killed enemy coordinates), then iterate over again to unset killed units, and before putting all that into file, i need to iterate over everything and remove unused data that was used for calculations. And to finish this 30 mins fight i need to repeat it 45000 times. Also, every minute there are less and less units. But my point is somehow to make all that file generating in less than a minute, just need a logical way, if some exist.
Questions:
1) What is the best way to save my files on server and make the files much less on size?
(so far is to use binary data and compress to zip)
2) what is the fastest way to calculate my fights?
(so far is to compile with C++)
// Edited. Here is my whole game code, just like that :)
This is main action:
class Simulator
{
private $units;
private $places = [];
private $oldPlaces = [];
public function initiateGame() {
$this->createUnits();
$this->startMoving();
}
private function createUnits() {
foreach(range(0, 150) as $column) { // i like exact army formation to look nice, so its 150x140=21000 units
foreach (range(0, 140) as $row) {
$this->setUnits($column, $row);
}
}
$this->oldPlaces = $this->places;
}
private function setUnits($column, $row) {
$beginning_of_team_A = 6; //starting point on canvas for A unit to look nice on screen
$unit_size_and_free_place = 6; //unit size= 3x3 (look js), and free place between each unit is 3 pixels.
$beginning_of_team_B = 1100; // next side where enemy army starts appearing
$x_a = $beginning_of_team_A + $column * $unit_size_and_free_place; // team A
$y = $beginning_of_team_A + $row * $unit_size_and_free_place; // same for both teams
$unitA = new Unit($x_a, $y, 1); // 1 is team A (it goes always +1 pixel every frame)
$this->units[] = $unitA;
$x_b = $beginning_of_team_B + $column * $unit_size_and_free_place; // team B
$unitB = new Unit($x_b, $y, -1); // -1 is team B (it goes always -1 pixel every frame)
$this->units[] = $unitB;
$this->places[$x_a.','.$y] = 1; // now that way tracking units, and calculating their next move
$this->places[$x_b.','.$y] = -2;
}
private function startMoving() {
set_time_limit(30000); // by default after 1 minute it throws exception
foreach(range(0, 400) as $frame) { //giving 400 frames is like 400/40=10 seconds of action
$this->places = [];
foreach($this->units as $unit) {
$returned = $unit->move($this->oldPlaces); //giving whole units list to every unit to look forward
$this->places[$returned[0]] = $returned[1]; // returns (next x/y position as string ['1514,148'] ) = ( id as int [15] )
}
file_put_contents('assets/games/'.$frame.'.json', json_encode($this->units)); // writing into file every frame and it uses ~2mb
$this->oldPlaces = $this->places; //resetting old positions
}
}
}
This is unit:
class Unit
{
public $x = 0;
public $y = 0;
public $team = 1;
public $stopped;
public function __construct($x, $y, $team, $stopped = false) {
$this->x = $x;
$this->y = $y;
$this->team = $team;
$this->stopped = $stopped;
}
public function move($places) {
$this->checkForward($places);
return [$this->x.','.$this->y, $this->team];
}
private function checkForward($places) {
$forward = $this->x + $this->team; // TODO: find out formula to replace the 4 ifs
$forward1 = $this->x + $this->team*2;
$forward2 = $this->x + $this->team*3;
$forward3 = $this->x + $this->team*4;
if(isset($places[$forward.','.$this->y])) {
$this->stopped = true;
} else if (isset($places[$forward1.','.$this->y])) {
$this->stopped = true;
} else if (isset($places[$forward2.','.$this->y])) {
$this->stopped = true;
} else if (isset($places[$forward3.','.$this->y])) {
$this->stopped = true;
} else {
$this->stopped = false;
}
if($this->stopped == false) { // move forward it is not stopped
$this->x = $this->x + $this->team;
}
}
}
This is js:
var app = angular.module('app', []);
app.controller('game', function($scope, $http, $interval) {
var canvas = document.getElementById("game"),
context = canvas.getContext("2d");
var frame = -2;
$scope.attacking = false;
var units = [];
function start_animation_loop() {
$scope.promise = $interval(function() {
if($scope.attacking == true) {
frame ++;
if(frame >= 0) {
downloadFile();
animate();
}
}
}, 40 );
}
function downloadFile() {
$http.get('assets/games/'+frame+'.json').success(function(response) {
units = response;
});
}
function animate() {
clear_canvas();
draw();
}
function clear_canvas() {
context.clearRect(0, 0, 1800, 912);
}
function draw() {
for(var a=0; a<units.length; a++) {
context.beginPath();
context.fillRect(units[a]['x'], units[a]['y'], 3, 3);
if(units[a]['team'] == 1) {
context.fillStyle = 'red';
} else {
context.fillStyle = 'blue';
}
}
}
start_animation_loop();
});
SOLVED! Thx to my colleague in my work! He gave me brilliant idea!
To get the result i needed i just need for every next battle to generate random number (0~10000) and place it into single MySQL database. In addition also put there formations, units, their starting strength, health and everything else.
And all the calculations do with javascript:
With one constant number (given from backend) i make a formula to always reproduce same army fight -> every unit will move forwards and they always stop at the same time anyways no matter what the calculation. The uniqueness is the random damage every unit gives and what process after. And all the damage will be just their "x/y position somehow compared to constant number" and do whatever to get single damage, random for every unit because they all are in different map positions, but damage will always be 0~10. With the same constant number, all units will always do the same damage after calculation and always will move same at every replay, die and do same damage at every replay. All the hardest work will be on javascript - to make calculations using this constant number.
My random number can be any. If first fight i generate random number "17", and next battle i generate random number "19666516546", it will not mean that battle with number "17" will do less damage - they all will do the "random" damage 0~15 to every unit, but replays with same formations, unit numbers, starting position and this random generated number will be always the same -> no more need to save any files! And i can add various spec effects, add something like defences, evasions, and all will fit in two MySQL rows - for every team :) Cool!!
id can be implicit in the storage medium. Sure, that means you have to save gaps, but you can compress said gaps.
'x' => 1488,
'y' => 1269,
depending on the canvas size, this can be compressed. If the canvas is 1e6 x 1e6 (a million by a million), there are 1e12 locations, which fits in ~40 bits.
'team' => 'red',
with 2 sides, this is 1 bit.
'health' => 10,
the vast majority of units have a low health. So what we can do is that units with a health < 15 are stored in 4 bits. If all the bits are set, we have to look up the units health elsewhere (with an id->health table).
'target' => [1486, 1271]
We could store an independent target for each unit, but that probably doesn't match how the UI works. You probably select a pile of units, and tell them to go somewhere, no? ~40 bits for a location, ~24 bits for a reference count, for 8 bytes per target.
If we give each side a limit of ~65k targets, that is 16 bits.
16+4+1+40 = 61 bits. Which means we have 3 more bits to play with to pack them into a 64 bit per unit.
At 64 bits per unit, that is 160k per side. Plus up to half-a-meg of target data, but that can be handled dynamically.
Plus a health overflow table (that maps id to health), which should usually be close to empty. If you do this sometimes, you can set up before-after id maps to maintain a consistent history (say, when half the units are dead, you do a compression pass with a before-after id mapping).
If id need not be consistent, you can compress the units down so that they are no longer sparse.
The target trick -- the target could be a unit ID if less than 40,000, and if above that value it would be a waypoint. That reduces your waypoints to ~15k ones. (I was assuming target was set by the UI, where someone would select a chunk of units, an order them to go somewhere).
You'd want to iterate over the packed data, skipping "dead" units (bitmask on health), unpacking them into a usable structure, evaluating their action, and writing them back. Double-buffering is an option (where you read from one buffer, and write to another), but it has a modest cost. Because units are fixed size, you can lookup other units fast (and unpack them), which helps if your targets are other unit ids, and with things like doing damage.
Single-buffering makes things easier, because things like simultaneous damage are tricky. It does mean that lower-id units act first -- you can fix this by flipping a coin each turn to determine if you iterate forward or backwards (and stick one side in low-ids, the other in high-ids), or make that an initiative check at the start of combat.
Working on the PHP side of things here is some initialization material to set up red and blue teams randomly. You'll notice that the data being stored is in the form of human readable strings so it is relatively easy to see what is going on just by looking at the data.
$red = array(); // stats per red unit
$blue = array(); // stats per blue unit
$sites = array(); // units (red and/or blue) at a location
$start = microtime(true);
echo "Generating red team:<br>\n";
for ($r=0; $r<20000; $r++)
{
$x = mt_rand(0,1940/2);
$y = mt_rand(0,1280);
$h = 10;
$red[$r] = "r:$r;x:$x;y:$y;h:$h";
if ( $r < 3 )
echo "... " . $red[$r] . "<br>\n";
if ( $r == 3 )
echo "...<br>\n";
if ( $r >= 19997 )
echo "... " . $red[$r] . "<br>\n";
#$sites[$x][$y][] = "r:$r";
}
$now = microtime(true);
echo "Red side generated, total time used " . ($now - $start) . "<br><br>\n";
echo "Generating blue team:<br>\n";
for ($b=0; $b<20000; $b++)
{
$x = mt_rand(1940/2,1940);
$y = mt_rand(0,1280);
$h = 10;
$blue[$b] = "b:$b;x:$x;y:$y;h:$h\n";
if ( $b < 3 )
echo "... " . $blue[$b] . "<br>\n";
if ( $b == 3 )
echo "...<br>\n";
if ( $b >= 19997 )
echo "... " . $blue[$b] . "<br>\n";
#$sites[$x][$y][] = "b:$b";
}
$now = microtime(true);
echo "Blue side generated, total time used " . ($now - $start) . "<br><br>\n";
$sum = 0;
foreach ($sites as $x => $list)
$sum += count($list);
echo "$sum screen locations contain one or more units<br>\n";
The output from this shows that we can generate 40,000 units at random locations and then track all units by screen x,y location, or site, for later use within a very short period of time.
Generating red team:
... r:0;x:49;y:642;h:10
... r:1;x:508;y:1162;h:10
... r:2;x:444;y:8;h:10
...
... r:19997;x:553;y:851;h:10
... r:19998;x:608;y:414;h:10
... r:19999;x:860;y:1203;h:10
Red side generated, total time used 0.070003986358643
Generating blue team:
... b:0;x:1799;y:445;h:10
... b:1;x:1913;y:177;h:10
... b:2;x:1730;y:678;h:10
...
... b:19997;x:1586;y:919;h:10
... b:19998;x:1445;y:3;h:10
... b:19999;x:1061;y:542;h:10
Blue side generated, total time used 0.14700794219971
39697 screen locations contain one or more units
In terms of file storage, I would suggest something similar to that suggested by others. You would probably write the full initialization state to file and then list adjustments to that state on a frame by frame basis. Your PHP code would then adjust state to generate display effects by reading changes on a frame by frame basis.
Before I continue I wonder if you could reply with some information about what you mean by targeting. Is this movement destination with combat occurring automatically when nearby? Also, why do you look for and find nearby friend and enemy units? Is this to adjust combat effects or to generate movement actions?
The following function demonstrates locating nearby units. Notice that the blue and the red are randomly place on opposite sides of the screen by the above so you aren't likely to see any nearby foes.
function nearby($unit, $sites, $withinx=5, $withiny=5, $verbose=0)
{
if ( $verbose )
echo "Looking for units near unit '$unit'<br>\n";
$data = explode(';',$unit);
foreach ($data as $datum)
{
if ( strncmp($datum,"x:",2)==0 )
$x = (integer)substr($datum,2);
if ( strncmp($datum,"y:",2)==0 )
$y = (integer)substr($datum,2);
}
if ( $verbose )
echo "... this unit is located at ($x,$y)<br>\n";
$nearby = array();
for ($sx = $x - $withinx; $sx <= $x + $withinx; $sx++)
{
for ($sy = $y - $withiny; $sy <= $y + $withiny; $sy++)
{
$list = #$sites[$sx][$sy];
if ( count($list) )
{
foreach ($list as $key => $candidate)
{
if ( strncmp($candidate,$unit,strlen($candidate))==0 )
continue;
$nearby[] = $candidate;
if ( $verbose )
echo "... ... unit at $sx,$sy found: $candidate<br>\n";
}
}
}
}
return $nearby;
}
Then, some code to run several thousand closeness checks with verbose mode turned on for the first few.
echo "<br>\n";
for ($i=0; $i<1000; $i++)
{
$r = mt_rand(0,19999);
$verbose = 0;
if ( $i < 2 )
$verbose = 1;
nearby($red[$r],$sites,5,5,$verbose);
}
echo "1000 red units randomly checked for nearby units<br>\n";
echo "<br>\n";
for ($i=0; $i<1000; $i++)
{
$r = mt_rand(0,19999);
$verbose = 0;
if ( $i < 2 )
$verbose = 1;
nearby($blue[$r],$sites,5,5,$verbose);
}
echo "1000 blue units randomly checked for nearby units<br>\n";
$now = microtime(true);
echo "<br>Total time used " . ( $now - $start) . "<br>\n";
Sample output from the search for nearby units follows:
Looking for units near unit 'r:16452;x:332;y:944;h:10'
... this unit is located at (332,944)
... ... unit at 335,945 found: r:3376
... ... unit at 336,948 found: r:14128
Looking for units near unit 'r:4414;x:3;y:1223;h:10'
... this unit is located at (3,1223)
... ... unit at 2,1219 found: r:1210
... ... unit at 8,1226 found: r:461
1000 red units randomly checked for nearby units
Looking for units near unit 'b:4002;x:1531;y:224;h:10 '
... this unit is located at (1531,224)
... ... unit at 1530,222 found: b:11267
Looking for units near unit 'b:3006;x:1011;y:349;h:10 '
... this unit is located at (1011,349)
1000 blue units randomly checked for nearby units
Total time used 0.56303095817566 (including generation, above)
Best Way to Save Files on Server
No matter how you do this you'll end up accumulating serious data if you want to store large numbers of games. The data you save can be reduced to initial state details followed by updates to that state data. You could end up with something similar to the following:
[Frame 0]
Game State
[Frame 1]
State Changes
...
[Frame X]
Last State
[Post Game]
Wrap up details (scores, etc)
For longer term storage you can compress the game state data and zap it up to Amazon's S3 storage system (or something similar). Playback will only involve generating frames quick enough based on the stream of state changes.
If you do store rendering information you might find that certain region, or strips, of the game board end up empty and unchanging for long periods of time. This too can reduce the data flowing between your unit state engine and your rendering engine.
Fastest Way to Calculate Battle
The language you use to generate or calculate the battle does not have to be the same language as your rendering engine. For example, you could have your rendering engine requesting frames from a separate state management engine. As long as the interfaces stay the same you could upgrade battle calculation, state replay and frame data generation systems as needed.
If time and interest permit I'd go with PHP at first just to get the kinks out of the system -- then invest in whatever portion gives you the biggest bang next. However, I like the challenge of pushing PHP and trying to get "fast" from a language some people assume is slow.
Don't hesitate to store additional state details (that are not written out) during the game. For example, above, I've stored the list of units keyed by the X,Y location on the screen. This attempts to provide a quick path for determining which other units are close to a unit. Anything that takes a long time to iterate through might be better served by a maintained data set that can be looked up via key.
As for the calculation itself, I'm going to suggest that you consider ways to reduce the amount of effort that is happening. Though you have 40,000 units on screen you don't have to process every one of them every frame. You could instead, for example, process all of them per 10 frames while adjusting the scope of action per unit processed to keep the pace of the game the same.
If needed, you can provide rules and reasons for behavior that reduces your processing load. For example, if a unit moved last frame it is not ready to fight until the +Nth frame. If a unit was wounded it must wait until the +Nth frame, healing 1 in the process, before continuing. To adjust for these processing friendly delays you could increase movement rates and damage rates.
Again, don't confuse the size of the battle processing state system with the amount of information that must be saved to replay the game. The state system can load up on data used to make processing more efficient without saving that data anywhere as long as it can be regenerated during playback.
To limit the size, you're probably best off not using JSON. From the structure you gave, it seems that each of the elements can fit in two bytes, meaning that each unit datum will only take up around 12 bytes or so. Since you're saving to disk, the cost of serialization and deserialization is not important compared to the cost of disk I/O.
I'd recommend using a binary format for this:
2 bytes for id
2 bytes for x
2 bytes for y
1 byte for color
1 byte for health
4 bytes for target
which is 12 bytes long. To do this is slightly clunky in Javascript, but can be done by using the bitwise operators to pull bytes out of a string, for instance:
var ustr = <get unit string somehow>
var unit = {};
unit.id = ustr.charCodeAt(0);
unit.x = ustr.charCodeAt(1);
unit.y = ustr.charCodeAt(2);
var teamAndHealth = ustr.charCodeAt(3);
unit.team = teams[teamAndHealth >>> 8];
unit.health = teamAndHealth & 0xFF;
unit.target = [ustr.charCodeAt(4), ustr.charCodeAt(5)];
As for generating the data, PHP is probably not your best choice either. I'd recommend using a language such as C#, Perl, or Java, which can all write binary data quite easily, and have automatic garbage collection to make your life easier.
So I am trying to make a javascript game for my geography class but I have run into some trouble, I can ask the questions and tell you if you're wrong or not but I would like to be able to keep track of the wrongs answers. I want to keep track using for loops but I'm not good at them, some help would be greatly appreciated!
This is the basis of what every question looks like, it's just that && is where I need to add a single mark to the incorrect tally which I am sure I need to use for loops for.
var y = "You are correct!!!"
var n = "You are incorrect!!!"
alert("Chapter 1, Human Cultural Connections. 1-10")
//==================================================
var Q1 = prompt("Demographers identify three different stages of life.
They are children, working adults, and older adults. What is the age
range for children? 0-13, 0-15, 0-18")
if (Q1 === "0-13")
{
alert(y)
}
else
{
alert(n) //&& add 1 tally to incorrect list
}
If someone could help me out with this it would be sooo helpful, and don't worry this is past do anyways but I still want to know how to do it for future projects!
p.s. I already have the script HTML so I don't need help with that.
var correct = [], // well store the index of the correctly answered questions here
wrong = [], // well store the index of the incorrectly answered questions here
questions = [
{
"question": "Demographers identify three different stages of life. They are children, working adults, and older adults. What is the age range for children?",
"answers": ["0-13", "0-15", "0-18"],
"correct": 0 // correct answer is item of index 0 in property "answers" (0-13)
},
{
"question": "whats your favorite color?",
"answers": ["red", "yellow", "blue", "purple"],
"correct": 2 // blue
}
];
for (var i in questions){
var answer = prompt(questions[i].question + questions[i].answers.join(','));
if (answer == questions[i].answers[questions[i].correct]){
correct.push(i);
}else{
wrong.push(i);
}
}
alert('wrong number of answers: ' + wrong.length);
alert('correct number of answers: ' + correct.length);
alert('first wrong question: ' + questions[wrong[0]].question);
I know this is practically overwngineering what you asked for but it might give you better flexibility and knowledge as to how js for loops work. Hope it helps.
Add a variable to keep track of incorrect answers:
var y = "You are correct!!!"
var n = "You are incorrect!!!"
var incorrectCount = 0;
alert("Chapter 1, Human Cultural Connections. 1-10")
//==================================================
var Q1 = prompt("Demographers identify three different stages of life.
They are children, working adults, and older adults. What is the age
range for children? 0-13, 0-15, 0-18")
if (Q1 === "0-13")
{
alert(y)
}
else
{
alert(n) //&& add 1 tally to incorrect list
incorrectCount++;
}