(31-07-2026, 04:00 PM)oshfdk Wrote: You are not allowed to view links. Register or Login to view.I tossed a coin and it came up heads, which means the numeric cipher theory is wrong. I think my method is no less reliable than yours 
The damn coin!

But again, the text corpus is small. You asked for metrics, and I provided them. It would be better if I gave them to you out of thin air.
Maybe your comments are right, but I think it's better to say what can be done or what needs to be worked on. I'm not a specialist, so I might not know or see what you don't.
As I understand it, your goal is to point out that my version has nothing (in terms of statistical research) and prove that it is very, very wrong. By the way, you don't believe in the Bavarian theory because it has statistical research, and you don't trust it.
I can tell you why I think the idea of a numeric cipher is correct. I can describe how it most likely works and illustrate it with an example of my own mini-cipher. At the same time, I can acknowledge any flaws in my theories if you actually find them and they are significant.
Of course, you would say, "Why is your theory correct and others are not?". But that's my position - I don't know if I'm right or not. And I may never know, so I don't criticize other theories if they are well-founded.
For example, I don't reject either the Bavarian theory, which I find quite complex, or the Chinese theory, which sometimes seems like a big assumption.
After a very, very long time of our discussions here, I still haven't understood what exactly you're not satisfied with. You say that I don't have any statistical evidence that the mini-cipher is similar to Voynichese, and I admit that there isn't any. However, you seem to view this as my surrender.
And remember, @oshfdk, a truly holistic critique includes a suggestion

In our case, at least.
(31-07-2026, 04:11 PM)ololololo Wrote: You are not allowed to view links. Register or Login to view.You asked for metrics, and I provided them.
You provided something made by Gemini. I'm sorry, but I'm not going to discuss this any further if you expect me to blindly trust some numbers produced by Gemini.
(31-07-2026, 07:23 PM)oshfdk Wrote: You are not allowed to view links. Register or Login to view. (31-07-2026, 04:11 PM)ololololo Wrote: You are not allowed to view links. Register or Login to view.You asked for metrics, and I provided them.
You provided something made by Gemini. I'm sorry, but I'm not going to discuss this any further if you expect me to blindly trust some numbers produced by Gemini.
Yes, you're right. I told you before that I don't have what you expect. Because of your persistence, I turned to Gemini.
I'm sorry, but if you're only here to achieve a specific outcome, I don't really want to discuss it

I tried to add nulls to the code. But it didn't really change much, and I'll tell you why.
import random
def letter_to_num(letter):
letter = letter.upper()
if letter in ['U', 'V']:
return 21
if 'A' <= letter <= 'Z':
return ord(letter) - ord('A') + 1
return None
def num_to_roman_tokens(num):
tokens = []
roman_rules = [
(22, 'XXII'), (21, 'XXI'), (20, 'XX'), (19, 'XIX'),
(18, 'XVIII'), (17, 'XVII'), (16, 'XVI'), (15, 'XV'),
(14, 'XIV'), (13, 'XIII'), (12, 'XII'), (11, 'XI'),
(10, 'X'), (9, 'IX'), (8, 'VIII'), (7, 'VII'),
(6, 'VI'), (5, 'V'), (4, 'IV'), (3, 'III'),
(2, 'II'), (1, 'I')
]
for val, sym in roman_rules:
while num >= val:
tokens.append(sym)
num -= val
return tokens
def encrypt_word(word):
numbers = [letter_to_num(l) for l in word if letter_to_num(l) is not None]
if not numbers:
return word
numbers.sort(reverse=True)
raw_tokens = []
for num in numbers:
raw_tokens.extend(num_to_roman_tokens(num))
separate_last_i = False
if len(raw_tokens) >= 2 and raw_tokens[-2] == 'III' and raw_tokens[-1] == 'I':
separate_last_i = True
raw_tokens.pop()
encrypted_tokens = []
is_standalone_xx = len(raw_tokens) == 1 and raw_tokens[0] == 'XX'
i = 0
while i < len(raw_tokens):
token = raw_tokens[i]
if token == 'XV' and i + 1 < len(raw_tokens) and raw_tokens[i+1] == 'XV':
encrypted_tokens.append("che")
i += 2
continue
if token == 'XVI':
if i + 1 < len(raw_tokens):
next_token = raw_tokens[i+1]
if next_token.startswith('XV') or next_token.startswith('X') or next_token.startswith('V'):
if next_token == 'XV':
encrypted_tokens.append("q")
i += 2
continue
else:
encrypted_tokens.append("qo")
i += 1
continue
encrypted_tokens.append("s")
i += 1
continue
if token == 'XXII': encrypted_tokens.append("chol")
elif token == 'XXI': encrypted_tokens.append("chor")
elif token == 'XIX':
prefix = random.choices(["ch", "yt", "yk"], weights=[60, 20, 20])[0]
encrypted_tokens.append(f"{prefix}eor")
elif token == 'XVIII': encrypted_tokens.append("oiin")
elif token == 'XVII': encrypted_tokens.append("cph")
elif token == 'XX': encrypted_tokens.append("sh" if is_standalone_xx else "ch")
elif token == 'XV': encrypted_tokens.append("o")
elif token == 'XIV': encrypted_tokens.append("oke")
elif token == 'XIII': encrypted_tokens.append("daiin")
elif token == 'XII': encrypted_tokens.append("dan")
elif token == 'XI': encrypted_tokens.append("ey")
elif token == 'IX':
base = random.choices(["or", "ol"], weights=[60, 40])[0]
prefix = random.choices(["ch", "yk", "yt"], weights=[80, 10, 10])[0]
encrypted_tokens.append(f"{prefix}{base}")
elif token == 'VIII': encrypted_tokens.append("aiin")
elif token == 'VII': encrypted_tokens.append("ain")
elif token == 'VI': encrypted_tokens.append("an")
elif token == 'IV': encrypted_tokens.append("ok")
elif token == 'X': encrypted_tokens.append("e")
elif token == 'V': encrypted_tokens.append("a")
elif token == 'III': encrypted_tokens.append("iin")
elif token == 'II': encrypted_tokens.append("in")
elif token == 'I':
current_word_str = "".join(encrypted_tokens)
if current_word_str and current_word_str[-1] in ['a', 'o']:
encrypted_tokens.append("n")
else:
encrypted_tokens.append("y")
i += 1
if separate_last_i:
current_word_str = "".join(encrypted_tokens)
last_i_char = "n" if current_word_str and current_word_str[-1] in ['a', 'o'] else "y"
encrypted_tokens.append(last_i_char)
if encrypted_tokens and encrypted_tokens[-1] == "n":
encrypted_tokens[-1] = "y"
encrypted_str = " ".join(encrypted_tokens)
return encrypted_str
def encrypt_text(text):
words = text.split()
encrypted_words = [encrypt_word(w) for w in words]
return " /// ".join(encrypted_words)
print(encrypt_text("OO"))
print(encrypt_text("PE"))
print(encrypt_text("PO"))
my_text = "YOUR TEXT"
print(encrypt_text(my_text))
1). In fact, I would like to make a more complicated version of this mini-cipher, but I think it should be published separately. I will make it a little later

2). @oshfdk, next time, your comments like "the cipher is not perfect/there is no statistics/it doesn't look like it/I don't understand anything at all" will be ignored, please.
Specifically, this cipher shows how the VMS text could have been created, demonstrating the intended encryption process, which I believe is not limited to a single algorithm that transforms A into B. I have no intention of making a cipher that just reproduces the VMS text. This is useless to me, because it doesn't prove anything, first of all. Secondly, there is the Naibbe cipher for this purpose.
If you want, play around with the Naibbe cipher at your leisure, get a perfect result, and if you want, never look at this thread. I've already described what I think about Voynichese, and as much as I would like to, your views seem to be completely different from mine.
Here is the "nulls" version of the code. Created using Gemini, there may be errors.
You can't force me to decipher it. I won't be able to do it anymore...
import random
def letter_to_num(letter):
letter = letter.upper()
if letter in ['U', 'V']:
return 21
if 'A' <= letter <= 'Z':
return ord(letter) - ord('A') + 1
return None
def num_to_roman_tokens(num):
tokens = []
if num <= 0:
return tokens
roman_rules = [
(22, 'XXII'), (21, 'XXI'), (20, 'XX'), (19, 'XIX'),
(18, 'XVIII'), (17, 'XVII'), (16, 'XVI'), (15, 'XV'),
(14, 'XIV'), (13, 'XIII'), (12, 'XII'), (11, 'XI'),
(10, 'X'), (9, 'IX'), (8, 'VIII'), (7, 'VII'),
(6, 'VI'), (5, 'V'), (4, 'IV'), (3, 'III'),
(2, 'II'), (1, 'I')
]
for val, sym in roman_rules:
while num >= val:
tokens.append(sym)
num -= val
return tokens
def encrypt_word(word):
numbers = [letter_to_num(l) for l in word if letter_to_num(l) is not None]
if not numbers:
return word
numbers.sort(reverse=True)
raw_tokens = []
for num in numbers:
raw_tokens.extend(num_to_roman_tokens(num))
separate_last_i = False
if len(raw_tokens) >= 2 and raw_tokens[-2] == 'III' and raw_tokens[-1] == 'I':
separate_last_i = True
raw_tokens.pop()
encrypted_tokens = []
is_standalone_xx = len(raw_tokens) == 1 and raw_tokens[0] == 'XX'
i = 0
while i < len(raw_tokens):
token = raw_tokens[i]
if token == 'XV' and i + 1 < len(raw_tokens) and raw_tokens[i+1] == 'XV':
encrypted_tokens.append("che")
i += 2
continue
if token == 'XVI':
if i + 1 < len(raw_tokens):
next_token = raw_tokens[i+1]
if next_token.startswith('XV') or next_token.startswith('X') or next_token.startswith('V'):
if next_token == 'XV':
encrypted_tokens.append("q")
i += 2
continue
else:
encrypted_tokens.append("qo")
i += 2
continue
encrypted_tokens.append("s")
i += 1
continue
if token == 'XXII': encrypted_tokens.append("chol")
elif token == 'XXI': encrypted_tokens.append("chor")
elif token == 'XIX': encrypted_tokens.append("eor")
elif token == 'XVIII': encrypted_tokens.append("oiin")
elif token == 'XVII': encrypted_tokens.append("cph")
elif token == 'XX': encrypted_tokens.append("sh" if is_standalone_xx else "ch")
elif token == 'XV': encrypted_tokens.append("o")
elif token == 'XIV': encrypted_tokens.append("oke")
elif token == 'XIII': encrypted_tokens.append("daiin")
elif token == 'XII': encrypted_tokens.append("dan")
elif token == 'XI': encrypted_tokens.append("ey")
elif token == 'IX':
selected_r = random.choices(["or", "ol"], weights=[60, 40], k=1)[0]
encrypted_tokens.append(selected_r)
elif token == 'VIII': encrypted_tokens.append("aiin")
elif token == 'VII': encrypted_tokens.append("ain")
elif token == 'VI': encrypted_tokens.append("dy")
elif token == 'IV': encrypted_tokens.append("ok")
elif token == 'X': encrypted_tokens.append("che")
elif token == 'V':
if i == len(raw_tokens) - 1:
encrypted_tokens.append("a")
else:
choices_a = ["char", "cha"]
weights_a = [60, 40]
selected_a = random.choices(choices_a, weights=weights_a, k=1)[0]
encrypted_tokens.append(selected_a)
elif token == 'III': encrypted_tokens.append("iin")
elif token == 'II': encrypted_tokens.append("in")
elif token == 'I':
current_word_str = "".join(encrypted_tokens)
if current_word_str and current_word_str[-1] in ['a', 'o']:
encrypted_tokens.append("n")
else:
encrypted_tokens.append("y")
i += 1
merged_tokens = []
idx = 0
while idx < len(encrypted_tokens):
if encrypted_tokens[idx] == "o" and idx + 1 < len(encrypted_tokens) and encrypted_tokens[idx+1] in ["oke", "ote"]:
suffix = "key" if encrypted_tokens[idx+1] == "oke" else "tey"
merged_tokens.append("qo" + suffix)
idx += 2
else:
merged_tokens.append(encrypted_tokens[idx])
idx += 1
encrypted_tokens = merged_tokens
if any(tok in ["qokey", "qotey"] for tok in encrypted_tokens) and "dy" in encrypted_tokens:
has_dy = False
cleaned_tokens = []
for tok in encrypted_tokens:
if tok == "dy":
has_dy = True
else:
cleaned_tokens.append(tok)
if has_dy:
final_tokens = []
for tok in cleaned_tokens:
if tok in ["qokey", "qotey"]:
base = "qoke" if tok == "qokey" else "qote"
final_tokens.append(base + "dy")
else:
final_tokens.append(tok)
encrypted_tokens = final_tokens
processed_tokens = []
for idx, token in enumerate(encrypted_tokens):
if token == "eor":
prev_token = encrypted_tokens[idx-1] if idx > 0 else ""
if prev_token not in ["sh", "oke", "ote"]:
prefix = random.choices(["ch", "yk", "yt"], weights=[60, 20, 20], k=1)[0]
processed_tokens.append(prefix + "eor")
else:
processed_tokens.append(token)
elif token == "or":
prefix = random.choices(["yk", "yt", ""], weights=[40, 40, 20], k=1)[0]
processed_tokens.append(prefix + "or")
elif token == "aiin":
prev_token = encrypted_tokens[idx-1] if idx > 0 else ""
if prev_token not in ["ch", "sh"]:
prefix = random.choices(["ch", "yk", "yt", ""], weights=[40, 20, 30, 10], k=1)[0]
processed_tokens.append(prefix + "aiin")
else:
processed_tokens.append(token)
else:
processed_tokens.append(token)
encrypted_tokens = processed_tokens
if encrypted_tokens:
last_token = encrypted_tokens[-1]
if last_token == "y":
choices_y = ["ch", "yk", "yt"]
weights_y = [60, 20, 20]
prefix_y = random.choices(choices_y, weights=weights_y, k=1)[0]
encrypted_tokens[-1] = prefix_y + "y"
elif last_token.endswith("aiin") and not (last_token.startswith("ch") or last_token.startswith("yk") or last_token.startswith("yt")):
choices_aiin = ["ch", "yt", ""]
weights_aiin = [40, 40, 20]
prefix_aiin = random.choices(choices_aiin, weights=weights_aiin, k=1)[0]
if prefix_aiin:
encrypted_tokens[-1] = prefix_aiin + "aiin"
if encrypted_tokens[-1] in ["a", "cha", "char"] or encrypted_tokens[-1].endswith("a"):
encrypted_tokens[-1] += "m"
if "qo" in encrypted_tokens and "dy" in encrypted_tokens:
if random.random() < 0.40:
return "ody"
encrypted_str = " ".join(encrypted_tokens)
if "a a" in encrypted_str:
encrypted_str = encrypted_str.replace("a a", "ody")
if separate_last_i:
current_word_str = "".join(encrypted_tokens)
last_i_char = "n" if current_word_str and current_word_str[-1] in ['a', 'o'] else "y"
encrypted_str += f" {last_i_char}"
return encrypted_str
def encrypt_text(text):
words = text.split()
encrypted_words = [encrypt_word(w) for w in words]
return " /// ".join(encrypted_words)
print("Тест 'EE':")
print(encrypt_word("EE"))
print()
for _ in range(5):
print(encrypt_word("PF"))
print()
my_text = "Lorem ipsum dolor sit amer"
print(encrypt_text(my_text))
(01-08-2026, 11:25 PM)ololololo Wrote: You are not allowed to view links. Register or Login to view.2). @oshfdk, next time, your comments like "the cipher is not perfect/there is no statistics/it doesn't look like it/I don't understand anything at all" will be ignored, please.
I just want to point out that I felt the same way as oshfdk - sorry...
(02-08-2026, 06:34 AM)JoJo_Jost Wrote: You are not allowed to view links. Register or Login to view.I just want to point out that I felt the same way as oshfdk - sorry...
Well, I'm not offended, but when I say that I don't have any statistics at the moment, and when I say that the cipher is similar to Voynichese and could be more similar to Voynichese, but I keep hearing the same objections, I'm sorry, but I can't take it anymore

Again, I'm willing to admit my mistakes and shortcomings in the theory, if there are any, but apparently, someone likes it...
I also never understood @oshfdk's intentions regarding the theory and the cipher. Yes, I messed up a bit when I was solving the encrypted texts he created

But I don't think it proves anything, except that I couldn't solve the cipher. I didn't write VMS, I didn't encrypt or decrypt it, so it's definitely not a criticism of my theory.
It's like going up to a person who deciphered, for example, the Festus disk and saying: "Okay, now write a fairy tale in this language" to mock his "stupidity."
A critical eye is always important, but when it's truly critical...
No, I just meant that a little structure would help your approach. Then people might understand better what you're doing.
I definitely don't want to discourage you!