commit 4f5a78ac050b636c9f09301cf842c64d04ffeb07 Author: Oliver Hofmann Date: Fri Mar 27 17:19:51 2026 +0100 Init diff --git a/data/elektro.txt b/data/elektro.txt new file mode 100644 index 0000000..1b0978e --- /dev/null +++ b/data/elektro.txt @@ -0,0 +1,8 @@ +"Höhleneingang";"Ost/West-Passage";5 +"Höhleneingang";"Nord/Süd-Passage";3 +"Nord/Süd-Passage";"Nebelraum";7 +"Steiniger Pfad";"Ost/West-Passage";2 +"Ost/West-Passage";"Schwefelgewölbe";4 +"Schwefelgewölbe";"Steiniger Pfad";1 +"Schatzkammer";"Nebelraum";2 +"Steiniger Pfad";"Schatzkammer";6 diff --git a/data/hoehle.txt b/data/hoehle.txt new file mode 100644 index 0000000..5b08cd4 --- /dev/null +++ b/data/hoehle.txt @@ -0,0 +1,8 @@ +"Höhleneingang" <> "Ost/West-Passage" +"Höhleneingang" <> "Nord/Süd-Passage" +"Nord/Süd-Passage" <> "Nebelraum" +"Steiniger Pfad" > "Ost/West-Passage" +"Ost/West-Passage" <> "Schwefelgewölbe" +"Schwefelgewölbe" > "Steiniger Pfad" +"Schatzkammer" > "Nebelraum" +"Steiniger Pfad" > "Schatzkammer" \ No newline at end of file diff --git a/data/labyrinth.txt b/data/labyrinth.txt new file mode 100644 index 0000000..796bb65 --- /dev/null +++ b/data/labyrinth.txt @@ -0,0 +1,9 @@ +xxxxxxxxxxxxxxxxxxxxx +x x +x S x +x x +x xxxxxxxx x +x x +x x +x A x +xxxxxxxxxxxxxxxxxxxxx \ No newline at end of file diff --git a/data/labyrinth1.txt b/data/labyrinth1.txt new file mode 100644 index 0000000..dc47eaa --- /dev/null +++ b/data/labyrinth1.txt @@ -0,0 +1,5 @@ +xxxxxAxxxxxxxxx +x xSx +xxxxxxxxxx xx x +x x +xxxxxxxxxxxxxxx \ No newline at end of file diff --git a/data/seq0.txt b/data/seq0.txt new file mode 100644 index 0000000..65e0d03 --- /dev/null +++ b/data/seq0.txt @@ -0,0 +1,14 @@ +-59 +52 +46 +14 +-50 +58 +-87 +-77 +34 +15 +50 +47 +51 +48 diff --git a/data/seq1.txt b/data/seq1.txt new file mode 100644 index 0000000..79fddf4 --- /dev/null +++ b/data/seq1.txt @@ -0,0 +1,100 @@ +56 +13 +97 +14 +5 +40 +33 +20 +51 +98 +52 +89 +31 +33 +47 +59 +47 +75 +11 +39 +0 +79 +33 +57 +5 +1 +28 +87 +77 +54 +35 +21 +24 +97 +96 +94 +6 +31 +-45 +53 +-98 +-44 +85 +-76 +-48 +-90 +-99 +47 +-11 +16 +-98 +98 +-23 +57 +27 +-35 +23 +65 +-54 +96 +71 +99 +81 +30 +-7 +76 +-22 +43 +62 +-49 +73 +59 +75 +36 +39 +15 +51 +-51 +63 +69 +1 +1 +-25 +-18 +88 +86 +93 +33 +71 +-95 +56 +2 +4 +11 +-55 +28 +60 +-55 +-69 +-97 diff --git a/data/seq2.txt b/data/seq2.txt new file mode 100644 index 0000000..cbed507 --- /dev/null +++ b/data/seq2.txt @@ -0,0 +1,1000 @@ +-82 +-26 +-90 +-72 +-48 +-18 +-2 +-7 +-10 +-32 +-6 +-40 +-31 +-20 +-70 +-64 +-38 +-76 +-66 +-76 +-92 +-22 +-89 +-6 +-19 +-50 +-47 +-8 +-14 +-94 +-42 +-75 +-71 +-22 +-70 +-99 +-18 +-98 +-89 +-39 +-79 +-40 +-96 +-58 +-30 +-40 +-37 +-48 +-78 +-41 +-90 +-24 +-78 +-48 +-47 +-4 +-89 +-44 +-11 +-29 +-48 +-23 +-6 +-31 +-67 +-95 +-17 +-86 +-7 +-76 +-10 +-42 +-83 +-81 +-7 +-90 +-39 +-85 +-87 +-8 +-5 +-87 +-80 +-47 +-17 +-18 +-96 +-68 +-19 +-74 +-71 +-79 +-92 +-13 +-26 +-67 +-52 +-76 +-23 +-97 +-74 +-83 +-53 +-88 +-7 +-28 +-45 +-40 +-2 +-64 +-79 +-97 +-8 +-30 +-39 +-58 +-27 +-8 +-71 +-95 +-69 +-48 +-27 +-74 +-27 +-94 +-77 +-21 +-31 +-53 +-64 +-21 +-98 +-50 +-98 +-69 +-51 +-10 +-78 +-1 +-9 +-39 +-10 +-49 +-45 +-17 +-17 +-46 +-73 +-3 +-22 +-30 +-68 +-83 +-32 +-34 +-55 +-62 +-36 +-2 +-57 +-92 +-98 +-32 +-8 +-10 +-33 +-16 +-96 +-93 +-99 +-54 +-2 +-4 +-19 +-31 +-50 +-81 +-46 +-39 +-48 +-38 +-69 +-8 +-7 +-30 +-93 +-10 +-24 +-64 +-7 +-2 +-77 +-24 +-25 +-71 +-74 +-43 +-40 +-71 +-30 +-18 +-37 +-15 +-32 +-96 +-21 +-92 +-39 +-42 +-8 +-19 +-63 +-72 +-20 +-56 +-81 +-20 +-99 +-63 +-10 +-44 +-90 +-48 +-55 +-45 +-67 +-74 +-54 +-88 +-32 +-7 +-12 +-89 +-14 +-45 +-53 +-63 +-4 +-44 +-29 +-54 +-61 +-84 +-41 +-14 +-8 +-35 +-97 +-81 +-12 +-86 +-37 +-28 +-96 +-17 +-11 +-11 +-39 +-80 +-77 +-96 +-22 +-91 +-95 +-2 +-63 +-91 +-81 +-79 +-68 +-92 +-32 +-98 +-21 +-61 +-5 +-7 +-13 +-27 +-7 +-99 +-4 +-89 +-63 +-77 +-22 +-86 +-53 +-47 +-27 +-48 +-86 +-38 +-66 +-16 +-8 +-30 +-90 +-99 +-99 +-10 +-32 +-14 +-82 +-40 +-66 +-75 +-64 +-56 +-7 +-90 +-10 +-28 +-39 +-8 +-3 +-71 +-57 +-44 +-14 +-26 +-58 +-66 +-31 +-48 +-33 +-52 +-62 +-69 +-79 +-49 +-98 +-30 +-55 +-93 +-20 +-15 +-37 +-52 +-15 +-8 +-66 +-54 +-97 +-46 +-15 +-97 +-6 +-49 +-59 +-45 +-75 +-87 +-86 +-70 +-96 +-36 +-44 +-90 +-28 +-14 +-65 +-71 +-91 +-94 +-47 +-10 +-33 +-84 +-43 +-93 +-14 +-74 +-24 +-54 +-56 +-72 +-49 +-48 +-84 +-4 +-75 +-20 +-23 +-14 +-43 +-50 +-11 +-43 +-45 +-92 +-60 +-95 +-33 +-87 +-60 +-46 +-6 +-58 +-29 +-35 +-38 +-82 +-88 +-21 +-77 +-35 +-1 +-19 +-17 +-65 +-91 +-27 +-1 +-27 +-50 +-54 +-44 +-76 +-70 +-37 +-45 +-16 +-68 +-64 +-92 +-17 +-61 +-92 +-10 +-42 +-74 +-20 +-59 +-50 +-2 +-88 +-38 +-86 +-83 +-13 +-35 +-94 +-48 +-92 +-7 +-69 +-23 +-94 +-32 +-96 +-40 +-75 +-89 +-93 +-29 +-33 +-77 +-25 +-74 +-17 +-59 +-98 +-89 +-58 +-82 +-91 +-77 +-73 +-46 +-55 +-32 +-47 +-99 +-95 +-19 +-7 +-4 +-42 +-84 +-77 +-78 +-62 +-83 +-6 +-1 +-34 +-72 +-53 +-18 +-25 +-7 +-39 +-77 +-82 +-60 +-89 +-60 +-18 +-48 +-61 +-19 +-71 +-48 +-89 +-75 +-70 +-46 +-89 +-57 +-45 +-18 +-83 +-29 +-32 +-58 +-17 +-45 +-17 +-85 +-54 +-48 +-28 +-50 +-46 +-44 +-4 +-36 +-66 +-85 +-89 +-82 +-98 +-63 +-50 +-59 +-57 +-31 +-43 +-18 +-28 +-61 +-36 +-50 +-46 +-15 +-98 +-64 +-50 +-75 +-81 +-99 +-33 +-64 +-45 +-74 +-47 +-96 +-2 +-63 +-96 +-29 +-60 +-47 +-33 +-25 +-38 +-5 +-5 +-26 +-75 +-98 +-59 +-56 +-49 +-16 +-30 +-83 +-86 +-12 +-46 +-10 +-29 +-8 +-82 +-50 +-39 +-89 +-92 +-65 +-80 +-67 +-56 +-5 +-2 +-20 +-77 +-93 +-9 +-90 +-10 +-48 +-52 +-18 +-19 +-87 +-32 +-60 +-50 +-16 +-81 +-87 +-55 +-57 +-16 +-26 +-75 +-20 +-22 +-39 +-43 +-74 +-95 +-82 +-19 +-91 +-65 +-60 +-53 +-67 +-2 +-77 +-57 +-94 +-7 +-76 +-23 +-40 +-73 +-8 +-47 +-70 +-23 +-26 +-84 +-98 +-39 +-25 +-14 +-44 +-13 +-60 +-88 +-78 +-78 +-43 +-69 +-18 +-87 +-16 +-57 +-49 +-25 +-39 +-25 +-24 +-87 +-44 +-20 +-91 +-47 +-57 +-11 +-69 +-44 +-55 +-11 +-23 +-51 +-98 +-94 +-6 +-29 +-82 +-9 +-60 +-23 +-9 +-43 +-79 +-72 +-95 +-6 +-6 +-89 +-48 +-74 +-24 +-96 +-75 +-75 +-38 +-28 +-54 +-45 +-70 +-62 +-92 +-23 +-3 +-29 +-86 +-60 +-14 +-46 +-80 +-89 +-73 +-18 +-57 +-28 +-11 +-81 +-78 +-95 +-74 +-17 +-24 +-20 +-63 +-58 +-92 +-19 +-64 +-35 +-87 +-1 +-50 +-9 +-73 +-42 +-31 +-91 +-42 +-77 +-65 +-92 +-78 +-94 +-34 +-27 +-11 +-6 +-17 +-14 +-84 +-47 +-22 +-72 +-35 +-39 +-70 +-43 +-6 +-27 +-52 +-63 +-60 +-50 +-60 +-21 +-50 +-57 +-92 +-73 +-55 +-74 +-56 +-5 +-2 +-84 +-62 +-26 +-22 +-57 +-45 +-12 +-82 +-79 +-36 +-66 +-36 +-32 +-75 +-54 +-5 +-74 +-60 +-10 +-86 +-95 +-20 +-93 +-29 +-43 +-2 +-49 +-27 +-24 +-42 +-30 +-75 +-71 +-81 +-76 +-13 +-9 +-9 +-31 +-62 +-37 +-99 +-96 +-77 +-31 +-92 +-40 +-70 +-24 +-34 +-13 +-62 +-55 +-78 +-44 +-63 +-10 +-81 +-90 +-79 +-81 +-59 +-66 +-83 +-47 +-51 +-68 +-48 +-28 +-56 +-47 +-48 +-67 +-86 +-42 +-31 +-60 +-60 +-78 +-60 +-63 +-76 +-84 +-59 +-81 +-99 +-69 +-86 +-7 +-90 +-95 +-46 +-69 +-71 +-74 +-68 +-43 +-74 +-93 +-79 +-67 +-9 +-22 +-58 +-60 +-15 +-14 +-11 +-48 +-25 +-6 +-41 +-94 +-69 +-27 +-1 +-37 +-19 +-27 +-10 +-76 +-15 +-55 +-76 +-13 +-91 +-30 +-84 +-49 +-26 +-80 +-26 +-73 +-21 +-15 +-30 +-15 +-60 +-38 +-1 +-84 +-82 +-79 +-54 +-89 +-36 +-94 +-59 +-8 +-48 +-74 +-53 +-59 +-82 +-75 +-14 +-24 +-42 +-17 +-95 +-83 +-56 +-79 +-99 +-28 +-15 +-54 +-71 +-73 +-5 +-15 +-55 +-38 +-61 +-21 +-50 +-66 +-61 +-89 +-17 +-90 +-12 +-56 +-49 +-47 +-56 +-43 +-17 +-36 +-69 +-77 +-34 +-6 +-30 +-94 +-6 +-39 +-47 +-41 +-88 +-1 +-49 +-98 +-54 +-9 +-61 +-77 +-68 +-38 +-64 +-31 +-73 +-4 +-53 +-46 +-69 +-85 +-58 +-49 diff --git a/data/seq3.txt b/data/seq3.txt new file mode 100644 index 0000000..708827d --- /dev/null +++ b/data/seq3.txt @@ -0,0 +1,10000 @@ +-56 +6 +5 +35 +54 +-10 +-35 +-98 +78 +55 +-30 +-45 +37 +35 +-18 +87 +-55 +47 +-60 +-2 +-58 +77 +-15 +-12 +-1 +-13 +-18 +-96 +-76 +2 +-18 +36 +-52 +6 +27 +74 +69 +19 +92 +84 +-89 +35 +-53 +86 +-12 +1 +-50 +-5 +3 +-61 +51 +-31 +-95 +97 +-3 +-59 +89 +-62 +51 +7 +-5 +-58 +46 +69 +69 +-81 +27 +97 +-56 +2 +-32 +35 +77 +-61 +-31 +-71 +-71 +77 +-33 +26 +-28 +32 +-8 +-35 +57 +31 +-42 +-29 +-41 +0 +94 +65 +-83 +-56 +99 +50 +18 +-33 +66 +-71 +-92 +11 +-94 +-48 +42 +76 +-87 +-35 +-15 +98 +-46 +62 +-6 +-69 +-69 +79 +67 +38 +64 +-50 +22 +-1 +80 +-55 +77 +72 +-48 +-83 +-69 +-79 +16 +-24 +65 +89 +48 +50 +-95 +-10 +-95 +-50 +-32 +-48 +82 +43 +93 +-31 +99 +39 +18 +0 +65 +-35 +-8 +95 +-12 +-92 +-20 +-50 +-95 +63 +67 +38 +0 +-10 +82 +5 +47 +83 +-45 +-72 +8 +93 +-1 +-61 +40 +-67 +16 +-44 +77 +78 +-65 +98 +88 +52 +-22 +-46 +15 +33 +-56 +37 +61 +50 +-27 +19 +91 +63 +-8 +-59 +58 +-55 +0 +-77 +-1 +80 +11 +50 +37 +74 +-92 +-70 +61 +-64 +53 +-95 +85 +65 +49 +-44 +-73 +42 +-76 +85 +29 +-82 +67 +38 +-20 +91 +98 +-50 +75 +-52 +71 +55 +16 +67 +94 +30 +-81 +-25 +-8 +-53 +92 +19 +70 +32 +-18 +-17 +93 +-59 +-98 +-14 +-49 +-24 +-40 +-73 +24 +86 +64 +-63 +61 +3 +-38 +-72 +-55 +-47 +-38 +-97 +-65 +-15 +-59 +-36 +5 +74 +45 +-97 +-87 +40 +97 +0 +65 +11 +-33 +70 +-30 +-68 +74 +-99 +17 +56 +-15 +-67 +13 +-61 +73 +-55 +59 +-48 +62 +43 +85 +26 +-28 +95 +79 +-9 +-49 +-23 +61 +13 +6 +-20 +22 +53 +-10 +54 +64 +-73 +10 +-74 +-91 +0 +-92 +-79 +61 +85 +-65 +-38 +-16 +-75 +-85 +16 +25 +-62 +83 +-17 +-5 +57 +12 +92 +44 +88 +18 +27 +-71 +57 +74 +-57 +71 +29 +-89 +47 +1 +81 +-96 +90 +-50 +30 +-45 +-21 +26 +83 +-67 +89 +50 +-28 +30 +78 +0 +35 +-73 +33 +-91 +48 +-45 +9 +37 +-74 +61 +-40 +18 +-65 +-46 +-73 +-29 +40 +38 +-56 +-55 +-62 +-31 +40 +96 +-14 +87 +33 +-60 +-32 +58 +-16 +-75 +-75 +-1 +-81 +67 +82 +-23 +64 +-96 +-53 +3 +-18 +42 +92 +46 +-26 +-48 +92 +28 +3 +57 +-7 +-84 +-10 +-15 +-29 +22 +6 +2 +-37 +-10 +68 +27 +-40 +-67 +65 +75 +-6 +47 +-97 +-11 +66 +-71 +28 +39 +76 +53 +-43 +61 +-6 +-67 +41 +64 +53 +-83 +71 +-15 +87 +43 +-70 +33 +-92 +20 +53 +-60 +55 +-24 +-61 +28 +95 +-73 +23 +-95 +56 +66 +82 +-60 +98 +-22 +-67 +90 +82 +-22 +-98 +-56 +-65 +-53 +-4 +67 +2 +59 +5 +53 +1 +0 +-89 +-6 +87 +0 +48 +-10 +34 +31 +-52 +-72 +40 +-91 +3 +82 +-61 +-58 +-59 +40 +51 +31 +-16 +-40 +63 +14 +-13 +-68 +-47 +90 +-60 +1 +23 +76 +49 +72 +-61 +-50 +-39 +-24 +79 +-3 +-97 +61 +-78 +-47 +-56 +-69 +-22 +-73 +-19 +18 +26 +-58 +48 +4 +66 +77 +-54 +65 +37 +-87 +-23 +-62 +-78 +74 +0 +34 +-13 +31 +-18 +-75 +77 +-57 +-49 +-14 +-49 +-2 +9 +28 +-20 +-30 +-30 +-61 +39 +37 +41 +-17 +-99 +79 +46 +24 +57 +79 +-9 +-83 +24 +-94 +-32 +-57 +-22 +27 +-84 +95 +53 +2 +-53 +25 +2 +-95 +-49 +-43 +-93 +-18 +45 +88 +-1 +-78 +-57 +-99 +46 +-7 +26 +-6 +18 +74 +55 +5 +71 +25 +-82 +-17 +-1 +-97 +70 +99 +2 +-50 +-13 +48 +-4 +-39 +5 +0 +71 +-20 +-55 +60 +-72 +97 +-65 +86 +94 +94 +81 +86 +-62 +19 +-29 +60 +44 +-83 +-77 +-94 +-42 +26 +-64 +-32 +57 +96 +84 +-72 +-12 +1 +-88 +-53 +-18 +73 +14 +-41 +54 +-55 +-4 +89 +-64 +-76 +40 +-46 +-90 +-35 +-50 +-23 +78 +55 +38 +-71 +44 +-45 +-97 +57 +-10 +46 +63 +16 +-98 +-74 +99 +-66 +63 +-49 +-67 +35 +65 +0 +51 +-81 +23 +61 +-15 +-54 +45 +49 +83 +-39 +-46 +18 +0 +53 +-76 +-64 +-46 +-23 +-92 +-81 +-1 +-89 +-1 +-90 +-46 +17 +50 +-91 +-5 +-41 +-26 +-40 +97 +77 +45 +64 +25 +-11 +25 +-6 +67 +-91 +83 +4 +89 +-39 +78 +-12 +-38 +-34 +-20 +-12 +-11 +-46 +22 +-57 +-12 +99 +-6 +-28 +-74 +91 +56 +2 +-92 +-50 +83 +49 +-19 +29 +67 +-26 +91 +57 +-82 +36 +-62 +-62 +-1 +96 +-38 +-29 +-18 +56 +-25 +-32 +48 +50 +2 +11 +8 +84 +46 +47 +24 +82 +53 +36 +-80 +-37 +61 +-12 +-2 +-84 +-7 +-10 +59 +31 +-66 +94 +85 +-62 +26 +-85 +25 +-84 +-54 +11 +-36 +-81 +99 +-83 +32 +54 +-59 +7 +81 +46 +35 +14 +98 +80 +86 +-67 +67 +-5 +15 +-41 +-10 +-57 +-2 +-6 +80 +-90 +93 +-74 +-42 +58 +-87 +-31 +94 +12 +25 +-32 +-97 +-7 +10 +-71 +32 +75 +56 +-57 +-9 +34 +-67 +-47 +-26 +-9 +66 +32 +-50 +53 +-58 +-47 +-84 +-17 +-72 +87 +20 +55 +72 +-35 +-97 +36 +65 +73 +-76 +78 +-22 +36 +97 +12 +-97 +-68 +-2 +-14 +-31 +43 +-2 +79 +-8 +-12 +59 +-24 +93 +-36 +93 +15 +90 +-17 +-28 +-38 +28 +-43 +-50 +36 +-22 +95 +28 +-49 +-9 +26 +-96 +79 +-97 +-65 +41 +-93 +-7 +4 +40 +-40 +26 +-52 +-86 +25 +4 +-6 +80 +92 +76 +-55 +-22 +48 +68 +-49 +-21 +30 +2 +-98 +-34 +-5 +76 +69 +-48 +89 +-41 +41 +-6 +78 +-75 +-53 +3 +51 +-8 +-97 +15 +-33 +31 +-29 +-1 +27 +-94 +-50 +77 +-53 +27 +-66 +-25 +-47 +-89 +-97 +94 +-57 +46 +96 +77 +-53 +20 +-23 +68 +86 +-30 +-28 +56 +-49 +58 +-30 +54 +-16 +-93 +33 +-52 +69 +16 +-86 +90 +8 +-18 +57 +99 +-66 +29 +77 +-43 +-15 +92 +-91 +37 +-60 +88 +57 +64 +-97 +5 +30 +-99 +26 +39 +36 +74 +17 +31 +-49 +60 +-37 +41 +11 +-85 +-42 +-69 +48 +-47 +-8 +52 +-77 +-30 +27 +-50 +28 +-38 +2 +14 +-39 +37 +-54 +-15 +-78 +67 +93 +-8 +-91 +20 +53 +-56 +-53 +-10 +-92 +37 +83 +41 +79 +-67 +-36 +-32 +-93 +-46 +70 +-99 +46 +51 +89 +48 +-34 +53 +87 +-96 +-86 +5 +94 +41 +-87 +44 +91 +75 +75 +25 +42 +-57 +-61 +-38 +37 +23 +10 +-21 +-36 +75 +64 +60 +-68 +93 +80 +80 +-10 +0 +-37 +71 +-31 +77 +88 +-67 +-79 +-73 +-56 +96 +-79 +96 +-97 +62 +-56 +-26 +-42 +53 +51 +78 +88 +-23 +97 +-91 +22 +-30 +-87 +-69 +-37 +76 +4 +62 +83 +-93 +-63 +-67 +21 +61 +-64 +-70 +35 +95 +-43 +-11 +64 +6 +-63 +-13 +97 +-53 +82 +-51 +-64 +-40 +-39 +81 +18 +84 +61 +74 +-96 +16 +-63 +73 +79 +-10 +-68 +7 +-61 +-62 +-78 +-97 +73 +-67 +-25 +-67 +75 +14 +18 +97 +-74 +-44 +14 +2 +-75 +97 +89 +-89 +18 +73 +97 +29 +-41 +-40 +3 +-34 +66 +47 +-34 +88 +-79 +-54 +65 +85 +-17 +-78 +23 +5 +72 +74 +18 +67 +46 +-23 +14 +46 +-93 +-58 +92 +-62 +-15 +9 +57 +-30 +-50 +-56 +3 +21 +31 +-92 +0 +-67 +-64 +47 +16 +-7 +-68 +-72 +97 +-49 +-71 +-41 +-42 +-18 +-45 +93 +10 +92 +-37 +62 +-16 +-49 +-76 +-30 +38 +-16 +37 +-3 +-19 +5 +-75 +92 +-67 +4 +-72 +-2 +-80 +-67 +54 +-42 +92 +-82 +54 +-76 +27 +91 +70 +-35 +-24 +-64 +52 +89 +0 +-17 +-75 +-38 +-80 +-40 +-90 +13 +53 +-35 +-62 +56 +-51 +90 +-34 +-26 +16 +40 +-90 +32 +-12 +-72 +51 +-50 +-29 +2 +54 +41 +-14 +-65 +46 +29 +33 +31 +-12 +65 +70 +10 +83 +-59 +-27 +31 +-55 +-79 +19 +58 +23 +61 +21 +-95 +-37 +-45 +-73 +-81 +66 +-12 +83 +6 +97 +26 +-40 +16 +42 +64 +62 +-7 +77 +24 +29 +-85 +-25 +1 +-93 +-48 +91 +-66 +-28 +-56 +-91 +-12 +11 +-64 +39 +18 +42 +-47 +92 +-66 +-82 +0 +62 +-27 +83 +52 +-41 +-62 +12 +0 +39 +99 +36 +-46 +67 +-91 +32 +95 +-94 +33 +30 +-11 +57 +14 +25 +26 +99 +47 +-87 +82 +-97 +-19 +-61 +12 +26 +-35 +83 +86 +98 +84 +63 +35 +-93 +-25 +92 +-64 +59 +48 +28 +-15 +-71 +-7 +-84 +-84 +69 +24 +84 +6 +-50 +-51 +22 +80 +76 +-28 +57 +25 +44 +32 +-76 +-70 +-58 +58 +-46 +88 +57 +-99 +68 +44 +86 +49 +-49 +33 +-3 +49 +-39 +11 +-25 +22 +16 +-47 +99 +7 +-33 +-79 +6 +73 +-70 +-48 +-93 +-87 +-69 +47 +17 +8 +94 +66 +-64 +45 +-50 +-70 +-11 +21 +-38 +21 +-17 +79 +-70 +83 +99 +-23 +40 +70 +-79 +2 +8 +99 +19 +-85 +-36 +-64 +-5 +-27 +-98 +-86 +-66 +1 +10 +26 +25 +-34 +0 +-22 +-75 +-57 +35 +54 +-2 +-28 +90 +-12 +95 +-12 +-13 +19 +-10 +81 +28 +-89 +-94 +-85 +-70 +-70 +20 +-98 +-73 +94 +42 +-54 +-4 +-88 +89 +-83 +-86 +-98 +-13 +37 +86 +61 +98 +89 +3 +-36 +-43 +21 +50 +5 +-35 +-80 +-33 +25 +0 +92 +16 +-6 +-16 +-68 +68 +-93 +-45 +-54 +17 +-59 +0 +56 +-65 +65 +43 +8 +-25 +-6 +-96 +37 +-92 +-5 +-81 +-85 +-89 +25 +99 +59 +-74 +-86 +-1 +91 +67 +67 +-32 +-15 +35 +0 +-50 +-42 +-4 +-40 +61 +-76 +41 +85 +91 +47 +28 +-8 +-57 +-57 +-58 +-15 +25 +61 +75 +27 +62 +-37 +-16 +85 +-92 +6 +83 +-10 +58 +-45 +23 +30 +-18 +-5 +75 +66 +77 +56 +65 +3 +9 +5 +-16 +-52 +68 +45 +-20 +24 +-24 +-96 +-71 +-6 +-7 +-66 +15 +62 +-74 +0 +84 +-87 +-51 +62 +68 +97 +-24 +41 +91 +-34 +-92 +-91 +74 +59 +-34 +91 +-25 +81 +55 +-52 +39 +50 +-62 +75 +59 +-43 +23 +-47 +-78 +40 +6 +-26 +-57 +-73 +91 +-15 +82 +-46 +-41 +15 +-95 +32 +57 +6 +20 +-28 +74 +-57 +-91 +36 +-55 +-67 +35 +-73 +30 +62 +63 +-73 +-37 +-12 +-38 +48 +65 +-44 +63 +-93 +73 +-36 +16 +84 +97 +10 +-80 +-23 +-44 +-77 +22 +-22 +-44 +-90 +93 +-17 +-99 +-38 +-36 +50 +-5 +72 +44 +-61 +-26 +-73 +-31 +50 +15 +97 +-13 +7 +-41 +-12 +87 +80 +31 +56 +49 +-64 +91 +55 +-81 +7 +-69 +79 +-15 +-55 +-77 +16 +77 +-49 +-99 +98 +38 +83 +30 +-29 +92 +89 +-47 +-62 +68 +-6 +-53 +-4 +-58 +65 +76 +-50 +-91 +62 +-28 +-5 +52 +-69 +57 +88 +63 +-91 +25 +70 +70 +-29 +11 +39 +-29 +26 +20 +93 +-6 +98 +-82 +-46 +28 +46 +-39 +88 +-82 +73 +48 +-15 +30 +-66 +-7 +-19 +-37 +12 +-23 +-84 +-3 +76 +81 +95 +33 +7 +-54 +69 +8 +51 +5 +-68 +-84 +12 +67 +58 +4 +-5 +87 +-47 +-22 +5 +86 +-44 +-30 +48 +14 +68 +-73 +-5 +32 +96 +95 +-84 +-35 +-96 +-19 +67 +-83 +-29 +71 +-22 +-69 +-3 +43 +56 +60 +-86 +41 +-33 +43 +-46 +60 +44 +-79 +85 +58 +63 +-99 +89 +-15 +-92 +-55 +-72 +-68 +20 +63 +89 +-91 +36 +-36 +30 +-20 +82 +-91 +-97 +99 +-42 +-58 +-89 +-62 +-54 +0 +-1 +89 +-52 +86 +53 +-66 +72 +-82 +-69 +-93 +21 +33 +-47 +26 +-11 +-66 +-93 +63 +-35 +-50 +-14 +57 +8 +80 +68 +-19 +65 +-4 +-4 +64 +-30 +-85 +59 +16 +53 +-24 +5 +-36 +-11 +52 +-9 +55 +79 +58 +-38 +-89 +59 +60 +65 +52 +-23 +-24 +77 +-26 +27 +3 +-46 +48 +82 +-36 +11 +39 +82 +20 +-61 +-55 +65 +-69 +-64 +-29 +-47 +49 +77 +22 +-2 +-61 +-32 +-36 +32 +-45 +17 +-45 +-18 +4 +-73 +41 +80 +97 +-59 +-34 +40 +-70 +-61 +43 +89 +-86 +-42 +-15 +86 +-20 +19 +60 +73 +-32 +40 +-98 +-76 +-71 +-58 +59 +-4 +-76 +-68 +-79 +25 +74 +-40 +-83 +19 +30 +0 +-28 +25 +-80 +-75 +39 +85 +14 +67 +27 +24 +-30 +-34 +-23 +-29 +-46 +-59 +43 +15 +32 +0 +-48 +77 +-1 +-95 +-82 +79 +-24 +42 +19 +-43 +29 +-97 +83 +6 +-92 +88 +99 +23 +-57 +60 +44 +-4 +87 +-60 +-31 +-38 +63 +-90 +-60 +-59 +75 +-89 +5 +-75 +66 +-9 +-17 +-46 +3 +-72 +63 +29 +71 +97 +-82 +-74 +58 +-25 +-76 +58 +-23 +-8 +49 +62 +-66 +30 +-27 +37 +-62 +-40 +-2 +-14 +69 +50 +98 +-63 +-12 +-27 +-17 +86 +-18 +10 +-28 +-85 +84 +9 +62 +-55 +-11 +74 +62 +31 +15 +72 +76 +34 +48 +-96 +0 +45 +-12 +-14 +-76 +-17 +65 +62 +-76 +61 +-70 +-21 +90 +-44 +67 +55 +61 +98 +-11 +73 +-11 +-69 +-19 +86 +97 +70 +-94 +-11 +-95 +75 +-40 +37 +-62 +71 +-17 +87 +79 +-19 +76 +30 +-27 +25 +-78 +74 +83 +-76 +-51 +60 +11 +-85 +93 +64 +72 +-78 +65 +-22 +-4 +62 +-83 +-22 +14 +25 +-67 +-82 +-92 +-51 +-24 +16 +23 +10 +-94 +26 +75 +-98 +-97 +-95 +12 +-66 +-45 +-37 +2 +-49 +5 +51 +-18 +-4 +-22 +-70 +-72 +20 +63 +-89 +-82 +-46 +-77 +38 +-91 +84 +46 +57 +95 +-31 +34 +29 +55 +-16 +10 +8 +-55 +-33 +78 +69 +17 +3 +8 +69 +29 +23 +66 +-33 +64 +-35 +-6 +-92 +15 +24 +89 +-46 +-51 +-95 +-50 +-85 +-12 +-85 +93 +96 +95 +84 +6 +-32 +-50 +62 +-78 +85 +1 +-11 +-18 +-99 +32 +44 +16 +12 +17 +-68 +-87 +38 +-28 +-19 +88 +-74 +31 +-99 +-41 +-45 +9 +9 +63 +-75 +-73 +2 +-13 +-52 +13 +-96 +-80 +53 +13 +-32 +26 +-21 +68 +27 +-33 +-14 +-43 +-19 +47 +39 +38 +-96 +-6 +97 +56 +81 +87 +-44 +-59 +-62 +-63 +97 +99 +-62 +42 +-31 +22 +96 +-45 +-72 +14 +39 +-97 +63 +52 +-99 +77 +-68 +41 +-3 +-26 +-72 +13 +-11 +-66 +-76 +9 +89 +75 +-28 +-90 +82 +-74 +27 +-13 +11 +62 +86 +-99 +46 +92 +3 +-92 +32 +19 +-40 +9 +81 +-83 +-10 +24 +41 +-59 +-41 +-4 +48 +5 +-55 +-19 +-91 +54 +98 +85 +91 +-4 +-65 +0 +70 +13 +-41 +-16 +89 +46 +77 +10 +34 +63 +-68 +-67 +-45 +-92 +-63 +59 +61 +-79 +-90 +-28 +-42 +-50 +69 +22 +-86 +-31 +-61 +65 +77 +44 +-26 +0 +-14 +-46 +-27 +18 +-62 +91 +-95 +25 +86 +-22 +-80 +61 +2 +-51 +8 +-71 +-62 +-30 +2 +8 +89 +-98 +11 +-61 +-98 +-75 +75 +74 +-77 +2 +26 +49 +28 +74 +5 +-41 +-60 +91 +-77 +61 +-11 +39 +-64 +56 +-89 +81 +-85 +52 +97 +11 +46 +41 +47 +25 +-17 +41 +4 +-98 +-20 +79 +-83 +-96 +-31 +-66 +48 +-36 +91 +-8 +96 +-73 +26 +33 +-86 +67 +-12 +-24 +46 +86 +-33 +41 +-49 +-54 +-37 +19 +-13 +46 +10 +-45 +52 +-71 +-74 +85 +50 +4 +-63 +-67 +53 +-65 +-52 +32 +-26 +-21 +-51 +-14 +27 +82 +71 +44 +0 +-97 +77 +-15 +3 +41 +12 +-5 +-2 +-94 +-58 +-71 +66 +43 +-51 +7 +75 +86 +26 +42 +28 +33 +21 +-85 +-97 +88 +-12 +79 +41 +11 +-26 +4 +88 +19 +-84 +-38 +43 +-70 +-19 +-92 +8 +-4 +-3 +8 +89 +-30 +55 +-59 +-86 +59 +-46 +73 +25 +-43 +-49 +-18 +-98 +58 +64 +41 +-41 +-71 +20 +70 +65 +-43 +35 +77 +89 +-77 +13 +-56 +92 +-18 +71 +-11 +-18 +99 +55 +6 +86 +-39 +9 +40 +-19 +44 +50 +60 +77 +-31 +79 +-32 +-59 +-22 +18 +-20 +40 +63 +42 +77 +80 +44 +27 +28 +81 +-45 +-42 +2 +8 +-47 +47 +75 +24 +98 +-31 +24 +-67 +56 +85 +-67 +69 +-70 +67 +52 +90 +-83 +-51 +-35 +21 +-16 +-56 +-2 +-84 +40 +-32 +-33 +-80 +-92 +45 +-9 +96 +98 +-55 +-76 +19 +-23 +-81 +-37 +-60 +-10 +-29 +-42 +83 +60 +-18 +-28 +99 +-59 +-49 +-6 +67 +-81 +-58 +-35 +58 +-4 +42 +78 +37 +45 +-28 +-58 +-82 +59 +-30 +53 +-44 +10 +-59 +91 +55 +87 +-27 +58 +19 +-68 +-97 +-44 +13 +33 +-66 +-10 +-19 +84 +-80 +-45 +-74 +-6 +46 +76 +-31 +81 +-43 +23 +-61 +95 +-16 +-68 +31 +-89 +-4 +1 +88 +-46 +-38 +-50 +-16 +87 +-19 +21 +-13 +10 +30 +-30 +64 +77 +-93 +-63 +64 +15 +39 +55 +79 +-19 +-45 +44 +90 +-17 +-83 +-74 +-31 +-38 +97 +-95 +94 +-80 +64 +-75 +98 +-77 +-65 +-71 +11 +-98 +6 +-56 +-48 +-18 +86 +-18 +63 +-30 +-79 +46 +-81 +-4 +-43 +18 +0 +-66 +57 +-90 +-41 +-97 +-90 +87 +94 +73 +-22 +-17 +3 +-17 +26 +2 +-50 +21 +-66 +-89 +-68 +25 +78 +-42 +35 +-20 +34 +86 +0 +-47 +20 +73 +28 +34 +-34 +30 +-41 +52 +-86 +43 +87 +28 +96 +-23 +-41 +80 +3 +97 +75 +13 +-17 +64 +-3 +-78 +-34 +-86 +-46 +-89 +38 +-19 +1 +70 +-73 +-41 +10 +-76 +91 +15 +-2 +12 +94 +99 +-59 +-46 +-85 +-94 +64 +-65 +-76 +-92 +38 +-25 +60 +-75 +87 +-54 +-94 +95 +-46 +-24 +-32 +-24 +39 +-18 +5 +61 +-86 +5 +-8 +76 +-85 +32 +-34 +-4 +-55 +-46 +33 +-85 +-38 +41 +17 +93 +6 +-87 +83 +74 +56 +-49 +-17 +-40 +-79 +-54 +-67 +-98 +27 +50 +78 +65 +-67 +24 +-68 +90 +-77 +18 +13 +-50 +66 +-46 +-94 +-74 +89 +4 +-45 +14 +44 +-84 +-49 +-79 +-60 +-82 +80 +34 +51 +14 +17 +4 +-5 +-52 +33 +-78 +-13 +-98 +-8 +-5 +83 +-59 +-11 +-97 +62 +-67 +94 +-30 +-5 +-45 +-16 +15 +83 +-99 +71 +-36 +24 +62 +-3 +89 +-99 +-81 +43 +27 +-76 +-17 +89 +-56 +33 +-67 +28 +-48 +-11 +-66 +30 +-20 +-68 +0 +65 +-76 +51 +89 +-96 +86 +-48 +-66 +-8 +53 +39 +-45 +-69 +36 +86 +59 +0 +-3 +-53 +36 +12 +19 +39 +-35 +-27 +36 +0 +36 +52 +23 +-75 +-67 +-44 +-18 +-55 +-28 +-74 +-44 +-35 +78 +-33 +3 +47 +38 +-27 +28 +98 +-43 +13 +95 +-68 +34 +-43 +22 +51 +-9 +-38 +-4 +-87 +-53 +-61 +4 +20 +-72 +15 +24 +84 +93 +-21 +-44 +67 +26 +42 +-14 +-5 +82 +36 +81 +64 +-30 +-66 +-48 +-44 +58 +-57 +50 +-48 +17 +-33 +37 +-4 +-80 +39 +41 +42 +45 +-98 +56 +-15 +-9 +71 +4 +57 +80 +-47 +-6 +0 +21 +-93 +-42 +83 +-56 +-94 +42 +38 +26 +-7 +26 +91 +-24 +-39 +-75 +14 +-98 +-47 +-34 +34 +0 +56 +95 +-40 +-40 +-45 +93 +-25 +-44 +-23 +54 +81 +18 +-50 +-20 +-60 +-36 +62 +68 +-25 +-91 +5 +75 +95 +18 +-17 +-73 +-42 +-54 +-8 +68 +-64 +65 +9 +-64 +2 +-73 +78 +-18 +90 +-27 +10 +-98 +-12 +-50 +-14 +67 +11 +-71 +22 +63 +-18 +68 +42 +-49 +-33 +-55 +46 +80 +-35 +37 +4 +79 +-12 +17 +31 +25 +78 +-84 +-55 +-56 +-17 +-9 +-97 +-44 +-64 +-96 +54 +-86 +75 +-64 +57 +58 +41 +-23 +99 +31 +-77 +-66 +87 +-72 +62 +95 +36 +-39 +61 +-32 +-20 +-27 +-39 +-3 +16 +11 +-29 +-90 +92 +26 +46 +-53 +10 +-94 +45 +1 +35 +30 +5 +20 +83 +-34 +34 +80 +88 +-4 +55 +-91 +59 +3 +7 +94 +-28 +73 +19 +0 +-64 +54 +-83 +89 +-79 +96 +86 +61 +-29 +-94 +-56 +-47 +-70 +87 +15 +-93 +-79 +62 +5 +64 +-68 +73 +-30 +98 +46 +-11 +88 +74 +-56 +-52 +79 +19 +-44 +74 +-3 +14 +-73 +-19 +-15 +27 +-52 +75 +37 +53 +88 +37 +75 +8 +-95 +-6 +49 +-7 +8 +99 +53 +-16 +-9 +-21 +-53 +-64 +8 +76 +70 +6 +88 +-38 +-80 +31 +-39 +-23 +38 +-88 +-22 +-5 +24 +-65 +-77 +-50 +60 +17 +-42 +-15 +71 +-41 +96 +-97 +95 +-52 +-91 +-27 +-69 +82 +16 +-28 +18 +55 +-55 +-67 +-87 +14 +36 +67 +94 +-64 +-56 +-91 +88 +-15 +31 +-9 +55 +-1 +61 +24 +-7 +1 +51 +95 +62 +-19 +5 +-65 +-74 +17 +59 +-1 +99 +-6 +-58 +65 +-52 +83 +-5 +-37 +-44 +78 +-10 +74 +-30 +60 +-56 +-32 +99 +-32 +24 +2 +77 +20 +-54 +-91 +-23 +-72 +6 +16 +-53 +32 +-73 +-39 +-70 +-88 +24 +-31 +-86 +-91 +-25 +66 +56 +-94 +83 +49 +-74 +36 +8 +64 +-97 +6 +-34 +93 +16 +65 +72 +15 +-82 +0 +-4 +-32 +-13 +-21 +40 +65 +55 +17 +2 +2 +46 +-82 +2 +16 +73 +-70 +72 +25 +39 +83 +72 +-65 +-93 +70 +-52 +56 +-88 +58 +-78 +91 +-10 +-31 +4 +13 +91 +81 +-70 +-7 +-98 +28 +0 +42 +-87 +-36 +82 +-27 +-76 +-12 +-81 +-42 +-14 +-64 +60 +22 +-50 +-36 +25 +68 +46 +-80 +-64 +69 +3 +36 +57 +2 +51 +59 +23 +83 +-82 +2 +-53 +-74 +90 +28 +9 +-11 +-68 +-96 +5 +-91 +94 +20 +83 +-27 +-5 +-90 +-86 +-92 +22 +-26 +-57 +-38 +-95 +88 +17 +-99 +-60 +-36 +-60 +-15 +60 +-55 +-2 +-75 +95 +38 +36 +39 +66 +-60 +77 +61 +93 +18 +-14 +-6 +74 +62 +55 +62 +4 +-82 +70 +17 +-28 +63 +-64 +82 +71 +64 +93 +-32 +-91 +54 +30 +88 +53 +80 +-39 +0 +10 +46 +-12 +36 +40 +23 +-85 +17 +-72 +20 +-16 +15 +-59 +-96 +-7 +-24 +-42 +-32 +44 +-81 +-72 +2 +58 +-57 +48 +-36 +-67 +50 +41 +-40 +9 +21 +32 +14 +83 +3 +-78 +-31 +-27 +56 +60 +21 +95 +-6 +84 +46 +19 +36 +-34 +48 +-62 +-28 +38 +47 +-42 +99 +87 +-80 +98 +77 +-27 +30 +-95 +95 +-91 +-13 +42 +-47 +37 +-1 +-97 +-40 +25 +29 +-7 +21 +-10 +69 +39 +52 +-8 +2 +49 +-24 +-58 +47 +-30 +-49 +11 +-20 +94 +57 +-14 +55 +-13 +-34 +7 +15 +-76 +72 +-93 +26 +-35 +-85 +8 +-76 +-66 +-56 +-10 +-68 +70 +-65 +-8 +-39 +-75 +45 +-63 +-89 +-61 +52 +81 +-33 +-49 +-64 +87 +-87 +66 +57 +-82 +-16 +94 +61 +-35 +-41 +68 +-43 +13 +17 +97 +61 +-96 +-61 +41 +3 +5 +-83 +-49 +83 +-26 +50 +-92 +84 +4 +22 +-83 +-41 +73 +-58 +31 +85 +-9 +47 +-7 +91 +-35 +-7 +49 +33 +43 +-72 +-80 +-98 +-91 +-53 +-68 +21 +47 +38 +-54 +45 +71 +-61 +-38 +40 +65 +-41 +-58 +-22 +69 +63 +-59 +98 +-59 +-92 +5 +57 +-49 +4 +69 +-95 +11 +95 +-86 +51 +8 +79 +-82 +80 +80 +-78 +-15 +99 +89 +-75 +-57 +42 +-36 +-46 +96 +-36 +-71 +66 +27 +91 +22 +28 +-41 +12 +52 +83 +-93 +-35 +85 +-92 +39 +61 +98 +40 +24 +3 +-2 +-30 +-76 +7 +-29 +16 +6 +-51 +32 +-46 +-25 +-75 +-82 +-49 +63 +33 +-67 +-71 +98 +-20 +69 +-45 +85 +63 +12 +67 +-37 +20 +-91 +16 +-45 +-27 +-29 +92 +20 +3 +87 +-63 +72 +97 +14 +-29 +82 +54 +71 +74 +83 +-31 +-9 +-89 +50 +20 +-47 +6 +60 +-15 +12 +73 +-30 +-23 +32 +-38 +23 +48 +-27 +29 +-36 +-87 +-14 +-21 +-85 +-72 +-98 +87 +-19 +-9 +-42 +-5 +-29 +6 +-45 +-17 +34 +-53 +91 +5 +-59 +12 +23 +-70 +18 +-31 +96 +23 +35 +-34 +-25 +73 +71 +84 +46 +-50 +-26 +28 +87 +-15 +39 +-94 +-74 +75 +44 +-2 +39 +4 +-9 +46 +-20 +51 +-1 +54 +51 +54 +-62 +64 +97 +-14 +12 +-47 +-58 +47 +2 +18 +77 +37 +74 +-96 +-14 +70 +-75 +-35 +-24 +-44 +78 +-30 +-38 +1 +96 +-24 +-80 +-43 +95 +-65 +-5 +-44 +50 +-77 +67 +-97 +72 +-38 +-80 +-35 +-25 +-41 +61 +11 +34 +-17 +95 +-39 +51 +12 +-31 +-64 +76 +-87 +95 +-77 +-50 +67 +-73 +50 +69 +-96 +24 +-40 +-78 +-31 +64 +17 +-51 +-93 +-36 +-35 +0 +-28 +71 +-99 +-5 +26 +-45 +71 +-38 +91 +48 +6 +-82 +1 +34 +92 +41 +86 +-91 +-12 +-99 +-60 +-81 +-76 +1 +-46 +-5 +65 +27 +93 +-65 +49 +14 +39 +-10 +46 +-37 +68 +4 +-70 +85 +-69 +71 +50 +-91 +-3 +10 +-77 +42 +18 +-31 +29 +68 +52 +83 +-53 +-84 +93 +-1 +19 +6 +46 +28 +13 +-55 +88 +-63 +60 +-27 +-95 +86 +-3 +-8 +97 +43 +46 +71 +-58 +12 +37 +40 +27 +93 +48 +-20 +-61 +-60 +-26 +30 +25 +-82 +-59 +-28 +-67 +40 +68 +0 +73 +-25 +-52 +98 +10 +25 +-27 +90 +-37 +13 +-8 +56 +-61 +-79 +-12 +49 +-56 +72 +81 +49 +62 +81 +53 +4 +-93 +-85 +39 +86 +85 +87 +6 +57 +-26 +69 +59 +16 +-54 +-89 +57 +-40 +-70 +65 +-68 +-28 +-37 +84 +93 +-86 +26 +37 +53 +-56 +-61 +13 +-63 +-33 +-10 +69 +61 +48 +-3 +-67 +-19 +-78 +-20 +-63 +60 +98 +-6 +72 +-74 +-81 +-67 +94 +-43 +-87 +26 +27 +-16 +-70 +5 +-40 +8 +96 +-51 +30 +-27 +-19 +-20 +27 +-33 +-54 +22 +-32 +70 +-34 +-35 +-7 +-17 +-7 +52 +-71 +78 +30 +77 +21 +-57 +-23 +-87 +99 +7 +22 +-20 +24 +-26 +-39 +91 +33 +-98 +44 +62 +11 +24 +-11 +81 +-75 +24 +50 +-99 +-76 +-71 +-76 +-9 +-1 +-53 +51 +84 +85 +38 +42 +-25 +-37 +88 +85 +72 +-62 +2 +-86 +-87 +-85 +-68 +68 +-1 +-88 +78 +11 +58 +-20 +-32 +-57 +75 +78 +-61 +-93 +76 +-48 +5 +71 +-99 +-87 +-61 +-72 +64 +-20 +8 +49 +56 +-81 +40 +-80 +84 +11 +-68 +68 +-17 +-35 +-10 +-68 +23 +94 +95 +-44 +79 +31 +-89 +33 +-71 +65 +-57 +3 +-7 +-63 +-74 +-14 +51 +-9 +18 +-99 +-5 +-78 +70 +-26 +-37 +54 +11 +-92 +69 +55 +-45 +96 +-32 +54 +-68 +-39 +89 +-37 +11 +25 +66 +-43 +-51 +-39 +27 +36 +-23 +-72 +51 +0 +79 +66 +95 +25 +42 +-28 +-71 +7 +65 +87 +94 +-74 +27 +15 +-46 +16 +-57 +41 +39 +-80 +-45 +16 +-99 +87 +-24 +-98 +96 +-79 +30 +81 +-75 +45 +-18 +92 +49 +-5 +-28 +45 +-30 +-82 +65 +74 +15 +-57 +43 +74 +-45 +-67 +91 +23 +-53 +-49 +65 +3 +-76 +-65 +36 +44 +-86 +92 +-63 +6 +8 +-39 +0 +-66 +-28 +91 +-10 +50 +-1 +-71 +68 +-1 +49 +-43 +6 +21 +-28 +68 +89 +32 +68 +-84 +-39 +74 +-17 +44 +-14 +-59 +-68 +-82 +92 +-99 +54 +6 +65 +7 +3 +-7 +-81 +-98 +5 +1 +-41 +43 +0 +38 +-96 +-47 +4 +86 +-25 +29 +92 +32 +-68 +20 +75 +77 +-15 +-77 +-23 +-18 +-66 +-27 +-36 +-15 +73 +32 +-27 +92 +-64 +79 +-89 +56 +33 +29 +-87 +6 +-80 +85 +-13 +-78 +0 +10 +-89 +26 +24 +98 +70 +63 +90 +-51 +55 +-87 +60 +-47 +31 +-42 +19 +-4 +-80 +71 +-97 +-54 +-34 +-18 +92 +14 +-63 +69 +-74 +31 +-86 +0 +-45 +-59 +-78 +-10 +19 +-16 +13 +-11 +-68 +-48 +87 +-22 +64 +62 +-82 +3 +3 +81 +-9 +0 +25 +70 +-32 +53 +69 +-39 +-19 +48 +80 +20 +-12 +-55 +17 +-58 +43 +91 +28 +-69 +-81 +-17 +-5 +41 +4 +-43 +63 +-25 +-7 +53 +18 +-96 +11 +-66 +3 +93 +-14 +-29 +-45 +-80 +24 +-86 +-32 +13 +98 +-36 +64 +-70 +-46 +-38 +79 +58 +-18 +-1 +-32 +85 +-65 +93 +8 +8 +-43 +37 +-44 +-64 +38 +57 +64 +83 +-9 +91 +72 +-64 +-14 +-37 +55 +-58 +22 +99 +13 +9 +69 +-75 +50 +46 +67 +-74 +-86 +33 +87 +-61 +52 +-95 +33 +18 +9 +-3 +9 +-79 +-56 +6 +37 +87 +25 +-64 +-49 +94 +-88 +94 +-25 +75 +-1 +-96 +0 +77 +-74 +50 +-13 +-88 +78 +85 +-10 +51 +-14 +-16 +83 +45 +-16 +-6 +-37 +2 +-26 +84 +45 +25 +-13 +32 +20 +4 +-12 +-42 +-78 +-77 +-91 +-75 +-48 +-13 +30 +-74 +-84 +80 +9 +73 +17 +74 +32 +-26 +-30 +-10 +-74 +40 +-22 +18 +-35 +33 +38 +76 +51 +15 +47 +88 +54 +-33 +-51 +24 +28 +-25 +-65 +6 +-12 +73 +-71 +-50 +51 +-48 +-33 +87 +95 +3 +81 +-52 +98 +98 +43 +41 +-66 +-90 +-19 +48 +12 +-18 +8 +-14 +-95 +-68 +8 +-89 +-24 +-7 +71 +-49 +93 +68 +47 +-26 +91 +-82 +50 +-65 +-86 +0 +41 +72 +-69 +-67 +89 +-48 +16 +-15 +-9 +-79 +60 +44 +-93 +89 +-31 +-39 +54 +-88 +-98 +0 +5 +50 +-76 +-27 +-19 +-23 +-46 +-80 +-19 +-21 +-31 +33 +93 +18 +59 +5 +15 +10 +33 +-11 +64 +-67 +78 +-86 +82 +26 +21 +-89 +-97 +48 +79 +77 +83 +8 +26 +61 +-76 +-70 +-68 +-62 +-89 +-87 +19 +41 +90 +77 +-7 +-33 +-2 +1 +-64 +35 +7 +96 +87 +-32 +68 +-96 +-22 +-23 +-77 +34 +-23 +-66 +71 +-44 +-3 +79 +54 +-10 +44 +-40 +-80 +-74 +-69 +-16 +-64 +89 +34 +98 +46 +6 +-46 +51 +-83 +59 +-91 +38 +51 +73 +10 +-49 +45 +-38 +-49 +-38 +-59 +-6 +10 +56 +16 +0 +27 +85 +47 +27 +-82 +24 +-91 +60 +-88 +-74 +70 +52 +59 +-66 +-60 +76 +13 +-63 +86 +14 +84 +94 +22 +-71 +66 +-10 +15 +61 +64 +-61 +-43 +-72 +1 +30 +-70 +-98 +89 +11 +-78 +40 +-20 +-57 +11 +-48 +-38 +-1 +-5 +-10 +78 +-55 +14 +26 +69 +-87 +-11 +90 +93 +53 +-44 +30 +9 +-10 +34 +-65 +41 +94 +55 +34 +64 +-9 +1 +29 +-78 +49 +8 +-86 +24 +-64 +71 +-71 +77 +75 +-83 +27 +49 +43 +69 +-62 +-15 +-16 +-98 +68 +8 +62 +82 +72 +-15 +-38 +-36 +80 +-52 +12 +70 +25 +96 +-16 +90 +-5 +-29 +-82 +-89 +-80 +-7 +47 +-40 +-73 +79 +-75 +-44 +-57 +68 +7 +73 +60 +42 +-42 +39 +-36 +-5 +94 +-65 +83 +-64 +50 +87 +42 +4 +-98 +13 +18 +72 +-60 +32 +-16 +-76 +-59 +-90 +-62 +8 +3 +79 +96 +-23 +-97 +-92 +70 +26 +-22 +-65 +-70 +81 +45 +-79 +24 +74 +47 +84 +-4 +11 +0 +-64 +-56 +65 +-89 +88 +8 +-11 +-46 +-61 +27 +15 +26 +71 +22 +53 +83 +-23 +29 +-29 +-17 +27 +-34 +-7 +44 +14 +51 +-35 +-76 +-22 +-24 +-76 +78 +64 +-64 +26 +66 +84 +-99 +-89 +0 +32 +-15 +1 +-29 +-99 +-12 +-86 +5 +-44 +-54 +55 +32 +-69 +-27 +-49 +-59 +-10 +23 +58 +25 +-33 +22 +68 +-88 +21 +-74 +-97 +-43 +1 +-7 +22 +-47 +32 +8 +98 +24 +12 +-33 +41 +30 +25 +52 +-59 +46 +-40 +42 +28 +-13 +-82 +81 +4 +-93 +-5 +-89 +70 +13 +-82 +-69 +-62 +63 +-15 +-77 +61 +-21 +-88 +71 +41 +62 +26 +-19 +-75 +-11 +78 +77 +-94 +-76 +-84 +83 +75 +11 +-11 +-17 +-32 +-25 +1 +-18 +-55 +-37 +-76 +86 +-63 +-83 +33 +64 +59 +14 +97 +55 +7 +76 +-92 +-11 +23 +-88 +64 +-98 +92 +34 +-41 +85 +8 +-12 +-88 +58 +20 +-33 +-9 +5 +71 +-38 +87 +61 +-33 +-94 +-72 +53 +-91 +32 +51 +17 +-51 +-5 +63 +-61 +27 +-16 +-11 +-82 +-96 +-75 +62 +-73 +0 +-61 +-86 +-73 +33 +-52 +51 +-97 +34 +90 +66 +45 +79 +-9 +-7 +24 +-54 +64 +85 +-1 +-78 +10 +43 +-80 +-8 +96 +-99 +47 +19 +72 +-48 +-95 +90 +-54 +64 +77 +-74 +-91 +-44 +23 +43 +89 +97 +-35 +-55 +64 +-75 +-88 +56 +-21 +32 +-74 +52 +-31 +-23 +-40 +17 +-31 +-55 +-13 +-96 +-89 +-22 +-2 +27 +-82 +28 +-59 +29 +69 +91 +59 +-6 +-72 +-18 +-6 +-62 +79 +60 +46 +-40 +-69 +-80 +-41 +33 +19 +-12 +79 +72 +-30 +-59 +78 +16 +-33 +-5 +-22 +51 +-34 +-56 +15 +-87 +-27 +-66 +-40 +20 +-63 +-59 +-19 +91 +-85 +-17 +30 +51 +-53 +-20 +5 +-32 +-75 +-41 +-39 +45 +84 +21 +96 +-99 +-53 +-61 +-9 +61 +-57 +-72 +-52 +63 +-53 +-26 +-7 +-17 +-30 +48 +38 +-63 +6 +19 +91 +-33 +0 +68 +-52 +5 +54 +-72 +-88 +29 +3 +55 +-75 +-60 +-64 +41 +-29 +30 +36 +-21 +-47 +-42 +63 +-26 +75 +85 +96 +31 +-47 +86 +67 +-22 +-26 +69 +15 +90 +43 +41 +78 +-30 +-39 +-28 +-13 +85 +92 +-8 +-27 +14 +94 +-37 +31 +51 +-68 +32 +91 +-11 +-25 +-27 +-77 +-30 +49 +-11 +0 +89 +-78 +60 +-70 +-4 +-69 +-80 +-68 +-78 +96 +-18 +-62 +-44 +-55 +74 +-90 +-71 +86 +64 +26 +57 +18 +72 +64 +93 +85 +8 +19 +-53 +68 +-39 +21 +-13 +-48 +33 +12 +63 +-16 +-22 +83 +-86 +43 +14 +3 +96 +40 +-56 +-96 +-54 +38 +-52 +0 +-56 +78 +19 +60 +19 +-98 +-43 +0 +-85 +-57 +-33 +17 +25 +-12 +-97 +-34 +-58 +96 +-26 +-17 +74 +-71 +-40 +24 +-25 +38 +55 +-50 +-12 +-5 +72 +-89 +44 +-67 +80 +-52 +94 +-85 +-69 +0 +-6 +-84 +2 +-97 +-3 +-61 +80 +-7 +-58 +99 +41 +-78 +-56 +88 +30 +44 +74 +9 +98 +-56 +-12 +13 +2 +3 +-96 +-78 +-24 +-96 +46 +-81 +-6 +84 +-63 +61 +94 +-52 +-36 +-96 +-53 +28 +-38 +83 +26 +52 +-5 +32 +-30 +80 +-7 +-10 +3 +49 +-80 +7 +34 +88 +5 +47 +39 +-43 +-86 +24 +1 +-88 +-17 +7 +0 +-31 +19 +45 +-45 +-73 +-55 +4 +66 +49 +-32 +81 +12 +68 +-78 +-25 +78 +66 +24 +-18 +65 +-80 +2 +-13 +56 +-65 +59 +-67 +-23 +80 +84 +-54 +77 +82 +89 +-67 +-96 +69 +37 +-43 +61 +-9 +-67 +15 +-54 +-91 +-13 +-58 +-61 +-98 +58 +91 +31 +48 +68 +33 +-56 +36 +-8 +97 +20 +-15 +59 +-32 +-73 +44 +-97 +-11 +-93 +81 +-48 +44 +-10 +-65 +-19 +0 +33 +94 +8 +-44 +82 +-38 +44 +-34 +-32 +-8 +-35 +47 +-3 +78 +-66 +-12 +99 +81 +95 +3 +19 +-18 +21 +-96 +-45 +1 +-43 +74 +-90 +-69 +75 +5 +28 +25 +-36 +-72 +93 +14 +98 +-58 +-71 +-55 +-70 +-66 +72 +19 +41 +20 +53 +-80 +28 +63 +96 +-35 +54 +31 +99 +-8 +58 +46 +-4 +33 +88 +29 +89 +27 +65 +17 +-51 +94 +49 +8 +81 +94 +46 +-27 +-72 +-73 +72 +-51 +17 +34 +41 +-62 +-39 +45 +-48 +28 +40 +-87 +-99 +84 +-41 +-36 +-58 +-38 +61 +8 +-99 +-80 +-68 +-60 +-29 +27 +73 +53 +-15 +49 +86 +-62 +8 +59 +-24 +3 +26 +-25 +78 +-21 +-78 +94 +-84 +65 +91 +31 +41 +-34 +-36 +69 +-31 +-54 +-61 +-61 +76 +-91 +1 +-12 +80 +31 +36 +9 +23 +-70 +29 +-20 +-78 +-20 +61 +-99 +-22 +66 +-64 +-82 +-90 +-55 +-57 +-48 +-84 +-45 +-31 +37 +32 +-23 +-11 +-11 +-46 +-49 +-70 +55 +50 +37 +86 +-83 +-35 +54 +94 +-75 +90 +21 +-44 +-94 +-30 +-94 +-52 +-92 +-47 +-9 +-87 +31 +41 +27 +42 +-67 +51 +83 +19 +-35 +26 +39 +0 +-72 +2 +79 +8 +-82 +45 +10 +-52 +-80 +-77 +-62 +-99 +59 +60 +-5 +64 +-95 +-47 +-94 +-90 +43 +72 +48 +42 +-27 +-74 +96 +83 +-69 +50 +-28 +-34 +14 +-45 +4 +-48 +79 +-86 +-9 +98 +78 +-70 +26 +-48 +-53 +60 +-53 +52 +-24 +49 +-23 +41 +56 +55 +37 +-79 +-80 +-11 +0 +39 +-4 +35 +-78 +45 +81 +14 +73 +-27 +74 +-2 +0 +-21 +30 +90 +61 +17 +89 +-67 +43 +33 +-18 +-37 +-52 +-49 +8 +-15 +70 +36 +51 +10 +95 +-68 +-97 +-16 +82 +81 +2 +-58 +85 +4 +-34 +-12 +-7 +-37 +-68 +-29 +17 +-50 +-79 +-49 +-62 +59 +-82 +45 +-28 +98 +69 +-79 +6 +-14 +-47 +-24 +98 +-6 +11 +79 +-83 +89 +77 +-9 +-13 +-29 +40 +45 +-61 +97 +35 +-3 +0 +-44 +-58 +34 +68 +22 +8 +-47 +-72 +19 +19 +-73 +94 +-9 +-97 +-33 +-85 +-88 +7 +13 +27 +-86 +-74 +38 +57 +-14 +-47 +-24 +-35 +58 +-20 +-59 +90 +-67 +-3 +33 +38 +-65 +11 +64 +59 +-69 +-52 +-2 +34 +-72 +-57 +44 +87 +92 +-53 +65 +-58 +-3 +4 +46 +8 +-28 +68 +-18 +28 +-68 +-35 +-49 +-76 +-38 +77 +43 +-75 +-44 +-28 +11 +-55 +-28 +14 +81 +61 +-68 +66 +-86 +-5 +35 +92 +24 +53 +89 +48 +5 +-75 +39 +-95 +11 +-89 +-50 +55 +-15 +-42 +66 +-29 +-39 +-92 +81 +31 +93 +-29 +39 +33 +-79 +-80 +-97 +-25 +-91 +31 +12 +37 +6 +80 +-76 +-41 +18 +-73 +-75 +11 +74 +82 +-17 +81 +-86 +68 +-99 +67 +58 +-49 +38 +39 +81 +-32 +3 +98 +84 +-19 +-86 +-90 +-54 +80 +-68 +51 +-94 +-23 +7 +88 +38 +76 +-55 +45 +12 +-71 +-40 +4 +-45 +53 +-36 +-66 +-68 +89 +-47 +-13 +-17 +-14 +-71 +-49 +67 +-97 +-95 +-8 +-40 +-97 +-46 +68 +65 +97 +27 +21 +-49 +77 +-16 +97 +-65 +-10 +76 +-93 +38 +1 +14 +79 +-64 +-21 +-70 +48 +-74 +79 +28 +81 +-73 +7 +66 +-4 +84 +-5 +40 +5 +-47 +62 +-87 +-75 +10 +-19 +65 +30 +-64 +-70 +65 +-84 +-74 +-46 +37 +-82 +-27 +77 +-88 +-37 +39 +44 +-62 +-67 +9 +92 +-61 +77 +51 +-98 +-79 +57 +75 +-16 +12 +-91 +-18 +32 +95 +-57 +-74 +41 +-82 +-36 +64 +22 +32 +26 +36 +60 +-48 +44 +46 +-5 +8 +87 +-61 +-61 +92 +16 +-77 +1 +42 +-26 +-74 +65 +22 +12 +68 +-32 +-49 +-17 +18 +76 +16 +58 +37 +-69 +59 +-84 +-56 +-90 +-20 +-32 +76 +66 +-7 +-16 +62 +-54 +-25 +-85 +-1 +-41 +19 +-45 +-31 +-57 +33 +99 +45 +93 +17 +-39 +93 +-91 +-38 +-85 +-9 +-24 +-52 +-31 +-79 +-69 +-25 +-66 +76 +-94 +19 +31 +75 +10 +-89 +-35 +72 +-44 +63 +-93 +67 +-25 +0 +-12 +65 +61 +-77 +83 +31 +-65 +-58 +23 +-15 +51 +37 +-45 +-24 +-99 +62 +-25 +-31 +-17 +55 +-36 +38 +-18 +-11 +87 +-18 +-18 +57 +-27 +70 +93 +-91 +-50 +-27 +52 +57 +36 +19 +18 +-69 +5 +-68 +53 +-50 +-71 +-64 +76 +12 +67 +0 +-5 +19 +82 +27 +-62 +85 +73 +-70 +81 +-2 +-78 +-3 +93 +-64 +58 +-44 +-55 +-14 +27 +50 +44 +78 +14 +8 +-40 +97 +4 +-51 +42 +-90 +73 +-81 +88 +13 +-17 +-80 +-93 +-96 +20 +-13 +10 +-65 +63 +-55 +48 +-4 +-88 +-63 +-86 +12 +48 +68 +-57 +-31 +60 +-34 +-49 +76 +78 +-56 +-39 +78 +-90 +-99 +14 +55 +-39 +63 +-4 +-11 +-33 +-26 +8 +76 +-54 +-26 +66 +78 +-79 +21 +24 +-78 +42 +-40 +-97 +53 +31 +31 +51 +-23 +-9 +-40 +87 +97 +-36 +-9 +53 +-58 +62 +44 +70 +71 +-55 +-14 +-69 +-12 +11 +55 +93 +-52 +-52 +94 +-47 +-61 +-6 +75 +66 +-15 +-41 +22 +-39 +-59 +22 +50 +-27 +-66 +84 +-17 +14 +21 +50 +-28 +52 +-16 +-71 +-25 +-74 +-20 +25 +-75 +83 +71 +-63 +21 +-28 +-53 +43 +-72 +-38 +46 +60 +32 +12 +60 +-21 +-19 +15 +-3 +-85 +40 +32 +-41 +-57 +91 +10 +-45 +-89 +50 +26 +-22 +-32 +77 +-32 +46 +11 +-83 +-9 +29 +-94 +16 +29 +13 +36 +5 +40 +-77 +-78 +-47 +82 +-97 +-28 +-61 +9 +-69 +85 +-8 +-87 +71 +-68 +70 +74 +-55 +86 +-26 +21 +58 +32 +-52 +70 +-90 +75 +-99 +92 +-21 +42 +-92 +-12 +-27 +-92 +-66 +-17 +-3 +-88 +-17 +-22 +-50 +94 +8 +44 +1 +-93 +81 +-78 +-70 +-28 +-6 +-66 +-27 +28 +47 +-19 +31 +-21 +-44 +-95 +-66 +-42 +98 +-43 +-2 +-44 +99 +-48 +-26 +-3 +-23 +50 +60 +-45 +19 +-61 +24 +-52 +-10 +-97 +88 +53 +-64 +-95 +88 +-21 +-49 +47 +-13 +97 +-44 +1 +-4 +43 +-42 +-39 +-69 +33 +46 +-94 +-38 +-14 +-88 +-98 +15 +86 +0 +13 +60 +0 +78 +88 +60 +-47 +-29 +71 +-82 +75 +-42 +-35 +48 +31 +-23 +23 +-82 +-46 +33 +21 +-65 +60 +-28 +28 +50 +56 +-16 +98 +30 +-52 +-24 +-32 +-21 +-66 +-29 +-14 +72 +27 +-76 +43 +-9 +-76 +-97 +-38 +91 +-90 +-84 +-21 +-32 +27 +-55 +-27 +-18 +-84 +89 +-2 +95 +19 +91 +-9 +61 +44 +-19 +16 +-85 +-21 +-66 +77 +65 +60 +-75 +98 +44 +65 +-90 +21 +67 +-87 +60 +-34 +-80 +-45 +8 +61 +63 +-35 +-69 +27 +-24 +-23 +-60 +0 +90 +-50 +80 +-67 +-43 +-35 +69 +86 +66 +19 +-27 +29 +67 +-49 +-19 +-8 +80 +-85 +-78 +7 +16 +-69 +-27 +-11 +96 +39 +-79 +88 +-66 +-2 +-31 +18 +-78 +41 +43 +62 +-85 +57 +-96 +24 +93 +84 +-91 +-71 +-4 +-62 +-26 +-50 +53 +29 +87 +95 +-64 +3 +-48 +-24 +63 +12 +99 +-40 +5 +-54 +-54 +0 +-88 +-34 +14 +32 +80 +46 +-77 +93 +95 +-66 +45 +90 +-25 +-49 +7 +48 +35 +79 +-3 +67 +-45 +34 +5 +-9 +86 +7 +31 +-48 +56 +-39 +-71 +-10 +14 +93 +-67 +50 +84 +80 +-36 +-53 +43 +94 +81 +-35 +19 +-5 +60 +-94 +-97 +6 +-45 +-27 +-19 +35 +11 +77 +69 +88 +-21 +-60 +-72 +-22 +74 +75 +-21 +-73 +6 +-39 +88 +-7 +-70 +-93 +46 +56 +5 +-21 +-13 +-27 +-58 +-71 +-73 +-59 +-82 +55 +58 +-41 +-81 +25 +70 +-42 +-29 +-67 +93 +-91 +0 +68 +-96 +58 +33 +33 +-17 +-44 +-95 +89 +-63 +-55 +-39 +94 +-20 +31 +-80 +20 +80 +86 +-70 +-41 +-25 +-25 +1 +97 +-67 +-86 +93 +10 +78 +62 +-93 +-89 +-28 +22 +-78 +49 +-86 +-31 +-39 +13 +-44 +-88 +7 +35 +87 +84 +-4 +-8 +29 +70 +28 +12 +-76 +-43 +-12 +92 +-4 +8 +58 +-60 +32 +34 +-85 +85 +-77 +87 +-53 +94 +-40 +-16 +-17 +-48 +10 +-26 +-70 +11 +67 +91 +19 +-80 +26 +80 +65 +-86 +-9 +42 +61 +-11 +90 +31 +-67 +-50 +-58 +67 +75 +21 +-18 +5 +11 +-50 +-74 +-90 +9 +-87 +40 +58 +20 +-95 +-40 +-99 +92 +0 +55 +-35 +-64 +68 +85 +-79 +61 +-22 +-69 +96 +-78 +76 +13 +19 +91 +4 +52 +62 +12 +-5 +-98 +85 +53 +25 +56 +0 +45 +-98 +9 +21 +48 +71 +61 +-68 +42 +-94 +-59 +-9 +-8 +-44 +-32 +-54 +-16 +62 +37 +32 +-47 +35 +63 +-20 +3 +-21 +-38 +-47 +-43 +67 +-35 +-67 +52 +-66 +-55 +-1 +23 +2 +96 +27 +-63 +87 +29 +17 +25 +38 +-76 +-6 +-20 +-83 +77 +-54 +69 +10 +10 +91 +29 +24 +70 +94 +-51 +57 +-88 +-8 +57 +-24 +94 +19 +8 +12 +80 +11 +-10 +-79 +32 +-83 +-57 +63 +41 +32 +-71 +3 +-90 +6 +-85 +-52 +62 +20 +-78 +-14 +55 +70 +7 +54 +-80 +-47 +-34 +59 +-17 +82 +80 +-18 +28 +41 +80 +4 +-71 +-55 +76 +40 +-82 +-55 +13 +23 +8 +68 +80 +-30 +-50 +-19 +-57 +-24 +85 +-44 +36 +-47 +34 +99 +76 +-93 +-21 +-2 +-82 +56 +36 +-25 +-41 +80 +-51 +68 +-9 +29 +-88 +-44 +53 +-47 +50 +24 +-54 +64 +43 +79 +79 +-54 +-3 +-12 +17 +47 +84 +-28 +-66 +27 +-70 +68 +-68 +-2 +30 +-6 +84 +79 +8 +-50 +-29 +-77 +35 +-55 +64 +-3 +-9 +29 +-47 +-73 +-25 +41 +-4 +-8 +22 +-86 +-92 +-27 +-51 +52 +70 +-52 +51 +40 +-47 +-71 +-68 +-49 +18 +-99 +29 +31 +87 +-77 +74 +51 +53 +-82 +56 +23 +82 +-62 +-83 +17 +3 +-41 +-70 +-69 +10 +43 +74 +-13 +85 +-61 +69 +98 +82 +-3 +30 +-13 +90 +-42 +-15 +44 +-40 +-17 +97 +29 +93 +-89 +-44 +72 +15 +-82 +-14 +38 +-73 +37 +-30 +22 +98 +47 +51 +-8 +46 +-34 +19 +-17 +39 +44 +94 +20 +-57 +-12 +66 +32 +-12 +28 +-78 +-57 +68 +3 +81 +9 +-96 +-99 +49 +-13 +77 +-78 +11 +56 +-85 +30 +-3 +92 +-6 +30 +50 +-38 +54 +59 +-29 +39 +91 +-30 +-17 +-21 +-34 +67 +43 +82 +-21 +53 +-10 +57 +99 +26 +-74 +86 +-40 +89 +-20 +32 +7 +-64 +-92 +78 +-21 +98 +-82 +8 +-88 +-27 +-22 +-41 +55 +0 +5 +-40 +91 +73 +32 +36 +81 +59 +16 +86 +4 +18 +-22 +28 +-2 +-89 +3 +-77 +-87 +-26 +-54 +17 +-50 +85 +-78 +-96 +-37 +-42 +91 +3 +-46 +93 +-33 +-84 +82 +-87 +-15 +-73 +-40 +20 +-31 +-57 +60 +-41 +92 +-76 +-94 +0 +-89 +-53 +82 +0 +-97 +-70 +-66 +28 +87 +-42 +-69 +77 +69 +96 +52 +-98 +2 +2 +-44 +77 +14 +-51 +97 +93 +50 +-17 +-83 +-15 +-94 +33 +21 +91 +-9 +-49 +79 +86 +-4 +-21 +-81 +95 +-52 +53 +23 +-7 +-63 +2 +-56 +31 +0 +-82 +-89 +30 +41 +38 +13 +57 +74 +-11 +-44 +81 +-52 +-92 +58 +5 +-65 +-32 +75 +-27 +-60 +-62 +-82 +85 +-23 +30 +-60 +-53 +-54 +30 +79 +-99 +70 +-15 +-97 +-15 +57 +23 +-76 +-2 +6 +-51 +5 +-67 +-32 +-65 +-62 +11 +77 +64 +-38 +-88 +76 +-40 +-86 +-51 +-29 +80 +87 +79 +-78 +19 +4 +43 +-17 +66 +-79 +-36 +82 +50 +-41 +-29 +-7 +52 +59 +17 +-44 +75 +-37 +-85 +-74 +-14 +-15 +-12 +97 +-63 +-40 +-85 +-81 +-80 +-89 +-12 +-58 +-15 +88 +82 +-45 +-99 +-51 +24 +-19 +-3 +60 +65 +-21 +-87 +-17 +-90 +-76 +-59 +-70 +-66 +-60 +-17 +-27 +28 +-99 +29 +-57 +6 +61 +54 +22 +61 +11 +-55 +-79 +73 +5 +25 +71 +72 +49 +-5 +-3 +84 +-55 +-32 +-8 +18 +-9 +-44 +-34 +-67 +39 +-50 +-90 +-24 +-65 +-44 +-53 +15 +-5 +-17 +17 +58 +-44 +18 +32 +-80 +94 +9 +28 +95 +-28 +-89 +12 +46 +86 +2 +87 +-79 +63 +-15 +-85 +-12 +58 +-21 +-87 +27 +-16 +-32 +83 +67 +19 +-30 +11 +-66 +94 +85 +-16 +6 +-75 +-38 +-69 +-42 +-3 +-74 +-91 +1 +-58 +82 +-76 +67 +-58 +72 +46 +64 +-98 +-21 +-71 +-14 +-60 +-94 +-20 +59 +69 +-61 +-63 +82 +1 +-19 +-51 +-52 +-13 +-61 +48 +73 +-43 +1 +-98 +-95 +-62 +-67 +28 +2 +-73 +-18 +-82 +44 +42 +-31 +9 +-60 +44 +-66 +16 +55 +-91 +65 +18 +21 +-68 +42 +-28 +-58 +-72 +18 +38 +15 +-19 +90 +42 +-92 +-75 +-86 +58 +-82 +28 +-46 +45 +-75 +51 +58 +6 +22 +29 +-11 +-50 +10 +-6 +83 +-96 +-4 +-60 +43 +-96 +-43 +-55 +56 +10 +-97 +-65 +-48 +-66 +77 +40 +-15 +27 +0 +-84 +4 +-42 +-86 +-49 +-15 +30 +-16 +26 +18 +-19 +29 +94 +86 +-24 +-59 +89 +81 +-86 +76 +91 +56 +97 +-35 +38 +56 +-64 +38 +99 +61 +-95 +-31 +-89 +47 +2 +25 +-75 +-70 +52 +-17 +80 +-55 +-2 +4 +-42 +-44 +-11 +81 +-94 +18 +28 +-81 +12 +-45 +-23 +-96 +-45 +-49 +-33 +38 +-41 +17 +85 +29 +95 +-88 +52 +39 +98 +18 +5 +-78 +-95 +-89 +-40 +-2 +-35 +6 +-97 +15 +-92 +-47 +-3 +-85 +37 +12 +35 +-5 +80 +76 +-24 +38 +9 +-63 +58 +23 +-97 +67 +-77 +13 +33 +0 +-97 +43 +-86 +-73 +-13 +-72 +89 +47 +-13 +92 +86 +51 +-34 +-4 +-43 +-49 +50 +37 +83 +-5 +-14 +-34 +29 +46 +-50 +4 +-68 +-79 +21 +75 +93 +92 +-43 +-87 +-78 +-91 +0 +69 +63 +5 +-40 +-26 +-93 +-3 +66 +-24 +-73 +28 +-64 +-41 +0 +-63 +-83 +57 +-33 +-63 +76 +-93 +-11 +25 +-55 +60 +-26 +-5 +56 +-15 +43 +-70 +82 +78 +-10 +-16 +54 +82 +-81 +-98 +22 +83 +-24 +80 +-80 +-17 +52 +-67 +-10 +84 +-70 +53 +93 +50 +-91 +-4 +72 +-85 +-87 +4 +-95 +71 +8 +-91 +22 +-15 +-26 +-86 +10 +-11 +6 +-90 +-72 +-1 +36 +-93 +-35 +60 +94 +25 +28 +-19 +52 +69 +24 +-14 +44 +93 +-71 +97 +-5 +24 +-93 +10 +30 +-33 +-54 +23 +-70 +24 +9 +19 +91 +-84 +49 +-92 +-4 +64 +-60 +15 +-40 +56 +-88 +17 +39 +87 +46 +90 +89 +72 +-25 +21 +28 +-18 +-26 +-45 +-24 +13 +-19 +3 +-87 +-9 +-10 +-86 +-84 +55 +56 +41 +45 +21 +80 +86 +-7 +17 +47 +99 +-58 +98 +-99 +-73 +23 +16 +-98 +21 +23 +-50 +14 +75 +-63 +47 +48 +-35 +0 +47 +18 +74 +-58 +-21 +-3 +67 +22 +-8 +39 +-76 +66 +-87 +-9 +-4 +-69 +-7 +38 +44 +-34 +54 +-78 +-40 +83 +-11 +11 +-13 +-87 +-18 +19 +74 +-70 +-3 +-20 +49 +-45 +71 +-27 +68 +1 +72 +92 +-26 +-46 +-75 +-25 +-73 +10 +-38 +-64 +35 +93 +-81 +24 +-79 +55 +46 +40 +-3 +-11 +-63 +0 +-13 +-53 +-44 +58 +27 +-61 +-80 +-83 +-49 +99 +-26 +92 +-67 +83 +33 +20 +26 +-27 +-14 +17 +81 +41 +94 +-32 +-58 +81 +39 +-55 +56 +-32 +70 +53 +39 +-32 +-39 +78 +-73 +-21 +-54 +5 +9 +55 +-13 +58 +40 +32 +-32 +66 +66 +48 +80 +-20 +75 +-85 +33 +95 +-72 +42 +69 +97 +45 +-46 +-26 +-36 +77 +8 +-28 +84 +-63 +73 +-65 +89 +29 +63 +98 +-99 +21 +94 +53 +30 +46 +2 +11 +-94 +49 +86 +33 +-41 +-81 +77 +-17 +-86 +77 +-80 +-56 +-37 +-23 +56 +-98 +13 +60 +11 +-34 +-92 +-89 +60 +49 +43 +65 +8 +40 +77 +37 +49 +24 +90 +-82 +-64 +51 +86 +95 +-56 +-90 +97 +1 +-51 +-39 +-57 +60 +85 +82 +9 +57 +69 +77 +6 +88 +41 +-1 +90 +69 +52 +-60 +94 +20 +29 +87 +-21 +31 +62 +-83 +-81 +-68 +63 +-25 +-30 +5 +46 +64 +56 +69 +-23 +-47 +79 +74 +-3 +26 +-63 +75 +27 +-83 +-71 +-77 +-51 +34 +-11 +35 +-77 +-15 +-11 +-99 +89 +20 +-43 +-33 +-8 +-66 +-67 +8 +30 +-83 +26 +-58 +98 +-82 +-36 +78 +79 +-92 +-26 +-1 +33 +31 +-70 +-60 +-20 +-82 +-1 +-37 +-85 +-17 +71 +-91 +36 +-91 +-35 +-9 +24 +44 +2 +-27 +91 +39 +-98 +-18 +-57 +-3 +36 +-2 +18 +3 +-3 +-23 +37 +-48 +-9 +-19 +29 +63 +35 +36 +-99 +-53 +58 +-67 +21 +-44 +62 +-9 +-54 +0 +35 +-94 +-68 +93 +44 +-66 +-12 +-17 +-42 +86 +-7 +17 +-36 +81 +8 +-6 +50 +29 +78 +-97 +99 +-65 +5 +-2 +-76 +-14 +9 +14 +-32 +-32 +-36 +-18 +-79 +44 +-34 +-20 +26 +-21 +40 +57 +-87 +85 +-24 +-12 +79 +22 +-49 +-67 +-97 +11 +-49 +46 +73 +46 +-43 +-13 +24 +77 +35 +22 +-72 +32 +3 +-77 +66 +-18 +-89 +74 +45 +-32 +5 +-11 +-63 +20 +-74 +28 +56 +-63 +62 +9 +-83 +13 +-87 +44 +-30 +95 +-35 +-29 +-59 +-56 +65 +83 +-71 +42 +-94 +-22 +44 +-64 +-64 +96 +-28 +-23 +-71 +-42 +-5 +-18 +92 +-94 +-80 +-88 +3 +-29 +40 +-94 +-83 +7 +-86 +92 +54 +-71 +68 +62 +-23 +-66 +-68 +29 +-26 +-24 +40 +-21 +-4 +-69 +61 +49 +-69 +-87 +17 +44 +-43 +30 +-19 +68 +-82 +-42 +3 +-87 +-87 +97 +21 +32 +-39 +91 +-12 +-36 +-91 +-83 +-13 +-23 +-47 +89 +55 +-93 +-88 +87 +85 +-63 +20 +54 +21 +-54 +-59 +60 +-97 +-8 +-85 +57 +25 +64 +-60 +91 +-6 +64 +-44 +-72 +-79 +38 +3 +-73 +-91 +-4 +64 +-34 +-36 +62 +33 +86 +-67 +-1 +-79 +-94 +-3 +-3 +63 +-31 +-45 +-80 +52 +5 +-42 +-60 +-61 +32 +54 +-55 +14 +63 +-88 +-31 +75 +-17 +-5 +74 +-22 +-74 +92 +-86 +-99 +4 +-64 +70 +35 +-76 +-51 +-32 +-28 +55 +-11 +-43 +28 +-31 +-69 +-76 +31 +74 +-64 +-18 +-16 +0 +24 +-3 +28 +-94 +17 +-35 +28 +-31 +62 +77 +-5 +-15 +-16 +7 +36 +75 +71 +53 +29 +-6 +-41 +-5 +9 +11 +-31 +-23 +94 +-50 +-5 +-97 +39 +18 +-23 +24 +-74 +73 +-67 +-11 +-79 +81 +-84 +-37 +72 +-27 +-94 +-51 +-5 +40 +-88 +41 +27 +-82 +17 +16 +23 +-56 +-44 +-94 +-25 +-47 +29 +15 +-6 +45 +-20 +88 +88 +50 +-85 +-3 +23 +49 +95 +8 +-12 +-45 +-11 +67 +91 +-90 +5 +16 +-46 +27 +-63 +58 +1 +60 +-19 +41 +-25 +98 +-79 +93 +91 +-47 +72 +99 +12 +5 +-80 +15 +63 +27 +-86 +78 +-36 +-29 +-3 +47 +-13 +7 +-24 +52 +-77 +-70 +-12 +59 +-75 +80 +61 +23 +57 +-31 +36 +70 +3 +82 +-74 +-90 +83 +17 +83 +-3 +-40 +95 +59 +12 +29 +91 +-49 +58 +-37 +-77 +-66 +75 +85 +-27 +72 +13 +-43 +6 +-9 +53 +-59 +85 +91 +-88 +41 +-83 +51 +85 +-87 +94 +-8 +18 +66 +16 +-71 +26 +22 +82 +46 +21 +-44 +-32 +38 +-66 +-86 +-50 +-31 +9 +67 +70 +-4 +67 +40 +93 +73 +44 +47 +81 +-63 +32 +8 +-73 +76 +80 +72 +-26 +-9 +99 +56 +-6 +-93 +-80 +29 +33 +65 +-68 +-83 +-70 +-96 +-94 +79 +-32 +50 +-8 +75 +-10 +46 +13 +-78 +65 +-9 +50 +-94 +18 +42 +3 +-83 +7 +58 +-72 +-23 +40 +43 +-6 +98 +36 +35 +66 +13 +-63 +71 +6 +-8 +-27 +62 +65 +82 +77 +61 +-97 +45 +82 +-14 +-40 +84 +93 +95 +-32 +-23 +-61 +-10 +-29 +-94 +12 +16 +48 +87 +-32 +51 +75 +11 +23 +74 +74 +-42 +-16 +57 +-73 +29 +-74 +-75 +-44 +53 +18 +62 +-49 +-63 +-85 +-19 +2 +-23 +-88 +-96 +29 +-50 +6 +-63 +-1 +-42 +-18 +-14 +0 +30 +-48 +83 +-81 +-48 +-10 +62 +-41 +-54 +60 +-88 +72 +-70 +-22 +-44 +6 +-98 +-3 +-13 +99 +7 +-5 +-25 +9 +-35 +-61 +73 +-43 +-53 +-42 +-39 +33 +78 +30 +38 +72 +4 +-2 +-99 +-21 +-74 +-4 +-71 +-94 +43 +-13 +81 +18 +78 +82 +70 +-40 +13 +-92 +44 +-84 +48 +98 +-50 +-15 +-68 +-43 +-15 +-94 +71 +-42 +0 +-7 +35 +56 +53 +-52 +96 +38 +-89 +45 +-81 +89 +88 +-75 +-23 +3 +-34 +12 +-15 +-77 +-98 +36 +-30 +4 +45 +-48 +48 +-42 +98 +10 +35 +76 +41 +-41 +-83 +-23 +-35 +-71 +2 +73 +-9 +59 +7 +95 +22 +-70 +88 +-66 +-96 +28 +-9 +71 +-63 +-82 +40 +-76 +59 +-60 +57 +94 +96 +-25 +93 +-68 +69 +-95 +16 +48 +83 +-26 +-73 +30 +84 +-77 +18 +-58 +-79 +-90 +-66 +-42 +-72 +-36 +-69 +67 +-82 +-41 +-99 +78 +59 +-3 +-86 +-5 +32 +61 +-39 +-61 +-95 +20 +-14 +66 +-41 +-48 +60 +-24 +-94 +-6 +98 +95 +6 +-93 +-5 +72 +-44 +7 +52 +-60 +32 +-31 +99 +9 +42 +50 +28 +8 +10 +-39 +42 +-47 +87 +-37 +8 +-87 +-43 +-62 +28 +17 +7 +47 +-18 +-57 +36 +88 +36 +-87 +90 +-66 +-81 +63 +77 +-92 +-79 +50 +32 +-97 +-75 +-6 +59 +-26 +-58 +-68 +3 +-26 +-95 +0 +3 +67 +-57 +82 +90 +80 +-15 +13 +-61 +38 +16 +88 +54 +-1 +-26 +55 +52 +86 +-48 +45 +-76 +44 +6 +-29 +55 +80 +50 +70 +-81 +50 +94 +-8 +-37 +-24 +54 +-90 +91 +-12 +69 +-31 +48 +-48 +88 +39 +-18 +-23 +-60 +26 +-58 +-30 +-90 +13 +-51 +-14 +-78 +97 +54 +-18 +26 +-33 +89 +-54 +-94 +41 +30 +77 +-76 +-83 +39 +-92 +-11 +27 +-42 +-18 +-93 +-24 +80 +-1 +66 +85 +10 +11 +-68 +27 +-48 +47 +-71 +-48 +-87 +-39 +-44 +62 +92 +-74 +83 +-63 +74 +41 +82 +-89 +-46 +36 +-70 +-20 +-98 +35 +-51 +10 +56 +-98 +17 +-47 +9 +-67 +-91 +38 +-1 +69 +-16 +27 +67 +20 +-10 +-73 +30 +13 +16 +-72 +-60 +-65 +-74 +-37 +-68 +63 +57 +-14 +-21 +56 +1 +81 +79 +23 +-65 +18 +71 +59 +-6 +27 +87 +94 +66 +-53 +-61 +9 +60 +-66 +-59 +68 +-74 +74 +97 +93 +-61 +71 +48 +97 +37 +75 +-7 +88 +-12 +34 +-89 +-48 +81 +-35 +63 +-34 +34 +6 +-1 +70 +-36 +16 +18 +89 +-52 +-44 +-46 +31 +5 +13 +29 +-96 +94 +55 +-50 +-28 +-94 +29 +71 +80 +-99 +77 +41 +-40 +-82 +-45 +-14 +-25 +87 +50 +5 +-58 +-63 +-69 +70 +-13 +-99 +-51 +0 +1 +-8 +-66 +-19 +63 +-95 +16 +-72 +82 +15 +-28 +10 +-80 +-96 +50 +-80 +96 +95 +21 +-24 +-28 +28 +20 +88 +2 +11 +67 +28 +85 +96 +-21 +-76 +-46 +0 +-49 +56 +-57 +20 +-14 +-52 +-67 +-93 +-17 +47 +-63 +56 +-56 +-74 +44 +1 +-51 +52 +38 +-66 +63 +-9 +86 +-11 +-15 +-17 +-16 +29 +88 +-43 +0 +24 +33 +-52 +-31 +15 +-63 +14 +-73 +-80 +72 +88 +2 +6 +-8 +54 +-15 +84 +38 +-55 +-48 +-93 +29 +-1 +-73 +96 +41 +-44 +83 +27 +-12 +-12 +-49 +-45 +-87 +78 +-57 +-41 +81 +4 +-70 +63 +89 +-70 +-73 +-56 +-73 +-33 +70 +43 +71 +32 +-57 +-92 +-19 +55 +95 +-53 +24 +-54 +9 +49 +-18 +17 +97 +27 +-59 +39 +-70 +-29 +76 +91 +2 +99 +-11 +-4 +-59 +-90 +0 +19 +84 +-63 +89 +-9 +-99 +-16 +48 +-56 +14 +95 +33 +-31 +-3 +96 +86 +-83 +-34 +-1 +88 +-30 +-19 +-57 +-30 +46 +-10 +-7 +34 +4 +17 +54 +-1 +-59 +-58 +-12 +-77 +3 +71 +-8 +66 +-28 +-80 +-78 +75 +-18 +61 +-44 +24 +25 +-73 +80 +-83 +-40 +40 +-34 +-8 +-11 +-42 +36 +52 +39 +-70 +-54 +-31 +-66 +80 +33 +-15 +-69 +88 +-61 +82 +43 +69 +-58 +-27 +-52 +-22 +-16 +-83 +89 +-93 +96 +36 +81 +-76 +-75 +65 +-51 +57 +-82 +-99 +-96 +39 +34 +11 +3 +97 +11 +-38 +57 +88 +15 +-27 +-8 +34 +-30 +-1 +5 +59 +-45 +-99 +-80 +0 +32 +30 +68 +-31 +-77 +-31 +5 +-4 +68 +-63 +-64 +12 +3 +80 +31 +-70 +-50 +67 +19 +-59 +-33 +90 +-91 +-47 +-98 +-88 +-96 +-55 +22 +-94 +29 +-55 +-89 +-46 +-66 +15 +-84 +39 +10 +11 +-55 +53 +-58 +8 +73 +-35 +18 +11 +-5 +94 +56 +-79 +80 +-14 +74 +76 +-60 +-17 +58 +12 +-32 +-74 +41 +45 +2 +-23 +-10 +-14 +-99 +96 +22 +81 +-35 +-93 +-84 +-64 +67 +24 +3 +11 +-33 +30 +88 +-53 +24 +-56 +15 +60 +-41 +-12 +19 +-7 +-83 +23 +91 +39 +24 +-50 +18 +-25 +-7 +75 +-68 +-7 +63 +-10 +95 +24 +86 +95 +39 +-58 +13 +24 +23 +-84 +-88 +56 +22 +-11 +0 +-32 +-98 +31 +54 +-74 +45 +1 +-11 +7 +-75 +-35 +-11 +-64 +97 +93 +44 +-2 +-66 +51 +-94 +-67 +33 +-42 +-14 +35 +-72 +90 +29 +-18 +-92 +19 +-91 +-6 +-68 +66 +6 +-15 +-28 +98 +90 +13 +96 +-89 +-1 +86 +-4 +-98 +-69 +2 +91 +50 +-50 +12 +-10 +37 +-83 +-72 +-19 +-96 +58 +-61 +-57 +10 +-3 +34 +12 +-92 +-67 +50 +31 +47 +22 +13 +-67 +2 +90 +-70 +-98 +83 +39 +-20 +71 +-93 +71 +-95 +30 +84 +50 +-91 +-26 +25 +-48 +73 +-96 +-36 +83 +7 +-71 +-51 +-96 +22 +96 +-7 +-31 +46 +80 +36 +-73 +95 +-63 +-67 +22 +-88 +41 +71 +-97 +-84 +24 +-10 +37 +-59 +75 +62 +-91 +88 +18 +-75 +-60 +89 +28 +69 +-58 +-99 +40 +87 +-4 +42 +-17 +44 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ce33b86 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +matplotlib +numpy +pygame +graphviz diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/constants.py b/utils/constants.py new file mode 100644 index 0000000..b68a192 --- /dev/null +++ b/utils/constants.py @@ -0,0 +1,5 @@ +from utils.literal import Literal + +MAX_VALUE = Literal(99999999999999999999) +MIN_VALUE = Literal(-99999999999999999999) + diff --git a/utils/game.py b/utils/game.py new file mode 100644 index 0000000..cdb9dff --- /dev/null +++ b/utils/game.py @@ -0,0 +1,53 @@ +import pygame + +class Game: + + def __init__(self, title, fps=60, size=(640, 400)): + self.title = title + self.fps = fps + self.size = size + self.clock = pygame.time.Clock() + self.dt = 0 + self.screen = None + + def init_game(self): + pygame.init() + pygame.display.set_caption(self.title) + self.screen = pygame.display.set_mode(self.size) + + + def game_loop(self): + while True: + # Berechnung der Zeitdifferenz seit dem letzten Frame + self.dt = self.clock.tick(self.fps) / 1000 + if self.event_handling() == False: + break + if self.update_game() == False: + break + self.draw_game() + + def exit_game(self): + pygame.quit() + + def event_handling(self): # bleibt in der Unterklasse unverändert + for event in pygame.event.get(): + if not self.handle_event(event): + return False + return True + + def handle_event(self, event): # wird in der Unterklasse überschrieben + if event.type == pygame.QUIT: + return False + return True + + def update_game(self): + return True + + def draw_game(self): + pygame.display.flip() + + def run(self): + self.init_game() + self.game_loop() + self.exit_game() + diff --git a/utils/literal.py b/utils/literal.py new file mode 100644 index 0000000..c574306 --- /dev/null +++ b/utils/literal.py @@ -0,0 +1,103 @@ + +class Literal: + def __init__(self, value): + """Initialisiert Literal.""" + if isinstance(value, Literal): + self.value = value.value + else: + self.value = value + self.read_count = 0 + self.compare_count = 0 + + def reset_counters(self): + """Setzt alle Zähler auf 0 zurück.""" + self.read_count = 0 + self.compare_count = 0 + + def get(self): + """Liest den Wert aus.""" + self.read_count += 1 + return self.value + + def __eq__(self, other): + """Vergleicht den Wert mit einem anderen Wert.""" + if other is None: + return False + assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell" + self.compare_count += 1 + self.read_count += 1 + other.read_count += 1 + return self.value == other.value + + def __ne__(self, other): + """Vergleicht den Wert der Speicherzelle mit einem anderen Wert.""" + if other is None: + return True + assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell" + self.compare_count += 1 + self.read_count += 1 + other.read_count += 1 + return self.value != other.value + + def __lt__(self, other): + """Vergleicht den Wert der Speicherzelle mit einem anderen Wert.""" + assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell" + self.compare_count += 1 + self.read_count += 1 + other.read_count += 1 + return self.value < other.value + + def __le__(self, other): + """Vergleicht den Wert der Speicherzelle mit einem anderen Wert.""" + assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell" + self.compare_count += 1 + self.read_count += 1 + other.read_count += 1 + return self.value <= other.value + + def __gt__(self, other): + """Vergleicht den Wert der Speicherzelle mit einem anderen Wert.""" + assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell" + self.compare_count += 1 + self.read_count += 1 + other.read_count += 1 + return self.value > other.value + + def __ge__(self, other): + """Vergleicht den Wert der Speicherzelle mit einem anderen Wert.""" + assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell" + self.compare_count += 1 + self.read_count += 1 + other.read_count += 1 + return self.value >= other.value + + def __str__(self): + """Repräsentation des Werts.""" + return f"{self.value}" + + def __repr__(self): + """Repräsentation des Werts für Debugging-Zwecke.""" + return f"Literal(value={self.value}, reads={self.read_count})" + + def get_read_count(self): + """Gibt zurück, wie oft der Wert gelesen wurde.""" + return self.read_count + + def __int__(self): + """Gibt den Wert als Integer zurück.""" + self.read_count += 1 + return int(self.value) + + def succ(self): + return Literal(self.value+1) + + def pred(self): + return Literal(self.value-1) + + +if __name__ == "__main__": + l1 = Literal(5) + l2 = Literal(3) + print(l1 == l2) + print(l1 > l2) + diff --git a/utils/memory_array.py b/utils/memory_array.py new file mode 100644 index 0000000..a8e033c --- /dev/null +++ b/utils/memory_array.py @@ -0,0 +1,126 @@ +from utils.literal import Literal +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.project_dir import get_path +from random import randint + +class MemoryArray: + + def __init__(self, parm): + if isinstance(parm, Literal): + self.init_with_size(parm) + elif isinstance(parm, list): + self.size = len(parm) + self.cells = [MemoryCell(value) for value in parm] + else: + raise ValueError("Invalid parameter type") + + def init_with_size(self, size): + """Initialisiert ein Speicherarray mit einer bestimmten Größe.""" + assert isinstance(size, Literal), "Size must be a Literal or MemoryCell" + assert isinstance(size.value, int), "Size must be an int" + assert size.value > 0, "Size must be positive" + self.size = size.value + self.cells = [MemoryCell() for _ in range(self.size)] + + def __getitem__(self, index): + """Gibt den Wert einer Speicherzelle zurück.""" + assert isinstance(index, Literal), "Index must be a Literal or MemoryCell" + assert isinstance(index.value, int), "Index value must be an int" + assert 0 <= index.value < self.size, "Index out of bounds" + return self.cells[index.value] + + def __setitem__(self, index, value): + """Setzt den Wert einer Speicherzelle.""" + assert isinstance(index, Literal), "Index must be a Literal or MemoryCell" + assert isinstance(index.value, int), "Index value must be an int" + assert 0 <= index.value < self.size, "Index out of bounds" + assert isinstance(value, Literal), "Value must be a Literal or MemoryCell" + self.cells[index.value].set(value.value) + + def __len__(self): + """Gibt die Größe des Speicherarrays zurück.""" + return self.size + + def __str__(self): + """Gibt eine Liste der Speicherzellen zurück.""" + return str([cell.value for cell in self.cells]) + + def __iter__(self): + """Gibt einen Iterator über die Speicherzellen zurück.""" + return iter(self.cells) + + def indices(self): + """Gibt eine Liste der Indizes der Speicherzellen zurück.""" + return [Literal(i) for i in range(self.size)] + + def length(self): + """Gibt die Größe des Speicherarrays zurück.""" + return Literal(self.size) + + def count_compares(self): + return sum([cell.compare_count for cell in self.cells]) + + + def reset_counters(self): + """Setzt alle Zähler auf 0 zurück.""" + for cell in self.cells: + cell.reset_counters() + + @staticmethod + def create_random_array(count, min_value, max_value): + """Erzeugt ein zufälliges Speicherarray.""" + size = Literal(count) + a = MemoryArray(size) + for i in a.indices(): + a[i] = Literal(randint(min_value, max_value)) + a.reset_counters() + return a + + @staticmethod + def create_sorted_array(count): + """Erzeugt ein sortiertes Speicherarray.""" + a = MemoryArray(list(range(count))) + a.reset_counters() + return a + + + @staticmethod + def create_array_from_file(filename, limit=None): + """Erzeugt ein Speicherarray aus einer Datei.""" + filename = get_path(filename) + with open(filename) as f: + lines = f.readlines() + if limit is not None: + lines = lines[:limit] + size = Literal(len(lines)) + a = MemoryArray(size) + for i, line in enumerate(lines): + a[Literal(i)] = Literal(int(line)) + a.reset_counters() + return a + + def __str__(self): + result = "[ " + for cell in self.cells: + result += str(cell) + ", " + result += "]" + return result + + +if __name__ == "__main__": + import random + size = Literal(5) + a = MemoryArray(size) + for i in a.indices(): + a[i] = Literal(random.randint(1,100)) + print(a) + s = MemoryCell(0) + for cell in a.cells: + s += cell + print(s) + print(f"Anzahl der Additionen: {MemoryManager.count_adds()}") + + a = MemoryArray.create_array_from_file("data/seq0.txt") + print(a) + diff --git a/utils/memory_cell.py b/utils/memory_cell.py new file mode 100644 index 0000000..ae748c3 --- /dev/null +++ b/utils/memory_cell.py @@ -0,0 +1,194 @@ +from utils.memory_manager import MemoryManager +from utils.literal import Literal + +class MemoryCell (Literal): + + def __new__(cls, *args, **kwargs): + """Erstellt eine neue Instanz von MemoryCell.""" + instance = MemoryManager().acquire_cell() + if instance is None: + instance = super().__new__(cls) + MemoryManager().register_cell(instance) + return instance + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + MemoryManager().release_cell(self) + + def __init__(self, value=None): + """Initialisiert eine Speicherzelle mit optionalem Startwert.""" + super().__init__(value) + self.write_count = 0 + self.add_count = 0 + self.sub_count = 0 + self.mul_count = 0 + self.div_count = 0 + self.bitop_count = 0 + if value is not None: + self.write_count +=1 + else: + self.value = 0 + + def reset_counters(self): + """Setzt alle Zähler auf 0 zurück.""" + super().reset_counters() + self.write_count = 0 + self.add_count = 0 + self.sub_count = 0 + self.mul_count = 0 + self.div_count = 0 + self.bitop_count = 0 + + def set(self, new_value): + """Schreibt einen neuen Wert in die Speicherzelle und erhöht den Schreibzähler.""" + self.write_count += 1 + if isinstance(new_value, Literal): + self.value = new_value.value + else: + self.value = new_value + + def add(self, other): + """Addiert den Wert der Speicherzelle mit einem anderen Wert.""" + self.set((self + other).value) + + def sub(self, other): + """Subtrahiert den Wert der Speicherzelle mit einem anderen Wert.""" + self.set((self - other).value) + + def mul(self, other): + """Multipliziert den Wert der Speicherzelle mit einem anderen Wert.""" + self.set((self * other).value) + + def div(self, other): + """Dividiert den Wert der Speicherzelle durch einen anderen Wert.""" + self.set((self // other).value) + + def modulo(self, other): + """Berechnet den Modulo des Wertes der Speicherzelle durch einen anderen Wert.""" + self.set((self % other).value) + + def lshift(self, other): + """Verschiebt den Wert der Speicherzelle um eine bestimmte Anzahl von Bits nach links.""" + assert isinstance(other, Literal), "Can only lshift Literal or MemoryCell by MemoryCell" + self.bitop_count += 1 + self.read_count += 1 + self.write_count += 1 + other.read_count += 1 + self.value <<= other.value + + def rshift(self, other): + """Verschiebt den Wert der Speicherzelle um eine bestimmte Anzahl von Bits nach rechts.""" + assert isinstance(other, Literal), "Can only rshift Literal or MemoryCell by MemoryCell" + self.bitop_count += 1 + self.read_count += 1 + self.write_count += 1 + other.read_count += 1 + self.value >>= other.value + + def and_op(self, other): + """Führt ein Bitweise AND auf den Wert der Speicherzelle mit einem anderen Wert aus.""" + assert isinstance(other, Literal), "Can only and Literal or MemoryCell with MemoryCell" + self.bitop_count += 1 + self.read_count += 1 + self.write_count += 1 + other.read_count += 1 + self.value &= other.value + + def or_op(self, other): + """Führt ein Bitweise OR auf den Wert der Speicherzelle mit einem anderen Wert aus.""" + assert isinstance(other, Literal), "Can only or Literal or MemoryCell with MemoryCell" + self.bitop_count += 1 + self.read_count += 1 + self.write_count += 1 + other.read_count += 1 + self.value |= other.value + + def xor_op(self, other): + """Führt ein Bitweise XOR auf den Wert der Speicherzelle mit einem anderen Wert aus.""" + assert isinstance(other, Literal), "Can only xor Literal or MemoryCell with MemoryCell" + self.bitop_count += 1 + self.read_count += 1 + self.write_count += 1 + other.read_count += 1 + self.value ^= other.value + + def get_write_count(self): + """Gibt zurück, wie oft der Wert geschrieben wurde.""" + return self.write_count + + def __repr__(self): + """Repräsentation der Speicherzelle für Debugging-Zwecke.""" + return f"MemoryCell(value={self.value}, reads={self.read_count}, writes={self.write_count})" + + def __add__(self, other): + assert isinstance(other, Literal), "Can only add Literal or MemoryCell to MemoryCell" + self.add_count += 1 + self.read_count += 1 + other.read_count += 1 + return Literal(self.value + other.value) + + def __sub__(self, other): + assert isinstance(other, Literal), "Can only add Literal or MemoryCell to MemoryCell" + self.sub_count += 1 + self.read_count += 1 + other.read_count += 1 + return Literal(self.value - other.value) + + def __mul__(self, other): + assert isinstance(other, Literal), "Can only mul Literal or MemoryCell with MemoryCell" + self.mul_count += 1 + self.read_count += 1 + other.read_count += 1 + return Literal(self.value * other.value) + + def __truediv__(self, other): + assert isinstance(other, Literal), "Can only div Literal or MemoryCell by MemoryCell" + self.div_count += 1 + self.read_count += 1 + other.read_count += 1 + return Literal(self.value / other.value) + + def __floordiv__(self, other): + assert isinstance(other, Literal), "Can only div Literal or MemoryCell by MemoryCell" + self.div_count += 1 + self.read_count += 1 + other.read_count += 1 + return Literal(self.value // other.value) + + def __mod__(self, other): + assert isinstance(other, Literal), "Can only div Literal or MemoryCell by MemoryCell" + self.div_count += 1 + self.read_count += 1 + other.read_count += 1 + return Literal(self.value % other.value) + + def __iadd__(self, other): + self.add(other) + return self + + def __isub__(self, other): + self.sub(other) + return self + + def __imul__(self, other): + self.mul(other) + return self + + def __itruediv__(self, other): + self.set(self // other) + return self + + def __ifloordiv__(self, other): + self.div(other) + return self + + +if __name__ == "__main__": + a = MemoryCell(5) + b = MemoryCell(3) + a += b + print(f"Ergebnis: {a}") + print(f"a wurde {a.get_read_count()} mal gelesen und {a.get_write_count()} mal geschrieben.") + print(f"b wurde {b.get_read_count()} mal gelesen und {b.get_write_count()} mal geschrieben.") diff --git a/utils/memory_manager.py b/utils/memory_manager.py new file mode 100644 index 0000000..f1a5ba2 --- /dev/null +++ b/utils/memory_manager.py @@ -0,0 +1,148 @@ +import matplotlib.pyplot as plt +import queue + + +class MemoryManager: + + _instance = None + stats = {} + + def __new__(cls, *args, **kwargs): + """Erstellt eine einzige Instanz von MemoryManager.""" + if cls._instance is None: + cls._instance = super().__new__(cls) + cls._instance._initialize() # Eigene Init-Methode, damit __init__ nicht mehrfach läuft + return cls._instance + + def _initialize(self): + """Initialisiert die Speicherverwaltung (einmalig).""" + self.cells = [] + self._pool = queue.Queue() + self._finalizers = {} + + + @staticmethod + def count_cells(): + return len(MemoryManager().cells) + + + @staticmethod + def count_reads(): + return sum([cell.read_count for cell in MemoryManager().cells]) + + @staticmethod + def count_writes(): + return sum([cell.write_count for cell in MemoryManager().cells]) + + @staticmethod + def count_compares(): + return sum([cell.compare_count for cell in MemoryManager().cells]) + + @staticmethod + def count_adds(): + return sum([cell.add_count for cell in MemoryManager().cells]) + + @staticmethod + def count_subs(): + return sum([cell.sub_count for cell in MemoryManager().cells]) + + @staticmethod + def count_muls(): + return sum([cell.mul_count for cell in MemoryManager().cells]) + + @staticmethod + def count_divs(): + return sum([cell.div_count for cell in MemoryManager().cells]) + + @staticmethod + def count_bitops(): + return sum([cell.bitop_count for cell in MemoryManager().cells]) + + @staticmethod + def reset(): + manager = MemoryManager() + for cell in manager.cells: + cell.reset_counters() + + @staticmethod + def purge(): + MemoryManager._instance = None + + @staticmethod + def save_stats(count): + data = { "cells": MemoryManager.count_cells(), + "reads": MemoryManager.count_reads(), + "writes": MemoryManager.count_writes(), + "compares": MemoryManager.count_compares(), + "adds": MemoryManager.count_adds(), + "subs": MemoryManager.count_subs(), + "muls": MemoryManager.count_muls(), + "divs": MemoryManager.count_divs(), + "bitops": MemoryManager.count_bitops() } + MemoryManager.stats[count] = data + + @staticmethod + def plot_stats(labels): + data = MemoryManager.stats + x = list(data.keys()) + + fig, axes = plt.subplots(len(labels), 1, figsize=(8, 4 * len(labels)), sharex=True) + + if len(labels) == 1: + axes = [axes] # Falls nur ein Plot vorhanden ist, in eine Liste umwandeln + + for ax, l in zip(axes, labels): + y = [data[k][l] for k in x] + ax.plot(x, y, label=l) + ax.set_ylabel(l) + ax.legend() + + plt.xlabel("n") + plt.show() + + + def acquire_cell(self): + try: + return self._pool.get_nowait() + except queue.Empty: + return None + + def register_cell(self, cell): + self.cells.append(cell) + + def release_cell(self, cell): + self._pool.put(cell) + + +class Testcell: + + def __new__(cls, *args, **kwargs): + instance = MemoryManager().acquire_cell() + if instance is None: + instance = super().__new__(cls) + MemoryManager().register_cell(instance) + return instance + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + MemoryManager().release_cell(self) + + +if __name__ == "__main__": + + # Einfaches Anlegen einer Zelle + a = Testcell() + print(MemoryManager.count_cells()) + + # Anlegen einer Zelle und Beenden des Scopes + with Testcell() as b: + print(MemoryManager.count_cells()) + + print(MemoryManager.count_cells()) + + # Reuse einer Zelle + c = Testcell() + print(MemoryManager.count_cells()) + diff --git a/utils/memory_range.py b/utils/memory_range.py new file mode 100644 index 0000000..6354159 --- /dev/null +++ b/utils/memory_range.py @@ -0,0 +1,29 @@ +from utils.literal import Literal + +# a generator that yields items instead of returning a list +def mrange(parm1, parm2=None, parm3=None): + if parm2 is None: + start = 0 + stop = int(parm1) + step = 1 + elif parm3 is None: + start = int(parm1) + stop = int(parm2) + step = 1 + else: + start = int(parm1) + stop = int(parm2) + step = int(parm3) + num = start + if step > 0: + while num < stop: + yield Literal(num) + num += step + else: + while num > stop: + yield Literal(num) + num += step + +if __name__ == "__main__": + for l in mrange(10): + print(l) diff --git a/utils/priority_queue.py b/utils/priority_queue.py new file mode 100644 index 0000000..7b377bf --- /dev/null +++ b/utils/priority_queue.py @@ -0,0 +1,40 @@ +import heapq + +class PriorityQueue: + def __init__(self): + self.heap = [] + self.entry_finder = {} # map: item -> [priority, item] + self.REMOVED = '' + self.counter = 0 # unique sequence count to break ties + + def add_or_update(self, item, priority): + if item in self.entry_finder: + self.remove(item) + count = self.counter + entry = [priority, count, item] + self.entry_finder[item] = entry + heapq.heappush(self.heap, entry) + self.counter += 1 + + def remove(self, item): + entry = self.entry_finder.pop(item) + entry[-1] = self.REMOVED # mark as removed + + def pop(self): + while self.heap: + priority, count, item = heapq.heappop(self.heap) + if item != self.REMOVED: + del self.entry_finder[item] + return item, priority + return None + +if __name__ == "__main__": + pq = PriorityQueue() + pq.add_or_update('task1', 1) + pq.add_or_update('task2', float('inf')) + pq.add_or_update('task3', float('inf')) + + print(pq.pop()) # Should print ('task1', 1) + pq.add_or_update('task2', 0) # Update priority of 'task1' + print(pq.pop()) # Should print ('task2', 0) + print(pq.pop()) # Should print ('task3', 3) \ No newline at end of file diff --git a/utils/project_dir.py b/utils/project_dir.py new file mode 100644 index 0000000..8c55bff --- /dev/null +++ b/utils/project_dir.py @@ -0,0 +1,13 @@ +from pathlib import Path + +def get_path(filename) -> Path: + this_dir = Path(__file__).resolve().parent + project_dir = this_dir.parent + return project_dir / filename + +if __name__ == "__main__": + filename = get_path("data/seq0.txt") + print(filename) + print(filename.resolve()) + print(filename.is_file()) + print(filename.exists()) diff --git a/utils/test_memory_array.py b/utils/test_memory_array.py new file mode 100644 index 0000000..5b5c81d --- /dev/null +++ b/utils/test_memory_array.py @@ -0,0 +1,47 @@ +from unittest import TestCase +from utils.literal import Literal +from utils.memory_array import MemoryArray +import random + +class TestMemoryArray(TestCase): + + def test_create_array(self): + l = random.randint(5,10) + size = Literal(l) + a = MemoryArray(size) + self.assertEqual(len(a), l) + + def test_set_item(self): + l = random.randint(5,10) + size = Literal(l) + a = MemoryArray(size) + i = Literal(random.randint(0,l-1)) + v = Literal(random.randint(1,100)) + a[i] = v + self.assertEqual(a[i].value, v.value) + + def test_get_item(self): + l = random.randint(5,10) + values = [random.randint(1,100) for _ in range(l)] + a = MemoryArray(values) + for pos, i in enumerate(a.indices()): + self.assertEqual(a[i].value, values[pos]) + + def test_reset_counters(self): + l = random.randint(5,10) + values = [random.randint(1,100) for _ in range(l)] + a = MemoryArray(values) + for i in a.indices(): + self.assertEqual(a[i].write_count, 1) + a.reset_counters() + for i in a.indices(): + self.assertEqual(a[i].write_count, 0) + + def test_create_random_array(self): + a = MemoryArray.create_random_array(10, 1, 100) + self.assertEqual(len(a), 10) + + def test_create_array_from_file(self): + a = MemoryArray.create_array_from_file("data/seq0.txt") + self.assertEqual(len(a), 14) + diff --git a/utils/test_memory_cell.py b/utils/test_memory_cell.py new file mode 100644 index 0000000..8b6578a --- /dev/null +++ b/utils/test_memory_cell.py @@ -0,0 +1,166 @@ +from unittest import TestCase +from utils.memory_cell import MemoryCell +from utils.literal import Literal +import random + + +class TestMemoryCell(TestCase): + + def test_create_cell(self): + v = random.randint(1, 100) + cell = MemoryCell(v) + self.assertEqual(cell.value, v) + self.assertEqual(cell.read_count, 0) + self.assertEqual(cell.write_count, 1) + self.assertEqual(cell.add_count, 0) + self.assertEqual(cell.sub_count, 0) + self.assertEqual(cell.mul_count, 0) + self.assertEqual(cell.div_count, 0) + self.assertEqual(cell.bitop_count, 0) + + def test_cast_cell(self): + v = random.randint(1, 100) + cell = MemoryCell(v) + self.assertEqual(int(cell), v) + self.assertEqual(cell.read_count, 1) + self.assertEqual(cell.write_count, 1) + self.assertEqual(cell.add_count, 0) + self.assertEqual(cell.sub_count, 0) + self.assertEqual(cell.mul_count, 0) + self.assertEqual(cell.div_count, 0) + self.assertEqual(cell.bitop_count, 0) + + def test_add(self): + v1 = random.randint(1, 100) + v2 = random.randint(1, 100) + + # "in place" Addition zweier MemoryCells + cell1 = MemoryCell(v1) + cell2 = MemoryCell(v2) + cell1 += cell2 + self.assertEqual(cell1.value, v1 + v2) + self.assertEqual(cell1.add_count, 1) + self.assertEqual(cell1.read_count, 1) + self.assertEqual(cell2.read_count, 1) + self.assertTrue(isinstance(cell1, MemoryCell)) + self.assertTrue(isinstance(cell2, MemoryCell)) + + # Freie Addition zweier MemoryCells + cell1 = MemoryCell(v1) + cell2 = MemoryCell(v2) + result = cell1 + cell2 + + self.assertEqual(result.value, v1 + v2) + self.assertEqual(cell1.add_count, 1) + self.assertEqual(cell1.read_count, 1) + self.assertEqual(cell2.read_count, 1) + self.assertTrue(isinstance(result, Literal)) + + def test_sub(self): + v1 = random.randint(1, 100) + v2 = random.randint(1, 100) + + # "in place" Subtraktion zweier MemoryCells + cell1 = MemoryCell(v1) + cell2 = MemoryCell(v2) + cell1 -= cell2 + + self.assertEqual(cell1.value, v1 - v2) + self.assertEqual(cell1.sub_count, 1) + self.assertEqual(cell1.read_count, 1) + self.assertEqual(cell2.read_count, 1) + self.assertTrue(isinstance(cell1, MemoryCell)) + self.assertTrue(isinstance(cell2, MemoryCell)) + + # Freie Subtraktion zweier MemoryCells + cell1 = MemoryCell(v1) + cell2 = MemoryCell(v2) + result = cell1 - cell2 + self.assertEqual(result.value, v1 - v2) + self.assertEqual(cell1.sub_count, 1) + self.assertEqual(cell1.read_count, 1) + self.assertEqual(cell2.read_count, 1) + self.assertTrue(isinstance(result, Literal)) + + def test_mul(self): + v1 = random.randint(1, 100) + v2 = random.randint(1, 100) + + # "in place" Multiplikation zweier MemoryCells + cell1 = MemoryCell(v1) + cell2 = MemoryCell(v2) + cell1 *= cell2 + + self.assertEqual(cell1.value, v1 * v2) + self.assertEqual(cell1.mul_count, 1) + self.assertEqual(cell1.read_count, 1) + self.assertEqual(cell2.read_count, 1) + self.assertTrue(isinstance(cell1, MemoryCell)) + self.assertTrue(isinstance(cell2, MemoryCell)) + + # Freie Multiplikation zweier MemoryCells + cell1 = MemoryCell(v1) + cell2 = MemoryCell(v2) + result = cell1 * cell2 + self.assertEqual(result.value, v1 * v2) + self.assertEqual(cell1.mul_count, 1) + self.assertEqual(cell1.read_count, 1) + self.assertEqual(cell2.read_count, 1) + self.assertTrue(isinstance(result, Literal)) + + def test_div(self): + v1 = random.randint(1, 100) + v2 = random.randint(1, 100) + + # "in place" Division zweier MemoryCells + cell1 = MemoryCell(v1) + cell2 = MemoryCell(v2) + cell1 //= cell2 + + self.assertEqual(cell1.value, v1 // v2) + self.assertEqual(cell1.div_count, 1) + self.assertEqual(cell1.read_count, 1) + self.assertEqual(cell2.read_count, 1) + self.assertTrue(isinstance(cell1, MemoryCell)) + self.assertTrue(isinstance(cell2, MemoryCell)) + + # Freie Division zweier MemoryCells + cell1 = MemoryCell(v1) + cell2 = MemoryCell(v2) + result = cell1 // cell2 + self.assertEqual(result.value, v1 // v2) + self.assertEqual(cell1.div_count, 1) + self.assertEqual(cell1.read_count, 1) + self.assertEqual(cell2.read_count, 1) + self.assertTrue(isinstance(result, Literal)) + + def test_reset_counters(self): + v1 = random.randint(1, 100) + v2 = random.randint(1, 100) + cell = MemoryCell(v1) + cell += Literal(v2) + + self.assertEqual(cell.value, v1+v2) + self.assertEqual(cell.read_count, 1) + self.assertEqual(cell.add_count, 1) + self.assertEqual(cell.write_count, 2) + + cell.reset_counters() + + self.assertEqual(cell.value, v1+v2) + self.assertEqual(cell.read_count, 0) + self.assertEqual(cell.add_count, 0) + self.assertEqual(cell.write_count, 0) + + + def test_set(self): + v1 = random.randint(1, 100) + v2 = random.randint(1, 100) + + cell = MemoryCell(v1) + cell.set(v2) + + self.assertEqual(cell.value, v2) + self.assertEqual(cell.read_count, 0) + self.assertEqual(cell.write_count, 2) + diff --git a/vorlesung/L01_grundlagen/euklid.py b/vorlesung/L01_grundlagen/euklid.py new file mode 100644 index 0000000..ae79752 --- /dev/null +++ b/vorlesung/L01_grundlagen/euklid.py @@ -0,0 +1,13 @@ +from utils.memory_cell import MemoryCell +from utils.literal import Literal + +x = MemoryCell(int(input("Erste Zahl: "))) +y = MemoryCell(int(input("Zweite Zahl: "))) + +while x > Literal(0): + if x < y: + x, y = y, x + x -= y +print(y) + +print(f"Insgesamt gab es {x.sub_count + y.sub_count} Subtraktionen.") \ No newline at end of file diff --git a/vorlesung/L02_elementares_sortieren/bubble_game.py b/vorlesung/L02_elementares_sortieren/bubble_game.py new file mode 100644 index 0000000..11bda67 --- /dev/null +++ b/vorlesung/L02_elementares_sortieren/bubble_game.py @@ -0,0 +1,41 @@ +import random +import pygame +from utils.game import Game +from utils.memory_array import MemoryArray +from bubble_sorting import bubble_sort_stepwise + +WHITE = (255, 255, 255) +BLUE = (0, 0, 255) + +class BubbleGame(Game): + + def __init__(self): + super().__init__("Bubble Game", fps=60, size=(400, 400)) + random.seed() + l =list(range(1, 101)) + random.shuffle(l) + self.z = MemoryArray(l) + self.finished = False + self.sort_generator = bubble_sort_stepwise(self.z) + + def update_game(self): + if not self.finished: + try: + next(self.sort_generator) + except StopIteration: + self.finished = True + return True + + def draw_game(self): + self.screen.fill(WHITE) + for i, cell in enumerate(self.z): + x = 50 + i*3 + y = 350 - cell.value * 3 + pygame.draw.rect(self.screen, BLUE, (x, y, 3, 3)) + super().draw_game() + + +if __name__ == "__main__": + b = BubbleGame() + b.run() + diff --git a/vorlesung/L02_elementares_sortieren/bubble_sorting.py b/vorlesung/L02_elementares_sortieren/bubble_sorting.py new file mode 100644 index 0000000..1ee4d8e --- /dev/null +++ b/vorlesung/L02_elementares_sortieren/bubble_sorting.py @@ -0,0 +1,83 @@ +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.memory_range import mrange +from utils.literal import Literal + +def bubble_sort_stepwise(z: MemoryArray): + n = z.length() + for i in mrange(n.pred()): + for j in mrange(n.pred(), i, -1): + if z[j.pred()] > z[j]: + swap(z, j, j.pred()) + yield z + + +def bubble_sort2_stepwise(z: MemoryArray): + n = MemoryCell(z.length()) + true = Literal(1) + false = Literal(0) + sortiert = MemoryCell() + while True: + sortiert.set(true) + for i in mrange(n.pred()): + if z[i] > z[i.succ()]: + swap(z, i, i.succ()) + sortiert.set(false) + yield z + n -= Literal(1) + if sortiert == true or n <= Literal(1): + break + + +def bubble_sort(z: MemoryArray): + sort_generator = bubble_sort_stepwise(z) + while True: + try: + next(sort_generator) + except StopIteration: + break + + +def bubble_sort2(z: MemoryArray): + sort_generator = bubble_sort2_stepwise(z) + while True: + try: + next(sort_generator) + except StopIteration: + break + + +def sort_file(filename, sort_func): + z = MemoryArray.create_array_from_file(filename) + sort_func(z) + return z + +def analyze_complexity(sort_func, sizes, presorted=False): + """ + Analysiert die Komplexität einer Sortierfunktion. + + :param sort_func: Die Funktion, die analysiert wird. + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + if presorted: + random_array = MemoryArray.create_sorted_array(size) + else: + random_array = MemoryArray.create_random_array(size, -100, 100) + sort_func(random_array) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "writes"]) + +def swap(z: MemoryArray, i: int, j: int): + tmp = z[Literal(i)].value + z[Literal(i)] = z[Literal(j)] + z[Literal(j)].set(tmp) + +if __name__ == '__main__': + analyze_complexity(bubble_sort, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) +# analyze_complexity(bubble_sort2, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) +# analyze_complexity(bubble_sort, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100], True) +# analyze_complexity(bubble_sort2, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100], True) diff --git a/vorlesung/L02_elementares_sortieren/insert_game.py b/vorlesung/L02_elementares_sortieren/insert_game.py new file mode 100644 index 0000000..3d17b29 --- /dev/null +++ b/vorlesung/L02_elementares_sortieren/insert_game.py @@ -0,0 +1,41 @@ +import random +import pygame +from utils.game import Game +from utils.memory_array import MemoryArray +from insert_sorting import insert_sort_stepwise + +WHITE = (255, 255, 255) +BLUE = (0, 0, 255) + +class InsertGame(Game): + + def __init__(self): + super().__init__("Insert Game", fps=60, size=(400, 400)) + random.seed() + l =list(range(1, 101)) + random.shuffle(l) + self.z = MemoryArray(l) + self.finished = False + self.sort_generator = insert_sort_stepwise(self.z) + + def update_game(self): + if not self.finished: + try: + next(self.sort_generator) + except StopIteration: + self.finished = True + return True + + def draw_game(self): + self.screen.fill(WHITE) + for i, cell in enumerate(self.z): + x = 50 + i*3 + y = 350 - cell.value * 3 + pygame.draw.rect(self.screen, BLUE, (x, y, 3, 3)) + super().draw_game() + + +if __name__ == "__main__": + b = InsertGame() + b.run() + diff --git a/vorlesung/L02_elementares_sortieren/insert_sorting.py b/vorlesung/L02_elementares_sortieren/insert_sorting.py new file mode 100644 index 0000000..e962dc3 --- /dev/null +++ b/vorlesung/L02_elementares_sortieren/insert_sorting.py @@ -0,0 +1,61 @@ +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.memory_range import mrange +from utils.literal import Literal + +def insert_sort_stepwise(z: MemoryArray): + n = z.length() + j = MemoryCell() + elem = MemoryCell() + for i in mrange(n): + elem.set(z[i]) + j.set(i) + while j > Literal(0) and z[j.pred()] > elem: + z[j].set(z[j.pred()]) + j -= Literal(1) + yield z + z[j].set(elem) + yield z + + +def insert_sort(z: MemoryArray): + sort_generator = insert_sort_stepwise(z) + while True: + try: + next(sort_generator) + except StopIteration: + break + +def sort_file(filename, sort_func): + z = MemoryArray.create_array_from_file(filename) + sort_func(z) + return z + + +def analyze_complexity(sort_func, sizes, presorted=False): + """ + Analysiert die Komplexität einer Sortierfunktion. + + :param sort_func: Die Funktion, die analysiert wird. + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + if presorted: + random_array = MemoryArray.create_sorted_array(size) + else: + random_array = MemoryArray.create_random_array(size, -100, 100) + sort_func(random_array) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "writes"]) + +def swap(z: MemoryArray, i: int, j: int): + tmp = z[Literal(i)].value + z[Literal(i)] = z[Literal(j)] + z[Literal(j)].set(tmp) + +if __name__ == '__main__': + analyze_complexity(insert_sort, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) + #analyze_complexity(insert_sort, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100], True) diff --git a/vorlesung/L02_elementares_sortieren/select_game.py b/vorlesung/L02_elementares_sortieren/select_game.py new file mode 100644 index 0000000..8c65eb3 --- /dev/null +++ b/vorlesung/L02_elementares_sortieren/select_game.py @@ -0,0 +1,41 @@ +import random +import pygame +from utils.game import Game +from utils.memory_array import MemoryArray +from select_sorting import select_sort_stepwise + +WHITE = (255, 255, 255) +BLUE = (0, 0, 255) + +class SelectGame(Game): + + def __init__(self): + super().__init__("Select Game", fps=60, size=(400, 400)) + random.seed() + l =list(range(1, 101)) + random.shuffle(l) + self.z = MemoryArray(l) + self.finished = False + self.sort_generator = select_sort_stepwise(self.z) + + def update_game(self): + if not self.finished: + try: + next(self.sort_generator) + except StopIteration: + self.finished = True + return True + + def draw_game(self): + self.screen.fill(WHITE) + for i, cell in enumerate(self.z): + x = 50 + i*3 + y = 350 - cell.value * 3 + pygame.draw.rect(self.screen, BLUE, (x, y, 3, 3)) + super().draw_game() + + +if __name__ == "__main__": + b = SelectGame() + b.run() + diff --git a/vorlesung/L02_elementares_sortieren/select_sorting.py b/vorlesung/L02_elementares_sortieren/select_sorting.py new file mode 100644 index 0000000..6f80f19 --- /dev/null +++ b/vorlesung/L02_elementares_sortieren/select_sorting.py @@ -0,0 +1,58 @@ +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.memory_range import mrange +from utils.literal import Literal + +def select_sort_stepwise(z: MemoryArray): + n = z.length() + cur_min = MemoryCell() + for i in mrange(n): + cur_min.set(i) + for j in mrange(i.succ(), n): + if z[j] < z[cur_min]: + cur_min.set(j) + swap(z, i, int(cur_min)) + yield z + + +def select_sort(z: MemoryArray): + sort_generator = select_sort_stepwise(z) + while True: + try: + next(sort_generator) + except StopIteration: + break + +def sort_file(filename, sort_func): + z = MemoryArray.create_array_from_file(filename) + sort_func(z) + return z + + +def analyze_complexity(sort_func, sizes, presorted=False): + """ + Analysiert die Komplexität einer Sortierfunktion. + + :param sort_func: Die Funktion, die analysiert wird. + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + if presorted: + random_array = MemoryArray.create_sorted_array(size) + else: + random_array = MemoryArray.create_random_array(size, -100, 100) + sort_func(random_array) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "writes"]) + +def swap(z: MemoryArray, i: int, j: int): + tmp = z[Literal(i)].value + z[Literal(i)] = z[Literal(j)] + z[Literal(j)].set(tmp) + +if __name__ == '__main__': + analyze_complexity(select_sort, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) +# analyze_complexity(select_sort, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100], True) diff --git a/vorlesung/L03_fortgeschrittenes_sortieren/heap_game.py b/vorlesung/L03_fortgeschrittenes_sortieren/heap_game.py new file mode 100644 index 0000000..8523e39 --- /dev/null +++ b/vorlesung/L03_fortgeschrittenes_sortieren/heap_game.py @@ -0,0 +1,42 @@ +import random +import pygame +from utils.game import Game +from utils.memory_array import MemoryArray +from utils.literal import Literal +from heap_sorting import heap_sort_stepwise + +WHITE = (255, 255, 255) +BLUE = (0, 0, 255) + +class HeapGame(Game): + + def __init__(self): + super().__init__("Heap Game", fps=20, size=(400, 400)) + random.seed() + l =list(range(1, 101)) + random.shuffle(l) + self.z = MemoryArray(l) + self.finished = False + self.sort_generator = heap_sort_stepwise(self.z) + + def update_game(self): + if not self.finished: + try: + next(self.sort_generator) + except StopIteration: + self.finished = True + return True + + def draw_game(self): + self.screen.fill(WHITE) + for i, cell in enumerate(self.z): + x = 50 + i*3 + y = 350 - cell.value * 3 + pygame.draw.rect(self.screen, BLUE, (x, y, 3, 3)) + super().draw_game() + + +if __name__ == "__main__": + sort_game = HeapGame() + sort_game.run() + diff --git a/vorlesung/L03_fortgeschrittenes_sortieren/heap_sorting.py b/vorlesung/L03_fortgeschrittenes_sortieren/heap_sorting.py new file mode 100644 index 0000000..3400789 --- /dev/null +++ b/vorlesung/L03_fortgeschrittenes_sortieren/heap_sorting.py @@ -0,0 +1,93 @@ +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.memory_range import mrange +from utils.literal import Literal + +def heap_sort_stepwise(z: MemoryArray): + n = z.length() + yield from make_max_heap(z) + with MemoryCell(n) as heapsize: + for i in mrange(n, 1, -1): + swap(z, 0, i.pred()) + yield z + heapsize.set(heapsize.pred()) + yield from max_heapyfy(z, Literal(1), heapsize) + + +def heap_sort(z: MemoryArray): + sort_generator = heap_sort_stepwise(z) + while True: + try: + next(sort_generator) + except StopIteration: + break + + +def left_child(i: Literal): + return Literal(2 * int(i)) + + +def right_child(i: Literal): + return Literal(2 * int(i) + 1) + + +def adjust_index(i: Literal): + return i.pred() + + +def make_max_heap(z: MemoryArray): + n = z.length() + for i in mrange(int(n) // 2, 0, -1): + yield from max_heapyfy(z, i, n) + + +def max_heapyfy(z: MemoryArray, i: Literal, heapsize: Literal): + l = left_child(i) + r = right_child(i) + with MemoryCell(i) as max_value: + if l <= heapsize and z[adjust_index(l)] > z[adjust_index(i)]: + max_value.set(l) + if r <= heapsize and z[adjust_index(r)] > z[adjust_index(max_value)]: + max_value.set(r) + if max_value != i: + swap(z, int(i)-1, int(max_value)-1) + yield z + yield from max_heapyfy(z, max_value, heapsize) + + +def sort_file(filename, sort_func): + z = MemoryArray.create_array_from_file(filename) + sort_func(z) + return z + + +def analyze_complexity(sort_func, sizes, presorted=False): + """ + Analysiert die Komplexität einer Sortierfunktion. + + :param sort_func: Die Funktion, die analysiert wird. + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + if presorted: + random_array = MemoryArray.create_sorted_array(size) + else: + random_array = MemoryArray.create_random_array(size, -100, 100) + sort_func(random_array) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "writes"]) + + +def swap(z: MemoryArray, i: int, j: int): + tmp = z[Literal(i)].value + z[Literal(i)] = z[Literal(j)] + z[Literal(j)].set(tmp) + + +if __name__ == '__main__': + sizes = range(10, 101, 10) + analyze_complexity(heap_sort, sizes) + # analyze_complexity(quick_sort, sizes, True) diff --git a/vorlesung/L03_fortgeschrittenes_sortieren/quick_game.py b/vorlesung/L03_fortgeschrittenes_sortieren/quick_game.py new file mode 100644 index 0000000..dd2f630 --- /dev/null +++ b/vorlesung/L03_fortgeschrittenes_sortieren/quick_game.py @@ -0,0 +1,42 @@ +import random +import pygame +from utils.game import Game +from utils.memory_array import MemoryArray +from utils.literal import Literal +from quick_sorting import quick_sort_stepwise + +WHITE = (255, 255, 255) +BLUE = (0, 0, 255) + +class QuickGame(Game): + + def __init__(self): + super().__init__("Quick Game", fps=10, size=(400, 400)) + random.seed() + l =list(range(1, 101)) + random.shuffle(l) + self.z = MemoryArray(l) + self.finished = False + self.sort_generator = quick_sort_stepwise(self.z, Literal(0), Literal(self.z.length().pred())) + + def update_game(self): + if not self.finished: + try: + next(self.sort_generator) + except StopIteration: + self.finished = True + return True + + def draw_game(self): + self.screen.fill(WHITE) + for i, cell in enumerate(self.z): + x = 50 + i*3 + y = 350 - cell.value * 3 + pygame.draw.rect(self.screen, BLUE, (x, y, 3, 3)) + super().draw_game() + + +if __name__ == "__main__": + sort_game = QuickGame() + sort_game.run() + diff --git a/vorlesung/L03_fortgeschrittenes_sortieren/quick_sorting.py b/vorlesung/L03_fortgeschrittenes_sortieren/quick_sorting.py new file mode 100644 index 0000000..9857f76 --- /dev/null +++ b/vorlesung/L03_fortgeschrittenes_sortieren/quick_sorting.py @@ -0,0 +1,81 @@ +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.memory_range import mrange +from utils.literal import Literal + +def quick_sort_stepwise(z: MemoryArray, l: Literal, r: Literal): + if l < r: + q = partition(z, l, r) + yield z + yield from quick_sort_stepwise(z, l, q.pred()) + yield from quick_sort_stepwise(z, q.succ(), r) + yield z + + +def partition(z: MemoryArray, l: Literal, r: Literal): + with MemoryCell(z[r]) as pivot, MemoryCell(l) as i, MemoryCell(r.pred()) as j: + while i < j: + while z[i] < pivot: + i.set(i.succ()) + while j > l and z[j] >= pivot: + j.set(j.pred()) + if i < j: + swap(z, int(i), int(j)) + i.set(i.succ()) + j.set(j.pred()) + if i == j and z[i] < pivot: + i.set(i.succ()) + if z[i] != pivot: + swap(z, int(i), int(r)) + return Literal(i) + + +def quick_sort(z: MemoryArray, l: Literal = None, r: Literal = None): + if l is None: + l = Literal(0) + if r is None: + r = z.length().pred() + sort_generator = quick_sort_stepwise(z, l, r) + while True: + try: + next(sort_generator) + except StopIteration: + break + + +def sort_file(filename, sort_func): + z = MemoryArray.create_array_from_file(filename) + sort_func(z) + return z + + +def analyze_complexity(sort_func, sizes, presorted=False): + """ + Analysiert die Komplexität einer Sortierfunktion. + + :param sort_func: Die Funktion, die analysiert wird. + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + if presorted: + random_array = MemoryArray.create_sorted_array(size) + else: + random_array = MemoryArray.create_random_array(size, -100, 100) + sort_func(random_array) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "writes"]) + + +def swap(z: MemoryArray, i: int, j: int): + tmp = z[Literal(i)].value + z[Literal(i)] = z[Literal(j)] + z[Literal(j)].set(tmp) + + +if __name__ == '__main__': + sizes = range(10, 101, 5) + #analyze_complexity(quick_sort, sizes) + analyze_complexity(quick_sort, sizes, True) diff --git a/vorlesung/L04_besondere_sortierverfahren/count_sorting.py b/vorlesung/L04_besondere_sortierverfahren/count_sorting.py new file mode 100644 index 0000000..507115d --- /dev/null +++ b/vorlesung/L04_besondere_sortierverfahren/count_sorting.py @@ -0,0 +1,60 @@ +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.memory_range import mrange +from utils.literal import Literal + + + +def count_sort(a: MemoryArray, b: MemoryArray, k: int): + c = MemoryArray(Literal(k + 1)) + for i in mrange(Literal(k + 1)): + c[i].set(Literal(0)) + + for j in mrange(a.length()): + c[a[j]].set(c[a[j]].succ()) + + for i in mrange(Literal(1), Literal(k + 1)): + c[i].set(int(c[i]) + int(c[i.pred()])) + + for j in mrange(a.length().pred(), Literal(-1), Literal(-1)): + b[c[a[j]].pred()].set(a[j]) + c[a[j]].set(c[a[j]].pred()) + + + +def analyze_complexity(sizes, presorted=False): + """ + Analysiert die Komplexität einer Sortierfunktion. + + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + if presorted: + random_array = MemoryArray.create_sorted_array(size, 0, 100) + else: + random_array = MemoryArray.create_random_array(size, 0, 100) + dest_array = MemoryArray(Literal(size)) + count_sort(random_array, dest_array, 100) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "writes"]) + + +def swap(z: MemoryArray, i: int, j: int): + tmp = z[Literal(i)].value + z[Literal(i)] = z[Literal(j)] + z[Literal(j)].set(tmp) + + +if __name__ == '__main__': + + # Test the count_sort function + a = MemoryArray([2, 5, 3, 0, 2, 3, 0, 3]) + b = MemoryArray(Literal(len(a))) + count_sort(a, b, 5) + + sizes = range(10, 101, 10) + analyze_complexity(sizes) + # analyze_complexity(sizes, True) diff --git a/vorlesung/L05_binaere_baeume/__init__.py b/vorlesung/L05_binaere_baeume/__init__.py new file mode 100644 index 0000000..2dc50f9 --- /dev/null +++ b/vorlesung/L05_binaere_baeume/__init__.py @@ -0,0 +1 @@ +from vorlesung.L05_binaere_baeume.bin_tree import BinaryTree diff --git a/vorlesung/L05_binaere_baeume/analyze_avl_tree.py b/vorlesung/L05_binaere_baeume/analyze_avl_tree.py new file mode 100644 index 0000000..96b74ca --- /dev/null +++ b/vorlesung/L05_binaere_baeume/analyze_avl_tree.py @@ -0,0 +1,26 @@ +from utils.memory_manager import MemoryManager +from utils.memory_array import MemoryArray +from utils.literal import Literal +from vorlesung.L05_binaere_baeume.avl_tree import AVLTree + +def analyze_complexity(sizes): + """ + Analysiert die Komplexität + + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + tree = AVLTree() + random_array = MemoryArray.create_random_array(size, -100, 100) + for i in range(size-1): + tree.insert(int(random_array[Literal(i)])) + MemoryManager.reset() + tree.insert(int(random_array[Literal(size-1)])) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares"]) + +if __name__ == "__main__": + sizes = range(1, 1001, 2) + analyze_complexity(sizes) \ No newline at end of file diff --git a/vorlesung/L05_binaere_baeume/analyze_binary_tree.py b/vorlesung/L05_binaere_baeume/analyze_binary_tree.py new file mode 100644 index 0000000..4e18f7d --- /dev/null +++ b/vorlesung/L05_binaere_baeume/analyze_binary_tree.py @@ -0,0 +1,26 @@ +from utils.memory_manager import MemoryManager +from utils.memory_array import MemoryArray +from utils.literal import Literal +from vorlesung.L05_binaere_baeume.bin_tree import BinaryTree + +def analyze_complexity(sizes): + """ + Analysiert die Komplexität + + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + tree = BinaryTree() + random_array = MemoryArray.create_random_array(size, -100, 100) + for i in range(size-1): + tree.insert(int(random_array[Literal(i)])) + MemoryManager.reset() + tree.insert(int(random_array[Literal(size-1)])) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares"]) + +if __name__ == "__main__": + sizes = range(1, 1001, 2) + analyze_complexity(sizes) \ No newline at end of file diff --git a/vorlesung/L05_binaere_baeume/avl_tree.py b/vorlesung/L05_binaere_baeume/avl_tree.py new file mode 100644 index 0000000..e4446d3 --- /dev/null +++ b/vorlesung/L05_binaere_baeume/avl_tree.py @@ -0,0 +1,94 @@ +from utils.memory_array import MemoryArray +from vorlesung.L05_binaere_baeume.avl_tree_node import AVLTreeNode +from vorlesung.L05_binaere_baeume.bin_tree import BinaryTree +import logging + +class AVLTree(BinaryTree): + + def __init__(self): + super().__init__() + + def new_node(self, value): + return AVLTreeNode(value) + + + def balance(self, node: AVLTreeNode): + node.update_balance() + if node.balance == -2: + if node.left.balance <= 0: + node = node.right_rotate() + else: + node = node.left_right_rotate() + elif node.balance == 2: + if node.right.balance >= 0: + node = node.left_rotate() + else: + node = node.right_left_rotate() + if node.parent: + self.balance(node.parent) + else: + self.root = node + + def insert(self, value): + insert_generator = self.insert_stepwise(value) + node, parent = None, None + while True: + try: + node, parent = next(insert_generator) + except StopIteration: + break + return node, parent + + def insert_stepwise(self, value): + node, parent = super().insert(value) + yield None, None + node.parent = parent + if parent: + self.balance(parent) + return node, parent + + + def delete(self, value): + node, parent = super().delete(value) + if node: + node.parent = parent + if parent: + self.balance(parent) + + def graph_filename(self): + return "AVLTree" + +if __name__ == "__main__": + + def print_node(node, indent=0, level=0): + print((indent * 3) * " ", node.value) + + tree = AVLTree() + #values = [5, 3, 7, 2, 4, 6, 5, 8] + values = MemoryArray.create_array_from_file("data/seq2.txt") + + for value in values: + tree.insert(value) + + + print("In-order traversal:") + tree.in_order_traversal(print_node) + print("\nLevel-order traversal:") + tree.level_order_traversal(print_node) + print("\nTree structure traversal:") + tree.tree_structure_traversal(print_node) + print("\nGraph traversal:") + tree.graph_traversal() + + tree.insert(9) + tree.graph_traversal() + + print("\nDeleting 5:") + tree.delete(5) + + print("In-order traversal after deletion:") + tree.in_order_traversal(print_node) + print("\nLevel-order traversal after deletion:") + tree.level_order_traversal(print_node) + print("\nTree structure traversal after deletion:") + tree.tree_structure_traversal(print_node) diff --git a/vorlesung/L05_binaere_baeume/avl_tree_game.py b/vorlesung/L05_binaere_baeume/avl_tree_game.py new file mode 100644 index 0000000..d726bb7 --- /dev/null +++ b/vorlesung/L05_binaere_baeume/avl_tree_game.py @@ -0,0 +1,59 @@ +import random +import pygame +from utils.game import Game +from avl_tree import AVLTree + +WHITE = (255, 255, 255) +BLUE = (0, 0, 255) +BLACK = (0, 0, 0) +WIDTH = 800 +HEIGHT = 400 +MARGIN = 20 + +class AVLTreeGame(Game): + + def __init__(self): + super().__init__("AVLTree Game", fps=10, size=(WIDTH, HEIGHT)) + random.seed() + self.z = list(range(1, 501)) + random.shuffle(self.z) + self.finished = False + self.tree = AVLTree() + self.tree.get_height = lambda node: 0 if node is None else 1 + max(self.tree.get_height(node.left), self.tree.get_height(node.right)) + self.height = self.tree.get_height(self.tree.root) + self.generator = None + + def update_game(self): + if not self.finished: + if self.generator is None: + self.generator = self.tree.insert_stepwise(self.z.pop()) + try: + next(self.generator) + except StopIteration: + self.generator = None + if self.generator is None and len(self.z) == 0: + self.finished = True + self.height = self.tree.get_height(self.tree.root) + return True + + def draw_game(self): + self.screen.fill(WHITE) + if self.height > 0: + self.draw_tree(self.tree.root, WIDTH // 2, MARGIN, WIDTH // 4 - MARGIN) + super().draw_game() + + def draw_tree(self, node, x, y, x_offset): + y_offset = (HEIGHT - (2 * MARGIN)) / self.height + if node is not None: + pygame.draw.circle(self.screen, BLUE, (x, y), 2) + if node.left is not None: + pygame.draw.line(self.screen, BLACK, (x, y), (x - x_offset, y + y_offset)) + self.draw_tree(node.left, x - x_offset, y + y_offset, x_offset // 2) + if node.right is not None: + pygame.draw.line(self.screen, BLACK, (x, y), (x + x_offset, y + y_offset)) + self.draw_tree(node.right, x + x_offset, y + y_offset, x_offset // 2) + +if __name__ == "__main__": + tree_game = AVLTreeGame() + tree_game.run() + diff --git a/vorlesung/L05_binaere_baeume/avl_tree_node.py b/vorlesung/L05_binaere_baeume/avl_tree_node.py new file mode 100644 index 0000000..ff4ccb9 --- /dev/null +++ b/vorlesung/L05_binaere_baeume/avl_tree_node.py @@ -0,0 +1,61 @@ +from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode + +class AVLTreeNode(BinaryTreeNode): + def __init__(self, value): + super().__init__(value) + self.parent = None + self.balance = 0 + + def __repr__(self): + return f"TreeNode(id={id(self)} value={self.value}, left={self.left}, right={self.right})" + + def graphviz_rep(self, row, col, dot): + dot.node(str(id(self)), label=str(self.value), pos=f"{col},{-row}!", xlabel=str(self.balance)) + + def update_balance(self): + left_height = self.left.height() if self.left else 0 + right_height = self.right.height() if self.right else 0 + self.balance = right_height - left_height + + def right_rotate(self): + new_root = self.left + new_root.parent = self.parent + self.left = new_root.right + if self.left: + self.left.parent = self + new_root.right = self + self.parent = new_root + if new_root.parent: + if new_root.parent.left is self: + new_root.parent.left = new_root + else: + new_root.parent.right = new_root + self.update_balance() + new_root.update_balance() + return new_root + + def left_rotate(self): + new_root = self.right + new_root.parent = self.parent + self.right = new_root.left + if self.right: + self.right.parent = self + new_root.left = self + self.parent = new_root + if new_root.parent: + if new_root.parent.left is self: + new_root.parent.left = new_root + else: + new_root.parent.right = new_root + self.update_balance() + new_root.update_balance() + return new_root + + def right_left_rotate(self): + self.right = self.right.right_rotate() + return self.left_rotate() + + def left_right_rotate(self): + self.left = self.left.left_rotate() + return self.right_rotate() + diff --git a/vorlesung/L05_binaere_baeume/bin_search.py b/vorlesung/L05_binaere_baeume/bin_search.py new file mode 100644 index 0000000..1bb0299 --- /dev/null +++ b/vorlesung/L05_binaere_baeume/bin_search.py @@ -0,0 +1,61 @@ +import random + +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_manager import MemoryManager +from utils.memory_range import mrange +from utils.literal import Literal + + +def binary_search(z: MemoryArray, s: MemoryCell, l: Literal = None, r: Literal = None): + """ + Perform a binary search on the sorted array z for the value x. + """ + if l is None: + l = Literal(0) + if r is None: + r = Literal(z.length().pred()) + if l > r: + return None + with MemoryCell(l) as m: + m += r + m //= Literal(2) + if s < z[m]: + return binary_search(z, s, l, m.pred()) + elif s > z[m]: + return binary_search(z, s, m.succ(), r) + else: + return m + + +def analyze_complexity(sizes): + """ + Analysiert die Komplexität + + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + random_array = MemoryArray.create_sorted_array(size) + search_value = random.randint(-100, 100) + binary_search(random_array, MemoryCell(search_value)) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "adds"]) + + + + +if __name__ == "__main__": + # Example usage + arr = MemoryArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + search_value = MemoryCell(8) + result = binary_search(arr, search_value) + if result is not None: + print(f"Value {search_value} found at index {result}.") + else: + print(f"Value {search_value} not found in the array.") + + + sizes = range(1, 1001, 2) + analyze_complexity(sizes) diff --git a/vorlesung/L05_binaere_baeume/bin_tree.py b/vorlesung/L05_binaere_baeume/bin_tree.py new file mode 100644 index 0000000..e0b83cf --- /dev/null +++ b/vorlesung/L05_binaere_baeume/bin_tree.py @@ -0,0 +1,206 @@ +from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode +from utils.project_dir import get_path +from datetime import datetime +import graphviz + + +class BinaryTree: + + def __init__(self): + self.root = None + self.size = 0 + + def new_node(self, value): + return BinaryTreeNode(value) + + def insert(self, value): + self.size += 1 + value = self.new_node(value) + if self.root is None: + self.root = value + return self.root, None + else: + current = self.root + while True: + if value < current: + if current.left: + current = current.left + else: + current.left = value + return current.left, current + elif value >= current: + if current.right: + current = current.right + else: + current.right = value + return current.right, current + else: + return None, None + + def search(self, value): + current = self.root + value = self.new_node(value) + while current: + if value < current: + current = current.left + elif value > current: + current = current.right + else: + return current + return None + + def delete(self, value): + # Der Wert wird im Baum gesucht und der erste Treffer gelöscht + # Rückgabe falls der Wert gefunden wird: + # der Knoten, der den zu löschenden Knoten ersetzt und der Elternknoten des gelöschten Knotens + parent = None + current = self.root + value = self.new_node(value) + while current: + if value < current: + parent = current + current = current.left + elif value > current: + parent = current + current = current.right + else: + # Knoten gefunden + break + else: + # Wert nicht gefunden + return None, None + return self.delete_node(current, parent) + + def delete_node(self, current, parent): + # Der übergebene Knoten wird + # Rückgabe ist ein Tupel: + # der Knoten, der den zu löschenden Knoten ersetzt und der Elternknoten des gelöschten Knotens + self.size -= 1 + # Fall 3: Es gibt zwei Kinder: wir suchen den Nachfolger + if current.left and current.right: + parent = current + successor = current.right + while successor.left: + parent = successor + successor = successor.left + # Wert des Nachfolgers wird in den Knoten geschrieben, der gelöscht werden soll + current.value = successor.value + # Ab jetzt muss successor gelöscht werden; parent ist bereits richtig gesetzt + current = successor + + # Ermitteln des einen Kindes (falls es eines gibt), sonst None + # Das eine Kind ist der Ersatz für den Knoten, der gelöscht werden soll + if current.left: + child = current.left + else: + child = current.right + + # Falls es keinen Elternknoten gibt, ist der Ersatzknoten die Wurzel + if not parent: + self.root = child + return child, None + elif parent.left is current: + parent.left = child + return child, parent + else: + parent.right = child + return child, parent + + + def in_order_traversal(self, callback): + + def in_order_traversal_recursive(callback, current): + if current is not None: + in_order_traversal_recursive(callback, current.left) + callback(current) + in_order_traversal_recursive(callback, current.right) + + in_order_traversal_recursive(callback, self.root) + + + def level_order_traversal(self, callback): + if self.root is None: + return + queue = [(self.root, 0)] + while queue: + current, level = queue.pop(0) + callback(current, level) + if current.left is not None: + queue.append((current.left, level + 1)) + if current.right is not None: + queue.append((current.right, level + 1)) + + def tree_structure_traversal(self, callback): + + def tree_structure_traversal_recursive(callback, current, level): + nonlocal line + if current: + tree_structure_traversal_recursive(callback, current.left, level + 1) + callback(current, level, line) + line += 1 + tree_structure_traversal_recursive(callback, current.right, level + 1) + + line = 0 + tree_structure_traversal_recursive(callback, self.root, 0) + + def graph_filename(self): + return "BinaryTree" + + def graph_traversal(self): + def define_node(node, level, line): + nonlocal dot + if node is not None: + node.graphviz_rep(level, line, dot) + + def graph_traversal_recursive(current): + nonlocal dot + if current is not None: + if current.left: + dot.edge(str(id(current)), str(id(current.left))) + graph_traversal_recursive(current.left) + if current.right: + dot.edge(str(id(current)), str(id(current.right))) + graph_traversal_recursive(current.right) + + dot = graphviz.Digraph( name="BinaryTree", + engine="neato", + node_attr={"shape": "circle", "fontname": "Arial"}, + format="pdf" ) + self.tree_structure_traversal(define_node) + graph_traversal_recursive(self.root) + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + filename = f"{self.graph_filename()}_{timestamp}.gv" + filename = get_path(filename) + dot.render(filename) + +if __name__ == "__main__": + tree = BinaryTree() + values = [5, 3, 7, 2, 4, 6, 5, 8] + + for value in values: + tree.insert(value) + + def print_node(node, indent=0, line=None): + print((indent * 3) * " ", node.value) + + + print("In-order traversal:") + tree.in_order_traversal(print_node) + print("\nLevel-order traversal:") + tree.level_order_traversal(print_node) + print("\nTree structure traversal:") + tree.tree_structure_traversal(print_node) + print("\nGraph traversal:") + tree.graph_traversal() + + print("\nDeleting 5:") + tree.delete(5) + + print("In-order traversal after deletion:") + tree.in_order_traversal(print_node) + print("\nLevel-order traversal after deletion:") + tree.level_order_traversal(print_node) + print("\nTree structure traversal after deletion:") + tree.tree_structure_traversal(print_node) + + diff --git a/vorlesung/L05_binaere_baeume/bin_tree_game.py b/vorlesung/L05_binaere_baeume/bin_tree_game.py new file mode 100644 index 0000000..3aef208 --- /dev/null +++ b/vorlesung/L05_binaere_baeume/bin_tree_game.py @@ -0,0 +1,54 @@ +import random +import pygame +from utils.game import Game +from bin_tree import BinaryTree + +WHITE = (255, 255, 255) +BLUE = (0, 0, 255) +BLACK = (0, 0, 0) +WIDTH = 800 +HEIGHT = 400 +MARGIN = 20 + +class BinTreeGame(Game): + + def __init__(self): + super().__init__("BinTree Game", fps=10, size=(WIDTH, HEIGHT)) + random.seed() + self.z = list(range(1, 101)) + random.shuffle(self.z) + self.finished = False + self.tree = BinaryTree() + self.tree.get_height = lambda node: 0 if node is None else 1 + max(self.tree.get_height(node.left), self.tree.get_height(node.right)) + self.height = self.tree.get_height(self.tree.root) + + def update_game(self): + if not self.finished: + i = self.z.pop() + self.tree.insert(i) + self.height = self.tree.get_height(self.tree.root) + if len(self.z) == 0: + self.finished = True + return True + + def draw_game(self): + self.screen.fill(WHITE) + if self.height > 0: + self.draw_tree(self.tree.root, WIDTH // 2, MARGIN, WIDTH // 4 - MARGIN) + super().draw_game() + + def draw_tree(self, node, x, y, x_offset): + y_offset = (HEIGHT - (2 * MARGIN)) / self.height + if node is not None: + pygame.draw.circle(self.screen, BLUE, (x, y), 2) + if node.left is not None: + pygame.draw.line(self.screen, BLACK, (x, y), (x - x_offset, y + y_offset)) + self.draw_tree(node.left, x - x_offset, y + y_offset, x_offset // 2) + if node.right is not None: + pygame.draw.line(self.screen, BLACK, (x, y), (x + x_offset, y + y_offset)) + self.draw_tree(node.right, x + x_offset, y + y_offset, x_offset // 2) + +if __name__ == "__main__": + tree_game = BinTreeGame() + tree_game.run() + diff --git a/vorlesung/L05_binaere_baeume/bin_tree_node.py b/vorlesung/L05_binaere_baeume/bin_tree_node.py new file mode 100644 index 0000000..d46dcff --- /dev/null +++ b/vorlesung/L05_binaere_baeume/bin_tree_node.py @@ -0,0 +1,22 @@ +from utils.memory_cell import MemoryCell + +class BinaryTreeNode(MemoryCell): + + def __init__(self, value): + super().__init__(value) + self.left = None + self.right = None + + def height(self): + left_height = self.left.height() if self.left else 0 + right_height = self.right.height() if self.right else 0 + return 1 + max(left_height, right_height) + + def __repr__(self): + return f"TreeNode(value={self.value}, left={self.left}, right={self.right})" + + def __str__(self): + return str(self.value) + + def graphviz_rep(self, row, col, dot): + dot.node(str(id(self)), label=str(self.value), pos=f"{col},{-row}!") \ No newline at end of file diff --git a/vorlesung/L06_b_baeume/analyze_b_tree.py b/vorlesung/L06_b_baeume/analyze_b_tree.py new file mode 100644 index 0000000..e142ee8 --- /dev/null +++ b/vorlesung/L06_b_baeume/analyze_b_tree.py @@ -0,0 +1,58 @@ +from utils.memory_manager import MemoryManager +from utils.memory_array import MemoryArray +from utils.literal import Literal +from b_tree import BTree +from b_tree_node import BTreeNode + +class MemoryManagerBTree(MemoryManager): + """ + Diese Klasse erweitert den MemoryManager, um spezifische Statistiken für B-Bäume zu speichern. + """ + + @staticmethod + def count_loads(): + return sum([cell.loaded_count for cell in MemoryManager().cells if isinstance(cell, BTreeNode)]) + + @staticmethod + def count_saves(): + return sum([cell.saved_count for cell in MemoryManager().cells if isinstance(cell, BTreeNode)]) + + @staticmethod + def save_stats(count): + data = { "cells": MemoryManager.count_cells(), + "reads": MemoryManager.count_reads(), + "writes": MemoryManager.count_writes(), + "compares": MemoryManager.count_compares(), + "adds": MemoryManager.count_adds(), + "subs": MemoryManager.count_subs(), + "muls": MemoryManager.count_muls(), + "divs": MemoryManager.count_divs(), + "bitops": MemoryManager.count_bitops(), + "loads": MemoryManagerBTree.count_loads(), + "saves": MemoryManagerBTree.count_saves() } + MemoryManager.stats[count] = data + + + + +def analyze_complexity(sizes): + """ + Analysiert die Komplexität + + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + tree = BTree(5) + random_array = MemoryArray.create_random_array(size, -100, 100) + for i in range(size-1): + tree.insert(int(random_array[Literal(i)])) + MemoryManager.reset() + tree.insert(int(random_array[Literal(size-1)])) + MemoryManagerBTree.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares", "loads", "saves"]) + +if __name__ == "__main__": + sizes = range(1, 1001, 2) + analyze_complexity(sizes) \ No newline at end of file diff --git a/vorlesung/L06_b_baeume/b_tree.py b/vorlesung/L06_b_baeume/b_tree.py new file mode 100644 index 0000000..7729930 --- /dev/null +++ b/vorlesung/L06_b_baeume/b_tree.py @@ -0,0 +1,120 @@ +from utils.literal import Literal +from utils.memory_cell import MemoryCell +from utils.memory_array import MemoryArray +from b_tree_node import BTreeNode + +class BTree: + def __init__(self, m: int): + self.m = m + self.root = BTreeNode(m) + + def search(self, value, start: BTreeNode = None) -> BTreeNode | None: + if not start: + start = self.root + start.load() + i = 0 + if not isinstance(value, MemoryCell): + value = MemoryCell(value) + while i < start.n and value > start.value[Literal(i)]: + i += 1 + if i < start.n and value == start.value[Literal(i)]: + return start + if start.leaf: + return None + return self.search(value, start.children[i]) + + def split_child(self, parent: BTreeNode, i: int): + child = parent.children[i] + child.load() + h = BTreeNode(self.m) + h.leaf = child.leaf + h.n = self.m - 1 + for j in range(self.m - 1): + h.value[Literal(j)] = child.value[Literal(j + self.m)] + if not h.leaf: + for j in range(self.m): + h.children[j] = child.children[j + self.m] + for j in range(self.m, child.n + 1): + child.children[j] = None + child.n = self.m - 1 + child.save() + h.save() + for j in range(parent.n, i, -1): + parent.children[j + 1] = parent.children[j] + parent.value[Literal(j)] = parent.value[Literal(j - 1)] + parent.children[i + 1] = h + parent.value[Literal(i)] = child.value[Literal(self.m - 1)] + parent.n += 1 + parent.save() + + def insert(self, value): + if not isinstance(value, MemoryCell): + value = MemoryCell(value) + r = self.root + if r.n == 2 * self.m - 1: + h = BTreeNode(self.m) + self.root = h + h.leaf = False + h.n = 0 + h.children[0] = r + self.split_child(h, 0) + self.insert_in_node(h, value) + else: + self.insert_in_node(r, value) + + def insert_in_node(self, start: BTreeNode, value): + start.load() + i = start.n + if start.leaf: + while i >= 1 and value < start.value[Literal(i-1)]: + start.value[Literal(i)] = start.value[Literal(i-1)] + i -= 1 + start.value[Literal(i)].set(value) + start.n += 1 + start.save() + else: + j = 0 + while j < start.n and value > start.value[Literal(j)]: + j += 1 + if start.children[j].n == 2 * self.m - 1: + self.split_child(start, j) + if value > start.value[Literal(j)]: + j += 1 + self.insert_in_node(start.children[j], value) + + def traversal(self, callback): + def traversal_recursive(node, callback): + i = 0 + while i < node.n: + if not node.leaf: + traversal_recursive(node.children[i], callback) + callback(node.value[Literal(i)]) + i += 1 + if not node.leaf: + traversal_recursive(node.children[i], callback) + + traversal_recursive(self.root, callback) + + def walk(self): + def print_key(key): + print(key, end=" ") + + self.traversal(print_key) + + def height(self, start: BTreeNode = None): + if not start: + start = self.root + if start.leaf: + return 0 + return 1 + self.height(start.children[0]) + + +if __name__ == "__main__": + a = MemoryArray.create_array_from_file("data/seq3.txt") + tree = BTree(3) + for cell in a: + tree.insert(cell) + print(f"Height: {tree.height()}") + tree.walk() + s = tree.search(0) + print(f"\nKnoten mit 0: {str(s)}") diff --git a/vorlesung/L06_b_baeume/b_tree_node.py b/vorlesung/L06_b_baeume/b_tree_node.py new file mode 100644 index 0000000..20b8bb5 --- /dev/null +++ b/vorlesung/L06_b_baeume/b_tree_node.py @@ -0,0 +1,29 @@ +from utils.literal import Literal +from utils.memory_cell import MemoryCell +from utils.memory_array import MemoryArray + +class BTreeNode(MemoryCell): + + def __init__(self, m: int): + super().__init__() + self.m = m + self.n = 0 + self.leaf = True + self.value = MemoryArray(Literal(2 * m - 1)) + self.children = [None] * (2 * m) + self.loaded_count = 0 + self.saved_count = 0 + + def reset_counters(self): + super().reset_counters() + self.loaded_count = 0 + self.saved_count = 0 + + def load(self): + self.loaded_count += 1 + + def save(self): + self.saved_count += 1 + + def __str__(self): + return "(" + " ".join([str(self.value[Literal(i)]) for i in range(self.n)]) + ")" \ No newline at end of file diff --git a/vorlesung/L07_hashtable/__init__.py b/vorlesung/L07_hashtable/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vorlesung/L07_hashtable/analyze_hashtable.py b/vorlesung/L07_hashtable/analyze_hashtable.py new file mode 100644 index 0000000..441d1bb --- /dev/null +++ b/vorlesung/L07_hashtable/analyze_hashtable.py @@ -0,0 +1,60 @@ +import math +import random +from utils.literal import Literal +from utils.memory_cell import MemoryCell +from utils.memory_array import MemoryArray +from utils.memory_manager import MemoryManager +from vorlesung.L07_hashtable.hashtable import HashTableOpenAddressing + +#Goldener Schnitt +a = Literal((math.sqrt(5) - 1) / 2) + +# Hashfunktion nach multiplikativer Methode +def h(x: MemoryCell, m: Literal) -> Literal: + with MemoryCell(int(x * a)) as integer_part, MemoryCell(x * a) as full_product: + with MemoryCell(full_product - integer_part) as fractional_part: + return Literal(abs(int(fractional_part * m))) + +# Quadratische Sondierung +def f(x: MemoryCell, i: Literal, m: Literal) -> Literal: + c1 = 1 + c2 = 5 + with MemoryCell(h(x, m)) as initial_hash, MemoryCell(c2 * int(i) * int(i)) as quadratic_offset: + with MemoryCell(initial_hash + quadratic_offset) as probe_position: + probe_position += Literal(c1 * int(i)) # Linear component + return probe_position % m + +# Symmetrische quadratische Sondierung +def fs(x: MemoryCell, i: Literal, m: Literal) -> Literal: + with MemoryCell(h(x, m)) as base_hash, MemoryCell(int(i) * int(i)) as square: + if int(i) % 2 == 0: # gerades i: Vorwärtssondierung + with MemoryCell(base_hash + square) as position: + return position % m + else: # ungerades i: Rückwärtssondierung + with MemoryCell(base_hash - square) as position: + return position % m + + +def analyze_complexity(sizes): + """ + Analysiert die Komplexität + + :param sizes: Eine Liste von Eingabegrößen für die Analyse. + """ + for size in sizes: + MemoryManager.purge() # Speicher zurücksetzen + ht = HashTableOpenAddressing(size, f) + random_array = MemoryArray.create_random_array(size, -100, 100) + for cell in random_array: + ht.insert(cell) + MemoryManager.reset() + cell = random.choice(random_array.cells) + ht.search(cell) + MemoryManager.save_stats(size) + + MemoryManager.plot_stats(["cells", "compares"]) + + +if __name__ == "__main__": + sizes = range(1, 1001, 10) + analyze_complexity(sizes) diff --git a/vorlesung/L07_hashtable/hashtable.py b/vorlesung/L07_hashtable/hashtable.py new file mode 100644 index 0000000..d2b7abd --- /dev/null +++ b/vorlesung/L07_hashtable/hashtable.py @@ -0,0 +1,76 @@ +from collections.abc import Callable +from utils.literal import Literal +from utils.memory_array import MemoryArray +from utils.memory_cell import MemoryCell +from utils.memory_range import mrange + + +UNUSED_MARK = "UNUSED" +DELETED_MARK = "DELETED" + +class HashTableOpenAddressing: + def __init__(self, m: Literal, f: Callable[[MemoryCell, Literal, Literal], Literal]): + if not isinstance(m, Literal): + m = Literal(m) + self.m = m + self.f = f + self.table = MemoryArray(m) + for i in mrange(m): + self.table[i].value = UNUSED_MARK + + def insert(self, x: MemoryCell): + with MemoryCell(0) as i: + while i < self.m: + j = self.f(x, i, self.m) + if self.is_free(j): + self.table[j].set(x) + return True + i.set(i.succ()) + return False + + def search(self, x: MemoryCell): + with MemoryCell(0) as i: + while i < self.m: + j = self.f(x, i, self.m) + if self.is_unused(j): + return False + if self.table[j] == x: + return True + i.set(i.succ()) + return False + + def delete(self, x: MemoryCell): + with MemoryCell(0) as i: + while i < self.m: + j = self.f(x, i, self.m) + if self.is_unused(j): + return False + if self.table[j] == x: + self.table[j].value = DELETED_MARK + return True + i.set(i.succ()) + return False + + def __str__(self): + return str(self.table) + + def alpha(self): + with MemoryCell(0) as i: + used = 0 + while i < self.m: + used += 0 if self.is_free(i) else 1 + i.set(i.succ()) + return used / int(self.m) + + def is_unused(self, i: Literal): + if self.table[i].value == UNUSED_MARK: + return True + return False + + def is_deleted(self, i: Literal): + if self.table[i].value == DELETED_MARK: + return True + return False + + def is_free(self, i: Literal): + return self.is_unused(i) or self.is_deleted(i) diff --git a/vorlesung/L08_graphen/__init__.py b/vorlesung/L08_graphen/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vorlesung/L08_graphen/aoc2212.py b/vorlesung/L08_graphen/aoc2212.py new file mode 100644 index 0000000..0c1147b --- /dev/null +++ b/vorlesung/L08_graphen/aoc2212.py @@ -0,0 +1,45 @@ +from vorlesung.L08_graphen.graph import Graph, AdjacencyMatrixGraph +from utils.project_dir import get_path + +graph = AdjacencyMatrixGraph() +start = "" +end = "" + +def read_file(filename: str = "data/aoc2212.txt"): + """Read a file and return the content as a string.""" + + def adjust_char(char): + """Adjust character for comparison.""" + if char == 'S': + return 'a' + elif char == 'E': + return 'z' + return char + + global start, end + with open(get_path(filename), "r") as file: + quest = file.read().strip().splitlines() + for row, line in enumerate(quest): + for col, char in enumerate(line): + label = f"{row},{col}" + graph.insert_vertex(label) + if char == "S": + start = label + if char == "E": + end = label + for row, line in enumerate(quest): + for col, char in enumerate(line): + for neighbor in [(row - 1, col), (row, col - 1), (row + 1, col), (row, col + 1)]: + if 0 <= neighbor[0] < len(quest) and 0 <= neighbor[1] < len(line): + if ord(adjust_char(quest[neighbor[0]][neighbor[1]])) <= ord(adjust_char(char)) + 1: + label1 = f"{row},{col}" + label2 = f"{neighbor[0]},{neighbor[1]}" + graph.connect(label1, label2) + + +# Lösung des Adventskalenders 2022, Tag 12 +read_file("data/aoc2212test.txt") +graph.graph() +distance_map, predecessor_map = graph.bfs(start) +print(distance_map[graph.get_vertex(end)]) +print(graph.path(end, predecessor_map)) \ No newline at end of file diff --git a/vorlesung/L08_graphen/graph.py b/vorlesung/L08_graphen/graph.py new file mode 100644 index 0000000..327cd8a --- /dev/null +++ b/vorlesung/L08_graphen/graph.py @@ -0,0 +1,366 @@ +from collections import deque +from typing import List +from enum import Enum +import graphviz +import math +import heapq +from datetime import datetime +from utils.project_dir import get_path +from utils.priority_queue import PriorityQueue +from vorlesung.L09_mst.disjoint import DisjointValue + + +class NodeColor(Enum): + """Enumeration for node colors in a graph traversal.""" + WHITE = 1 # WHITE: not visited + GRAY = 2 # GRAY: visited but not all neighbors visited + BLACK = 3 # BLACK: visited and all neighbors visited + + +class Vertex: + """A vertex in a graph.""" + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + + def __repr__(self): + return f"Vertex({self.value})" + + + +class Graph: + """A graph.""" + def insert_vertex(self, name: str): + raise NotImplementedError("Please implement this method in subclass") + + def connect(self, name1: str, name2: str, weight: float = 1): + raise NotImplementedError("Please implement this method in subclass") + + def all_vertices(self) -> List[Vertex]: + raise NotImplementedError("Please implement this method in subclass") + + def get_vertex(self, name: str) -> Vertex: + raise NotImplementedError("Please implement this method in subclass") + + def get_adjacent_vertices(self, name: str) -> List[Vertex]: + raise NotImplementedError("Please implement this method in subclass") + + def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]: + raise NotImplementedError("Please implement this method in subclass") + + def all_edges(self) -> List[tuple[str, str, float]]: + raise NotImplementedError("Please implement this method in subclass") + + def bfs(self, start_name: str): + """ + Perform a breadth-first search starting at the given vertex. + :param start_name: the name of the vertex to start at + :return: a tuple of two dictionaries, the first mapping vertices to distances from the start vertex, + the second mapping vertices to their predecessors in the traversal tree + """ + + color_map = {} # maps vertices to their color + distance_map = {} # maps vertices to their distance from the start vertex + predecessor_map = {} # maps vertices to their predecessor in the traversal tree + + # Initialize the maps + for vertex in self.all_vertices(): + color_map[vertex] = NodeColor.WHITE + distance_map[vertex] = None + predecessor_map[vertex] = None + + # Start at the given vertex + start_node = self.get_vertex(start_name) + color_map[start_node] = NodeColor.GRAY + distance_map[start_node] = 0 + + # Initialize the queue with the start vertex + queue = deque() + queue.append(start_node) + + # Process the queue + while len(queue) > 0: + vertex = queue.popleft() + for dest in self.get_adjacent_vertices(vertex.value): + if color_map[dest] == NodeColor.WHITE: + color_map[dest] = NodeColor.GRAY + distance_map[dest] = distance_map[vertex] + 1 + predecessor_map[dest] = vertex + queue.append(dest) + color_map[vertex] = NodeColor.BLACK + + # Return the distance and predecessor maps + return distance_map, predecessor_map + + def dfs(self): + """ + Perform a depth-first search starting at the first vertex. + :return: a tuple of two dictionaries, the first mapping vertices to distances from the start vertex, + the second mapping vertices to their predecessors in the traversal tree + """ + color_map : dict[Vertex, NodeColor]= {} + enter_map : dict[Vertex, int] = {} + leave_map : dict[Vertex, int] = {} + predecessor_map : dict[Vertex, Vertex | None] = {} + white_vertices = set(self.all_vertices()) + time_counter = 0 + + def dfs_visit(vertex): + nonlocal time_counter + color_map[vertex] = NodeColor.GRAY + white_vertices.remove(vertex) + time_counter += 1 + enter_map[vertex] = time_counter + for dest in self.get_adjacent_vertices(vertex.value): + if color_map[dest] == NodeColor.WHITE: + predecessor_map[dest] = vertex + dfs_visit(dest) + color_map[vertex] = NodeColor.BLACK + time_counter += 1 + leave_map[vertex] = time_counter + + # Initialize the maps + for vertex in self.all_vertices(): + color_map[vertex] = NodeColor.WHITE + predecessor_map[vertex] = None + + while white_vertices: + v = white_vertices.pop() + dfs_visit(v) + + return enter_map, leave_map, predecessor_map + + + def path(self, destination, map): + """ + Compute the path from the start vertex to the given destination vertex. + The map parameter is the predecessor map + """ + path = [] + destination_node = self.get_vertex(destination) + while destination_node is not None: + path.insert(0, destination_node.value) + destination_node = map[destination_node] + return path + + def graph(self, filename: str = "Graph"): + dot = graphviz.Digraph( name=filename, + node_attr={"fontname": "Arial"}, + format="pdf" ) + for vertex in self.all_vertices(): + dot.node(str(id(vertex)), label=str(vertex.value)) + for edge in self.all_edges(): + dot.edge(str(id(self.get_vertex(edge[0]))), str(id(self.get_vertex(edge[1]))), label=str(edge[2])) + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + filename = f"{filename}_{timestamp}.gv" + filename = get_path(filename) + dot.render(filename) + + def dijkstra(self, start_name: str) -> tuple[dict[Vertex, float], dict[Vertex, Vertex | None]]: + """ + Führt den Dijkstra-Algorithmus für kürzeste Pfade durch, implementiert mit Knotenfarben. + + Args: + start_name: Name des Startknotens + + Returns: + Ein Tupel aus zwei Dictionaries: + - distance_map: Abbildung von Knoten auf ihre kürzeste Distanz vom Startknoten + - predecessor_map: Abbildung von Knoten auf ihre Vorgänger im kürzesten Pfad + """ + + def relax(vertex, dest, weight): + """ + Entspannt die Kante zwischen vertex und dest. + Aktualisiert die Distanz und den Vorgänger, wenn ein kürzerer Pfad gefunden wird. + """ + if distance_map[vertex] + weight < distance_map[dest]: + distance_map[dest] = distance_map[vertex] + weight + predecessor_map[dest] = vertex + queue.add_or_update(dest, distance_map[dest]) + + # Initialisierung der Maps + distance_map = {} # Speichert kürzeste Distanzen + predecessor_map = {} # Speichert Vorgänger + + # Initialisiere alle Knoten + queue = PriorityQueue() + for vertex in self.all_vertices(): + distance_map[vertex] = float('inf') # Initiale Distanz unendlich + predecessor_map[vertex] = None # Initialer Vorgänger None + queue.add_or_update(vertex, distance_map[vertex]) # Füge Knoten zur Prioritätswarteschlange hinzu + + + + # Setze Startknoten + start_node = self.get_vertex(start_name) + distance_map[start_node] = 0 + queue.add_or_update(start_node, distance_map[start_node]) + + while True: + entry = queue.pop() + if entry is None: + break + vertex = entry[0] + for dest, weight in self.get_adjacent_vertices_with_weight(vertex.value): + relax(vertex, dest, weight) + return distance_map, predecessor_map + + def mst_prim(self, start_name: str = None): + """ Compute the minimum spanning tree of the graph using Prim's algorithm. """ + + distance_map = {} # maps vertices to their current distance from the spanning tree + parent_map = {} # maps vertices to their predecessor in the spanning tree + + Vertex.__lt__ = lambda self, other: distance_map[self] < distance_map[other] + + queue = [] + + if start_name is None: + start_name = self.all_vertices()[0].value + + # Initialize the maps + for vertex in self.all_vertices(): + distance_map[vertex] = 0 if vertex.value == start_name else math.inf + parent_map[vertex] = None + queue.append(vertex) + + heapq.heapify(queue) # Convert the list into a heap + + # Process the queue + cost = 0 # The cost of the minimum spanning tree + while len(queue) > 0: + vertex = heapq.heappop(queue) + cost += distance_map[vertex] # Add the cost of the edge to the minimum spanning tree + for (dest, w) in self.get_adjacent_vertices_with_weight(vertex.value): + if dest in queue and distance_map[dest] > w: + # Update the distance and parent maps + queue.remove(dest) + distance_map[dest] = w + parent_map[dest] = vertex + queue.append(dest) # Add the vertex back to the queue + heapq.heapify(queue) # Re-heapify the queue + + # Return the distance and predecessor maps + return parent_map, cost + + def mst_kruskal(self, start_name: str = None): + """ Compute the minimum spanning tree of the graph using Kruskal's algorithm. """ + + cost = 0 + result = [] + edges = self.all_edges() + + # Create a disjoint set for each vertex + vertex_map = {v.value: DisjointValue(v) for v in self.all_vertices()} + + # Sort the edges by weight + edges.sort(key=lambda edge: edge[2]) + + # Process the edges + for edge in edges: + start_name, end_name, weight = edge + # Check if the edge creates a cycle + if not vertex_map[start_name].same_set(vertex_map[end_name]): + result.append(edge) + vertex_map[start_name].union(vertex_map[end_name]) + cost += weight + + return result, cost + + +class AdjacencyListGraph(Graph): + """A graph implemented as an adjacency list.""" + def __init__(self): + self.adjacency_map = {} # maps vertex names to lists of adjacent vertices + self.vertex_map = {} # maps vertex names to vertices + + def insert_vertex(self, name: str): + if name not in self.vertex_map: + self.vertex_map[name] = Vertex(name) + if name not in self.adjacency_map: + self.adjacency_map[name] = [] + + def connect(self, name1: str, name2: str, weight: float = 1): + adjacency_list = self.adjacency_map[name1] + dest = self.vertex_map[name2] + adjacency_list.append((dest, weight)) + + def all_vertices(self) -> List[Vertex]: + return list(self.vertex_map.values()) + + def get_vertex(self, name: str) -> Vertex: + return self.vertex_map[name] + + def get_adjacent_vertices(self, name: str) -> List[Vertex]: + return list(map(lambda x: x[0], self.adjacency_map[name])) + + def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]: + return self.adjacency_map[name] + + def all_edges(self) -> List[tuple[str, str, float]]: + result = [] + for name in self.adjacency_map: + for (dest, weight) in self.adjacency_map[name]: + result.append((name, dest.value, weight)) + return result + + +class AdjacencyMatrixGraph(Graph): + """A graph implemented as an adjacency matrix.""" + def __init__(self): + self.index_map = {} # maps vertex names to indices + self.vertex_list = [] # list of vertices + self.adjacency_matrix = [] # adjacency matrix + + def insert_vertex(self, name: str): + if name not in self.index_map: + self.index_map[name] = len(self.vertex_list) + self.vertex_list.append(Vertex(name)) + for row in self.adjacency_matrix: # add a new column to each row + row.append(None) + self.adjacency_matrix.append([None] * len(self.vertex_list)) # add a new row + + def connect(self, name1: str, name2: str, weight: float = 1): + index1 = self.index_map[name1] + index2 = self.index_map[name2] + self.adjacency_matrix[index1][index2] = weight + + + def all_vertices(self) -> List[Vertex]: + return self.vertex_list + + def get_vertex(self, name: str) -> Vertex: + index = self.index_map[name] + return self.vertex_list[index] + + def get_adjacent_vertices(self, name: str) -> List[Vertex]: + index = self.index_map[name] + result = [] + for i in range(len(self.vertex_list)): + if self.adjacency_matrix[index][i] is not None: + name = self.vertex_list[i].value + result.append(self.get_vertex(name)) + return result + + def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]: + index = self.index_map[name] + result = [] + for i in range(len(self.vertex_list)): + if self.adjacency_matrix[index][i] is not None: + name = self.vertex_list[i].value + result.append((self.get_vertex(name), self.adjacency_matrix[index][i])) + return result + + def all_edges(self) -> List[tuple[str, str, float]]: + result = [] + for i in range(len(self.vertex_list)): + for j in range(len(self.vertex_list)): + if self.adjacency_matrix[i][j] is not None: + result.append((self.vertex_list[i].value, self.vertex_list[j].value, self.adjacency_matrix[i][j])) + return result + + + diff --git a/vorlesung/L09_mst/__init__.py b/vorlesung/L09_mst/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vorlesung/L09_mst/disjoint.py b/vorlesung/L09_mst/disjoint.py new file mode 100644 index 0000000..293262e --- /dev/null +++ b/vorlesung/L09_mst/disjoint.py @@ -0,0 +1,18 @@ + + +class DisjointValue(): + + def __init__(self, value): + self.value = value + self.parent = None + + def canonical(self): + if self.parent: + return self.parent.canonical() + return self + + def same_set(self, other): + return self.canonical() == other.canonical() + + def union(self, other): + self.canonical().parent = other.canonical() diff --git a/vorlesung/__init__.py b/vorlesung/__init__.py new file mode 100644 index 0000000..e69de29