diff --git a/src/global.gd b/src/global.gd index 51abf61..91bfa42 100644 --- a/src/global.gd +++ b/src/global.gd @@ -65,3 +65,70 @@ func is_valid_word(word: String) -> bool: func _notification(what: int) -> void: if what == NOTIFICATION_WM_CLOSE_REQUEST: get_tree().quit() + + +## Returns the number of 1 bits in an integer +func popcnt(num: int) -> int: + # Is this already implemented somewhere? + var count := 0 + for i in range(64): + if num & (1 << i): + count += 1 + return count + + +## Encodes a word using a very basic "encryption" method. Returns -1 if invalid word +func encode_word(word: String) -> int: + if word.length() != 5: + return -1 + word = word.to_upper() + + # Encode word in base 26 + var num := 0 + for i in range(word.length()): + var letter_ind := word[i].unicode_at(0) - 65 # 65 = ascii "A" + if letter_ind < 0 or letter_ind >= 26: + return -1 + num += letter_ind * (26 ** i) + # Add an offset so that "aaaaa" isn't just zeroes + num += 123456 + + # Shuffle bits around + # uvwxyz -> vuxwzy -> zyvuxw + num = ((num & 0xf0f0f0) >> 4) | ((num & 0x0f0f0f) << 4) + num = ((num & 0xffff00) >> 8) | ((num & 0x0000ff) << 16) + # Count bits and add as checksum + var bits := popcnt(num) + num = num | (bits << 24) + + return num + + +## Decodes an encoded word. Returns an empty string if invalid +func decode_word(encoded_word: int) -> String: + var bits := encoded_word >> 24 + var num := encoded_word & 0xffffff + + # Verify bit count + if popcnt(num) != bits: + return "" + + # Unshuffle bits + num = ((num << 8) & 0xffff00) | ((num >> 16) & 0x0000ff) + num = ((num << 4) & 0xf0f0f0) | ((num >> 4) & 0x0f0f0f) + + num -= 123456 + + if num < 0 or num >= (26 ** 5): # (26 ** 5) - 1 = "zzzzz" + # Someone is trying to be sneaky! Or more likely I just messed up. + return "" + + # Decode base 26 word + var word := "" + for i in range(5): + var letter_ind := num % 26 + word += char(letter_ind + 65) # 65 = ascii "A" + @warning_ignore("integer_division") + num = num / 26 + + return word diff --git a/src/main.gd b/src/main.gd index 2cdb57a..ecd0ee9 100644 --- a/src/main.gd +++ b/src/main.gd @@ -21,6 +21,7 @@ var won: bool var input_guess: String @onready var title: Label = %Title +@onready var subtitle: Label = %Subtitle @onready var letter_grid: GridContainer = %LetterGrid @onready var info_text: Label = %InfoText @@ -54,6 +55,7 @@ func _ready() -> void: random_seed = Time.get_unix_time_from_datetime_dict(current_time) title.text = "Daily " + title.text + subtitle.text = "%d-%02d-%02d" % [current_time["year"], current_time["month"], current_time["day"]] else: title.text = "Random " + title.text @@ -62,6 +64,9 @@ func _ready() -> void: ended = false won = false + if not Global.daily_mode: + subtitle.text = String.num_int64(Global.encode_word(target_word), 16) + for i in range(0, 26): var letter := char("A".unicode_at(0) + i) var keyboard_button: Button = keyboard_vbox.find_child("Button" + letter) @@ -219,14 +224,14 @@ func _on_ButtonBksp_pressed() -> void: func _on_share_button_pressed() -> void: - var text := title.text + var text := "%s %s\n" % [title.text, subtitle.text] if won: - text += " %d/%d\n\n" % [current_guess, guess_count] + text += "%d/%d\n\n" % [current_guess, guess_count] elif ended: - text += " X/%d\n\n" % [guess_count] + text += "X/%d\n\n" % [guess_count] else: # Can probably bail early but I might as allow it - text += " ?/%d\n\n" % [guess_count] + text += "?/%d\n\n" % [guess_count] for i in range(current_guess): for j in range(letter_count): diff --git a/src/main.tscn b/src/main.tscn index 9b747d7..a3d945d 100644 --- a/src/main.tscn +++ b/src/main.tscn @@ -175,7 +175,11 @@ anchor_bottom = 1.0 layout_mode = 2 theme_override_constants/separation = 20 -[node name="Title" type="Label" parent="C/V"] +[node name="Header" type="VBoxContainer" parent="C/V"] +layout_mode = 2 +theme_override_constants/separation = 0 + +[node name="Title" type="Label" parent="C/V/Header"] unique_name_in_owner = true layout_mode = 2 theme_override_fonts/font = SubResource("1") @@ -183,6 +187,12 @@ text = "Gordle" label_settings = SubResource("LabelSettings_h2dux") horizontal_alignment = 1 +[node name="Subtitle" type="Label" parent="C/V/Header"] +unique_name_in_owner = true +layout_mode = 2 +text = "Subtitle" +horizontal_alignment = 1 + [node name="LetterGrid" type="GridContainer" parent="C/V"] unique_name_in_owner = true layout_mode = 2 @@ -403,6 +413,7 @@ text = "Guess" [node name="ShareButton" type="Button" parent="C/V/KeyboardVBox/GuessButton"] unique_name_in_owner = true +layout_mode = 0 offset_left = 180.0 offset_right = 283.0 offset_bottom = 49.0 @@ -411,6 +422,7 @@ text = "Share" [node name="CopiedText" type="Label" parent="C/V/KeyboardVBox/GuessButton"] modulate = Color(1, 1, 1, 0) +layout_mode = 0 offset_left = 126.0 offset_top = 31.0 offset_right = 347.0