initial commit

This commit is contained in:
2021-08-08 21:11:22 +02:00
commit fe7136d801
130 changed files with 6858 additions and 0 deletions

108
bash/tournament/README.md Normal file
View File

@@ -0,0 +1,108 @@
# Tournament
Tally the results of a small football competition.
Based on an input file containing which team played against which and what the
outcome was, create a file with a table like this:
```text
Team | MP | W | D | L | P
Devastating Donkeys | 3 | 2 | 1 | 0 | 7
Allegoric Alaskans | 3 | 2 | 0 | 1 | 6
Blithering Badgers | 3 | 1 | 0 | 2 | 3
Courageous Californians | 3 | 0 | 1 | 2 | 1
```
What do those abbreviations mean?
- MP: Matches Played
- W: Matches Won
- D: Matches Drawn (Tied)
- L: Matches Lost
- P: Points
A win earns a team 3 points. A draw earns 1. A loss earns 0.
The outcome should be ordered by points, descending. In case of a tie, teams are ordered alphabetically.
###
Input
Your tallying program will receive input that looks like:
```text
Allegoric Alaskans;Blithering Badgers;win
Devastating Donkeys;Courageous Californians;draw
Devastating Donkeys;Allegoric Alaskans;win
Courageous Californians;Blithering Badgers;loss
Blithering Badgers;Devastating Donkeys;loss
Allegoric Alaskans;Courageous Californians;win
```
The result of the match refers to the first team listed. So this line
```text
Allegoric Alaskans;Blithering Badgers;win
```
Means that the Allegoric Alaskans beat the Blithering Badgers.
This line:
```text
Courageous Californians;Blithering Badgers;loss
```
Means that the Blithering Badgers beat the Courageous Californians.
And this line:
```text
Devastating Donkeys;Courageous Californians;draw
```
Means that the Devastating Donkeys and Courageous Californians tied.
Run the tests with:
```bash
bats tournament_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats tournament_test.sh
```
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

132
bash/tournament/tournament.sh Executable file
View File

@@ -0,0 +1,132 @@
#!/usr/bin/env bash
# v1: - initial version
# v2-3: - backport bubble sort (while -> for) & debug system from next exercises
# - always read from stdin
# - some syntax improvement
# v4: - cosmetic/syntax changes
# - change from empty file handling (empty string becomes valid filename)
# v5: - cosmetic changes following "shellcheck" usage.
# v6: - removed debug calls.
# v7-8: - cosmetic changes
die() {
echo "${@}" >&2
exit 1
}
# the results, associative arrays with team name as key. Some tables look
# redundant, but easier to understand.
declare -A mp # matches played
declare -A win # matches won
declare -A draw # matches tied
declare -A loss # matches lost
declare -A points # points
declare -a order # final order.
nteams=0
# create a team entry in arrays if non existent. $1: team
create_team() {
if ! [[ -v "mp[$1]" ]]; then
(( nteams++ ))
(( mp["$1"]=0 ))
(( win["$1"]=0 ))
(( loss["$1"]=0 ))
(( draw["$1"]=0 ))
(( points["$1"]=0 ))
order[$nteams]="$1"
fi
}
# update results for a team: $1, $2: teams, $3: result for $1: win/draw/loss
update_results() {
create_team "$1"
create_team "$2"
((mp["$1"]++))
((mp["$2"]++))
case "$3" in
win)
((win["$1"]++))
((loss["$2"]++))
((points["$1"]+=3))
;;
loss)
((win["$2"]++))
((loss["$1"]++))
((points["$2"]+=3))
;;
draw)
((draw["$1"]++))
((draw["$2"]++))
((points["$1"]++))
((points["$2"]++))
;;
*) # should not happen
die "fatal: invalid result $3, exiting."
esac
}
# inspired from https://stackoverflow.com/questions/7442417/how-to-sort-an-array-in-bash
# (bubble sort)
sort_teams()
{
local max i
for ((max=nteams; max>0; max--)); do
for ((i=1; i<max; ++i )); do
local team1=${order[$i]} team2=${order[$i + 1]} switch=0
if (( ${points["$team1"]} < ${points["$team2"]} )) || \
( (( ${points["$team1"]} == ${points["$team2"]} )) && \
[[ "$team1" > "$team2" ]] ); then
order[$i]="$team2"
order[$i + 1]="$team1"
fi
done
done
}
output() {
printf "%-30s |%3s |%3s |%3s |%3s |%3s\n" "${@:1:6}"
}
output_team() {
output "$1" "${mp[$1]}" "${win[$1]}" "${draw[$1]}" "${loss[$1]}" "${points[$1]}"
}
# output teams, according to "order" table
output_teams() {
local i
# header
output "Team" "MP" "W" "D" "L" "P"
for (( i=1; i<= nteams; ++i )); do
output_team "${order[$i]}"
done
}
load_teams() {
# set separator. Note we ignore escaping ';': a\;a;b;win wont work
local team1 team2 result
local IFS=$';\n'
while read -r team1 team2 result ; do
# should empty result considered as error or ignored? Ignored here.
[[ -z "$team1" || -z "$team2" || -z "$result" ]] && continue
update_results "$team1" "$team2" "$result"
done
}
# we will accept both argument (file name) or stdin input
if (( $# == 0 )); then
load_teams
elif [[ -f "$1" ]]; then
load_teams < "$1"
else
die Invalid "[$1]" file. Exiting.
fi
sort_teams
output_teams
exit 0