GNU/Stow bir süredir bildiğim fakat bir türlü deneme fırsatı bulamadığım çok basit bir paket veya sembolik link yöneticisi. Her ne kadar /usr/local içerisindeki linkleri yönetmek için düşünülmüş olsa da, esnek yapısı nedeniyle kullanım alanlarından biri de ev dizininde bulunan yapılandırma dosyalarını (yani nokta dosyaları ya da dotfiles) yönetmek.

Örneğin ~/dotfiles içerisinde x ve zsh adında iki dizininiz var. Bu dizinler stow için aslında birer paket ve diyelim bu paketlerin yapısı şu şekilde:

~/dotfiles
├── x
│   ├── .i3
│   │   └── config
│   ├── .Xdefaults
│   ├── .xsession
│   └── ...
└── zsh
    ├── .zlogin -> .zprezto/runcoms/zlogin
    ├── .zlogout -> .zprezto/runcoms/zlogout
    ├── .zprezto
    │   └── ...
    ├── .zpreztorc -> .zprezto/runcoms/zpreztorc
    ├── .zprofile -> .zprezto/runcoms/zprofile
    ├── .zshenv -> .zprezto/runcoms/zshenv
    └── .zshrc -> .zprezto/runcoms/zshrc

Eğer kullandığınız ve herhangi bir x ortamı bulunmayan bir sunucuda, sadece zsh ayarlarınızı kullanmak isterseniz stow zsh dediğinizde, stow sizin için sadece zsh dizini altında bulunan dosyalar ve dizinlerin ev dizininde yer alan gerekli linklerini oluşturacaktır. Bu şekilde yapılandırma dosyalarınızı paketlere bölerek, istediğiniz yapılandırmayı istediğiniz makinada rahatça kullanmanızı sağlıyor.

Bir başka örnek kullandığım yapılandırma dosyalarım verilebilir. gitin sağladığı dağıtık model ile her zaman tüm makineler arası senkronize olan bu dosyalar, stow ile de sadece gerekli makinede gerekli uygulamaları yapılandırmak için kullanılabiliyor.

PHP

PHP’nin neresinin kötü olduğunu söyleyemem bile, çünkü… Düşünün bir alet kutunuz var. Bir takım araçlardan oluşuyor. Standart şeyler var içerisinde, normal gözüküyor.

İçerisinden bir tornavida çıkardınız ve bir bakıyorsunuz garip 3 kafalı vidalar için kullanılan şeylerden biri. Tamam, peki bu sizin işinize yaramayabilir, fakat ileride işe yarayabileceğini varsayıyorsunuz.

İçerisinden çekici çıkardınız, dehşete kapıldınız, iki ucu da tırnaklı. Fakat hâlâ iş görebilir, yani yan tutarak ortasındaki yüzey sayesinde çivi çakabilirsiniz.

İçerisinden penseyi çıkardınız, fakat ucu tırtırlı değil dümdüz. Daha az kullanışlı ama yine de civataları döndürmek için yeterli, yani herneyse.

Devam ediyorsunuz. Kutuda ki her şey bir garip ve değişik, tamamen işe yaramaz diyecek kadar değiller. Üstelik kutunuz da her şey var.

Şimdi düşünün sizinkiyle aynı aletleri kullanan milyonlarca marangozla tanıştınız ve size “Bu aletlerin sorunu ne? Hepsi kullandığım şeyler ve çalışıyorlar!” diyorlar. Ardından marangozlar size yaptığı evi gösteriyor, her oda beşgen ve çatı ters. Giriş kapısını çalıyorsunuz kapı içeri devriliyor ve hepsi sana kapılarını kırdınız diye bağırıyor.

İşte PHP’nin burası kötü.1


PHP tutarsızdır ve öngörülemez

Her C ailesi dilinde yer alan == operatörü, PHP’de tam anlamıyla patır patır dökülmektedir. == her şeyi sayıya çevirmeye çalışır. Ama bunu yaparken bile saçmalar:

Örnek 1:

<?php

if ("6 portakal" + "4 elma" == "10 armut") {
    echo "Çok dogru!";
} else {
    echo "Hayır olamaz!";
}

Çıktı 1:

Çok dogru!

Örnek 2:

<?php
var_dump(123 == "123foo");
var_dump("123" != "123foo");

Çıktı 2:

bool(true)
bool(true)

Killer Örnek 3:

<?php
var_dump(md5('240610708') == md5('QNKCDZO'));
var_dump(md5('aabg7XSs') == md5('aabC9RqS'));
var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));
var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m'));
var_dump('0010e2' == '1e3');
var_dump('0x1234Ab' == '1193131');
var_dump('0xABCdef' == '     0xABCdef');

Killer Çıktı 3:

bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)

Bunun yerine PHP’de C apisini kullanan ve kendi standartı olan tip kontrolü de yapan === operatörü vardır. Ama < ve > operatörlerinin bir alternatifi yoktur. Aynı zamanda switch de == kullanır.

Örnek 4:

<?php
$option = 2;

switch($option) {
  case "2 belli ki doğru seçenek değil";
    echo "İlk seçenek seçildi!";
    break;
  case 2:
    echo "İkinci seçenek seçildi!";
    break;
}

Çıktı 4:

İlk şecenek seçildi!

Eğer geliştirici dikkatsizlikten dolayı veya daha önceki alışkanlıklarından dolayı === yerine == kullanırsa, ruhunu ve kaderini PHP’ye teslim etmiş olur.


PHP’de aynı perl’de ki gibi false, "" ve 0 olmayan her şey true dir. Ama PHP’de "foo" == 0 da "0" == 0 da true dir. 0 da false dir (beyin eridi).

Örnek 5::

<?php
var_dump("foo" == TRUE);
var_dump("foo" == 0);
var_dump(TRUE != 0);

Çıktı 5:

bool(true)
bool(true)
bool(true)

== operatörü beyin yakan tablolar oluşturulmasına vesile olmuştur.


Dil tutarlılığı, geliştirici verimliliği için çok önemlidir. Her bir tutarsızlık geliştiricinin hatırlaması gereken yeni bir özellik, dökümantasyonu okuma gerekliliği veya konsantrasyon kaybına neden olur. PHP standart kütüphanesinde bazı fonksiyonlarda _ vardır bazılarında yoktur, bazılarnda to kullanılmıştır bazılarında 2. PHP standart kütüphanesinde yer alan fonksiyon isimlerindeki tutarsızlıklar saymakla bitmez, bunlardan bazıları:

Örnek 6: Alt-cizgi kullanan fonksiyonlar:

get: gettype get_class
str: str_ireplace str_pad str_repeat str_replace str_shuffle str_split str_word_count strcasecmp strchr strcmp strcoll strcspn
encode: base64_encode quoted_printable_encode session_encode rawurlencode urlencode gzencode
php: php_uname php_sapi_name php_logo_guid phpinfo phpcredits phpversion
htmlentites: htmlentities html_entity_decode[/code]

Örnek 7: to ve 2 kullanan fonksiyonlar:

to: stream_copy_to_stream strtolower strtotime strtoupper unixtojd
2: bin2hex deg2rad hex2bin ip2long long2ip nl2br rad2deg

PHP evrendeki tek sol çağrışımlı ternary operatörüne sahiptir

Horse

Örnek 8:

$ perl -le 'print 1 ? 2 : 3 ? 4 : 5'
2
$ ruby -e 'print 1 ? 2 : 3 ? 4 : 5'
2
$ php -r 'print 1 ? 2 : 3 ? 4 : 5;'
4

PHP geliştiricileri…

Buna ben de katıla katıla gülmekten başka bir şey yazamıyorum. Rasmus (PHP dilinin yaratıcısı)’un da fonksiyon adlarını seçerken bir dahi gibi düşündüğünü görebilirsiniz.

Diğer dillerde yer alan strtotime implementasyonları, 00-00-00’a hata döner. Fakat bu PHP’de normal bir tarihtir, aynı zamanda 2000-00-00’a eşittir, o da aynı zamanda 1999-12-00’a eşittir o da aynı zamanda 1999-11-30’a eşittir ve bu da aynı zamanda birer dahi olan PHP geliştiricilerine göre: No bug, perfectly normal.

PHP geliştiricileri fonksiyon adı seçiminde çok iyidir. parse_str fonksiyonu URL sorgusunda yer alan anahtar ve değerleri döner.


PHP parseri buglarla doludur

PHP kendi standartlarını da yoksayar. Örneğin her dilde olduğu gibi PHP’de de || operatörünün = operatörüne göre işlem önceliği vardır. Hiç bir dilde: a || a = 1; yapamazsınız. Ama PHP’de yapabilirsiniz.

|| operatörü çalışır. Aslında çalışmaz da. Örneğin 4 || 5, 1 (true) döner, 0 || 6 da 1 (true) döner. Gerzekçe olmayan her dilde || operatörü sol değeri döner ve insanlar || operatörünü varsayılan değer atamak için kullanırken PHP’de $foo = $bar || "varsayılan değer"; yapılamaz.

Parser buglarına başka bir örnek 8 tabanındaki sayılar için verilebilir. Örneğin 8 tabanında yazılan 08 her dilde hatalıdır. Elbette PHP hariç:

Örnek 9:

$ perl -le 'print 07'
7
$ perl -le 'print 08'
Illegal octal digit '8' at -e line 1, at end of line
Execution of -e aborted due to compilation errors.

$ python -c 'print 07'
7
$ python -c 'print 08'
  File "", line 1
    print 08
           ^
SyntaxError: invalid token

$ php -r 'print 07;'
7
$ php -r 'print 08;'
0

Üstelik en ukalâ (pedantic) hata raporunu açsanız dahi sizi hiç uyarmaz:

<?php
error_reporting(E_ALL);
eval("print 028;");  # hiç bir uyarı olmadan 2 yazar

Diğer irili ufaklı özellikleri:

  • PHP geliştiricileri bazen kendilerine sorarlar. Neden bir arrayı sıralamak için 13 farklı fonksiyona ihtiyaç duyulmuş? PHP içerisinde sadece 2019 dahili fonksiyon vardır. PHP bir dilden çok, rastgele katılmış fonksiyon ve sözcüklerin patlamış halidir.
  • include ve saz arkadaşları, C de yer alan #include dir. Standart bir modül sistemi yoktur.
  • PHP’nin temelinde thread safe bir fonksiyon yoktur. 2015 yılında ne threadları ne de fork’u destekler
  • Threadlar gibi unicode desteği de yoktur.
  • Birer dahi olan PHP geliştiricileri, yeni bir PHP sürümünü unit testleri çalıştırmayı akıl etmeden de çıkarabilirler. (PHP 5.3.7 bir unit testi olmasına ve bu testi geçememesine rağmen linkteki hata ile yayımlanmıştır.) Başka bir örnek: Test Failures: 111 Build Status: OK. Ama unutmayın perfectly normal.
  • root yetkisine sahip bir VPS’e mi ihtiyacınız var? Github’dan bir tane bedavaya bulabilirsiniz.
  • İngilizce’de last kelimesi son demektir. PHP’de last kelimesi son, lAst kelimesi son ama Last kelimesi ilk demektir. Aklıma geldikçe gülüyorum.
  • feof() fonksiyonu eğer dosya işaretcisi EOF ise veya bir hata olursa TRUE döner, diğer haller için FALSE –sadece bir hatadan başka bir hata daha olursa FALSE döner.
  • htmlentities() bir hatayı sadece hata raporu gösterme kapalıyken gösterir.
  • PHP topluluğu en çok küfür eden topluluktur.

Zamanında rast gelince gülüp not aldıklarım bunlar. Sonuçta PHP, geliştiriciler arasında birbirlerini trollemek için yaygın olarak kullanılan bir araç.

Bonus:

Hadouken

i3 modern bir döşeme pencere yöneticisidir (tiling window manager). Başıma gelen en güzel şey ne diye sorsalar, i3 derim heralde. Peki nedir i3’ü benim için bu kadar çekici kılan ona bakalım.

i3 kullandığım ilk tiling window manager. Gelişmiş kullanıcılar (power users) için hazırlanmış bu pencere yöneticisi, pencereleri ekranınızda hiç boşluk kalmayacak şekilde döşüyor. Bu da size, özellikle her işinizi klavyeden yapmaya alışkınsanız inanılmaz bir verimlilik sağlıyor.

Gündelik kullandığım örnek bir masaüstüm aşağıda yer alıyor:

i3 screenshot 01

Gördüğünüz gibi i3 monitörümdeki tüm alanı en verimli şekilde kullanmamı sağlıyor. Herşey klavyeden kontrol edildiğinden (isterseniz mouse ile de kontrol edebilirsiniz); başlık çubuğu ve pencere yönetim düğmeleri (simge durumuna getirme, tam ekran vs.) bulunmamakta.

i3 pencereleri yatay ve dikey döşemenin yanında, yığın ve sekme olarak da döşeyebiliyor. Bu da size iç içe geçmiş kullanılabilir sınırsız sayıda pencere oluşturabilme imkânı tanıyor.

i3 screenshot 02

Yukarıdaki örnek çalışma alanında görebildiğiniz gibi, pencereleri istediğiniz gibi açalabilirsiniz. Sağ tarafta 2 sekme altında açılmış 3 sekme ve 3. sekmede açılmış yine onlarca terminal penceresi yer alıyor. Bu resmi sekmeli kısımdan ikiye ayırıp bakacak olursak, sağ tarafta aslında yepyeni bir masaüstü kullandığımızı bile düşünebiliriz. Pencereleri nasıl döşeyeceğinize karar vermek hayal gücünüze kalmış.

i3 aynı zamanda sınırsız sayıda çalışma ortamı (workspace) oluşturmaya da imkân tanıyor. Yeni çalışma ortamı geçis yaptığınızda oluşturuluyor ve eğer içerisinde bir pencere varsa hayatta kalıyor.

i3 pencere eylemlerini gerçekleştirmek için JSON tabanlı IPC arabirimi kullanıyor. Yani bir örnek ile açıklamak gerekirse, siz bir pencereyi sola taşımak için (benim kullandığım) $mod+Shift+j tuş kombinasyonunu kullandığınızda aslında i3 pencere yöneticisine move left mesajını göndermiş oluyorsunuz. Bu yapı da size inanılmaz bir özelleştirme imkanı tanıyor. Pencere yöneticinizi istediğiniz programlama diliyle istediğiniz gibi kontrol edebilirsiniz.

i3 aynı zamanda vi gibi farklı modları da destekliyor. Örneğin vi de komut modundayken tuşlar farklı eylemler gerçekleştirirken INSERT veya VISUAL modlarında farklı eylemler gerçekleştiriyor. Aynı şey i3 için de sağlanmış. Normalde pencereler arası geçis yapmak için kullandığınız HJKL tuş takımını, $mod+r tuşlarına bastığınızda resize moduna girerek pencereleri yeniden boyutlandırmak için kullanabilirsiniz. Üstelik bu özelliklerin hepsi özelleştirilebilir, istediğiniz kadar farklı mod tanımlayabilir, istediğiniz tuşlarla farklı eylemleri gerçekleştirebilirsiniz. Ve tüm bu eylemler inanılmaz hızlı gerçekleşiyor. i3’ün şuanki sürümü 859kb ve gücünü C’den alıyor. Şuan çalışan masaüstü oturumum ise sadece 27mb bellek kullanıyor.

Durum çubuğu (i3status) da kendisi gibi verimli ve istediğiniz programlama dilini kullanarak istediğiniz modülü yazmanıza olanak tanıyor.

Özelleştirilmiş bir durum çubuğunu aşağıdaki ekran görüntüsünde görebilirsiniz:

i3 screenshot 05

Fare kullanmaya alışkınsanız, i3 pencereleri fare yardımıyla da daha verimli kullanmanız mümkün. Örneğin standart bir pencere yöneticisinde bir pencereye odaklanmak için, pencereye tıklamanız gerekirken, i3’de tüm pencereler zaten önde olduğundan, imleci pencerenin üzerine getirdiğinizde pencere aktif hale geliyor. Yine de eğer her işinizi fare ile yapmaya alıştıysanız i3 sizin için uygun olmayabilir.

Eğer her işinizi terminalden yapıyor ve terminalinizde screen veya tmux kullanmaya alışkınsanız, i3’ü çok gelişmiş bir terminal çoklayıcı olarak kullanabilirsiniz. Haydi ne bekliyorsunuz, hemen favori paket yöneticiniz ile i3 denemeye başlayın :) Tüm sorularınızı ayrıntılı cevaplandıran kullanıcı rehberine buradan ulaşabilirsiniz.

Son olarak bir kaç ekran görüntüsü daha:

i3 screenshot 03

Yazıyı hazırlarken chrome’a ihtiyaç duymadığımdan, hemen chrome penceresini sekmeler haline dönüştürüp, yeni bir sekmede vim ile bu yazıyı hazırladım. Diğer pencereler ise sürekli kontrol ettiğim pencereler olduğundan hepsi görüş alanım içerisinde.

Örnek bir geliştirme ortamı:

i3 screenshot 04

Masaüstünüzün büyük bir bölümüyle kod geliştirken, hemen sağda test edebilir git işlemlerinizi gerçekleştirebilirsiniz. Bu sadece çok basit bir örnek (git blame kullanımı çok yersiz olmuş farkındayım), daha önce de dediğim gibi i3 her türlü kullanım alanında size verimlilik sağlayacaktır.

Bir arkadaşınızın SSH sunucusuna bağlanmak istiyorsunuz fakat arkadaşınız bir NAT arkasında (modem vb) veya güvenlik duvarı arkadaşınıza bağlanmanıza izin vermiyor. SSH Reverse Tunneling tam da aradığınız şey!

SSH Reverse Tunnel ile arkadaşınız, sizin SSH sunucunuza bağlanabilir ve oluşturacağı tünel ile herhangi bir portunu sizin sunucunuzda kullanılabilir hale getirebilir.

Bu tür bir tünel oluşturabilmek için yapmanız gerekenler şunlardır:

  1. Öncelikle arkadaşınızın sizin makinenize bağlanmasını sağlamalısınız. Bunun için de sizin SSH sunucunuzun dışarıdan ulaşılabilir olması gerekmekte. adduser ile makinanızda arkadaşınıza bir kullanıcı oluşturun.

  2. Ardından arkadaşınızın, sizin makinanıza şu komutla giriş yapmasını sağlayın:

     ssh -R 14443:localhost:22 kullaniciadi@ip-adresiniz
    

    Arkadaşınız giriş yaptığında, sizin makinanızda açılacak olan 14443 numaralı port, arkadaşınızın makinasının 22 numaralı portuna yönlendirilecektir. 22 numaralı port SSH portudur, isterseniz farklı bir portu da yönlendirebilirsiniz. 14443 yerine herhangi bir port numarası tercih edebilirsiniz, fakat unutmayın ki 1024 den küçük portlar için root yetkisi gerekmektedir.

  3. Arkadaşınız sizin makinanıza başarılı bir şekilde giriş yaptıktan sonra, yönlendirmiş olduğu SSH portunu kullanmak ve arkadaşınızın makinasına giriş yapmak için şu komutu kullanın:

     ssh -p 14443 port arkadasinizinkullaniciadi@localhost
    

    Başarılı bir şekilde giriş yapın.

Bu özellik sayesinde NAT arkasında olan tüm makinelere bağlanabilirsiniz. Özellikle port yönlendirmesi yapamayacak olan makinelere bağlanmak için çok yararlı bir özellik ve GNU/Linux’de herşeyin mümkün olduğunu bir kere daha gösteriyor.

Bu yazı ilk olarak 2008-07-15 tarihinde yazılmış kaynak kodları kaybetmem üzerine 2015-10-02 tarihinte tekrar düzenlenmiştir.

Google code.jam‘i keşfetmem üzerine hemen kolları sıvadım. Code Jam, Google tarafından düzenlenen bir programlama yarışması. Verilen problemleri istediğiniz bir programlama dili kullanarak çözmeye çalışıyorsunuz. Yarışmanın ilk ayağı 16 Temmuz Çarşamba günü başlayacak. Üyelik ücretsiz. Profesyonelinden öğrencisine herkes yarışmaya katılabilir. Birinciye $10.000 ödül verilen yarışmada derece yapmanın Google’da bir iş bulabilmeye yarayacağını düşünüyorum.

Şu an için code.jam’da örnek problemler mevcut. Bu problemler yarışanların code.jam hakkında fikir sahibi olmalarını sağlıyor. Örnek problemler arasında yer alan ilk problem Alien Numbers. Diğer problemlere göre kolay olan bu probleme bende bir çözüm üretmeyi başarabildim.

Uzaylı Sayıları

Bu problem yeni bir sayı sistemi yaratmak ile ilgili. Problem sizden verilen karakterlere göre 2 değişik sayı sistemi yaratmanızı ve bu sistemde geçen bir sayıyı, ikinci sayı sisteminde yer alan karşılığını vermenizi istiyor. Diğer problemlere göre kolay olan bu problemi Perl Rust ile yapmayı başardım. Size kısaca algoritmasından bahsedeyim.

Kullandığımı sayı sistemi 0123456789 rakamlarından oluşmakta. Problem bize verilen karakterlerden yeni bir sayı sistemi oluşturmamızı ve yine bu sayı sistemiyle yazılmış alien sayısını, hedef dil ile oluşturulmuş sayı sisteminde ki karşılığını bulmamızı istiyor. Verilenler şu şekilde:

alien_sayisi kaynak_dil hedef_dil

Problem sayfasında yer alan örneklere bakacak olursak; alien sayısı olarak 9, kaynak dil olarak 0123456789 ve hedef sayı sistemi olarak “oF8” karakterleri verilmiş. Öncelikle kaynak dili ele alalım. Kaynak dil şuan kullandığımız sayı sistemi ve oluşturulabilecek sayılar şu şekildedir: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12… Görüdüğünüz gibi 0’ı kullanmadık. Sayma sayıları 1 den başlamakta. Hedef dilimizde de böyle olmalı. Verilen alien sayısı 9 bu sayı sisteminin 9. sayısını oluşturmaktadır. İkinci sayı sistemine bakacak olursak bize “oF8” karakterleri verilmiş. Bu karakterler ile oluşturulacak sayılar şu şekilde olur: F, 8, Fo, FF, F8, 8o, 8F, 88, Foo, FoF… 9 sayısı kaynak dilimizde 9. sırada yer almaktaydı. Demekki 9 sayısının hedef dilimizde ki karşılığı, hedef dilimizde 9. sırada yer alan Foo.

Peki bunu programlama ile nasıl yapacağız?

Camel

Bu problemi programa dökmek için gerçek hayattaki gibi düşündüm (farklı çözümler üretenler de olmuş). Kullandığımız sayı sisteminde yer alan sayılar ile sonsuz miktarda sayı üretebiliyoruz. 0 1 2 3 4 5 6 7 8 9 ile saydıktan sonra 10 geliyor. Yani son sayıya geldiğimizde, eğer solunda bir sayı yoksa soluna bir ilk sayma sayımız ekleniyor ve ilk sayımız başa dönüyor. 17 18 19 20 şeklinde saydığımızda ise solda yer alan sayı, sayma sayılarımızın son sayısı olmadığından bir arttırılıyor. Yaptığım programın aynen bunu yapmasını sağladım. Öncelikle tüm sayıları bir *array*'a bölüp, daha sonra 1. sayıdan başlayarak artmasını sağladım. Arttır fonksiyonunu inceleyecek olursak...

Programı yıllar sonra tekrar Rust ile yazdım. Bu sefer ilkinden farklı bir algoritma kullanarak alien sayısını, verilen karakter dizesindeki karşılıklarıyla ondalık tabana çevirdim ve ardından hedef dil tabanına çevirerek, hedef dildeki rakam karşılıklarını buldum.

Problemdeki ilk örneği ele alalım:

Foo oF8 0123456789

oF8 rakamlarıyla yazılmış Foo alien sayısını, 0123456789 rakamlarını kullanarak yazmamızı istiyor. Bunun için öncelikle Foo sayısını 10 tabanında yazmayı deneyelim.

Foo sayısını oF8 rakamlarını kullanarak onluk sayı sistemine şöyle dönüştürebiliriz:

oF8 sadece 3 karakter olduğundan alien sayı dilimiz aynı zamanda 3 tabanında olmalıdır. Foo karakterleri yerine de index değerlerini kullanırsak, sayımızı tam anlamıyla onluk tabana çevirebiliriz.

Alien diliyle yazılmış Foo sayısı, onluk tabanda 9’a karşılık geliyor. Ardından hedef dile baktığımızda: 0123456789 zaten kullandığımız onluk sayı sisteminin rakamları. Alien diliyle yazılmış Foo, sayı sistemimizde 9’a eşit.

Diğer bir örneğe bakalım:

CODE O!CDE? A?JM!.

O!CDE? rakamlarıyla yazılmış CODE alien sayısını, A?JM!. rakamlarını kullanan başka bir alien sayı sistemiyle yazmamızı istiyor. Hemen O!CDE?‘u onluk tabana çevirelim. İlk alien sayı sistemi 6 karakter içerdiğinden, altılık tabanda olmalı:

Alien diliyle yazılmış CODE sayısının onluk tabandaki eşitini bulduk. Şimdi bu sayıyı A?JM! rakamlarını kullanan diğer bir alien diline çevirmemiz gerekli. Hedef dilimiz 6 rakamdan oluştuğundan, onluk tabanda yazılan sayımızı altılık tabana çevirirsek bulabiliriz. Onluk tabandan altılık tabana çevirme bildiğimiz gibi sayıyı 6’dan küçük olana kadar 6’ya bölüp, bölüm ve kalanları sağdan sola yazarak yapılıyor:

6'lık tabana çevirme

Bu da bize: sonucunu veriyor. Ama bizim kaynak dilimiz altılık sayı sisteminde olmasına rağmen 012345 rakamlarını yerine A?JM!. rakamlarından oluşuyor. Hedef dilimizdeki rakamları indexleyecek olursak:

012345
A?JM!.

2034’ü şöyle yazabiliriz:


Bu işlemi bilgisayara nasıl yaptırabiliriz ona bakalım:

use std::io;
use std::io::prelude::*;

// alien sayısı, kaynak dil sayı sisteminde (source) ile
// yazıldığında onluk tabanda karşılığını bulan fonksiyon
fn to_base_10(alien_number: &str, source: &str) -> usize {

    // n: onluk tabandaki karşılığı, bulmaya çalıştığımız değer
    // d: taban çarpanı, sayının basamak değerini bulmamız için
    //    gerekli çarpan her sayının sıfırıncı kuvveti 1
    //    olduğundan ilk değeri 1
    let (mut n, mut d) = (0, 1);

    // alien_number karakterlerine sondan başa doğru bakıyoruz
    // normalde bir sayıyı başka bir tabana çevirirken de
    // sondan başlayarak basamak değerlerini topluyoruz
    for c in alien_number.chars().rev() {

        // baktığımız alien karakterinin source
        // dizesi içerisindeki indexini buluyoruz.
        // bu index bizim onluk sayı sistemimizdeki rakama eşit
        // ve aynı zamanda sayı değeri
        let p = source.find(c).unwrap();

        // basamak değerini topluyoruz
        n += p * d;

        // basamak değeri çarpanımızın bir üssünü alıyoruz
        // source'da ne kadar karakter varsa, tabanımızda
        // bu olmalı
        d *= source.len();
    }

    n
}


// onluk tabandaki sayıyı, hedef dil tabanındaki sayıya
// dönüştürüp hedef dil ile yazılımını dönen fonksiyon
fn from_base_10(mut n: usize, target: &str) -> String {
    let mut string = String::new();

    // taban, hedef dildeki karakter sayısına eşit
    let b = target.len();

    // aynı yukarıdaki örnek gibi sayı tabandan büyük
    // olduğu sürece, sayıyı tabana bölmeye devam edeceğiz
    // tek şart son kalan'ı da almak için sıfırdan büyük
    // olduğu sürece bölmeye devam ediyoruz
    while n > 0 {

        // n % b ile bulduğumuz kalan'ın hedef alien dilindeki
        // karşılığını döneceğimiz string'e ekliyoruz
        string.push(target.chars().nth(n % b).unwrap());

        n /= b;
    }

    // sayıyı onluk tabandan başka bir tabana
    // çevirdiğimizde, kalanlan sağdan itibaren yazıldığından
    // son olarak strigimizi ters çevirip dönüyoruz
    string.chars().rev().collect()
}


fn main() {

    let stdin = io::stdin();

    for (i, line) in stdin.lock().lines().enumerate() {

        // ilk satır soru miktarını
        // içerdiğinden atlıyoruz
        if i == 0 { continue }

        let line = line.unwrap();

        // standart girdiden okuduğumuz string'i parçalıyoruz
        // vectorümüzün ilk değeri alien sayısını
        // ikinci değeri kaynak alien dilini
        // üçüncü değeri de hedef alien dilini tutuyor
        let v: Vec<&str> = line.split_whitespace().collect();

        let n = to_base_10(v[0], v[1]);
        let r = from_base_10(n, v[2]);

        println!("Case #{}: {}", i, r);
    }

}