tutorials.de Buch-Aktion 05/2012
ERLEDIGT
NEIN
ANTWORTEN
0
ZUGRIFFE
229
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
  1. #1
    Avatar von Dennis Wronka
    Dennis Wronka Dennis Wronka ist offline Soulcollector
    Registriert seit
    Apr 2002
    Ort
    Hong Kong
    Beiträge
    12.296
    Blog-Einträge
    231
    So, erstmal ein wenig zur Erklaerung.

    Mein Script (jodler.php) liest die Daten aus einer Text-Datei (jodler.txt) und gewichtet anschliessend die Strecken.
    Dazu wird jede Strecke rueckwaerts durchlaufen. Dadurch spaere ich mir hier die ansonsten noetige Rekursion.

    Dazu moechte ich sagen dass dies im Grunde die 7. Version der Gewichtung ist. Die erste Version, von der diese hier nun direkt abstammt, war aehnlich einfach, hatte aber ein paar Probleme mit der Gewichtung.
    Die erste bis sechte Version hatten alle Probleme mit der Gewichtung. Dadurch konnte es, unter gewissen Umstaenden, dazu kommen dass der falsche Weg eingeschlagen wurde wenn der insgesamt laengste Weg im Zweig mit dem insgesamt niedrigeren Gewicht lag.
    Das koennte passieren da immer die Gewichte der linken und rechten Zelle der naechsten Zeile addiert wurden.
    Dieses Problem ist nun geloest dadurch dass immer nur das Gewicht des dominanten (hoeheres Gewicht, oder bei Gewichtgleichheit der Pfad mit dem laengeren Teilstueck)Zweiges weitergetragen wird.

    Anschliessend erfolgt die Berechnung der laengsten Strecke.
    Dies geschieht rekursiv indem schlichtweg der Gewichtung gefolgt wird. Bei Stellen mit gleichem Gewicht erhaelt der laengere Abschnitt Vorrang.

    Die aus diesen Bearbeitungen gewonnenen Daten werden nun in einer Schleife durchlaufen um festzustellen welche Piste die laengste Abfahrt bietet.

    Zu guter Letzt wird diese Piste ausgegeben (mit verschiedenen Methoden zur Ausgabe an den Browser oder in der Command-Line), inklusive Hervorhebung der laengsten Abfahrt.

    Der letzte Abschnitt des Codes ist zum Debugging, hier werden alle Strecken mit Highlighting und Gewichtung ausgegeben. Hier fehlt die Verzweigung zwischen Web und CLI.

    Uebrigens, damit weighcourse() sowohl das Gewicht in die Gewichtung des Teilabschnitte in das Array eintragen kann als auch das Ergebnis der Auswertung dieser Gewichtung der tracepath() zurueckgeben kann nutze ich eine Referenz.
    Das Array wird weighcourse() als Referenz uebergeben. Dadurch wird dieses Array direkt bearbeitet und muss nicht zurueckgegeben werden. Der Rueckgabewert kann also fuer tracepath() genutzt werden.

    So, jetzt aber mal zum Code. Mit Kommentaren, und im Grunde mehr als ich sonst mache...
    Code php:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    
    <?php
    error_reporting(E_ALL);
     
    /**
     * Diese Funktion "wiegt" den Kurs und all seine Abschnitte.
     * Anhand des Gesamtgewichts eines Abschnitts wird spaeter der zu nehmende Pfad bestimmt.
     * Die Abarbeitung von unten nach oben, also den Berg hinauf, macht Rekursion unnoetig.
     *
     * @param array $course
     * @return array
     */
    function weighcourse(&$course)
    {
        //Durchlaufe die Piste von unten nach oben
        for ($row=count($course);$row>0;$row--)
        {
            //Durchlaufe die Zellen von links nach rechts
            for ($cell=0;$cell<count($course[$row-1]);$cell++)
            {
                //Initialisiere das Pfad-Gewicht mit der eigenen Laenge
                $course[$row-1][$cell]['weight']=$course[$row-1][$cell]['length'];
     
                //Falls es eine naechste Reihe gibt wird noch was am Gewicht geaendert
                if (isset($course[$row]))
                {
                    //Ist das Gewicht der linken Zelle der naechsten Reihe kleiner als das der rechten Zelle addiere das Gewicht der rechten Zelle zum Gewicht der aktuellen Zelle hinzu
                    if ($course[$row][$cell]['weight']<$course[$row][$cell+1]['weight'])
                    {
                        $course[$row-1][$cell]['weight']+=$course[$row][$cell+1]['weight'];
                    }
                    //Sind die Gewichte gleich wird anhand der Laenge des Teilstuecks entschieden
                    elseif ($course[$row][$cell]['weight']==$course[$row][$cell+1]['weight'])
                    {
                        if ($course[$row-1][$cell]['length']<$course[$row][$cell+1]['length'])
                        {
                            $course[$row-1][$cell]['weight']+=$course[$row][$cell+1]['weight'];
                        }
                        else
                        {
                            $course[$row-1][$cell]['weight']+=$course[$row][$cell]['weight'];
                        }
                    }
                    //Ist das Gewicht der linken Zelle der naechsten Reihe groesser als das der rechten Zelle addiere das Gewicht der linken Zelle zum Gewicht der aktuellen Zelle hinzu
                    else
                    {
                        $course[$row-1][$cell]['weight']+=$course[$row][$cell]['weight'];
                    }
                }
            }
        }
     
        return tracepath($course);
    }
     
    /**
     * Diese Funktion wertet den Kurs von oben nach unten aus.
     * Dabei wird der laengste Pfad berechnet und die entsprechend Indizes festgehalten.
     * Der Kurs wird anhand der zuvor in weighcourse() vorgenommenen Pfad-Gewichtung verfolgt.
     * Der Teil-Abschnitt mit dem hoechsten Gesamtgewicht hat Vorrang.
     *
     * @param array $course
     * @param int $row
     * @param int $cell
     * @return array
     */
    function tracepath($course,$row=0,$cell=0)
    {
        //Setze die Laenge auf die Laenge des aktuellen Abschnitts
        $length=$course[$row][$cell]['length'];
     
        //Initialisiere den Pfad mit dem Index der aktuellen Zelle
        $path=array($cell);
     
        //Falls es eine naechste Zeile gibt wird diese ausgewertet und tracepath() nochmal aufgerufen
        if (isset($course[$row+1]))
        {
            //Ist das Gewicht der linken Zelle kleiner, oder, bei gleichem Gewicht die Laenge, wird als naechstes die rechte Zelle angesteuert
            if ((isset($course[$row+1][$cell+1])) && (($course[$row+1][$cell]['weight']<$course[$row+1][$cell+1]['weight']) || (($course[$row+1][$cell]['weight']==$course[$row+1][$cell+1]['weight']) && ($course[$row+1][$cell]['length']<$course[$row+1][$cell+1]['length']))))
            {
                $nextcell=$cell+1;
            }
            //Ansonsten die linke...
            else
            {
                $nextcell=$cell;
            }
     
            //Rekursiver Aufruf von tracepath() zur weiteren Auswertung des Pfades
            $next=tracepath($course,$row+1,$nextcell);
     
            //Erhoehe die Laenge der Piste um die zurueckgegebene Laenge (welches die Laenge der Piste von der naechsten Zelle bis ganz unten ist) und haenge den zurueckgegebenen Pfad (auch von der naechsten Zelle bis ganz unten) an den aktuellen Pfad
            $length+=$next['length'];
            $path=array_merge($path,$next['path']);
        }
     
        //Rueckgabe der ermittelten Werte
        return array('length'=>$length,'path'=>$path);
    }
     
    //Daten einlesen
    $data=file_get_contents('jodler.txt');
     
    //Zeilen trennen
    $lines=explode("\n",$data);
     
    //Erstellung und Fuellung des Pisten-Arrays
    $courses=array();
    for ($line=0;$line<count($lines);$line++)
    {
        //Wenn die Zeile nicht leer ist und nicht mit einem numerischen Wert anfaengt dann ist es eine neue Piste
        if ((!empty($lines[$line])) && (!is_numeric(substr($lines[$line],0,1))))
        {
            //Speicherung des Namens der Piste
            $name=$lines[$line];
     
            //Speicherung der Hoehe der Piste
            if (isset($lines[$line+1]))
            {
                $line++;
                $height=$lines[$line];
            }
     
            //Erstellung und Fuellung des Kurs-Arrays
            $course=array();
            while ((isset($lines[$line+1])) && (is_numeric(substr($lines[$line+1],0,1))))
            {
                $line++;
                $path=explode(' ',$lines[$line]);
                for ($sector=0;$sector<count($path);$sector++)
                {
                    $path[$sector]=array('length'=>$path[$sector],'weight'=>false);
                }
                $course[]=$path;
            }
     
            //Nachdem sichergestellt wurde dass die Piste nicht leer ist wird sie ausgewertet und gespeichert
            if (!empty($course))
            {
                //Pfad-Gewichtung und Berechnung des laengsten Pfades
                $longestpath=weighcourse($course);
     
                //Uebertragung der Daten in das Pisten-Array
                $courses[]=array('name'=>$name,'height'=>$height,'course'=>$course,'longestpath'=>$longestpath);
            }
        }
    }
     
    //Bestimmung der laengsten Piste
    $longestcourse=false;
    for ($x=0;$x<count($courses);$x++)
    {
        if (($longestcourse===false) || ($courses[$x]['longestpath']['length']>$longestcourse['longestpath']['length']))
        {
            $longestcourse=$courses[$x];
        }
    }
     
    //Ausgabe
    //HTML
    if (isset($_SERVER['REMOTE_ADDR']))
    {
        //Name und Laenge der Piste
        echo '<div style="text-align:center; font-weight:bold;">'.$longestcourse['name'].' ('.$longestcourse['longestpath']['length'].')</div>';
     
        //Ausgabe der Abschnitte der Piste
        for ($row=0;$row<count($longestcourse['course']);$row++)
        {
            echo '<div style="text-align:center;">';
            for ($cell=0;$cell<count($longestcourse['course'][$row]);$cell++)
            {
                echo '<span style="margin-left:5px; margin-right:5px;';
     
                //Highlighting falls der aktuelle Abschnitt Teil des laengsten Pfades ist
                if ($cell==$longestcourse['longestpath']['path'][$row])
                {
                    echo ' color:#ff0000;';
                }
                echo '">'.$longestcourse['course'][$row][$cell]['length'].'</span>';
            }
            echo '</div>';
        }
    }
    //Text
    else
    {
        //Name und Laenge der Piste
        echo $longestcourse['name'].' ('.$longestcourse['longestpath']['length'].')'."\n";
     
        //Die Laenge der Piste wird fuer die Einrueckungen bei der Ausgabe genutzt
        $height=$longestcourse['height'];
     
        //Ausgabe der Abschnitte der Piste
        for ($row=0;$row<count($longestcourse['course']);$row++)
        {
            //Einrueckung der Ausgabe
            for ($tab=0;$tab<$height-$row;$tab++)
            {
                echo "\t";
            }
     
            for ($cell=0;$cell<count($longestcourse['course'][$row]);$cell++)
            {
                //Highlighting falls der aktuelle Abschnitt Teil des laengsten Pfades ist
                if ($cell==$longestcourse['longestpath']['path'][$row])
                {
                    echo '>>';
                }
     
                echo $longestcourse['course'][$row][$cell]['length'];
     
                //Highlighting falls der aktuelle Abschnitt Teil des laengsten Pfades ist
                if ($cell==$longestcourse['longestpath']['path'][$row])
                {
                    echo '<<';
                }
     
                echo "\t\t";
            }
            echo "\n";
        }
    }
     
    //Debug-Code der alle Strecken ausgibt
    //Nur HTML
    /*for ($x=0;$x<count($courses);$x++)
    {
        //Name und Laenge der Piste
        echo '<div style="text-align:center; font-weight:bold;">'.$courses[$x]['name'].' ('.$courses[$x]['longestpath']['length'].')</div>';
     
        //Ausgabe der Abschnitte der Piste
        for ($row=0;$row<count($courses[$x]['course']);$row++)
        {
            echo '<div style="text-align:center;">';
            for ($cell=0;$cell<count($courses[$x]['course'][$row]);$cell++)
            {
                echo '<span style="margin-left:5px; margin-right:5px;';
     
                //Highlighting falls der aktuelle Abschnitt Teil des laengsten Pfades ist
                if ($cell==$courses[$x]['longestpath']['path'][$row])
                {
                    echo ' color:#ff0000;';
                }
                echo '">'.$courses[$x]['course'][$row][$cell]['length'].'('.$courses[$x]['course'][$row][$cell]['weight'].')</span>';
            }
            echo '</div>';
        }
    }*/
    ?>

    Kurioses:
    • tracepath() hiess urspruenglich followthewhiterabbit().
    • Versionen 3 bis 5 hatten pro Zelle 2 Gewichte, eines fuer den linken Pfad, eines fuer den rechten Pfad.
    • Version 5 nutzte die kosmologische Konstante COSMOLOGIC um der Abschnittslaenge ein hoeheres Gewicht bei der Berechnung zu geben.
      Diese Konstante musste aber sehr fein getunt werden und ist extem Abhaengig von den Eigenschaften der ausgewerteten Pisten.
    Angehängte Dateien Angehängte Dateien
     
    PHP Class Collection - PHP-Klassen fuer PHP 5 (und Teilweise auch fuer PHP 4)
    Updates: Catcher 1.1, FTPConnection 1.2, MultiSQL 1.1, RSS2 1.1, SMTPConnection 1.4
    __________________
    EasyLFS - Hintergrundinformationen, Installationsanleitung, Softwareliste und Download
    EasyLFS Projektthread - Informationen, Status und Diskussion zu meiner Linux-Distribution
    __________________
    Ich bin die Schildkroete, mein Sohn. Ich habe das Universum erschaffen, aber bitte mach mir daraus keinen Vorwurf; ich hatte Bauchschmerzen.
    __________________
    Zitat Zitat von Friedrich Nietzsche
    Man muss noch Chaos in sich haben, um einen tanzenden Stern gebaeren zu koennen.

Thema nicht erledigt

Ähnliche Themen

  1. [QUIZ#8] (Squares) Dennis Wronka (Fortran)
    Von Dennis Wronka im Forum Archiv
    Antworten: 4
    Letzter Beitrag: 12.07.09, 06:34
  2. [QUIZ#8] (Twister) Dennis Wronka (Python)
    Von Dennis Wronka im Forum Archiv
    Antworten: 0
    Letzter Beitrag: 06.07.09, 18:46
  3. [QUIZ#8] (GuessIt) Dennis Wronka (Java)
    Von Dennis Wronka im Forum Archiv
    Antworten: 0
    Letzter Beitrag: 06.07.09, 11:10
  4. [QUIZ#8] (FibFact) Dennis Wronka (VB.net)
    Von Dennis Wronka im Forum Archiv
    Antworten: 0
    Letzter Beitrag: 06.07.09, 09:12
  5. [QUIZ#8] (Greeter) Dennis Wronka (Ada)
    Von Dennis Wronka im Forum Archiv
    Antworten: 0
    Letzter Beitrag: 05.07.09, 07:37