I've been racking my brains over this problem for two days, I've tried different things but none of them work. I'm building an app which is a kind of quizz. There are three subjects which contain questions. I would like to use 3 sliders to define the percentage of questions they want on each subject.
ex : slider one = History
slider two = Maths
slider three = Grammar
If I choose to have more history, I slide the history slider up and the other sliders should decrease according to the values they have to reach 100% for the 3 sliders...
Any idea for an algorithm ? And what happens when one slider reach a zero value ?
Maths has never been my scene.
Any Help would be very much appreciated.
Thanks in advance.
Mike
The following algorithm should be reviewed and of course optimized. It is only something that I have put together and I've not tested it.
initialize each slider with a max and minimum value and set the inital value as desired, but respecting that x + y + z = 1
.
[self.slider1 setMinimumValue:0.0];
[self.slider1 setMaximumValue:1.0];
[self.slider1 setValue:0.20];
[self.slider2 setMinimumValue:0.0];
[self.slider2 setMaximumValue:1.0];
[self.slider2 setValue:0.30];
[self.slider3 setMinimumValue:0.0];
[self.slider3 setMaximumValue:1.0];
[self.slider3 setValue:0.50];
Set the three slider to the same selector:
[self.slider1 addTarget:self action:@selector(valueChanged:) forControlEvents:UIControlEventValueChanged];
[self.slider2 addTarget:self action:@selector(valueChanged:) forControlEvents:UIControlEventValueChanged];
[self.slider3 addTarget:self action:@selector(valueChanged:) forControlEvents:UIControlEventValueChanged];
The selector should do something like that:
- (void)valueChanged:(UISlider *)slider {
UISlider *sliderX = nil;
UISlider *sliderY = nil;
UISlider *sliderZ = nil;
if (slider == self.slider1) {
sliderX = self.slider1;
sliderY = self.slider2;
sliderZ = self.slider3;
} else if (slider == self.slider2) {
sliderY = self.slider1;
sliderX = self.slider2;
sliderZ = self.slider3;
} else {
sliderY = self.slider1;
sliderZ = self.slider2;
sliderX = self.slider3;
}
float x = sliderX.value;
float y = sliderY.value;
float z = sliderZ.value;
// x + y + z = 1
// Get the amout x has changed
float oldX = 1 - y - z;
float difference = x - oldX;
float newY = y - difference / 2;
float newZ = z - difference / 2;
if (newY < 0) {
newZ += y + newY;
newY = 0;
}
if (newZ < 0) {
newY += z + newZ;
newZ = 0;
}
[sliderY setValue:newY animated:YES];
[sliderZ setValue:newZ animated:YES];
}
If there is something wrong with this code, please let me know, and I can fix it!
Though Snowangelic's answer is good, I think it makes more sense to to constrain the ratio between the unchanged values as follows.
Let s1, s2, s3 be the current values of the sliders, so that s1+s2+s3=100. You want to solve for n1, n2, n3 the new values of the sliders, so that n1+n2+n3=100. Assume s1 is changed to n1 by the user. Then this adds the following constraint:
n2/n3 = s2/s3
So the solution to the problem, with n1+n2+n3=100, is
n2 = (100-n1)/(s3/s2 + 1) or 0 (if s2=0) and
n3 = (100-n1)/(s2/s3 + 1) or 0 (if s3=0)
Start all three sliders at 33.333...%
When the users moves a slider up say 10% : move the two other sliders down of 5%. But if one of two slider reaches 0 => only move the other one of ten percent. So it gives something like this :
User moved slider of x (my be positive or negative)
for first slider
if slider -x/2 > 0 and x/2 < 100
move this slider of -x/2
else
move the other slider of -x/2
for second slider
if slider -x/2 > 0 and x/2 < 100
move this slider of -x/2
else
move the other slider of -x/2
end
Another possibility would be to consider that the sum os the available ressources is 100, the ressources are separated into n buckets (in your case 3). When the user moves a slider, he fixes the number of ressources in the corresponding bucket. And so you may either take ressources from other bucket or put ressources in these other buckets.
You have something like :
state 1 ; modified bucket ; new number of ressources in that bucket
modification = new number of ressources in the bucket - number of rescources in the state 1
for (int i=0 ; modification > 0 ; i++){
i=i%nbr of buckets;
if(bucket i != modified bucket){
if(number of ressources in bucket i-- > 0 && number of ressources in bucket i-- < 100){
number of ressources in bucket i--;
modification --;
}
}
}
That is assuming the modification is positive (new number in the modified bucket is higher than before). This small algorithm would work with any number of buckets (sliders in your case).