bash - while loop - rolling 2 dice - bash

I'm writing a bash script that rolls 2 dice(with 6 sides). When the 2 dice hits double sixes I want the script to stop (break) and count how many rolls it took to get double sixes.
#!/bin/bash
DOUBLESIX="6-6"
while (( 0 ==0 )) ; do
dice=$RANDOM; ((dice = dice % 6 )); (( dice = dice +1 ))
dice2=$RANDOM; ((dice2 = dice2 % 6 )); (( dice = dice + 1))
pair="$dice-dice$2"
echo $pair
if [[ "$pair" == "$DOUBLESIX" ]]; then
break
fi
done
echo "It took $count rolls to get 6-6 "
Here's what i have so far. Question is, how do I count how many times the while loop ran and put it in my $count?
Thanks in advance!

I won't comment too much on the other potential issues you have with your code, such as the dice$2 "variable", or the fact you can generate a random number between one and six inclusive with the somewhat simpler ((num = $RANDOM % 6 + 1)) - the learning process of fixing/improving those is what will make you a better coder.
But, for the specific question on how to maintain a count, that's relatively simple. Before the loop starts, insert the following code to initialise the count to zero:
((count = 0))
Then, with each roll of the two dice, use the following to increment the count:
((count = count + 1))
An example of how to do this can be seen below. It's for counting from one to ten but you should get the idea:
((count = 1))
while [[ ${count} -le 10 ]] ; do
echo $count
((count = count + 1))
done
For what it's worth (don't use this if this is a classwork problem, you'd be crazy to think educators don't search the net for plagiarism), here's how I would implement such a beast:
#!/bin/bash
DESIRED="6-6"
((count = 0))
dice="NOT ${DESIRED}"
while [[ "${dice}" != "${DESIRED}" ]] ; do
((count = count + 1))
((die1 = $RANDOM % 6 + 1))
((die2 = $RANDOM % 6 + 1))
dice="${die1}-${die2}"
echo ${dice}
done
echo "It took ${count} rolls to get ${DESIRED}"

I advice to use shuf for this purpose.
#!/bin/bash
declare -i count=1
while [ "6 6" != "$(shuf --input-range='1-6' -r -n 2 | xargs)" ]; do
(( ++count ))
done
echo "It took $count rolls to get double six."
To generating two random numbers between 1 and 6 we use
shuf --input-range='1-6' -r -n 2
shuf [OPTION]... [FILE] write a random permutation of the input lines to standard output. Each output permutation is equally likely. -i lo-hi or --input-range=lo-hi act as if input came from a file containing the range of unsigned decimal integers lo-hi, one per line. -r or --repeat repeat output values, that is, select with replacement. With this option the output is not a permutation of the input; instead, each output line is randomly chosen from all the inputs. -n count or --head-count=count output at most count lines (by default, all input lines are output). If --head-count is not given, shuf repeats indefinitely.
Type man shuf or see coreutils manual for more details.

Related

BASH: loop array values unlimited

In bash I want array let say:
array=(1 2 3)
Then I need a loop for program where
x will be 1,2,3,1,2,3... (from array)
i will be unlimited 1,2,3,4,5,6.... (main loop)
My code:
array=(1 2 3)
while true ; do
((i=i+1))
#screen -dmS plot$i -d /destinatin$x
echo $i $x
sleep 1
done
I do not know how to loop array and set $x to go 1,2,3,1,2,3....
Infinite loops are generally generated using the shell built-in command : which does nothing in its singular form. So if you want to loop infinitely over the elements of a list, you can do the following:
1. The infinite nested while-for loop:
while :; do for i in "${a[#]}"; do echo "${i}"; done; done
2. using an index-reset
i=0; while :; do echo "${a[i]}"; ((i=i+1)); ((i==${#a[#]})) && i=0; done
2. using modulo calculation:
i=0; while :; do echo "${a[i]}"; (( i=(i+1) % ${#a[#]} )); done
3. the infinite for loop with modulo index
for ((i=0;;i++)); do echo "${a[i%${#a[#]}]}"; done
This code should solve your problem:
#!/bin/bash
array=(1 2 3)
i=0
count_of_elements=${#array[#]} #counting the number of array elements
while true; do
rest=$(($i%$count_of_elements)) #counting rest of the division by count of array elements
printf "${array[$rest]}," #dispay result
i=$((i+1))
done
It will be also working if you change your input array (for example if it will be array=(1 2 3 4 5).

How do I write a Bash script for a C program that takes 4 numerical inputs? [duplicate]

This question already has answers here:
How to zero pad a sequence of integers in bash so that all have the same width?
(15 answers)
Closed 2 years ago.
I am writing a bash script for a c program, where the program asks for a 4 numerical pin inputs. However, when I wrote the script, the output seems to run in a loop, but it doesn't break where it gets identified as the correct number the program will accept.
#!/bin/bash
RANGE=9000
count=${RANDOM:0:4}
while [[ "$count" -le $RANGE ]]
do
number=$RANDOM
(( "number %= $RANGE" ))
echo $number
if [[ "$count" == "$RANGE" ]]; then
break
fi
done
When I run it, I can see some numbers in the output that returned as 2 or 3 digits, instead of 4. So in theory, what I want to do is find a random number that is 4 digits that the program will take, but I don't know what is the random number, so essentially it is a brute force, or just me manually guessing the pin number.
If all you need is a random 4-digit number, you can do that with:
printf -v number "%04d" $((RANDOM % 10000))
The $RANDOM gives you a random number 0..32767, the % 10000 translates that to the range 0..9999 (not perfectly distributed, but should be good enough for most purposes), and the printf ensures leading zeros are attached to it (so you'll see 0042 rather than 42, for example).
You can test it with the following script:
(( total = 0 ))
(( bad = 0 ))
for i in {1..10000} ; do
printf -v x "%04d" $((RANDOM % 10000))
(( total += 1 ))
[[ "${x}" =~ ^[0-9]{4}$ ]] || { echo Bad ${x}; (( bad += 1 )); }
done
(( good = total - bad ))
echo "Tested: ${total}, bad ${bad}, good ${good}"
which should give you:
Tested: 10000, bad 0, good 10000

Bash while loop till EOF

I need to write a program that calculates the arithmetic mean and variance with intiger division, but i don't now how many numbers will be entered. Example input:
5
4
1
5
2
6
Example output:
3
8
For now when i enter x instead of a number, the loop ends, but those numbers are read from file, so i think it should be something like:
while read -r num; do
if [[ "$num" -eq EOF ]]; then #that condition is my question, what should be inside [[]]?
break
fi
else
#do sth
done
#the rest of the program
You don't get a special value when the end of the input file is reached; rather, read exits with a non-zero exit status, which terminates the loop. For example:
count=0
total=0
while read -r num; do
count=$((count + 1))
total=$((total + num))
done
avg=$((total / count))

bash loop through list of numbers except given number

to loop through a continous list of numbers in bash I can do
for s in $(seq 1 5);do
echo ${s}
done
to loop through a continous list of numbers leaving a given number out in python I can do:
list = [s2 for s2 in range(6)[1:] if s2 != s1]
for s1 in list:
print s1
where list contains all numbers in range except s1
How do I do the same in bash?
Just use continue to skip this step:
for s in {1..5} # note there is no need to use $(seq...)
do
[ "$s" -eq 3 ] && continue # if var is for example 3, jump to next loop
echo "$s"
done
This returns:
1
2
4 # <--- 3 is skipped
5
From Bash Reference Manual → 4.1 Bourne Shell Builtins:
continue
continue [n]
Resume the next iteration of an enclosing for, while, until, or select
loop. If n is supplied, the execution of the nth enclosing loop is
resumed. n must be greater than or equal to 1. The return status is
zero unless n is not greater than or equal to 1.
Add a short circuit evaluation, || (logical OR) :
for s in $(seq 1 5); do
(( s == 3 )) || echo "$s"
done
(( s == 3 )) checks if $s is equal to 3, if not (||) echo the number.
With the reverse check ($s not equal to 3) and logical AND (&&):
for s in $(seq 1 5); do
(( s != 3 )) && echo "$s"
done
The classic way, if with test ([), non-equity test:
for s in $(seq 1 5); do
if [ "$s" -ne 3 ]; then
echo "$s"
fi
done
Reverse test, equity check:
for s in $(seq 1 5); do
if [ "$s" -eq 3 ]; then
continue
fi
echo "$s"
done
continue will make the loop control to go at the top rather than evaluating the following commands.
There is also a bash keyword [[ which behaves similarly in most cases but more robust.
You can use BASH arithmetic construct ((...)) like this:
s1=3 # skip this
s2=6 # upper count
for ((i=1; i<s2; i+=(i==s1-1?2:1) )); do echo $i; done
1
2
4
5
About: i+=(i==s1-1?2:1)
In the for loop instead of always incrementing i by 1 here we are incrementing i by 2 when i is 1 less then the number to be skipped.
Alternatively solution using BASH array:
arr=({1..5}) # populate 1 to 5 in an array
unset arr[s1-1] # delete element s1-1
# print the array
printf "%s\n" "${arr[#]}"
1
2
4
5

Bash: Formating numbers in a n digit string

I am a bash newbie. I would like to echo the numbers 1 to x in a n digits format. For example, let's consider n=3: 5 should become 005, 13 should become 013, 110 should remain 110.
One way to achieve this is with this kind of structure:
for i in $(seq 1 120)
do
if [ "$i" -lt "10" ]
then
echo "00$i"
elif [ "$i" -gt "99" ]
then
echo "$i"
else
echo "0$i"
fi
done
but it is quite ugly and is really not flexible to changing values of n (number of digits). I'd rather have a function that just do the formatting in n digits? Is there an already built in function for that? If not can you help me to create such function?
Use printf:
for i in {1..120} ; do
printf '%03d\n' $i
done
% starts the format string
d means integer
3 means length = 3
0 means zero padded
\n is a newline

Resources