views:

662

answers:

5

I have some homework for my school and I have to make a snake game, like Nokia's, in Delphi. I wonder which solution is the best. I want my snake be a class and the body is an array of points (parent class) or a linked list of points. What's the best? An array or a linked list?

+2  A: 

Here are some nice starting points for you...since i dont want to do your homework:

Pseudo Code for Snake Game to get an Idea

Thread with a german example...maybe this code helps you

If errors occur during your programming process feel free to open a new question.

bastianneu
I don't want anybody do my homework.. I just want advice about array or linkedlist..
bAN
But links are very interesting thanks a lot!
bAN
+5  A: 

A Linked list is better. (Each node can point to the previous and next node) It is easier to add nodes to the end of a linked list.

If you use an array you would either need to resize it or initialise it to the Maximum possible snake length to start with which can be wasteful on memory.

UPDATE This article talks about pointers in Delph and even suggests a simple Node definition delphi article

Andrew
And since this is homework, any exercise using pointers would be very helpful.
skamradt
@skamradt suggest you ask this as another question. You don't specify what language. I don't normally code in Pascal (Delphi) but I think unlike C++ it hides the use of pointers
Andrew
@Andrew, you can still use pointers in Delphi. They are not hidden, just implied for class instances.
skamradt
@skamradt - interesting - added a link to an article that may help. Delphi is more versatile than I realised (I normally code in C# or Java, C++ is becoming a more distant memory).
Andrew
Pascal (and hence Delphi) has always supported pointers. I remember writing linked lists back in 1984!
Gerry
+2  A: 

In Delphi, I'd use a TQueue, witch is defined in the Contnrs unit. You can "push" your new coordinate into it (snake head), and when your max snake size is reached you just have to call "pop" to free the snake tail.

lp := new(PPoint);
lp^.X := x;
lp^.X := y;

Body.Push(lp);    

if Body.count > iSnakeLength then
  Dispose(Body.Pop); // Free the last TCoord that is pop'ed.

Then, all you need to do is to draw what's in that TObjectQueue. To access the List of the TQueue, you have to expose the property List... To do that, simply define your snake body class like that;

  TSnakeBody = class(TObjectQueue)
  public
    property List;  //Expose the list
  end;
Pmax
Popping from a queue removes the *head* element, not the tail. And in what version of the snake game does the snake have a maximum length? It's supposed to keep growing — that's the game's challenge. If you need to get at the inner contents of a queue, then a queue is not the right data structure. Use an ordinary list instead. Also, I'm not sure that's valid syntax for `New`.
Rob Kennedy
A queue is a First-In-First-Out (FIFO) data structurecontrast with a stack that is Last-In-Fist-Out (LIFO)You are adding to your collection as Rob says not removing items.
Andrew
With Delphi's TQueue (Not a TStack), pop remove the first data entered. So you push the head, you pop the tail... In my snake version, you have to eat stuff with the snake to make it grow.Getting the inner contents of the queue is needed to draw the snake.
Pmax
A: 

I have a very old turbopascal snake program. It uses an array for the body.

const MaxBodyLength = 100;
type
  TSnake = record
    Dir : (nord,sud,est,oest);
    Head : tpoint;
    BodyLength : integer;
    Body : array[1..MaxBodyLength] of tPoint;
    Tail : tpoint;
  end;    
var
  Snake : TSnake;
  Fruit : tPoint;

and the code that moves the snake around...

procedure Slither;
var i : integer;
    npos,lpos : tPoint;
    hasEaten:boolean;
begin
  npos:=Snake.Head;
  lpos:=Snake.Tail;
  case Snake.dir of
    East  : inc(npos.x);
    West  : dec(npos.x);
    South : inc(npos.y);
    North : dec(npos.y);
  end;
  hasEaten:=(npos.x=fruit.x) and (npos.y=fruit.y);
  if hasEaten then 
    inc(Snake.BodyLength)
  else
    Snake.Tail:=Snake.Body[Snake.BodyLength];

  for i:=Snake.BodyLength downto 2 do
    Snake.Body[i]:=Snake.Body[i-1];
  Snake.Body[1]:=Snake.Head; 

  if not hasEaten then
    Snake.Head:=npos;

  writeP(idHead,Snake.Head);  
  writeP(idBody,Snake.Body[1]); 

  if not hasEaten then 
   begin
    writeP(idTail,Snake.Tail); 
    writeP(idResidual,lPos); 
   end;
  if hasEaten then 
    NewFruit;
end;
PA
I'm fairly certain that's not Turbo Pascal. The record's array length is defined by a member of the record? That's not allowed. Records have sizes fixed at compile time. You can't increment the BodyLength field and have the array get longer.
Rob Kennedy
Oooops you are right! Edited
PA
+4  A: 

A simple solution is to make an array[horizontal][vertical] of type, so that there is one item for each coordinate on the screen. Each type can be a snake-direction, food, poison, wall or empty. This means that you only need to remember the head and tail position of the snake, and the count of food and poisons, and the array describes how the screen looks like.

This removes the hassle of handling the snake's elements, and makes it easy to position new food or poison items on the screen, ensuring that you're not putting it into a place that is already occupied.

When you need to remove the tail element of the snake, get the direction of the tail using direction:=array[tailx,taily]; and then set array[tailx,taily]:=empty. Afterwards, update tailx and taily depending on the direction. That's it.

Lars D
Not bad idea...
bAN
http://compaspascal.blogspot.com/2009/12/snake-game-when-programming-isnt.html
Lars D