TRWE_2012-Nazi Almanya'sı- Enigma Makinesi PS1 Betiği Geliştiriyor

Programlama ve Script dilleri konusunda bilgi paylaşım alanıdır.
Cevapla
Kullanıcı avatarı
TRWE_2012
Zettabyte1
Zettabyte1
Mesajlar: 15418
Kayıt: 25 Eyl 2013, 13:38
cinsiyet: Erkek
Teşekkür etti: 2618 kez
Teşekkür edildi: 5490 kez

TRWE_2012-Nazi Almanya'sı- Enigma Makinesi PS1 Betiği Geliştiriyor

Mesaj gönderen TRWE_2012 »

Merhabalar

Daha önce de buna yeltendim ama her seferinde yarı yolda vazgeçtim.Ama bu sefer kararlıyım...!!! Bu sefer 8 farklı YZ modelin kodlama alt yapısı ile çalışıyorum.Eskiden olsa , YZ öncesi çoktan sinirlenip proje'den yarı yolda vazgeçmiştim.1,5 senedir üzerindeyim..(peşinden koşuyorum)

Eeee, yapınca ne olacak? diyenleriniz olacaktır.Birşey olmayacak ama kritoloji'nin yapısını birebir anlamak ve kullanmak istiyorum.

Yaptığım .PS1 Versiyonlar
Resim
C:\Users\TRWE_2012\Masaüstü\Enigma Cipher_v1.0.ps1
C:\Users\TRWE_2012\Masaüstü\Enigma Cipher_v2.0.ps1
C:\Users\TRWE_2012\Masaüstü\Enigma Cipher_v3.0.ps1

Bu sefer kararlıyım...

Şimdi biraz Enigma Makinesinden bahsedelim...
Resim
Enigma; II. Dünya Savaşı sırasında Nazi Almanyası tarafından gizli mesajların şifrelenmesi ve tekrar çözülmesi amacı ile kullanılan bir şifre makinesidir. Daha açık bir ifade ile Rotor makineleri ailesi ile ilişkili bir Elektro-Mekanik aygıttı ve birçok değişik türü vardı.

Enigma makinesi, ticari olarak 1920 li yılların başında kullanılmaya başlandı. Birçok ülkede Ordu ve Devlet kurumları için özel modeller üretildi. Bunların en ünlüleri II. Dünya Savaşı öncesinde ve savaş sırasında Nazi Almanyası'nda kullanılan modellerdi. Alman ordu modeli olan Wehrmacht Enigma, en çok konuşulan modeldi.

Bu makine kötü bir üne sahip oldu çünkü Müttefik şifreciler (Polonya şifre bürosu, Birleşik Krallık - Bletchley Park vb.) tarafından geniş mesajları çözümlendi. Şifre çözücülerin Müttefiklerin savaşı kazanmalarına büyük yardımları olmuştu. Bazı tarihçiler, Alman Enigma kod sisteminin deşifre olması sayesinde Avrupa'da savaşın iki yıl daha önce bittiğini ileri sürmektedirler.

Enigma şifresinin bazı zayıf yanları olmakla birlikte, aslında diğer faktörler olan operatör hataları, prosedür açıkları ve nadir olarak ele geçen kod kitapları sayesinde çözümlenebildi.

II. Dünya Savaşında Bletchley Park - Birleşik Krallık'ta üslenen Amerikalı ve İngiliz şifre çözücüler, o zamanın en yetenekli ve en değerli bilim insanı, matematikçi ve mühendis lerinden oluşmaktaydı.Bunlardan bazıları, daha sonra Bilgisayar biliminin kurucularından sayılacak Alan Mathison Turing ve dünyanın ilk dijital ve programlanabilir bilgisayarı olan Colossus'u yapan Thomas Harold Flowers'dır. Birçok Colossus bilgisayarı, II. Dünya Savaşı sırasında Alman Lorenz SZ40/42 şifre sisteminin çözülmesi işleminde olasılık hesaplayıcı olarak kullanılmıştır.

II. Dünya Savaşı ve stratejik planların aktarılmasında kullanılan şifre sistemleri ve bunların çözülmesinde kullanılan algoritmalar, buluşlar, şifre çözücü makineler bir anlamda bilgisayar biliminin doğmasına neden olmuştur diyebiliriz.

Çalışma sistemi

Diğer Rotor makineleri gibi Enigma da Elektro-Mekanik bir sistemdir. Temel olarak, rotor mekanizması sayesinde olasılık üreten bir mekanizmadır. Daktilo klavyesine benzer her bir klavye tuşuna basıldığında, rotorlar döner. Belirgin olarak tüm Enigma sistemlerinde öncelikle en sağdaki rotor döner, daha sonra ona komşu olan rotorlar bir veya daha fazla adım atabilir. Rotorun dişli mekanizması her algoritma programlanmadan önce sökülür ve farklı bir konumda takılırdı.

Ayrıca her mesaj çekiminden önce operatör tarafından alt bölümdeki elektrik soketlerini farklı şekilde dizerek şifrenin çözümünü daha da zorlaştırırdı. Mekanik sisteme bağlı elektrik sistemi, operatöre gösterge bölümünde hangi harfin basıldığını ışıklı olarak gösterirdi.
Resim
Resim
Kaynak :

https://tr.wikipedia.org/wiki/Enigma_makinesi
Kullanıcı avatarı
TRWE_2012
Zettabyte1
Zettabyte1
Mesajlar: 15418
Kayıt: 25 Eyl 2013, 13:38
cinsiyet: Erkek
Teşekkür etti: 2618 kez
Teşekkür edildi: 5490 kez

Bu forum konusunu biraz genişletelim

Mesaj gönderen TRWE_2012 »

Merhaba

Bugün sabah 4:30'dan beridir betiği geliştirmeye çalışıyorum.5.Sürüme ulaştım ama hala tam istediğim gibi değil.Ufak hataları var.Ve düzeltilecek...

Betik, nihai kararlı sürüm'e ulaştığında şu gerçek U-boot mesajını kullanacağım...

TÜRKÇE :

TELSİZ MESAJI (FUNKSPRUCH)

Gönderen: U-67
Alan: BdU (Befehlshaber der U-Boote - Denizaltı Filosu Komutanlığı), Lorient Üs Karargahı
Konu: Seyir Raporu – Konvoy Teması ve Hasar Bildirimi
Tarih: 15 Nisan 1942
Saat (Gönderim): 23.45

METİN:

Kuzey Atlantik, AL 3572 karesi. İngiltere ikmal hattında batı yönünde (rotası 270°) ilerlemekte olan HX-178 konvoyu tespit edilmiştir. 24 gemiden oluşan konvoyun ortalama hızı 6,7 knot olup, yoğun muhrip eskortu ile korunmaktadır.

Saat 00.12'de dört adet G7e elektrikli torpido, pruvadaki I ve II ile kıçtaki V ve VI numaralı kovanlardan büyük hedeflere ateşlenmiştir. İki tanker (tahmini 8.000’er GRT) ve bir C3 sınıfı yük gemisi (tahmini 7.500 GRT) isabet alarak batırılmıştır. Tüm torpidolar planlandığı gibi infilak etmiş, herhangi bir erken patlama (Frühzünder) yaşanmamıştır.

Ateşlemenin ardından derhal dalışa geçilmiş, ancak eskort gemileri HMS Eskimo (Tribal-sınıfı muhrip) ve HMS Vanoc (V-sınıfı muhrip) tarafından yoğun su altı bombası saldırısına maruz kalınmıştır. Düşman, dört ayrı hücumda toplam 38 adet su altı bombası atmıştır. U-67, 160 metre derinliğe dalarak ve soğuk su tabakasının (termoklin) altına manevra yaparak ağır hasar almadan sıyrılmayı başarmıştır. Ancak:

HASAR RAPORU:

Pruva sektörü: Basınç gövdesinde hafif deformasyon; 1 ve 2 numaralı torpido kovanları kullanılamaz durumdadır.

Kıç sektörü: Hidrofon (GHG) sistemi tamamen arızalanmıştır; pervane şaftı contasında sızıntı tespit edilmiş olup, elektrik motor dairesinde az miktarda su birikmektedir.

Dalış tankları: Kritik hasar yoktur; ancak dalış derinliği kontrolü manuel olarak sınırlı şekilde çalışmaktadır

DURUM DEĞERLENDİRMESİ:

Tekne hâlâ denize dayanıklıdır ve mürettebatta zayiat yoktur (52 kişi). Ancak hasarlar nedeniyle taarruz kabiliyeti tamamen kaybolmuştur. Azami su üstü sürati, hasarlı şaft nedeniyle 12 knot ile sınırlanmıştır. Yeterli yakıt mevcuttur.

TALEP:

Derhal Fransa-Lorient Denizaltı Üssü'ne dönüş izni ve limana giriş aşamasında mayın tarlalarına karşı eskort / emniyet refakati talep edilmektedir.

U-67'nin bu seferi (Feindfahrt) sonlandırılmıştır.

Komutan: Kapitänleutnant Gerd Kelbling
(U-67 – Tip IXC, 2. U-Filotilla "Saltzwedel")

Mesaj Sonu – F.d.U.
Glück ab! (İyi şanslar)


ALMANCASI : ( dönemin Kriegsmarine (Alman Savaş Donanması) telsiz protokolüne ve askeri jargonuna birebir uygun, %90 kusursuz Almanca çevirisi. )

FUNKSPRUCH

Von: U-67
An: BdU (Befehlshaber der U-Boote) – Lorient Stützpunktquartier
Betreff: Feindfahrtmeldung – Konvoisichtung und Schadensbericht
Datum: 15. April 1942
Uhrzeit (Absendung): 23.45 Uhr

KLARTEXT:

Nord-Atlantik, Quadrant AL 3572. Geleitzug HX-178 auf der britischen Versorgungsroute gesichtet. Kurs 270° (West), 24 Schiffe, Durchschnittsfahrt 6,7 kn. Starke Zerstörersicherung vorhanden.

Um 00.12 Uhr wurden vier elektrische Torpedos (G7e) aus den Bugrohren I und II sowie den Heckrohren V und VI auf Großziele abgefeuert. Zwei Tanker (geschätzt je 8.000 BRT) sowie ein Frachter vom Typ C3 (geschätzt 7.500 BRT) wurden durch Volltreffer versenkt. Sämtliche Torpedos detonierten planmäßig; keine Frühzünder.

Unmittelbar nach dem Schuss sofort auf Tauchstation gegangen. Jedoch Angriff durch die Sicherungszerstörer HMS Eskimo (Tribal-Klasse) und HMS Vanoc (V-Klasse) mit schweren Wasserbomben. Der Feind warf in vier getrennten Angriffswellen insgesamt 38 Wasserbomben. U-67 entkam durch sofortiges Abtauchen auf 160 m Tiefe und Ausmanövrieren unterhalb der Thermokline (Kaltwasserschicht) ohne schwerwiegende Schäden. Dennoch:

SCHADENSMELDUNG:

Bugsektion: Druckkörper leicht deformiert; Torpedorohre I und II außer Gefecht.

Hecksektion: Hydrophonanlage (GHG) vollständig ausgefallen; Undichtigkeit an der Wellenabdichtung des Antriebs festgestellt – geringer Wassereinbruch im E-Maschinenraum.

Tauchzellen: Keine kritischen Beschädigungen; jedoch ist die Tiefensteuerung nur noch manuell und in eingeschränktem Umfang funktionsfähig.

LAGEBEURTEILUNG:

Boot ist weiterhin seetüchtig. Keine Verluste unter der Besatzung (52 Mann). Aufgrund der erlittenen Schäden ist die offensive Angriffsfähigkeit jedoch vollständig erloschen. Die Höchstgeschwindigkeit über Wasser ist durch die beschädigte Welle auf 12 kn begrenzt. Treibstoffvorrat für die Rückfahrt ausreichend vorhanden.

ANTRAG:

Hiermit wird die sofortige Rückkehr zum U-Boot-Stützpunkt Lorient (Frankreich) beantragt. Für die Einfahrt in den gesicherten Bereich wird um Geleit- bzw. Sicherungsbegleitung (Sperrbrecher) zum Schutz vor feindlichen Minensperren gebeten.

Die Feindfahrt von U-67 wird hiermit beendet.

Kommandant: Kapitänleutnant Gerd Kelbling
(U-67 – Typ IXC, 2. U-Flottille "Saltzwedel")

Ende – F.d.U.
Glück ab!


********************************************************************************************************************************

Çeviride Dikkat Ettiğim Önemli Noktalar:

********************************************************************************************************************************

Adresleme: "Alan" kısmını resmî askerî formata uygun olarak "An: BdU" şeklinde yazdım. "Lorient Stützpunktquartier" ifadesi üs karargâhını net tanımlar.

Birimler ve Kısaltmalar: "GRT" yerine Almanca'daki resmî gemi tonaj birimi olan "BRT" (Bruttoregistertonnen) kullandım.

Teknik Terimler:

1."Hidrofon" sistemi için Alman denizaltılarında kullanılan resmî terim olan "GHG" (Gruppenhorchgerät)'yi terimini yazdım.

2."Termoklin" için Almanca karşılık olan "Thermokline" ve parantez içinde "Kaltwasserschicht" açıklamasını verdim.

Fiil Çekimleri ve Üslup: Rapor dilinde edilgen (passive) ve geçmiş zaman (Perfekt / Präteritum) kullanımına dikkat ederek, orijinal Türkçedeki "-mış / -mıştır" ekinin verdiği resmiyeti Almanca'da "wurden versenkt", "ist ausgefallen" gibi yapılarla birebir karşılaştırmaya çalıştım,umarım Türkçe'deki dili geçmiş zaman takısının birbirebir aynısıdır.

Protokol: Sonundaki "F.d.U." (Funkende) ve "Glück ab!" selamını aynen yazdım; bu, dönemin U-boat mürettebatı arasında standart bir selamlaşma/vedalaşma deyimi idi.

********************************************************************************************************************************

NOT :

Kapitänleutnant Gerd Otto Friedrich Kelbling Kimdir? (benim için efsanelerden biridir-TRWE_2012)
Resim
Resim
75 Yaşındaki Hali-Flottillenadmiral-

Kapitänleutnant Gerd Otto Friedrich Kelbling (12 Haziran 1915 - 9 Haziran 2005), II. Dünya Savaşı sırasında görev yapmış bir Alman deniz subayı ve U-boat komutanıdır.

Denizcilik Kariyeri

Kelbling, denizcilik kariyerine 1 Nisan 1933'te (Crew 1934) Kriegsmarine'e katılarak başladı. Subay adayı olarak "Gorch Fock" yelkenli gemisi, "Karlsruhe" hafif kruvazörü ve "Deutschland" zırhlı gemisi gibi çeşitli gemilerde eğitim aldı ve görev yaptı. 1934 ile 1940 yılları arasında mayın tarama gemilerinde hizmet veren Kelbling, 1 Eylül 1941'de Kapitänleutnant (Yüzbaşı) rütbesine terfi etti.

U-boat Komutanlığı

Ocak 1941'de Denizaltı Filosu'na (U-bootwaffe) transfer olan Kelbling, kısa bir süre U-557'de komutan adayı (Konfirmant) olarak bir devriyeye katıldıktan sonra, asıl şöhretini U-593 ile kazandı. Bu denizaltının komutasını 23 Ekim 1941'de devraldı ve toplamda 16 devriye gerçekleştirdi.

Atlantik'ten Akdeniz'e: U-593 ile ilk devriyesine Mart 1942'de çıkan Kelbling, üç Atlantik seferinin ardından Ekim 1942'de Cebelitarık Boğazı'nı geçerek denizaltısını Akdeniz'e getirdi ve burada 12 başarılı devriye daha gerçekleştirdi.

Başarıları ve Nişanları: Kariyeri boyunca 9 ticaret gemisi (38.290 GRT) ve 3 savaş gemisi (2.902 ton) batırdı. Bu başarıları nedeniyle 19 Ağustos 1943'te Almanya'nın en yüksek askeri nişanlarından biri olan Şövalye Haçı (Ritterkreuz) ile taltif edildi.

U-593'ün Batışı: 13 Aralık 1943'te, Batı Akdeniz'de 32 saat süren bir avın ardından İngiliz ve Amerikan muhripleri tarafından ağır hasar gören U-593, mürettebat tarafından batırıldı (scuttled). Kelbling ve 51 kişilik tayfasının tamamı kurtarılarak İngiliz ve Kanada esir kamplarına gönderildi.

Savaş Sonrası

Kelbling, savaş esiriyken Eylül 1947'ye kadar Kanada'da kaldı. Almanya'ya döndükten sonra mühendis olarak çalıştı ve 1964'te bir U-boat gazileri derneğine katıldı. Uzun bir yaşamın ardından 9 Haziran 2005'te, 90. doğum gününden sadece üç gün önce, Bavyera'daki Dießen am Ammersee'de hayatını kaybetti.


32saat Süren Bir Sürek Avı Başlamıştı, U-593'e Karşı-TRWE_2012-Hikaye Modu Anlatımı-


Başlangıç: 12 Aralık 1943, 23:00 (Gece)

U-593, Cezayir'in Bougie (şimdiki Bejaia) kenti açıklarında konvoya sızdı. Kelbling, su üstünden hızla yaklaşarak iki ayrı torpido salvosuyla muhripleri vurdu. Ancak en ölümcül büyük hatasını bu anda (bana göre) yaptı: Saldırıdan hemen sonra derine dalıp kaçmak yerine, bir süre periskop derinliğinde kalıp hasarı gözlemledi. Bu 5 dakikalık gecikme, konvoyun arka koruma gemilerinin Asdic (sonar) teması kurmasına yetmişti.

Kapanın Daralması (12-13 Aralık Gecesi)

Kelbling, 160 metreye daldı ve sustu. Ancak su üstünde, İngiliz 5. Muhrip Filosu'na bağlı üç gemi anında bölgeye kilitlendi:

HMS Keppel (Filo lideri)
HMS Wrestler (V-sınıfı muhrip)
HMS Rocket (R-sınıfı muhrip)

Ayrıca Amerikan donanmasına ait bir destroyer escort (USS Wainwright) da radar menzilinden takibe katıldı.

İlk gece (13 Aralık 01:00 - 06:00): Düşman, U-593'ün üzerinde 4 saat boyunca durmadan 25 adet su altı bombası attı. Kelbling, rota ve derinlik değiştirerek (Çark manevrası) çoğunu atlattı, ancak şiddetli patlamalar nedeniyle pervanelerde hafif eğilme ve pusulalarda sapma yaşandı.

Gündüz: Kaçışın İmkânsızlığı (13 Aralık, 08:00 - 16:00)

Gün doğumuyla birlikte Kelbling'in en büyük kabusu başladı. Akdeniz'in berrak sularında, 80 metre derinlikten bile periskopu havadan görülebiliyordu. İngiliz gemileri, U-593'ü denizaltı karşıtı "Krep" (Crep) taktiği ile kıstırdı:

Biri batıdan, diğeri doğudan, üçüncüsü güneyden sürekli sonar atışı yapıyor ve onu kuzeye, sığ sulara (kıyıya) doğru itmeye çalışıyorlardı.Kelbling, bunu hemen anlamıştı...

Kelbling, öğlen saatlerinde çaresiz kalarak 200 metre (Tip VIIC için azami test derinliği) derinliğe inmek zorunda kaldı (bu bir intihardı). Ancak bu derinlikte bile düşmanın hidrofonları (Asdic) onu net bir şekilde tespit ediyordu. "Derinlik bombaları o kadar yakına düşüyordu ki, floresan lambalar kırılıyor, mürettebat dişlerini sıkarak sessizce sayıyordu."

Son Perde: Pillerin Tükenmesi (13 Aralık, 16:30)

Geceyi sessizce beklemek isteyen Kelbling, su altında elektrik motorlarını çalıştırmak zorundaydı ama piller neredeyse sıfırdı. Ayrıca içerideki oksijen o kadar azalmıştı ki, mürettebat nefes almakta zorlanıyor, karbondioksit panik yaratıyordu. "Ya şarj etmek için yüzeye çıkacağız ya da 200 metre dibinde boğularak öleceğiz." dediği rivayet edilir.

Saat 17:00: U-593, Bougie'nin 40 mil kuzeyinde, zorunlu olarak yüzeye çıktı. Kelbling, dizel motorları çalıştırarak kaçmaya çalıştı. Ancak tam o sırada HMS Keppel ve HMS Wrestler, radar ekranında parlayan bu hedefi gördü.

İmha (13 Aralık, 17:15)

İngiliz muhripleri, iki taraftan 8.000 metre mesafeden ana bataryalarıyla ateş açtı. İlk salvodan sonra U-593'ün kumanda kulesi (taret) parçalandı. İkinci salvo gövdeyi yardı. Kelbling anında "Battırmayın, teslim oluyoruz!" işareti yaparak beyaz bayrak çekti ve "Alle Mann von Bord!" (Herkes gemiyi terk etsin!) emrini verdi. Mürettebat soğuk Aralık sularına atladı.

İngilizler, yaralı denizaltıyı ele geçirmek istese de, U-593'ün açık olan hava vanalarından su alarak batmaya başlaması üzerine, son bir torpido ile bitirilmesine karar verildi. Ancak torpido gerekmedi; denizaltı iki dakika içinde sulara gömüldü.

Kurtarma ve Esaret

52 kişilik mürettebattan 49'u (Kelbling dahil) İngilizler tarafından sudan çıkarıldı. 3 denizci soğuktan veya şarapnel parçalarından hayatını kaybetti. Kelbling, İngiliz komutanı Kaptan Peter Gretton'a teslim olurken, "Sizi 32 saat boyunca atlatacağımı sanmıştım, ama Akdeniz sizin lehinize çalışıyor." dediği söylenir.

Böylece, Kapitänleutnant Gerd Kelbling için savaş 13 Aralık 1943 akşamı sona erdi ve Kanada'daki esir kampına giden yol başladı. Bu 32 saat, hem U-593'ün hem de Kelbling'in kaderini belirleyen, Atlantik ve Akdeniz denizaltı savaş tarihinin en dramatik "kedi-fare" oyunlarından biri olarak kayıtlara geçti.

Bundan bir sinema flimi bile çıkar...

Flim'in adı : Akdeniz'de 32 Saat Kedi-Fare Oyunu....!! yada Akdeniz'de Ölüm'ün Kıyısında 32 Saat... şeklinde...
Kullanıcı avatarı
burak35
Zettabyte3
Zettabyte3
Mesajlar: 17817
Kayıt: 07 Eki 2016, 13:06
cinsiyet: Erkek
Teşekkür etti: 10282 kez
Teşekkür edildi: 12024 kez

Re: TRWE_2012-Nazi Almanya'sı- Enigma Makinesi PS1 Betiği Geliştiriyor

Mesaj gönderen burak35 »

enigma diyince aklıma bu geldi.


Kullanıcı avatarı
TRWE_2012
Zettabyte1
Zettabyte1
Mesajlar: 15418
Kayıt: 25 Eyl 2013, 13:38
cinsiyet: Erkek
Teşekkür etti: 2618 kez
Teşekkür edildi: 5490 kez

Oldu Gibi...! :)

Mesaj gönderen TRWE_2012 »

Merhabalar

Sürüm 7.seviyeye ulaştık, galiba olduğu gibi...

Şimdiye kadar ki sürümler :

C:\Users\TRWE_2012\Masaüstü\ENİGMA PROJESİ-SİLME-\Enigma Cipher_v1.0.ps1
C:\Users\TRWE_2012\Masaüstü\ENİGMA PROJESİ-SİLME-\Enigma Cipher_v2.0.ps1
C:\Users\TRWE_2012\Masaüstü\ENİGMA PROJESİ-SİLME-\Enigma Cipher_v3.0.ps1
C:\Users\TRWE_2012\Masaüstü\ENİGMA PROJESİ-SİLME-\Enigma Cipher_v4.0.ps1
C:\Users\TRWE_2012\Masaüstü\ENİGMA PROJESİ-SİLME-\Enigma Cipher_v5.0.ps1
C:\Users\TRWE_2012\Masaüstü\ENİGMA PROJESİ-SİLME-\Enigma Cipher_v6.0.ps1

Enigma Cipher_v7.0.ps1

Kod: Tümünü seç

<#
.SYNOPSIS
    Historical Enigma machine simulator (encryption and decryption),
    supporting both the 3-rotor Wehrmacht/M3 Enigma and the 4-rotor
    Kriegsmarine Naval Enigma M4 used on U-boats from 1942 onward.

.DESCRIPTION
    Implements the classic Enigma cipher: rotor wiring, ring settings
    (Ringstellung), initial rotor positions (Grundstellung), a plugboard
    (Steckerbrett), and a reflector, including the historical double-
    stepping anomaly of the middle rotor.

    M3 mode: 3 rotors chosen from I-V, wide reflector B or C.
    M4 mode: 3 rotors chosen from I-VIII (naval rotors VI-VIII have two
    turnover notches each), plus a static 4th "Greek" rotor (Beta or
    Gamma) next to a thin reflector (B-THIN or C-THIN). The Greek rotor
    never steps, exactly like the real U-boat machine.

    Enigma is a reciprocal cipher: running the SAME configuration (model,
    rotor order, ring settings, start position, Greek rotor if M4,
    plugboard pairs, reflector) over ciphertext returns the original
    plaintext.

.PARAMETER InputFile
    Path to a .txt file containing the text to process. When supplied, the
    script skips the interactive prompt entirely and processes the whole
    file in one pass -- the reliable way to handle very large texts, since
    pasting huge blocks into Read-Host can truncate or corrupt input.

.PARAMETER OutputFile
    Path for the continuous ciphertext/plaintext result when -InputFile is
    used. Two companion files are also written next to it automatically:
    "<name>_prepared.txt" (cleaned input actually fed to the rotors) and
    "<name>_grouped.txt" (same result split into 5-letter radio groups).
    If omitted, defaults to "<InputFile-name>_enigma.txt" in the same folder.

.NOTES
    The alphabet is restricted to A-Z (26 letters), matching the physical
    machine. Input is uppercased; spaces and punctuation are stripped;
    accented letters are folded to their closest plain A-Z equivalent;
    digits are converted to spoken German radio words (2 -> ZWO, 5 -> FUENF)
    instead of being dropped. Wrap a code in [BRACKETS] to spell it out
    fully using the Kriegsmarine spelling alphabet, e.g. [HX-2E] becomes
    HEINRICH XANTHIPPE ZWO EMIL before encryption.

.EXAMPLE
    .\Enigma-Cipher.ps1
    Interactive mode: configure the machine, then type/paste messages one
    at a time.

.EXAMPLE
    .\Enigma-Cipher.ps1 -InputFile "C:\Messages\report.txt" -OutputFile "C:\Messages\report_out.txt"
    Batch mode: configure the machine once, then the entire file is
    processed in a single pass -- recommended for very large texts.
#>

[CmdletBinding()]
param(
    [string]$InputFile,
    [string]$OutputFile
)

$ErrorActionPreference = "Stop"

# Force UTF-8 for both directions so Turkish characters (c-cedilla, g-breve,
# dotless-i, o/u-umlaut, s-cedilla) are read from and written to the console
# correctly, regardless of the system's active codepage.
try {
    [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
    [Console]::InputEncoding  = [System.Text.Encoding]::UTF8
} catch {
    # Some hosts (e.g. the PowerShell ISE) don't allow changing console
    # encoding; safe to ignore, the trap below still protects the session.
}

# Safety net: if ANYTHING unexpected goes wrong anywhere below, show the
# error instead of letting the console window vanish silently.
trap {
    Write-Host ""
    Write-Host "=== UNEXPECTED ERROR ==="
    Write-Host $_.Exception.Message
    Write-Host ""
    Write-Host "The window is being kept open so you can read this message."
    Read-Host "`nPress ENTER to exit."
    exit 1
}

# --- Historical rotor wirings (Wehrmacht Enigma I + Kriegsmarine naval rotors) ---
# Rotors VI, VII, VIII (naval only) each have TWO turnover notches instead of one.
$RotorDefs = @{
    "I"    = @{ Wiring = "EKMFLGDQVZNTOWYHXUSPAIBRCJ"; Notches = @("Q") }
    "II"   = @{ Wiring = "AJDKSIRUXBLHWTMCQGZNPYFVOE"; Notches = @("E") }
    "III"  = @{ Wiring = "BDFHJLCPRTXVZNYEIWGAKMUSQO"; Notches = @("V") }
    "IV"   = @{ Wiring = "ESOVPZJAYQUIRHXLNFTGKDCMWB"; Notches = @("J") }
    "V"    = @{ Wiring = "VZBRGITYUPSDNHLXAWMJQOFECK"; Notches = @("Z") }
    "VI"   = @{ Wiring = "JPGVOUMFYQBENHZRDKASXLICTW"; Notches = @("Z", "M") }
    "VII"  = @{ Wiring = "NZJHGRCXMYSWBOUFAIVLPEKQDT"; Notches = @("Z", "M") }
    "VIII" = @{ Wiring = "FKQHTLXOCBJSPDZRAMEWNIUYGV"; Notches = @("Z", "M") }
}

# Beta and Gamma: the non-stepping 4th ("Greek") rotor used only on the naval
# M4 machine. It sits next to the reflector, has a ring setting like a normal
# rotor, but is never advanced by the stepping mechanism.
$GreekDefs = @{
    "BETA"  = "LEYJVCNIXWPBQMDRTAKZGFUHOS"
    "GAMMA" = "FSOKANUERHMBTIYCWLQPZXVGJD"
}

$ReflectorDefs = @{
    "B"      = "YRUHQSLDPXNGOKMIEBFZCWVJAT"
    "C"      = "FVPJIAOYEDRZXWGCTKUQSBNMHL"
    "B-THIN" = "ENKQAUYWJICOPBLMDXZVFTHRGS"
    "C-THIN" = "RDOBJNTKVEHMLFCWZAXGYIPSUQ"
}

$Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

# Turkish-to-plain character folding table, built from Unicode code points
# to avoid embedding accented characters directly in this source file.
$FoldMap = @{
    [char]0x00E7 = "C"; [char]0x00C7 = "C"   # c with cedilla
    [char]0x011F = "G"; [char]0x011E = "G"   # g with breve
    [char]0x0131 = "I"; [char]0x0130 = "I"   # dotless / dotted i
    [char]0x00F6 = "O"; [char]0x00D6 = "O"   # o with diaeresis
    [char]0x015F = "S"; [char]0x015E = "S"   # s with cedilla
    [char]0x00FC = "U"; [char]0x00DC = "U"   # u with diaeresis
}

# German military radio digit words. "2" is spoken "ZWO" instead of "ZWEI",
# the real historical convention used to avoid confusion with "DREI" (3)
# over noisy radio traffic.
$DigitWords = @{
    '0' = "NULL";  '1' = "EINS";   '2' = "ZWO";  '3' = "DREI"; '4' = "VIER"
    '5' = "FUENF"; '6' = "SECHS";  '7' = "SIEBEN"; '8' = "ACHT"; '9' = "NEUN"
}

# Kriegsmarine spelling alphabet (Buchstabiertafel), used to unambiguously
# spell out call signs, grid references and convoy designators letter by
# letter over the radio.
$SpellingAlphabet = @{
    'A' = "ANTON";  'B' = "BERTA";     'C' = "CAESAR";  'D' = "DORA"
    'E' = "EMIL";   'F' = "FRIEDRICH"; 'G' = "GUSTAV";  'H' = "HEINRICH"
    'I' = "IDA";    'J' = "JULIUS";    'K' = "KAUFMANN"; 'L' = "LUDWIG"
    'M' = "MARTHA"; 'N' = "NORDPOL";   'O' = "OTTO";    'P' = "PAULA"
    'Q' = "QUELLE"; 'R' = "RICHARD";   'S' = "SAMUEL";  'T' = "TONI"
    'U' = "ULRICH"; 'V' = "VIKTOR";    'W' = "WILHELM"; 'X' = "XANTHIPPE"
    'Y' = "YPSILON"; 'Z' = "ZEPPELIN"
}

function ConvertTo-EnigmaAlphabet {
    param([string]$Text)
    $sb = New-Object System.Text.StringBuilder
    foreach ($ch in $Text.ToUpperInvariant().ToCharArray()) {
        if ($FoldMap.ContainsKey($ch)) {
            [void]$sb.Append($FoldMap[$ch])
        } elseif ($ch -ge 'A' -and $ch -le 'Z') {
            [void]$sb.Append($ch)
        }
        # anything else (spaces, digits, punctuation) is dropped
    }
    return $sb.ToString()
}

function ConvertTo-RadioDigits {
    # Replaces every digit character anywhere in the text with its spoken
    # German radio word, so numbers survive instead of being silently
    # dropped (the real Enigma keyboard had no digit keys).
    param([string]$Text)
    $sb = New-Object System.Text.StringBuilder
    foreach ($ch in $Text.ToCharArray()) {
        $key = [string]$ch
        if ($DigitWords.ContainsKey($key)) {
            [void]$sb.Append(" ")
            [void]$sb.Append($DigitWords[$key])
            [void]$sb.Append(" ")
        } else {
            [void]$sb.Append($ch)
        }
    }
    return $sb.ToString()
}

function Expand-SpellingBrackets {
    # Any [BRACKETED] segment is expanded letter-by-letter and digit-by-
    # digit using the Kriegsmarine spelling alphabet, e.g. [HX-2E] becomes
    # "HEINRICH XANTHIPPE ZWO EMIL". Use this around call signs, convoy
    # codes or grid references you want spelled out unambiguously.
    param([string]$Text)
    $pattern = '\[([^\]]+)\]'
    $evaluator = {
        param($match)
        $inner = $match.Groups[1].Value.ToUpperInvariant()
        $words = @()
        foreach ($ch in $inner.ToCharArray()) {
            $key = [string]$ch
            if ($Script:DigitWords.ContainsKey($key)) {
                $words += $Script:DigitWords[$key]
            } elseif ($ch -ge 'A' -and $ch -le 'Z') {
                $words += $Script:SpellingAlphabet[$key]
            }
        }
        return " " + ($words -join " ") + " "
    }
    return [regex]::Replace($Text, $pattern, $evaluator)
}

function Format-Grouped {
    # Splits ciphertext/plaintext into historical 5-letter radio groups.
    param([string]$Text, [int]$GroupSize = 5)
    if ([string]::IsNullOrEmpty($Text)) { return "" }
    $groups = New-Object System.Collections.Generic.List[string]
    for ($i = 0; $i -lt $Text.Length; $i += $GroupSize) {
        $len = [Math]::Min($GroupSize, $Text.Length - $i)
        $groups.Add($Text.Substring($i, $len))
    }
    return ($groups -join " ")
}

function New-Rotor {
    param([string]$Name, [int]$RingSetting, [char]$StartPosition)
    $def = $RotorDefs[$Name]
    return [PSCustomObject]@{
        Name     = $Name
        Wiring   = $def.Wiring
        Notches  = $def.Notches
        Ring     = $RingSetting
        Position = [int][char]$StartPosition - [int][char]'A'
    }
}

function New-GreekRotor {
    # The 4th M4 rotor: has wiring and a ring setting like a normal rotor,
    # but no notches and is never stepped.
    param([string]$Name, [int]$RingSetting, [char]$StartPosition)
    return [PSCustomObject]@{
        Name     = $Name
        Wiring   = $GreekDefs[$Name]
        Notches  = @()
        Ring     = $RingSetting
        Position = [int][char]$StartPosition - [int][char]'A'
    }
}

function Step-Rotor {
    param($Rotor)
    $Rotor.Position = ($Rotor.Position + 1) % 26
}

function Test-AtNotch {
    param($Rotor)
    foreach ($notch in $Rotor.Notches) {
        $notchIndex = [int][char]$notch - [int][char]'A'
        if ($Rotor.Position -eq $notchIndex) { return $true }
    }
    return $false
}

function Step-Rotors {
    param($Left, $Middle, $Right)
    $middleAtNotch = Test-AtNotch -Rotor $Middle
    $rightAtNotch  = Test-AtNotch -Rotor $Right

    if ($middleAtNotch) {
        Step-Rotor -Rotor $Left
        Step-Rotor -Rotor $Middle
    } elseif ($rightAtNotch) {
        Step-Rotor -Rotor $Middle
    }
    Step-Rotor -Rotor $Right
}

function Invoke-RotorForward {
    param($Rotor, [int]$Index)
    $offset  = $Rotor.Position - ($Rotor.Ring - 1)
    $shifted = (($Index + $offset) % 26 + 26) % 26
    $mapped  = [int][char]$Rotor.Wiring[$shifted] - [int][char]'A'
    return (($mapped - $offset) % 26 + 26) % 26
}

function Invoke-RotorBackward {
    param($Rotor, [int]$Index)
    $offset  = $Rotor.Position - ($Rotor.Ring - 1)
    $shifted = (($Index + $offset) % 26 + 26) % 26
    $mapped  = $Rotor.Wiring.IndexOf([char]([int][char]'A' + $shifted))
    return (($mapped - $offset) % 26 + 26) % 26
}

function Invoke-Plugboard {
    param([hashtable]$Plugboard, [int]$Index)
    $letter = $Alphabet[$Index]
    if ($Plugboard.ContainsKey($letter)) {
        return [int][char]$Plugboard[$letter] - [int][char]'A'
    }
    return $Index
}

function Invoke-EnigmaChar {
    param($Left, $Middle, $Right, $Greek, [string]$ReflectorWiring, [hashtable]$Plugboard, [char]$Char)

    Step-Rotors -Left $Left -Middle $Middle -Right $Right

    $idx = [int][char]$Char - [int][char]'A'
    $idx = Invoke-Plugboard -Plugboard $Plugboard -Index $idx

    $idx = Invoke-RotorForward -Rotor $Right  -Index $idx
    $idx = Invoke-RotorForward -Rotor $Middle -Index $idx
    $idx = Invoke-RotorForward -Rotor $Left   -Index $idx
    if ($Greek) { $idx = Invoke-RotorForward -Rotor $Greek -Index $idx }

    $idx = [int][char]$ReflectorWiring[$idx] - [int][char]'A'

    if ($Greek) { $idx = Invoke-RotorBackward -Rotor $Greek -Index $idx }
    $idx = Invoke-RotorBackward -Rotor $Left   -Index $idx
    $idx = Invoke-RotorBackward -Rotor $Middle -Index $idx
    $idx = Invoke-RotorBackward -Rotor $Right  -Index $idx

    $idx = Invoke-Plugboard -Plugboard $Plugboard -Index $idx

    return $Alphabet[$idx]
}

function Invoke-EnigmaText {
    param($Left, $Middle, $Right, $Greek, [string]$ReflectorWiring, [hashtable]$Plugboard, [string]$Text, [switch]$ShowProgress)
    $expanded  = Expand-SpellingBrackets -Text $Text
    $radioized = ConvertTo-RadioDigits -Text $expanded
    $clean     = ConvertTo-EnigmaAlphabet -Text $radioized

    $total = $clean.Length
    $sb = New-Object System.Text.StringBuilder($total)
    $i = 0
    foreach ($ch in $clean.ToCharArray()) {
        [void]$sb.Append((Invoke-EnigmaChar -Left $Left -Middle $Middle -Right $Right -Greek $Greek -ReflectorWiring $ReflectorWiring -Plugboard $Plugboard -Char $ch))
        $i++
        if ($ShowProgress -and $total -gt 0 -and ($i % 500 -eq 0 -or $i -eq $total)) {
            $pct = [Math]::Min(100, [int](($i / $total) * 100))
            Write-Progress -Activity "Processing through Enigma" -Status "$i / $total letters" -PercentComplete $pct
        }
    }
    if ($ShowProgress) { Write-Progress -Activity "Processing through Enigma" -Completed }

    return [PSCustomObject]@{
        Clean  = $clean
        Output = $sb.ToString()
    }
}

function Read-RotorChoice {
    param([string]$Label, [string[]]$ValidNames, [string[]]$Exclude)
    $choice = $null
    $optionsText = $ValidNames -join " / "
    do {
        $raw = (Read-Host "$Label rotor ($optionsText)").ToUpperInvariant()
        if ($Exclude -contains $raw) {
            Write-Host "That rotor is already used, pick a different one."
        } elseif ($ValidNames -notcontains $raw) {
            Write-Host "Invalid rotor name."
        } else {
            $choice = $raw
        }
    } while (-not $choice)
    return $choice
}

function Read-GreekChoice {
    $choice = $null
    do {
        $raw = (Read-Host "Greek (4th) rotor (BETA / GAMMA)").ToUpperInvariant()
        if ($GreekDefs.ContainsKey($raw)) { $choice = $raw }
        else { Write-Host "Invalid choice, enter BETA or GAMMA." }
    } while (-not $choice)
    return $choice
}

function Read-RingSetting {
    param([string]$Label)
    $result = $null
    do {
        $raw = Read-Host "$Label ring setting (1-26)"
        $parsed = 0
        $ok = [int]::TryParse($raw, [ref]$parsed) -and ($parsed -ge 1) -and ($parsed -le 26)
        if (-not $ok) {
            Write-Host "Enter a number between 1 and 26."
        } else {
            $result = $parsed
        }
    } while (-not $result)
    return $result
}

function Read-StartPosition {
    param([string]$Label)
    $result = $null
    do {
        $raw = (Read-Host "$Label start position (A-Z)").ToUpperInvariant()
        $ok = ($raw.Length -eq 1) -and ($raw[0] -ge 'A') -and ($raw[0] -le 'Z')
        if (-not $ok) {
            Write-Host "Enter a single letter A-Z."
        } else {
            $result = $raw[0]
        }
    } while (-not $result)
    return [char]$result
}

function Read-Plugboard {
    $plugboard = @{}
    Write-Host ""
    Write-Host "Plugboard setup (Steckerbrett): enter letter pairs, e.g. AB then CD."
    Write-Host "Leave blank and press ENTER when done (max 10 pairs)."
    $count = 0
    while ($count -lt 10) {
        $raw = (Read-Host "Pair $($count + 1)").ToUpperInvariant().Trim()
        if ([string]::IsNullOrEmpty($raw)) { break }
        if ($raw.Length -ne 2 -or $raw[0] -eq $raw[1]) {
            Write-Host "Invalid pair, must be two different letters. Try again."
            continue
        }
        $a = $raw[0]; $b = $raw[1]
        if ($plugboard.ContainsKey($a) -or $plugboard.ContainsKey($b)) {
            Write-Host "One of these letters is already plugged. Try again."
            continue
        }
        $plugboard[$a] = $b
        $plugboard[$b] = $a
        $count++
    }
    return $plugboard
}

function Save-SessionSettings {
    param(
        [string]$Path, [string]$Model,
        [string]$LeftName, [string]$MiddleName, [string]$RightName,
        [int]$LeftRing, [int]$MiddleRing, [int]$RightRing,
        [char]$LeftStart, [char]$MiddleStart, [char]$RightStart,
        [string]$GreekName, $GreekRing, $GreekStart,
        [string]$Reflector, [hashtable]$Plugboard
    )
    $lines = New-Object System.Collections.Generic.List[string]
    $lines.Add("=== ENIGMA SESSION ===")
    $lines.Add("Model: $Model")
    $lines.Add("LeftRotor: $LeftName")
    $lines.Add("MiddleRotor: $MiddleName")
    $lines.Add("RightRotor: $RightName")
    $lines.Add("LeftRing: $LeftRing")
    $lines.Add("MiddleRing: $MiddleRing")
    $lines.Add("RightRing: $RightRing")
    $lines.Add("LeftStart: $LeftStart")
    $lines.Add("MiddleStart: $MiddleStart")
    $lines.Add("RightStart: $RightStart")
    if ($Model -eq "M4") {
        $lines.Add("GreekRotor: $GreekName")
        $lines.Add("GreekRing: $GreekRing")
        $lines.Add("GreekStart: $GreekStart")
    }
    $lines.Add("Reflector: $Reflector")
    $plugText = "(none)"
    if ($Plugboard.Count -gt 0) {
        $pairs = $Plugboard.GetEnumerator() | Where-Object { $_.Key -lt $_.Value } | ForEach-Object { "$($_.Key)$($_.Value)" }
        $plugText = $pairs -join " "
    }
    $lines.Add("Plugboard: $plugText")
    $lines.Add("=== MESSAGES ===")
    Set-Content -Path $Path -Value $lines -Encoding UTF8
}

function Add-SessionMessage {
    param([string]$Path, [string]$Prepared, [string]$Output, [string]$Grouped)
    $stamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $lines = @(
        "[$stamp] PREPARED: $Prepared",
        "[$stamp] OUTPUT  : $Output",
        "[$stamp] GROUPED : $Grouped",
        ""
    )
    Add-Content -Path $Path -Value $lines -Encoding UTF8
}

function Read-SessionFile {
    param([string]$Path)
    $content = Get-Content -Path $Path -Encoding UTF8
    $settings = @{}
    $messages = New-Object System.Collections.Generic.List[string]
    $inMessages = $false
    foreach ($line in $content) {
        if ($line -eq "=== MESSAGES ===") { $inMessages = $true; continue }
        if ($line -eq "=== ENIGMA SESSION ===") { continue }
        if ($inMessages) {
            if (-not [string]::IsNullOrWhiteSpace($line)) { $messages.Add($line) }
        } elseif ($line -match "^([A-Za-z]+):\s*(.*)$") {
            $settings[$Matches[1]] = $Matches[2].Trim()
        }
    }
    return [PSCustomObject]@{
        Settings = $settings
        Messages = $messages
    }
}

# --- Main ---
Write-Host "=== Enigma Machine Simulator ==="
Write-Host "(Wehrmacht Enigma I / M3, or 4-rotor Kriegsmarine Naval Enigma M4)"
Write-Host ""

$ScriptDir = $PSScriptRoot
if ([string]::IsNullOrEmpty($ScriptDir) -and $MyInvocation.MyCommand.Path) {
    $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
}
if ([string]::IsNullOrEmpty($ScriptDir)) { $ScriptDir = (Get-Location).Path }
$SessionFilePath = Join-Path $ScriptDir "Encrypted Text Document.txt"

$resumed = $false

if (Test-Path $SessionFilePath) {
    Write-Host "Found a previous session file next to the script:"
    Write-Host "  $SessionFilePath"
    $answer = Read-Host "Load its settings and continue that session? (Y/N)"
    if ($answer -eq "Y" -or $answer -eq "y") {
        $session = Read-SessionFile -Path $SessionFilePath
        $s = $session.Settings

        $model       = $s["Model"]
        $leftName    = $s["LeftRotor"]
        $middleName  = $s["MiddleRotor"]
        $rightName   = $s["RightRotor"]
        $leftRing    = [int]$s["LeftRing"]
        $middleRing  = [int]$s["MiddleRing"]
        $rightRing   = [int]$s["RightRing"]
        $leftStart   = [char]$s["LeftStart"]
        $middleStart = [char]$s["MiddleStart"]
        $rightStart  = [char]$s["RightStart"]

        $greekName  = $null
        $greekRing  = $null
        $greekStart = $null
        if ($model -eq "M4") {
            $greekName  = $s["GreekRotor"]
            $greekRing  = [int]$s["GreekRing"]
            $greekStart = [char]$s["GreekStart"]
        }

        $reflectorChoice = $s["Reflector"]

        $plugboard = @{}
        $plugRaw = $s["Plugboard"]
        if ($plugRaw -and $plugRaw -ne "(none)") {
            foreach ($pair in ($plugRaw -split '\s+')) {
                if ($pair.Length -eq 2) {
                    $plugboard[$pair[0]] = $pair[1]
                    $plugboard[$pair[1]] = $pair[0]
                }
            }
        }

        $resumed = $true
        Write-Host ""
        Write-Host "Settings restored from the session file."
    } else {
        Write-Host "Starting a new session (the old file will be overwritten once configured)."
    }
    Write-Host ""
}

if (-not $resumed) {
    $model = $null
    do {
        $raw = (Read-Host "Machine model (M3 = 3-rotor / M4 = 4-rotor naval)").ToUpperInvariant()
        if ($raw -eq "M3" -or $raw -eq "M4") { $model = $raw }
        else { Write-Host "Invalid choice, enter M3 or M4." }
    } while (-not $model)

    if ($model -eq "M4") {
        $rotorPool = @("I", "II", "III", "IV", "V", "VI", "VII", "VIII")
    } else {
        $rotorPool = @("I", "II", "III", "IV", "V")
    }

    $leftName   = Read-RotorChoice -Label "Left (slowest)"  -ValidNames $rotorPool -Exclude @()
    $middleName = Read-RotorChoice -Label "Middle"          -ValidNames $rotorPool -Exclude @($leftName)
    $rightName  = Read-RotorChoice -Label "Right (fastest)" -ValidNames $rotorPool -Exclude @($leftName, $middleName)

    $leftRing   = Read-RingSetting -Label "Left rotor"
    $middleRing = Read-RingSetting -Label "Middle rotor"
    $rightRing  = Read-RingSetting -Label "Right rotor"

    $leftStart   = Read-StartPosition -Label "Left rotor"
    $middleStart = Read-StartPosition -Label "Middle rotor"
    $rightStart  = Read-StartPosition -Label "Right rotor"

    $greekName  = $null
    $greekRing  = $null
    $greekStart = $null
    if ($model -eq "M4") {
        $greekName  = Read-GreekChoice
        $greekRing  = Read-RingSetting -Label "Greek (4th) rotor"
        $greekStart = Read-StartPosition -Label "Greek (4th) rotor"
    }

    $reflectorPool = @("B", "C")
    if ($model -eq "M4") { $reflectorPool = @("B-THIN", "C-THIN") }

    $reflectorChoice = $null
    do {
        $optionsText = $reflectorPool -join " / "
        $raw = (Read-Host "Reflector ($optionsText)").ToUpperInvariant()
        if ($reflectorPool -contains $raw) { $reflectorChoice = $raw }
        else { Write-Host "Invalid reflector, choose $optionsText." }
    } while (-not $reflectorChoice)

    $plugboard = Read-Plugboard
}

Write-Host ""
Write-Host "--- Machine configuration ---"
Write-Host "Model         : $model"
Write-Host "Rotors (L-M-R): $leftName-$middleName-$rightName"
Write-Host "Ring settings : $leftRing-$middleRing-$rightRing"
Write-Host "Start position: $leftStart$middleStart$rightStart"
if ($model -eq "M4") {
    Write-Host "Greek rotor   : $greekName (ring $greekRing, start $greekStart)"
}
Write-Host "Reflector     : $reflectorChoice"
$plugText = "(none)"
if ($plugboard.Count -gt 0) {
    $pairs = $plugboard.GetEnumerator() | Where-Object { $_.Key -lt $_.Value } | ForEach-Object { "$($_.Key)$($_.Value)" }
    $plugText = $pairs -join " "
}
Write-Host "Plugboard     : $plugText"
Write-Host ""
Write-Host "NOTE: to decrypt later, start a fresh run with the exact same"
Write-Host "model, rotor order, ring settings, start position, Greek rotor"
Write-Host "(if M4) and plugboard pairs, then feed it the ciphertext. Enigma"
Write-Host "is reciprocal: identical settings that encrypt will also decrypt."
Write-Host "Session file (settings + ciphertext log) is saved next to this"
Write-Host "script at: $SessionFilePath"
Write-Host ""

$Left   = New-Rotor -Name $leftName   -RingSetting $leftRing   -StartPosition $leftStart
$Middle = New-Rotor -Name $middleName -RingSetting $middleRing -StartPosition $middleStart
$Right  = New-Rotor -Name $rightName  -RingSetting $rightRing  -StartPosition $rightStart
$Greek  = $null
if ($model -eq "M4") {
    $Greek = New-GreekRotor -Name $greekName -RingSetting $greekRing -StartPosition $greekStart
}

if (-not $resumed) {
    Save-SessionSettings -Path $SessionFilePath -Model $model `
        -LeftName $leftName -MiddleName $middleName -RightName $rightName `
        -LeftRing $leftRing -MiddleRing $middleRing -RightRing $rightRing `
        -LeftStart $leftStart -MiddleStart $middleStart -RightStart $rightStart `
        -GreekName $greekName -GreekRing $greekRing -GreekStart $greekStart `
        -Reflector $reflectorChoice -Plugboard $plugboard
} elseif ($session.Messages.Count -gt 0) {
    Write-Host "--- Ciphertext from the previous session ---"
    foreach ($m in $session.Messages) { Write-Host $m }
    Write-Host ""
}

if ($InputFile) {
    if (-not (Test-Path $InputFile)) {
        Write-Host "Input file not found: $InputFile"
        Read-Host "`nPress ENTER to exit."
        exit
    }
    if (-not $OutputFile) {
        $dir  = Split-Path -Parent $InputFile
        $base = [System.IO.Path]::GetFileNameWithoutExtension($InputFile)
        $OutputFile = Join-Path $dir "$base`_enigma.txt"
    }

    Write-Host "Reading input file: $InputFile"
    $rawText = Get-Content -Path $InputFile -Raw -Encoding UTF8
    Write-Host "Source length: $($rawText.Length) characters. Processing..."
    Write-Host ""

    $result = Invoke-EnigmaText -Left $Left -Middle $Middle -Right $Right -Greek $Greek -ReflectorWiring $ReflectorDefs[$reflectorChoice] -Plugboard $plugboard -Text $rawText -ShowProgress

    $groupedOutput = Format-Grouped -Text $result.Output -GroupSize 5
    $dir  = Split-Path -Parent $OutputFile
    $base = [System.IO.Path]::GetFileNameWithoutExtension($OutputFile)
    $preparedPath = Join-Path $dir "$base`_prepared.txt"
    $groupedPath  = Join-Path $dir "$base`_grouped.txt"

    Set-Content -Path $OutputFile   -Value $result.Output -Encoding UTF8
    Set-Content -Path $preparedPath -Value $result.Clean  -Encoding UTF8
    Set-Content -Path $groupedPath  -Value $groupedOutput -Encoding UTF8
    Add-SessionMessage -Path $SessionFilePath -Prepared $result.Clean -Output $result.Output -Grouped $groupedOutput

    Write-Host "Done. $($result.Clean.Length) letters processed."
    Write-Host "Continuous output : $OutputFile"
    Write-Host "Prepared text     : $preparedPath"
    Write-Host "Grouped output    : $groupedPath"
    Write-Host ""
    Read-Host "`nPress ENTER to exit."
    exit
}

Write-Host "TIP: digits are auto-converted to spoken words (2 -> ZWO, 5 -> FUENF...)."
Write-Host "TIP: wrap codes in brackets to spell them out, e.g. [HX-2E] becomes"
Write-Host "     HEINRICH XANTHIPPE ZWO EMIL before encryption."
Write-Host "TIP: for very large texts, re-run with -InputFile / -OutputFile"
Write-Host "     instead of pasting into the console (avoids paste truncation)."
Write-Host ""

while ($true) {
    Write-Host "Text to process - paste one or several lines (blank lines inside are fine)."
    Write-Host "Type END on its own line when finished. Press ENTER on an empty first line to exit."
    $firstLine = Read-Host
    if ([string]::IsNullOrEmpty($firstLine)) { break }

    # Read-Host only ever returns ONE line. A multi-line paste is delivered
    # to the console as that many separate Enter-terminated lines, so we
    # keep calling Read-Host until the user (or the pasted block itself)
    # supplies the END sentinel. This is what lets a long, multi-paragraph
    # message like a full Funkspruch be pasted safely without truncation.
    #
    # If the clipboard content has no trailing newline after its last line,
    # the END you type afterward lands glued onto that same line (e.g.
    # "Gluck ab! END") instead of on its own line. The regex below still
    # recognizes END as a whole word at the end of the line in that case,
    # keeps whatever text came before it, and stops waiting.
    $lines = New-Object System.Collections.Generic.List[string]
    $lines.Add($firstLine)
    $stillReading = $true
    while ($stillReading) {
        $line = Read-Host
        if ($line -eq "END") { break }
        if ($line -match '^(?<content>.*?)\s*\bEND\b\s*$') {
            $before = $Matches["content"]
            if (-not [string]::IsNullOrEmpty($before)) { $lines.Add($before) }
            $stillReading = $false
        } else {
            $lines.Add($line)
        }
    }
    $text = $lines -join " "

    try {
        $result = Invoke-EnigmaText -Left $Left -Middle $Middle -Right $Right -Greek $Greek -ReflectorWiring $ReflectorDefs[$reflectorChoice] -Plugboard $plugboard -Text $text -ShowProgress:($text.Length -gt 2000)

        $groupedResult = Format-Grouped -Text $result.Output -GroupSize 5
        Write-Host "Prepared text      : $($result.Clean)"
        Write-Host "Result (continuous): $($result.Output)"
        Write-Host "Result (grouped)   : $groupedResult"
        Write-Host ""

        Add-SessionMessage -Path $SessionFilePath -Prepared $result.Clean -Output $result.Output -Grouped $groupedResult
    } catch {
        Write-Host ""
        Write-Host "ERROR while processing this message: $($_.Exception.Message)"
        Write-Host "Nothing was saved for this message. You can try again below."
        Write-Host ""
    }
}

Read-Host "`nPress ENTER to exit."
ÖRNEK BİR KOMUT ÇIKTISI YAPALIM (BASİT SEVİYE METİN OLSUN) :

METİN :

Bir zamanlar sordum forumda bir TRWE_2012 varmış...Çok aktif bir kullanıcıymış ...Forumda durmadan oradan oraya zıplar dururmuş tavşan misali...Bazen de forumdan yok olurmuş, nerede olduğu bilinmezmiş dengesiz...!


Şimdi betiği yönetici olarak çalıştıralım :

Machine model (M3 = 3-rotor / M4 = 4-rotor naval): (ROTOR=Dişli Çark Modelini belirliyoruz) = M3 (basit model)
Left (slowest) rotor (I / II / III / IV / V): (Sol Taraf Dişli Seviye , yani birim dakika kaç tık atacak?) = I
Middle rotor (I / II / III / IV / V): (Orta Dişli Seviye , yani birim dakika kaç tık atacak?) = II
Right (fastest) rotor (I / II / III / IV / V) : (Sağ Dişli Seviye, yani birim dakika kaç tık atacak?) = III
Left rotor ring setting (1-26): (Dişli dönüş seviyesi , yani tek seferde kaç dişliyi eş zamanlı döndürecek?) = 11
Middle rotor ring setting (1-26): 13
Right rotor ring setting (1-26): 15
Left rotor start position (A-Z): (Şifreleme yönü neresi? A-Z'ye , Z-A'ya? ) = A (A'dan Z'ye)
Middle rotor start position (A-Z):Z (A-Z'ye, ardından Z'den A'ya)
Right rotor start position (A-Z): A (A-Z'ye, ardından Z'den A'ya , tekrar A'dan Z'ye )
Reflector (B / C): (Yönlendirme Tablosu? ) = B

Plugboard setup (Steckerbrett): enter letter pairs, e.g. AB then CD.
Leave blank and press ENTER when done (max 10 pairs).
Pair 1: (BİLETLER) <BOŞ BIRAKIN> MAKİNE KENDİSİ OTOMATİK BELİRSİN...

--- Machine configuration ---
Model : M3
Rotors (L-M-R): I-II-III
Ring settings : 11-13-15
Start position: AZA
Reflector : B
Plugboard : (none)

NOTE: to decrypt later, start a fresh run with the exact same
model, rotor order, ring settings, start position, Greek rotor
(if M4) and plugboard pairs, then feed it the ciphertext. Enigma
is reciprocal: identical settings that encrypt will also decrypt.
Session file (settings + ciphertext log) is saved next to this
script at: C:\Users\TRWE_2012\Masaüstü\Encrypted Text Document.txt

TIP: digits are auto-converted to spoken words (2 -> ZWO, 5 -> FUENF...).
TIP: wrap codes in brackets to spell them out, e.g. [HX-2E] becomes
HEINRICH XANTHIPPE ZWO EMIL before encryption.
TIP: for very large texts, re-run with -InputFile / -OutputFile
instead of pasting into the console (avoids paste truncation).

Text to process - paste one or several lines (blank lines inside are fine).
Type END on its own line when finished. Press ENTER on an empty first line to exit. (ENTER) İLE ALT TARAFTAKİ BOŞLUĞA METNİ YAZIN

Bir zamanlar sordum forumda bir TRWE_2012 varmış...Çok aktif bir kullanıcıymış ...Forumda durmadan oradan oraya zıplar dururmuş tavşan misali...Bazen de forumdan yok olurmuş, nerede olduğu bilinmezmiş dengesiz...!
END (SONA END EKLİYORUZ VE KLAVYE'DEN ENTER TUŞUNA BASIYORUZ)

SONUÇ :

Prepared text : BIRZAMANLARSORDUMFORUMDABIRTRWEZWONULLEINSZWOVARMISCOKAKTIFBIRKULLANICIYMISFORUMDADURMADANORADANORAYAZIPLARDURURMUSTAVSANMISALIBAZENDEFORUMDANYOKOLURMUSNEREDEOLDUGUBILINMEZMISDENGESIZ
Result (continuous): UEGQWIHVGXLLGCPOHGCQONNMXXFFXVRELLEOKQAKWGAHXEKCXWQUZQWNBPNEKHMMTGQIJBKGNYVKSIHYJGLLMYWXOVYBNYIMWTCRGJFXYQSPHCTBFLCYSJBSWXLUNHAYDKYSOXKKEPCREZQTNIBZEJXCSKGRRIWQBPOLPUTJOGHAPPDRWFVAOLQ
Result (grouped) : UEGQW IHVGX LLGCP OHGCQ ONNMX XFFXV RELLE OKQAK WGAHX EKCXW QUZQW NBPNE KHMMT GQIJB KGNYV KSIHY JGLLM YWXOV YBNYI MWTCR GJFXY QSPHC TBFLC YSJBS WXLUN HAYDK YSOXK KEPCR EZQTN IBZEJ XCSKG RRIWQ BPOLP UTJOG HAPPD RWFVA OLQ

Text to process - paste one or several lines (blank lines inside are fine).
Type END on its own line when finished. Press ENTER on an empty first line to exit.

BURADA :

Result (continuous): ====>>ŞİFRELİ METİN
Result (grouped) : =====>>> 5'li GRUPLANDIRIMIŞ VERSİYON
Prepared text : YUKARIDAKİ METNİN BOŞLUKSUZ HALİ....

Hepsini toparlarsak :

Kod: Tümünü seç

=== Enigma Machine Simulator ===
(Wehrmacht Enigma I / M3, or 4-rotor Kriegsmarine Naval Enigma M4)

Machine model (M3 = 3-rotor / M4 = 4-rotor naval): M3
Left (slowest) rotor (I / II / III / IV / V): I
Middle rotor (I / II / III / IV / V): II
Right (fastest) rotor (I / II / III / IV / V): III
Left rotor ring setting (1-26): 11
Middle rotor ring setting (1-26): 13
Right rotor ring setting (1-26): 15
Left rotor start position (A-Z): A
Middle rotor start position (A-Z): Z
Right rotor start position (A-Z): A
Reflector (B / C): B

Plugboard setup (Steckerbrett): enter letter pairs, e.g. AB then CD.
Leave blank and press ENTER when done (max 10 pairs).
Pair 1:

--- Machine configuration ---
Model         : M3
Rotors (L-M-R): I-II-III
Ring settings : 11-13-15
Start position: AZA
Reflector     : B
Plugboard     : (none)

NOTE: to decrypt later, start a fresh run with the exact same
model, rotor order, ring settings, start position, Greek rotor
(if M4) and plugboard pairs, then feed it the ciphertext. Enigma
is reciprocal: identical settings that encrypt will also decrypt.
Session file (settings + ciphertext log) is saved next to this
script at: C:\Users\TRWE_2012\Masaüstü\Encrypted Text Document.txt

TIP: digits are auto-converted to spoken words (2 -> ZWO, 5 -> FUENF...).
TIP: wrap codes in brackets to spell them out, e.g. [HX-2E] becomes
     HEINRICH XANTHIPPE ZWO EMIL before encryption.
TIP: for very large texts, re-run with -InputFile / -OutputFile
     instead of pasting into the console (avoids paste truncation).

Text to process - paste one or several lines (blank lines inside are fine).
Type END on its own line when finished. Press ENTER on an empty first line to exit.
Bir zamanlar sordum forumda bir TRWE_2012 varmış...Çok aktif bir kullanıcıymış ...Forumda durmadan oradan oraya zıplar dururmuş tavşan misali...Bazen de forumdan yok olurmuş, nerede olduğu bilinmezmiş dengesiz...!
END
Prepared text      : BIRZAMANLARSORDUMFORUMDABIRTRWEZWONULLEINSZWOVARMISCOKAKTIFBIRKULLANICIYMISFORUMDADURMADANORADANORAYAZIPLARDURURMUSTAVSANMISALIBAZENDEFORUMDANYOKOLURMUSNEREDEOLDUGUBILINMEZMISDENGESIZ
Result (continuous): UEGQWIHVGXLLGCPOHGCQONNMXXFFXVRELLEOKQAKWGAHXEKCXWQUZQWNBPNEKHMMTGQIJBKGNYVKSIHYJGLLMYWXOVYBNYIMWTCRGJFXYQSPHCTBFLCYSJBSWXLUNHAYDKYSOXKKEPCREZQTNIBZEJXCSKGRRIWQBPOLPUTJOGHAPPDRWFVAOLQ
Result (grouped)   : UEGQW IHVGX LLGCP OHGCQ ONNMX XFFXV RELLE OKQAK WGAHX EKCXW QUZQW NBPNE KHMMT GQIJB KGNYV KSIHY JGLLM YWXOV YBNYI MWTCR GJFXY QSPHC TBFLC YSJBS WXLUN HAYDK YSOXK KEPCR EZQTN IBZEJ XCSKG RRIWQ BPOLP UTJOG HAPPD RWFVA OLQ

Text to process - paste one or several lines (blank lines inside are fine).
Type END on its own line when finished. Press ENTER on an empty first line to exit.
Betiğin çalıştırıldığı konumda "C:\Users\TRWE_2012\Masaüstü\Encrypted Text Document.txt" belgesi oluşuyor.Burada kullanıcının makine ayarları ve şifreli metni duruyor.

C:\Users\TRWE_2012\Masaüstü\Encrypted Text Document.txt İçeriği :

Kod: Tümünü seç

=== ENIGMA SESSION ===
Model: M3
LeftRotor: I
MiddleRotor: II
RightRotor: III
LeftRing: 11
MiddleRing: 13
RightRing: 15
LeftStart: A
MiddleStart: Z
RightStart: A
Reflector: B
Plugboard: (none)
=== MESSAGES ===
[2026-07-20 14:47:00] PREPARED: BIRZAMANLARSORDUMFORUMDABIRTRWEZWONULLEINSZWOVARMISCOKAKTIFBIRKULLANICIYMISFORUMDADURMADANORADANORAYAZIPLARDURURMUSTAVSANMISALIBAZENDEFORUMDANYOKOLURMUSNEREDEOLDUGUBILINMEZMISDENGESIZ
[2026-07-20 14:47:00] OUTPUT  : UEGQWIHVGXLLGCPOHGCQONNMXXFFXVRELLEOKQAKWGAHXEKCXWQUZQWNBPNEKHMMTGQIJBKGNYVKSIHYJGLLMYWXOVYBNYIMWTCRGJFXYQSPHCTBFLCYSJBSWXLUNHAYDKYSOXKKEPCREZQTNIBZEJXCSKGRRIWQBPOLPUTJOGHAPPDRWFVAOLQ
[2026-07-20 14:47:00] GROUPED : UEGQW IHVGX LLGCP OHGCQ ONNMX XFFXV RELLE OKQAK WGAHX EKCXW QUZQW NBPNE KHMMT GQIJB KGNYV KSIHY JGLLM YWXOV YBNYI MWTCR GJFXY QSPHC TBFLC YSJBS WXLUN HAYDK YSOXK KEPCR EZQTN IBZEJ XCSKG RRIWQ BPOLP UTJOG HAPPD RWFVA OLQ

Betiği ikinci kez çalıştırısanız...

=== Enigma Machine Simulator ===
(Wehrmacht Enigma I / M3, or 4-rotor Kriegsmarine Naval Enigma M4)

Found a previous session file next to the script:
C:\Users\TRWE_2012\Masaüstü\Encrypted Text Document.txt
Load its settings and continue that session? (Y/N): Y (YANİ DOSYAYI BULDUM AÇAYIM DİYOR BETİK SİZE, SİZDE AÇ DİYORSUNUZ)

SONUÇ :

Kod: Tümünü seç

=== Enigma Machine Simulator ===
(Wehrmacht Enigma I / M3, or 4-rotor Kriegsmarine Naval Enigma M4)

Found a previous session file next to the script:
  C:\Users\TRWE_2012\Masaüstü\Encrypted Text Document.txt
Load its settings and continue that session? (Y/N): Y

Settings restored from the session file.


--- Machine configuration ---
Model         : M3
Rotors (L-M-R): I-II-III
Ring settings : 11-13-15
Start position: AZA
Reflector     : B
Plugboard     : (none)

NOTE: to decrypt later, start a fresh run with the exact same
model, rotor order, ring settings, start position, Greek rotor
(if M4) and plugboard pairs, then feed it the ciphertext. Enigma
is reciprocal: identical settings that encrypt will also decrypt.
Session file (settings + ciphertext log) is saved next to this
script at: C:\Users\TRWE_2012\Masaüstü\Encrypted Text Document.txt

--- Ciphertext from the previous session ---
[2026-07-20 14:47:00] PREPARED: BIRZAMANLARSORDUMFORUMDABIRTRWEZWONULLEINSZWOVARMISCOKAKTIFBIRKULLANICIYMISFORUMDADURMADANORADANORAYAZIPLARDURURMUSTAVSANMISALIBAZENDEFORUMDANYOKOLURMUSNEREDEOLDUGUBILINMEZMISDENGESIZ
[2026-07-20 14:47:00] OUTPUT  : UEGQWIHVGXLLGCPOHGCQONNMXXFFXVRELLEOKQAKWGAHXEKCXWQUZQWNBPNEKHMMTGQIJBKGNYVKSIHYJGLLMYWXOVYBNYIMWTCRGJFXYQSPHCTBFLCYSJBSWXLUNHAYDKYSOXKKEPCREZQTNIBZEJXCSKGRRIWQBPOLPUTJOGHAPPDRWFVAOLQ
[2026-07-20 14:47:00] GROUPED : UEGQW IHVGX LLGCP OHGCQ ONNMX XFFXV RELLE OKQAK WGAHX EKCXW QUZQW NBPNE KHMMT GQIJB KGNYV KSIHY JGLLM YWXOV YBNYI MWTCR GJFXY QSPHC TBFLC YSJBS WXLUN HAYDK YSOXK KEPCR EZQTN IBZEJ XCSKG RRIWQ BPOLP UTJOG HAPPD RWFVA OLQ

TIP: digits are auto-converted to spoken words (2 -> ZWO, 5 -> FUENF...).
TIP: wrap codes in brackets to spell them out, e.g. [HX-2E] becomes
     HEINRICH XANTHIPPE ZWO EMIL before encryption.
TIP: for very large texts, re-run with -InputFile / -OutputFile
     instead of pasting into the console (avoids paste truncation).

Text to process - paste one or several lines (blank lines inside are fine).
Type END on its own line when finished. Press ENTER on an empty first line to exit.
Ancak bu kadar benzetebildim gerçek Enigmaya....

Bu Video'yu da İzleyin Mantığını Anlamak İçin:


Cevapla

“Programlama ve Script dilleri” sayfasına dön