Gra w życie to gra zero-osobowa, czyli nie wymaga sterowania. Idea jest dość prosta: mamy określoną planszę i na niej umieszczone komórki, którą mogą być żywe lub martwe, np.:
Białe pola to żywe komórki, czarne to martwe komórki.
W każdym cyklu programu sprawdzane są dla każdej z komórek następujące warunki:
każda żywa komórka, która ma mniej niż dwóch żywych sąsiadów, umiera z samotności
każda żywa komórka, która ma dokładnie dwóch lub trzeb żywych sąsiadów, żyje dalej
każda żywa komórka, która ma więcej niż trzech żywych sąsiadów, umiera z przeludnienia
każda martwa komórka, która ma trzech żywych sąsiadów, ożywa w ramach reprodukcji
Do implementacji użyłem języka Python i biblioteki PyGame, zestaw ten pozwolił mi w bardzo krótkim czasie zacząć zabawę z automatami komórkowymi.
Któż nie lubi posłuchać radia, jedni słuchają dla muzyki, inni dla informacji, a jeszcze inni po prostu włączają radio jako tło. W dzisiejszych czasach nie jesteśmy już ograniczeni tylko do stacji radiowych, które odbiera nasz odbiornik fm, możemy słuchać audycji z całego świata. W niniejszym artykule pokażę jak zbudować swój własny odbiornik radiowy działający na mini-komputerze Raspberry Pi, sterowany przez przeglądarkę z dowolnego urządzenia w sieci wi-fi. Sercem systemu będzie aplikacja w języku Python.
Czego użyjemy
Na początek wystarczy Raspberry Pi z systemem Raspbian i podłączone do niego słuchawki, na końcu artykułu przedstawię możliwości rozbudowy naszego radia.
Kod źródłowy napiszemy w języku Python 3, do stworzenia prostego interfejsu webowego wykorzystamy framework Flask, zaś za odtwarzanie dźwięku odpowiadać będzie aplikacja Music Player Daemon (mpd) oraz prosty interfejs konsolowy o nazwie mpc. Lista stacji radiowych będzie pobierana z pliku YAML.
Instalacja zależności
Aby zainstalować wszystkie potrzebne narzędzia w systemie Ubuntu lub Raspbian należy wykonać polecenia:
Po wykonaniu aplikacji stream zacznie się odtwarzać, a aplikacja się zakończy. Aby zakończyć odtwarzanie musimy w konsoli systemowej wykonać polecenie mpc stop.
Jeśli wykonamy polecenie mpc playlist, zobaczymy że do naszej playlisty została dodana stacja „http://bbcwssc.ic.llnwd.net/stream/bbcwssc_mp1_ws-einws”. W celu uproszczenia komunikacji naszego skryptu z mpd, przed każdym rozpoczęciem odtwarzania będziemy czyścić listę i dodawać wybraną przez nas stację. Implementacja sprowadza się do dodania linii self.mpcCommand(["mpc", "clear"]) przed innymi wywołaniami self.mpcCommand(). Dodatkowo na końcu naszej metody __init__(self) możemy dodać:
while True:
None
Spowoduje to, że aplikacja będzie uruchomiona dopóki nie przerwiemy jej działania, na przykład kombinacją klawiszy CTRL+C. Przerwanie pracy aplikacji nie spowoduje jednak przerwania odtwarzania strumienia przez demon mpd, dlatego musimy dodać metodę exitHandler() oraz zadeklarować jej wywołanie po zakończeniu aplikacji.
Jak widać metoda zatrzymuje odtwarzanie i czyści playlistę. Aby python wykonał tą metodę po zakończeniu aplikacji, należy metodzie __init__() dodać linijkę:
atexit.register(self.exitHandler)
Linia ta musi być umieszczona przed pętlą while True.
Kolejnym krokiem będzie wczytanie listy stacji z pliku YAML. Przykładowy plik znajduje się tutaj, natomiast jego wczytanie wygląda następująco:
stationsFile = open("stations.yml", "r")
data = yaml.load(stationsFile)
self.stations = []
for k in data:
self.stations.append({
"name": k,
"url": data[k]
})
Powyższy kod wczytuje zawartość pliku, ładuje go do zmiennej data a następnie tworzy listę słowników self.stations. Aby kod zadziałał musimy dodać jeszcze jeden moduł:
import oyaml as yaml
Użyłem oyaml zamiast PyYaml, ponieważ PyYaml nie zawsze wczytuje listę stacji w takiej kolejności jaką ustaliliśmy w pliku .yml, oyaml rozwiązuje ten problem.
Następnie usuwamy pętlę while True a zamiast niej wstawiamy kod:
self.initWebUi()
Jest to wywołanie metody, której definicja wygląda następująco:
from flask import Flask
from flask import render_template
from flask import request
Metoda initWebUi() inicjuje framework flask i definuje prosty routing wewnątrz którego jest akcja control_page wyświetlająca szablon z pliku template/control.html oraz obsługująca komendy „Play” i „Stop”. Plik szablonu znajduje się tutaj.
Dodatkowo w metodzie __init__() musimy dodać:
self.currentStationUrl = None
W tym momencie możemy otworzyć w przeglądarce adres http://0.0.0.0:1234/ i zobaczymy prosty panel pozwalający na wybór stacji i rozpoczęcie lub zatrzymanie odtwarzania.
Pełny kod aplikacji umiesciłem się w repozytorium na GitHub https://github.com/jakubthedeveloper/PythonInternetRadio, znajduje się w nim kod z artykułu z kilkoma usprawnieniami, na przykład możliwość podania w argumentach wywołania skryptu adresu i portu na którym ma działać nasze webowe UI. W pliku README.md znajdziemy również informację jak uruchomić projekt na mini-komputerze Raspberry Pi.
Dodatkowo kod w repozytorium został zrefaktoryzowany, poszczególne funkcje zostały przeniesione do odpowiednich klas, dodałem też unit testy.
Rozwój projektu
W momencie gdy na słuchawkach podpiętych do Raspberry Pi słyszymy stację radiową wybraną w naszym webowym interfejsie mamy doskonały punkt wyjścia, żeby zbudować coś ciekawszego. Kilka pomysłów:
Możemy użyć zewnętrznego głośnika, np. połączonego z Raspberry przez bluetooth
Możemy użyć nakładki wzmacniacza audio dla Raspberry Pi i podłączyć dowolny głośnik
Możemy użyć starego radioodbiornika, z którego wymontujemy całą elektronikę a w jej miejsce wstawimy Raspberry i moduł wzmacniacza podłączony do głośnika, który służył w wykorzystanym urządzeniu.
Możemy do naszej konstrukcji wstawić powerbank i uczynić ją bardziej przenośną
Możemy zamienić interfejs webowy na bluetooth i stworzyć interfejs mobilny na Androida lub iOS, w ten sposób naszym radiem będziemy mogli sterować nawet tam gdzie nie mamy dostępu do sieci Wi-fi
Możemy stworzyć fizyczny interfejs dla naszego radia, zawierający takie elementy jak: przyciski do wywoływania zdefiniowanych stacji radiowych, wyświetlacz wyświetlający nazwę aktualnej stacji, kontrolę głośności (można to zrobić przez komendę `mpc volume [+-]<num>` lub sprzętowo), kontrolę tonów niskich/wysokich.
Można zbudować old-schoolowo wyglądające urządzenie, na przykład używając obudowy i głośnika z radioodbiornika Unitra Kasprzak
Można zbudować futurystycznie wyglądające urządzenie, na przykład budując panel przypominający kokpit statku kosmicznego
Zachęcam do eksperymentowania i podsyłania waszych realizacji.
Aktualizacja
Już po napisaniu powyższego artykułu dokonałem wielu modyfikacji, które znajdziecie w repozytorium projektu. Jedną z nich jest modyfikacja interfejsu webowego z wykorzystaniem Bootstrap i jQuery:
Przykład użycia
Moje radyjko zbudowane z wykorzystaniem rozwiązania przedstawionego w niniejszym artykule opiera się na następującej architekturze:
Mieszanie kreatywności z nudą i odrobiną wolnego czasu bywa zaskakujące w skutkach, u mnie dziś taka mieszana zaowocowała urządzeniem, które pokazuje powiadomienie o nieprzeczytanej poczcie w postaci ikony koperty narysowanej flamastrem na kawałku tektury, powiadomienie wyskakuje zza monitora po nadejściu nowej wiadomości i chowa się gdy wszystkie wiadomości są przeczytane.
Jeśli nie podamy adresu serwera IMAP, zostanie użyty adres imap.gmail.com, domyślną wartością parametru –serial-port jest /dev/ttyUSB0, natomiast parametr –imap-user jest obowiązkowy. Przykład:
Więcej informacji o uruchomieniu skryptu znajduje się w pliku readme.
Po uruchomieniu, skrypt sprawdza pocztę na serwerze i wysyła na port szeregowy (usb) tekst ‚mail’ lub ‚nomail’, zależnie czy są nieprzeczytane wiadomości czy też nie.
Aplikacja dla Arduino nasłuchuje na porcie szeregowym i ustawia serwo w jednej z dwóch predefiniowanych pozycji, zależnie od otrzymanej komendy. Poziome ustawienie zamocowanej do serwo tekturki pozwala jej się schować za monitorem, natomiast w ustawieniu pionowym tektura wystaje nad górną krawędź monitora.
Filmik z testów:
Problemy jakie przyszło rozwiązać
Największym problemem było znalezienie sposobu na zamontowanie urządzenia z tyłu monitora, na szczęście z pomocą przyszły nawiercone kątowniki, śrubki i trytytki 🙂
Jakiś czas temu moja sześcioletnia córka miała powiedzieć w przedszkolu czym zajmują się rodzice i bezbłędnie powiedziała że jestem programistą, ale do końca nie wiedziała o co w tym chodzi.
Dziś, gdy siedziałem i czytałem książkę o Pythonie, przyszła do mnie mówiąc jakie obliczenia matematyczne umie robić. Jako że miałem komputer z odpalonym linuksem pod ręką, odpaliłem interpreter pythona i zacząłem wpisywać równania, które mówiła córka: 1+1, 2+2, później odejmowanie, a nawet pokazałem jej dzielenie i co się dzieje gdy podzielimy przez zero. Widziałem w jej oczach zainteresowanie, więc zacząłem opowiadać że to właśnie na tym polega programowanie, że mówimy komputerowi żeby coś policzył a on to bardzo szybko robi. Aby pokazać że nie tylko o liczenie możemy poprosić nasz komputer wpisałem w pythonie:
Na ekranie zaczęło się coś rysować, a rysowanie to jest hobby mojej córki, więc zainteresowanie się nasiliło do tego stopnia, że już po chwili mieliśmy narysowany prosty domek.
W ciągu ostatnich kilka miesięcy przetestowałem mniej lub bardziej dogłębnie kilka bibliotek do tworzenia gier 2d, w celu znalezienia tego optymalnego dla mnie. Najlepsze efekty jak dotąd dawał mi język Lua i framework LÖVE, jednak dziś rolę lidera mojej klasyfikacji objął bezdyskusyjnie Python i biblioteka PyGame.
PyGame daje dużą szybkość uczenia się oraz znikomą ilość problemów związanych z samą biblioteką, zatem mogę się skupić na problemach dotyczących mechaniki mojej gry. Podstawy Pythona oraz tworzenia gier 2d posiadłem już wcześniej, natomiast PyGame ma dobrą dokumentację, łatwo dostępną choćby poprzez wyszukiwarkę Google, więc bez przeszkód na starcie, zacząłem pisać. Oto co udało mi się uzyskać po pierwszych kilku godzinach pisania (mocno przerywanych innymi zajęciami):
Ta strona korzysta z plików cookie, abyśmy mogli zapewnić Ci najlepszą możliwą obsługę. Informacje o plikach cookie są przechowywane w przeglądarce użytkownika i służą do wykonywania funkcji, takich jak rozpoznawanie użytkownika po powrocie do naszej witryny i pomaganie naszemu zespołowi w zrozumieniu, które sekcje witryny są dla niego najbardziej interesujące i użyteczne.
Możesz dostosować wszystkie ustawienia plików cookie, przeglądając karty po lewej stronie.
Ściśle niezbędne pliki cookie
Ściśle konieczne pliki cookie powinny być włączone przez cały czas, abyśmy mogli zapisać preferencje dotyczące ustawień plików cookie.
Jeśli wyłączysz ten plik cookie, nie będziemy mogli zapisać twoich preferencji. Oznacza to, że za każdym razem, gdy odwiedzasz tę stronę, musisz ponownie włączyć lub wyłączyć pliki cookie.