# Python Colliding balls in a 2D box

#### Arman777

Gold Member
We have a 2D box (billiard table) which have size of Width = 600 and Height = 300. We have two identical ball a radius of 20. Also the balls decelerate with a rate of 5 m/s^2. The problem is to find the position of the ball after 10 second. ( The balls may have collide)

Python:
    from math import sqrt, atan, sin, cos, pi, inf
from numpy import array

W = 600  # width of the table
H = 300  # height of the table
A = 5  # deceleration constant
dt = 0.1
ma = mb = 1

def collision_test(Xa, Ya, Xb, Yb):
if sqrt((Yb - Ya) ** 2 + (Xb - Xa)**2) <= 2 * radius:
return True

def dot_product(V1, V2):
return sum(V1 * V2)

def vec_magnitude(V1):
return sqrt(V1[0]**2 + V1[1]**2)

def after_collision_velocity(Va, Vb, Ra, Rb):
Va_new = Va - ((2 * mb * dot_product(Va - Vb, Ra - Rb)) /  ((ma + mb) * vec_magnitude(Ra - Rb)**2)) * (Ra - Rb)
Vb_new = Vb - ((2 * ma * dot_product(Vb - Va, Rb - Ra)) /  ((ma + mb) * vec_magnitude(Rb - Ra)**2)) * (Rb - Ra)
return Va_new, Vb_new

def check_reflection(R, angle):
R[1] += 2 * (radius - R[1])
angle *= -1
R = array([R[0], R[1]])
return R, angle
R[0] += 2 * (radius - R[0])
angle = pi - angle
R = array([R[0], R[1]])
return R, angle
if R[1] > H - radius:
R[1] += 2 * (H - radius - R[1])
angle *= -1
R = array([R[0], R[1]])
return R, angle
if R[0] > W - radius:
R[0] += 2 * (W - radius - R[0])
angle = pi - angle
R = array([R[0], R[1]])
return R, angle
else:
return R, angle

def motion(V, R, angle):
V_mag = vec_magnitude(V)
V_mag -= A * dt
Vx = V_mag * cos(angle)
Vy = V_mag * sin(angle)
R[0] += Vx * dt
R[1] += Vy * dt
V = array([Vx, Vy])
R = array([R[0], R[1]])
return V, R

for line in open("test1.txt", "r"):
t = 0
Xa, Ya, Xb, Yb, Vxa, Vya, Vxb, Vyb = [int(i) for i in (line.rstrip()).split(" ")]
Ra = array([Xa, Ya])
Rb = array([Xb, Yb])
Va = array([Vxa, Vya])
Vb = array([Vxb, Vyb])
angle_a = atan(Vya / Vxa)
angle_b = atan(Vyb / Vxb)
while t < 10:
Va, Ra =  motion(Va, Ra, angle_a)
Vb, Rb = motion(Vb, Rb, angle_b)
Ra, angle_a = check_reflection(Ra, angle_a)
Rb, angle_b = check_reflection(Rb, angle_b)
if collision_test(Xa, Ya, Xb, Yb) == True:
Va, Vb = after_collision_velocity(Va, Vb, Ra, Rb)
angle_a = atan(Va[1] / Va[0])
angle_b = atan(Vb[1] / Vb[0])
t += dt
print(Ra[0], Ra[1], Rb[0], Rb[1])

In file the data is 235 124 365 176 181 34 -34 -14 and answer should be approximately 399 104 106 62 but I get 480 147 426 169 I guess theres a logic problem somewhere.

Debug data for dt = 0.1

Code:
  0.1: 253 127 362 175
0.2: 271 131 358 173
0.3: 289 134 355 172
0.4: 307 138 352 171
0.5: 323 139 350 171
0.6: 329 129 359 183
0.7: 335 120 368 194
0.8: 340 110 377 206
0.9: 346 101 385 218
1.0: 352 91 394 229
1.1: 358 82 403 241
1.2: 363 73 411 252
1.3: 369 63 420 263
1.4: 375 54 429 275
1.5: 380 45 437 274
1.6: 386 35 446 263
1.7: 391 26 454 251
1.8: 397 23 463 240
1.9: 402 32 471 229
2.0: 408 41 479 218
2.1: 413 50 488 207
2.2: 419 59 496 196
2.3: 424 68 505 185
2.4: 429 76 513 174
2.5: 435 85 521 163
2.6: 440 94 529 152
2.7: 445 103 537 141
2.8: 451 111 546 131
2.9: 456 120 554 120
3.0: 461 129 562 109
3.1: 466 137 570 98
3.2: 471 146 578 88
3.3: 477 154 574 77
3.4: 482 163 566 67
3.5: 487 171 558 56
3.6: 492 179 550 46
3.7: 497 188 542 35
3.8: 502 196 535 25
3.9: 507 204 527 26
4.0: 512 212 519 36
4.1: 517 220 511 46
4.2: 522 228 503 56
4.3: 526 236 496 67
4.4: 531 244 488 77
4.5: 536 252 480 87
4.6: 541 260 473 97
4.7: 546 268 465 107
4.8: 550 276 458 117
4.9: 555 276 450 127
5.0: 560 268 443 137
5.1: 564 261 435 147
5.2: 569 253 428 156
5.3: 574 245 420 166
5.4: 578 238 413 176
5.5: 577 230 406 186
5.6: 573 223 398 195
5.7: 568 215 391 205
5.8: 564 208 384 215
5.9: 559 201 377 224
6.0: 555 193 369 234
6.1: 550 186 362 243
6.2: 546 179 355 253
6.3: 542 172 348 262
6.4: 537 165 341 271
6.5: 533 158 334 279
6.6: 529 150 327 270
6.7: 524 143 320 261
6.8: 520 136 313 252
6.9: 516 130 306 243
7.0: 512 123 299 233
7.1: 508 116 292 224
7.2: 504 109 285 215
7.3: 499 102 279 206
7.4: 495 96 272 197
7.5: 491 89 265 188
7.6: 487 82 258 180
7.7: 483 76 252 171
7.8: 479 69 245 162
7.9: 475 63 238 153
8.0: 472 56 232 144
8.1: 468 50 225 136
8.2: 464 43 219 127
8.3: 460 37 212 119
8.4: 456 31 206 110
8.5: 452 25 199 101
8.6: 449 22 193 93
8.7: 445 28 187 85
8.8: 441 34 180 76
8.9: 437 40 174 68
9.0: 434 46 168 59
9.1: 430 52 161 51
9.2: 427 58 155 43
9.3: 423 64 149 35
9.4: 419 70 143 27
9.5: 416 75 137 22
9.6: 412 81 131 30
9.7: 409 87 125 38
9.8: 406 93 118 46
9.9: 402 98 112 54
10.0: 399 104 106 62

#### Attachments

• 14.3 KB Views: 30
• 18.7 KB Views: 29
Last edited:
Related Programming and Computer Science News on Phys.org

#### jedishrfu

Mentor
The two pictures look wildly different. They don't have the same starting point checking either end of either track. In the original it looks like the orange ball starts at about 110,60 and the blueball at 400,100

Why not start the balls in the same place and then watch how their tracks differ from the original graph?

It could be as simple are not considering the balls radius when they collide ie using the collision point as the center of mass for one or both balls.

#### Arman777

Gold Member
I remember that I put the same initial values but maybe in the drawing part there could have be some mistake.
It could be as simple are not considering the balls radius when they collide ie using the collision point as the center of mass for one or both balls.
I dod not understand this part ...

#### jedishrfu

Mentor
When the balls collide its at their collision pt right? This point is not the position of either ball.

If I have two balls colliding on a one-dimensional number line at 10 and each ball has a 1 unit radius then ball 1 is located at 9 and ball 2 is located at 11 extend this notion to 2D. That's all I'm saying. Its a coding check for you to verify..

I think your chart shows that already so I think you're okay and I was just trying to think where things could go wrong in your calculations.

#### FactChecker

Gold Member
2018 Award

1) Even with correct logic, the results may be very sensitive to the exact point and angle of contact. Do you know that the $\Delta t = 0.1$ value is small enough for the accuracy needed? In fact, you may not be able to specify a fixed value for $\Delta t$. You might need to calculate intersection points and do the calculations at the exactly correct time of the impact. That would be an "event driven" simulation. Maybe you do that somewhere, but it is hard to tell.

2) Your code has a lack of comments as though you are charged $for every comment. Some comments in the code with explanations of calculations is very good when you are requesting help. 3) As @jedishrfu pointed out, you should make sure that your examples and plots start in the exact same state. Last edited: #### FactChecker Science Advisor Gold Member 2018 Award This may be the type of simulation that is impossible to make it accurately duplicate a real example. Consider a collision of the two balls. Even the slightest change in the direction of travel can cause a significant change in the impact position and angle. No matter how small the initial error is, these errors accumulate and multiply with each impact until the simulation will have no similarity to the actual example. If there is no impact of the two balls, the simulation has a much better chance of reasonably duplicating the real example. Last edited: #### jedishrfu Mentor One other observation is that the wall bounces show rounded trajectories which indicates some elasticity in the balls which makes it even harder to simulate accurately. #### FactChecker Science Advisor Gold Member 2018 Award There is at least one obvious error in the simulation graph. There is an impact between the balls where the brown ball completely changes its direction but the blue one continues straight. That is wrong. That part of the code should be examined. #### Klystron Gold Member Two comments from skimming part of code and data. The condition checks on collisions appear to allow interpenetration of the radii of the balls. (or my poor reading of the code). For debug purposes at least, consider assigning function calls to a local variable before testing the return condition. Inline function calls look cool but when testing/debugging code I prefer examining the function return value before branching on condition, just in case. (JIC). #### Arman777 Gold Member This may be the type of simulation that is impossible to make it accurately duplicate a real example. Consider a collision of the two balls. Even the slightest change in the direction of travel can cause a significant change in the impact position and angle. These changes accumulate and multiply with each impact until the simulation will have no similarity to the actual example. If there is no impact of the two balls, the simulation has a much better chance of reasonably duplicating the real example. Well thats kind of happens in my code at small changes becomes big but I guess its due to algorithm implamentation or some of the rounding errors that happens during the calculation. 1) Even with correct logic, the results may be very sensitive to the exact point and angle of contact. Do you know that the Δt=0.1Δt=0.1\Delta t = 0.1 value is small enough for the accuracy needed? In fact, you may not be able to specify a fixed value for ΔtΔt\Delta t . You might need to calculate intersection points and do the calculations at the exactly correct time of the impact. That would be an "event driven" simulation. Maybe you do that somewhere, but it is hard to tell. Well if I decrease $dt$ the things get worse and my code does not work properly. (You can also try that). I am not sure how can I find the exact time of collusion. 2) Your code has a lack of comments as though you are charged$ for every comment. Some comments in the code with explanations of calculations is very good when you are requesting help.
Which part is hard to understand ? So I can explain in a better way that part of the code
3) As @jedishrfu pointed out, you should make sure that your examples and plots start in the exact same state.
I re-checked and I started them from the same point but I get same graphs. I dont know why that happens ?
One other observation is that the wall bounces show rounded trajectories which indicates some elasticity in the balls which makes it even harder to simulate accurately.
In which part, real one or my version ? they shouldnt actually have rounded trajectories after bouncing. I solved the similar problem without collision and I got it right. I can share that code if its needed

#### Arman777

Gold Member
The condition checks on collisions appear to allow interpenetration of the radii of the balls. (or my poor reading of the code).
Thats how collision condition should be right ? If the centers of the two balls are less then the 2 * radius of the balls it means they are collided.

I seperatly tested each function (not the motion and check_reflection) and they seem correct for the simple cases.

I discovered one of my errors and I fixed it..My new code looks like this.

Python:
from math import sqrt, atan, sin, cos, pi, inf
from numpy import array

W = 600  # width of the table
H = 300  # height of the table
A = 5  # decelration constant
dt = 0.1
ma = mb = 1 #masses of the particles a and b

def collision_test(Xa, Ya, Xb, Yb):
if sqrt((Yb - Ya) ** 2 + (Xb - Xa)**2) <= 2 * radius:
return True

def dot_product(V1, V2):
return sum(V1 * V2)

def vec_magnitude(V1):
return sqrt(V1[0]**2 + V1[1]**2)

def after_collision_velocity(Va, Vb, Ra, Rb):
''' the equation that produces the velocity of the objects after the collision'''
Va_new = Va - ((2 * mb * dot_product(Va - Vb, Ra - Rb)) /  ((ma + mb) * vec_magnitude(Ra - Rb)**2)) * (Ra - Rb)
Vb_new = Vb - ((2 * ma * dot_product(Vb - Va, Rb - Ra)) /  ((ma + mb) * vec_magnitude(Rb - Ra)**2)) * (Rb - Ra)
return Va_new, Vb_new

def check_reflection(R, angle):
'''checks reflection from the billiard table'''
R[1] += 2 * (radius - R[1])
angle *= -1
R = array([R[0], R[1]])
return R, angle
R[0] += 2 * (radius - R[0])
angle = pi - angle
R = array([R[0], R[1]])
return R, angle
if R[1] > H - radius:
R[1] += 2 * (H - radius - R[1])
angle *= -1
R = array([R[0], R[1]])
return R, angle
if R[0] > W - radius:
R[0] += 2 * (W - radius - R[0])
angle = pi - angle
R = array([R[0], R[1]])
return R, angle
else:
return R, angle

def motion(V, R, angle):
V_mag = vec_magnitude(V)
V_mag -= A * dt
Vx = V_mag * cos(angle)
Vy = V_mag * sin(angle)
R[0] += Vx * dt
R[1] += Vy * dt
V = array([Vx, Vy])
R = array([R[0], R[1]])
return V, R

for line in open("test1.txt", "r"):
t = 0
Xa, Ya, Xb, Yb, Vxa, Vya, Vxb, Vyb = [int(i) for i in (line.rstrip()).split(" ")]
Ra = array([Xa, Ya]) #position vector of the ball a
Rb = array([Xb, Yb]) #position vector of the ball b
Va = array([Vxa, Vya]) #Velocity vector of a
Vb = array([Vxb, Vyb]) #Velocity vector of b
angle_a = atan(Vya / Vxa)
angle_b = atan(Vyb / Vxb)
while t < 10:
(Va, Ra), (Vb, Rb) =  motion(Va, Ra, angle_a), motion(Vb, Rb, angle_b)
(Ra, angle_a), (Rb, angle_b) = check_reflection(Ra, angle_a), check_reflection(Rb, angle_b)
print(Ra[0], Ra[1], Rb[0], Rb[1])
if collision_test(Ra[0], Ra[1], Rb[0], Rb[1]) == True:
Va, Vb = after_collision_velocity(Va, Vb, Ra, Rb)
angle_a, angle_b = atan(Va[1] / Va[0]), atan(Vb[1] / Vb[0])
t += dt

#### Attachments

• 14.9 KB Views: 18

#### jedishrfu

Mentor
Well thats kind of happens in my code at small changes becomes big but I guess its due to algorithm implamentation or some of the rounding errors that happens during the calculation.

Well if I decrease $dt$ the things get worse and my code does not work properly. (You can also try that). I am not sure how can I find the exact time of collusion.

Which part is hard to understand ? So I can explain in a better way that part of the code

I re-checked and I started them from the same point but I get same graphs. I dont know why that happens ?

In which part, real one or my version ? they shouldnt actually have rounded trajectories after bouncing. I solved the similar problem without collision and I got it right. I can share that code if its needed
Both versions show it, but now I'm thinking it may be due to your time step being too coarse.

In an ideal world, your ball trajectory should make a sharp angle each time there's a collision but the images show that a small deviation before going in a straight line. I guess this is because the collision occurred between two time steps.

#### FactChecker

Gold Member
2018 Award
Step 1: Correct the plots. I don't think that your plots look valid. Even the actual data plot has one ball changing direction for no apparent reason. You should get those corrected first so that you can see events that look like the simulation is wrong.
Step 2: Dump data. When you have a simulation where something might go wrong on frame 10 or 100 or 10,000, I like to dump as much data as possible to a file. Stuff your program with prints to a file. Then you can look at the plots to see strange behavior, go into the data file, find the lines that match the time of the bad behavior and examine the calculation results step-by-step.

#### Arman777

Gold Member
Even the actual data plot has one ball changing direction for no apparent reason. You should get those corrected first so that you can see events that look like the simulation is wrong.
I just copy and paste the data and draw it. If theres something wrong I dont think thats my fault.

I am trying something new. I understand which part is wrong and I ll try to fix it
Both versions show it, but now I'm thinking it may be due to your time step being too coarse.

In an ideal world, your ball trajectory should make a sharp angle each time there's a collision but the images show that a small deviation before going in a straight line. I guess this is because the collision occurred between two time steps.
I guess so. And I think this part of my code is what is wrong..

#### Klystron

Gold Member
 if collision_test(Ra[0], Ra[1], Rb[0], Rb[1]) == True: 
If the collision_test() function call returns a Boolean value, does the language require a comparison to True; or is the statement written this way for clarity?

Generally, in C-derived languages and most other programming languages that I have used, the simplest form would be (ignoring indentation)
If function_that_returns_boolean (arg1, arg2,...) # then do something

or, using a temporary Boolean variable for test purposes
 temp_boolean = function_that_returns_boolean (arg1, arg2,...) If temp_boolean # then...

I had intended to learn Python this Summer but have been delayed by other issues. I ask because 25+ years ago there was a raging discussion in the programming community about the preferred form for conditional branching somewhat analogous to PF "Quantum Interpretation" discussions. The consensus then was to use a form similar to the OP with explicit truth comparisons.

[EDIT: I should have said "Prior consensus seemed to be" to use the longer form.]

I will start another thread if this question detracts from troubleshooting effort. Thanks.

Last edited:

#### PeterDonis

Mentor
If the collision_test() function call returns a Boolean value, does the language require a comparison to True
No. In fact it doesn't require the comparison for any return value at all. Every Python object has a truth value even if it's not of the bool type. (Basically, None is false, False is false, empty strings and containers are false, and anything else is true unless it's an instance of a user-defined class that implements some custom behavior.)

The consensus then was to use a form similar to the OP with explicit truth comparisons.
In other languages this might be necessary (or might have been necessary 25 years ago), but in Python this is strongly discouraged. The idea of the if statement is that it is going to test a condition for truth or falsity, and as above, every Python object has a truth value already. There's no need to explicitly compare it to True.

#### Arman777

Gold Member
I re-write my code again. This time I fixed one of my functons. However my code still does not work properly. I dont know what to do now. I really dont. I guess its about something else since I checked my each function and they seem to work well.

Python:
from math import sqrt, atan, sin, cos, pi, inf
from numpy import array

W = 600  # width of the table
H = 300  # height of the table
R = 20  # the radius of the ball
A = 5  # decelration constant
dt = 0.01
ma = mb = 1  # masses of the particles a and b

def vec_magnitude(V1):
return sqrt(V1[0]**2 + V1[1]**2)

def collision_test(V1, V2):
if vec_magnitude(V1 - V2) < 2 * R:
return True

def dot_product(V1, V2):
return sum(V1 * V2)

def after_collision_velocity(Va, Vb, Ra, Rb):
''' the equation that produces the velocity of the objects after the collision'''
Va_new = Va - ((2 * mb * dot_product(Va - Vb, Ra - Rb)) /
((ma + mb) * vec_magnitude(Ra - Rb)**2)) * (Ra - Rb)
Vb_new = Vb - ((2 * ma * dot_product(Vb - Va, Rb - Ra)) /
((ma + mb) * vec_magnitude(Rb - Ra)**2)) * (Rb - Ra)
return Va_new, Vb_new

def check_reflection(P, V_mag, angle, V):
if P[1] < R:
P += array([0, 2 * (R - P[1])])
angle *= -1
return P, V_mag, angle, V
if P[0] < R:
P += array([2 * (R - P[0]), 0])
angle = pi - angle
return P, V_mag, angle,V
if P[1] > H - R:
P += array([0, 2 * (H - R - P[1])])
angle *= -1
return P, V_mag, angle, V
if P[0] > W - R:
P += array([2 * (W - R - P[0]), 0])
angle = pi - angle
return P, V_mag, angle, V
else:
V_mag -= A * dt
Vx = V_mag * cos(angle)
Vy = V_mag * sin(angle)
P += array([Vx * dt, 0])
P += array([0, Vy * dt])
V = array([Vx, Vy])
return P, V_mag, angle, V

for line in open("tex.txt", "r"):
t = 0
Xa, Ya, Xb, Yb, Vxa, Vya, Vxb, Vyb = [int(i) for i in (line.rstrip()).split(" ")]
Pa = array([Xa, Ya], dtype=float)  #position vector of ball a
Pb = array([Xb, Yb], dtype=float) #position vector of ball b
Va = array([Vxa, Vya], dtype=float) # velocity vector of ball a
Vb = array([Vxb, Vyb], dtype=float) # velocity vector of ball b
Va_mag = vec_magnitude(Va)
Vb_mag = vec_magnitude(Vb)
angle_a = atan(Vya / Vxa)
angle_b = atan(Vyb / Vxb)
while t <= 10:
Pa, Va_mag, angle_a, Va = check_reflection(Pa, Va_mag, angle_a, Va)
Pb, Vb_mag, angle_b, Vb= check_reflection(Pb, Vb_mag, angle_b, Vb)
if collision_test == True:
Va, Vb = after_collision_velocity(Va, Vb, Pa, Pb)
Va_mag = vec_magnitude(Va)
Vb_mag = vec_magnitude(Vb)
angla_a = atan( Va[1] / Va[0] )
angle_b = atan( Vb[1] / Vb[0] )
t += dt
print(Pa[0], Pa[1], Pb[0], Pb[1])

#### jedishrfu

Mentor
This is the lonely life of the programmer ultimately you own the problem and you own the code and only you can fix it.

My approach would now be to annotate with print statements or using a stepping debugger to walk through step by step and let the computer do the hard work and you review it and decide where it went wrong. Sometimes this takes an inordinate amount of time and sometimes you get an epiphany and see the gotcha in your code.

#### Arman777

Gold Member
This is the lonely life of the programmer ultimately you own the problem and you own the code and only you can fix it.

My approach would now be to annotate with print statements or using a stepping debugger to walk through step by step and let the computer do the hard work and you review it and decide where it went wrong. Sometimes this takes an inordinate amount of time and sometimes you get an epiphany and see the gotcha in your code.
I might try online debugger but numpy array will not work in there. I guess i ll just give up and try to solve later on. I can print the values but somehow the things seems okay

#### FactChecker

Gold Member
2018 Award
I might try online debugger but numpy array will not work in there. I guess i ll just give up and try to solve later on. I can print the values but somehow the things seems okay
One thing to change is from the function atan to atan2. Only atan2 keeps track of the quadrant correctly.

With the changes, do you have new data or a new plot? Your data and plot should include the exact initial values so that we know the initial conditions. A complete state would be the (x,y) positions, and (x,y) velocities. You should print all that at the very least. Looking at the latest plot in post #11, I don't understand the initial(?) slow velocity of one ball that then suddenly speeds up.

#### Arman777

Gold Member
One thing to change is from the function atan to atan2. Only atan2 keeps track of the quadrant correctly
I ll try that.

With the changes, do you have new data or a new plot? Your data and plot should include the exact initial values so that we know the initial conditions. A complete state would be the (x,y) positions, and (x,y) velocities. You should print all that at the very least. Looking at the latest plot in post #11, I don't understand the initial(?) slow velocity of one ball that then suddenly speeds up.
That picture was bad i agree. Well one of the objects has larger speed than the other. I ll post the graphs and data tomorrow (its late here). The inital conditions are the same as in the post #1.

#### Klystron

Gold Member
Line 75
1) The def statement (line 16) shows collision_test function with two arguments. No args in line 75. Even assuming global variables, the function call does not match the definition.

2) As PeterDonis explained above,
In fact it doesn't require the comparison for any return value at all. Every Python object has a truth value even if it's not of the bool type. (Basically, None is false, False is false, empty strings and containers are false, and anything else is true unless it's an instance of a user-defined class that implements some custom behavior.)
Have you tested this condition? Should not line 75 read
if collision_test (arg1, arg2)

#### FactChecker

Gold Member
2018 Award
Line 75
1) The def statement (line 16) shows collision_test function with two arguments. No args in line 75. Even assuming global variables, the function call does not match the definition.
I am surprised that it compiles with this mistake.

#### DavidSnider

Gold Member
It will help to write unit tests for each of your functions before attempting to debug the program as a whole.

#### FactChecker

Gold Member
2018 Award
This is the lonely life of the programmer ultimately you own the problem and you own the code and only you can fix it.

My approach would now be to annotate with print statements or using a stepping debugger to walk through step by step and let the computer do the hard work and you review it and decide where it went wrong. Sometimes this takes an inordinate amount of time and sometimes you get an epiphany and see the gotcha in your code.
It's my experience that it is possible to stare at code for a long, long time without spotting a simple error. The real trick in debugging is to develop techniques that allow one to narrow down to the specific location of the problem. It may take much less time to stuff a lot of prints into code than it does to find a bug by staring at code.
But before you do that, please put it into a good interpreter/compiler and eliminate all warnings.

"Colliding balls in a 2D box"

### Physics Forums Values

We Value Quality
• Topics based on mainstream science
• Proper English grammar and spelling
We Value Civility
• Positive and compassionate attitudes
• Patience while debating
We Value Productivity
• Disciplined to remain on-topic
• Recognition of own weaknesses
• Solo and co-op problem solving