Using a 1D array on a 2D array to calculate movement

Hello! I'm a first-year CS student and no this isn't homework help, this is personal project help for a project just for fun. So I've been attempting to recreate the basic javascript snake game, with walls, a fruit, and a regular snake. I have everything down, except for the snake. I have my movement loop and everything set up, but my snake doesn't grow past 1 when it picks up fruit.

I've worked with my professor on this a bit, but it's hard to understand what he means sometimes and he isn't all that much help. My professor has his own SSDL class which is used for basic things such as drawing images on screen, circles, boxes, etc. I'm going to post my code but please try to overlook that SSDL stuff, the main issue is in my moveSnake function, at least I think.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#include "SSDL.h"
#include <ctime>
#include <conio.h>

struct Location { int row_, clm_; };
enum			{ UP = 0, LEFT = 1, DOWN = 2, RIGHT = 3 };
enum	Items	{ WALL = 4, EMPTY = 5, TAIL = 6, HEAD = 7, FRUIT = 8 };
enum			{ ROWS = 25, CLMS = 25, VELO = 100, BOX = 20, BOXxy = 21 };

//initialize
void initialize(Items Board[ROWS][CLMS], int cRow, int cClm, Location Snake[], int& snakeLength);
//display
void display(Items Board[ROWS][CLMS], int cRow, int cClm, int tail, Location Snake[], int& snakeLength);
//generate candy
int candy();
// set/change direction
void changeDirection(char key, int tail, int& direction);
// move snake
void move(Items Board[ROWS][CLMS], int tail, Location Snake[], int snakeLength, int& direction);
// check for fruit
bool isFruit(Items Board[ROWS][CLMS], int cRow, int cClm, Location Snake[]);
	
int main(int argc, char** argv)
{
	SSDL_SetWindowSize(503,503);
	srand(time(nullptr));

	int direction = -1;

	int candyRow = candy(); // initial candy's
	int candyClm = candy();

	char key;

	int candyNum = 0;								// candy/score starts at 0
	int tail = 0;									// tail starts at 0


	Items Board[ROWS][CLMS];
	constexpr int MAXSNAKE = 256;
	Location Snake[MAXSNAKE];
	int snakeLength = 1;

	initialize(Board, candyRow, candyClm, Snake, snakeLength);			// initialize the board

	display(Board, candyRow, candyClm, tail, Snake, snakeLength);				// display the board


	SSDL_SetFramesPerSecond(60);

	while (SSDL_IsNextFrame())
	{
		SSDL_DefaultEventHandler();

		//*** DISPLAY THINGS ***
		SSDL_RenderClear();    //first, erase previous frame
		display(Board, candyRow, candyClm, tail, Snake, snakeLength);
		if (SSDL_IsKeyPressed('a'))
		{
			key = 'a';
			changeDirection(key, tail, direction);
		}
		if (SSDL_IsKeyPressed('w'))
		{
			key = 'w';
			changeDirection(key, tail, direction);
		}
		if (SSDL_IsKeyPressed('s'))
		{
			key = 's';
			changeDirection(key, tail, direction);
		}
		if (SSDL_IsKeyPressed('d'))
		{
			key = 'd';
			changeDirection(key, tail, direction);
		}


		//*** UPDATE  THINGS ***
		move(Board, tail, Snake, snakeLength, direction);							// this only moves the head
		if (isFruit(Board, candyRow, candyClm, Snake) == true)		// cehck if head goes over fruit, if so, add to tail and score
		{
			candyNum = candyNum + 1;
			candyRow = candy();
			candyClm = candy();
			tail++;
			snakeLength = snakeLength + 1;
			// next part of the snake, needs to be equal to previous part


		}
		// given by professor
		//Snake[snakeLength + 1] = Snake[snakeLength - 2];
		// snake[1] = 1, 1
		// goes down
		// snake[1] = 1, 2
		// snake[1] = 1,3
		//tail = snake[1] = 1,2

	}

	/*
		Maybe like this
		[][][][][][][][][][][][][]
		[]==--------------------[]
		[]-=--------------------[]
		[]----------------+-----[]
		[]----------------------[]
		[]----------------------[]
		[]----------------------[]
		[]----------------------[]
		[][][][][][][][][][][][][]
		= is the snake head
		+ is candy
		[] is wall

	*/
	return 0;
}

void initialize(Items Board[ROWS][CLMS], int cRow, int cClm, Location Snake[], int& snakeLength)
{
	for (int i = 0; i < ROWS; ++i)
	{
		for (int j = 0; j < CLMS; ++j)
		{
			if (i == 0 || i == 23)
			{
				Board[i][j] = WALL;
			}
			if (j == 0 || j == 23)
			{
				Board[i][j] = WALL;
			}
			if (i != 0 && j != 0 && i != 23 && j != 23)
			{
				Board[i][j] = EMPTY;
			}
		}
	}
	Snake[0] = { 1,1 }; snakeLength = 1;
	Snake[300] = { cRow, cClm }; // not sure what to do here for the snake[]
	Board[cRow][cClm] = FRUIT;
}

void display(Items Board[ROWS][CLMS], int cRow, int cClm, int tail, Location Snake[], int& snakeLength)
{								// this function should work fine.
	SSDL_SetCursor(250, 30);
	sout << "Score:" << tail;
	for (int i = 0; i < 25; i++)
	{
		SSDL_RenderDrawRect(BOXxy * i, 0, BOX, BOX);		// top boxes
		SSDL_RenderDrawRect(0, BOXxy * i, BOX, BOX);		// left boxes
		SSDL_RenderDrawRect(BOXxy * i, 483, BOX, BOX);		// bottom boxes
		SSDL_RenderDrawRect(483, BOXxy * i, BOX, BOX);		// right boxes
	}
	for (int i = 0; i < 25; i++)
	{
		for (int j = 0; j < 25; j++)
		{
			if (i == cRow && j == cClm)
			{
				SSDL_SetRenderDrawColor(RED);
				SSDL_RenderFillRect(cRow * BOXxy, cClm * BOXxy, BOX, BOX);		// draws the candy
				SSDL_SetRenderDrawColor(WHITE);
			}
		}
	}

	//Draw that snake!
	SSDL_SetRenderDrawColor(GREEN);
	for (int i = 0; i < snakeLength; ++i)
		SSDL_RenderFillRect(Snake[i].row_ * BOXxy, Snake[i].clm_ * BOXxy, BOX, BOX);
	SSDL_SetRenderDrawColor(WHITE);
} 

int candy()
{
	int num = rand() % 23;
	while (num == 0)
	{
		num = rand() % 23;
	}
	return num;
}

void changeDirection(char key, int tail, int& direction) 
{
	/*
	  W
	A + D
	  S

	  0
	1 + 3
	  2
	*/
	switch (key) 
	{ 
		case 'w':
			if (direction != 2) direction = 0;
			else if (tail == 0)  direction = 0;
			break;
		case 'a':
			if (direction != 3) direction = 1;
			else if (tail == 0)  direction = 1;
			break;
		case 's':
			if (direction != 0) direction = 2;
			else if (tail == 0)  direction = 2;
			break;
		case 'd':
			if (direction != 1) direction = 3;
			else if (tail == 0)  direction = 3;
			break;
	}
}

void move(Items Board[ROWS][CLMS], int tail, Location Snake[], int snakeLength, int& direction)
{
	SSDL_Delay(VELO);

	for (int i = 1; i < snakeLength; i++) // my professor gave me this loop but I'm not sure how it works or how I can fix it.
	{
		Snake[i] = Snake[i - 1];
	}
	switch (direction)
	{
	case UP: --Snake[0].clm_;
		break;
	case DOWN: ++Snake[0].clm_;
		break;
	case LEFT: --Snake[0].row_;
		break;
	case RIGHT: ++Snake[0].row_;
		break;
	}
}
bool isFruit(Items Board[ROWS][CLMS], int cRow, int cClm, Location Snake[])
{
	return Snake[0].row_ == cRow && Snake[0].clm_ == cClm;

}

Last edited on
> Snake[300] = { cRow, cClm }; // not sure what to do here for the snake[]
Well since your array is only 256 elements, writing to element 300 is a bad idea.

TBH, you need to take a step back and actually think about using some C++.

1
2
3
4
5
6
7
8
9
10
11
12
class Snake {
  private:
    struct coord { int x, int y };
    vector<coord> positions;
  public:
    Snake();  // make a 1-segment snake at position 0,0
    void eat(fruit);
    void move(direction);
    void draw();
    bool oroborous();  returns true if the snake eats itself
    // https://en.wikipedia.org/wiki/Ouroboros
};


In your first implementation, all you have is this class, and a main() as a console program.
The draw() method just uses cout.

1
2
3
4
5
int main ( ) {
    Snake snake; // default snake
    snake.move(RIGHT);
    snake.draw();
}

Compile and test, make sure it does what you expect.

When you're sufficiently confident that sufficiently complex cases of move + eat + move all do what you want, then you can recode the draw() function (and only that function) to use SSDL.
I appreciate the response, we aren't that far into learning C++ and we haven't learned vectors, or private and public classes yet, but I'll look into them and see if they can help my problem.
Topic archived. No new replies allowed.