Копипаста:Метод Шульце

Материал из Неолурк, народный Lurkmore
Перейти к навигации Перейти к поиску
<?php
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;

class Schulze
{
    private $app;
    private $request;
    private $candidates;
    private $paths;

    public function __construct(Application $app, Request $request)
    {
        $this->app = $app;
        $this->request = $request;
    }

    public function mainReturn()
    {
        $votes = $this->request->get('votes');

        if(!$this->getCandidates($this->request) || !$votes)
        {
            return $this->returnError();
        }

        $votes_arr = explode('|', $votes);
        foreach ($votes_arr as $vote)
        {
            $names = explode(',', $vote);
            foreach ($names as $i)
            {
                $is_next = false;
                $f_i = htmlspecialchars($i);
                foreach ($names as $j)
                {
                    $f_j = htmlspecialchars($j);
                    if ($is_next && array_key_exists($f_i, $this->candidates) && array_key_exists($f_j, $this->candidates[$f_i]))
                    {
                        $this->candidates[$f_i][$f_j] += 1;
                    }

                    if ($f_i == $f_j)
                    {
                        $is_next = true;
                    }
                }
            }
        }

        foreach ($this->candidates as $i => $v)
        {
            foreach ($this->candidates as $j => $v)
            {
                if ($i !== $j)
                {
                    if ($this->candidates[$i][$j] > $this->candidates[$j][$i])
                    {
                        $this->paths[$i][$j] = $this->candidates[$i][$j];
                    }
                    else
                    {
                        $this->paths[$i][$j] = 0;
                    }
                }
            }
        }

        foreach ($this->candidates as $i => $v)
        {
            foreach ($this->candidates as $j => $v)
            {
                if ($i !== $j) {
                    foreach ($this->candidates as $k => $v)
                    {
                        if ($i !== $k && $j !== $k)
                        {
                            $this->paths[$j][$k] = max( $this->paths[$j][$k], min( $this->paths[$j][$i], $this->paths[$i][$k] ) );
                        }
                    }
                }
            }
        }

        $table = $this->htmlTable();
        return $this->app['twig']->render('base.twig', array( 'title' => 'Выборы по Шульце', 'content' => $table ));
    }

    private function returnError ()
    {
        return $this->app['twig']->render('base.twig', array( 'title' => 'Ошибка', 'content' => 'Никаких данных не передано' ));
    }

    private function getCandidates (Request $request)
    {
        $dataset = $request->get('dataset');
        if(!$dataset)
        {
            return false;
        }

        $candidates = explode('|', $dataset);

        foreach ($candidates as $c)
        {
            $f_c = htmlspecialchars($c);
            $this->candidates[$f_c] = array();
            $this->paths[$f_c] = array();

            foreach ($candidates as $k)
            {
                $f_k = htmlspecialchars($k);
                if ($f_c !== $f_k)
                {
                    $this->candidates[$f_c][$f_k] = 0;
                    $this->paths[$f_c][$f_k] = 0;
                }
            }
        }

        return true;
    }

    private function htmlTable()
    {
        $asort = array();
        foreach ($this->paths as $k => $v)
        {
            $asort[$k] = 0;
            foreach ($this->paths as $j => $v)
            {
                if($k !== $j) {
                    if ($this->paths[$k][$j] > $this->paths[$j][$k])
                    {
                        $asort[$k] += 2;
                    }

                    if ($this->paths[$k][$j] === $this->paths[$j][$k])
                    {
                        $asort[$k] += 1;
                    }
                }
            }
        }
        arsort($asort);

        $c = "<div class=\"subheader\" style=\"padding-top:1.75em\">Попарные победы</div>\n<table class=\"maintable\">\n<tr><th><!--empty--></th> ";
        $t = "<div class=\"subheader\" style=\"padding-top:0.5em\">Сильнейший путь</div>\n<table class=\"maintable\">\n<tr><th><!--empty--></th> ";
        foreach ($asort as $k => $v)
        {
            $line = sprintf("<th title=\"%s\">%s</th> ", $k, substr($k, 0, 3));
            $t .= $line;
            $c .= $line;
        }
        $t .= "</tr>\n";
        $c .= "</tr>\n";

        foreach ($asort as $k => $v)
        {
            $line = sprintf("<tr><td>%s</td> ", $k, substr($k, 0, 3));
            $t .= $line;
            $c .= $line;

            foreach ($asort as $j => $v)
            {
                if($k === $j)
                {
                    $p = '';
                    $z = '';
                    $p_class = 'blank';
                    $z_class = 'blank';
                }
                else
                {
                    $p = $this->paths[$k][$j];
                    $z = $this->candidates[$k][$j];

                    if ($this->paths[$k][$j] === $this->paths[$j][$k])
                    {
                        $p_class = 'white';
                    }

                    if ($this->candidates[$k][$j] === $this->candidates[$j][$k])
                    {
                        $z_class = 'white';
                    }

                    if ($this->paths[$k][$j] > $this->paths[$j][$k])
                    {
                        $p_class = 'green';
                    }

                    if ($this->candidates[$k][$j] > $this->candidates[$j][$k])
                    {
                        $z_class = 'green';
                    }

                    if ($this->paths[$k][$j] < $this->paths[$j][$k])
                    {
                        $p_class = 'red';
                    }

                    if ($this->candidates[$k][$j] < $this->candidates[$j][$k])
                    {
                        $z_class = 'red';
                    }
                }

                $t .= sprintf("<td class=\"%s\">%d</td> ", $p_class, $p);
                $c .= sprintf("<td class=\"%s\">%d</td> ", $z_class, $z);
            }
            $t .= "</tr>\n";
            $c .= "</tr>\n";
        }
        $t .= "</table>\n";
        $c .= "</table>\n";

        return $t . $c;
    }
}