Satranç – Retrograde (Çözüm)

diagram

Bu pozisyon siyahın son hamlesinden sonra meydana geldiğine göre siyah şah bir önceki hamlede a7 karesinde olmalıdır. Beyaz şah yüzünden b7 karesinden a8 karesine gelmiş olamaz. Peki siyah şah a7 karesindeyken beyazın hamlesi ne olmuş olabilir?

Beyaz şahı oynamış olamaz, g1 karesindeki fil şahı tehdit ederken başka bir taşı hareket ettirmiş olamaz. h2 karesindeki piyon da oynamış olamaz. Beyaz fil de hareket etmiş olamaz, çünkü hareket edebileceği tek diyagonalin bütün kareleri siyah şahı tehdit ediyor olurdu. Demek ki beyaz son hamlesinde açarak şah çekmiş ve siyah da son hamlesinde bu taşı almış, çünkü bu taş artık tahtada değil. a7-g1 dıyagonali üzerinde olup bir hamlede a8 karesine gelebilecek tek taş b6 karesindeki beyaz attır. Demek ki son hamleler şöyleydi:

1. Aa8    Şa8

Başka bir satranç sorusu (Çözüm)

Beyaz oynar ve 1 hamlede mat eder.
Beyaz oynar ve 1 hamlede mat eder.

Bu pozisyonda beyazın mat edebilmesi için şah çekmesi lazım. Şah çekebilmesinin tek yolu da piyonu sekizinci sıraya çıkarması fakat piyon hangi taşa dönüşürse dönüşsün siyah şah onu alabilir ve mat önlenebilir gibi gözüküyor.

İngiltere Satranç Birliği’nin 1862 kurallarından XIII numaralı kurala göre son sıraya erişen piyon istenilen bir taşa çevrilebiliyordu. Piyon olarak kalabiliyordu ya da bu problemin çözümünde olduğu gibi başka bir renkteki taş da olabiliyordu.

Soruyu bu kural doğrultusunda çözmeye kalkarsak

1. b8=A(siyah)

hamlesi sonucunda şahın kaçabileceği tek kareyi kendi renginde bir at ile kullanılamaz bir hale getirebiliriz. Böylece siyah mat olur.

Biraz da satranç (Çözüm)

Beyaz oynar iki hamlede mat eder.
Beyaz oynar iki hamlede mat eder.

Beyaz piyon 8. sıraya ulaşıp da vezir olursa siyah şah g2 noktasına kaçarak matı önler.

1. e8=V    Şg2

2. Ve2      Şh1

 

ya da

1. e8=V    Şg2

2. Ve4+     de

İlginç bir şekilde piyonun kale yapılması 1972 yılında iki hamlede matı sağlıyordu.

1. e8=K    Şg2

2. 0-0-0-0-0-0!#

Evet ikinci hamle 1972 yılından beri kurallara aykırı bir rok hamlesi. 1972 yılına kadar rok yapmak için rok yapacak kalenin ve şahın daha önce oynamamış olmasını, şahın bulunduğu yada rok sırasında geçeceği karelerin rakip kontrolü altında olmamasını gerektiriyordu. Fakat kurala göre şah ve kalenin aynı yatayda olma zorunluluğu yoktu. Tabii ki bu kurallar konurken gözden kaçan bir durumdu, o zamana kadar bu kimsenin aklına gelmemişti. Max Pam bu imkanı ortaya attığında Tim Krabbe de yukarıdaki problemi hazırladı. Bunun üzerine 1972 yılında FIDE (satranç federasyonu) kurala küçük bir ek yaparak şah ile kalenin aynı yatayda olması şartını getirdi.

Not:

Tabii ki böyle bir hamle öngörülmediği için standard bir notasyonu da yok. Bazı kaynaklarda sadece 0-0-0-0 hamlesi olarak da kullanılıyor.

 

Julia kümesi

Mandelbrot kümesini bir çok insan duymuştur. Hani şeklin içine girdikçe büyük şeklin sonsuz tekrarıyla karşılaştığımız fraktal dizaynlar. Konunun matematiğine dalmayacağım, yani çok dalmayacağım. Sonuçta çoğu insan için bu şekilleri anlaşılır bir şekilde üretmenin yolunu javascript yardımıyla göstereceğim.

Öncelikle Julia kümesiyle başlayacağım. Mandelbrot kümesi başka bir yazının konusu olacak. Algoritmik olarak arada çok az bir fark olmasına rağmen matematiksel olarak farklı kümeler bunlar. Olay kompleks düzlemde geçmektedir. Hani kompleks sayılarla oluşturulan düzlem. Kompleks saylar deyince akla tabii ki meşhur \(i=\sqrt{-1}\) tanımı gelir.

Bu kompleks sayıların bir reel bir de sanal kısmı vardır. Yani verilen bir \(z \) kompleks sayısını \(z=a+ib \) şeklinde yazabiliriz. Burada \(a \) ve \(b \) sayıları bildiğimiz reel sayılardır. Aslında bu noktadan itibaren bu kompleks sayıları xy-koordinat sistemindeki noktalar gibi düşünebiliriz. \(a \) sayısı noktanın x koordinatını, \(b \) sayısı da noktanın y koordinatını göstersin. 

Şimdi algoritmamızda verilen bir \(z \) kompleks sayısını (ya da düzlemdeki noktasını) nasıl dönüştüreceğimize bakalım. 

\(f(z) = z^2 + c \)

Burada \(c \) sayısı da kompleks bir sayıdır. Bilmeyenler için kısaca yukarıdaki işlemi reel ve sanal kısımlar cinsinden yazacağım.

\(z = a + i b \) ve \(c = d + i e \) olsun.

\(z^2 = z \cdot z = {a \cdot a – b \cdot b} + i {2 \cdot a \cdot b} \)

\(z^2 + c= {a \cdot a – b \cdot b + d} + i {2 \cdot a \cdot b + e} \)

Şimdi hesap kısmını hallettiğimize göre yaptığımız dönüşümü indeksleyelim, yani her adımda bulduğumuz kompleks sayıya bir sıra numarası verelim.

\(z_{n+1} = z_n^2 + c \)    (1)

Hesapladığımız toplamı bir sonraki adımda yeni kompleks sayı olarak kullanacağız. Her adımda bu kompleks sayının belli bir alanın dışına çıkıp çıkmadığına bakacağız. Bunun için de bu sayının orijine uzaklığını hesaplayacağız.

\(\lvert z \rvert = a \cdot a + b \cdot b \)    (2)

Eğer bu nokta yarıçapı 2 olan dairenin dışındaysa sayının o adımdaki indeks numarasını alacağız ve başlangıçtaki noktamızı bu indekse göre ürettiğimiz bir renkle koordinat sistemimizde işaretleyeceğiz. Bu dönüşümler sırasında bazı başlangıç sayıları her zaman bu dairenin içinde kalabilir. Bu durumda programın devam etmesi için maksimum adım sayısı tanımlayacağız. En basit renklendirme olarak eğer maksimum adım sayısına ulaşılmışsa siyah, aksi durumda beyaz noktalar kullanılabilir.

Algoritma:

  1. \(c \) kompleks sayısı belirlenir. Bu sayı rastgele de seçilebilir ama her değer için güzel şekiller ortaya çıkmıyor.
  2. Çizim yapılacak ekranın her noktası için: Seçilen nokta bir \(z_0 \) kompleks sayısına dönüştürülür.
  3. Her adımda elde edilen kompleks sayı yarı çapı 2 olan dairenin dışına düşmediği ve maksimum adım sayısına erişilmediği sürece (1) numaralı dönüşüm uygulanır.
  4. Seçilmiş nokta için elde edilen adım sayısına göre bir renk üretilir.
  5. Seçilmiş nokta ekran üzerinde bu renge boyanır.

Örnek:

1. \(c=-0.5 + 0.5 i \) olsun.

2. Ekranımız 400 satır ve 400 sütundan oluşsun. Ekranın orta noktası düzlemimizin orijini olsun ve sol üst köşe koordinat sisteminde (-2, 2) noktası, sağ üst köşe (2, 2) noktası, sol alt köşe (-2, -2) noktası ve son olarak da sağ alt köşe (2, -2) noktası olsun. Şimdi ekran piksel konumlarını bu koordinatlara gönderen dönüşümü hazırlayalım.

Ekran  koordinatlarına x ve y diyelim.

\(z = a + bi\longrightarrow{a=\frac{x – 200}{100},b=\frac{y – 200}{100}} \)

Burada ekran noktası olarak x = 225 ve y = 350 alalım. Bu değerleri yukarıdaki dönüşüme koyarsak

\(z_0 =\frac{225 – 200}{100}+\frac{350 – 200}{100}i=0.25+1.5i \) kompleks sayısını buluruz.

3. (1) numaralı dönüşümü uygulamaya başlayalım.

\(z_1=z_0^2-0.5+0.5i=(0.25 + 1.5i)\cdot (0.25+1.5i)-0.5+0.5i \)

\(z_1=0.625-2.25-0.5+(0.75+0.5)i=-2.125+1.25i \)

\(\lvert z_1 \rvert = \sqrt{2.125^2 + 1.25^2}=\sqrt{6.078125}=2.46 \)

demek ki seçtiğimiz nokta daha ilk adımda yarıçapı 2 olan dairenin dışına çıkıyor. Bu durumda adım sayısı 1 oluyor ve bu nokta için 1 indeksli rengi kullanıyoruz. İşin görsel kısmı tamamen bu renk seçimine bağlı. İlk denemelerde oldukça basit bir renk şeması seçtim. Eğer maksimum adım sayısına erişilmişse siyah, aksi durumda beyaz noktalar kullandım. Bu bile yeterli aslında ama sonra daha renkli şekiller oluşturmak için HSV renk uzayını denedim.

Aşağıdaki linkte yazdığım javascript uygulamasını deneyebilirsiniz.

yilmazaksoy.com/apps/Julia.html

Reel(c) ve Sanal(c) parametrelerine istenilen değerleri verdikten sonra Başlat düğmesine basarak şeklin oluşmasını bekleyebilirsiniz. Eğer sisteminizde şeklin ortaya çıkması çok uzun sürüyorsa adım sayısını azaltabilirsiniz. Bu durumda program daha hızlanacaktır ama çıkan sonuçta daha az renk kullanılacaktır.

Örneğin Reel(c) = -0.7 ve Sanal(c) 0.25 için aşağıdaki şekil elde edilebilir.

Download (1)

Program:

Kullanıcı girdileri ve çizimin yapılacağı alanı tanımlamak için aşağıdaki gibi bir blok kullandım. Basit bir uygulama olduğundan hiç CSS de kullanmadım.

[code language=”html”]

<div id=”first”>
Adım sayısı: <input id=”maxIterations” type=”number”step=”1″/>
</div>
<div id=”last”>Reel (c): <input id=”c_real” type=”number”step=”any”/>
Sanal (c):<input id=”c_imaginary” type=”number”step=”any”/>
<button id=”start” onclick=”startDrawing()”>Başlat</button>
</div>
<canvas id=”drawingArea” width=”400″ height=”400″ style=”border:1px solid #000000;”></canvas>

[/code]

Bu giriş elemanlarına ilk değerlerini atamak için sayfa yüklendiğinde init adlı fonksiyon çağrılıyor.

[code language=”javascript”]
<body onload=”init()”>
<script>
var c_real = 0.0;
var c_imaginary = 0.0;
var maxIterations = 300;
function init() {
document.getElementById(“maxIterations”).value = ‘300’;
document.getElementById(“c_real”).value = ‘0’;
document.getElementById(“c_imaginary”).value = ‘0’;
}

</script>
[/code]

Başlat düğmesine basıldığında startDrawing() adlı fonksiyon çağrılıyor:

[code language=”javascript”]

function startDrawing() {
c_real = parseFloat(document.getElementById(“c_real”).value);
c_imaginary = parseFloat(document.getElementById(“c_imaginary”).value);
maxIterations = parseInt(document.getElementById(“maxIterations”).value);
var canvas = document.getElementById(“drawingArea”);
var width = canvas.width;
var height = canvas.height;
var i = 0;
var j = 0;
for ( i = 0; i < width; ++i) {
for ( j = 0; j < height; ++j) {
var value = calculatePoint(i, j, width, height);
var numberOfIterations = checkPoint(value, [c_real, c_imaginary], maxIterations, 4);
plotPoint(i, j, numberOfIterations);
}
}
var img = canvas.toDataURL(“image/png”);
document.write(‘<img src=”‘ + img +'”/>’);
}

[/code]

İlk önce c_real, c_imaginary ve maxIterations değişkenleri kullanıcı girdilerinden okunuyor. İlk iki değer reel sayı, adım sayısı ise tam sayı olduğundan parseFloat ve parseInt fonksiyonları yardımıyla değerler doğru tiplere dönüştürülüyor. Ardından çizim alanımız olan canvas değişkeni okunuyor ve bu alanın satır ve sütun sayısı elde ediliyor. Sonra içiçe döngüyle bu çizim alanının bütün noktaları işleniyor. calculatePoint fonksiyonu ile bulunduğumuz satır ve sütundaki ekran noktası için bir kompleks sayı üretiyoruz. checkPoint() fonksiyonu ile bu kompleks sayının kaç adımda yarıçapı 2 olan dairenin dışına çıktığını kontrol ediyoruz. Son olarak da elde ettiğimiz adım sayısını kullanarak bu noktanın rengini belirliyoruz ve noktayı çiziyoruz.

[code language=”javascript”]
var img = canvas.toDataURL(“image/png”);
document.write(‘<img src=”‘ + img +'”/>’);
[/code]

Bu son iki satır ile canvas’ın içindeki şekli HTML dökümanının içine tekrar yazıyorum ki kullanıcı şekli isterse kaydedebilsin. Normalde masaüstü tarayıcıları bu satırlar olmadan da canvas’ın içeriğini kaydedebiliyor ama akıllı telefonlar ve tabletlerde bu her zaman mümkün değil anladığım kadarıyla.

[code language=”javascript”]
function calculatePoint(x, y, width, height) {
var real = (x – (width / 2)) * 4.0 / width;
var imaginary = (y – (height / 2)) * 4.0 / height;
return [real, imaginary];
}
[/code]

Bu fonksiyon ekran koordinatlarını x ve y koordinatları -2 ve 2 arasındaki reel sayılar olacak şekilde yeni noktalara çeviriyor.

[code language=”javascript”]
function checkPoint(z, c, maxIterations, radius) {
var i = 0;
var p = z;
for ( i = 0; i < maxIterations; ++i) {
p = calculateNewValue(p, c);
if (!isPointInCircle(p, radius)) {
return i;
}
}
return i;
}
[/code]

Bu fonksiyon elimizdeki kompleks sayının kaç adımda dairenin dışına çıktığını buluyor. Tabii ki adım sayısı maksimum adım sayısını geçerse aramayı kesiyoruz. Her adımda bir sonraki kompleks sayıyı üretiyoruz (calculateNewValue) ve noktayı kontrol ediyoruz (isPointInCircle).

[code language=”javascript”]
function calculateNewValue(z, c) {
var realPart = z[0] * z[0] – z[1] * z[1] + c[0];
var imaginaryPart = 2 * z[0] * z[1] + c[1];
return [realPart, imaginaryPart];
}
[/code]

Bu fonksiyon da \(z_{n+1} = z_n^2 + c\) dönüşümünü uyguluyor. Burada kompleks sayıları iki elemanlı javascript dizileri olarak tanımladım (z ve c değişkenleri) bu nedenle [] index operatörü ile reel ve sanal kısımlarına erişebiliyoruz ve aynı şekilde iki elemanlı bir javascript dizisi geri döndürüyoruz.

[code language=”javascript”]
function isPointInCircle(z, radius) {
var norm = z[0] * z[0] + z[1] * z[1];
if (norm < radius) {
return true;
}
return false;
}
[/code]

Bu fonksiyonda aslında normu yukarıda tanımladığım gibi kullanmadım. Karekökü almadım, yerine yarıçapı 2 değil de karesi olan 4 olarak kullandım. Bu şekilde oldukça yavaş olan karekök işlemini optimize etmiş olduk.

[code language=”javascript”]
function plotPoint(x, y, index) {
var c = document.getElementById(“drawingArea”);
var ctx = c.getContext(“2d”);
if (index < maxIterations) {
ctx.fillStyle = HSVtoRGB(index/Math.PI, 1.0, 1.0);
} else {
ctx.fillStyle = HSVtoRGB(index/Math.PI, 1.0, 0.0);
}
ctx.fillRect(x, y, 1, 1);
}
[/code]

Bu fonksiyon da adım sayısına göre noktayı rengiyle beraber çiziyor. Dikkat edilirse nokta yerine büyüklüğü 1 piksel olan dikdörtgen kullandım, javascript’te nokta çizme fonksiyonu yok. Bu istediğime yeterince yakın sonuçlar verdi ama. HSVtoRGB fonksiyonu da adım sayısından canvas’ta kullanılacak RGB renk kodunu üretiyor. Bu fonksiyonun kodunu aşağıdaki 2 numaralı kaynaktan aldım. Sadece son satırını aşağıdaki gibi değiştirdim:

[code language=”javascript”]
return “#” + d2h(Math.round(r * 255)) + d2h(Math.round(g * 255)) + d2h(Math.round(b * 255));
[/code]

Amacım renk kodunu #ff23ff şeklinde RGB formatında elde etmekti. He renk için iki karakter kullanmak gerektiğinden de yardımcı olarak d2h (onluk düzenden onaltılık düzene çevirme) adlı bir fonksiyon kullandım (Fonksiyonu 3 numaralı kaynakta buldum).

[code language=”javascript”]
function d2h(d) {
var s = (+d).toString(16);
if (s.length < 2) {
s = ‘0’ + s;
}
return s;
}
[/code]

Tüm program linkte açılan sayfanın kaynak kodundan alınabilir. Bütün javascript rutinleri de sayfanın içindedir.

Kaynaklar:

  1. http://lodev.org/cgtutor/juliamandelbrot.html
  2. http://stackoverflow.com/questions/17242144/javascript-convert-hsb-hsv-color-to-rgb-accurately
  3. http://stackoverflow.com/questions/17204335/convert-decimal-to-hex-missing-padded-0