Contest 37: The Balancing Act

Online C++ programming contests.

Moderators: Darobat, RecursiveS, Dante Shamest, Bugdude, Wizard, raimo

Postby Guest » Fri Jun 25, 2004 8:06 am

i thought we were :) especially with the wind else how could you track the balls current speed,

before the wind mine was lasting over 30 mins, now (with the wind) it dies after a few seconds, gona have another go at it somethime.
Guest
 

Postby Animatronic » Fri Jun 25, 2004 8:07 am

-- doh not logged in --
Animatronic
 
Posts: 90
Joined: Wed Jun 23, 2004 9:08 pm

Postby Ryan » Fri Jun 25, 2004 8:11 am

Alvaro wrote:Are we allowed to use static variables? I think the contest is a lot more interesting if we are.

I had intended that, but I forgot to explicitly state that. Thank you for addressing it. The original rules are now updated.
Ryan
Moderator
 
Posts: 323
Joined: Sat Jun 12, 2004 1:34 pm

Postby Zen » Sun Jun 27, 2004 10:46 am

Ok, I think I'll give it a try anyway...

My record is ca. 800 ticks with static variabels.. (But that was with some luck. Normally I get 400 :? )

I guess I need to do some more work, but I have kinda little time. (going to Itali tomorrow)

Can I access all global variabels? (Not that it matters all that much)

I guess I'm allowed to create additional functions to use within the control function? (Not that this matters much either)
User avatar
Zen
 
Posts: 1088
Joined: Wed Sep 24, 2003 1:41 am
Location: Norway

Postby Ryan » Sun Jun 27, 2004 11:46 am

Zen wrote:Can I access all global variabels? (Not that it matters all that much)

You can access global variables you declare. You cannot access any variables or functions defined in the main part of the program.

Zen wrote:I guess I'm allowed to create additional functions to use within the control function? (Not that this matters much either)

Sure. Classes, functions, variables, whatever.
Ryan
Moderator
 
Posts: 323
Joined: Sat Jun 12, 2004 1:34 pm

Postby Alvaro » Mon Jun 28, 2004 10:11 pm

In order to tune your function, you can simplify the program a lot and just count the average number of ticks that a function survives, without graphics or any other distractions.

Code: Select all
#include <math.h>
#include <stdlib.h>
#include "vector2d.hpp"

static const double PI = 3.1415926535897932384626433832795;

signed char control(Vector2D cartPos, Vector2D ballPos);

// Include your implementation here

struct Object
{
  Vector2D position;
  Vector2D oldPosition;

  virtual void step(double deltaTime) { }
  virtual void constrain() { }
};


struct MovableObject : Object
{
  double mass;
  static double gravity;

  void step(double deltaTime)
  {
    // newPos = 2*pos - oldPos + accel * deltaTime^2
    Vector2D result(0,0);
    accumulateForces(result);
    result *= (deltaTime*deltaTime/ mass);
    result += position;
    result += position;
    result -= oldPosition;

    oldPosition = position;
    position = result;
  }

  virtual void accumulateForces(Vector2D& result)=0;
};
double MovableObject::gravity = -9.8;


struct LineConstraint : Object
{
  MovableObject* left;
  MovableObject* right;
  double distance;
  double invmassLeft, invmassRight;

  LineConstraint(MovableObject* a, MovableObject* b, double dist)
  {
    left = a;
    right = b;
    distance = dist;
    invmassLeft = 1.0/left->mass;
    invmassRight = 1.0/right->mass;
  }

  void constrain()
  {
    Vector2D delta = right->position - left->position;
    double length = sqrt(delta.x*delta.x + delta.y*delta.y);
    double diff = (length-distance)/(length*(invmassLeft+invmassRight));
    left->position += delta*(invmassLeft*diff);
    right->position -= delta*(invmassRight*diff);
  }

};


struct Ball : MovableObject
{
  double radius;
  double windForce;

  Ball() : windForce(0.0) { }

  virtual void accumulateForces(Vector2D& result)
  {
    result.x += windForce;
    windForce = 0;
    result.y += gravity*mass;
  }

};


struct Cart : MovableObject
{
  static const double WIDTH;
  static const double HEIGHT;
  static const double FRICTION_COEFFICIENT;
  float externalForce;

  Cart()
  {
    externalForce = 0;
    position.x = 0;
    position.y = -1.0 + HEIGHT;
  }

  virtual void accumulateForces(Vector2D& result)
  {
    result.x += externalForce - (position.x - oldPosition.x)*FRICTION_COEFFICIENT;
    externalForce = 0;
  }

  void constrain()
  {
    position.y = -1.0 + HEIGHT;
  }

};
const double Cart::WIDTH = 0.12;
const double Cart::HEIGHT = 0.02;
const double Cart::FRICTION_COEFFICIENT = 0.1;


inline double frand(double min, double max)
{
  return ((double)rand())/RAND_MAX*(max-min)+min;
}




#include <vector>
#include <iostream>
using std::vector;
using std::cout;

namespace
{
  vector<Object*> objects;
  Cart cart;
  Ball ball;
  LineConstraint rod(&ball, &ball, 0); // this will change
  int tickCount=0;
  int gustCount=0;
  int ticksTillNextGust=-1;

  void initDynamics(double ballVelocity, double cartVelocity)
  {
    cart = Cart();
    cart.mass = 5;
    ball = Ball();
    ball.position.x = cart.position.x;
    ball.position.y = 0.8;
    ball.mass = 1;
    ball.radius = 0.02;
    rod = LineConstraint(&ball, &cart, ball.position.y - cart.position.y);

    objects.clear();
    objects.push_back(&cart);
    objects.push_back(&ball);
    objects.push_back(&rod);

    for(size_t i=0; i < objects.size(); ++i)
    {
      objects[i]->oldPosition = objects[i]->position;
    }

    cart.oldPosition.x += cartVelocity;
    ball.oldPosition.x += ballVelocity;
  }

  bool gameOver()
  {
    return (ball.position.y < cart.position.y) || (cart.position.x < -1) || (cart.position.x > 1);
  }
}




static const int TICK_MS = 50;
static const double TICK_SEC = TICK_MS/1000.0;

int tick(void)
{
  tickCount=0;
  gustCount=0;
  while(1){
    // query the controlling function and clamp it
    signed char force = control(cart.position, ball.position);
    if (force < -10) force = -10;
    else if (force > 10) force = 10;
    cart.externalForce = force*10.0;
   
    // determine wind
    if (ticksTillNextGust == 0)
      {
   ++gustCount;
   double scale = gustCount;
   ball.windForce = frand(-scale,+scale);
      }
    if (ticksTillNextGust <= 0)
      {
   ticksTillNextGust = rand()%(4000/TICK_MS);
      }
    --ticksTillNextGust;
   
   
    // dynamics step
    for(size_t i=0; i < objects.size(); ++i)
      objects[i]->step(TICK_SEC);
   
    // satisfy constraints
    for(int j=0; j < 32; ++j)
      for(size_t i=0; i < objects.size(); ++i)
   objects[i]->constrain();
   
    // check for game over condition
    ++tickCount;
    if (gameOver())
      return tickCount;
  }
}

int main()
{
  double sum=0;
  unsigned u;
  for(u=0;u<1000;++u){
    // setup dynamics
    srand(u);
    static const double VEL_SCALE = 0.01;
    initDynamics(frand(-VEL_SCALE,VEL_SCALE), frand(-VEL_SCALE,VEL_SCALE));
    sum+=tick();
  }
  std::cout << (sum/u) << std::endl;
  return 0;
}

User avatar
Alvaro
Moderator
 
Posts: 5185
Joined: Mon Sep 22, 2003 4:57 pm
Location: NY, USA

Postby Dudi Hatotah » Tue Jun 29, 2004 4:41 pm

I have just sent my code for this contest.
Thanks to Alvaro's tuning code (thanks, Alvaro!), I tuned it up to about 1200 avarage ticks.

Good luck to everyone! :)
May the best code win! :)
User avatar
Dudi Hatotah
 
Posts: 222
Joined: Fri Oct 03, 2003 4:17 pm
Location: Micronesia, the island of Yap

Postby Alvaro » Tue Jun 29, 2004 4:58 pm

Dudi Hatotah wrote:I have just sent my code for this contest.
Thanks to Alvaro's tuning code (thanks, Alvaro!), I tuned it up to about 1200 avarage ticks.

You are welcome. I also got to about 1200 average (slightly less). I don't think you can do much better than that.

Good luck, everyone!
User avatar
Alvaro
Moderator
 
Posts: 5185
Joined: Mon Sep 22, 2003 4:57 pm
Location: NY, USA

Previous

Return to Contests

Who is online

Users browsing this forum: No registered users and 1 guest