Okul ders programı

Merhaba yazbel, merhaba yazbel emekçileri, merhaba bu ülkede kodlamayı muassır medeniyetler seviyesine ulaştırmak isteyen gönül dostları.

Bu gönderimde en baştan söyleyeyim bir işi bir projeyi halletmeye çalışmıyorum sadece öğrenmeye çalışıyorum.

Öğrenmek istediğim şu: Bir okuldaki öğretmenlerin ders programını pythonda yapmak için hangi konulara ileri seviyede hakim olmak gerekir. Öğrenmek istediğim bu.

Bu mesajı yazmadan önce yaptığım ön incelemeler şunlar. İlk önce şu konuyu inceledim Sınav Zaman Tablosu aslında burada benzer bir konu tartışılmış ama tam olarak benim örneğime benzemiyor. Yine aynı yerde bir arkadaş ‘bit optimization’ ile biraz ilgilenmek gerekir demiş ama yine araştırmalarımda bir şeye ulaşamadım.

Benim isteğim basit anlamda şöyle(aslında bu kadar az veri yok ama ben anlaşılır ve basit olması açısından daha az veriyle anlatmak istedim)

Dersler - fen , matematik, İngilizce

Günler - Pazartesi , salı

Öğretmenler - fen(ahmet), matematik(aysu), İngilizce(metin)

Ders saatleri- fen(5), mat(5), ing(4)

Günlük ders saati- 7

Derslikler(sınıflar)- 5a, 5b

Dersler arka arkaya gelecek (örneğin matematiği ikiye bölersek üç ders üst üste ve iki ders üst üste, İngilizce de bu durumda iki iki oluyor)

Öğretmenin 5a sınıfında dersi varken aynı anda 5b sınıfına derse giremez(bunu neden yazdım bilmiyorum)

Örnek olarak Python kodu aşağıdakini yapabilmeli

5a
Pazartesi - fen,fen,fen,mat,mat,ing,ing
Salı--------- ing,ing,mat,mat,mat,fen,fen

5b
Pazartesi - mat,mat,mat,ing,ing,fen,fen
Salı----------- fen,fen,fen,ing,ing,mat,mat

Burada daha fazla veriyle yapılmış örnek bir çarşaf program var https://koprululeral.meb.k12.tr/meb_iys_dosyalar/55/13/758011/dosyalar/2022_11/26144832_Ekran-Alintisi-ogretmen.png

Bu işlemleri otomatik yapan programlar var. En bilindik olanı asc timetables. Ama ben bunu Python’da nasıl yapılır öğrenmek istiyorum.

github’da bunu yapan Python kodlarını buldum “timetable Python” yazınca yüzlerce çıkıyor. Çoğunu inceledim ama dediğim gibi mantığını anlayamıyorum. Mesela burada GitHub - MahmoudAbusaqer/Timetabling_Graduation-Project: IUG Timetabling Using Evolutionary Strategy With Shotgun Hill-Climbing Algorithms güzelce kodlamış arkadaşlar. Kodları tek tek inceleyerek anlayamıyorum. Belki de hangi konuya ileri seviye hakim olmam gerektiğini bilmediğim için ilerleyemiyorum. Zaten sizden isteğimde bu, bunu yapabilmek için hangi konuları bilmek gerekir. Python bilgim orta seviye diyebiliriz. Python benim için zevkli bir hobi, işim değil.

Belki de tamamen yanlış yerden bakıyorum. Bunu tartışmak ümidiyle sevgiyle kalın.

Her seyden once yazacagimiz program veya algoritmanin girdi ve ciktilarini belirlemek gerekiyor. Mesela:

dersler = [
	{
		'isim': "fen",
		'ogretmen': "ahmet",
		'saatler': [3, 2],
	}, {
		'isim': "matematik",
		'ogretmen': "aysu",
		'saatler': [3, 2],
	}, {
		'isim': "İngilizce",
		'ogretmen': "metin",
		'saatler': [2, 2],
	}
]

gunler = ["Pazartesi", "salı"]

siniflar = ["5a", "5b"]

gunluk_ders_saati = 7

Bu girdi. Cikti neye benzeyecek?

Daha bu surecte problemle ilgili ongoruler kazaniyoruz. Mesela hem “isim” hem de “ogretmen” girdisine gerek yok—birini digerine cevirmek cuzi (trivial) bir islem. Mesela dersleri bloklara bolmeyi program yaratma algoritmasina vermemize gerek yok, onden yapabiliriz.

Ciktiyi da tanimladiktan sonra problem bir eslestirme (mapping) problemine donuyor. Ilk yazacagimiz algoritma brute-force, yani butun olasiliklari tek tek denemek.

Ne yapiyoruz? Butun siniflarin butun derslerine ahmet giriyor. Olmadi mi? Neden olmadi? Bir ogretmen ayni anda iki derse giremez. O zaman algoritmayi degistiriyoruz, butun siniflarin butun derslerine siradaki ogretmen giriyor. 5a: ahmet ahmet ahmet ahmet ahmet ahmet ahmet, 5b: aysu aysu aysu aysu aysu aysu aysu

Olmadi mi? Neden olmadi? Bir ogretmen bloklari kadar ders vermeli. Algoritmayi degistiriyoruz, bir ogretmen bloklari kadar ders yapiyor. 5a: [ahmet ahmet ahmet] [ahmet ahmet] [metin metin], 5b: [aysu aysu aysu] [aysu aysu] [bos bos]

Bu da mi olmadi? Neden olmadi? Onun da kuralini yaziyoruz…

“siradaki ders” veya “ilk bos ogretmen” gibi kavramlarin hepsi girdiler uzerinde donguler ile yapildigi icin kuralin bozuldugu noktada continue deyip bir sonraki olasiligin denenmesini saglayabiliriz.

Kisacasi her sey girdi ve cikti uzaylarini (evrenlerini) tanimlayarak basliyor. Brute-force-vari bir algoritma, girdinin butun kombinasyonlarini kullanarak cikti uzayinin boyutunu veriyor. Sonra bu uzayda istedigimiz kriterlere uyan cozumleri aramaya basliyoruz. En basit arama ise, butun cozumlere siradan bakmak.

2 Beğeni

Yanıtınız için teşekkürler aib.

Dediğiniz yöntemi yapmaya çalışmıştım dün akşam ama yanlış bir yere girmişim gibi geldi. Sürekli if and and and. Böyle gitmez diye düşündüm.

import random
import operator as op

a=[]

b=["mat","fen","ing"]

def count_function(list, target):
    if len(list) < 2:
        return 0
    val = 0
    prev = list[0]
    for elem in list[1:]:
        if elem == target and elem == prev:
            val += 1
        prev = elem
    return val


while True:
    
    a.append(random.choices(b, k=7))
    
    if op.countOf(a[0], "ing")==1 and op.countOf(a[0], "fen")==3 and op.countOf(a[0], "mat")==3 and count_function(a[0], 'mat')==2 and count_function(a[0], 'fen')==2:
        break
    else:
        a.clear()
    
a[0]

çıktı:
[‘fen’, ‘fen’, ‘fen’, ‘ing’, ‘mat’, ‘mat’, ‘mat’]

buradan if else continue while True try except deneme yanılma ile girecektim ama yanlış yoldayım diye düşündüm.

ek olarak da "map"den kastınız, böyle bir şey mi?

num1 = ["fen", "fen", "fen"]
num2 = ["mat", "mat", "fen"]

result = map(lambda n1, n2: n1==n2, num1, num2)

for i in list(result):
    if i==True:
        print("eşleşti")
    else:
        print("olmadı")

çıktı:
olmadı
olmadı
eşleşti

Gitmez.

Dorduncu bir ders eklendigi noktada bu kodun degismesi lazim.
Ders eklendiginde degismeyecek kod yazmak lazim.

Kod olasi cozum uzayini gezebiliyorsa sorun yok.

Daha cok soyle bir sey:

cikti = fonksiyon(girdi)

{ siniflar=['5a'], dersler=["mat"], ders_saati=3 }['5a': ['mat', 'mat', 'mat']]

Ciktilari girdiye eslestirme.


Kod yazmaya baslamadan once girdi ve cikti formatlarini belirlemeniz lazim.

import random
from openpyxl import Workbook
from openpyxl.styles import Alignment

# Veriler
ogretmenler = ["Öğretmen1", "Öğretmen2", "Öğretmen3", "Öğretmen4", "Öğretmen5", "Öğretmen6", "Öğretmen7", "Öğretmen8", "Öğretmen9", "Öğretmen10"]
dersler = ["Matematik", "Seçmeli Müzik", "Sosyal Bilgiler", "Türkçe", "Fen Bilgisi", "Beden Eğitimi", "Din Kültürü ve Ahlak Bilgisi", "İngilizce", "Müzik", "Seçmeli Matematik", "Bilişim Teknolojileri ve Yazılım", "Görsel Sanatlar", "Seçmeli Spor Faaliyetleri"]
gunler = ["Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma"]
saatler = 7

siniflar = ["Sınıf1", "Sınıf2", "Sınıf3"]
siniflar = {sinif: idx for idx, sinif in enumerate(siniflar)}
siniflar_liste = list(siniflar.keys())

ogretmen_ders_sinif = {
    "Sınıf1": {
        "Öğretmen1": {"Matematik": (5, [2, 2, 1]), "Seçmeli Matematik": (2, [2])},
        "Öğretmen2": {"Sosyal Bilgiler": (3, [2, 1])},
        "Öğretmen3": {"Fen Bilgisi": (4, [2, 2])},
        "Öğretmen4": {"Türkçe": (6, [2, 2, 2])},
        "Öğretmen5": {"İngilizce": (3, [2, 1])},
        "Öğretmen6": {"Beden Eğitimi": (2, [2]), "Seçmeli Spor Faaliyetleri": (2, [2])},
        "Öğretmen7": {"Din Kültürü ve Ahlak Bilgisi": (2, [2])},
        "Öğretmen8": {"Bilişim Teknolojileri ve Yazılım": (2, [2])},
        "Öğretmen9": {"Müzik": (1, [1]), "Seçmeli Müzik": (2, [2])},
        "Öğretmen10": {"Görsel Sanatlar": (1, [1])}
    },
    "Sınıf3": {
        "Öğretmen1": {"Matematik": (5, [2, 2, 1]), "Seçmeli Matematik": (2, [2])},
        "Öğretmen2": {"Sosyal Bilgiler": (3, [2, 1])},
        "Öğretmen3": {"Fen Bilgisi": (4, [2, 2])},
        "Öğretmen4": {"Türkçe": (6, [2, 2, 2])},
        "Öğretmen5": {"İngilizce": (3, [2, 1])},
        "Öğretmen6": {"Beden Eğitimi": (2, [2]), "Seçmeli Spor Faaliyetleri": (2, [2])},
        "Öğretmen7": {"Din Kültürü ve Ahlak Bilgisi": (2, [2])},
        "Öğretmen8": {"Bilişim Teknolojileri ve Yazılım": (2, [2])},
        "Öğretmen9": {"Müzik": (1, [1]), "Seçmeli Müzik": (2, [2])},
        "Öğretmen10": {"Görsel Sanatlar": (1, [1])}
    },
    "Sınıf2": {
        "Öğretmen1": {"Matematik": (5, [2, 2, 1]), "Seçmeli Matematik": (2, [2])},
        "Öğretmen2": {"Sosyal Bilgiler": (3, [2, 1])},
        "Öğretmen3": {"Fen Bilgisi": (4, [2, 2])},
        "Öğretmen4": {"Türkçe": (6, [2, 2, 2])},
        "Öğretmen5": {"İngilizce": (3, [2, 1])},
        "Öğretmen6": {"Beden Eğitimi": (2, [2]), "Seçmeli Spor Faaliyetleri": (2, [2])},
        "Öğretmen7": {"Din Kültürü ve Ahlak Bilgisi": (2, [2])},
        "Öğretmen8": {"Bilişim Teknolojileri ve Yazılım": (2, [2])},
        "Öğretmen9": {"Müzik": (1, [1]), "Seçmeli Müzik": (2, [2])},
        "Öğretmen10": {"Görsel Sanatlar": (1, [1])}
    }
}

# Ders programı matrisi
program = [[[None for _ in range(saatler)] for _ in range(len(gunler))] for _ in range(len(siniflar))]

# Aktiviteleri sırala
aktiviteler = []
for sinif, ogretmenler in ogretmen_ders_sinif.items():
    for ogretmen, dersler in ogretmenler.items():
        for ders, detaylar in dersler.items():
            ders_sayisi, bloklar = detaylar
            for blok in bloklar:
                aktiviteler.append((ogretmen, ders, sinif, blok))

random.shuffle(aktiviteler)  # Zorluğa göre sıralanabilir
aktiviteler.sort(key=lambda x: x[3], reverse=True)


def ogretmen_cakisiyor_mu(ogretmen, gun, saat, blok_uzunlugu):
    for sinif in range(len(siniflar)):
        for blok in range(blok_uzunlugu):
            if program[sinif][gun][saat + blok] is not None and program[sinif][gun][saat + blok][0] == ogretmen:
                return True
    return False


def yerlestir(aktivite, max_deneme=50000):
    for _ in range(max_deneme):
        gun = random.randint(0, len(gunler) - 1)
        # Her blok dersi için alan ayır, eğer alan yoksa yeni bir deneme başlat
        for saat in range(saatler - aktivite[3] + 1):
            conflict = False
            # Eğer blok için yeterli alan var mı diye kontrol et
            for i in range(aktivite[3]):
                if program[siniflar[aktivite[2]]][gun][saat + i]:
                    conflict = True
                    break
                # Eğer öğretmen aynı saatte başka bir sınıfta ders veriyorsa çakışma vardır
                elif ogretmen_cakisiyor_mu(aktivite[0], gun, saat + i, 1):
                    conflict = True
                    break
            if not conflict:  # Eğer çakışma yoksa dersi yerleştir
                for i in range(aktivite[3]):
                    program[siniflar[aktivite[2]]][gun][saat + i] = (aktivite[0], aktivite[1])  # Öğretmen ve ders adını yerleştir
                return True
    return False


yerlestiremeyenler = []
for aktivite in aktiviteler:
    if not yerlestir(aktivite):
        yerlestiremeyenler.append(aktivite)

for aktivite in yerlestiremeyenler:
    for _ in range(aktivite[3]):
        if not yerlestir((aktivite[0], aktivite[1], aktivite[2], 1)):
            print(f"Yerleştirilemeyen aktivite: {aktivite}")


# Sınıflara göre ders programı
sinif_workbook = Workbook()
for sinif in siniflar_liste:
    sheet = sinif_workbook.create_sheet(title=sinif)

    # Başlık satırını yazma
    sheet["A1"] = "Saatler / Günler"
    for gun in range(len(gunler)):
        sheet.cell(row=1, column=gun + 2, value=gunler[gun])

    # Ders programını yazma
    for saat in range(saatler):
        sheet.cell(row=saat + 2, column=1, value=f"Saat {saat + 1}")
        for gun in range(len(gunler)):
            ders = program[siniflar[sinif]][gun][saat]
            if ders:
                sheet.cell(row=saat + 2, column=gun + 2, value=f"{ders[0]} - {ders[1]}")
            else:
                sheet.cell(row=saat + 2, column=gun + 2, value="Boş")

    # Hücre boyutlarını otomatik ayarlama
    for column_cells in sheet.columns:
        max_length = 0
        for cell in column_cells:
            if cell.value:
                cell.alignment = Alignment(wrap_text=True)
                if len(str(cell.value)) > max_length:
                    max_length = len(str(cell.value))
        adjusted_width = (max_length + 2) * 1.2
        sheet.column_dimensions[column_cells[0].column_letter].width = adjusted_width

# Varsayılan sayfayı silme
sinif_workbook.remove(sinif_workbook.active)

# Sınıf ders programını kaydetme
sinif_workbook.save("sinif_ders_programi.xlsx")


# Öğretmenlere göre ders programı
ogretmen_workbook = Workbook()
for ogretmen in ogretmenler:
    sheet = ogretmen_workbook.create_sheet(title=ogretmen)

    # Başlık satırını yazma
    sheet["A1"] = "Saatler / Günler"
    for gun in range(len(gunler)):
        sheet.cell(row=1, column=gun + 2, value=gunler[gun])

    # Ders programını yazma
    for saat in range(saatler):
        sheet.cell(row=saat + 2, column=1, value=f"Saat {saat + 1}")
        for gun in range(len(gunler)):
            dersler_listesi = []
            for sinif in siniflar_liste:
                ders = program[siniflar[sinif]][gun][saat]
                if ders and ders[0] == ogretmen:
                    dersler_listesi.append(ders[1])
            dersler_str = "\n".join(dersler_listesi)
            if dersler_str:
                sheet.cell(row=saat + 2, column=gun + 2, value=dersler_str)
            else:
                sheet.cell(row=saat + 2, column=gun + 2, value="Boş")

    # Hücre boyutlarını otomatik ayarlama
    for column_cells in sheet.columns:
        max_length = 0
        for cell in column_cells:
            if cell.value:
                cell.alignment = Alignment(wrap_text=True)
                if len(str(cell.value)) > max_length:
                    max_length = len(str(cell.value))
        adjusted_width = (max_length + 2) * 1.2
        sheet.column_dimensions[column_cells[0].column_letter].width = adjusted_width

# Varsayılan sayfayı silme
ogretmen_workbook.remove(ogretmen_workbook.active)

# Öğretmen ders programını kaydetme
ogretmen_workbook.save("ogretmen_ders_programi.xlsx")

hocam yukarıdaki kodlar üzerinde bir incele istersen . blok yapısıda var. ders dagıtım optimisazyonu dediğimiz olay cok zor :slight_smile: imiş bende araştırmalarım sonucu öğrendim.
kısıtlamalar mevcut blocklar mevcut. belki işine yarar eger ekleme yapmak istersen yada masa üstü yani görsel arayüz mevzusuna girmek istersen iletişime geçersen sevinirim veri yapısı içinde db modelisazyonu farklı bir uzmanlık alanı