Kattis Run Time Error

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
lalelu169
User
Beiträge: 12
Registriert: Dienstag 7. April 2020, 10:56

Hallo,
ich habe vor kurzem angefangen Aufgaben auf Kattis zu bearbeiten. Nun hänge ich bei der folgenden Aufgabe fest.
https://open.kattis.com/pro ... narea

Der Code funktioniert innerhalb von PyCharm, allerdings bekomme ich bei Kattis einen RunTimeError, was ich leider nicht verstehe. Kann mir bitte jemand einen Tipp geben.

Code: Alles auswählen

# ProblemID:      polygonarea
# Difficulty:     3.1
# date:           31JAN2022

import sys
import math


def parse_input():
    """reads data and gives back a list of polygons each containing a list of coordinates"""

    lines = [line.split() for line in sys.stdin.readlines()]
    lines = [[int(x) for x in line] for line in lines]

    idx = 0
    polygons = []
    while lines[idx][0] != 0:
        anz_dots = lines[idx][0]

        coordinates = [[int(x) for x in lines[i]] for i in range(idx + 1, idx + anz_dots + 1)]
        polygons.append(coordinates)
        idx = idx + anz_dots + 1

    return polygons


def solution(data):
    """calculates area according to the shoelace formula"""
    for polygon in data:
        z1 = [polygon[i][0] for i, _ in enumerate(polygon)]
        z1.append(z1[0])

        z2 = [polygon[i][1] for i, _ in enumerate(polygon)]
        z2.append(z2[0])

        s1 = sum([math.prod(x) for x in list(zip(z1, z2[1:]))])
        s2 = sum([math.prod(x) for x in list(zip(z1[1:], z2))])
        area = (s1 - s2) / 2
        if area < 0:
            print(f'CW {-area:.1f}')
        else:
            print(f'CCW {area:.1f}')

    return -1


polygons = parse_input()
solution(polygons)
P.S: Generelle Tipps zum 'pythonic way' sind natürlich auch herzlich willkommen :)
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@lalelu169: Was denn für eine Ausnahme und wo genau wird die ausgelöst?

Beide Funktionen sind auch zu umständlich formuliert und mit Indexzugriffen die da nicht sein sollten.

`x` ist kein guter Name für ein Tupel mit zwei Elementen und `math.prod()` ist nicht wirklich sinnvoll wenn man immer genau zwei Zahlen multiplizieren will. Da wäre ``*`` einfacher/verständlicher.

Was sollen die `enumerate()`-Aufrufe bei denen grundsätzlich das zweite Element ignoriert wird, die Zahl dann aber nur als Index verwendet wird um an genau das Element zu kommen, das mit `enumerate()` zwar auch generiert aber dann ignoriert wird.

Das ``if area < 0:`` und das ``else`` ist eigentlich die eingebaute `abs()`-Funktion.

Was soll der unsinnige -1 Rückgabewert?

Bei `parse_input()` ist der `readlines()`-Aufruf überflüssig; ein iterieren über das Dateiobjekt liefert auch so die Zeilen.

Und wie gesagt, nicht so viel komischen undurchsichtigen Indexzugriffsmist bitte. Die Daten sind klar strukturiert — eine Zeile mit einer Zahl die angibt wie viele folgenden Zeilen Koordinaten enthalten. Das kann man deutlich einfacher und an dieser Struktur orientiert ohne Indexzugriff formulieren.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
lalelu169
User
Beiträge: 12
Registriert: Dienstag 7. April 2020, 10:56

Vielen Dank für den Review.
Auf Kattis sieht man leider nicht in welcher Zeile das Problem auftritt. Ich habe die DInge umgesetzt und auf einmal hat es funktioniert. Es lag an math.prod().

Mit Deinem Kommentar zu abs(area) konnt ich nichts anfangen.

Code: Alles auswählen

if abs(area) == area:
	print('CCW', abs(area))
else:
	print('CW', abs(area))
ist doch ähnlich zu meinem Code

Hier mein neuer Code, der wirklich besser aussieht

Code: Alles auswählen

# ProblemID:      polygonarea
# Difficulty:     3.1
# date:           31JAN2022

import sys

def parse_input():
    """reads data and gives back a list of polygons each containing a list of coordinates"""
    polygons = []
    while True:
        anz_zeilen = int(sys.stdin.readline())
        if anz_zeilen == 0:
            break

        coords = [input().split() for _ in range(anz_zeilen)]
        coords = [[int(pos) for pos in coord] for coord in coords]
        polygons.append(coords)

    return polygons


def solution(data):
    """calculates area according to the shoelace formula"""
    for polygon in data:
        z1 = [polygon[i][0] for i in range(len(polygon))]
        z1.append(z1[0])

        z2 = [polygon[i][1] for i in range(len(polygon))]
        z2.append(z2[0])

        s1 = sum([a * b for a, b in list(zip(z1, z2[1:]))])
        s2 = sum([a * b for a, b in list(zip(z1[1:], z2))])
        area = (s1 - s2) / 2
        if area < 0:
            print(f'CW {-area:.1f}')
        else:
            print(f'CCW {area:.1f}')

    return


polygons = parse_input()
solution(polygons)
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Da sind immer noch unnötige Indexzugriffe drin. ``for i in range(len(sequence)`` nur um `i` dann als Index in `sequence` zu verwenden ist in Python ein „anti pattern“ weil man direkt über die Elemente von Sequenzen iterieren kann, ohne den Umweg über einen Laufindex.

Und die Listen bei `zip()` kann man sich sparen, und auch das `sum()` eine Liste übergeben wird.

Ungetestst:

Code: Alles auswählen

def solve(polygons):
    """
    Calculate areas according to the shoelace formula.
    """
    for polygon in polygons:
        xs = [x for x, _ in polygon]
        xs.append(xs[0])
        ys = [y for _, y in polygon]
        ys.append(ys[0])

        area = (
            sum(a * b for a, b in zip(xs, ys[1:]))
            - sum(a * b for a, b in zip(xs[1:], ys))
        ) / 2
        direction = "CW" if area < 0 else "CCW"
        print(f"{direction} {abs(area):.1f}")
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
lalelu169
User
Beiträge: 12
Registriert: Dienstag 7. April 2020, 10:56

cool. Vielen Dank. Da habe ich ja noch viel zu lernen :shock: :o
Antworten