LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   Bash Random Keys (http://www.linuxquestions.org/questions/programming-9/bash-random-keys-4175473675/)

Lucien Lachance 08-16-2013 08:19 PM

Bash Random Keys
 
I've declared an associative array in bash and I need to be able to assign a random key to a variable called opponent. In Python, I can do this like so:
Code:

# /usr/bin/env python

 moves = [('r', "rock"), ('p', "paper"), ('s', "scissor")]

opponent = random.choice(moves)[0]

How can I accomplish this with bash?

PTrenholme 08-16-2013 11:33 PM

Note the use of the ${!<var_name>} in the code below
Code:

#!/bin/bash
random_move()
{
  local -i k=$(shuf -i 1-$# -n 1)
  echo ${!k}
}
####
declare -A moves
moves=(['r']="rock" ['p']="paper" ['s']="scissors")
for ((i=0;i<10;++i))
do
  key=$(random_move ${!moves[@]})
  echo key=${key}
  echo "move ${i} = ${moves[${key}]}"
done

Which produces
Code:

$ ./lucian
key=p
move 0 = paper
key=s
move 1 = scissors
key=r
move 2 = rock
key=s
move 3 = scissors
key=s
move 4 = scissors
key=s
move 5 = scissors
key=p
move 6 = paper
key=p
move 7 = paper
key=p
move 8 = paper
key=s
move 9 = scissors


Lucien Lachance 08-17-2013 11:40 AM

Hmm, is there perhaps another of doing this without shuf? I don't have that command unfortunately.

mina86 08-18-2013 09:17 AM

Bash has a $RANDOM variable which produces a random number every time it is referenced, so:
Code:

moves=(rock paper scissors)
echo "${moves[$(($RANDOM % ${#moves[@]}))]}"

But since it's not in POSIX, do not put “#!/bin/sh” at the beginning of your script.

Lucien Lachance 08-18-2013 10:56 AM

I have an associative array called move_set, how can I just get 'r' 'p' 's' at random?

Code:

declare -A move_set=(['r']="rock" ['p']="paper" ['s']="scissors")

ntubski 08-18-2013 11:06 AM

Using PTrenholme's code, replace
Code:

$(shuf -i 1-$# -n 1)
with
Code:

$((RANDOM % $# + 1))

PTrenholme 08-18-2013 12:46 PM

To clarify, ${move_set[*]} is the list of the values in move_set, and ${!move_set[*]} is the list of the key values. See "info bash" in the "Parameter Expansion" section in the "Basic Shell Features" group for details.

konsolebox 08-18-2013 02:55 PM

Quote:

Originally Posted by mina86 (Post 5011384)
Code:

moves=(rock paper scissors)
echo "${moves[$(($RANDOM % ${#moves[@]}))]}"


This could also be simplified as:
Code:

echo "${moves[RANDOM % ${#moves[@]}]}"

Lucien Lachance 08-18-2013 05:58 PM

So far I've come up with this:
I'll try out your solutions in just a minute..

Code:

main() {
  local play_again='y'
  local player opponent
  declare -A move_set=(['r']='Rock' ['p']='Paper' ['s']='Scissors')
  while [[ $play_again == 'y' ]]; do
    print_moves "$(declare -p move_set)"
    read -p 'Enter a move: ' player
    read -p 'Play again? (y/n): ' play_again
    play_again=$(echo $play_again | awk '{ print tolower($0) }')
  done
}


grail 08-18-2013 08:16 PM

Nearly, the awk is an overkill for something bash can already do:
Code:

while [[ ${play_again,} == 'y' ]]; do
You can then delete the awk line. Of course, there is no error checking so they could enter different characters, for that matter i would also change your read to be:
Code:

read -n 1 -p 'Play again? (y/n): ' play_again
I would also change your other read as you are only expecting the user to enter a single letter.

Lucien Lachance 08-19-2013 02:46 PM

Could you explain what
Code:

while [[ ${play_again,} == 'y' ]]; do
does exactly? Does it convert to lowercase? And I'm still having trouble pulling out a random key from move_set.

konsolebox 08-19-2013 06:10 PM

Also how come you ask for a move then ask immediately if a player should play again?

Code:

    read -p 'Enter a move: ' player
    read -p 'Play again? (y/n): ' play_again


Lucien Lachance 08-19-2013 06:51 PM

Oh, because I initially coded the while loop to just get the structure of the game setup. It's almost like a roadmap, I can't go anywhere unless I know how the game will be setup. Now I'm going to add things in between where I'm receiving a move from player. After that I'll validate the move and see if it's a key of move_set and so forth.. Sorry for leaving that out. I originally just wrote this in Python and thought it would be fun to port it to Bash.

grail 08-19-2013 08:09 PM

Yes a comma converts the first / single character to lower case, see here for further details.

Quote:

And I'm still having trouble pulling out a random key from move_set.
You might have to explain further what trouble you are referring to?

Lucien Lachance 08-19-2013 09:38 PM

@grail in Python it was really simple to pick out a key from a list tuple. However, I'm working with an associative array in Bash. Here I've made a function that gets a move from player and opponent makes a random decision of either 'r', 'p', or 's'. For some reason I'm not understanding how to do this same thing in bash.

Code:

#!/usr/bin/env python

def main():
    """Illustrate the concept of assigning a random key value."""
    moves = [('r', "rock"), ('p', "paper"), ('s', "scissor")]

    player = get_move()

    opponent = random.choice(moves)[0]



All times are GMT -5. The time now is 01:57 PM.