228 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			228 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								#!/usr/bin/env bash
							 | 
						|||
| 
								 | 
							
								# Copyright 2015 Vladimir Ivanov <ivvl82@gmail.com>
							 | 
						|||
| 
								 | 
							
								# Distributed under the terms of the GNU General Public License v2
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								REPO_DIR=
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# Specify the tournament here
							 | 
						|||
| 
								 | 
							
								TOURNAMENT=
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# Version information
							 | 
						|||
| 
								 | 
							
								VERSION="0.1"
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								argv0=${0##*/}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								function usage {
							 | 
						|||
| 
								 | 
							
								    cat <<EOF
							 | 
						|||
| 
								 | 
							
								Automatic generation of tours.
							 | 
						|||
| 
								 | 
							
								EOF
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    exit "${1:-0}"
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								function version {
							 | 
						|||
| 
								 | 
							
								    exec echo "${argv0}-${VERSION}"
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								function rr_setup {
							 | 
						|||
| 
								 | 
							
								    : ${REPO_DIR:=`dirname "$0"`}
							 | 
						|||
| 
								 | 
							
								    # If no tournament given, set it to the last one
							 | 
						|||
| 
								 | 
							
								    if [[ -z $TOURNAMENT ]]; then
							 | 
						|||
| 
								 | 
							
								        local year_dir=$(ls -1 -d ${REPO_DIR}/[0-9][0-9][0-9][0-9]/ | tail -1)
							 | 
						|||
| 
								 | 
							
								        TOURNAMENT=$(ls -1 -d ${year_dir}[0-9]-*/ | tail -1 \
							 | 
						|||
| 
								 | 
							
								                            | sed -E "s|${REPO_DIR}/(.*)/|\1|")
							 | 
						|||
| 
								 | 
							
								    fi
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    # Configuration file for players
							 | 
						|||
| 
								 | 
							
								    ply_ini=${REPO_DIR}/${TOURNAMENT}/players.ini
							 | 
						|||
| 
								 | 
							
								    [[ -f $ply_ini ]] || die "File ${ply_ini} not found."
							 | 
						|||
| 
								 | 
							
								    local dir_for_tours=${REPO_DIR}/${TOURNAMENT}/tours
							 | 
						|||
| 
								 | 
							
								    [[ -d $dir_for_tours ]] && die "Directory ${dir_for_tours} already exist."
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								function rr_get_names {
							 | 
						|||
| 
								 | 
							
								    declare -a TMP_NAMES
							 | 
						|||
| 
								 | 
							
								    name_re="^ *name *="
							 | 
						|||
| 
								 | 
							
								    TMP_NAMES=( $(grep "$name_re" "$ply_ini" | sed "s/${name_re}//") )
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    if $RAND_ORDER; then
							 | 
						|||
| 
								 | 
							
								        # Get the set of random positions
							 | 
						|||
| 
								 | 
							
								        local max_range=$(( ${#TMP_NAMES[@]} - 1 ))
							 | 
						|||
| 
								 | 
							
								        local rand_array=( $(seq 0 1 $max_range) )
							 | 
						|||
| 
								 | 
							
								        for (( range=$max_range; range>1; --range )); do
							 | 
						|||
| 
								 | 
							
								            # Peek a random position from 0 to `range'
							 | 
						|||
| 
								 | 
							
								            local rand_value=$RANDOM
							 | 
						|||
| 
								 | 
							
								            local norm_rand_value=$(bc -l <<< "($rand_value / 32768) * $range")
							 | 
						|||
| 
								 | 
							
								            local rand_idx=$(printf "%.0f" $norm_rand_value)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            # Place the value at the position to the end of range
							 | 
						|||
| 
								 | 
							
								            local tmp=${rand_array[range]}
							 | 
						|||
| 
								 | 
							
								            rand_array[range]=${rand_array[rand_idx]}
							 | 
						|||
| 
								 | 
							
								            rand_array[rand_idx]=$tmp
							 | 
						|||
| 
								 | 
							
								        done
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        # Randomize the order of players
							 | 
						|||
| 
								 | 
							
								        for (( idx=0; idx<${#rand_array[@]}; ++idx )); do
							 | 
						|||
| 
								 | 
							
								            local rand_idx=${rand_array[idx]}
							 | 
						|||
| 
								 | 
							
								            NAMES[idx]=${TMP_NAMES[rand_idx]}
							 | 
						|||
| 
								 | 
							
								        done
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        echo "$(tput setaf 2)New randomized list of players:$(tput sgr0)"
							 | 
						|||
| 
								 | 
							
								        for (( idx=0; idx<${#NAMES[@]}; ++idx )); do
							 | 
						|||
| 
								 | 
							
								            echo "$(tput setaf 2)$(( idx+1 )).$(tput sgr0) ${NAMES[idx]}"
							 | 
						|||
| 
								 | 
							
								        done
							 | 
						|||
| 
								 | 
							
								        rr_update_ini
							 | 
						|||
| 
								 | 
							
								    else
							 | 
						|||
| 
								 | 
							
								        NAMES=( ${TMP_NAMES[@]} )
							 | 
						|||
| 
								 | 
							
								    fi
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								function rr_update_ini {
							 | 
						|||
| 
								 | 
							
								    local answer
							 | 
						|||
| 
								 | 
							
								    echo -n "Update 'players.ini'? (Y/n)> "
							 | 
						|||
| 
								 | 
							
								    read answer
							 | 
						|||
| 
								 | 
							
								    [[ $answer =~ ^(Y|y|Yes|yes)$ ]] || return
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    # Extract INI blocks from config
							 | 
						|||
| 
								 | 
							
								    declare -a ini_array
							 | 
						|||
| 
								 | 
							
								    local ini_block=
							 | 
						|||
| 
								 | 
							
								    while read line; do
							 | 
						|||
| 
								 | 
							
								        if [[ $line =~ ^\[player[0-9]+\]$ ]]; then
							 | 
						|||
| 
								 | 
							
								            # Close the previous INI block
							 | 
						|||
| 
								 | 
							
								            if [[ -n $ini_block ]]; then
							 | 
						|||
| 
								 | 
							
								                ini_array+=( "$ini_block" )
							 | 
						|||
| 
								 | 
							
								                ini_block=
							 | 
						|||
| 
								 | 
							
								            fi
							 | 
						|||
| 
								 | 
							
								        fi
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        [[ $line =~ ^\ *$ ]] || ini_block+="${line}\n"
							 | 
						|||
| 
								 | 
							
								    done <"$ply_ini"
							 | 
						|||
| 
								 | 
							
								    [[ -n $ini_block ]] && ini_array+=( "$ini_block" )
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    echo "Updating ${ply_ini}..."
							 | 
						|||
| 
								 | 
							
								    mv "$ply_ini" "${ply_ini}.orig"
							 | 
						|||
| 
								 | 
							
								    for (( idx=0; idx<${#rand_array[@]}; ++idx )); do
							 | 
						|||
| 
								 | 
							
								        local rand_idx=${rand_array[idx]}
							 | 
						|||
| 
								 | 
							
								        echo -en "${ini_array[rand_idx]}" \
							 | 
						|||
| 
								 | 
							
								            | sed "s/^\[player$(( rand_idx+1 ))\]$/[player$(( idx+1 ))]/" >> "$ply_ini"
							 | 
						|||
| 
								 | 
							
								        (( idx < ${#rand_array[@]} - 1 )) && echo >> "$ply_ini"
							 | 
						|||
| 
								 | 
							
								    done
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								function rr_gen_table1 {
							 | 
						|||
| 
								 | 
							
								    local ply_num= idx= next_idx=
							 | 
						|||
| 
								 | 
							
								    # Number of table cells
							 | 
						|||
| 
								 | 
							
								    local cell_total=$(bc <<< "$PLY_MAX * ($PLY_MAX + 1)")
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    # First pass: fill the table with 'PLY_MAX'
							 | 
						|||
| 
								 | 
							
								    for (( round=0; round < PLY_MAX; ++round )); do
							 | 
						|||
| 
								 | 
							
								        idx=$(bc <<< "($PLY_MAX + 1) * $round + ($round + 1) % 2")
							 | 
						|||
| 
								 | 
							
								        TABLE1[idx]=$PLY_MAX
							 | 
						|||
| 
								 | 
							
								    done
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    # Second pass: fill the table with players in ascending order
							 | 
						|||
| 
								 | 
							
								    ply_num=0
							 | 
						|||
| 
								 | 
							
								    for (( pair=0; pair < cell_total/2; ++pair )); do
							 | 
						|||
| 
								 | 
							
								        idx=$(( 2 * pair ))
							 | 
						|||
| 
								 | 
							
								        next_idx=$(( 2 * pair + 1 ))
							 | 
						|||
| 
								 | 
							
								        if [[ -z ${TABLE1[idx]} ]]; then
							 | 
						|||
| 
								 | 
							
								            TABLE1[idx]=$ply_num
							 | 
						|||
| 
								 | 
							
								        else
							 | 
						|||
| 
								 | 
							
								            TABLE1[next_idx]=$ply_num
							 | 
						|||
| 
								 | 
							
								        fi
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        ply_num=$(( (ply_num + 1) % PLY_MAX ))
							 | 
						|||
| 
								 | 
							
								    done
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    # Second pass: fill the table with players in descending order
							 | 
						|||
| 
								 | 
							
								    ply_num=$(( PLY_MAX - 1 ))
							 | 
						|||
| 
								 | 
							
								    for (( idx=0; idx < cell_total; ++idx )); do
							 | 
						|||
| 
								 | 
							
								        if [[ -z ${TABLE1[idx]} ]]; then
							 | 
						|||
| 
								 | 
							
								            TABLE1[idx]=$ply_num
							 | 
						|||
| 
								 | 
							
								            ply_num=$(( PLY_MAX - 1 - (PLY_MAX - ply_num) % PLY_MAX ))
							 | 
						|||
| 
								 | 
							
								        fi
							 | 
						|||
| 
								 | 
							
								    done
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								function rr_gen_table2 {
							 | 
						|||
| 
								 | 
							
								    # Number of table cells
							 | 
						|||
| 
								 | 
							
								    local cell_total=$(bc <<< "$PLY_MAX * ($PLY_MAX + 1)")
							 | 
						|||
| 
								 | 
							
								    # Alter white and black players in the second half of tournament
							 | 
						|||
| 
								 | 
							
								    for (( pair=0; pair < cell_total/2; ++pair )); do
							 | 
						|||
| 
								 | 
							
								        local idx=$(( 2 * pair ))
							 | 
						|||
| 
								 | 
							
								        local next_idx=$(( 2 * pair + 1 ))
							 | 
						|||
| 
								 | 
							
								        TABLE2+=( ${TABLE1[next_idx]} ${TABLE1[idx]} )
							 | 
						|||
| 
								 | 
							
								    done
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								function rr_gen_tours {
							 | 
						|||
| 
								 | 
							
								    declare -a tour_table
							 | 
						|||
| 
								 | 
							
								    local tour_num=0 ply_num=0
							 | 
						|||
| 
								 | 
							
								    for ply in ${TABLE1[@]} ${TABLE2[@]}; do
							 | 
						|||
| 
								 | 
							
								        tour_table+=($ply)
							 | 
						|||
| 
								 | 
							
								        (( ply_num++ ))
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (( ply_num > PLY_MAX )); then
							 | 
						|||
| 
								 | 
							
								            rr_gen_tour_info
							 | 
						|||
| 
								 | 
							
								            # Start new tour
							 | 
						|||
| 
								 | 
							
								            (( tour_num++ ))
							 | 
						|||
| 
								 | 
							
								            ply_num=0
							 | 
						|||
| 
								 | 
							
								            tour_table=()
							 | 
						|||
| 
								 | 
							
								        fi
							 | 
						|||
| 
								 | 
							
								    done
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								function rr_gen_tour_info {
							 | 
						|||
| 
								 | 
							
								    # Change tour numbers: '1' -> '01', '2' -> '02', and so on
							 | 
						|||
| 
								 | 
							
								    local tour=$(printf "%02g" $(( tour_num + 1 )))
							 | 
						|||
| 
								 | 
							
								    mkdir -p "${REPO_DIR}/${TOURNAMENT}/tours/${tour}"
							 | 
						|||
| 
								 | 
							
								    local tour_info=${REPO_DIR}/${TOURNAMENT}/tours/${tour}/tour_info
							 | 
						|||
| 
								 | 
							
								    echo "Generating ${tour_info}..."
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    # Create header
							 | 
						|||
| 
								 | 
							
								    (
							 | 
						|||
| 
								 | 
							
								        echo "Тур №$(( tour_num + 1 ))"
							 | 
						|||
| 
								 | 
							
								        echo "=========="
							 | 
						|||
| 
								 | 
							
								        echo
							 | 
						|||
| 
								 | 
							
								        echo "Время проведения: ??.??.???? - ??.??.????"
							 | 
						|||
| 
								 | 
							
								        echo
							 | 
						|||
| 
								 | 
							
								    ) >> "$tour_info"
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    # Create pairs
							 | 
						|||
| 
								 | 
							
								    for (( pair=0; pair < (PLY_MAX+1)/2; ++pair )); do
							 | 
						|||
| 
								 | 
							
								        local idx=$(( 2 * pair ))
							 | 
						|||
| 
								 | 
							
								        local next_idx=$(( 2 * pair + 1 ))
							 | 
						|||
| 
								 | 
							
								        local white_ply=${tour_table[idx]}
							 | 
						|||
| 
								 | 
							
								        local black_ply=${tour_table[next_idx]}
							 | 
						|||
| 
								 | 
							
								        echo "${NAMES[white_ply]} - ${NAMES[black_ply]}"
							 | 
						|||
| 
								 | 
							
								    done | column -t | sed "s/ - /-/; s/^/??.??.???? /" >> "$tour_info"
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								function die {
							 | 
						|||
| 
								 | 
							
								    echo "$@" >&2
							 | 
						|||
| 
								 | 
							
								    exit 1
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								RAND_ORDER=false
							 | 
						|||
| 
								 | 
							
								while getopts rhv opt; do
							 | 
						|||
| 
								 | 
							
								    case $opt in
							 | 
						|||
| 
								 | 
							
								        r) RAND_ORDER=true ;;
							 | 
						|||
| 
								 | 
							
								        h) usage ;;
							 | 
						|||
| 
								 | 
							
								        v) version ;;
							 | 
						|||
| 
								 | 
							
								        *) usage 1 ;;
							 | 
						|||
| 
								 | 
							
								    esac
							 | 
						|||
| 
								 | 
							
								done
							 | 
						|||
| 
								 | 
							
								shift $(( $OPTIND - 1 ))
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								rr_setup
							 | 
						|||
| 
								 | 
							
								declare -a NAMES
							 | 
						|||
| 
								 | 
							
								rr_get_names
							 | 
						|||
| 
								 | 
							
								# The number of players should be even
							 | 
						|||
| 
								 | 
							
								PLY_MAX=$(( ${#NAMES[@]} + ${#NAMES[@]} % 2 - 1 ))
							 | 
						|||
| 
								 | 
							
								declare -a TABLE1 TABLE2
							 | 
						|||
| 
								 | 
							
								rr_gen_table1                   # first half of tournament
							 | 
						|||
| 
								 | 
							
								rr_gen_table2                   # second half of tournament
							 | 
						|||
| 
								 | 
							
								rr_gen_tours
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								exit 0
							 |