Fikstür Oluşturma Algoritmasının En Basit Anlatımı

Fikstür algoritmasını kurarken bilmemiz gereken şeyler,

  • Takımlar bir kere mi eşleşecek, iki kere mi eşleşecek?
  • Toplam kaç takım var?
Bu iki soruya verdiğimiz cevaplar ile geri kalan tüm sorularımızın cevabını bulabiliyoruz.
  • Her turda kaç takım eşleşecek? => Toplam takım sayısını ikiye bölerek bulabiliriz.
  • Toplam kaç tur oynanacak? =>
    - Eğer takımlar bir kere eşleşecekse: Toplam takım sayısı eksi bir kez...
    - Eğer takımlar iki kere eşleşecekse: Toplam takım sayısı eksi bir çarpı iki kez...

Algoritmanın Yazılı Anlatımı

  1. Takımları bir dizi içerisinde alalım. [a, b, c, d]
  2. Takımların yerlerini rastgele değiştirelim. [c, a, b, d]
  3. Eğer ki dizinin içerisinde 3, 5, 7 gibi tek sayıda takım varsa, dizimize "Oynamayacak" adında bir takım daha ekleyelim.
    Bunu yapmamızın sebebi boşta kalacak olan takımın o tur oynamayacak olduğunu belirtmek sadece.
  4. Toplam tur sayısı kadar dönen bir döngü başlatıyoruz.
    Bu döngü benim anlatacağım algoritmaya göre takımlar bir kez eşleşecekmiş gibi kurgulanmalı. Çünkü bu döngünün içerisinde ihtiyaç duyduğumuzda takımları ikinci kez eşleyebileceğiz.
  5. Dizinin ilk indisindeki takım ile ikinci indisindeki takımı bir döngü vasıtasıyla eşleyip yeni bir dizide saklayalım.
    Örnek: takımları karıştırdıktan sonra elimizdeki lise [c, a, b, d] olmuştu.
    Eşleşen takımlar dizimiz de şuna benzemeli [c-a, b-d]
  6. Dizimizdeki elemanlardan birini sabit tutarak diğerlerinin yerlerini bir kaydıralım.
    Orijinal listemiz : [c, a, b, d] olmuştu, eğer ilk indisi sabit tutup geri kalanı bir indis değiştirirsem şöyle olur: [c, d, a, b] ve dizimiz bir kere daha karışmış olur.
  7. Eşleşen takımlar listemizi tekrar güncellersek şu şekilde olur : [c-a, b-d, c-d, a-b]
    Ancak takımlar iki kere eşlenecekse ikinci eşlemeyi önce tersten yapmalıyız [c-a, b-d, d-c, b-a] şeklinde olmalı.
  8. Toplam tur sayısı kadar döngümüz döndükçe (5. adımdan devam edin) takımlarımız bu şekilde birbiriyle eşleşmeye devam eder.

Algoritmanın Görsel Anlatımı

Algoritmanın içine gönderdiğimiz ilk liste bu olsun;

Gelen dizide 4 eleman var. 4 tek bir rakam değil. Devam edebiliriz. (örneğin 3 eleman gelmiş olsaydı en sona "oynamayacak" takımını ekleyecektik.)

Şimdi elemanları bir defalığına rastgele karıştıralım. Bunun için kendi algoritmanızı da yazabilirsiniz veya kullandığınız dilin kütüphanelerinden faydalanabilirsiniz.

Artık orijinal dizimiz şu olacak;
ve artık bir döngünün içerisinde algoritmamız çalışmaya devam ediyor.

Artık ilk eşleşmemizi "eşleşmeler" adındaki listemize yazmaya başlayalım;
Bundan sonrası asıl kilit noktamız diyebiliriz. Geçici bir dizi ile orijinal dizimizdeki elemanları kaydırarak eşleşmeleri devam ettiriyoruz.
Döngümüz bu adıma geldiğinde her zaman geçici olan liste boş olmalı.

Ardından tek yapmamız gereken, ilk elemanı sabit tutmak ve geri kalan elemanları geçici dizimiz yardımıyla bir birim kaydırmak. Tıpkı aşağıdaki gibi;

Burada devam etmeden önce takımları ikişer kez eşleyeceksek orijinal dizimizdeki veya geçici listemizdeki elemanları önce 1. sonra 2. eleman şeklinde değil de tam tersi şekilde eşlememiz gerekiyor.

Ardından geçici dizimizi orijinal dizimize eşitledikten sonra geçici dizimizi tekrardan boşaltıyoruz.

Artık orijinal dizimiz şu oldu;

Buradan itibaren döngümüz toplam tur sayısı kadar başa sararak aynı işlemleri yapmaya devam ediyor.

Algoritmanın Java ile Kodlanması

Fikstür algoritmasının kendi yazdığım java kodlarına erişmek için GitHub bağlantısını kullanabilirsiniz: github.com/serveta/java-102/blob/main/src/FixtureGenerator/Fixture.java

Aşağıda ise türkçe açıklama satırlarıyla algoritmanın önemli kısımları inceleyebilirsiniz;

Algoritmaya gönderilen takım sayısı ikiye bölünmüyorsa tek sayı demektir. Eğer öyleyse adı Oynamayacak olan yeni bir takım ekle. Dediğimiz kod satırı;

if (teams.size() % 2 != 0) { 
     teams.add(new Team("Oynamayacak")); 
 }

Gelen takımların bir defalığına mahsus yerlerini değiştirdiğimiz kod satırı;

Collections.shuffle(teams);

ve gerisi


  /*
	ilk döngümüz toplam round(tur) sayısı kadar dönüyor.
	*(toplam round = toplam takım sayısı - 1)* 'di.
	Bu demek oluyor ki her takım diğer takımla bir kere eşleştikten sonra
	tekrar eşlemek istersek bu döngünün içerisindeki karıştırma işleminden
	sonra takımları bir kez daha eşlememiz gerekecek.
	Ancak çift devreli lig değil de tek devreli olsaydı takımları birer kez
	eşlememiz yeterli olacaktı.
    */
 for (int i = 0; i < totalRounds; i++) {
     // Her round(tur) için eşleşmeyi aşağıdaki for döngüsüyle gerçekleştiriyoruz.
     for (int j = 0; j < eachRoundMatches; j++) {
         int leftSide = j;
         int rightSide = ((teams.size() - 1) - j);
	 fixtureArrayList.add(new Fixture(teams.get(leftSide), teams.get(rightSide)));
     }

     /* 
        tempTeams sayesinde orijinal listemizdeki (teams) değerleri koruyarak 
	karıştırma işlemini tempTeams listemizde gerçekleştirip ondan sonra
	asıl listemize aktarıyoruz.
     */
			
     // Bunun için öncelikle tempTeams listemizin içini her doldurduğumuzda
     // boş olduğunu teyit etmemiz gerekiyor.
	tempTeams.clear();

	// Ardından orijinal (teams) listemizdeki ilk ve son değeri tempTeams 
	// listemizde ard arda yazdıktan sonra;
	tempTeams.add(teams.get(0));
        tempTeams.add(teams.get(teams.size() - 1));

	// ... geri kalan değerleri 1. indisten son kalan indise kadar döngü
	// vasıtasıyla aktarıyoruz.
        for (int k = 1; k < teams.size() - 1; k++) {
	    tempTeams.add(teams.get(k));
        }

        // Takımların eşleşmelerini çift devreli lig usulüne göre yapacağımız için
	// aşağıdaki döngüyle yeni bir round oluşturmuş oluyoruz.
	/* 
	    Buradaki önemli bir fark ise leftSide ve rightSide kısımlarını 
	    Fixture classına kayıt ederken tam tersi bir işlem uyguluyoruz.
	*/
	for (int j = 0; j < eachRoundMatches; j++) {
	    int leftSide = j;
            int rightSide = ((tempTeams.size() - 1) - j);
            fixtureArrayList.add(new Fixture(tempTeams.get(rightSide), tempTeams.get(leftSide)));
        }

      // Ardından tempTeams listemizde oluşturduğumuz yeni listeyi
      // orijinal listemizle değiştiriyoruz.
      teams.clear();
      teams.addAll(tempTeams);
    // ... ve döngümüz tüm turlardaki eşleşmeler tamamlanana kadar bu şekilde dönüyor...
 }
Bundan sonraki işlemde eşleşmeleri yazdırmak kalıyor. Kolay gelsin!

Konu ile ilgili görüşlerinizi aşağıdaki yorum kutusundan paylaşabilirsiniz.

Yorumlar