Bir masa üzerine 1.000.000 (bir milyon) kibrit çöpü bırakılmıştır. İki kişi bu kibrit çöpleri ile aşağıdaki kurala göre oyun oynuyorlar. Sırası gelen oyuncu bir asal sayı p ve negatif olmayan bir n sayısı seçip masa üzerinden p^n tane kibrit çöpünü alabiliyor. (örneğin 8, 1, 25, 5 ,49, 125 vs) En son kibrit çöpünü alan oyuncu oyunu kazanıyor?
Bu oyuna uygun bir program yazmak istiyorum. Taktiği ve algoritması nasıl olmalı üzerinde konuşalım.
asallar = [n for n in range(2,1000000)if all([n%i for i in range(2,n)])]
kalancop = 1000000
def kullanici_kontrol(p,n):
if p in asallar and n>1:
return True
else:
return False
def sistem_sayi(copler):
# kalan çöplerden küçük, kurala uygun bir sayı üretilecek
pass
print("""Bir masa üzerine 1.000.000 (bir milyon) kibrit çöpü bırakılmıştır.
İki kişi bu kibrit çöpleri ile aşağıdaki kurala göre oyun oynuyorlar.
Sırası gelen oyuncu bir asal sayı p ve negatif olmayan bir n sayısı seçip masa üzerinden p^n tane kibrit çöpünü alabiliyor.
(örneğin 8, 1, 25, 5 ,49, 125 vs)
En son kibrit çöpünü alan oyuncu oyunu kazanıyor.""")
while kalancop>0:
p,n = map(int,input("Bir asal ve bir üs giriniz aralarında boşlukla.").split())
if kullanici_kontrol(p,n):
pass
else:
print("Geçersiz, lütfen yeniden girin")
continue
kalancop -= p**n
sistem_sayi(kalancop)
Şöyle bir giriş yaptım. Ama hatalı olduğum yerleri söylemenize veya ekstra fikirlerinize açığım.
Tahmin ettiğim gibi ilk satır programın çalışmasını epey yavaşlattı. Şununla değiştirmeye karar verdim ama diğer yandan da sistemin sayı üretebilmesi için elimde bir asal tablosu olması gerektiğine inancım devam ediyor.
kalancop = 1000000
def asal(n):
for i in range(2,int(n**0.5)+1):
if (n%i) == 0:
return False
return True
def kullanici_kontrol(p,n):
if asal(p) and n>=0 and p**n<kalancop:
return True
else:
return False
def sistem_sayi(copler):
# kalan çöplerden küçük, kurala uygun bir sayı üretilecek
pass
print("""Bir masa üzerine 1.000.000 (bir milyon) kibrit çöpü bırakılmıştır.
İki kişi bu kibrit çöpleri ile aşağıdaki kurala göre oyun oynuyorlar.
Sırası gelen oyuncu bir asal sayı p ve negatif olmayan bir n sayısı seçip masa üzerinden p^n tane kibrit çöpünü alabiliyor.
(örneğin 8, 1, 25, 5 ,49, 125 vs)
En son kibrit çöpünü alan oyuncu oyunu kazanıyor.""")
while kalancop>0:
p,n = map(int,input("Bir asal ve bir üs giriniz aralarında boşlukla.").split())
if kullanici_kontrol(p,n):
pass
else:
print("Geçersiz, lütfen yeniden girin")
continue
kalancop -= p**n
sistem_sayi(kalancop)
Edit: if asal(p) and n>=0 and p**n<kalancop şu satır düzelttim. örnek değerler içinde 1 olduğuna göre 0 da girilebiliyor, ayrıca girdiği sayıların kurala uyması kalan çöpten fazla olamaz.
Yok siz doğru anlatmışsınız. Ben bu işlemle çok ilerleyemeyiz onu anlatmak istedim. 1 Milyon’un asal çarpanları gibi bir durum oyun çok ilerlemez gibi geldi. Kısa sürer gibi geldi.
Sanki koşulları daha da zorlamak yada asal sayıyı yada n sayısını rasgele vermek yada bir aralık içinde tutmak gerekir gibi onu ifade etmeye çalıştım.
Yani asal çarpan kalmazsa kimin kaybedeceği gibi bir durum gerekiyor sanki.
EDIT:
Örneklemek gerekirse;
p:2 (Asal) n19 seçersem. Kafadan 2^19=524288 çöp alırım, sonraki hamlelerin anlamı kalmaz yarıdan fazlasını almış ve oyunu kazanmış olurum.
Oyunun bir noktasında kalan çöp sayısı,125, 1048, 19683, 117649 vs olduğunda sırası gelen kazanabiliyor örneğin. Sadece 1,2 çöp kalmasa da olur. Kalan çöplerin bir asalın üssü olup olmadığına bakmalı program aynı zamanda.
Bunda mutabıkız, kodlama kısmı en kolay kısmı. Bu bir oyun olmaktan çok sabit çözümlü yada sabit kurallı bir çözüme yakın gibi duruyor. Yani bir tercih taktiği ile hep aynı kişi kazanabilir.
Oyun gibi bakmayın bunu kim nasıl kazanır bir çözüm üretin demek gibi bir durum var ortada. Anlatmak istediğim bu.
Koda tabi ki farklı şekilde asal çarpanlar ile asal sayılarla bir şeyler yapılır. Ama sürekli bir avantaj durumu var entropi eşit dağılmış gibi durmuyor. 3 Taş oynayıp ilk başlayıp hatalı oynamadığınız sürece ya kazanırsınız yada berabere kalır gibi bir durum oluyor sanki.
Bunu ifade etmeye çalışıyorum. Alınacak çöp sayısı mevcut çöplerin yarısını geçemez, aynı asal sayı iki kere kullanılamaz gibi biraz kısıtlama olması gerekir gibi düşünüyorum.
Taktiği üzerine konuşuyorum. Yoksa söylediğiniz şey kodlanabilir basit bir durum.
Asal bir sayı seç üssü için bir sayı seç, sonra çıkan sayı yerdeki çöpten azsa çıkar gibi bir durum kodlaması kolay.
Ama asal ve bir sayı ile sonlu bir çözüm kümesi gibi duruyor.
Bütün varyasyonları bile hesaplamak mümkün mü acaba diye düşünmeye başladım.
Hatta zaten asal sayı hesaplamaya da gerek var mı?
Sadece bir asal sayı tablosu tutup, bu tablodan mı verilen asal sayı diye kolayca da kontrol edilebilir mi her seferinde asal sayı hesaplamak da gerekir mi?
Gibi farklı kodlama fikirlerimde var. Sadece soru sanki çözümü sınırlı ve tekrarlanan hale gelmeye müsait gibi onu ifade ediyorum.
Anladım evet. Mutlaka bir triği vardır. Sayı o yüzden bir milyon verilmiştir. Kolay hesaplanamasın diye. En azından insan insana oynarken.
Şu oyuna benziyor teorik olarak. 1 ile 11 arasında bir sayı söyleyip 100 çöpten alıyoruz. Son çöpü alan kazanıyor. Burada 12 nin katlarını yakalayan kazanıyordu yanlış hatırlamıyorsam.
Ama en azından ilk başta şunları kontrol etmesi biraz daha adaletli olur. Kalan kibrip çöpü bir asalın üssüyse alsın hepsini değilse rastgele bir asal ve üs belirlesin, ama kendisi aldıktan sonra yine kalan çöpler yine bir asalın üssüyse başka iki sayı belirlesin.
Tam da bunu söylemek istedim. Yoksa ilk haliyle sorunuzun kodu.
Bir asal bir doğal sayı al, bu sayıları manipüle et (çarp, topla, böl yada üssünü al) Sonra mevcut tan eksilt.
Bu da gayet basit bir kod olur. Oyun kuralı karmaşlıklaştırarak kazanma şansı nasıl adil hale getirileiblir matematiksel analizi bu kısımda olmalı diye düşündüm.
İfade etmek istediğim bu idi. Ha sizin verdiğiniz kurala göre en anlamlı hamleler ne olurd o da analiz edilebilir ve zaten analiz ediliyorsa oyun çözümlenebilir oluyor gibi tabi dikkatle hesaplayıp bakmak da gerekebilir. Belki dengeyi bozan marjinal bir durum vardır.
Collatz serisine bayılırım tabiki. Hala ispatlanamamış serilerden birisidir.
Programın son hali şu, rastgele oynuyor tabi kaybediyor genelde. Asal tablosu da çok dar.
import random
kalancop = 1000000
def asal(n):
for i in range(2,int(n**0.5)+1):
if (n%i) == 0:
return False
return True
def kullanici_kontrol(p,n):
if asal(p) and n>=0 and p**n<=kalancop:
return True
else:
return False
def sistem_sayi(copler):
# kalan çöplerden küçük, kurala uygun bir sayı üretilecek
asaltablosu = [2,3,5,7,11,13,17]
rast_asal = random.choice(asaltablosu)
rast_us = random.randint(0,10)
while rast_asal**rast_us>kalancop:
rast_asal = random.choice(asaltablosu)
rast_us = random.randint(1,10)
return rast_asal,rast_us
print("""Bir masa üzerine 1.000.000 (bir milyon) kibrit çöpü bırakılmıştır.
İki kişi bu kibrit çöpleri ile aşağıdaki kurala göre oyun oynuyorlar.
Sırası gelen oyuncu bir asal sayı p ve negatif olmayan bir n sayısı seçip masa üzerinden p^n tane kibrit çöpünü alabiliyor.
(örneğin 8, 1, 25, 5 ,49, 125 vs)
En son kibrit çöpünü alan oyuncu oyunu kazanıyor.""")
while kalancop>0:
p,n = map(int,input("Bir asal ve bir üs giriniz aralarında boşlukla.").split())
if kullanici_kontrol(p,n):
kalancop -= p**n
print(f"Girdiğiniz sayılar {p} ^ {n} ve kalan çöp sayısı {kalancop}")
else:
print("Geçersiz, lütfen yeniden girin")
continue
sp,sn= sistem_sayi(kalancop)
kalancop -= sp**sn
print(f"Söylediğim sayılar {sp} ^ {sn} ve kalan çöp sayısı {kalancop}")
sistemsayi(copler) , copleri parametre aldım bunun sebebi kullanmaktı işte sonraki adımlar için hesaplama vs için. Yapacağım o kısmı daha.
Mesela 999983 sayısı asal, ama benim tablomda yok. Kalap çöp sayısı 999983 olsaydı, oyunu 999983 1 diyerek kazanmış olacaktı program.
1 milyona kadar asalları bir listede tutmak yerine, kalan sayının bir asalın üssü olup olmadığına kısa yoldan bakmanın bir algoritması var mı?
Edit: Sorarken farkettim, asal çarpanlarına ayırmak işe yarabilir kalan kibrit sayısını. Onu da yaptım asal çarpan sayısı 1 ise bir asalın üssü olduğu anlamına geliyor.
import random
kalancop = 1000000
def asal(n):
for i in range(2,int(n**0.5)+1):
if (n%i) == 0:
return False
return True
def asal_carpan_sayisi(sayi):
carpanlar = []
bolen = 2
while sayi>1:
if sayi%bolen == 0:
carpanlar.append(bolen)
sayi = sayi / bolen
bolen -= 1
bolen +=1
return bolen,len(set(carpanlar))
def kullanici_kontrol(p,n):
if asal(p) and n>=0 and p**n<=kalancop:
return True
else:
return False
def sistem_sayi(copler):
# kalan çöplerden küçük, kurala uygun bir sayı üretilecek
sayi,carpanlar = asal_carpan_sayisi(copler)
if carpanlar==1:
pass # burada sayi değişkenini uygun üsle geri gönderme planım var.
asaltablosu = [2,3,5,7,11,13,17]
rast_asal = random.choice(asaltablosu)
rast_us = random.randint(0,10)
while rast_asal**rast_us>kalancop:
rast_asal = random.choice(asaltablosu)
rast_us = random.randint(1,10)
return rast_asal,rast_us
print("""Bir masa üzerine 1.000.000 (bir milyon) kibrit çöpü bırakılmıştır.
İki kişi bu kibrit çöpleri ile aşağıdaki kurala göre oyun oynuyorlar.
Sırası gelen oyuncu bir asal sayı p ve negatif olmayan bir n sayısı seçip masa üzerinden p^n tane kibrit çöpünü alabiliyor.
(örneğin 8, 1, 25, 5 ,49, 125 vs)
En son kibrit çöpünü alan oyuncu oyunu kazanıyor.""")
while kalancop>0:
p,n = map(int,input("Bir asal ve bir üs giriniz aralarında boşlukla.").split())
if kullanici_kontrol(p,n):
kalancop -= p**n
print(f"Girdiğiniz sayılar {p} ^ {n} ve kalan çöp sayısı {kalancop}")
else:
print("Geçersiz, lütfen yeniden girin")
continue
sp,sn= sistem_sayi(kalancop)
kalancop -= sp**sn
print(f"Söylediğim sayılar {sp} ^ {sn} ve kalan çöp sayısı {kalancop}")
Bu da bizi şu açmaza götürür, herkes belirli bir sınıra kadar en küçük asal üssü bir sayı söyleme çabasına götürür. Taki o sınırdaki asal sayıyı söyleyip son kalanı alana kadar.
Bu da ikinci bir kural ihtiyacının altını çizer asal üzeri bir doğal sayı.
üzeri 1 yada üzeri 0 hileli durumlar. En az karesi olduğunda bu kadar büyük bir asal tablosu oluşmayacaktır. Karesi 1 milyon u geçmeyen asal sayı max asal sayıdır. Bu da bizi 1000x1000 gibi bir durumda zaten binden küçük ilk asal sayıya götürür. Yani üsü sıfır ve üssü bir hariç tutarsanız. Max asal sayınız binden küçük bir tablo olacaktır.
Bu kural olduğu sürece oyun rahatlıkla asalların savaşı olarak daha da analiz edilebilir hale gelir ki bu şartlarda 2^0 ve 2^1 ile 2 ve bir eksilterek birinci kurala kadar rakibi eksiltmeye zorlar max sınıra gelince de alırsınız.
Sanki bunu analiz etmek daha kolay.
EDIT bu durumda oyun 0-17 aralığına sıkışır. Karşılıklı 1 ve 2 eksilterek 17 ye ulaşıldığında yada geçildiğinde diğeri 999983 dediğinde oyun biter.
Bir şey eksik rastgelelik oluşmuyor sanki. Satrançtaki gibi her hamlenin farklı kısıtı olmalı ki varyasyon çeşitlensin.
Bu sefer bir milyon-5^3 üzerinde yine en büyük asal arasına sıkıştırmaya çalışırsınız.
Sonra bir asala denk gelmeden 2^0 , 2^1 döngüsüne tekrar döneriz.
EDIT:
Aklıma bir fikir getirdiniz.
Şimdi şöyle bir ile 1 milyon arasındaki asal sayıları bir alayım. Bir metin dosyası yada tabloya yerleştireyim.
Sonra ihtmaller üzerine bir karar robotu yada çözümleme önerisi çıkarabilen bir kod yazabilir miyiz bakalım. Zaten her asal üzeri sayı kullanılduğında benim başlangıç tablomdaki max asal sayı miktarı azalacaktır.
Sonra masada kalan sayı ile vereceğim max sayı arasındaki fark asal değilse oyna değilse bir küçük asala geç gibi bir yaklaşım üzerinde bir çözümleme çıkarabilir mi görmeye çalışayım.
Asalları saydırayım bakalım kaç asal alternatifimiz var görelim. Her hamlede zaten azalacak buradan bir yere varıyor muyum bakar bir kod oluşursa paylaşırım.
EDIT 2:
Kendime ve meraklılarına not. Tek tek tüm asalları 1 milyona kadar hesaplatmayı bekleyecek kadar delirmedim.
Burada belirli aralıklarda asal sayıların dosyaları var. Başlangıç noktası olarak olarak bu tür bir dosya kullanacağım.
İlk dosya: 2 15,485,863 aralığında bana 1 Milyona kadar ki kısmı lazım. Kırptım.
Yaklaşık olarak saydığımda: Kolonlar 8 erli ve ve son satırdan bir önceki satır numarası, 9812 ve en son satırda 2 sayı daha var. 78.498 sayılık bir metin dosyam var.
Artık bir sayı asal mı diye bakmak için bu dosyada aralık yarılama metodu ile basit bir arama yaparak tabloda yoksa hızlı bir şekilde asal olup olmadığını bulabileceğim. Tabi belki yanılıyoruz asal mı diye kontrol etmek daha kısa sürebilir. Bir zaman tutar ikisini de karşılaştırabiliriz.
Tabi tablo 8 sütun bunu bir algoritma ile her sayıyı bir satıra mı indirsem satırda 8 grup içinde mi arasam henüz karar veremedim. Ama buradan bir asal look up table çıkar gibi geliyor bana.