AUFGABE: Jeden tag eine Änderung des Bankcodes...

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.
PythonRookie9000
User
Beiträge: 2
Registriert: Mittwoch 1. Februar 2017, 17:16

[codebox=pycon file=Unbenannt.txt][/code]

Hey Leute!

Ich bin hier neu und ein Anfänger in Python. Ich versuche es mir selbst bei zu bringen, was etwas hartnäckig ist. Deswegen brauche ich Hilfe bei folgender Aufgabe:

"Ein Bankdirektor stellte auf dem Ziffernschloss zum Tresorraum die Codezahl 1986 ein. Aus Sicherheitsgründen sollte der Code täglich geändert werden. Dazu dachte sich der Direktor folgende Methode aus:

Er bildete die Summe der aktuellen vier Ziffern (am ersten Tag also 24) und fügte die Einerstelle dieser Summe (bei 24 also 4) der Codezahl rechts an, dafür wurde die erste linksstehende Ziffer (am ersten Tag die 1) gestrichen.

Nun wollte der Bankdirektor wissen, ob bei diesem Vorgehen die Zahl 1986 noch einmal als Code auftreten werde. Als ihm dies ein Computerexperte bestätigte, interessierte er sich brennend dafür, wieviele Tage vergehen werden, bis die Codezahl wieder 1986 lautet."

Das ist soweit meine Lösung:

Code: Alles auswählen

Code = "1986"
Tag = 1

while Tag != 3000:
    Summe = str(int(Code[0])+int(Code[1])+int(Code[2])+int(Code[3]))
    Code = Code.replace(Code[0], "")
    Code = str(Code + Summe[1])
    print(Code)
    Tag += 1
    if Code == "1986":
        print(Tag)
        break
Ich habe jetzt einfach mal eine Schleife bis zum Tag 3000 erstmal genommen. Eig. funktioniert alles bis zum 10. Code, welcher dann plötzlich dreistellig ist, obwohl die Summe des Code davor wunderbar aussieht. Naja es wird mir ein IndexError angezeigt(string out of range) auf Zeile 5 hingewiesen.

Ich würde mich freuen, wenn ihr mir ein bisschen helfen könntet, da ich hier überfragt bin.

Viele Grüße!!

PS: Falls jemand Webseiten mit guten Python-Aufgaben für Anfänger kennt, immer rein damit!! :D
Zuletzt geändert von Anonymous am Mittwoch 1. Februar 2017, 17:31, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@PythonRookie9000: Schau Dir doch einfach mal die Operation an bei der die Zahl dreistellig wird. Was passiert in dem Schritt denn genau? Wie sieht die Zahl vorher aus und welche Ziffern fehlen danach? Das sollte eigentlich offensichtlich sein was da passiert und warum es so nicht funktionieren kann wenn man es mal Schritt für Schritt durchgeht.

Als Endbedingung für die ``while``-Schleife hätte man auch einfach `True` verwenden können, also eine ”Endlosschleife” die ja abgebrochen wird wenn der Code wieder '1986' ist.

Man könnte aber auch eine ``for``-Schleife mit `itertools.count()` verwenden um das manuelle hochzählen des Tags zu vermeiden.

Der `str()`-Aufruf in Zeile 7 ist sinnfrei weil da bereits eine Zeichenkette übergeben wird und der Index 1 der in dieser Zeile verwendet wird ist ein weiterer Programmierfehler. Der stimmt nämlich nur wenn die Summe zweistellig ist. Man kann aber auch vier Ziffern haben die nur eine einstellige Summe haben, was dann zu einem `IndexError` führt.

Namenskonvention ist übrigens das nur Klassennamen mit einem Grossbuchstaben beginnen und Konstanten durchgehend in Grossbuchstaben geschrieben werden.
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@PythonRookie9000: schau mal in der Dokumentation nach, was Code.replace genau macht und wann das ein Problem werden könnte. Warum könnte Zeile 7 auch ein Problem machen?

Allgemein: Wenn man weiß, wie viele Durchläufe eine while-Schleife laut Schleifenbedingung macht, sollte man eine for-Schleife verwenden. Variablennamen werden komplett klein geschrieben.
PythonRookie9000
User
Beiträge: 2
Registriert: Mittwoch 1. Februar 2017, 17:16

@BlackJack
@Sirius3
Aaaaalllsooo,

Ich habe jetzt anstatt das replace Kommando, einfach code[1:] genommen. Es war echt nicht so einfach das Problem zu erkennen( wegen dem mangelnden Verständnis der Vorgehensweise der Sprache) und dann noch zu lösen. Ich habe die ganze Zeit nach anderen Kommandos gesucht, aber dann war es doch so einfach...

In Linie 7 habe ich anstatt summe[1] , summe[-1] benutzt. Hätte ich gleich sehen müssen... Zu dem str in der Linie 7 sag ich mal lieber nichts mehr...

Und ab heute werden Variablennamen klein geschrieben!!

Vielen Dank für eure schnelle Antwort und dass ihr mir nicht gleich die Lösung verratet habt!

Ich denke mal ihr wollt unbedingt die wissen wie viele Tage es dauert bis der Code wieder 1986 lautet...1561. Unglaublich, ich weiß!
BlackJack

@PythonRookie9000: Dabei hast Du jetzt aber den ersten Tag mitgezählt, ich komme nämlich nur auf 1560 Tage. Mit QBasic:

Code: Alles auswählen

CONST StartCode$="1986"
Day=0
Code$=StartCode$
DO
  Sum=0
  FOR i=1 TO 4
    Sum=Sum+VAL(MID$(Code$,i,1))
  NEXT
  Code$=MID$(Code$,2)+LTRIM$(STR$(Sum MOD 10))
  Day=Day+1
  PRINT "Day:";Day;" Code: ";Code$
LOOP UNTIL Code$=StartCode$
sebastian0202
User
Beiträge: 168
Registriert: Montag 9. Mai 2016, 09:14
Wohnort: Berlin

Ich will auch :lol:
Nicht besonderes, aber zum warm werden bevor man anfängt zu arbeiten.

Code: Alles auswählen

def mathe():
    ur_code = "1986"
    Code = "1986"
    Tag = 0
    while True:
        ergebnis = 0
        for zahl in Code:
            ergebnis += int(zahl)
        Code += str(ergebnis)[-1]
        Code = Code[1:]
        Tag += 1
        if Code == ur_code: 
            break
    print("Es sind %s Tage vergangen, bis sich der Code wiederholt hat!" % Tag)


if __name__ == '__main__':
    mathe()
BlackJack

Code: Alles auswählen

#!/usr/bin/env python
from __future__ import absolute_import, division, print_function
from itertools import count


def main():
    start_code = '1986'
    code = start_code
    for day in count(1):
        code = code[1:] + str(sum(map(int, code)) % 10)
        if code == start_code:
            break
    print('Nach {} Tagen ist der Code wieder {}.'.format(day, start_code))


if __name__ == '__main__':
    main()
BlackJack

@sebastian0202: Wenn Du die Funktion schon `mathe()` nennst, hätte ich ja mindestens erwartet, dass Du keine Zeichenketten sondern ausschliesslich Zahlen und mathematische Operationen verwendest. :P

@PythonRookie9000: Das wäre vielleicht eine interessante weitere Teilaufgabe, den Code als *eine* Zahl zu repräsentieren und nicht auf Zeichenkettenoperationen zurück zu greifen.
sebastian0202
User
Beiträge: 168
Registriert: Montag 9. Mai 2016, 09:14
Wohnort: Berlin

War etwas schwierig und lässt sich sicher auch eleganter lösen.
Aber hier die mathe Funktion nur mit Zahlen.

Code: Alles auswählen

def mathe(ur_code):
    Code = ur_code
    Zahl = ur_code
    Tag = 0
    while True:
        zwischen_ergebnis = 0
        rest_raw = 0
        for potenz in (10,100,1000,10000):
            rest_raw = Zahl % potenz
            rest = Zahl % potenz
            while rest > 9:
                rest /= 10
            zwischen_ergebnis += rest
            Zahl -= rest_raw

        Code -= rest_raw
        Code *= 10
        Code += zwischen_ergebnis % 10
        Zahl = Code
        
        Tag += 1
        if Zahl == ur_code:
            break
    return Tag
 
if __name__ == '__main__':
    code = 1986
    tag = mathe(code)
    print("Es vergehen %i Tage, bis sich der Code %i wiederholt!" % (tag, code))
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@sebastian0202: bei der Länge der Funktion ist es schon sinnvoll, mehrere Funktionen zu schreiben; z.B. kann man das Bilden der Quersumme gut in eine eigene Funktion packen.

Code: Alles auswählen

from itertools import count
def cross_sum(number, base=10):
    result = 0
    while number:
        number, residual = divmod(number, base)
        result += residual
    return result

def calculate_series_length(code):
    original_code = code
    for cnt in count(1):
        code = (code % 1000) * 10 + cross_sum(code) % 10
        if original_code == code:
            break
    return cnt
sebastian0202
User
Beiträge: 168
Registriert: Montag 9. Mai 2016, 09:14
Wohnort: Berlin

Habe gesehen, dass es Probleme geben kann sobald eine 0 in der Zahl vorkommt.
Muss die Zahl also erst erweitern bevor ich mit ihr rechne.
Dafür darf der Code jetzt beliebig lang sein.

Nachtrag: Die vorige Funktion hatte ja nur 24 Zeilen. Für mich war sie übersichtlich.
Ich konnte mich damit noch nicht anfreunden, für jedes mögliche Problem was sich auslagern lässt, auch auszulagern.
Damit hat man unzählige Funktionen und da verliere ich schnell den Überblick.

Code: Alles auswählen

def stellen(zahl):
    anzahl = 1
    while zahl > 9:
        zahl /= 10
        anzahl += 1
    return anzahl

def code_erweitern(code, stellen):
    zahl = 1
    for i in range(stellen):
        zahl *= 10
    code += zahl
    return code

def rest_potenz(anzahl_stellen, zahl):
    zwischen_ergebnis = 0
    rest = 0
    potenz = 0.1
    for i in range(anzahl_stellen):
        rest = zahl % 10
        zwischen_ergebnis += rest
        zahl -= rest
        zahl /= 10
        potenz *= 10
    return rest, zwischen_ergebnis, potenz

def stelle_verrutschen(zahl, rest, zwischen_ergebnis, potenz):
    zahl -= (rest * potenz) 
    rest = zahl % potenz
    zahl -= rest
    zahl += rest*10
    zahl += zwischen_ergebnis % 10
    return zahl

def mathe(ur_code):
    anzahl_stellen = stellen(ur_code)
    Code = code_erweitern(ur_code, anzahl_stellen)
    Zahl = Code

    Tag = 0
    while True:
        rest, zwischen_ergebnis, potenz = rest_potenz(anzahl_stellen, Zahl)
        Code = stelle_verrutschen(Code, rest, zwischen_ergebnis, potenz)
        Zahl = Code
        Tag += 1
        if Zahl-potenz*10 == ur_code:
            break
    return Tag
 
if __name__ == '__main__':
    code = 1986
    tag = mathe(code)
    print("Es vergehen %i Tage, bis sich der Code %i wiederholt!" % (tag, code))

BlackJack

@sebastian0202: Die Aufteilung auf die Funktionen ist ja auch total komisch. Das sieht irgendwie so willkürlich aus und nicht so als wenn man wirklich sinnvoll Teilprobleme in Funktionen ausgelagert hätte. So etwas wie `quersumme()` was eine Zahl bekommt und eine Zahl zurück gibt. Und `ziffern_verschieben()` das den Code und eine einstellige Zahl bekommt und eine Zahl zurück gibt die um eine Zehnerstelle verschoben ohne die erste Ziffer und mit der neuen Ziffer zurück gibt, also beispielsweise `ziffern_verschieben(4711, 3)` → 7113.
BlackJack

Das ganze mit Zahlen in Assembler für DOS (129 Bytes .COM-Datei):
[codebox=asm file=Unbenannt.asm] cpu 386
org 0x0100
[map all]

start_code equ 1986

segment .code

; `code` is stored in SI register.
; `sum` is stored in DI register.

start:
xor ax,ax ; day := 0
mov [day],ax
mov si,start_code ; code := start_code

day_loop:
xor ax,ax ; sum := 0
mov di,ax

mov ax,si ; divide code value by 10 until it reaches 0
mov bx,10 ; summing the remainder in `sum`.
sum_loop:
or ax,ax
jz sum_loop_exit
xor dx,dx
div bx
add di,dx
jmp sum_loop
sum_loop_exit:

mov ax,di ; CX = last decimal digit of `sum`
xor dx,dx
div bx
mov cx,dx

mov ax,si ; multiply `code` by 10 and add the digit in CX.
mul bx
add ax,cx

mov bx,10000 ; get rid of digits beyound the four of the code.
div bx
mov si,dx

inc word [day] ; INC(day)

; check if we reached the day with the same code we started with
cmp si,start_code
jne day_loop

mov ax,[day] ; print day and code.
call print_number

mov ah,2
mov dl,' '
int 0x21

mov ax,si
call print_number

mov ah,2
mov dl,13
int 0x21

mov ah,2
mov dl,10
int 0x21

exit:
mov ax,0x4c00 ; AL = exit code.
int 0x21

;--------------------------------------------------------------------
print_number:
xor cx,cx
mov bx,10
digit_loop:
or ax,ax
jz digit_loop_exit
xor dx,dx
div bx
add dl,'0'
push dx
inc cx
jmp digit_loop
digit_loop_exit:
or cx,cx
jnz not_zero_digits
push word '0'
inc cx
not_zero_digits:

print_loop:
mov ah,2
pop dx
int 0x21
loop print_loop

ret

;--------------------------------------------------------------------

segment .bss

day:
resw 1[/code]
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

Oder kurz, knackig und hässlich:

Code: Alles auswählen

c = 1968
d = c + c // 10 + c // 100 + c // 1000
for i in range(1, 10000):
    c, d = 10 * (c % 1000) + d % 10, d + d % 10 - c // 1000
    if c == 1968:
        break
print(i)
BlackJack

Die Aufteilung auf Funktionen die ein bisschen weniger unübersichtlich aussehen in CoffeeScript:
[codebox=coffeescript file=Unbenannt.coffee]#!/usr/bin/env coffee
'use strict'

crossSum = (code) ->
sum = 0
while code > 0
digit = code % 10
code = (code - digit) / 10
sum += digit
sum


shiftCode = (code, digit) ->
code * 10 % 10000 + digit


main = ->
startCode = 1986
day = 0
code = startCode
loop
code = shiftCode(code, crossSum(code) % 10)
day++
break if code is startCode
console.log(day, code)


main() if require.main == module[/code]
BlackJack

@PythonRookie9000: Eine weitere Idee aufgrund dieser Aufgabe wäre es mal zu schauen wie sich das bei den anderen 9999 Möglichkeiten neben 1986 verhält. Wie lange brauchen andere Kombinationen und wie viele Kombinationen gibt es, die nie wieder zum Ausgangscode zurückkehren?
sebastian0202
User
Beiträge: 168
Registriert: Montag 9. Mai 2016, 09:14
Wohnort: Berlin

Dann will ich mal wieder 8)
Hoffe die Namen sind jetzt eindeutiger..

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-



class Mathe_Functions(object):
    def __init__(self):
        super(Mathe_Functions, self).__init__()
        # Zahl hat mindestens eine Stelle
        self.stellen = 1

    def anzahl_ziffern(self, zahl):
        # die Anzahl der Stellen von der Zahl ermitteln
        anzahl = 1
        while zahl >= 10:
            zahl /= 10
            anzahl += 1
        return anzahl
     
    def quersumme(self, zahl):
        # Quersumme der Zahl bilden
        stellen = self.anzahl_ziffern(zahl)
        summe = 0
        while stellen > 0:
            summe += zahl % 10
            zahl = (zahl - zahl % 10) / 10
            stellen -= 1
        return int(summe)

    def stellen_kuerzen(self, zahl, kuerzen = 1):
        # Zahl um x Stellen kuerzen (standard eine Stelle)
        # dabei muss die Zahl mindestens x Stellen lang 'self.stellen' sein
        stellen = self.anzahl_ziffern(zahl)
        if stellen - self.stellen >= kuerzen:
            zahl = zahl % 10**(stellen-kuerzen)
        return zahl

    def zahl_links_shiften(self, zahl, einer):
        # Zahl um eine Stelle nach Links verschieben 
        zahl *= 10
        zahl += einer
        zahl = self.stellen_kuerzen(zahl, 1)
        return zahl

    def letzte_zahl(self, zahl):
        # die letzte Ziffer der Zahl ermitteln 
        if zahl >= 10:
            return zahl % 10
        return zahl

 
class Code_X_Stellig(Mathe_Functions):
    def __init__(self, stellen):
        super(Code_X_Stellig).__init__()
        self.stellen = stellen
        self.codes = {}
        self.groups = []
    
    def __str__(self):
        liste = [int(zahl) for zahl in self.codes]
        liste.sort()
        for code in liste:
            tage = str(self.codes[str(code)]['tage']).ljust(4)
            code_string = ('000'+str(code))[-4:]
            print("Code: %s Tage: %s Gruppe: %i" % (code_string, tage, self.codes[str(code)]['gruppe']))

        return ''

    def auswertung(self):
        gruppen_anzahl = len(self.groups)
        kombinationen = set()
        ohne_wiederkehr = []
        for code in self.codes:
            kombinationen.add(self.codes[code]['tage'])
            if self.codes[code]['tage'] == -1:
                ohne_wiederkehr.append(code)
        print("Es existieren %i unterschiedliche Gruppierungen" % gruppen_anzahl)
        print("Folgende Komibnationen traten dabei auf: %s" % kombinationen)
        print("Folgende Zahlen kehren nie wieder zurück: %s" % ohne_wiederkehr)

    def recheck_groups(self):
        liste = [int(zahl) for zahl in self.codes]
        liste.sort()
        for zahl in liste:
            for nr, group in enumerate(self.groups):
                if zahl in group:
                    self.codes[str(zahl)]['gruppe'] = nr
                    break
        
    def add_group(self, zahl, liste):
        gefunden = False
        for group in self.groups:
            if zahl in group:
                gefunden = True
                break

        if not gefunden:
            self.groups.append(liste)
    
    def mathe(self, ur_code):
        # nach wievielen durchlaeufen kommt die zahl wieder vor
        # bedingung:  1. links-shiften um eine Stelle 
        #             2. quersumme (einer-stelle) anhaengen
        code = ur_code
        tage = 0
        zahlen_liste = []
        while tage < 10000:
            summe = self.quersumme(code)
            zahl = self.letzte_zahl(summe)
            code = self.zahl_links_shiften(code, zahl)
            zahlen_liste.append(code)
            tage += 1
            if code == ur_code:
                break
        if tage == 10000: tage = -1
        return tage, zahlen_liste
    
    def experimental(self, zahlen_liste, tage):
        # da der vorige Code nach X Durchlaeufen wiederkehrt, 
        # kehren auch alle Zahlen in der zahlen_liste nach diesen X Durchlaeufen wieder
        for zahl in zahlen_liste:
            sammeln.codes[str(zahl)] = {'tage' : tage, 'gruppe': -1}

if __name__ == '__main__':

    stellen = 4
    sammeln = Code_X_Stellig(stellen)
    # tage, zahlen_liste = sammeln.mathe(1986)
    # print("Es vergehen %i Tage, bis sich der Code %i wiederholt!" % (tage, 1986))

    for code in range(1,10000):
        if not str(code) in sammeln.codes:
            tage, zahlen_liste = sammeln.mathe(code)
            sammeln.codes[str(code)] = {'tage' : tage, 'gruppe': -1}
            sammeln.add_group(code, zahlen_liste)
            sammeln.experimental(zahlen_liste, tage)
    
    sammeln.recheck_groups()
    # print(sammeln)
    sammeln.auswertung()

BlackJack

@sebastian0202: Das sind keine Klassen die Du da geschrieben hast. Das ist so gar keine objektorientierte Programmierung. Bei `Mathe_Functions` sagt es ja schon der Name das es keine Klasse mit Methoden ist, sondern einfach nur Funktionen die ohne Grund in eine Klasse gesteckt wurden.

`Code_X_Stellig` ist auch ein komischer Name. Da würde ich erwarten das *ein* Exemplar dieser Klasse für *einen* x-stelligen Code steht. Unterstriche haben in Klassennamen übrigens nichts zu suchen.

Vererbung ist eine „ist-ein(e)“-Beziehung. Was `Code_X_Stellig` ist ein(e) `Mathe_Functions` überhaupt bedeuten soll ist mir an sich schon schleierhaft. Aber es macht ja sowieso schon keinen Sinn Funktionen in eine Klasse zu stecken.

Die `__str__()`-Methode ist dazu da eine Zeichenkettendarstellung des Objekts zu erzeugen und zurück zu geben. *Nicht* um irgendwelche Ausgaben oder andere Effekte zu haben. Du wirst ja sogar gezwungen eine Zeichenkette zurück zu geben, wie man an dem hier sinnlosen ``return ''`` sehen kann.

Die Ausrichtungen der Tage und des Codes (inklusive führender Nullen) hätte man beim Platzhalter in der Zeichenkette wo die Werte hinein formatiert werden, erledigen können.

`sorted()` hätte eine bzw. sogar zwei Zeilen sparen können.

Das ganze ständige hin und her wandeln zwischen `int()` und `str()` bei den Codes ist verwirrend und hätte man ziemlich sicher einfach weglassen können in dem man nur Zahlen nimmt und die einzig für die Ausgabe mit 0en aufgefüllt formatiert.

Wenn das `codes`-Attribut auf `collections.namedtuple` abbilden würde, dann hätte man im Code eine Dokumentation wie die Struktur aussieht, also welche Attribute/Schlüssel ein Wert in diesem Wörterbuch hat.

Programmlogik und Benutzerinteraktion sind vermischt.

Den Namen `recheck_groups()` verstehe ich nicht im Zusammenhang mit dem was die Methode tut. Bei `mathe()` das gleiche.

Für `add_group()` könntest Du Dir mal `any()` und `all()` anschauen und wie man eine der beiden Funktionen verwenden kann um da einen Ein- oder Zweizeiler draus zu machen.

Zur ``while``-Schleife in `mathe()` könntest Du Dir mal ``else``-Anschauen, dann muss man den Test mit der 10000 nach der Schleife nicht machen.

Einerseits scheint `stellen` etwas variables zu sein, andererseits funktioniert es nicht etwas anderes als 4 dafür zu verwenden, weil die 10000 als magische Zahl im Quelltext steht und nicht zu anderen Werten als 4 passt.

Ist das `ur` bei `ur_code` die deutsche Vorsilbe „Ur“ wie in „Ursprung“ oder Slangabkürzung für das englische `your`? Im ersten Fall: Keine natürlichen Sprachen mischen, schon gar nicht in *einem* Bezeichner (betrifft auch `Mathe_Functions`). Im zweiten Fall: Keine kryptischen Abkürzungen verwenden.

`experimental()` ist eindeutig keine Methode, wie so einiges andere auch auf `Code_X_Stellig` wahrscheinlich als Funktion geschrieben werden könnte, und die ”Methode” greift auf `sammeln` zu was nicht möglich sein dürfte, denn das Hauptprogramm sollte unter anderem genau aus diesem Grund in einer Funktion stehen.

`sammeln` ist auch wieder ein Name den ich nicht verstehe. Das wäre ein Name für eine Funktion oder eine Methode weil es eine Tätigkeit beschreibt. Aber `Code_X_Stellig` ist ja schon ein unverständlicher Name. Wenn Dir für die beiden nichts besseres, passendes einfällt, dann liegt das daran das die Klasse IMHO keinen Sinn macht. Das was da an Daten und Funktionen zusammengefasst wurde sieht völlig willkürlich aus. Also im Grunde alles was das Programm so können muss abzüglich einiger Hilfsfunktionen die sinnloser Weise in einer ererbten Klasse stehen. Irgendwie habe ich den Eindruck das Ziel war es keine Funktionen zu schreiben und alles *irgendwie* in Klassen zu stopfen. Das ist falsch! Funktionen sind nichts böses, und Klassen sollte man verwenden um *sinnvoll* Daten und Funktionen zu einem Objekt zusammen zu fassen.

Im Hauptprogramm wird dann umgekehrt in einer Art und Weise auf `codes` zugegriffen die man so auch nicht unbedingt erwarten würde.

Eine `Code`-Klasse die *tatsächlich* *einen* x-stelligen Code als Werttyp modelliert, könnte beispielsweise Sinn machen. Die könnte dann zum Beispiel eine Methode haben, welche den nächsten Code liefert. Und Methoden um die Quersumme abzufragen und einen verschobenen Code zu liefern.

Mal am Beispiel der CoffeeScript-Lösung objektorientiert, dort allerdings nicht mit einer zusätzlichen Klasse, sondern einfach die vorhandene `Number`-Klasse um entsprechende Methoden erweitert:
[codebox=coffeescript file=Unbenannt.coffee]#!/usr/bin/env coffee
'use strict'

Number::lastDigit = -> this % 10

Number::crossSum = ->
sum = 0
n = this
while n > 0
digit = n.lastDigit()
sum += digit
n = (n - digit) / 10
sum

Number::shiftCode = (digit) -> this * 10 % 10000 + digit

Number::nextCode = -> this.shiftCode(this.crossSum().lastDigit())

main = ->
startCode = 1986
day = 0
code = startCode
loop
code = code.nextCode()
day++
break if code is startCode
console.log(day, code)

main() if require.main == module[/code]
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@sebastian0202: auf die Schnelle habe ich nichts gefunden, was das Verwenden von Klassen rechtfertigen würde. Mathe_Functions ist nur eine Sammlung von einzelnen Funktionen, die entweder zu kompliziert gedacht, oder gleich ganz überflüssig sind. Man will eben nicht eine 5 stellige Zahl um eine Ziffer kürzen, sondern nur dafür sorgen, dass man immer eine 4 stellige Zahl hat. Bei Code_X_Stellig.__str__: es gibt Formatangaben um Zahlen 4 stellig (mit und ohne führende Nullen) auszugeben (wobei Du da die 4 fest codiert hast, statt die Stellenanzahl zu benutzen). __str__ sollte auch einen String zurückgeben, und nicht etwas per print ausgeben! Die ständige Umwandlung von Zahl zu String und zurück ist unnötig kompliziert. Mit Sets könnte man sich wohl 99% der Rechenzeit sparen. Es ist sinnvoller, eine Listen mit Gruppen anzulegen, da dort die Anzahl der Tage implizit durch die Länge gegeben ist und die Gruppennummer als Index.
BlackJack

Ein C-Programm das die Tage für alle Codes berechnet. Läuft grundsätzlich auch auf dem C64, allerdings quälend langsam.
[codebox=c file=Unbenannt.c]#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

uint8_t cross_sum(uint16_t code)
{
uint8_t sum = 0;
div_t tmp;

while (code) {
tmp = div(code, 10);
code = tmp.quot;
sum += tmp.rem;
}
return sum;
}

uint16_t shift_code(uint16_t code, uint8_t digit) {
return (code % 1000) * 10 + digit;
}

bool calculate_days(uint16_t start_code, uint16_t *days) {
register uint16_t day = 0;
register uint16_t code = start_code;
bool is_code_used[10000];

memset(is_code_used, 0, sizeof(is_code_used));
do {
code = shift_code(code, cross_sum(code) % 10);
if (is_code_used

Code: Alles auswählen

) return false;
        is_code_used[code] = true;
        ++day;
    } while (code != start_code);
    *days = day;
    return true;
}

int main(void)
{
    uint16_t start_code;
    uint16_t days;
    
    puts("start_code,days");
    for (start_code = 0; start_code <= 9999; ++start_code) {
        if (calculate_days(start_code, &days)) {
            printf("%04u,%u\n", start_code, days);
        } else {
            printf("%04u,inf\n", start_code);
        }
    }

    return 0;
}
Antworten