Related
I am trying to prove the following property in Dafny: covariance(x,y) <= variance(x) * variance(y), where x and y are real.
First of all, I would like to know if I am interpreting covariance and variance correctly. Thus, I make the following question: is it the same proving covariance(x,y) <= variance(x) * variance(y) and proving covariance(x,y) <= covariance(x,x) * covariance(y,y)? I make this question because the variance usually appears to the power of 2 (i.e., sigma^2(x)), which confuses me.
However, I understand from https://en.wikipedia.org/wiki/Covariance that this equivalence holds. Concretely, the following is stated: The variance is a special case of the covariance in which the two variables are identical.
I also take one of the definitions of covariance from that link. Concretely: cov(x,y)=(1/n)*summation(i from 1 to n){(x_i-mean(x))*(y_i-mean(y))}.
Thus, assuming that I must prove covariance(x,y) <= covariance(x,x) * covariance(y,y) and that covariance is defined like above, I test the following lemma in Dafny:
lemma covariance_equality (x: seq<real>, y:seq<real>)
requires |x| > 1 && |y| > 1; //my conditions
requires |x| == |y|; //my conditions
requires forall elemX :: elemX in x ==> 0.0 < elemX; //my conditions
requires forall elemY :: elemY in y ==> 0.0 < elemY; //my conditions
ensures covariance_fun (x,y) <= covariance_fun(x,x) * covariance_fun (y,y);
{}
Which cannot be proven automatically. The point is that I do not know how to prove it manually. I made this (not useful) approach of a contraction proof, but I guess this is not the way:
lemma covariance_equality (x: seq<real>, y:seq<real>)
requires |x| > 1 && |y| > 1; //my conditions
requires |x| == |y|; //my conditions
requires forall elemX :: elemX in x ==> 0.0 < elemX; //my conditions
requires forall elemY :: elemY in y ==> 0.0 < elemY; //my conditions
ensures covariance_fun (x,y) <= covariance_fun(x,x) * covariance_fun (y,y);
{
if !(covariance_fun(x,y) < covariance_fun(x,c) * covariance_fun (y,y)) {
//...
assert !(forall elemX' :: elemX' in x ==> 0.0<elemX') && (forall elemY' :: elemY' in y ==> 0.0<elemY'); //If we assume this, the proof is verified
assert false;
}
}
My main question is: how can I prove this lemma?
So that you have all the information, I offer the functions by which covariance calculation is made up. First, the covariance function is as follows:
function method covariance_fun(x:seq<real>, y:seq<real>):real
requires |x| > 1 && |y| > 1;
requires |x| == |y|;
decreases |x|,|y|;
{
summation(x,mean_fun(x),y,mean_fun(y)) / ((|x|-1) as real)
}
As you can see, it performs summation and then divides by the length. Also, note that the summation function receives mean of x and mean of y. Summation is as follows:
function method summation(x:seq<real>,x_mean:real,y:seq<real>,y_mean:real):real
requires |x| == |y|;
decreases |x|,|y|;
{
if x == [] then 0.0
else ((x[0] - x_mean)*(y[0] - y_mean))
+ summation(x[1..],x_mean,y[1..],y_mean)
}
As you can see, it recursively performs (x-mean(x))*(y-mean(y)) of each position.
As for helper functions, mean_fun calculates the mean and is as follows:
function method mean_fun(s:seq<real>):real
requires |s| >= 1;
decreases |s|;
{
sum_seq(s) / (|s| as real)
}
Note that is uses sum_seq function which, given a sequence, calculates the sum of all its positions. It is defined recursively:
function method sum_seq(s:seq<real>):real
decreases s;
{
if s == [] then 0.0 else s[0] + sum_seq(s[1..])
}
Now, with all these ingredientes, can anyone tell me (1) if I already did something wrong and/or (2) how to prove the lemma?
PS: I have been looking and this lemma seems to be the Cauchy–Schwarz inequality, but still do not know how to solve it.
Elaborating on the answer
I will (1) define a convariance function cov in terms of product and then (2) use this definition in a new lemma that should hold.
Also, note that I add the restriction that 'x' and 'y' are non-empty, but you can modify this
//calculates the mean of a sequence
function method mean_fun(s:seq<real>):real
requires |s| >= 1;
decreases |s|;
{
sum_seq(s) / (|s| as real)
}
//from x it constructs a=[x[0]-x_mean, x[1]-x_mean...]
function construct_list (x:seq<real>, m:real) : (a:seq<real>)
requires |x| >= 1
ensures |x|==|a|
{
if |x| == 1 then [x[0]-m]
else [x[0]-m] + construct_list(x[1..],m)
}
//covariance is calculated in terms of product
function cov(x: seq<real>, y: seq<real>) : real
requires |x| == |y|
requires |x| >= 1
ensures cov(x,y) == product(construct_list(x, mean_fun(x)),construct_list(y, mean_fun(y))) / (|x| as real) //if we do '(|x| as real)-1', then we can have a division by zero
//i.e., ensures cov(x,y) == product(a,b) / (|x| as real)
{
//if |a| == 1 then 0.0 //we do base case in '|a|==1' instead of '|a|==1', because we have precondition '|a| >= 1'
//else
var x_mean := mean_fun(x);
var y_mean := mean_fun(y);
var a := construct_list(x, x_mean);
var b := construct_list(y, y_mean);
product(a,b) / (|a| as real)
}
//Now, test that Cauchy holds for Cov
lemma cauchyInequality_usingCov (x: seq<real>, y: seq<real>)
requires |x| == |y|
requires |x| >= 1
requires forall i :: 0 <= i < |x| ==> x[i] >= 0.0 && y[i] >= 0.0
ensures square(cov(x,y)) <= cov(x,x)*cov(y,y)
{
CauchyInequality(x,y);
}
\\IT DOES NOT HOLD!
Proving HelperLemma (not provable?)
Trying to prove HelperLemma I find that Dafny is able to prove that LHS of a*a*x + b*b*y >= 2.0*a*b*z is positive.
Then, I started to prove different cases (I know this is not the best procedure):
(1) If one of a,b or z is negative (while the rest positive) or when the three are negative; then RHS is negative
And when RHS is negative, LHS is greater or equal (since LHS is positive).
(2) If a or b or z are 0, then RHS is 0, thus LHS is greater or equal.
(3) If a>=1, b>=1 and z>=1, I tried to prove this using sqrt_ineq().
BUT! We can find a COUNTER EXAMPLE.
With a=1, b=1, z=1, RHS is 2; now, choose x to be 0 and y to be 0 (i.e., LHS=0). Since 0<2, this is a counter example.
Am I right? If not, how can I prove this lemma?
lemma HelperLemma(a: real, x: real, b: real, y: real, z: real)
requires x >= 0.0 && y >= 0.0 //&& z >= 0.0
requires square(z) <= x * y
ensures a*a*x + b*b*y >= 2.0*a*b*z
{
assert square(z) == z*z;
assert a*a*x + b*b*y >= 0.0; //a*a*x + b*b*y is always positive
if ((a<0.0 && b>=0.0 && z>=0.0) || (a>=0.0 && b<0.0 && z>=0.0) || (a>=0.0 && b>=0.0 && z<0.0) || (a<0.0 && b<0.0 && z<0.0)) {
assert 2.0*a*b*z <=0.0; //2.0*a*b*z <= 0.0 is negative or 0 when product is negative
assert a*a*x + b*b*y >= 2.0*a*b*z; // When 2.0*a*b*z <= 0.0 is negative or 0, a*a*x + b*b*y is necessarily greater
}
if (a==0.0 || b==0.0 || z==0.0){
assert a*a*x + b*b*y >= 2.0*a*b*z;
}
else if (a>=1.0 && b>=1.0 && z>= 1.0){
assert a*a >= a;
assert b*b >= b;
assert a*a+b*b >= a*b;
assert square(z) <= x * y;
//sqrt_ineq(square(z),x*y);
//assert square(z) == z*z;
//sqrt_square(z);
//assert sqrt(z) <= sqrt(x*y);
//assert (x==0.0 || y == 0.0) ==> (x*y==0.0) ==> (square(z) <= 0.0) ==> z<=0.0;
assert a*a*x + b*b*y >= 2.0*a*b*z;
//INDEED: COUNTER EXAMPLE: a=1, b=1, z=1. Thus: RHS is 2; now, choose x to be 0 and y to be 0 (i.e., LHS=0). Since 0<2, this is a counter example.
}
}
Edited after clarification/fixing of post condition.
Here is attempt to do it in Dafny using calculation and induction.
Few comments on verification
Since task at hand is verification, I assumed sqrt function and some of its properties. HelperLemma is provable provided we assume some properties of sqrt function. There are two assumption in verification that is easy to prove.
function square(r: real) : real
ensures square(r) >= 0.0
{
r * r
}
function sqrt(r: real) : real
function {:fuel 2} product(a: seq<real>, b: seq<real>) : real
requires |a| == |b|
{
if |a| == 0 then 0.0
else a[0] * b[0] + product(a[1..], b[1..])
}
lemma sqrt_ineq(a: real, b: real)
requires a >= 0.0 && b >= 0.0
requires a <= b
ensures sqrt(a) <= sqrt(b)
lemma sqrt_square(a: real)
ensures sqrt(square(a)) == a
lemma CauchyBaseInequality(a1: real, a2: real, b1: real, b2: real)
ensures square(a1*b1 + a2*b2) <= (a1*a1 + a2*a2) * (b1*b1 + b2*b2)
{
calc <= {
square(a1*b1 + a2*b2) - (a1*a1 + a2*a2) * (b1*b1 + b2*b2);
a1*b1*a1*b1 + a2*b2*a2*b2 + 2.0*a1*b1*a2*b2 - a1*a1*b1*b1 - a1*a1*b2*b2 - a2*a2*b1*b1 - a2*a2*b2*b2;
2.0*a1*b1*a2*b2 - a1*a1*b2*b2 - a2*a2*b1*b1;
- square(a1*b2 - a2*b1);
0.0;
}
}
lemma HelperLemma(a: real, x: real, b: real, y: real, z: real)
requires x >= 0.0 && y >= 0.0
requires square(z) <= x * y
ensures a*a*x + b*b*y >= 2.0*a*b*z
lemma CauchyInequality(a: seq<real>, b: seq<real>)
requires |a| == |b|
ensures square(product(a, b)) <= product(a, a) * product(b, b)
{
if |a| <= 2 {
if |a| == 2 {
CauchyBaseInequality(a[0], a[1], b[0], b[1]);
}
}
else {
var x, xs := a[0], a[1..];
var y, ys := b[0], b[1..];
calc >= {
product(a, a) * product(b, b) - square((product(a, b)));
(x*x + product(xs, xs))*(y*y + product(ys, ys)) - square(x*y + product(xs, ys));
x*x*y*y + y*y*product(xs, xs) + x*x*product(ys, ys) + product(xs, xs)*product(ys, ys)
- x*x*y*y - square(product(xs, ys)) - 2.0*x*y*product(xs, ys);
y*y*product(xs, xs) + x*x*product(ys, ys) + product(xs, xs) * product(ys, ys)
- square(product(xs, ys)) - 2.0*x*y*product(xs, ys);
{ CauchyInequality(xs, ys); }
y*y*product(xs, xs) + x*x*product(ys, ys) - 2.0*x*y*product(xs, ys);
{
CauchyInequality(xs, ys);
assume product(xs, xs) >= 0.0;
assume product(ys, ys) >= 0.0;
HelperLemma(y, product(xs, xs), x, product(ys, ys), product(xs, ys));
}
0.0;
}
}
}
lemma cauchyInequality_usingCov (x: seq<real>, y: seq<real>)
requires |x| == |y|
requires |x| >= 1
requires forall i :: 0 <= i < |x| ==> x[i] >= 0.0 && y[i] >= 0.0
ensures square(cov(x,y)) <= cov(x,x)*cov(y,y)
{
var x_mean := mean_fun(x);
var y_mean := mean_fun(y);
var a := construct_list(x, x_mean);
var b := construct_list(y, y_mean);
assert cov(x, y) == product(a, b) / (|x| as real);
assert cov(x, x) == product(a, a) / (|x| as real);
assert cov(y, y) == product(b, b) / (|x| as real);
CauchyInequality(a, b);
}
Verification of Helper Lemma
function square(r: real): real
ensures square(r) >= 0.0
{
r * r
}
function abs(a: real) : real
ensures abs(a) >= 0.0
{
if a < 0.0 then -a else a
}
function sqrt(r: real): real
requires r >= 0.0
ensures square(sqrt(r)) == r && sqrt(r) >= 0.0
lemma sqrtIneq(a: real, b: real)
requires a >= 0.0 && b >= 0.0
requires a <= b
ensures sqrt(a) <= sqrt(b)
lemma sqrtLemma(a: real)
ensures sqrt(square(a)) == abs(a)
lemma sqrtMultiply(a: real, b: real)
requires a >= 0.0 && b >= 0.0
ensures sqrt(a*b) == sqrt(a) * sqrt(b);
lemma differenceLemma(a: real, b: real)
requires a >= abs(b)
ensures a - b >= 0.0 && a + b >= 0.0
{
}
lemma HelperLemma(a: real, x: real, b: real, y: real, z: real)
requires x >= 0.0 && y >= 0.0
requires square(z) <= x * y
ensures a*a*x + b*b*y >= 2.0*a*b*z
{
var sx := sqrt(x);
var sy := sqrt(y);
assert sx * sx == x;
assert sy * sy == y;
if (a >= 0.0 && b >= 0.0) || (a < 0.0 && b < 0.0) {
calc >= {
a*a*x + b*b*y - 2.0*a*b*z;
a*a*sx*sx + b*b*sy*sy - 2.0*a*b*sx*sy + 2.0*a*b*sx*sy - 2.0*a*b*z;
square(a*sx - b*sy) + 2.0*a*b*sx*sy - 2.0*a*b*z;
2.0*a*b*sx*sy - 2.0*a*b*z;
2.0*a*b*(sx*sy - z);
{
sqrtIneq(square(z), x * y);
assert sqrt(x * y) >= sqrt(square(z));
sqrtMultiply(x, y);
assert sx * sy >= sqrt(square(z));
sqrtLemma(z);
assert sx * sy >= abs(z);
differenceLemma(sx*sy, z);
assert sx*sy >= z;
}
0.0;
}
}
else {
calc >= {
a*a*x + b*b*y - 2.0*a*b*z;
a*a*sx*sx + b*b*sy*sy + 2.0*a*b*sx*sy - 2.0*a*b*sx*sy - 2.0*a*b*z;
square(a*sx + b*sy) - 2.0*a*b*sx*sy - 2.0*a*b*z;
- 2.0*a*b*sx*sy - 2.0*a*b*z;
- 2.0*a*b*(sx*sy + z);
{
sqrtIneq(square(z), x * y);
assert sqrt(x * y) >= sqrt(square(z));
sqrtMultiply(x, y);
assert sx * sy >= sqrt(square(z));
sqrtLemma(z);
assert sx * sy >= abs(z);
differenceLemma(sx*sy, z);
assert sx*sy >= -z;
}
0.0;
}
}
}
local delay = math.random(25, 50)
[string "LuaVM"]:5: attempt to index a nil value (global 'math')
I can't use math.random anymore is there any way to fix this ?
If math library is missed you can insert the following code block at the beginning of your script.
It will not fix the whole math library, but only some of the most frequently used functions (including math.random).
It will also fix the following errors:
bad argument #1 to 'Sleep' (number has no integer representation)
attempt to call a nil value (field 'getn')
do
local state_8, state_45, cached_bits, cached_bits_qty = 2, 0, 0, 0
local prev_width, prev_bits_in_factor, prev_k = 0
for c in GetDate():gmatch"." do
state_45 = state_45 % 65537 * 23456 + c:byte()
end
local function get_53_random_bits()
local value53 = 0
for shift = 26, 27 do
local p = 2^shift
state_45 = (state_45 * 233 + 7161722017421) % 35184372088832
repeat state_8 = state_8 * 76 % 257 until state_8 ~= 1
local r = state_8 % 32
local n = state_45 / 2^(13 - (state_8 - r) / 32)
n = (n - n%1) % 2^32 / 2^r
value53 = value53 * p + ((n%1 * 2^32) + (n - n%1)) % p
end
return value53
end
for j = 1, 10 do get_53_random_bits() end
local function get_random_bits(number_of_bits)
local pwr_number_of_bits = 2^number_of_bits
local result
if number_of_bits <= cached_bits_qty then
result = cached_bits % pwr_number_of_bits
cached_bits = (cached_bits - result) / pwr_number_of_bits
else
local new_bits = get_53_random_bits()
result = new_bits % pwr_number_of_bits
cached_bits = (new_bits - result) / pwr_number_of_bits * 2^cached_bits_qty + cached_bits
cached_bits_qty = 53 + cached_bits_qty
end
cached_bits_qty = cached_bits_qty - number_of_bits
return result
end
table = table or {}
table.getn = table.getn or function(x) return #x end
math = math or {}
math.huge = math.huge or 1/0
math.abs = math.abs or function(x) return x < 0 and -x or x end
math.floor = math.floor or function(x) return x - x%1 end
math.ceil = math.ceil or function(x) return x + (-x)%1 end
math.min = math.min or function(x, y) return x < y and x or y end
math.max = math.max or function(x, y) return x > y and x or y end
math.sqrt = math.sqrt or function(x) return x^0.5 end
math.pow = math.pow or function(x, y) return x^y end
math.frexp = math.frexp or
function(x)
local e = 0
if x == 0 then
return x, e
end
local sign = x < 0 and -1 or 1
x = x * sign
while x >= 1 do
x = x / 2
e = e + 1
end
while x < 0.5 do
x = x * 2
e = e - 1
end
return x * sign, e
end
math.exp = math.exp or
function(x)
local e, t, k, p = 0, 1, 1
repeat e, t, k, p = e + t, t * x / k, k + 1, e
until e == p
return e
end
math.log = math.log or
function(x)
assert(x > 0)
local a, b, c, d, e, f = x < 1 and x or 1/x, 0, 0, 1, 1
repeat
repeat
c, d, e, f = c + d, b * d / e, e + 1, c
until c == f
b, c, d, e, f = b + 1 - a * c, 0, 1, 1, b
until b <= f
return a == x and -f or f
end
math.log10 = math.log10 or
function(x)
return math.log(x) / 2.3025850929940459
end
math.random = math.random or
function(m, n)
if m then
if not n then
m, n = 1, m
end
local k = n - m + 1
if k < 1 or k > 2^53 then
error("Invalid arguments for function 'random()'", 2)
end
local width, bits_in_factor, modk
if k == prev_k then
width, bits_in_factor = prev_width, prev_bits_in_factor
else
local pwr_prev_width = 2^prev_width
if k > pwr_prev_width / 2 and k <= pwr_prev_width then
width = prev_width
else
width = 53
local width_low = -1
repeat
local w = (width_low + width) / 2
w = w - w%1
if k <= 2^w then
width = w
else
width_low = w
end
until width - width_low == 1
prev_width = width
end
bits_in_factor = 0
local bits_in_factor_high = width + 1
while bits_in_factor_high - bits_in_factor > 1 do
local bits_in_new_factor = (bits_in_factor + bits_in_factor_high) / 2
bits_in_new_factor = bits_in_new_factor - bits_in_new_factor%1
if k % 2^bits_in_new_factor == 0 then
bits_in_factor = bits_in_new_factor
else
bits_in_factor_high = bits_in_new_factor
end
end
prev_k, prev_bits_in_factor = k, bits_in_factor
end
local factor, saved_bits, saved_bits_qty, pwr_saved_bits_qty = 2^bits_in_factor, 0, 0, 2^0
k = k / factor
width = width - bits_in_factor
local pwr_width = 2^width
local gap = pwr_width - k
repeat
modk = get_random_bits(width - saved_bits_qty) * pwr_saved_bits_qty + saved_bits
local modk_in_range = modk < k
if not modk_in_range then
local interval = gap
saved_bits = modk - k
saved_bits_qty = width - 1
pwr_saved_bits_qty = pwr_width / 2
repeat
saved_bits_qty = saved_bits_qty - 1
pwr_saved_bits_qty = pwr_saved_bits_qty / 2
if pwr_saved_bits_qty <= interval then
if saved_bits < pwr_saved_bits_qty then
interval = nil
else
interval = interval - pwr_saved_bits_qty
saved_bits = saved_bits - pwr_saved_bits_qty
end
end
until not interval
end
until modk_in_range
return m + modk * factor + get_random_bits(bits_in_factor)
else
return get_53_random_bits() / 2^53
end
end
local orig_Sleep = Sleep
function Sleep(x)
return orig_Sleep(x - x%1)
end
end
I'm implementing an image processing algorithm called BM3D and I've already achieved the outcome which is denoising a grayscale image but the thing is that it is too slow, even with a 436 by 436 gray image.
I have already tried to find way to maybe fasten up the work that I do with array and lists, but didn't get much improvement
val img = imread("files/image.png", 0)
val img3= Mat(img.rows(),img.cols(),img.type())
val listaBlocos = mutableListOf(Pair(0.0, Pair(0,0)))
val tamanhoBloco = 3 //Block Size
val tamanhoJanela = 9 //Window Size
val mediaPorBloco = DoubleArray(16)
var sum = 0.0
listaBlocos.clear()
val stats_file = File("files/tempos436x436.txt")
val test = 10
for (x in 0 until test){
val timeelapsed = measureTimeMillis {
for (col in 20 ..img.width() - 20) {
for (row in 20 ..img.height() - 20) {
val block1 = generateBlock(img, row, col, tamanhoBloco)
for (c in -tamanhoJanela..tamanhoJanela) {
for (l in -tamanhoJanela..tamanhoJanela) {
val block2 = generateBlock(img, row + l, col + c, tamanhoBloco)
val d = distBlock(block1, block2)
val par = Pair(d, Pair(row + l, col + c))
listaBlocos.add(par)
}
}
val listaBlocosOrdenada = listaBlocos.sortedWith(compareBy { it.first })
listaBlocos.clear()
for (k in 0..15) {
sum = 0.0
val c2 = listaBlocosOrdenada[k].second.second
val l2 = listaBlocosOrdenada[k].second.first
for (c in 0..tamanhoBloco - 1) {
for (l in 0..tamanhoBloco - 1) {
sum += img.get(l2 - l, c2 - c)[0]
}
}
mediaPorBloco[k] = sum / 4
}
val v = mediaPorBloco.average()
img3.put(row,col,v)
}
}
}
imwrite("files/resultado.png", img3)
stats_file.appendText("teste$x 100X200 $timeelapsed\n")
}
well the result in the actual image denoising is good but is takes maybe 15 min to denoise a 436 x 436 image. I'm currently using a virtual machine with Ubuntu and 4 cores a 4 gbs of Ram
I'm trying to resize and relocate an object, by changing the x, y and area values, all at the same time.
I can do them one after another by running 3 separate for loops, but the animation needs to be smooth and as one.
I tried nesting another for loop inside the function but that provides the same result as 1 loop has to finish before the next one starts.
The only way I can find to complete it is to make 3 separate scripts and run all 3 at the same time.
SSxPOSA = 0.00
SSxPOSB = -12.00
SSyPOSA = 0.00
SSyPOSB = -6.55
SSsizeA = 1.00
SSsizeB = 0.2
function SSBox1X()
for i = SSxPOSA, SSxPOSB, 0.1
do
Object1X( i );
end;
end;
function SSBox1Y()
for i = SSyPOSA, SSyPOSB, 0.5
do
Object1Y( i );
end;
end;
function SSBox1Scale()
for i = SSsizeA, SSsizeB, 0.8
do
Object1Scale( i );
end;
end;
SSBox1X();
SSBox1Y();
SSBox1Scale();
Happy to read and learn best practice
If I understood your problem correctly, something like this should work:
function xys()
local x, y, s = SSxPOSA, SSyPOSA, SSsizeA
return coroutine.wrap(
function()
while x >= SSxPOSB and y >= SSyPOSB and s >= SSsizeB do
coroutine.yield(x,y,s)
x = x - 0.1
y = y - 0.5
s = s - 0.8
end
end)
end
SSxPOSA = 0.00
SSxPOSB = -12.00
SSyPOSA = 0.00
SSyPOSB = -6.55
SSsizeA = 1.00
SSsizeB = 0.2
for x,y,s in xys() do
print(x,y,s)
--Object1X(x)
--Object1Y(y)
--Object1Scale(s)
end
And, because of floating point comparison not always yielding the expected result, it's probably better to convert to integers and divide just before using. Like so:
function xys()
local x, y, s = SSxPOSA, SSyPOSA, SSsizeA
return coroutine.wrap(
function()
while x >= SSxPOSB and y >= SSyPOSB and s >= SSsizeB do
coroutine.yield(x/100,y/100,s/100)
x = x - 10
y = y - 50
s = s - 80
end
end)
end
SSxPOSA = 0
SSxPOSB = -1200
SSyPOSA = 0
SSyPOSB = -655
SSsizeA = 100
SSsizeB = 20
for x,y,s in xys() do
print(x,y,s)
--Object1X(x)
--Object1Y(y)
--Object1Scale(s)
end
You can also do it without coroutines:
function xys()
local x, y, s = SSxPOSA, SSyPOSA, SSsizeA
return function()
if x < SSxPOSB or y < SSyPOSB or s < SSsizeB then return end
local xx, yy, ss = x/100, y/100, s/100
x = x - 10
y = y - 50
s = s - 80
return xx,yy,ss
end
end
Can the following code be refactored to be more concise or more clear? I have also attached a picture below to help illustrate what I have in mind.
local playerAreaPos = {
{x = playerPos.x, y = playerPos.y - 1, z = playerPos.z}, -- NORTH
{x = playerPos.x, y = playerPos.y + 1, z = playerPos.z}, -- SOUTH
{x = playerPos.x + 1, y = playerPos.y, z = playerPos.z}, -- EAST
{x = playerPos.x - 1, y = playerPos.y, z = playerPos.z}, -- WEST
{x = playerPos.x - 1, y = playerPos.y + 1, z = playerPos.z}, -- SOUTH-WEST
{x = playerPos.x + 1, y = playerPos.y + 1, z = playerPos.z}, -- SOUTH-EAST
{x = playerPos.x - 1, y = playerPos.y - 1, z = playerPos.z}, -- NORTH-WEST
{x = playerPos.x + 1, y = playerPos.y - 1, z = playerPos.z} -- NORTH-EAST
}
local posTable = {
{x = playerPos.x, y = playerPos.y - 2, z = playerPos.z, dir = "NORTH"},
{x = playerPos.x, y = playerPos.y - 3, z = playerPos.z, dir = "NORTH"},
{x = playerPos.x, y = playerPos.y + 2, z = playerPos.z, dir = "SOUTH"},
{x = playerPos.x, y = playerPos.y + 3, z = playerPos.z, dir = "SOUTH"},
{x = playerPos.x + 2, y = playerPos.y, z = playerPos.z, dir = "EAST"},
{x = playerPos.x + 3, y = playerPos.y, z = playerPos.z, dir = "EAST"},
{x = playerPos.x - 2, y = playerPos.y, z = playerPos.z, dir = "WEST"},
{x = playerPos.x - 3, y = playerPos.y, z = playerPos.z, dir = "WEST"},
{x = playerPos.x - 2, y = playerPos.y - 2, z = playerPos.z, dir = "NORTH_WEST"},
{x = playerPos.x - 3, y = playerPos.y - 3, z = playerPos.z, dir = "NORTH_WEST"},
{x = playerPos.x + 2, y = playerPos.y - 2, z = playerPos.z, dir = "NORTH_EAST"},
{x = playerPos.x + 3, y = playerPos.y - 3, z = playerPos.z, dir = "NORTH_EAST"},
{x = playerPos.x - 2, y = playerPos.y + 2, z = playerPos.z, dir = "SOUTH_WEST"},
{x = playerPos.x - 3, y = playerPos.y + 3, z = playerPos.z, dir = "SOUTH_WEST"},
{x = playerPos.x + 2, y = playerPos.y + 2, z = playerPos.z, dir = "SOUTH_EAST"},
{x = playerPos.x + 3, y = playerPos.y + 3, z = playerPos.z, dir = "SOUTH_EAST"}
}
for i = 1, #posTable do
if targetPos == Position(posTable[i]) then
if posTable[i].dir == "NORTH_EAST" then
print("TELEPORT TO: ", playerAreaPos[8].x, playerAreaPos[8].y)
elseif posTable[i].dir == "NORTH_WEST" then
print("TELEPORT TO: ", playerAreaPos[7].x, playerAreaPos[7].y)
elseif posTable[i].dir == "NORTH" then
print("TELEPORT TO: ", playerAreaPos[1].x, playerAreaPos[1].y)
elseif posTable[i].dir == "SOUTH_WEST" then
print("TELEPORT TO: ", playerAreaPos[5].x, playerAreaPos[5].y)
elseif posTable[i].dir == "SOUTH_EAST" then
print("TELEPORT TO: ", playerAreaPos[6].x, playerAreaPos[6].y)
elseif posTable[i].dir == "SOUTH" then
print("TELEPORT TO: ", playerAreaPos[2].x, playerAreaPos[2].y)
elseif posTable[i].dir == "EAST" then
print("TELEPORT TO: ", playerAreaPos[3].x, playerAreaPos[3].y)
elseif posTable[i].dir == "WEST" then
print("TELEPORT TO: ", playerAreaPos[4].x, playerAreaPos[4].y)
end
end
end
The aim of this function is to teleport enemies from posTable to playerAreaPos while ensuring they teleport within the corresponding line, which means if they are 3 squares north from main character they will be teleported to 1 square north of main character
local enemyPos = {x = 11, y = 22, z = 33}
local playerPos = {x = 10, y = 20, z = 30}
local beam_length = 3
if enemyPos.z == playerPos.z then
local dx = enemyPos.x - playerPos.x
local dy = enemyPos.y - playerPos.y
local ax, ay = math.abs(dx), math.abs(dy)
local len_max, len_min = math.max(ax, ay), math.min(ax, ay)
if len_max >= 2 and len_max <= beam_length and len_min % len_max == 0 then
print("TELEPORT TO: ", playerPos.x + dx / len_max, playerPos.y + dy / len_max)
end
end
There's a many way to implementation your question but I'm going try to use some math and after I'm going do some considerations about them.
Look at the next diagram there's a minimum distance between our hero and enemy when enemy fall into range it'll be teleport to hero's radius and after, foe can not teleport unless our hero throw it far its radius.
When these consideration, I made this implementation
-- returns math functions as local functions
local deg = math.deg
local sin = math.sin
local cos = math.cos
local atan2 = math.atan2
-- returns the distance between two points
local lengthOf = function ( dots )
local dx, dy = dots.x[2]-dots.x[1], dots.y[2]-dots.y[1]
return (dx*dx + dy*dy)^.5
end
-- returns the degrees between two points
-- note: 0 degrees is 'east'
local angleBetweenPoints = function ( dots )
local x, y = dots.x[2]-dots.x[1], dots.y[2]-dots.y[1]
local radian = atan2(x, y)
local angle = deg(radian)
angle = angle < 0 and (360 + angle) or angle
return angle
end
--config your hero
local hero = {}
hero.posX, hero.posY = 0, 0
hero.radius = 10
-- config enemy
local foe = {}
foe.posX, foe.posY = 0, 18
foe.radius = 8
foe.theta = 0
foe.teleported = false
foe.distToHero = 18
foe.points = {}
foe.curDist = 0
-- this part will be a sort like frame
foe.points = {x={hero.posX,foe.posX}, y={hero.posY,foe.posY}}
foe.curDist = lengthOf( foe.points )
if foe.distToHero<=foe.curDist and not foe.teleported then
foe.theta = angleBetweenPoints ( foe.points )
foe.posX = hero.radius*sin( foe.theta ) -- yes it's reverse
foe.posY = hero.radius*cos( foe.theta ) -- yes it's reverse
foe.teleported = true
else
foe.teleported = false -- if enemy is hit far of the hero
end
print(foe.posX,foe.posY)
-- printed output: 0, 10
The previous implementation, require a lot calculation if you put a lot foes on the landscape my suggestion is use C API or Box2D this last use a sensor fixture when a collision occur and is very useful for this sort situations. Currently there's many Lua SDK with these features so you can kickstart.