From af904867dafefb1a18cd3bda5df345a06d2680bf Mon Sep 17 00:00:00 2001 From: Filip Gralinski Date: Fri, 11 Jan 2019 20:11:02 +0100 Subject: [PATCH] new tasks --- automata/Task201Test.py | 47 +++++++++++ automata/Task202Test.py | 49 ++++++++++++ automata/Task203Test.py | 51 ++++++++++++ automata/Task204Test.py | 52 ++++++++++++ automata/Task205Test.py | 40 ++++++++++ automata/Task206Test.py | 38 +++++++++ automata/Task207Test.py | 47 +++++++++++ automata/Task208Test.py | 49 ++++++++++++ automata/Task209Test.py | 40 ++++++++++ automata/Task210Test.py | 45 +++++++++++ automata/Task211Test.py | 41 ++++++++++ automata/Task212Test.py | 41 ++++++++++ automata/Task213Test.py | 40 ++++++++++ automata/Task214Test.py | 44 ++++++++++ automata/Task215Test.py | 48 +++++++++++ automata/Task216Test.py | 40 ++++++++++ automata/Task217Test.py | 40 ++++++++++ automata/Task218Test.py | 42 ++++++++++ automata/Task219Test.py | 45 +++++++++++ automata/deterministic_automaton.py | 119 ++++++++++++++++++++++++++++ 20 files changed, 958 insertions(+) create mode 100755 automata/Task201Test.py create mode 100755 automata/Task202Test.py create mode 100755 automata/Task203Test.py create mode 100755 automata/Task204Test.py create mode 100755 automata/Task205Test.py create mode 100755 automata/Task206Test.py create mode 100755 automata/Task207Test.py create mode 100755 automata/Task208Test.py create mode 100755 automata/Task209Test.py create mode 100755 automata/Task210Test.py create mode 100755 automata/Task211Test.py create mode 100755 automata/Task212Test.py create mode 100755 automata/Task213Test.py create mode 100755 automata/Task214Test.py create mode 100755 automata/Task215Test.py create mode 100755 automata/Task216Test.py create mode 100755 automata/Task217Test.py create mode 100755 automata/Task218Test.py create mode 100755 automata/Task219Test.py create mode 100644 automata/deterministic_automaton.py diff --git a/automata/Task201Test.py b/automata/Task201Test.py new file mode 100755 index 0000000..7f23953 --- /dev/null +++ b/automata/Task201Test.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 201 + +Napisz funkcję `is_initial_state_a_final_one(automaton)`, która +sprawdza, czy stan początkowy automatu jest równocześnie +stanem końcowym. Należy używać metod klasy (nie odwoływać +się bezpośrednio do pól!). + +NAME: is_initial_state_a_final_one +PARAMS: automaton +RETURN: bool +POINTS: 2 +""" + +import unittest +from Task201 import is_initial_state_a_final_one +from deterministic_automaton import DeterministicAutomaton + +class Task201Test(unittest.TestCase): + """Testy do zadania 201""" + + def test_simple(self): + """Prosty test.""" + + automaton = DeterministicAutomaton() + + state_a = automaton.add_state() + state_b = automaton.add_state() + + automaton.mark_as_initial(state_b) + + self.assertFalse(is_initial_state_a_final_one(automaton)) + + automaton.mark_as_final(state_a) + + self.assertFalse(is_initial_state_a_final_one(automaton)) + + automaton.mark_as_final(state_b) + + self.assertTrue(is_initial_state_a_final_one(automaton)) + + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task202Test.py b/automata/Task202Test.py new file mode 100755 index 0000000..b83dad8 --- /dev/null +++ b/automata/Task202Test.py @@ -0,0 +1,49 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 202 + +Napisz funkcję `get_number_of_final_states(automaton)`, która oblicza +liczbę stanów końcowych automatu. Należy używać metod klasy (nie +odwoływać się bezpośrednio do pól!). + + +NAME: get_number_of_final_states +PARAMS: automaton +RETURN: int +POINTS: 2 +""" + +import unittest +from Task202 import get_number_of_final_states +from deterministic_automaton import DeterministicAutomaton + +class Task202Test(unittest.TestCase): + """Testy do zadania 202""" + + def test_simple(self): + """Prosty test.""" + + automaton = DeterministicAutomaton() + + state_a = automaton.add_state() + state_b = automaton.add_state() + state_c = automaton.add_state() + + automaton.mark_as_initial(state_b) + + self.assertEqual(get_number_of_final_states(automaton), 0) + + automaton.mark_as_final(state_a) + + self.assertEqual(get_number_of_final_states(automaton), 1) + + automaton.mark_as_final(state_c) + automaton.mark_as_final(state_b) + + self.assertEqual(get_number_of_final_states(automaton), 3) + + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task203Test.py b/automata/Task203Test.py new file mode 100755 index 0000000..2ade7ce --- /dev/null +++ b/automata/Task203Test.py @@ -0,0 +1,51 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 203 + +Napisz funkcję `get_number_of_transitions(automaton, symbol)`, która +oblicza liczbę przejść automatu etykietowanych zadanym symbolem. +Należy używać metod klasy (nie odwoływać się bezpośrednio do pól!). + + +NAME: get_number_of_transitions +PARAMS: automaton, char +RETURN: int +POINTS: 3 +""" + +import unittest +from Task203 import get_number_of_transitions +from deterministic_automaton import DeterministicAutomaton + +class Task203Test(unittest.TestCase): + """Testy do zadania 203""" + + def test_simple(self): + """Prosty test.""" + + automaton = DeterministicAutomaton() + + state_a = automaton.add_state() + state_b = automaton.add_state() + state_c = automaton.add_state() + + automaton.mark_as_initial(state_b) + automaton.mark_as_final(state_a) + + self.assertEqual(get_number_of_transitions(automaton, 'b'), 0) + + automaton.add_transition(state_b, 'a', state_a) + + self.assertEqual(get_number_of_transitions(automaton, 'a'), 1) + self.assertEqual(get_number_of_transitions(automaton, 'b'), 0) + + automaton.add_transition(state_b, 'b', state_a) + automaton.add_transition(state_a, 'b', state_b) + automaton.add_transition(state_c, 'b', state_a) + + self.assertEqual(get_number_of_transitions(automaton, 'b'), 3) + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task204Test.py b/automata/Task204Test.py new file mode 100755 index 0000000..905abc8 --- /dev/null +++ b/automata/Task204Test.py @@ -0,0 +1,52 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 204 + +Napisz funkcję `get_number_of_loops(automaton, symbol)`, która +oblicza liczbę pętli (tj. przejść od stanu z powrotem do danego +stanu) w zadanym automacie etykietowanych zadanym symbolem. + +NAME: get_number_of_loops +PARAMS: automaton, char +RETURN: int +POINTS: 2 +""" + +import unittest +from Task204 import get_number_of_loops +from deterministic_automaton import DeterministicAutomaton + +class Task204Test(unittest.TestCase): + """Testy do zadania 204""" + + def test_simple(self): + """Prosty test.""" + + automaton = DeterministicAutomaton() + + state_a = automaton.add_state() + state_b = automaton.add_state() + state_c = automaton.add_state() + + automaton.mark_as_initial(state_b) + automaton.mark_as_final(state_a) + + self.assertEqual(get_number_of_loops(automaton, 'b'), 0) + + automaton.add_transition(state_b, 'a', state_a) + + self.assertEqual(get_number_of_loops(automaton, 'a'), 0) + self.assertEqual(get_number_of_loops(automaton, 'b'), 0) + + automaton.add_transition(state_b, 'b', state_b) + automaton.add_transition(state_c, 'b', state_c) + automaton.add_transition(state_a, 'a', state_a) + automaton.add_transition(state_a, 'b', state_b) + + self.assertEqual(get_number_of_loops(automaton, 'a'), 1) + self.assertEqual(get_number_of_loops(automaton, 'b'), 2) + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task205Test.py b/automata/Task205Test.py new file mode 100755 index 0000000..a5083d7 --- /dev/null +++ b/automata/Task205Test.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 205 + +Napisz funkcję `haha_automaton()`, która +tworzy i zwraca automat, który akceptuje śmiechy +tj. napisy typu "hahaha!!!", gdzie ha powtarza +się przynajmniej dwa razy, wykrzyknik występuje dowolną liczbę +razy (przynajmniej raz). + +NAME: haha_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task205 import haha_automaton + +class Task205Test(unittest.TestCase): + """Testy do zadania 205""" + + def test_simple(self): + """Prosty test.""" + + automaton = haha_automaton() + + self.assertTrue(automaton.accepts("hahaha!!!!!!!!!")) + self.assertTrue(automaton.accepts("haha!")) + self.assertTrue(automaton.accepts("hahahaha!!")) + self.assertFalse(automaton.accepts("ha!!!!!")) + self.assertFalse(automaton.accepts("hahaha")) + self.assertFalse(automaton.accepts("hahoha")) + self.assertFalse(automaton.accepts("!!haha")) + + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task206Test.py b/automata/Task206Test.py new file mode 100755 index 0000000..3a2f3fa --- /dev/null +++ b/automata/Task206Test.py @@ -0,0 +1,38 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 206 + +Napisz funkcję `big_no_automaton()`, która tworzy i zwraca automat, +który akceptuje "Big NO!" tj. napisy typu "NOO...OO!", gdzie "O" +powtarza się przynajmniej 5 razy (zob. +http://tvtropes.org/pmwiki/pmwiki.php/Main/BigNo). + +NAME: big_no_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task206 import big_no_automaton + +class Task206Test(unittest.TestCase): + """Testy do zadania 206""" + + def test_simple(self): + """Prosty test.""" + + automaton = big_no_automaton() + + self.assertTrue(automaton.accepts("NOOOOO!")) + self.assertTrue(automaton.accepts("NOOOOOOOOOOOOOOOO!")) + self.assertFalse(automaton.accepts("NOOOO!")) + self.assertFalse(automaton.accepts("NOOOOOO!!!!!!")) + self.assertFalse(automaton.accepts("NOOOOOO")) + self.assertFalse(automaton.accepts("ONOOOOO!")) + self.assertFalse(automaton.accepts("")) + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task207Test.py b/automata/Task207Test.py new file mode 100755 index 0000000..29a9343 --- /dev/null +++ b/automata/Task207Test.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 207 + +Napisz funkcję `three_automaton()`, która +tworzy i zwraca automat, który akceptuje +napisy reprezentujące liczby podzielne przez 3. Automat +nie powinien akceptować napisów zaczynających +nieznaczącymi zerami (np. "033"). + +NAME: three_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task207 import three_automaton + +class Task207Test(unittest.TestCase): + """Testy do zadania 207""" + + def test_simple(self): + """Prosty test.""" + + automaton = three_automaton() + + self.assertTrue(automaton.accepts("3")) + self.assertTrue(automaton.accepts("0")) + self.assertTrue(automaton.accepts("12")) + self.assertTrue(automaton.accepts("324")) + self.assertTrue(automaton.accepts("333333")) + self.assertTrue(automaton.accepts("30003")) + self.assertTrue(automaton.accepts("513")) + + self.assertFalse(automaton.accepts("00")) + self.assertFalse(automaton.accepts("012")) + self.assertFalse(automaton.accepts("0000324")) + self.assertFalse(automaton.accepts("1")) + self.assertFalse(automaton.accepts("2")) + self.assertFalse(automaton.accepts("5")) + self.assertFalse(automaton.accepts("1111")) + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task208Test.py b/automata/Task208Test.py new file mode 100755 index 0000000..579f762 --- /dev/null +++ b/automata/Task208Test.py @@ -0,0 +1,49 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 208 + +Napisz funkcję `twenty_five_automaton()`, która +tworzy i zwraca automat, który akceptuje +napisy reprezentujące liczby podzielne przez 25. Automat +może akceptować napisy zaczynające +nieznaczącymi zerami (np. "075"). Nie powinien akceptować natomiast +samego zera ("0"). + +NAME: twenty_five_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task208 import twenty_five_automaton + +class Task208Test(unittest.TestCase): + """Testy do zadania 208""" + + def test_simple(self): + """Prosty test.""" + + automaton = twenty_five_automaton() + + self.assertTrue(automaton.accepts("25")) + self.assertTrue(automaton.accepts("50")) + self.assertTrue(automaton.accepts("75")) + self.assertTrue(automaton.accepts("100")) + self.assertTrue(automaton.accepts("1098375")) + self.assertTrue(automaton.accepts("333325")) + self.assertTrue(automaton.accepts("17150")) + + self.assertTrue(automaton.accepts("025")) + self.assertTrue(automaton.accepts("0000175")) + self.assertFalse(automaton.accepts("1")) + self.assertFalse(automaton.accepts("2")) + self.assertFalse(automaton.accepts("5")) + self.assertFalse(automaton.accepts("10")) + self.assertFalse(automaton.accepts("45")) + self.assertFalse(automaton.accepts("124")) + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task209Test.py b/automata/Task209Test.py new file mode 100755 index 0000000..6d1aa01 --- /dev/null +++ b/automata/Task209Test.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 209 + +Napisz funkcję `monsters_automaton()`, która +tworzy i zwraca automat, który akceptuje +wyłącznie napisy "Godzilla", "Ghidora" oraz "Mothra" +i żadnych innych. + +NAME: monsters_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task209 import monsters_automaton + +class Task209Test(unittest.TestCase): + """Testy do zadania 209""" + + def test_simple(self): + """Prosty test.""" + + automaton = monsters_automaton() + + self.assertTrue(automaton.accepts("Godzilla")) + self.assertTrue(automaton.accepts("Ghidora")) + self.assertTrue(automaton.accepts("Mothra")) + + self.assertFalse(automaton.accepts("Biollante")) + self.assertFalse(automaton.accepts("")) + self.assertFalse(automaton.accepts("Godzil")) + self.assertFalse(automaton.accepts("Kojot")) + self.assertFalse(automaton.accepts("Godzra")) + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task210Test.py b/automata/Task210Test.py new file mode 100755 index 0000000..a5dbced --- /dev/null +++ b/automata/Task210Test.py @@ -0,0 +1,45 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 210 + +Napisz funkcję `abc_automaton()`, która +tworzy i zwraca automat, który akceptuje +napisy składające z dowolnej liczby +znaków 'a', po których następuje dowolna liczba +znaków 'b', po których następuje dowolna liczba +znaków 'c'. "Dowolna" oznacza także zero. + +NAME: abc_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task210 import abc_automaton + +class Task210Test(unittest.TestCase): + """Testy do zadania 210""" + + def test_simple(self): + """Prosty test.""" + + automaton = abc_automaton() + + self.assertTrue(automaton.accepts("")) + self.assertTrue(automaton.accepts("abc")) + self.assertTrue(automaton.accepts("aaaaaaaabccc")) + self.assertTrue(automaton.accepts("bbbccc")) + self.assertTrue(automaton.accepts("ac")) + self.assertTrue(automaton.accepts("abbbbbbbbbbbbbb")) + + self.assertFalse(automaton.accepts("ba")) + self.assertFalse(automaton.accepts("cccbbbaaa")) + self.assertFalse(automaton.accepts("baba")) + self.assertFalse(automaton.accepts("abcca")) + + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task211Test.py b/automata/Task211Test.py new file mode 100755 index 0000000..b1ce5ca --- /dev/null +++ b/automata/Task211Test.py @@ -0,0 +1,41 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 211 + +Napisz funkcję `kot_automaton()`, która tworzy i zwraca automat, który +akceptuje napisy "kos", "kot", "kat", "lot", "lat" i nie akceptuje +żadnych innych napisów. + +NAME: kot_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task211 import kot_automaton + +class Task211Test(unittest.TestCase): + """Testy do zadania 211""" + + def test_simple(self): + """Prosty test.""" + + automaton = kot_automaton() + + self.assertTrue(automaton.accepts("kos")) + self.assertTrue(automaton.accepts("kot")) + self.assertTrue(automaton.accepts("kat")) + self.assertTrue(automaton.accepts("lot")) + self.assertTrue(automaton.accepts("lat")) + + self.assertFalse(automaton.accepts("ko")) + self.assertFalse(automaton.accepts("")) + self.assertFalse(automaton.accepts("los")) + self.assertFalse(automaton.accepts("kota")) + + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task212Test.py b/automata/Task212Test.py new file mode 100755 index 0000000..10ec1b2 --- /dev/null +++ b/automata/Task212Test.py @@ -0,0 +1,41 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 212 + +Napisz funkcję `negation_automaton()`, która tworzy i zwraca automat +akceptujący wszystkie napisy nad alfabetem "abcd" +z wyjątkiem napisu "abba". + +NAME: negation_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task212 import negation_automaton + +class Task212Test(unittest.TestCase): + """Testy do zadania 212""" + + def test_simple(self): + """Prosty test.""" + + automaton = negation_automaton() + + self.assertTrue(automaton.accepts("abbb")) + self.assertTrue(automaton.accepts("baca")) + self.assertTrue(automaton.accepts("dddddd")) + self.assertTrue(automaton.accepts("abbaa")) + self.assertTrue(automaton.accepts("abb")) + self.assertTrue(automaton.accepts("ab")) + self.assertTrue(automaton.accepts("")) + + self.assertFalse(automaton.accepts("abba")) + self.assertFalse(automaton.accepts("xa")) + + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task213Test.py b/automata/Task213Test.py new file mode 100755 index 0000000..fa49cc6 --- /dev/null +++ b/automata/Task213Test.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 213 + +Napisz funkcję `tricky_automaton()`, która tworzy i zwraca automat +akceptujący wszystkie napisy złożone z napisu "abc" powtórzonego +dowolną liczbę razy (ale przynajmniej raz) oraz napis "a". + +NAME: tricky_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task213 import tricky_automaton + +class Task213Test(unittest.TestCase): + """Testy do zadania 213""" + + def test_simple(self): + """Prosty test.""" + + automaton = tricky_automaton() + + self.assertTrue(automaton.accepts("a")) + self.assertTrue(automaton.accepts("abc")) + self.assertTrue(automaton.accepts("abcabc")) + self.assertTrue(automaton.accepts("abcabcabcabcabc")) + + self.assertFalse(automaton.accepts("ab")) + self.assertFalse(automaton.accepts("")) + self.assertFalse(automaton.accepts("abca")) + self.assertFalse(automaton.accepts("abcabca")) + + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task214Test.py b/automata/Task214Test.py new file mode 100755 index 0000000..e3a7b3d --- /dev/null +++ b/automata/Task214Test.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 214 + +Napisz funkcję `hex_automaton()`, która tworzy i zwraca automat +akceptujący napisy reprezentujące liczby szesnastkowo. +Cyfry szesnastkowe mogą być reprezentowane za pomocą małych +bądź wielkich liter, ale konsekwentnie ("a0f9" i "A0F9" ma być akceptowane, +"a0F9" i "A0f9" - nie). Liczba może zawierać zera nieznaczące na początku. + +NAME: hex_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task214 import hex_automaton + +class Task214Test(unittest.TestCase): + """Testy do zadania 214""" + + def test_simple(self): + """Prosty test.""" + + automaton = hex_automaton() + + self.assertTrue(automaton.accepts("a0f9")) + self.assertTrue(automaton.accepts("A0F9")) + self.assertTrue(automaton.accepts("0")) + self.assertTrue(automaton.accepts("0B000")) + self.assertTrue(automaton.accepts("DDDD")) + self.assertTrue(automaton.accepts("baca")) + + self.assertFalse(automaton.accepts("gg")) + self.assertFalse(automaton.accepts("a0F9")) + self.assertFalse(automaton.accepts("A0f9")) + self.assertFalse(automaton.accepts("Baca")) + + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task215Test.py b/automata/Task215Test.py new file mode 100755 index 0000000..86632a1 --- /dev/null +++ b/automata/Task215Test.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 215 + +Napisz funkcję `four_automaton()`, która +tworzy i zwraca automat, który akceptuje +napisy reprezentujące liczby podzielne przez 4. Automat +nie powinien akceptować napisów zaczynających +nieznaczącymi zerami (np. "044"). + +NAME: four_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task215 import four_automaton + +class Task215Test(unittest.TestCase): + """Testy do zadania 215""" + + def test_simple(self): + """Prosty test.""" + + automaton = four_automaton() + + self.assertTrue(automaton.accepts("4")) + self.assertTrue(automaton.accepts("0")) + self.assertTrue(automaton.accepts("12")) + self.assertTrue(automaton.accepts("324")) + self.assertTrue(automaton.accepts("1052")) + self.assertTrue(automaton.accepts("444444")) + + self.assertFalse(automaton.accepts("012")) + self.assertFalse(automaton.accepts("0000324")) + self.assertFalse(automaton.accepts("5")) + self.assertFalse(automaton.accepts("1")) + self.assertFalse(automaton.accepts("3")) + self.assertFalse(automaton.accepts("34")) + self.assertFalse(automaton.accepts("1057")) + self.assertFalse(automaton.accepts("4454")) + + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task216Test.py b/automata/Task216Test.py new file mode 100755 index 0000000..1182f51 --- /dev/null +++ b/automata/Task216Test.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 216 + +Napisz funkcję `code_automaton()`, która +tworzy i zwraca automat, który akceptuje +kody pocztowe (ciągi cyfra-cyfra-minus-cyfra-cyfr-cyfra). + +NAME: code_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task216 import code_automaton + +class Task216Test(unittest.TestCase): + """Testy do zadania 216""" + + def test_simple(self): + """Prosty test.""" + + automaton = code_automaton() + + self.assertTrue(automaton.accepts("61-909")) + self.assertTrue(automaton.accepts("22-340")) + self.assertTrue(automaton.accepts("00-000")) + self.assertTrue(automaton.accepts("99-999")) + + self.assertFalse(automaton.accepts("61909")) + self.assertFalse(automaton.accepts("61-90")) + self.assertFalse(automaton.accepts("000-000")) + self.assertFalse(automaton.accepts("")) + + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task217Test.py b/automata/Task217Test.py new file mode 100755 index 0000000..6e85ddd --- /dev/null +++ b/automata/Task217Test.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 217 + +Napisz funkcję `dna_automaton()`, która +tworzy i zwraca automat, który akceptuje +niepuste ciągi złozone z liter "A", "C", "G" i "T" +których długość jest wielokrotnością liczby 3. + +NAME: dna_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task217 import dna_automaton + +class Task217Test(unittest.TestCase): + """Testy do zadania 217""" + + def test_simple(self): + """Prosty test.""" + + automaton = dna_automaton() + + self.assertTrue(automaton.accepts("AAACGT")) + self.assertTrue(automaton.accepts("ACA")) + self.assertTrue(automaton.accepts("ACAAAAGCAACAAAAGCA")) + self.assertTrue(automaton.accepts("TTT")) + + self.assertFalse(automaton.accepts("TT")) + self.assertFalse(automaton.accepts("A")) + self.assertFalse(automaton.accepts("AAACG")) + self.assertFalse(automaton.accepts("")) + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task218Test.py b/automata/Task218Test.py new file mode 100755 index 0000000..6add010 --- /dev/null +++ b/automata/Task218Test.py @@ -0,0 +1,42 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 218 + +Napisz funkcję `binary_list_automaton()`, która +tworzy i zwraca automat, który akceptuje +napisy złożone z liczb zapisanych binarnie +(bez zbędnych zer na początku) oddzielonych dwukropkami. +Akceptowana powinna być także pojedyncza liczba. + +NAME: binary_list_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task218 import binary_list_automaton + +class Task218Test(unittest.TestCase): + """Testy do zadania 218""" + + def test_simple(self): + """Prosty test.""" + + automaton = binary_list_automaton() + + self.assertTrue(automaton.accepts("100:11:11101")) + self.assertTrue(automaton.accepts("1")) + self.assertTrue(automaton.accepts("0:110")) + + self.assertFalse(automaton.accepts("")) + self.assertFalse(automaton.accepts("010:110")) + self.assertFalse(automaton.accepts("2")) + self.assertFalse(automaton.accepts("100::11:11101")) + self.assertFalse(automaton.accepts("100:11:11101:")) + self.assertFalse(automaton.accepts(":100:11:11101")) + +if __name__ == '__main__': + unittest.main() diff --git a/automata/Task219Test.py b/automata/Task219Test.py new file mode 100755 index 0000000..5acf84f --- /dev/null +++ b/automata/Task219Test.py @@ -0,0 +1,45 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 219 + +Napisz funkcję `alt_automaton()`, która +tworzy i zwraca automat, akceptujący +napisy złożone z "abc" powielonego dowolną liczbę razy +(w tym zero) oraz napisy złożone z "ab" powielonego +dowolną liczbę razy. + +NAME: alt_automaton +PARAMS: - +RETURN: DeterministicAutomaton +POINTS: 8 +""" + +import unittest +from Task219 import alt_automaton + +class Task219Test(unittest.TestCase): + """Testy do zadania 219""" + + def test_simple(self): + """Prosty test.""" + + automaton = alt_automaton() + + self.assertTrue(automaton.accepts("abababab")) + self.assertTrue(automaton.accepts("abcabc")) + self.assertTrue(automaton.accepts("abc")) + self.assertTrue(automaton.accepts("ab")) + self.assertTrue(automaton.accepts("")) + self.assertTrue(automaton.accepts("abab")) + self.assertTrue(automaton.accepts("abcabcabcabcabcabcabcabc")) + + self.assertFalse(automaton.accepts("ba")) + self.assertFalse(automaton.accepts("abca")) + self.assertFalse(automaton.accepts("aba")) + self.assertFalse(automaton.accepts("ababc")) + self.assertFalse(automaton.accepts("abcab")) + +if __name__ == '__main__': + unittest.main() diff --git a/automata/deterministic_automaton.py b/automata/deterministic_automaton.py new file mode 100644 index 0000000..05efaa2 --- /dev/null +++ b/automata/deterministic_automaton.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- + +""" +Automat deterministyczny. +""" + +class DeterministicAutomaton: + """ + Klasa reprezentująca deterministyczny automat skończenie stanowy. + """ + + def __init__(self): + """ + Konstruktor. + """ + + # Liczba wszystkich stanów, + # stany będą identyfikowane przez kolejne liczby: + # 0, 1, ..., number_of_states - 1 + self.number_of_states = 0 + + # przejścia będą przechowywane w tablicy + # haszującej indeksowanej parą stan-znak, + # tj. transitions[(state_from, character)] + # przechowuje stan docelowy przy + # przejściu od stanu state_from przez znak + # character + self.transitions = { } + + # stan początkowy + self.initial_state = None + + # zbiór stanów końcowych + self.final_states = set() + + # funkcje modyfikujące automat + + def add_state(self): + """ + Dodaje nowy stan, zwraca numer utworzonego stanu + """ + self.number_of_states += 1 + return self.number_of_states - 1 + + def add_transition(self, state_from, symbol, state_to): + """ + Dodaje przejście od stanu state_from przez znak symbol + do stanu state_to. + """ + self.transitions[(state_from, symbol)] = state_to + + def mark_as_initial(self, state): + """ + Oznacza stan jako początkowy. + """ + self.initial_state = state + + def mark_as_final(self, state): + """ + Oznacza stan jako końcowy. + """ + self.final_states.add(state) + + # dostęp do automatu + + def get_number_of_states(self): + """ + Zwraca liczbę stanów. + """ + return self.number_of_states + + def get_initial_state(self): + """ + Zwraca stan początkowy. + """ + return self.initial_state + + def is_final_state(self, state): + """ + Zwraca informacje, czy stan jest końcowy. + """ + return state in self.final_states + + def get_target_state(self, state_from, symbol): + """ + Zwraca stan docelowy, przy przejściu od stanu state_from + przez symbol bądź wartość None, jeśli nie + ma takiego przejścia. + """ + return self.transitions.get((state_from, symbol)) + + def accepts(self, string): + """ + Sprawdza, czy automat akceptuje napis. + """ + current_state = self.get_initial_state() + + for symbol in string: + current_state = self.get_target_state(current_state, symbol) + + if current_state is None: + return False + + return self.is_final_state(current_state) + + +if __name__ == '__main__': + AUTOMATON = DeterministicAutomaton() + + INITIAL_STATE = AUTOMATON.add_state() + FINAL_STATE = AUTOMATON.add_state() + AUTOMATON.add_transition(INITIAL_STATE, 'x', FINAL_STATE) + + AUTOMATON.mark_as_initial(INITIAL_STATE) + AUTOMATON.mark_as_final(FINAL_STATE) + + print AUTOMATON.accepts("x") # wypisze True + print AUTOMATON.accepts("") # wypisze False + print AUTOMATON.accepts("ab") # wypisze False