Annotation of processmail/subroutines.pl, revision 3.3

1.1       boris       1: # В этот файл собраны процедуры, общие для всей системы
                      2: # работы с ответами.
                      3: #
3.3     ! boris       4: #$Id: subroutines.pl,v 3.2 2013-10-11 15:39:35 boris Exp $
1.1       boris       5: #
                      6: sub readhash
                      7: {
                      8:     my ($answers) = @_;
                      9:     my $answer = "";
                     10:     my $score = "";
                     11:     my $number = -1;
                     12:     while (<INFILE>)
                     13:     {
                     14:        if (/^\s*\#(\d+).*Score:\s*([+-\?])/) # Нашли новый ответ
                     15:        {
                     16:            if ($DEBUG)
                     17:            {
                     18:                print STDERR "\#$number. Score: $score\n",$answer;
                     19:            }
3.3     ! boris      20:            if ($answer ne "" && $number >= 0)
1.1       boris      21:            {
                     22:                $$answers[$number]->{$answer}->{score} = $score;
1.4       boris      23:                %{$$answers[$number]->{$answer}->{teams}} = ();
1.1       boris      24:            }
                     25:            $answer = "";
                     26:            $number = $1;
                     27:            $score = $2;
                     28:            next;
                     29:        }
                     30:        if (/^Team:/)
                     31:        {
                     32:            next;
                     33:        }
                     34:        if (/^\s*\*\*\*\s*$/)
                     35:        {
3.3     ! boris      36:            if ($answer ne "" && $number >= 0)
1.1       boris      37:            {
                     38:                $$answers[$number]->{$answer}->{score} = $score;
                     39:            }
                     40:            last;
                     41:        }
                     42:        $answer .= &canonize_answer;
                     43:     }
                     44:     return 1;
                     45: }
                     46: 
                     47: #
                     48: # Читаем файл с письмами команд
                     49: #
                     50: sub readmail
                     51: {
                     52:     my ($table) = @_;
                     53:     $team="";
                     54:     $number=-1;
                     55:     while (<INFILE>)
                     56:     {
                     57:        if (/^\s*\*\*\*\s*"(.+)"\s*[,.]*\s*(\d+)*/) # Нашли новую команду
                     58:        {
                     59:            if ($DEBUG)
                     60:            {
                     61:                print STDERR "Команда: $1, рег. номер: $2\n";
                     62:            } 
                     63:            $team = $1;
                     64:            $number = -1;
                     65:            if (!exists($$table{$team})) # Новая команда...
                     66:            {
                     67:                my @teamanswers = ();
                     68:                my %teamhash = ('answers' => \@teamanswers, 
1.2       boris      69:                                'regnum' => $2,
                     70:                                'numletters'=>0);
1.1       boris      71:                $$table{$team} = \%teamhash;
                     72:            }
1.2       boris      73:            $$table{$team}->{'numletters'}++;
1.1       boris      74:            if ($$table{$team}->{regnum} != $2)
                     75:            {
3.3     ! boris      76:                print STDERR "Warning: Team $team uses registration numbers ",
        !            77:                      "'" . $$table{$team}->{regnum} . "'", " and '$2'!\n";
1.1       boris      78:            }
                     79:            next;
                     80:        }
                     81:        if (s/^\s*\#(\d+)\.*// && $team ne "")
                     82:        {
                     83:            if ($DEBUG)
                     84:            {
                     85:                print STDERR "Ответ $1\n";
                     86:                print STDERR;
                     87:            }
                     88:            $number = $1;
                     89:            $$table{$team}->{answers}[$number] = &canonize_answer;
                     90:            next;
                     91:        }
                     92:        if (/^\*\*\*/) # Команда кончилась
                     93:        {
                     94:            $team="";
                     95:            $number=-1;
                     96:        }
                     97:        if ($team ne "" && $number >0)
                     98:        {
                     99:            if ($DEBUG)
                    100:            {
                    101:                print STDERR;
                    102:            }
                    103:            $$table{$team}->{answers}[$number] .= &canonize_answer;
                    104:        }
                    105:     }
                    106:     return 1;
                    107: }
                    108: 
                    109: #
                    110: # Приводим ответ к канонической форме: два пробела в начале, 
                    111: # ни одного в конце
                    112: #
                    113: sub canonize_answer
                    114: {
                    115:     s/^\s*(.*)\s*$/  $1/;
                    116:     if (/^\s*$/) 
                    117:     {
                    118:        return "";
                    119:     }
                    120:     else 
                    121:     {
                    122:        return $_."\n";
                    123:     }
                    124: }
                    125: 
                    126: #
                    127: # Заполняем поля %answers
                    128: #
                    129: sub collect_answers
                    130: {
                    131:     my ($teams,$answers) = @_;
3.3     ! boris     132:     for ($i=$MINQUEST;$i<=$MAXQUEST;$i++)
1.1       boris     133:     {
                    134:        foreach $team (keys %$teams)
                    135:        {
                    136:            $answer = $$teams{$team}->{answers}[$i];
                    137:            if ($answer eq "")
                    138:            {
                    139:                next;
                    140:            }
1.4       boris     141:            $$answers[$i]->{$answer}->{teams}->{$team}=1;
                    142:            if (!exists $$answers[$i]->{$answer}->{score})
1.1       boris     143:            {
                    144:                $$answers[$i]->{$answer}->{score} = '?';
                    145:            }
                    146:        }
                    147:     }
                    148:     return 1;
                    149: 
                    150: }
                    151: 
                    152: #
                    153: # Сбрасываем ответы на вопрос $number с оценкой $symbol
                    154: #
                    155: sub dumphash
                    156: {
                    157:     my ($teams,$answers,$number,$symbol) = @_;
                    158:     foreach $answer (keys %{$answers->[$number]})
                    159:     {
                    160:        if ($$answers[$number]->{$answer}{score} eq $symbol)
                    161:        {
                    162:            print "\#$number. Frequency: ", 
1.4       boris     163:            scalar keys %{$answers->[$number]->{$answer}->{teams}},
1.1       boris     164:            ". Score: ",
                    165:            $$answers[$number]->{$answer}{score},"\n"; 
                    166:            print $answer;
                    167:            if ($DEBUG)
                    168:            {
1.4       boris     169:                foreach $team (keys %{$answers->[$number]->{$answer}->{teams}})
1.1       boris     170:                {
                    171:                    print "Team: ",
                    172:                    " \"$team\", ",$$teams{$team}->{regnum}, "\n";
                    173:                }
                    174:            }
                    175:        }
                    176:     }
                    177:     return 1;
                    178: }
3.2       boris     179: 
1.1       boris     180: #
                    181: # Сбрасываем ответы на вопрос $number с оценкой $symbol
                    182: # в формате, пригодном для собрания сочинений
                    183: #
                    184: sub anondump
                    185: {
                    186:     my ($teams,$answers,$number,$symbol) = @_;
                    187:     foreach $answer (keys %{$answers->[$number]})
                    188:     {
                    189:        if ($$answers[$number]->{$answer}{score} eq $symbol)
                    190:        {
1.4       boris     191:            my $frequency = scalar keys %{$answers->[$number]->{$answer}->{teams}};
1.1       boris     192:            my $canon = $answer;
                    193:            $canon =~ s/^ /$symbol/;
                    194:            if ($frequency >1)
                    195:            {
                    196:                chomp $canon;
                    197:                $canon .= " [$frequency]\n";
                    198:            }
                    199:            print $canon;
                    200:            if ($DEBUG)
                    201:            {
1.4       boris     202:                foreach $team (keys %{$answers->[$number]->{$answer}->{teams}})
1.1       boris     203:                {
                    204:                    print STDERR "Team: ",
                    205:                    " \"$team\", ",$$teams{$team}->{regnum}, "\n";
                    206:                }
                    207:            }
                    208:        }
                    209:     }
                    210:     return 1;
                    211: }
                    212: 
                    213: #
                    214: # Подсчитываем рейтинги вопросов. Рейтинг вопроса есть 
                    215: # 1+количество команд, которые на него НЕ ответили
                    216: #
                    217: sub rate_questions
                    218: {
1.5       boris     219:     my($teams,$answers,$ratings,$round) = @_;
1.1       boris     220:     my $numteams = scalar keys %$teams;
1.5       boris     221:     for ($i=$MINQUEST[$round];$i<=$MAXQUEST[$round];$i++)
1.1       boris     222:     {
                    223:        $$ratings[$i]=$numteams+1;
                    224:        foreach $answer (keys %{$$answers[$i]})
                    225:        {
                    226:            if ($$answers[$i]->{$answer}{score} eq '+')
                    227:            {
                    228:                $$ratings[$i] -= 
1.5       boris     229:                scalar keys %{$answers->[$i]->{$answer}->{teams}} ;
                    230:                if ($DEBUG) {
                    231:                    print STDERR "Частота ответа $answer", 
                    232:                    scalar keys %{$answers->[$i]->{$answer}->{teams}},
                    233:                                  "\n";
                    234:                }
1.1       boris     235:            }
                    236:        }
                    237:     }
                    238: }
                    239: 
                    240: #
                    241: # Подсчитываем рейтинги команд
3.0       boris     242: # @{$nopoint_questions} - список номеров вопросов, идущих вне зачёта.
3.2       boris     243: # Для них проставляются плюсы/минусы, но они не учитываются в подсчёте
3.0       boris     244: # очков и рейтингов команд.
1.1       boris     245: #
                    246: sub find_scores
                    247: {
3.0       boris     248:     my ($teams,$answers,$ratings,$round,$factor,$nopoint_questions) = @_;
1.1       boris     249:     foreach $team (keys %$teams)
                    250:     {
1.2       boris     251:        if (!defined($factor)) {
                    252:            $factor=1;
                    253:        }
                    254:        $$teams{$team}->{score} *=$factor;
1.1       boris     255:        $$teams{$team}->{rating} = 0;
1.5       boris     256:        for ($i=$MINQUEST[$round];$i<=$MAXQUEST[$round];$i++)
1.1       boris     257:        {
                    258:            my $answer=$$teams{$team}->{answers}[$i];
                    259:            if ($$answers[$i]->{$answer}{score} eq '+')
                    260:            {
3.0       boris     261:                next if  ( @{$nopoint_questions} && 
                    262:                          grep($_==$i, @{$nopoint_questions})
                    263:                         );
1.1       boris     264:                $$teams{$team}->{score}  += 1;
                    265:                $$teams{$team}->{rating} +=
                    266:                    $$ratings[$i];
                    267:            }
                    268:        }
                    269:        if ($DEBUG)
                    270:        {
                    271:            print STDERR "$team: Score ",
                    272:            $$teams{$team}->{score},
                    273:            ", Rating ",
                    274:            $$teams{$team}->{rating},"\n";
                    275:        }
                    276:     }
                    277: }
                    278: 
                    279: 
3.1       boris     280: #
                    281: # Проверяем на наличие дублирующихся номеров у разных команд.
                    282: #
                    283: sub check_dup_numbers
                    284: {
                    285:     my ($teams) = @_;
                    286: 
                    287:     my %seen;
                    288: 
                    289:     # Имена команд, номера которых встречаются >1 раза.
                    290:     # Массив uniq_compr_names содержит по одному имени на каждый повторяющийся
3.2       boris     291:     # номер (чуть позже мы найдём все имена, соответствующие каждому из       
                    292:     # этих номеров).                                                          
3.1       boris     293:     # '+0' - чтобы номера обрабатывались как числа (072 == 72).
                    294:     my @uniq_compr_names =
3.2       boris     295:        grep( ++$seen{$teams->{$_}->{regnum}+0} > 1, keys %$teams );
3.1       boris     296: 
                    297:     # А теперь извлекаем номера из полученного списка.
                    298:     my @dup_numbers = map {$teams->{$_}->{regnum}} @uniq_compr_names;
                    299:     @dup_numbers = sort @dup_numbers;
                    300: 
                    301:     # И печатаем предупреждение.
                    302:     if ( @dup_numbers ) {
                    303:        print STDERR "\nВНИМАНИЕ!  Одинаковые номера у нескольких команд:\n";
                    304:        foreach my $num ( @dup_numbers ) {
3.2       boris     305:            my @dup_names = grep($teams->{$_}->{regnum}+0 == $num+0, keys %$teams);
3.1       boris     306:            print STDERR "\tНомер $num: " .  join(", ", @dup_names) . "\n";
                    307:         }
                    308:        print STDERR "\n";
                    309:     }
                    310: }
1.1       boris     311: 
                    312: 
3.2       boris     313: #
                    314: # Считаем ответы на вопрос $number с оценкой $symbol
                    315: # (фактически, это anondump(), только без печати списка
                    316: # таких ответов).
                    317: #
                    318: sub countanswers
                    319: {
                    320:     my ($teams,$answers,$number,$symbol) = @_;
                    321:     my $num=0;
                    322:     foreach $answer (keys %{$answers->[$number]})
                    323:     {
                    324:         if ($$answers[$number]->{$answer}{score} eq $symbol)
                    325:         {
                    326:             $num++;
                    327:         }
                    328:     }
                    329:     return $num;
                    330: }
                    331: 
1.1       boris     332: 
3.1       boris     333: 1;

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>