Page 1 of 1 [ 11 posts ] 

kalantir
Veteran
Veteran

User avatar

Joined: 25 Dec 2008
Gender: Male
Posts: 712
Location: Redmond, WA USA

14 May 2009, 4:36 pm

In C++, is there any way to switch user defined variables?

Code:
// Movement commands //
#define KEYMAP_WEST     0
#define KEYMAP_SOUTH    1
#define KEYMAP_NORTH    2
#define KEYMAP_EAST     3
#define KEYMAP_NW       4
#define KEYMAP_NE       5
#define KEYMAP_SW       6
#define KEYMAP_SE       7

#define KEYMAP_WAIT     8   // Key to wait in place //

#define NUM_COMMANDS     9


Code:
  switch(Input)
  {
    // Movement commands //
    case Player.Keys[KEYMAP_WEST]:
      --Player.Pos.X;
      break;
    case Player.Keys[KEYMAP_SOUTH]:
      ++Player.Pos.Y;
      break;
    case Player.Keys[KEYMAP_NORTH]:
      --Player.Pos.Y;
      break;
    case Player.Keys[KEYMAP_EAST]:
      ++Player.Pos.X;
      break;
    case Player.Keys[KEYMAP_NW]:
      --Player.Pos.Y;
      --Player.Pos.X;
      break;
    case Player.Keys[KEYMAP_NE]:
      --Player.Pos.Y;
      ++Player.Pos.X;
      break;
    case Player.Keys[KEYMAP_SW]:
      ++Player.Pos.Y;
      --Player.Pos.X;
      break;
    case Player.Keys[KEYMAP_SE]:
      ++Player.Pos.Y;
      ++Player.Pos.X;
      break;
    case Player.Keys[KEYMAP_WAIT]:
      break;
    default:
      mvwaddstr(stdscr, 0, 0, "Invalid Command!");
  }


Player.Keys[] is an int array.
The whole idea here is to allow players to remap the controls to whatever they want. I realize that I could do a crap ton of if-else statements instead of a switch but that looks rather ugly(and from my understanding it's also less efficient.... not that it really matters for an ASCII game, but still).

I've never before felt a need to do anything like this and so it's never been a problem but... I feel like there has to be a way. The exact compiler error is
Code:
g++ -c -Wall -Wextra -pedantic -ansi input.cpp
input.cpp: In function 'void Handler(int, Creature&)':
input.cpp:15: error: 'Player' cannot appear in a constant-expression
input.cpp:15: error: `.' cannot appear in a constant-expression
input.cpp:15: error: an array reference cannot appear in a constant-expression
input.cpp:17: error: 'Player' cannot appear in a constant-expression
input.cpp:17: error: `.' cannot appear in a constant-expression
input.cpp:17: error: an array reference cannot appear in a constant-expression
input.cpp:19: error: 'Player' cannot appear in a constant-expression
input.cpp:19: error: `.' cannot appear in a constant-expression
input.cpp:19: error: an array reference cannot appear in a constant-expression
input.cpp:21: error: 'Player' cannot appear in a constant-expression
input.cpp:21: error: `.' cannot appear in a constant-expression
input.cpp:21: error: an array reference cannot appear in a constant-expression
input.cpp:23: error: 'Player' cannot appear in a constant-expression
input.cpp:23: error: `.' cannot appear in a constant-expression
input.cpp:23: error: an array reference cannot appear in a constant-expression
input.cpp:25: error: 'Player' cannot appear in a constant-expression
input.cpp:25: error: `.' cannot appear in a constant-expression
input.cpp:25: error: an array reference cannot appear in a constant-expression
input.cpp:27: error: 'Player' cannot appear in a constant-expression
input.cpp:27: error: `.' cannot appear in a constant-expression
input.cpp:27: error: an array reference cannot appear in a constant-expression
input.cpp:29: error: 'Player' cannot appear in a constant-expression
input.cpp:29: error: `.' cannot appear in a constant-expression
input.cpp:29: error: an array reference cannot appear in a constant-expression
input.cpp:31: error: 'Player' cannot appear in a constant-expression
input.cpp:31: error: `.' cannot appear in a constant-expression
input.cpp:31: error: an array reference cannot appear in a constant-expression

I understand the compiler errors and know why they occur, I'm just trying to find some sort of workaround that doesn't sacrifice speed or readability.

EDIT:
Just in case further clarification is needed...
Player.Keys[] holds user defined variables that determine which key does what. For example, if Player.Keys[KEYMAP_WEST] == 'h' then hitting the h key should make them go west one square on the grid, etc..


_________________
2101729 Kalantir-Bar-Orc-Mal-Cha escaped the dungeon


Last edited by kalantir on 14 May 2009, 5:31 pm, edited 1 time in total.

CloudWalker
Veteran
Veteran

User avatar

Joined: 26 Mar 2009
Age: 34
Gender: Male
Posts: 711

14 May 2009, 5:30 pm

You know, the standard actually requires constants in the case expression. That's why gcc complained.

If I were you, I would reverse the array lookup, something like Player.Keys['h'] == KEYMAP_WEST.



kalantir
Veteran
Veteran

User avatar

Joined: 25 Dec 2008
Gender: Male
Posts: 712
Location: Redmond, WA USA

14 May 2009, 5:33 pm

CloudWalker wrote:
You know, the standard actually requires constants in the case expression. That's why gcc complained.

If I were you, I would reverse the array lookup, something like Player.Keys['h'] == KEYMAP_WEST.

I don't quite understand how that will allow me to switch it.
Also, that would require the array to be upwards of Keys[256] as opposed to the current size at Keys[9];
And I also don't think that would work, now that I think about it. So, you want me to set Player.Keys['h'] to 0?
EDIT: nvm, I understand your logic behind this now... but I still don't see how that'd allow me to switch it and I still think the way I'm doing it is better as it uses less memory and I won't even be using all the keys when I'm finished.


_________________
2101729 Kalantir-Bar-Orc-Mal-Cha escaped the dungeon


Last edited by kalantir on 14 May 2009, 6:02 pm, edited 1 time in total.

kalantir
Veteran
Veteran

User avatar

Joined: 25 Dec 2008
Gender: Male
Posts: 712
Location: Redmond, WA USA

14 May 2009, 5:48 pm

Ok, now here I'm trying to do something different. I've never tried anything like this so I don't even know if this is possible the way I'm trying to do it but I did

Code:
class Creature
{
  const int Keys[NUM_COMMANDS];
public:
  Creature(int *Keymap)
  {
    for(short i = 0; i < NUM_COMMANDS; i++)
      Keys[i] = Keymap[i];
  }
// Didn't copy the rest of Creature as it's not relevant //


And I also made my Handler function part of Creature since it was complaining about the '.' in Player.Keys so now I can call Keys directly.
But now the compiler generates this error
Code:
classes.h: In constructor 'Creature::Creature(int*)':
classes.h:27: error: uninitialized member 'Creature::Keys' with 'const' type 'const int [9]'

I clearly am initializing Keys, so I don't know what its bitching about.
I know its possible to initialize a const variable via a constructor but I'm apparently doing something wrong.

On another note... why does the switch care if its const or not? an int is an int... It still has a value which can be compared to another value... So I don't understand the logic behind it.


_________________
2101729 Kalantir-Bar-Orc-Mal-Cha escaped the dungeon


CloudWalker
Veteran
Veteran

User avatar

Joined: 26 Mar 2009
Age: 34
Gender: Male
Posts: 711

14 May 2009, 6:09 pm

kalantir wrote:
Also, that would require the array to be upwards of Keys[256] as opposed to the current size at Keys[9];


Yes, but you only need one instance if declared as static. I don't think that's too much a problem. You could also reduce the size further if you only allow certain keys, say 'a'..'z' and use an if ... then clause b/f the switch clause.

kalantir wrote:
And I also don't think that would work, now that I think about it. So, you want me to set Player.Keys['h'] to 0?


Yes.

kalantir wrote:
const int Keys[NUM_COMMANDS];


You have to supply the initial values at declaration time if you use const. And you can't change it afterwards either.



kalantir
Veteran
Veteran

User avatar

Joined: 25 Dec 2008
Gender: Male
Posts: 712
Location: Redmond, WA USA

14 May 2009, 6:14 pm

CloudWalker wrote:
You have to supply the initial values at declaration time if you use const. And you can't change it afterwards either.

With the sole exception being constructors. You can't initialize a member variable when you declare it.
EDIT: I really wish I would have payed attention back when I was taking CS120... I know they covered initialization of const member variables... I just can't remember for the life of me how they did it.

Quote:
Yes, but you only need one instance if declared as static. I don't think that's too much a problem. You could also reduce the size further if you only allow certain keys, say 'a'..'z' and use an if ... then clause b/f the switch clause

That doesn't leave room for arrow keys or the numpad, and I'll definiately want to be using capitol letters as well... I don't want to break away from standard roguelike controls. People(myself included) find it frustrating to have to relearn all the controls every time we pick up a new roguelike.


_________________
2101729 Kalantir-Bar-Orc-Mal-Cha escaped the dungeon


Last edited by kalantir on 14 May 2009, 6:35 pm, edited 1 time in total.

kalantir
Veteran
Veteran

User avatar

Joined: 25 Dec 2008
Gender: Male
Posts: 712
Location: Redmond, WA USA

14 May 2009, 6:20 pm

Just curious... How would one go about writing their own custom switch statement. This is not the only limitation of switch statements that bother me. For example, C# can switch strings. Why can't C++? I mean, I realize that I can associate a string with an enum and switch them in that manner, but its not quite the same. I'd love to write my own switch statement and add it to my tools.h that I use in all my projects.

I think I get it now... So you want me to do

Code:
switch(Keys[Input])
{
    case KEYMAP_WEST:
        --Pos.X;
        break;
    case KEYMAP_SOUTH:
        ++Pos.Y;
        breakl;
    // etc.. //
}

right? I don't know why I failed to see that before... Thanks for the help and sorry I was so blind and stubborn. I get this way when I'm up for over 24 hours at a time... Also, my code tends to be stupid(lol at wordfilter... it showed up as delayed when I called my code r-tarded) when I'm tired. I'll probably look at all this code I've written today when I've had more to rest and go "wtf was I even thinking here?"


_________________
2101729 Kalantir-Bar-Orc-Mal-Cha escaped the dungeon


CloudWalker
Veteran
Veteran

User avatar

Joined: 26 Mar 2009
Age: 34
Gender: Male
Posts: 711

14 May 2009, 7:18 pm

kalantir wrote:
I really wish I would have payed attention back when I was taking CS120... I know they covered initialization of const member variables... I just can't remember for the life of me how they did it.


You need to use member initialization list, but that won't work with array. So either change Keys to a class
Creature(someclass Keymap) : Keys(Keymap) {};

or change Keys to a pointer
const int* const Keys;
Creature(const int* const Keymap) : Keys(Keymap) {};


I think the reason why C++ switch is so limited is because it's meant to be fast. It's supposed to be implemented with a function pointer look up table. And since C++ only allow you to overload functions, you can't change the behavior of switch yourself. Well, maybe with something like a function with a pointer array and a comparison function pointer. Not likely to be faster than If..then though.



CloudWalker
Veteran
Veteran

User avatar

Joined: 26 Mar 2009
Age: 34
Gender: Male
Posts: 711

14 May 2009, 7:26 pm

kalantir wrote:
Code:
switch(Keys[Input])
{
    case KEYMAP_WEST:
        --Pos.X;
        break;
    case KEYMAP_SOUTH:
        ++Pos.Y;
        break;
    // etc.. //
}



Yeah, that's what I meant. Actually, I'm sorry I didn't put it clearer, I'm a bit lazy at typing.



Dussel
Veteran
Veteran

User avatar

Joined: 19 Jan 2009
Age: 60
Gender: Male
Posts: 1,788
Location: London (UK)

14 May 2009, 7:34 pm

kalantir wrote:
In C++, is there any way to switch user defined variables?



Not directly - you need to work with if-else-cascades:

Code:
if (Input ==  Player.Keys[KEYMAP_WEST])
      --Player.Pos.X;
  else if (Input == Player.Keys[KEYMAP_SOUTH])
      ++Player.Pos.Y;
  else if (Input == Player.Keys[KEYMAP_NORTH])
//etc.



lau
Veteran
Veteran

User avatar

Joined: 17 Jun 2006
Age: 75
Gender: Male
Posts: 9,619
Location: Somerset UK

15 May 2009, 7:16 am

Code:
#define INTRO(x) { if (Input ==  Player.Keys[(x)]) {
#define AGAIN(x) } else if (Input ==  Player.Keys[(x)]) {
#define ORTNI } )

while (we_get_a_nice_key(&Input))
INTRO(KEYMAP_WEST) --Player.Pos.X;
AGAIN(KEYMAP_SOUTH)  ++Player.Pos.Y; if (happy) wave_at_the_crowd();
AGAIN(KEYMAP_NORTH) .....
ORTNI


_________________
"Striking up conversations with strangers is an autistic person's version of extreme sports." Kamran Nazeer