sobota, 14 stycznia 2012

Tworzenie klasy do deserializacji pliku XML

Español: fotoXML
Image via Wikipedia
Jak zdeserializować plik XML jeżeli nie posiadamy klasy, która została zserializowana.
Do zdeserializowania pliku XML potrzebujemy odpowiedną klasę, która przyjmę dane z pliku.
Za pomocą narzędzia znajdującego się w Windows SDK możemy potrzebne klasy wygenerować. Owym narzędziem rozwiązującym problem jest xsd.exe znajdujący się domyślnie w katalogu:

(Windows 7 x64)
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin

Aby wygenerować potrzebną mam klasę uruchamiamy Visual Studio Command Prompt znajdujący się w:

Start->Wszystkie programy -> Microsoft Visual Studio 2010 -> Visual Studio Tools

Odtworzy się nam okno wiersza poleceń przechodzimy w nim do katalogu z naszym plikiem .xml i wykonujemy następujące czynności:
  • xsd filename.xml – tworzony jest plik XSD dla naszego pliku XML. Jeżeli takowy plik już istnieje pomijamy ten krok.
    • Plik XSD posiada opis schematu pliku XML (jakie pola występują w pliku)
    • Warto przejrzeć wygenerowany plik ponieważ to narzędzie przyjmuje że każda dana jest stringiem, warto zamienić odpowiednie wpisy w pliku na inny typ
    • Typ pola w XSD jest definiowany za pomocą atrybutu type, oprócz xs:string może zawierać następujące typy
      • xs:dateTime
      • xs:time
      • xs:date
      • xs:integer
      • xs: float
      • xs:double
      • resztę typów możliwych do wprowadzenie można znaleźć na stronach W3C
  • xsd filename.xsd /c – tworzone są klasy w języku C# 
    • Można również utworzyć klasę w innym języku korzystając z przełącznika /language.
    • Przykłady:
      • /language:VB – Visual Basic
      • /language:CPP – C++/CLI
  • Zdeserializować przy użyciu klasy XmlSerializer
Enhanced by Zemanta

sobota, 3 grudnia 2011

Programmer Bot - wersja Alpha. Moje przeżycia część 1

W pierwszym semestrze na 2 roku studiów na Zachodniopomorskim Uniwersytecie Technologicznym na kierunku Informatyka, jest zadanie. Trzeba napisać grę.

I to grę 3D.

Ludziom co nie znają poziomu ZUT'u dopowiem, że piszemy korzystając z OpenGL 1.1 - 2.1, czyli czegoś super wypas nie musimy robić, bo też narzędzia wydają się mało ostre.

Chyba w tym roku najpopularniejszym pomysłem wśród braci studenckiej są wyścigi 3 rzędowe. Przykładowa gra taka jak Wild Wild Taxi (gra flash).

Ja pomysł na grę także zaczerpnąłem z gier flashowych, a mianowicie z gry lightBot.

Nie zamierzam opisać tej gry, wystarczy przejść kilka pierwszych poziomów oryginału, aby wiedzieć z czym musiałem się zmagać podczas tworzenia tego klonu gry.

Start programowania, zgrzyt językowy
Domyślnie językiem, który każdy student na drugim roku powinien potrafić, to C. Obok zajęć z grafiki istnieje przedmiot programowanie obiektowe na którym zgłębiamy język C++.

Rozpocząłem projekt od zera, od pustego projektu konsolowego. Następnie dodałem biblioteki i zadbałem aby projekt był łatwy do przeniesienia pomiędzy komputerami. Biblioteki umieściłem w katalogu lib obok źródeł. A ścieżki dla kompilatora były podane jakie ścieżki pośrednie.

Gdy projekt osiągnął pułap 300-400 linii kodu, stwierdziłem, że język C++ spowalnia pisanie gry. Uciążliwe stały się pliki nagłówkowe które trzeba było pamiętać, aby je aktualizować za każdym razem gdy chcemy dodać, zmienić, zmodyfikować, usunąć funkcję.

Ponadto trudne do zrozumienia były błędy kompilatora, a sam proces kompilacji wydłużał się z powodu wielu zbędnych #includów. Wtedy zmiana jednego fragmentu programu powodowała re-kompilację całego projektu.

Poczułem, że za mało znam C++ aby mógł komfortowo z niego korzystać. Teraz czuję, że dalsze korzystanie z C++ mogło spowodować przyspieszone łysienie.
OpenTK
Jako, że znam C# chyba najlepiej z wszystkich języków to postanowiłem poszukać bibliotek które pozwoliły mi przenieść istniejący kod na C#

Przeszukując rożne istniejące biblioteki, których rozwój jest martwy lub nie całkiem martwy, wybrałem OpenTK
Zalety OpenTK:
  • Pozwala na wykorszystanie OpenGL 1.1, 2.0
  • Jest bibliotką niskiego poziomu
  • Posiada API do przechwytywania danych z klawiatury, myszy, josticka
  • Możliwość tworzenia okna przy użyciu OpenTK
  • Przykładowe programy.
Wady OpenTK:
  • projekt nie jest aktywny, ostatnia stabilna wersja datowana jest na 6-10-2010 (choć pojawią się nocne paczki)
  • nie wspiera najnowszych wersji OpenGL
  • Duża ilość śmieciowego kodu, oznaczonego jako deprecate

niedziela, 20 listopada 2011

Prezentacja drzewa binarnego za pomocą przeglądarki

Na laboratoriach z struktur danych tworzymy drzewo binarne, do prezentacji tego drzewa mieliśmy stworzyć prezentację semigraficzną. Taka prezentacja ma wadę  taką że w oknie konsoli zmieści się tylko mała ilość węzłów. Z moich szybkich szacowań w oknie konsoli nie zmieści się więcej niż 40 węzłów (trzeba zachować hierarchę etc.)

Miałem parę pomysł jak taki graficzną prezentacje zrobić:
  • wykorzystać bibliotekę taką jak SDL i wykonać obliczenia pozycji węzłów ręcznie i je połączyć za pomocą lini.
  • wykorzystać istniejące oprogramowanie takie jak: Graphviz
  • szukać czegoś w związanego z przeglądarką
Pierwsze pomysł odrzuciłem ponieważ wymagał zbyt dużego poświęcenia czasu (programowanie odbywa się w późnych godzinach wieczornych), o drugim wtedy nie pamiętałem.

Wszedłem na Google i rozpocząłem poszukiwania, wiedząc że coś z javascriptem musi być.

Moja pewność była spowodowana znajomością pewnego prawa w oprogramowaniu.
 Atwood's Law: any application that can be written in JavaScript, will eventually be written in JavaScript.
Rozpocząłem szukanie od strony Google Charts, przeszukałem wszystko i... nic odpowiedniego nie znalazłem, nie było nic tworzeniu grafów.

Niezrażony przeszukałem sieć pod kątem "graphs jquery". i znalazłem! Ale... znaleziony biblioteki wydały mi się zbyt skomplikowane jak do takiego małego problemu, do wróbla nie strzela się z armaty.

Zawiedziony rozpocząłem na nowo przeszukiwania Google Charts teraz stawiąc na coś co raczej przypomina coś co chcę stworzyć.

W oko padło mi Org Charts (służące do pokazywania hierarchii wewnątrz firm).

Niemalże wszystkie Charts jako dostawcy danych korzystają z google.visualization.DataTable(); jako dostawcy danych do tabel, rysunków etc.

DataTable dla Org Charts może składać się 3 kolumn (o dowolnych nazwach):
  • Pierwsza jest wymagana i posiada informacje o nazwie elementu. Ta nazwa musi być unikatowa wewnątrz całej tabeli. Można rozdzielić unikatową nazwę od nazwy wyświetlanej.
  • Druga kolumna jest opcjonalna i posiada informacje od rodzicu
  • Trzecia kolumna przechowuje tekst ToolTipa (informacji która się pojawia po najechaniu kursorem)
Wypełnienie danych w tabeli było proste, do póki nie doszło do wyświetlania :)

Chciałem aby wyświetlał się informacje o NULL'u (czyli że wskaźnik jakieś węzła nie posiada lewo/prawego potomka), a na stronie pokazywał się tylko jeden NULL.

Problemem było nie unikatowość NULL'a. Przypomniało mi się pewna rzecz z języka C#, tam aby coś miało unikalny identyfikator korzystało się z GUID'ów (jest implementacją UUID).

W C++ aby uzyskać GUID trzeba skorzystać z funkcji CoCreateGuid (która jest dostępna w za pomocą pliku nagłówkowego windows.h) w sposób następujący:
GUID guid
CoCreateGuid(&guid); 
Po wykonaniu tej funkcji struktura GUID zostaje zapełniona danymi. Kolejne części identyfikatora znajdują się w polach guid.Data1, guid.Data2, guid.Data3, guid.Data4.

I teraz dzięki unikalnemu GUID'owi oraz możliwości rozdzielenia unikalnego klucza oraz wyświetlanej nazwy, mogłem się cieszyć stroną internetową, która posiada hierarchię drzewa binarnego.

Przykłady wygenerowanych drzew:
Mała ilość danych, wartości wprowadzane z ręki

Dane losowe

środa, 9 listopada 2011

Kod mnożący dwie liczby w asemblerze bez używania MUL

Turbo Debugger 1.0 (1989) debugging a "he...
Image via Wikipedia
Mnożenie w asemblerze można wykonać za pomocą instrukcji MUL, jednak zadanie na Architekturze Systemów Komputerowych, brzmiało:
Dany jest 8-bitowe ‘a’ i ‘b’, a wynik to 16 bitowy zapis w zmiennej ‘wynik’ . Proszę wykonać operację mnożenia.
Zanim przejdę do kodu i jego omawiania trzeba poznać trochę logiki, która 'stoi' za algorytmem.
Algorytm rozkłada liczbę b na sumę potęg dwójki wykonuje mnożenie a potem sumuje wyniki mnożenia.

Ale przecież nadal mamy mnożenie liczb ze sobą! Tak to prawda, ale do mnożenia liczb które są potęgami dwójki nie musimy korzystać z instrukcji MUL a za pomocą przesunięć bitowych w prawo SHR i lewo SHL

Zakładając że liczba b wynosi 10 to wtedy algorytm by tak 'pracował'
Kod z komentarzami:
unsigned char a,b; //char'y są 8 bitowe (patrz treść zadania)
unsigned short int wynik = 0; // short int 16 bitowy (patrz treść zadania)
a=12; //Ustawiamy dwie wartości które chcemy przemnożyć
b=8;
//Rozpoczynamy wstawkę assemblerową
_asm
{ 
 mov dx,0 //kolejne sumy a << coś będziemy przechowywać w dx (patrz wzór)
 mov bl, b //kopiujemy do bl wartość zmiennejb
 mov cl, 0x00 //cl będzie przechowywać wykładnik potęgi 2 (patrz wzór) 
multi_loop: //etykieta służy później do przeskoków

 shr bl, 1 // przesuwamy bl czyli kopię naszej zmiennej o jeden bit w prawo
     // wartość na pozycji zerowego bitu (najbardziej na prawo)
     // wchodzi do flagi pożyczki (ang. carry flag)
     // dzięki temu wykonujemy dalsze przeskoki (ang. jumpy)
     
 jc multiply //jeżeli właśnie ustawiliśmy flagę pożyczki na 1
    //wykonaj przeskok do etykiety o nazwie multiply
    //jeżeli flaga pożyczki jest ustawiona na zero
    //to ta instrukcja nic nie robi
    
 jz end_multi //Jeżeli wyniku ciągłego przesuwania b wyzerowaliśmy b
        //to oznacza koniec mnożenia (nie ma już w b żadnych jedynek)
 
 jnc next_bit //To przypadek w którym nie wyzerowaliśmy b
     //oraz w bicie zerowym znajduje się zero
     //czyli przeskakujemy do next_bit

multiply:        
 mov al, a    //kopiujemy wartość a do rejestru al
 shl al, cl   //wykonujemy al=al*2^cl
 
 cbw          //abyśmy mogli przekazać wartość z rejestru 8 bitowego
     //do rejestru 16 bitowego musimy 'rozszerzyć' rejestr al
     //aby zajmował wielkość 16 bitową
     //do ax zostaje przypisana wartość al
    
 add dx, ax // wykonywanie dodawania jednego z czynników 
next_bit:
 inc cl     //zwiększamy o jeden wykładnik potęgi
 jmp multi_loop // wykonujemy bezwzględny skok do multi_loop
end_multi:
 mov wynik, dx //Przypisujemy wartość dx do wyniku
} //Kończymy algorytm.


Enhanced by Zemanta

niedziela, 6 listopada 2011

Jak można programować odpowiedź na pytanie: Ile dni upłynęło od początku roku? (w sposób sprytny)

Odkopałem swój post na forum roku informatyki i stwierdziłem że jest warty podzielenia się ze wszystkimi.
Przypomnę że treść zadania
Napisać program który po podaniu daty podaje ile dni upłynęło od początku roku do podanej daty włącznie. Rok przestępny jeżeli dzieli się przez 4 i nie dzieli się przez 100 lub dzieli się przez 400.
Kod w języku C:
#include <stdio.h>
#include <ctype.h>

int is_leap_year(int year);
int day_of_year(int day, int month, int year);
int main() {
    int day = 0, month = 0, year = 0;

    printf("Podaj date (dd/mm/rrrr): ");

    scanf("%d/%d/%d",&day,&month,&year);

    printf("Dzień roku: %d",day_of_year(day,month,year));

    return 0;
}
int is_leap_year(int year){
    return (year % 4 ==0 && year %100 != 0) || year %400 ==0;
}
int get_month_days(int month,int year)
{
    if(month == 2)
            return 28+is_leap_year(year);
    unsigned int magic_number=0xAD5;
    magic_number = magic_number >> (month -1);
    if(magic_number & 1)
        return 31;
    else
        return 30;
}
int day_of_year(int day, int month, int year)
{
   int number_days=0,i;

   for (i=1;i<month;i++)
   {
      number_days+=get_month_days(i,year);
   }
   return number_days+day;
}

Reszta postu będzie się odnościć tylko do jednej funkcji a mianowicie get_month_days.

Najpierw sprawdzana jest sytuacja z lutym, ponieważ on zależy od roku.
Funkcja posiada w sobie liczbę bez znaku o nazwie magic_number która jest zapisana w postaci szesnastkowej. Ale najważniejsze jest jej rozwinięcie binarne, które wygląda tak:
101011010101

Gdzie miejsce jedynek odpowiada który miesiąc posiadający 31 dni (styczeń to pierwszy z prawej)
Linjka:
magic_number = magic_number >> (month -1);

powoduje przesunięcie cyfr w prawo, aby 'miesiąc' był przesunięty na pierwszej pozycji z prawej.
if(magic_number & 1)

Sprawdza czy w liczbie po przesunięciu na pozycji najbardziej z prawej znajduje się 1. Jeżeli tak to 31 jeżeli nie to 30

Mam nadzieje że kogoś może ‘zainspirowałem’ do podchodzenie do problemów programistycznych inaczej niż najprostsza ścieżka.

piątek, 28 października 2011

MemoryStream jako zamiennik dla wyjścia konsoli (lub pliku)

Different RAM types. From top to bottom: DIP, ...
Image via Wikipedia
Obecnie tworze aplikację konsolową, jest to REPL dla mojego tyci-mini języka (język nie istnieje poza REPL).

Postanowiłem, że istniejącą funkcję print pokryję testami jednostkowymi. Zastanawiałem się jak to zrobić. Problem polegał na tym że wynik przekazywałem na ekran i teraz miałem zagwostkę jak ten tekst przechwycić.

Dowiedziałem się o klasie MemoryStream, który tworzy strumień piszący po pamięci przydzielonej dla klasy. 

Moją klasę PrintMethod, musiałem z modyfikować z:
public override Result Run()
{
    string text = base.paramList["text"].Value;
    text = getVariablesFromMemory(text);
    Console.WriteLine(text);
    return new PrintResult(text);
}
na:
TextWriter output;
public PrintMethod(string textToPrint,TextWriter output)
    : base("Print")
{
    base.loadParametr("text", new Parametr(textToPrint));
    this.output = output;
}
  
public override Result Run()
{
    string text = base.paramList["text"].Value;
    text = getVariablesFromMemory(text);
    output.WriteLine(text);
    return new PrintResult(text);
}
Teraz ta klasa mogła przyjąć dowolny obiekt typu TextWriter (który jest typem abstrakcyjnym). Wykorzystałem StreamWriter (który jest typem dziedziczonym po TextWriter). Jeden z konstruktorów StreamWriter przyjmuje klasę Stream poszedłem typ tropem i utworzyłem obiekty w następujący sposób:
using (var memoryStream = new MemoryStream())
{
    TextWriter memoryWriter = new StreamWriter(memoryStream);

    PrintMethod printMethod = new PrintMethod(text, memoryWriter);
    printMethod.Run();
    memoryWriter.Flush();
    //...
}
Teraz tylko potrzebowałem sposobu na odczyt tekstu który został zapisany do MemoryStream. Pomyślałem że zapis jest podobny jak zapis, więc utworzyłem obiekt StreamReader i wykonałem funkcję ReadLine():
string output;
using (var memoryStream = new MemoryStream())
{
//..
TextReader memoryReader = new StreamReader(memoryStream);
output = memoryReader.ReadLine();
}
Jednak za każdym razem string zwracany przez ReadLine() był pusty! Musiałem się użyć Google i dzięki StackOverflow.com otrzymałem odpowiedź.

Zapomniałem przesunąć wskaźnik będący w klasie MemoryStream, w sposób taki:
memoryStream.Position = 0;

I dzięki takim zabiegom mogłem się cieszyć działającymi testami jednostkowymi.

Podsumowanie, jeden test jednostkowy (wykorzystuje bibliotekę do tesów NUnit):
private static string printTextToMemory(string text)
{
    string output;
    using (var memoryStream = new MemoryStream())
    {
        TextWriter memoryWriter = new StreamWriter(memoryStream);

        PrintMethod printMethod = new PrintMethod(text, memoryWriter);
        printMethod.Run();
        memoryWriter.Flush();
        memoryStream.Position = 0;
        TextReader memoryReader = new StreamReader(memoryStream);

        output = memoryReader.ReadLine();
    }
    return output;
}
[Test]
public void WriteSimpleText()
{
    string output;
    output = printTextToMemory("Simple Text");
    Assert.AreEqual("Simple Text", output);
}
Enhanced by Zemanta

środa, 26 października 2011

Po prezentacji - NuGet

Wcześniej pisałem o przygotowaniach, teraz przyszedł moment na podsumowanie moich starań, wrażeń, doświadczeń.

Krótki opis prezentacji dla tych co nie uczestniczyli na mojej prezentacji. Prezentacja była podzielona na dwie części.

Slajdową, omówienie tematów:
  • Czym jest pakiet?
  • Czym jest menadżer pakietów?
  • Czym jest NuGet? (projekt open-source, różnice pomiędzy NuGet, a apt-get etc.)
  • Jak wygląda dodawanie pakietów dla ludzi nie robiących tego wcześniej (tzn dlaczego słuchacz powinienem uważać na prezentacji, oraz pokazanie, że NuGet'em potrafi zaoszczędzić czas)
Demo, tutaj pokazałem:
  • Instalowanie pakietów (z GUI i konsola)
  • Odinstalowanie pakietów (z GUI i konsola)
  • Aktualizowanie pakietów (z GUI i konsola)
  • Wspomnienie że można dodawać własne repozytoria
  • Pokazanie gdzie ściągnięte pakiety leżą.
Czas około 30 min.
Wrażenia
Po pierwsze chce zaznaczyć nie miałem dużego problemu z stresem. Nie zablokował mnie, chodź popełniłem parę błędów (o czym będzie później). Muszę powiedzieć że czas leci strasznie szybko.

Atmosfera była bardzo dobra, sądzę że rozluźniłem ludzi moją tapetą. Myślę, że możecie wyobrazić sobie zachowanie sali :)

Błędy oraz wnioski na przyszłość
Przygotowałem się dosyć solidnie do części slajdowej, gdzie cześć z demem nie poszła mi tak gładko.
Zapomniałem uruchomić Visual Studio z podniesionymi uprawnieniami (wtedy konsola NuGet nie chce mi działać), powiniem wtedy wtłumaczyć w czym polega błąd niż bez wyjaśnień zrestartować Visuala Studio.

Zabrakło mi analogowej kartki papieru z planem dema. Jeżeli bym taką kartkę sporządził bym sprawniej przechodził pomiędzy kolejnymi częściami dema.

Stres odbił się na mojej mowie, dziś bym starał się wolniej mówić i przesadnie uważać na dykcję.
Przyszłość
Jasne, że będę prowadził prelekcje. Dobrze się zmierzyć z publicznymi wystąpieniami. Takie doświadczenie na przyszłość.

Z ewentualnych tematów, o których chciałbym mówić znajduje się temat Visual Studio (obsługa, tips and tricks) oraz tematy związane z web developing takie jak javascript.

Jakieś sugestie?