Here is a problem that I wld like to formulate:
The painter intends to frame his square canvases of different sizes in centimeters:
25cm x 35cm -- 20 pcs,
50 x 30 -- 30 pcs,
90 x 50 -- 40 pcs,
110 x 60 -- 25 pcs,
The painter will purchase wooden stretcher bars of 200cm and cut them accordingly.
Condition is "each frame edge should be single continuous bar. No gluing".
Unlimited wooden stretcher bars available in length 200 cm.
how many bars of (200 cm) the Painter should buy?
How to calculate the optimized number of bars, with least wastage of bars?
Is this problem related to optimization (mathematical programming) or AI?
PHP, Perl, vbscript codes welcome.
==============
For clarification purpose, here are the exact lengths to be produced from 200cm bars.
LENGTH PIECES TOTAL LENGTH
110 cm 50 pcs 5500 cm
90 cm 80 pcs 7200 cm
60 cm 50 pcs 3000 cm
50 cm 140 pcs 7000 cm
35 cm 40 pcs 1400 cm
30 cm 60 pcs 1800 cm
25 cm 40 pcs 1000 cm
===========================================
ALL TOTAL: 26900 cm
it is equal to 134.5 bars, if we were allowed to glue small remaining pieces.
It will be practical to guide the painter what lengths should be cut from each bar.
Otherwise he will not know what to do with the bars supplied.
You'll need width of stretcher bars to calculate length for angles (spending additional 2*$stretcher_width for each side of canavas)
use strict;
use warnings;
my $stretcher_length = 200;
my $stretcher_width = 0;
my $wasted_per_side = 2*$stretcher_width;
my #sc = (
{w=> 25, h=> 35, pcs=> 20},
{w=> 50, h=> 30, pcs=> 30},
{w=> 90, h=> 50, pcs=> 40},
{w=> 110, h=> 60, pcs=> 25},
);
# all possible bars needed from longest to shortest
my #all = sort { $b <=> $a } map {
(
($_->{w}+$wasted_per_side) x2, ($_->{h}+$wasted_per_side) x2
)x $_->{pcs};
}
#sc;
# lets cut from 200cm bars
my #rest;
for my $len (#all) {
my $cut_from;
# do we already have bar which can be used?
for my $len_have (#rest) {
# yes, we have
if ($len_have >= $len) { $cut_from = \$len_have; last; }
}
# no, we need another 200cm bar
if (!$cut_from) {
print "Taking new $stretcher_length cm bar\n";
push #rest, $stretcher_length;
$cut_from = \$rest[-1];
}
# cut it
print "Now you have at least one bar $$cut_from long and cut away $len\n";
$$cut_from -= $len;
# keep #rest bars sorted from shortest to longest
#rest = sort { $a <=> $b } #rest;
}
print scalar #rest;
# print "#rest\n"; # left overs
it is actually cutting stock problem
Wikipedia article
There is a C implementation
CPSOL
Solves above problem with 135 sticks.
Unfortunately, failed to find a Perl implementation
Related
Using the length of a string, I want to scale the font size up/down based on that.
So, lower string length, higher number. Higher string length, lower number.
But I don't want to do dozens upon dozens of if/else or a switch statement. Ideally I'd programmatically scale the output based on the input.
Something like...
text_length = strlen($full_text)
size_range = range(0, 5)
// if text_length = 1 then 100% of size_range
// if text_length = 280 then 0% of size_range
In this case, the maximum text length is 280 (they're tweets).
If the plot of y = 1/-279x + 280/279 reflects what you want.
I did the following script in Ruby that should be easy to translate to PHP:
require "bundler/inline"
gemfile do
gem "rspec"
end
require "rspec/autorun"
MAX_SIZE_PERCENTAGE = 1.0
def size_it(text_length, maximum_length)
alpha = - MAX_SIZE_PERCENTAGE / (maximum_length - MAX_SIZE_PERCENTAGE)
beta = maximum_length / (maximum_length - MAX_SIZE_PERCENTAGE)
((alpha * text_length) + beta).round(2)
end
RSpec.describe "dynamic size calculation" do
it "100% when minimal size" do
text_length = 1
maximum_size = 280
expect(size_it(text_length, maximum_size)).to eq(1)
end
it "75% when almost too short" do
text_length = 70
maximum_size = 280
expect(size_it(text_length, maximum_size)).to eq(0.75)
end
it "50% when half point" do
text_length = 140
maximum_size = 280
expect(size_it(text_length, maximum_size)).to eq(0.5)
end
it "25% when almost too long" do
text_length = 210
maximum_size = 280
expect(size_it(text_length, maximum_size)).to eq(0.25)
end
it "0% when maximum size" do
text_length = 280
maximum_size = 280
expect(size_it(text_length, maximum_size)).to eq(0)
end
end
The math is intuitive, a few landmines:
integer division, e.g 1/280 resulting in 0 instead of 0.0003, I prevented this by calling .to_f, Ruby way to cast to float.
rounding errors, expecting 0.25 and getting 0.2503213, I adjusted this by calling round(2), Ruby way to round to nearest decimal point.
What I'm doing here is probably stupid and useless, but it turned out to be a great way to learn php, I appreciate your help.
I came up with a cipher which wraps text in a spiral much like Ulam's spiral maps numbers.
Refer to this image:
I consider the whole spiral as a cube, so if the string is too short to form a full cube, the remaining characters are left as empty spaces (in my picture example there is one space left, because the string is 24 characters and the next full cube is at 25 characters.
I want to add a further step of obfuscation, reading the array diagonally, so the output would be like this:
What is an easy/efficient way to achieve this? I'm storing the data in a 2D array, so it looks like this:
field[0][0]='l';
Bonus tangent question: How easily would something like this be deciphered?
Thank you!
This is the schema for a 5x5 square:
yx yx yx yx yx
0 1 2 3 4 a > 00
0 a b c d e b > 10 01
1 b c d e f c > 20 11 02
2 c d e f g d > 30 21 12 03
3 d e f g h e > 40 31 22 13 04
4 e f g h i f > 41 32 23 14
g > 42 33 24
h > 43 34
i > 44
As you can see, we have:
9 groups (= cols+rows-1 or keys+keys+1);
in each line, the y+x sum is the same, increasing from 0 to 8;
in each line, the y decreases, while the x increases.
each line ends when x reaches initial y
Based on these assumptions, we can write a single loop, using $sum and $startY as criteria to change line: when the decreasing $x has same value of $startY, we increment $sum and we set next $startY to the lowest value between $sum and the higher $array key, then we set next $x to the difference between $sum and $y:
$sum = $startY = $y = $x = 0;
while( $sum < 2*count($array)-1 )
{
echo $array[$y][$x];
if( $x == $startY )
{
$sum++;
$startY = $y = min( $sum, count($array)-1 );
$x = $sum - $y;
}
else
{
$y--;
$x++;
}
}
The result for above square is:
abbcccddddeeeeeffffggghhi
Looking at this eval.in demo you can see three different examples.
Just use for loops. It doesn't matter what language you are learning, you need to learn how to use for loops (or while loops or foreach loops or any good control structure).
You are going 00, then 10, 01, then 20, 11, 02, then 30, 21, 12, 03, etc... YOu can see that the first number decreases by 1 and the second number increases by 1. That goes until you hit n0...0n. That covers the first half of the square...
// Assume $n is the width/height of the square
for($m=0; $m<=$n; $m++)
{
for($a=$n; $a>=0; $a--)
{
for($b=0; $b<=$n; $b++)
{
//Do whatever you want with $array[$a][$n]...
}
}
}
Now, the second half of the square hits 41, 32, 23, 14 on the first stripe. It hits 42, 33, 24 on the second stripe. It hits 43, 34, and finally 44. You can see they both step up until they hit $n
for($m=1; $m<=$n; $m++)
{
for($b=$m; $b<=$n; $b++) // Put B on the outside because it is the limitation
{
for($a=4; $b<=$n; $a--)
{
//Do what you want with $a and $b
}
}
}
Now... can this be deciphered easily? Yes. You are just scrambling up the letters. No matter how you scramble it, it is deciphered easily. You need to substitute the letters with a replacement set that changes. Optimally, you want a completely new replacement set per letter you replace - which is difficult to use. So, most ciphers use a set of replacement sets, say 32 sets of replacement letters or symbols, that cycle through as randomly as possible.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Suppose i have 7 bags with different weight. Actually a php array contains this data.
Bag A 60 Kg
Bag B 80 Kg
Bag C 20 Kg
Bag D 10 Kg
Bag E 80 Kg
Bag F 100 Kg
Bag G 90 Kg
In php it will look like this
Array
(
[30] => 60
[31] => 120
[32] => 120
[33] => 60
[35] => 180
)
Now i have to divide all 7 bags in 4 container equally by balancing there weight.
But i cannot break the bag to manage weight. How to do this please suggest me. How can i build a formula or php function which will distribute all bags balancing there weight.
There is no limitation in container capacity. And its also not necessary to have all containers weight equal after distribution. I just need a load balancing.
Thanks in advance.
Calculate the sum of the weight of your bags then divide it by the number of containers. Then use a bin packaging algorithm to distribute the bags to the individual containers. E.g. take one bag at a time from your array and put it in the first container where the weight of the container plus the weight of your bag is less than the maximally possible container weight.
http://en.wikipedia.org/wiki/Bin_packing_problem
Update:
example written in Ruby. Should be not to hard to rewrite it in PHP. It distributes the bags to the containers relatively evenly (There might be a solution that is more accurate).
# A list of bags with different weights
list_of_bags = [11, 41, 31, 15, 15, 66, 67, 34, 20, 42, 22, 25]
# total weight of all bags
weight_of_bags = list_of_bags.inject(0) {|sum, i| sum + i}
# how many containers do we have at our disposal?
number_of_containers = 4
# How much should one container weight?
weight_per_container = weight_of_bags / number_of_containers
# We make an array containing an empty array for each container
containers = Array.new(number_of_containers){ |i| [] }
# For each bag
list_of_bags.each do |bag|
# we try to find the first container
containers.each do |container|
# where the weight of the container plus the weigth of the bag is
# less than the maximum allowed (weight_per_container)
if container.inject(0) {|sum, i| sum + i} + bag < weight_per_container
# if the current container has space for it we add the bag
# and go to the next one
container.push(bag)
break
end
end
end
# output all containers with the number of items and total weight
containers.each_with_index do |container, index|
puts "container #{index} has #{container.length} items and weigths: #{container.inject(0) {|sum, i| sum + i}}"
end
example result:
container 0 has 3 items and weigths: 83
container 1 has 3 items and weigths: 96
container 2 has 2 items and weigths: 87
container 3 has 2 items and weigths: 76
Create a function that gets a product weight and returns a bag number - the one which has the least free space that's still enough to fit. Put it in the bag. Repeat until done.
$bags = array(60,80,20,10,80,100,90);
$containers = array(1=>100,2=>100,3=>100,4=>100); // number -> free space
$placement = array();
rsort($bags); // biggest first - usually it's better
function bestContainerFor($weight) {
global $containers;
$rest = 0;
$out = 0; // in it won't change $weight fits nowhere
foreach($containers as $nr=>$space) {
if($space<$weight) continue; // not enough space
if($space-$weight<$rest) continue; // we have a better case
$rest = $space-$weight;
$out = $nr;
}
if($out) $containers[$out]-=$weight; // occupy the space
return $out;
}
foreach($bags as $nr=>$w) {
$p = bestContainerFor($w);
$placement[$nr] = $p; // for later use; in this example it's not needed
if( $p) print "Bag $nr fits in $p<br>";
if(!$p) print "Bag $nr fits nowhere<br>";
}
It's not tested. If you give me some details of your code I'll try to adapt. This just shows the principle of it.
Note that
it works with variable container sizes,
it gives you the placement of each bag, not the sum weight,
it's not optimal for equal distribution, just gives a good case
Im making a browser based PHP game and in my database for the players it has a record of that players total EXP or experience.
What i need is a formula to translate that exp into a level or rank, out of 100.
So they start off at level 1, and when they hit say, 50 exp, go to level 2, then when they hit maybe 125/150, level 2.
Basically a formula that steadily makes each level longer (more exp)
Can anyone help? I'm not very good at maths :P
Many formulas may suit your needs, depending on how fast you want the required exp to go up.
In fact, you really should make this configurable (or at least easily changed in one central location), so that you can balance the game later. In most games these (and other) formulas are determined only after playtesting and trying out several options.
Here's one formula: First level-up happens at 50 exp; second at 150exp; third at 300 exp; fourth at 500 exp; etc. In other words, first you have to gather 50 exp, then 100 exp, then 150exp, etc. It's an Arithmetic Progression.
For levelup X then you need 25*X*(1+X) exp.
Added: To get it the other way round you just use basic math. Like this:
y=25*X*(1+X)
0=25*X*X+25*X-y
That's a standard Quadratic equation, and you can solve for X with:
X = (-25Âħsqrt(625+100y))/50
Now, since we want both X and Y to be greater than 0, we can drop one of the answers and are left with:
X = (sqrt(625+100y)-25)/50
So, for example, if we have 300 exp, we see that:
(sqrt(625+100*300)-25)/50 = (sqrt(30625)-25)/50 = (175-25)/50 = 150/50 = 3
Now, this is the 3rd levelup, so that means level 4.
If you wanted the following:
Level 1 # 0 points
Level 2 # 50 points
Level 3 # 150 points
Level 4 # 300 points
Level 5 # 500 points etc.
An equation relating experience (X) with level (L) is:
X = 25 * L * L - 25 * L
To calculate the level for a given experience use the quadratic equation to get:
L = (25 + sqrt(25 * 25 - 4 * 25 * (-X) ))/ (2 * 25)
This simplifies to:
L = (25 + sqrt(625 + 100 * X)) / 50
Then round down using the floor function to get your final formula:
L = floor(25 + sqrt(625 + 100 * X)) / 50
Where L is the level, and X is the experience points
It really depends on how you want the exp to scale for each level.
Let's say
LvL1 : 50 Xp
Lvl2: LvL1*2=100Xp
LvL3: LvL2*2=200Xp
Lvl4: LvL3*2=400Xp
This means you have a geometric progression
The Xp required to complete level n would be
`XPn=base*Q^(n-1)`
In my example base is the inital 50 xp and Q is 2 (ratio).
Provided a player starts at lvl1 with no xp:
when he dings lvl2 he would have 50 total Xp
at lvl3 150xp
at lvl4 350xp
and so forth
The total xp a player has when he gets a new level up would be:
base*(Q^n-1)/(Q-1)
In your case you already know how much xp the player has. For a ratio of 2 the formula gets simpler:
base * (2^n-1)=total xp at level n
to find out the level for a given xp amount all you need to do is apply a simple formula
$playerLevel=floor(log($playerXp/50+1,2));
But with a geometric progression it will get harder and harder and harder for players to level.
To display the XP required for next level you can just calculate total XP for next level.
$totalXpNextLevel=50*(pow(2,$playerLevel+1)-1);
$reqXp=$totalXpNextLevel - $playerXp;
Check start of the post:
to get from lvl1 -> lvl2 you need 50 xp
lvl2 ->lvl3 100xp
to get from lvl x to lvl(x+1)
you would need
$totalXprequired=50*pow(2,$playerLevel-1);
Google gave me this:
function experience($L) {
$a=0;
for($x=1; $x<$L; $x++) {
$a += floor($x+300*pow(2, ($x/7)));
}
return floor($a/4);
}
for($L=1;$L<100;$L++) {
echo 'Level '.$L.': '.experience($L).'<br />';
}
It is supposed the be the formula that RuneScape uses, you might me able to modify it to your needs.
Example output:
Level 1: 0
Level 2: 55
Level 3: 116
Level 4: 184
Level 5: 259
Level 6: 343
Level 7: 435
Level 8: 536
Level 9: 649
Level 10: 773
Here is a fast solution I used for a similar problem. You will likely wanna change the math of course, but it will give you the level from a summed xp.
$n = -1;
$L = 0;
while($n < $xp){
$n += pow(($L+1),3)+30*pow(($L+1),2)+30*($L+1)-50;
$L++;
}
echo("Current XP: " .$xp);
echo("Current Level: ".$L);
echo("Next Level: " .$n);
I take it what you're looking for is the amount of experience to decide what level they are on? Such as:
Level 1: 50exp
Level 2: 100exp
Level 3: 150exp ?
if that's the case you could use a loop something like:
$currentExp = x;
$currentLevel;
$i; // initialLevel
for($i=1; $i < 100; $i *= 3)
{
if( ($i*50 > $currentExp) && ($i < ($i+1)*$currentExp)){
$currentLevel = $i/3;
break;
}
}
This is as simple as I can make an algorithm for levels, I haven't tested it so there could be errors.
Let me know if you do use this, cool to think an algorithm I wrote could be in a game!
The original was based upon a base of 50, thus the 25 scattered across the equation.
This is the answer as a real equation. Just supply your multiplier (base) and your in business.
$_level = floor( floor( ($_multipliter/2)
+ sqrt( ($_multipliter^2) + ( ($_multipliter*2) * $_score) )
)
/ $_multipliter
) ;
I know question title seems quite 'un-understandable', but I don't know how to write question title for this particular question.
Question:
I want to find factor for position.
Let me clear you with an example.
Value Factor
[Available] [Have to find out]
----------------------------------
1 10
3 10
9 10
10 10
11 10
25 10
50 10
75 10
99 10
100 100
101 100
105 100
111 100
127 100
389 100
692 100
905 100
999 100
1000 1000
1099 1000
1111 1000
4500 1000
6825 1000
7789 1000
9999 1000
10000 10000
10099 10000
51234 10000
98524 10000
99999 10000
100000 100000
and so on.
I hope you understand what I mean to get.
Assuming that the first three values should be 1 (as noted by Asaph), then you just need to use all that logarithm stuff you learned in school:
pow(10, floor(log10($n)))
So, how does this work? The base-10 logarithm of a number x is the y such that 10^y = x (where ^ stands for exponentiation). This gives us the following:
log( 1) 0
log( 10) 1
log(100) 2
...
So the log10 of a number between 1 and 10 will be between 0 and 1, the log10 of a number between 10 and 100 will be between 1 and 2, etc. The floor function will give you the integer part of the logarithm (we're only dealing with non-negative values here so there's no need to worry about which direction floor goes with negative values) so floor(log10()) will be 0 for for anything between 1 and 10, 1 for anything between 10 and 100, etc. Now we have how many factors of ten we need so a simple pow(10, ...) gives us the final result.
References:
log10
floor
pow
I'm still a little unsure of what you're asking, but it seems like you want to map values to other values... In php arrays can be indexed with anything (making them a map). If 999 always means a factor of 100 and 1099 always means a factor of 1000, you can set the value of array[999] to 100 and the value of array[1099] to 1000, etc.
Basically Factor is 10 to the power of number of digits in $value minus 1 (except for the single digit numbers):
if($value < 10) {
$value += 10;
}
$numOfDigits = count(str_split($value,1));
$factor = pow(10,$numDigits-1);
This function should work for you. It seems like the first 3 "factors" in your list don't fit the pattern. If, in your sample data set, those first 3 "factors" should really be 1 instead of 10, then you can safely remove the first 3 lines of the body of the function below.
function getFactor($num) {
if ($num < 10) { // If the first 3 "factors" listed
return 10; // in the question should be 1 instead of 10
} // then remove these 3 lines.
$factor = 1;
while($factor <= $num) {
$factor *= 10;
}
return $factor / 10;
}