Create simple word encoding scheme and display in game

This commit is contained in:
Terry Hearst 2024-03-07 19:29:13 -05:00
parent 0f8c97dca5
commit a7e83622d2
3 changed files with 89 additions and 5 deletions

View file

@ -65,3 +65,70 @@ func is_valid_word(word: String) -> bool:
func _notification(what: int) -> void: func _notification(what: int) -> void:
if what == NOTIFICATION_WM_CLOSE_REQUEST: if what == NOTIFICATION_WM_CLOSE_REQUEST:
get_tree().quit() 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

View file

@ -21,6 +21,7 @@ var won: bool
var input_guess: String var input_guess: String
@onready var title: Label = %Title @onready var title: Label = %Title
@onready var subtitle: Label = %Subtitle
@onready var letter_grid: GridContainer = %LetterGrid @onready var letter_grid: GridContainer = %LetterGrid
@onready var info_text: Label = %InfoText @onready var info_text: Label = %InfoText
@ -54,6 +55,7 @@ func _ready() -> void:
random_seed = Time.get_unix_time_from_datetime_dict(current_time) random_seed = Time.get_unix_time_from_datetime_dict(current_time)
title.text = "Daily " + title.text title.text = "Daily " + title.text
subtitle.text = "%d-%02d-%02d" % [current_time["year"], current_time["month"], current_time["day"]]
else: else:
title.text = "Random " + title.text title.text = "Random " + title.text
@ -62,6 +64,9 @@ func _ready() -> void:
ended = false ended = false
won = 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): for i in range(0, 26):
var letter := char("A".unicode_at(0) + i) var letter := char("A".unicode_at(0) + i)
var keyboard_button: Button = keyboard_vbox.find_child("Button" + letter) 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: func _on_share_button_pressed() -> void:
var text := title.text var text := "%s %s\n" % [title.text, subtitle.text]
if won: if won:
text += " %d/%d\n\n" % [current_guess, guess_count] text += "%d/%d\n\n" % [current_guess, guess_count]
elif ended: elif ended:
text += " X/%d\n\n" % [guess_count] text += "X/%d\n\n" % [guess_count]
else: else:
# Can probably bail early but I might as allow it # 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 i in range(current_guess):
for j in range(letter_count): for j in range(letter_count):

View file

@ -175,7 +175,11 @@ anchor_bottom = 1.0
layout_mode = 2 layout_mode = 2
theme_override_constants/separation = 20 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 unique_name_in_owner = true
layout_mode = 2 layout_mode = 2
theme_override_fonts/font = SubResource("1") theme_override_fonts/font = SubResource("1")
@ -183,6 +187,12 @@ text = "Gordle"
label_settings = SubResource("LabelSettings_h2dux") label_settings = SubResource("LabelSettings_h2dux")
horizontal_alignment = 1 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"] [node name="LetterGrid" type="GridContainer" parent="C/V"]
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 2 layout_mode = 2
@ -403,6 +413,7 @@ text = "Guess"
[node name="ShareButton" type="Button" parent="C/V/KeyboardVBox/GuessButton"] [node name="ShareButton" type="Button" parent="C/V/KeyboardVBox/GuessButton"]
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 0
offset_left = 180.0 offset_left = 180.0
offset_right = 283.0 offset_right = 283.0
offset_bottom = 49.0 offset_bottom = 49.0
@ -411,6 +422,7 @@ text = "Share"
[node name="CopiedText" type="Label" parent="C/V/KeyboardVBox/GuessButton"] [node name="CopiedText" type="Label" parent="C/V/KeyboardVBox/GuessButton"]
modulate = Color(1, 1, 1, 0) modulate = Color(1, 1, 1, 0)
layout_mode = 0
offset_left = 126.0 offset_left = 126.0
offset_top = 31.0 offset_top = 31.0
offset_right = 347.0 offset_right = 347.0