Recent

Author Topic: [SOLVED] Best way to implement associative array/hashmap syntax  (Read 5297 times)

mrguzgog

  • Jr. Member
  • **
  • Posts: 71
I'd like to record the state of a number of (keyboard) keys when using SDL2. At the minute I'm doing this:

Code: [Select]
type TKeys = (KeyUp, KeyDown, KeyLeft);
var
keys: array [0..2] of boolean;
...
if keys[ord(KeyUp)] = true then...

It works but feels a little clunky. I'd prefer to set or retrieve the values using AA type syntax:

Code: Pascal  [Select]
  1. keys[KeyUp] := false;
  2. ...
  3. if keys[KeyUp] = true then...
  4.  

Declaring KeyUp etc as constants would work but would be error prone. Is there a different/better way to implement this? I found a couple of articles about simulating an AA using string lists but I'd imagine it wouldn't be great from a performance point of view.


« Last Edit: August 21, 2016, 01:59:16 pm by mrguzgog »

howardpc

  • Hero Member
  • *****
  • Posts: 3203
Re: Best way to implement associative array/hashmap
« Reply #1 on: August 20, 2016, 11:30:56 pm »
Declaring KeyUp etc as constants would work but would be error prone.

This has already been done for you. Instead of using your TKeys enum, use the LCLType unit.

Code: Pascal  [Select]
  1. uses LCLType;
  2. type
  3.   TV_Keys = array[VK_UNKNOWN..VK_HIGHESTVALUE] of boolean;      
  4.  
  5. var
  6.   keys: TV_Keys;
  7. ...
  8.   code that sets keys values
  9. ...
  10.   if TV_Keys[VK_UP] then ...

mrguzgog

  • Jr. Member
  • **
  • Posts: 71
Re: Best way to implement associative array/hashmap
« Reply #2 on: August 21, 2016, 10:27:47 am »
Thanks for that, however isn't LCL geared towards GUI apps rather than plain fp (+SDL in this case)? Looking at https://github.com/alrieckert/lazarus/blob/master/lcl/lcltype.pp, VK_HIGHESTVALUE is $FFFF which means I'll have a 64K array which has to be read and written very frequently so not ideal :D On reflection I wouldn't be handling more than a dozen or so keys at most so declaring my own constants might be the way to go.

howardpc

  • Hero Member
  • *****
  • Posts: 3203
Re: Best way to implement associative array/hashmap
« Reply #3 on: August 21, 2016, 10:53:43 am »
If you know in advance that certain keys will never be encountered obviously you would declare an array range to suit the actual values, rather than waste memory on key ranges that are never used.

But the point is, if you use the LCL and OnKeyDown etc. you will need to use (or re-interpret) the predeclared values of VK_xxx. So why not use them from the outset rather than declare your own different enum? If you don't use the LCL, then the VK_ constants are probably less relevant, though they are based on the widely used Windows API.

How do you get the keycodes of the keys pressed by your program's users?

Leledumbo

  • Hero Member
  • *****
  • Posts: 8114
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Best way to implement associative array/hashmap
« Reply #4 on: August 21, 2016, 11:20:40 am »
Code: Pascal  [Select]
  1. type
  2.   TKeys = (KeyUp, KeyDown, KeyLeft);
  3. var
  4.   keys: array [Low(TKeys) .. High(TKeys)] of boolean;
  5.  

Basile-B

  • Sr. Member
  • ****
  • Posts: 457
Re: Best way to implement associative array/hashmap
« Reply #5 on: August 21, 2016, 11:46:45 am »
Code: Pascal  [Select]
  1. type
  2.   TKeys = (KeyUp, KeyDown, KeyLeft);
  3. var
  4.   keys: array [Low(TKeys) .. High(TKeys)] of boolean;
  5.  

Code: Pascal  [Select]
  1. type
  2.   TKeys = (KeyUp, KeyDown, KeyLeft);
  3. var
  4.   keys: array [TKeys] of boolean;
  5.  

Or use a set of TKeys, it will fit in 1 byte while the array takes 3...
« Last Edit: August 21, 2016, 11:48:47 am by BBasile »

Thaddy

  • Hero Member
  • *****
  • Posts: 9293
Re: Best way to implement associative array/hashmap
« Reply #6 on: August 21, 2016, 12:23:28 pm »
Code: Pascal  [Select]
  1. TGameKeys = bitpacked record
  2.   KeyUp, KeyDown, KeyLeft, KeyRight, KeyCtrl, KeyAlt, KeySpace, KeyEsc: Boolean;
  3. end;
« Last Edit: August 21, 2016, 12:25:38 pm by Thaddy »
also related to equus asinus.

mrguzgog

  • Jr. Member
  • **
  • Posts: 71
Re: Best way to implement associative array/hashmap
« Reply #7 on: August 21, 2016, 12:44:25 pm »
How do you get the keycodes of the keys pressed by your program's users?

They're coming from the SDL event queue. SDL has constants declared for the scancodes, the virtual keycodes, key names etc - I'm using these but I'd like a simple way to store and access the key states.

@BBasile, Leledumbo: Thanks for that information although it doesn't allow access in the manner of an associated array.

@Thaddy: That's neat, assuming I can use for..in... on such a record to conveniently 'reset' all the values to false when required I could then do
Code: Pascal  [Select]
  1. var gameKeys: TGameKeys;
  2. ...
  3. if gameKeys.KeyUp = true then ...
  4.  

Which is pretty much what I was aiming for. I'll try this later!

Leledumbo

  • Hero Member
  • *****
  • Posts: 8114
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Best way to implement associative array/hashmap
« Reply #8 on: August 21, 2016, 01:29:30 pm »
@BBasile, Leledumbo: Thanks for that information although it doesn't allow access in the manner of an associated array.
It will, this is what you want, right?
Code: Pascal  [Select]
  1. keys[KeyUp] := false;
  2. ...
  3. if keys[KeyUp] = true then...
  4.  

P.S.:
remove = true, Pascal treats boolean as boolean, unlike in most other languages where everything else can be boolean and must be explicitly compared with boolean literal.

mrguzgog

  • Jr. Member
  • **
  • Posts: 71
Re: Best way to implement associative array/hashmap
« Reply #9 on: August 21, 2016, 01:58:10 pm »
It will, this is what you want, right?
Code: Pascal  [Select]
  1. keys[KeyUp] := false;
  2. ...
  3. if keys[KeyUp] = true then...
  4.  

Ooops, you're right and I just realised why I couldn't get it to work first time around -

1 I was defining the array using numeric indices (rather than low() and high() of the type, although I'm not sure that really matters)
2 I was trying to iterate over it using an integer in the for loop rather than a variable of type TKeys  :-[

Quote
P.S.remove = true, Pascal treats boolean as boolean, unlike in most other languages where everything else can be boolean and must be explicitly compared with boolean literal.
I've been tripped up so many times so far by omitting the '=true' that I just type it as a matter of course now! Thanks for the tip, the implementation is logical after all.