ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I'm trying to replicate this function I've written in Python that prints a message based on the player and opponents move and compares those moves with an associative array called match. How can I pass a key array to a function in bash? I've declared match in my main function and I need to use this in another function which looks like this:
Code:
#!/bin/bash
declare -A match=(['r']='s' ['p']='r' ['s']='p')
Code:
def compare_moves(player, opponent, match):
"""Compares the moves of player and opponent.
To determine a winner, we need to be aware of
the move of player, as well as the opponent's
move. We can then cross check the results of
both moves against match and determine the
winner of the game with the following: "rock"
beats scissors, "paper" beats rock, "scissors"
beats paper.
Args:
player: The decision and/or move of player
determines the outcome of the game.
opponent: A decision at random of opponent
which is played against the player.
match: The winning outcomes of the game
that gets compared to both moves made.
"""
if player == opponent:
print "It appears we have a tie!"
elif match[player] == opponent:
print "Congratulations, you win!"
else:
print "You walk away with shame."
#!/bin/bash
function myFunction
{
eval "declare -A ref"=${1#*=}
for key in ${!ref[@]}; do
echo -n "$key "
done
echo
for value in ${ref[@]}; do
echo -n "$value "
done
echo
}
declare -A match=(['r']='s' ['p']='r' ['s']='p')
myFunction "$(declare -p match)"
Yeah, that's the only thing I've been able to find. I have three arguments in my case. Off the top of my head, this is the only way I could think of how it could be done. I just would like to know how can I pass in this associative array with my function compare_moves. Is there a better way of handling this?
Code:
compare_moves() {
local player_move=$1
local enemy_move=$2
eval "declare -A compare="${3#*=}
if [[ $player == $opponent ]]; then
echo 'It appears we have a tie'
elif [[ ${compare[$player]} == $opponent ]]; then
echo 'Congratulations, you win!'
else
echo 'You walk away with shame.'
fi
}
Last edited by Lucien Lachance; 08-25-2013 at 03:53 PM.
I am a little lost?? Why would you need to pass the array? Are you saying you have multiple functions that will all need access to this 'match' array? (seems unlikely, but I could be wrong)
I would have said that this would be the only function needing access to this array, hence simply declare it in this function.
You could also make it a global array and then you can access it from any function or part of your code (personally, not my first choice)
I need this function to access this array. Sorry for the confusion. I thought about declaring it inside of the function, but I would prefer to keep it the same way as I had wrote it in Python. @grail
As Python is a higher level language it would be obvious not all things will be directly transferable. I would say that even in the Python example, whilst it has worked, I fail to see the need to pass the array if this is to be the only place a comparison is to be done, ie if the calling entry simply calls the command and passes the array which is not used anywhere but for this check, what advantage
do you gain except to use a feature?
May I suggest an alternative, if the array is indeed used elsewhere, why not simply pass the result from the array to the function that performs the test?
Code:
compare_moves() {
local player_move=$1
local enemy_move=$2
local compare=$3 # third will be value of ${match[$player]}
if [[ $player == $opponent ]]; then
echo 'It appears we have a tie'
elif [[ $compare == $opponent ]]; then
echo 'Congratulations, you win!'
else
echo 'You walk away with shame.'
fi
}
@grail everything is declared in my main function like so. I just want to be able to directly access table because it's already declare in main. So the function you've written I can use by saying
correct? I'll also provide some more clarity so you can have an idea as to what I've set up:
Code:
print_all() {
eval "declare -A move_set="${1#*=}
for move in "${!move_set[@]}"; do
printf "%s => %s\n" "$move" "${move_set[$move]}"
done
}
main() {
local reply='y'
local player enemy
declare -A plays=(['r']='rock' ['p']='paper' ['s']='scissors')
declare -A table=(['r']='s' ['p']='r' ['s']='p')
print_all "(declare -p plays)" # Prints all available moves
# code continues...
}
Last edited by Lucien Lachance; 08-26-2013 at 08:22 AM.
As I said before though, bash is not OO orientated like Python so not all constructs will convert directly.
May I ask, is your intention to learn how to translate from Python to bash or how to implement the same solution (ie the game) in bash?
If the latter, then suggestion from konsolebox and myself earlier would fit with a bash implementation. Also, most (not all but a large number I have seen and implemented) generally
have the list of functions and then 'main' is not a function but the end part of the script. This would then still fit your format but all those items created in the main, such as
plays array, would all be globally accessible within any function you require them.
As a side note (and I may get a little flamed for this), however, most scripters steer away from using eval. Like any command it can be used safely and for the likes of a game / script that
only you will play and hence no issue with malicious usage occurring it poses no real threat. That being said, I use it sparingly and with extreme caution as to become reliant on it,
and hence use as a standard feature of any script can be hazardous (from someone who had half a system wiped from such use).
I see, what would you suggest I use to handle print_all? I have one idea. I could make a one-liner and use declare -p and pipe the output to awk to format the array output.
Well under the global landscape idea you would simply use the plays array in the print_all function:
Code:
print_all() {
for move in "${!plays[@]}"; do
printf "%s => %s\n" "$move" "${plays[$move]}"
done
}
I guess then you have to look at coding style, generally I would create a function for a repetitive task that needs to be called several times throughout the code.
Looking at this snippet, I cannot see why you would need to call it again?
If the idea is to present all the options to the users at the start of each game then simply place the for loop inside a while loop that checks when the game is to end.
This function is only called on each iteration of a while loop I've set up. It's more of a display function than anything. I'll go with your idea of just writing the loop without using a function. I'm so used to writing C and Python and having everything in small compartments and/or modules. I also wrote a check to make sure the user's response is within the key values of plays which represents: r, p, and s. @grail
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.