Linux.org.ru chess tournament logs and tables
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

231 lines
6.5KB

  1. #!/usr/bin/env bash
  2. # Copyright 2015 Vladimir Ivanov <ivvl82@gmail.com>
  3. # Distributed under the terms of the GNU General Public License v2
  4. REPO_DIR=
  5. # Specify the tournament here
  6. TOURNAMENT=
  7. # Version information
  8. VERSION="0.1"
  9. argv0=${0##*/}
  10. # Fix the notation of decimal point
  11. export LANG=en_US.UTF-8
  12. function usage {
  13. cat <<EOF
  14. Automatic generation of tours.
  15. EOF
  16. exit "${1:-0}"
  17. }
  18. function version {
  19. exec echo "${argv0}-${VERSION}"
  20. }
  21. function rr_setup {
  22. : ${REPO_DIR:=`dirname "$0"`}
  23. # If no tournament given, set it to the last one
  24. if [[ -z $TOURNAMENT ]]; then
  25. local year_dir=$(ls -1 -d ${REPO_DIR}/[0-9][0-9][0-9][0-9]/ | tail -1)
  26. TOURNAMENT=$(ls -1 -d ${year_dir}[0-9]-*/ | tail -1 \
  27. | sed -E "s|${REPO_DIR}/(.*)/|\1|")
  28. fi
  29. # Configuration file for players
  30. ply_ini=${REPO_DIR}/${TOURNAMENT}/players.ini
  31. [[ -f $ply_ini ]] || die "File ${ply_ini} not found."
  32. local dir_for_tours=${REPO_DIR}/${TOURNAMENT}/tours
  33. [[ -d $dir_for_tours ]] && die "Directory ${dir_for_tours} already exist."
  34. }
  35. function rr_get_names {
  36. declare -a TMP_NAMES
  37. name_re="^ *name *="
  38. TMP_NAMES=( $(grep "$name_re" "$ply_ini" | sed "s/${name_re}//") )
  39. if $RAND_ORDER; then
  40. # Get the set of random positions
  41. local max_range=$(( ${#TMP_NAMES[@]} - 1 ))
  42. local rand_array=( $(seq 0 1 $max_range) )
  43. for (( range=$max_range; range>1; --range )); do
  44. # Peek a random position from 0 to `range'
  45. local rand_value=$RANDOM
  46. local norm_rand_value=$(bc -l <<< "($rand_value / 32768) * $range")
  47. local rand_idx=$(printf "%.0f" $norm_rand_value)
  48. # Place the value at the position to the end of range
  49. local tmp=${rand_array[range]}
  50. rand_array[range]=${rand_array[rand_idx]}
  51. rand_array[rand_idx]=$tmp
  52. done
  53. # Randomize the order of players
  54. for (( idx=0; idx<${#rand_array[@]}; ++idx )); do
  55. local rand_idx=${rand_array[idx]}
  56. NAMES[idx]=${TMP_NAMES[rand_idx]}
  57. done
  58. echo "$(tput setaf 2)New randomized list of players:$(tput sgr0)"
  59. for (( idx=0; idx<${#NAMES[@]}; ++idx )); do
  60. echo "$(tput setaf 2)$(( idx+1 )).$(tput sgr0) ${NAMES[idx]}"
  61. done
  62. rr_update_ini
  63. else
  64. NAMES=( ${TMP_NAMES[@]} )
  65. fi
  66. }
  67. function rr_update_ini {
  68. local answer
  69. echo -n "Update 'players.ini'? (Y/n)> "
  70. read answer
  71. [[ $answer =~ ^(Y|y|Yes|yes)$ ]] || return
  72. # Extract INI blocks from config
  73. declare -a ini_array
  74. local ini_block=
  75. while read line; do
  76. if [[ $line =~ ^\[player[0-9]+\]$ ]]; then
  77. # Close the previous INI block
  78. if [[ -n $ini_block ]]; then
  79. ini_array+=( "$ini_block" )
  80. ini_block=
  81. fi
  82. fi
  83. [[ $line =~ ^\ *$ ]] || ini_block+="${line}\n"
  84. done <"$ply_ini"
  85. [[ -n $ini_block ]] && ini_array+=( "$ini_block" )
  86. echo "Updating ${ply_ini}..."
  87. mv "$ply_ini" "${ply_ini}.orig"
  88. for (( idx=0; idx<${#rand_array[@]}; ++idx )); do
  89. local rand_idx=${rand_array[idx]}
  90. echo -en "${ini_array[rand_idx]}" \
  91. | sed "s/^\[player$(( rand_idx+1 ))\]$/[player$(( idx+1 ))]/" >> "$ply_ini"
  92. (( idx < ${#rand_array[@]} - 1 )) && echo >> "$ply_ini"
  93. done
  94. }
  95. function rr_gen_table1 {
  96. local ply_num= idx= next_idx=
  97. # Number of table cells
  98. local cell_total=$(bc <<< "$PLY_MAX * ($PLY_MAX + 1)")
  99. # First pass: fill the table with 'PLY_MAX'
  100. for (( round=0; round < PLY_MAX; ++round )); do
  101. idx=$(bc <<< "($PLY_MAX + 1) * $round + ($round + 1) % 2")
  102. TABLE1[idx]=$PLY_MAX
  103. done
  104. # Second pass: fill the table with players in ascending order
  105. ply_num=0
  106. for (( pair=0; pair < cell_total/2; ++pair )); do
  107. idx=$(( 2 * pair ))
  108. next_idx=$(( 2 * pair + 1 ))
  109. if [[ -z ${TABLE1[idx]} ]]; then
  110. TABLE1[idx]=$ply_num
  111. else
  112. TABLE1[next_idx]=$ply_num
  113. fi
  114. ply_num=$(( (ply_num + 1) % PLY_MAX ))
  115. done
  116. # Second pass: fill the table with players in descending order
  117. ply_num=$(( PLY_MAX - 1 ))
  118. for (( idx=0; idx < cell_total; ++idx )); do
  119. if [[ -z ${TABLE1[idx]} ]]; then
  120. TABLE1[idx]=$ply_num
  121. ply_num=$(( PLY_MAX - 1 - (PLY_MAX - ply_num) % PLY_MAX ))
  122. fi
  123. done
  124. }
  125. function rr_gen_table2 {
  126. # Number of table cells
  127. local cell_total=$(bc <<< "$PLY_MAX * ($PLY_MAX + 1)")
  128. # Alter white and black players in the second half of tournament
  129. for (( pair=0; pair < cell_total/2; ++pair )); do
  130. local idx=$(( 2 * pair ))
  131. local next_idx=$(( 2 * pair + 1 ))
  132. TABLE2+=( ${TABLE1[next_idx]} ${TABLE1[idx]} )
  133. done
  134. }
  135. function rr_gen_tours {
  136. declare -a tour_table
  137. local tour_num=0 ply_num=0
  138. for ply in ${TABLE1[@]} ${TABLE2[@]}; do
  139. tour_table+=($ply)
  140. (( ply_num++ ))
  141. if (( ply_num > PLY_MAX )); then
  142. rr_gen_tour_info
  143. # Start new tour
  144. (( tour_num++ ))
  145. ply_num=0
  146. tour_table=()
  147. fi
  148. done
  149. }
  150. function rr_gen_tour_info {
  151. # Change tour numbers: '1' -> '01', '2' -> '02', and so on
  152. local tour=$(printf "%02g" $(( tour_num + 1 )))
  153. mkdir -p "${REPO_DIR}/${TOURNAMENT}/tours/${tour}"
  154. local tour_info=${REPO_DIR}/${TOURNAMENT}/tours/${tour}/tour_info
  155. echo "Generating ${tour_info}..."
  156. # Create header
  157. (
  158. echo "Тур №$(( tour_num + 1 ))"
  159. echo "=========="
  160. echo
  161. echo "Время проведения: ??.??.???? - ??.??.????"
  162. echo
  163. ) >> "$tour_info"
  164. # Create pairs
  165. for (( pair=0; pair < (PLY_MAX+1)/2; ++pair )); do
  166. local idx=$(( 2 * pair ))
  167. local next_idx=$(( 2 * pair + 1 ))
  168. local white_ply=${tour_table[idx]}
  169. local black_ply=${tour_table[next_idx]}
  170. echo "${NAMES[white_ply]} - ${NAMES[black_ply]}"
  171. done | column -t | sed "s/ - /-/; s/^/??.??.???? /" >> "$tour_info"
  172. }
  173. function die {
  174. echo "$@" >&2
  175. exit 1
  176. }
  177. RAND_ORDER=false
  178. while getopts rhv opt; do
  179. case $opt in
  180. r) RAND_ORDER=true ;;
  181. h) usage ;;
  182. v) version ;;
  183. *) usage 1 ;;
  184. esac
  185. done
  186. shift $(( $OPTIND - 1 ))
  187. rr_setup
  188. declare -a NAMES
  189. rr_get_names
  190. # The number of players should be even
  191. PLY_MAX=$(( ${#NAMES[@]} + ${#NAMES[@]} % 2 - 1 ))
  192. declare -a TABLE1 TABLE2
  193. rr_gen_table1 # first half of tournament
  194. rr_gen_table2 # second half of tournament
  195. rr_gen_tours
  196. exit 0