Stringstream returns 0

I'm building a program that simulates a game of Snakes & Ladders. I have a text file representing a 10x10 board. Every square not containing a snake or ladder is represented by ___, and every other square is represented by a number representing the square to which the program is to go. When the program goes to advance to square #36, which has a ladder up to 37, the program terminates because it thinks its supposed to advance to square #0.

Here's my code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void advanceToNextSquare(char currentChar, int &currentSquareIndex)
{
    stringstream ss;
    ss << currentChar;
    int nextSquareChar;
    ss >> nextSquareChar;
    // If currentSquareChar is not integer
    if (ss.fail()) {
        // Set advanceNumber to random integer between 1 and 6.
        int advanceNumber = rand() % 6 + 1;
        currentSquareIndex += advanceNumber;
    }
    // Else, currentSquareChar is integer
    else
    {
        // Set currentSquareIndex to (nextSquareChar - 1)
        currentSquareIndex = nextSquareChar - 1;
    }
    
}


Here's my text file:

__ ___ ___ ___ ___ ___ ___ ___ 2 ___
___ ___ 20 ___ ___ ___ ___ ___ ___ ___
___ ___ ___ ___ ___ ___ 1 ___ 16 ___
___ ___ ___ ___ 36 37 ___ ___ ___ ___
___ ___ ___ ___ ___ ___ ___ ___ ___ ___
___ ___ ___ ___ ___ ___ ___ ___ ___ ___
___ ___ ___ ___ ___ ___ ___ ___ ___ ___
___ ___ ___ ___ ___ ___ ___ ___ ___ ___
___ ___ ___ ___ ___ ___ ___ ___ ___ ___
___ ___ ___ ___ ___ ___ ___ ___ 1 ___
I'm not sure exactly what you are doing with that stringstream, but you are not seeking back to the beginning in order to extract the value of nextSquareChar, so the extraction operator fails and nextSquareChar is set to zero (as per the current standard).

I think you need to rethink your board design. It should be an array of integers, not chars.

int board[10][10] = {0};

In snakes and ladders, the position "snakes" its way up the board. Starting with cell 1 in the lower-left-hand corner, increasing to the right, then up a row and increasing to the left, etc.

An invalid cell number would be 0; you can then use 0 to represent a blank cell (no snake or ladder originates at that cell).
So the above board definition is for a board with no snakes or ladders. Add snakes and ladders as you wish. The difference between a snake or a ladder is a position that turns into a row higher or lower than the current row. Take care not to create any board values that lead to the same row.

To help, you'll need a couple of functions to convert between a position and a row,column pair:

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
int row_col_to_position( int row, int col )
{
  row = 9 - row;  // Invert: Row now indexes from the bottom
  return (row % 2)
    ? ((row+1) * 10 - col)   // odd rows are right to left
    : (row * 10 + col) + 1;  // even rows are left to right
}

void position_to_row_col( int pos, int& row, int& col )
{
  pos -= 1;
  row = 9 - (pos / 10);
  col = pos % 10;
  col = (row % 2) ? col : (9 - col);
}

int position_to_row( int pos )
{
  int row, col;
  position_to_row_col( pos, row, col );
  return row;
}

int position_to_col( int pos )
{
  int row, col;
  position_to_row_col( pos, row, col );
  return col;
}

That was, frankly, the hardest part.

Now you can populate the snakes and ladders on the board by placing the indices:

    - positions that target a position whose row is LESS than the first is a LADDER
    - positions that target a position whose row is GREATER than the first is a SNAKE
    - positions that target a position whose row is the same as the first is illegal (and must be removed).

Next, you can implement a function to "move to" a specific square:

1
2
3
4
5
6
7
8
9
10
11
// Go to a specific square on the board.
// Follow any snakes or ladders.
// Return the final board position.
int go_to_position( int n )
{
  while (board[n] != 0)
  {
    n = board[n];
  }
  return n;
}

That was pretty easy, right? You can now update a player's position just as easily. You'll need a function to make sure that the results are always in [1,100]:

1
2
3
4
5
6
7
int add_to_position( int pos, int n )
{
  pos += n;
  if (pos <   1) pos = 1;
  if (pos > 100) pos = 100;
  return pos;
}

And:

 
  player_position[0] = go_to_position( add_to_position( player_position[0], /*whatever player rolls*/ ) );


The next issue is displaying your board properly. This takes a couple of useful functions:

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
// Draw the player "icons" for each player found at "pos".
// Returns true if any players are at "pos"
// Returns false if no players are at "pos"
bool display_players_at( int pos )
{
  std::string players;
  for (int p = 0; p < num_players; p++)
    if (player_positions[p] == pos)
      players += player_icon[p];

  if (!players.empty())
    cout << setw( 4 ) << players;

  return !players.empty();
}

// Draw the game board and players
void display_board()
{
  for (int row = 0; row < 10; row++)
  {
    for (int col = 0; col < 10; col++)
    {
      if (!display_player( row_col_to_position( row, col ) ))
      {
        if (board[row][col] < 0) cout << "___ ";
        else cout << setw( 3 ) << board[row][col] << " ";
      }
    }
    cout << "\n";
  }
}

Personally, I would display the board with a little more effort than this.
It is useful to get out a text editor and "draw" your board the way you want it to look. If each cell is displayed on more than one line, you might "display" the board by first drawing into a 2D array of characters and then drawing that array to the actual screen.

Well, that should be enough to get you going.

Good luck!
Topic archived. No new replies allowed.