Initial commit
This commit is contained in:
commit
a36b57ed2e
|
@ -0,0 +1,560 @@
|
||||||
|
extends Node
|
||||||
|
const THEME_EMPTY := preload('res://letter_empty.tres')
|
||||||
|
const THEME_ABSENT := preload('res://letter_absent.tres')
|
||||||
|
const THEME_PRESENT := preload('res://letter_present.tres')
|
||||||
|
const THEME_CORRECT := preload('res://letter_correct.tres')
|
||||||
|
|
||||||
|
const WORD_LENGTH := 5
|
||||||
|
const MAX_TURNS := 6
|
||||||
|
var required_charmask := 0
|
||||||
|
var absent_charmask := 0
|
||||||
|
var charmask_bans := []
|
||||||
|
|
||||||
|
onready var GuessesPanel := $'/root/Control/VBoxContainer/GuessesPanel'
|
||||||
|
onready var KeyboardPanel := $'/root/Control/VBoxContainer/KeyboardPanel'
|
||||||
|
onready var PlayGameDialog := $'/root/Control/PlayGameDialog'
|
||||||
|
onready var NewGameButton := $'/root/Control/PlayGameDialog/NewGameButton'
|
||||||
|
|
||||||
|
var WordContainers: Array # Nodes
|
||||||
|
var WordStrings: Array = [] # Strings
|
||||||
|
var WordMasks: Array = [] # Mask form
|
||||||
|
var WordChars: Array = [] # Mask form
|
||||||
|
var Words: Array = [] # Entered words, string form
|
||||||
|
var WordsMaskLookup: Dictionary = {}
|
||||||
|
var AllValidWords: Array = []
|
||||||
|
var ValidWords: Array = []
|
||||||
|
var BotOpeners: Array = []
|
||||||
|
var botopener: PoolStringArray
|
||||||
|
|
||||||
|
var working_word = ''
|
||||||
|
var game_is_over = false
|
||||||
|
|
||||||
|
func _generate_WordsMaskLookup_recursive(key:=0, next_key:=0, depth:=5): # This is many orders of magnitude slower than Python, let alone Rust :/
|
||||||
|
for k in range(next_key, 26):
|
||||||
|
var key2 = key | (1<<k)
|
||||||
|
var wordslist = []
|
||||||
|
for w in WordsMaskLookup[key]:
|
||||||
|
if WordMasks[w] & key2 == key2:
|
||||||
|
wordslist.push_back(w)
|
||||||
|
if len(wordslist) > 0:
|
||||||
|
WordsMaskLookup[key2] = PoolIntArray(wordslist)
|
||||||
|
if depth > 0:
|
||||||
|
_generate_WordsMaskLookup_recursive(key2, next_key+1, depth-1)
|
||||||
|
|
||||||
|
func _generate_WordsMaskLookup(): # This seems fine perf-wise
|
||||||
|
print('Generating WordsMask cache')
|
||||||
|
for k1 in range(0, 26):
|
||||||
|
var key1 = (1<<k1)
|
||||||
|
var wl1 = []
|
||||||
|
for w in WordsMaskLookup[0]:
|
||||||
|
if WordMasks[w] & key1 == key1:
|
||||||
|
wl1.push_back(w)
|
||||||
|
if len(wl1) > 0:
|
||||||
|
WordsMaskLookup[key1] = wl1
|
||||||
|
|
||||||
|
for k2 in range(k1+1, 26):
|
||||||
|
var key2 = key1 | (1<<k2)
|
||||||
|
var wl2 = []
|
||||||
|
for w in WordsMaskLookup[key1]:
|
||||||
|
if WordMasks[w] & key2 == key2:
|
||||||
|
wl2.push_back(w)
|
||||||
|
if len(wl2) > 0:
|
||||||
|
WordsMaskLookup[key2] = wl2
|
||||||
|
|
||||||
|
for k3 in range(k2+1, 26):
|
||||||
|
var key3 = key2 | (1<<k3)
|
||||||
|
var wl3 = []
|
||||||
|
for w in WordsMaskLookup[key2]:
|
||||||
|
if WordMasks[w] & key3 == key3:
|
||||||
|
wl3.push_back(w)
|
||||||
|
if len(wl3) > 0:
|
||||||
|
WordsMaskLookup[key3] = wl3
|
||||||
|
|
||||||
|
for k4 in range(k3+1, 26):
|
||||||
|
var key4 = key3 | (1<<k4)
|
||||||
|
var wl4 = []
|
||||||
|
for w in WordsMaskLookup[key3]:
|
||||||
|
if WordMasks[w] & key4 == key4:
|
||||||
|
wl4.push_back(w)
|
||||||
|
if len(wl4) > 0:
|
||||||
|
WordsMaskLookup[key4] = wl4
|
||||||
|
|
||||||
|
for k5 in range(k4+1, 26):
|
||||||
|
var key5 = key4 | (1<<k5)
|
||||||
|
var wl5 = []
|
||||||
|
for w in WordsMaskLookup[key4]:
|
||||||
|
if WordMasks[w] & key5 == key5:
|
||||||
|
wl5.push_back(w)
|
||||||
|
if len(wl5) > 0:
|
||||||
|
WordsMaskLookup[key5] = wl5
|
||||||
|
|
||||||
|
func _setup_globals() -> void:
|
||||||
|
print('Loading dictionary')
|
||||||
|
var file = File.new()
|
||||||
|
match file.open('res://WORDLE', File.READ):
|
||||||
|
OK:
|
||||||
|
WordStrings = file.get_as_text().split('\n', false)
|
||||||
|
var err:
|
||||||
|
get_tree().quit(err)
|
||||||
|
|
||||||
|
print('Loading openers')
|
||||||
|
match file.open('res://opening_words.txt', File.READ):
|
||||||
|
OK:
|
||||||
|
for line in file.get_as_text().split('\n', false):
|
||||||
|
BotOpeners.push_back(PoolStringArray(line.split(',')))
|
||||||
|
var err:
|
||||||
|
get_tree().quit(err)
|
||||||
|
|
||||||
|
for s in WordStrings:
|
||||||
|
var w = str2Word(s)
|
||||||
|
AllValidWords.push_back(w)
|
||||||
|
WordMasks.push_back(w[1])
|
||||||
|
WordChars.push_back(w[2])
|
||||||
|
var w_idxs = []
|
||||||
|
for i in len(AllValidWords):
|
||||||
|
w_idxs.push_back(i)
|
||||||
|
WordsMaskLookup[0] = w_idxs
|
||||||
|
_generate_WordsMaskLookup()
|
||||||
|
|
||||||
|
func new_game() -> void:
|
||||||
|
PlayGameDialog.hide()
|
||||||
|
print('Preparing new game')
|
||||||
|
ValidWords = AllValidWords.slice(0, len(AllValidWords)-1)
|
||||||
|
charmask_bans = []
|
||||||
|
for i in WORD_LENGTH:
|
||||||
|
charmask_bans.push_back(0)
|
||||||
|
required_charmask = 0
|
||||||
|
absent_charmask = 0
|
||||||
|
botopener = BotOpeners[randi()%(len(BotOpeners))]
|
||||||
|
Words = []
|
||||||
|
for guess in WordContainers:
|
||||||
|
for button in guess.letter_btns:
|
||||||
|
button.text = ''
|
||||||
|
button.theme = THEME_EMPTY
|
||||||
|
for child in button.get_children():
|
||||||
|
child.queue_free()
|
||||||
|
game_is_over = false
|
||||||
|
update_keyboard()
|
||||||
|
bot_guess()
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
WordContainers = GuessesPanel.get_children().slice(2, -1)
|
||||||
|
assert(len(WordContainers)%2 == 0)
|
||||||
|
|
||||||
|
_setup_globals()
|
||||||
|
print('Cache completed')
|
||||||
|
|
||||||
|
randomize()
|
||||||
|
print('RNG seeded')
|
||||||
|
|
||||||
|
# yield(KeyboardPanel, 'ready')
|
||||||
|
print('Skinning keyboard')
|
||||||
|
update_keyboard()
|
||||||
|
|
||||||
|
NewGameButton.connect('pressed', self, 'new_game')
|
||||||
|
print('Ready to play')
|
||||||
|
|
||||||
|
|
||||||
|
func game_over() -> void:
|
||||||
|
game_is_over = true
|
||||||
|
var guesses := int(len(Words)/2)
|
||||||
|
var ws := len(ValidWords)
|
||||||
|
var endstr := ''
|
||||||
|
if guesses <= 1:
|
||||||
|
endstr = 'DEFEAT:\nThe goal is to pick different words...'
|
||||||
|
elif guesses < 6:
|
||||||
|
endstr = 'DEFEAT:\nYou were caught by the bot in %d guesses!'%guesses
|
||||||
|
if ws > 1:
|
||||||
|
endstr = endstr + '\nYou did have %d other words though...'%ws
|
||||||
|
else:
|
||||||
|
endstr = 'VICTORY:\nYou escaped the bot with %d words left to hide behind!'%ws
|
||||||
|
PlayGameDialog.get_child(0).text = endstr
|
||||||
|
PlayGameDialog.show()
|
||||||
|
|
||||||
|
|
||||||
|
func _exhaustive_search_best() -> String:
|
||||||
|
print('Doing a full exhaustive search')
|
||||||
|
var best := 0
|
||||||
|
var best_remainder := 1<<20
|
||||||
|
for idx in len(WordMasks):
|
||||||
|
var guessmask: int = WordMasks[idx]
|
||||||
|
var guesschars: Array = WordChars[idx]
|
||||||
|
var worst_remainder := 0
|
||||||
|
for soli in len(ValidWords):
|
||||||
|
var solw: Array = ValidWords[soli]
|
||||||
|
var remainder := 0
|
||||||
|
var reqmask: int = required_charmask | (guessmask & solw[1])
|
||||||
|
var banmask: int = absent_charmask | (guessmask & ~solw[1])
|
||||||
|
var charmasks := []
|
||||||
|
var solc: Array = solw[2]
|
||||||
|
for c in WORD_LENGTH:
|
||||||
|
if solc[c] == guesschars[c]:
|
||||||
|
charmasks.push_back(~solc[c])
|
||||||
|
else:
|
||||||
|
charmasks.push_back(charmask_bans[c] | guesschars[c])
|
||||||
|
for w in ValidWords:
|
||||||
|
if (w[1] & reqmask == reqmask) and (w[1] & banmask == 0):
|
||||||
|
var remains := true
|
||||||
|
var wc = w[2]
|
||||||
|
for c in WORD_LENGTH:
|
||||||
|
if wc[c] & charmasks[c] != 0:
|
||||||
|
remains = false
|
||||||
|
break
|
||||||
|
if remains:
|
||||||
|
remainder += 1
|
||||||
|
worst_remainder = max(worst_remainder, remainder)
|
||||||
|
if worst_remainder < best_remainder:
|
||||||
|
best = idx
|
||||||
|
best_remainder = worst_remainder
|
||||||
|
if best_remainder == 1:
|
||||||
|
break
|
||||||
|
return WordStrings[best]
|
||||||
|
|
||||||
|
func _exhaustive_search_fast() -> String:
|
||||||
|
print('Doing a fast exhaustive search')
|
||||||
|
var best := 0
|
||||||
|
var best_remainder := 1<<30
|
||||||
|
for idx in len(WordMasks):
|
||||||
|
var guessmask: int = WordMasks[idx]
|
||||||
|
var worst_remainder := 0
|
||||||
|
for soli in len(ValidWords):
|
||||||
|
var solw: Array = ValidWords[soli]
|
||||||
|
var remainder := 0
|
||||||
|
var reqmask: Array = required_charmask | (guessmask & solw[1])
|
||||||
|
var banmask: Array = absent_charmask | (guessmask & ~solw[1])
|
||||||
|
for w in ValidWords:
|
||||||
|
if (w[1] & reqmask == reqmask) and (w[1] & banmask == 0):
|
||||||
|
remainder += 1
|
||||||
|
worst_remainder = max(worst_remainder, remainder)
|
||||||
|
if worst_remainder < best_remainder:
|
||||||
|
best = idx
|
||||||
|
best_remainder = worst_remainder
|
||||||
|
if best_remainder == 1:
|
||||||
|
break
|
||||||
|
return WordStrings[best]
|
||||||
|
|
||||||
|
func _eliminative_search() -> String:
|
||||||
|
print('Doing an eliminative search')
|
||||||
|
var best := 0
|
||||||
|
var untested_mask: int = ~(required_charmask | absent_charmask) & (1<<26 - 1)
|
||||||
|
var highest_key = 0
|
||||||
|
for key in WordsMaskLookup.keys():
|
||||||
|
if key & untested_mask > highest_key:
|
||||||
|
highest_key = key
|
||||||
|
var indices = WordsMaskLookup[highest_key]
|
||||||
|
best = indices[randi()%len(indices)]
|
||||||
|
return WordStrings[best]
|
||||||
|
|
||||||
|
func bot_guess() -> void:
|
||||||
|
assert(len(Words)%2 == 0)
|
||||||
|
if game_is_over:
|
||||||
|
return
|
||||||
|
var words_left = len(ValidWords)
|
||||||
|
var lw = len(Words)
|
||||||
|
|
||||||
|
var guess = botopener[0]
|
||||||
|
if lw == 0:
|
||||||
|
guess = botopener[0]
|
||||||
|
elif lw == 2 and words_left > 20:
|
||||||
|
guess = botopener[1]
|
||||||
|
elif words_left <= 2: # 50:50
|
||||||
|
match randi()%2:
|
||||||
|
0: guess = Words[-1] # Make a cool effect for when it peeks answer to pressure you?
|
||||||
|
_: guess = ValidWords[randi()%words_left][0] # This is fine
|
||||||
|
elif words_left > 100: # Favor mass elimination
|
||||||
|
match randi()%100:
|
||||||
|
0: guess = Words[-1] # Make a cool effect for when it peeks answer to pressure you?
|
||||||
|
1,2,3: guess = ValidWords[randi()%words_left][0] # Maybe adjust this?
|
||||||
|
_: guess = _eliminative_search()
|
||||||
|
elif words_left > 30: # Maybe some reasonably fast checking?
|
||||||
|
match randi()%80:
|
||||||
|
0: guess = Words[-1] # Make a cool effect for when it peeks answer to pressure you?
|
||||||
|
1,2,3: guess = ValidWords[randi()%words_left][0] # Maybe adjust this?
|
||||||
|
_: guess = _exhaustive_search_fast()
|
||||||
|
else: # Go exhaustive bestcase
|
||||||
|
match randi()%50:
|
||||||
|
0: guess = Words[-1] # Make a cool effect for when it peeks answer to pressure you?
|
||||||
|
1,2,3: guess = ValidWords[randi()%words_left][0] # Losing move tbh
|
||||||
|
_: guess = _exhaustive_search_best()
|
||||||
|
push_word(guess)
|
||||||
|
|
||||||
|
|
||||||
|
func _exhaustive_answer_judgement(solution: String) -> String:
|
||||||
|
print('Doing a full exhaustive answer grade')
|
||||||
|
assert(len(Words)%2 == 1)
|
||||||
|
var guess: Array = str2Word(Words[-1])
|
||||||
|
var guessmask: int = guess[1]
|
||||||
|
var guesschars: Array = guess[2]
|
||||||
|
var results := []
|
||||||
|
var chosen_result := 0
|
||||||
|
for ans in ValidWords:
|
||||||
|
var remainder := 0
|
||||||
|
var reqmask: int = required_charmask | (guessmask & ans[1])
|
||||||
|
var banmask: int = absent_charmask | (guessmask & ~ans[1])
|
||||||
|
var charmasks := []
|
||||||
|
var ansc: Array = ans[2]
|
||||||
|
for c in WORD_LENGTH:
|
||||||
|
if ansc[c] == guesschars[c]:
|
||||||
|
charmasks.push_back(~ansc[c])
|
||||||
|
else:
|
||||||
|
charmasks.push_back(charmask_bans[c] | guesschars[c])
|
||||||
|
for w in ValidWords:
|
||||||
|
if (w[1] & reqmask == reqmask) and (w[1] & banmask == 0):
|
||||||
|
var remains := true
|
||||||
|
var wc = w[2]
|
||||||
|
for c in WORD_LENGTH:
|
||||||
|
if wc[c] & charmasks[c] != 0:
|
||||||
|
remains = false
|
||||||
|
break
|
||||||
|
if remains:
|
||||||
|
remainder += 1
|
||||||
|
results.push_back(remainder)
|
||||||
|
if ans[0] == solution:
|
||||||
|
chosen_result = remainder
|
||||||
|
# Note: we don't care about returning which word was best, just the possible scores
|
||||||
|
results.sort()
|
||||||
|
var sol_position = float(results.rfind(chosen_result))/len(results)
|
||||||
|
if sol_position > 0.97 and len(results) > 200:
|
||||||
|
return '!!'
|
||||||
|
if sol_position > 0.9:
|
||||||
|
return '!'
|
||||||
|
elif sol_position > 0.5:
|
||||||
|
return ''
|
||||||
|
elif sol_position > 0.4:
|
||||||
|
return '?!'
|
||||||
|
elif sol_position > 0.2:
|
||||||
|
return '?'
|
||||||
|
else:
|
||||||
|
return '??'
|
||||||
|
|
||||||
|
func _fast_answer_judgement(solution: String) -> String:
|
||||||
|
print('Doing a fast exhaustive answer grade')
|
||||||
|
assert(len(Words)%2 == 1)
|
||||||
|
var guess: Array = str2Word(Words[-1])
|
||||||
|
var guessmask: int = guess[1]
|
||||||
|
var results := []
|
||||||
|
var chosen_result := 0
|
||||||
|
for ans in ValidWords:
|
||||||
|
var remainder := 0
|
||||||
|
var reqmask: int = required_charmask | (guessmask & ans[1])
|
||||||
|
var banmask: int = absent_charmask | (guessmask & ~ans[1])
|
||||||
|
for w in ValidWords:
|
||||||
|
if (w[1] & reqmask == reqmask) and (w[1] & banmask == 0):
|
||||||
|
remainder += 1
|
||||||
|
results.push_back(remainder)
|
||||||
|
if ans[0] == solution:
|
||||||
|
chosen_result = remainder
|
||||||
|
# Note: we don't care about returning which word was best, just the possible scores
|
||||||
|
results.sort()
|
||||||
|
var sol_position = float(results.rfind(chosen_result))/len(results)
|
||||||
|
if sol_position > 0.9:
|
||||||
|
return '!'
|
||||||
|
elif sol_position > 0.4:
|
||||||
|
return ''
|
||||||
|
elif sol_position > 0.25:
|
||||||
|
return '?!'
|
||||||
|
elif sol_position > 0.1:
|
||||||
|
return '?'
|
||||||
|
else:
|
||||||
|
return '??'
|
||||||
|
|
||||||
|
|
||||||
|
func _estimated_answer_judgement(solution: String) -> String:
|
||||||
|
print('Estimating answer grade')
|
||||||
|
assert(len(Words)%2 == 1)
|
||||||
|
var guess: Array = str2Word(Words[-1])
|
||||||
|
var guessmask: int = guess[1]
|
||||||
|
var guesschars: Array = guess[2]
|
||||||
|
var ans = str2Word(solution)
|
||||||
|
var remainder := 0
|
||||||
|
var reqmask: int = required_charmask | (guessmask & ans[1])
|
||||||
|
var banmask: int = absent_charmask | (guessmask & ~ans[1])
|
||||||
|
for w in ValidWords:
|
||||||
|
if (w[1] & reqmask == reqmask) and (w[1] & banmask == 0):
|
||||||
|
remainder += 1
|
||||||
|
var sol_position = float(remainder)/len(ValidWords)
|
||||||
|
if sol_position > 0.75:
|
||||||
|
return '!!'
|
||||||
|
elif sol_position > 0.5:
|
||||||
|
return '!'
|
||||||
|
elif sol_position > 0.09:
|
||||||
|
return ''
|
||||||
|
elif sol_position > 0.025:
|
||||||
|
return '?!'
|
||||||
|
elif sol_position > 0.01:
|
||||||
|
return '?'
|
||||||
|
else:
|
||||||
|
return '??'
|
||||||
|
|
||||||
|
func _answer_judgement(solution: String) -> String:
|
||||||
|
if len(ValidWords) < 2:
|
||||||
|
return '#'
|
||||||
|
elif len(ValidWords) > 2400:
|
||||||
|
return _estimated_answer_judgement(solution)
|
||||||
|
elif len(ValidWords) > 300:
|
||||||
|
return _fast_answer_judgement(solution)
|
||||||
|
else:
|
||||||
|
return _exhaustive_answer_judgement(solution)
|
||||||
|
|
||||||
|
func is_word_valid(word: Array) -> bool:
|
||||||
|
if word[1] & required_charmask != required_charmask:
|
||||||
|
return false
|
||||||
|
for i in WORD_LENGTH:
|
||||||
|
if word[2][i] & charmask_bans[i] != 0:
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
func push_word(word: String) -> void:
|
||||||
|
update_word(word)
|
||||||
|
Words.push_back(word)
|
||||||
|
if len(Words)%2 == 0: # Just entered a solution
|
||||||
|
var guess: String = Words[-2]
|
||||||
|
var solution: String = Words[-1]
|
||||||
|
if guess == solution:
|
||||||
|
game_over()
|
||||||
|
return
|
||||||
|
for i in WORD_LENGTH:
|
||||||
|
var gcm = ascii2cm(guess[i])
|
||||||
|
if guess[i] == solution[i]:
|
||||||
|
charmask_bans[i] = ~gcm
|
||||||
|
required_charmask |= gcm
|
||||||
|
elif guess[i] in solution:
|
||||||
|
charmask_bans[i] |= gcm
|
||||||
|
required_charmask |= gcm
|
||||||
|
else:
|
||||||
|
absent_charmask |= gcm
|
||||||
|
for j in WORD_LENGTH:
|
||||||
|
charmask_bans[j] |= gcm
|
||||||
|
for i in range(len(ValidWords)-1, -1, -1):
|
||||||
|
if not is_word_valid(ValidWords[i]):
|
||||||
|
ValidWords.remove(i)
|
||||||
|
update_keyboard()
|
||||||
|
|
||||||
|
|
||||||
|
func update_keyboard() -> void:
|
||||||
|
for button in KeyboardPanel.buttons:
|
||||||
|
var cm = ascii2cm(button.text)
|
||||||
|
if cm & absent_charmask != 0:
|
||||||
|
button.theme = THEME_ABSENT
|
||||||
|
elif cm & required_charmask != 0:
|
||||||
|
button.theme = THEME_PRESENT
|
||||||
|
else:
|
||||||
|
button.theme = THEME_EMPTY
|
||||||
|
|
||||||
|
|
||||||
|
func update_word(word: String) -> void:
|
||||||
|
WordContainers[len(Words)].set_word(word)
|
||||||
|
if len(Words)%2 == 1: # Solution entry
|
||||||
|
WordContainers[len(Words)-1].grade_word(word)
|
||||||
|
WordContainers[len(Words)].grade_solution(Words[-1])
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if event is InputEventKey and not event.pressed:
|
||||||
|
print('Processing InputEvent', event)
|
||||||
|
for i in event.unicode:
|
||||||
|
randi()
|
||||||
|
var c = char(event.unicode).capitalize()
|
||||||
|
var cm = ascii2cm(c)
|
||||||
|
if cm > 0:
|
||||||
|
if len(working_word) < WORD_LENGTH:
|
||||||
|
if cm & charmask_bans[len(working_word)] == 0:
|
||||||
|
working_word += c
|
||||||
|
else:
|
||||||
|
if cm & charmask_bans[-1] == 0:
|
||||||
|
working_word[-1] = c
|
||||||
|
update_word(working_word)
|
||||||
|
else:
|
||||||
|
match event.scancode:
|
||||||
|
KEY_BACKSPACE:
|
||||||
|
working_word.erase(len(working_word)-1, 1)
|
||||||
|
update_word(working_word)
|
||||||
|
KEY_ENTER:
|
||||||
|
if (len(working_word) == WORD_LENGTH) and working_word in WordStrings:
|
||||||
|
var judgement = _answer_judgement(working_word)
|
||||||
|
push_word(working_word)
|
||||||
|
if judgement != '':
|
||||||
|
var lbl := Label.new()
|
||||||
|
lbl.text = judgement
|
||||||
|
lbl.align = Label.ALIGN_CENTER
|
||||||
|
lbl.anchor_left = 1.0
|
||||||
|
lbl.grow_horizontal = Control.GROW_DIRECTION_BOTH
|
||||||
|
lbl.margin_top = 1
|
||||||
|
lbl.add_color_override("font_color_shadow", Color(0, 0, 0))
|
||||||
|
lbl.add_constant_override("shadow_offset_x", 1)
|
||||||
|
lbl.add_constant_override("shadow_offset_y", 1)
|
||||||
|
lbl.add_constant_override("shadow_as_outline", 1)
|
||||||
|
match lbl.text:
|
||||||
|
'?!': lbl.add_color_override("font_color", Color(1, 0.5, 0.5))
|
||||||
|
'?': lbl.add_color_override("font_color", Color(1, 0.25, 0.25))
|
||||||
|
'??': lbl.add_color_override("font_color", Color(1, 0, 0))
|
||||||
|
WordContainers[len(Words)-1].letter_btns[-1].add_child(lbl)
|
||||||
|
working_word = ''
|
||||||
|
if len(Words) < 12:
|
||||||
|
bot_guess()
|
||||||
|
else:
|
||||||
|
game_over()
|
||||||
|
_:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func _osk_pressed(c):
|
||||||
|
c = c[0]
|
||||||
|
if c == '⌫':
|
||||||
|
working_word.erase(len(working_word)-1, 1)
|
||||||
|
update_word(working_word)
|
||||||
|
else:
|
||||||
|
var cm = ascii2cm(c)
|
||||||
|
if len(working_word) < WORD_LENGTH:
|
||||||
|
if cm & charmask_bans[len(working_word)] == 0:
|
||||||
|
working_word += c
|
||||||
|
else:
|
||||||
|
if cm & charmask_bans[-1] == 0:
|
||||||
|
working_word[-1] = c
|
||||||
|
update_word(working_word)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func ascii2cm(c: String) -> int:
|
||||||
|
match c:
|
||||||
|
'S': return 1<<25
|
||||||
|
'E': return 1<<24
|
||||||
|
'A': return 1<<23
|
||||||
|
'O': return 1<<22
|
||||||
|
'R': return 1<<21
|
||||||
|
'I': return 1<<20
|
||||||
|
'L': return 1<<19
|
||||||
|
'T': return 1<<18
|
||||||
|
'N': return 1<<17
|
||||||
|
'U': return 1<<16
|
||||||
|
'D': return 1<<15
|
||||||
|
'Y': return 1<<14
|
||||||
|
'C': return 1<<13
|
||||||
|
'P': return 1<<12
|
||||||
|
'M': return 1<<11
|
||||||
|
'H': return 1<<10
|
||||||
|
'G': return 1<<9
|
||||||
|
'B': return 1<<8
|
||||||
|
'K': return 1<<7
|
||||||
|
'W': return 1<<6
|
||||||
|
'F': return 1<<5
|
||||||
|
'V': return 1<<4
|
||||||
|
'Z': return 1<<3
|
||||||
|
'J': return 1<<2
|
||||||
|
'X': return 1<<1
|
||||||
|
'Q': return 1<<0
|
||||||
|
_: return 0
|
||||||
|
|
||||||
|
func popcnt(x: int) -> int:
|
||||||
|
var c = 0
|
||||||
|
while x != 0:
|
||||||
|
x &= x-1
|
||||||
|
c += 1
|
||||||
|
return c
|
||||||
|
|
||||||
|
func str2Word(s: String) -> Array:
|
||||||
|
var chars = []
|
||||||
|
var mask = 0
|
||||||
|
for i in WORD_LENGTH:
|
||||||
|
var cm = ascii2cm(s[i])
|
||||||
|
mask |= cm
|
||||||
|
chars.push_back(cm)
|
||||||
|
return [s, mask, chars]
|
|
@ -0,0 +1,45 @@
|
||||||
|
tool
|
||||||
|
extends PanelContainer
|
||||||
|
|
||||||
|
const BACKSPACE = '⌫'
|
||||||
|
const QWERTY := ['QWERTYUIOP', 'ASDFGHJKL', 'ZXCVBNM'+BACKSPACE]
|
||||||
|
const ALPHABETICAL := ['ABCDEFGHI', 'JKLMNOPQR', 'STUVWXYZ']
|
||||||
|
const BY_FREQUENCY := ['SEAORILTN', 'UDYCPMHGB', 'KFWVZJXQ']
|
||||||
|
enum KeyboardLayout {
|
||||||
|
QWERTY,
|
||||||
|
ALPHABETICAL,
|
||||||
|
BY_FREQUENCY
|
||||||
|
}
|
||||||
|
|
||||||
|
var rows := []
|
||||||
|
var buttons := []
|
||||||
|
var vcont
|
||||||
|
|
||||||
|
func make_buttons() -> void:
|
||||||
|
# delete children and then
|
||||||
|
vcont = VBoxContainer.new()
|
||||||
|
for r in QWERTY:
|
||||||
|
var row = HBoxContainer.new()
|
||||||
|
row.alignment = BoxContainer.ALIGN_CENTER
|
||||||
|
for c in r:
|
||||||
|
var button = Button.new()
|
||||||
|
button.text = c
|
||||||
|
if c == BACKSPACE:
|
||||||
|
button.text = '<-'
|
||||||
|
button.connect('pressed', Game, '_osk_pressed', [c])
|
||||||
|
button.rect_min_size = Vector2(32, 32)
|
||||||
|
buttons.append(button)
|
||||||
|
row.add_child(button)
|
||||||
|
rows.push_back(row)
|
||||||
|
vcont.add_child(row)
|
||||||
|
add_child(vcont)
|
||||||
|
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
make_buttons()
|
||||||
|
|
||||||
|
|
||||||
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
|
#func _process(delta: float) -> void:
|
||||||
|
# pass
|
|
@ -0,0 +1,137 @@
|
||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://KeyboardPanel.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://WordContainer.tscn" type="PackedScene" id=2]
|
||||||
|
|
||||||
|
[node name="Control" type="Control"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="GuessesPanel" type="GridContainer" parent="VBoxContainer"]
|
||||||
|
margin_right = 420.0
|
||||||
|
margin_bottom = 478.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
columns = 2
|
||||||
|
|
||||||
|
[node name="lbl_guess" type="Label" parent="VBoxContainer/GuessesPanel"]
|
||||||
|
margin_right = 208.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
text = "Computer's Guess"
|
||||||
|
align = 1
|
||||||
|
|
||||||
|
[node name="lbl_solution" type="Label" parent="VBoxContainer/GuessesPanel"]
|
||||||
|
margin_left = 212.0
|
||||||
|
margin_right = 420.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
text = "Your Solution"
|
||||||
|
align = 1
|
||||||
|
|
||||||
|
[node name="WordContainer" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_right = 208.0
|
||||||
|
|
||||||
|
[node name="WordContainer2" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_left = 212.0
|
||||||
|
margin_right = 420.0
|
||||||
|
|
||||||
|
[node name="WordContainer3" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 54.0
|
||||||
|
margin_right = 208.0
|
||||||
|
margin_bottom = 86.0
|
||||||
|
|
||||||
|
[node name="WordContainer4" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_left = 212.0
|
||||||
|
margin_top = 54.0
|
||||||
|
margin_right = 420.0
|
||||||
|
margin_bottom = 86.0
|
||||||
|
|
||||||
|
[node name="WordContainer5" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 90.0
|
||||||
|
margin_right = 208.0
|
||||||
|
margin_bottom = 122.0
|
||||||
|
|
||||||
|
[node name="WordContainer6" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_left = 212.0
|
||||||
|
margin_top = 90.0
|
||||||
|
margin_right = 420.0
|
||||||
|
margin_bottom = 122.0
|
||||||
|
|
||||||
|
[node name="WordContainer7" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 126.0
|
||||||
|
margin_right = 208.0
|
||||||
|
margin_bottom = 158.0
|
||||||
|
|
||||||
|
[node name="WordContainer8" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_left = 212.0
|
||||||
|
margin_top = 126.0
|
||||||
|
margin_right = 420.0
|
||||||
|
margin_bottom = 158.0
|
||||||
|
|
||||||
|
[node name="WordContainer9" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 162.0
|
||||||
|
margin_right = 208.0
|
||||||
|
margin_bottom = 194.0
|
||||||
|
|
||||||
|
[node name="WordContainer10" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_left = 212.0
|
||||||
|
margin_top = 162.0
|
||||||
|
margin_right = 420.0
|
||||||
|
margin_bottom = 194.0
|
||||||
|
|
||||||
|
[node name="WordContainer11" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 198.0
|
||||||
|
margin_right = 208.0
|
||||||
|
margin_bottom = 230.0
|
||||||
|
|
||||||
|
[node name="WordContainer12" parent="VBoxContainer/GuessesPanel" instance=ExtResource( 2 )]
|
||||||
|
margin_left = 212.0
|
||||||
|
margin_top = 198.0
|
||||||
|
margin_right = 420.0
|
||||||
|
margin_bottom = 230.0
|
||||||
|
|
||||||
|
[node name="KeyboardPanel" type="PanelContainer" parent="VBoxContainer"]
|
||||||
|
margin_top = 482.0
|
||||||
|
margin_right = 420.0
|
||||||
|
margin_bottom = 600.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="PlayGameDialog" type="ColorRect" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
color = Color( 0, 0, 0, 0.705882 )
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="PlayGameDialog"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_bottom = -300.0
|
||||||
|
text = "A bot is trying to hunt you down!
|
||||||
|
When it guesses a word, choose a word to hide behind.
|
||||||
|
You can change words each turn,
|
||||||
|
but you can't contradict your previous clues!
|
||||||
|
|
||||||
|
Try to last 6 turns!"
|
||||||
|
align = 1
|
||||||
|
valign = 1
|
||||||
|
|
||||||
|
[node name="NewGameButton" type="Button" parent="PlayGameDialog"]
|
||||||
|
anchor_top = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_top = -300.0
|
||||||
|
text = "Play New Game"
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
extends HBoxContainer
|
||||||
|
|
||||||
|
const WORD_LENGTH := 5
|
||||||
|
const THEME_EMPTY := preload('res://letter_empty.tres')
|
||||||
|
const THEME_ABSENT := preload('res://letter_absent.tres')
|
||||||
|
const THEME_PRESENT := preload('res://letter_present.tres')
|
||||||
|
const THEME_CORRECT := preload('res://letter_correct.tres')
|
||||||
|
|
||||||
|
var word := ''
|
||||||
|
var solution := ''
|
||||||
|
var guess := ''
|
||||||
|
onready var letter_btns := get_children()
|
||||||
|
|
||||||
|
func set_word(word: String):
|
||||||
|
self.word = word
|
||||||
|
for i in WORD_LENGTH:
|
||||||
|
letter_btns[i].text = word[i] if len(word) > i else ''
|
||||||
|
|
||||||
|
func grade_word(solution: String):
|
||||||
|
assert(self.word.length() == WORD_LENGTH)
|
||||||
|
if solution.length() < WORD_LENGTH:
|
||||||
|
self.solution = solution + ' '.repeat(WORD_LENGTH - len(solution))
|
||||||
|
elif solution.length() == WORD_LENGTH:
|
||||||
|
self.solution = solution
|
||||||
|
else:
|
||||||
|
self.solution = solution.left(WORD_LENGTH)
|
||||||
|
for i in WORD_LENGTH:
|
||||||
|
if self.word[i] == self.solution[i]:
|
||||||
|
self.letter_btns[i].theme = THEME_CORRECT
|
||||||
|
elif self.word[i] in self.solution:
|
||||||
|
self.letter_btns[i].theme = THEME_PRESENT
|
||||||
|
else:
|
||||||
|
self.letter_btns[i].theme = THEME_ABSENT
|
||||||
|
|
||||||
|
func grade_solution(guess: String):
|
||||||
|
if guess.length() < WORD_LENGTH:
|
||||||
|
self.guess = guess + ' '.repeat(WORD_LENGTH - len(guess))
|
||||||
|
elif guess.length() == WORD_LENGTH:
|
||||||
|
self.guess = guess
|
||||||
|
else:
|
||||||
|
self.guess = guess.left(WORD_LENGTH)
|
||||||
|
for i in WORD_LENGTH:
|
||||||
|
if len(self.word) > i:
|
||||||
|
if self.word[i] == self.guess[i]:
|
||||||
|
self.letter_btns[i].theme = THEME_CORRECT
|
||||||
|
elif self.word[i] in self.guess:
|
||||||
|
self.letter_btns[i].theme = THEME_PRESENT
|
||||||
|
else:
|
||||||
|
self.letter_btns[i].theme = THEME_EMPTY
|
||||||
|
else:
|
||||||
|
self.letter_btns[i].theme = THEME_EMPTY
|
|
@ -0,0 +1,45 @@
|
||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://letter_empty.tres" type="Theme" id=1]
|
||||||
|
[ext_resource path="res://WordContainer.gd" type="Script" id=2]
|
||||||
|
|
||||||
|
[node name="WordContainer" type="HBoxContainer"]
|
||||||
|
margin_top = 18.0
|
||||||
|
margin_right = 198.0
|
||||||
|
margin_bottom = 50.0
|
||||||
|
theme = ExtResource( 1 )
|
||||||
|
alignment = 1
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="WordChar1" type="Button" parent="."]
|
||||||
|
margin_left = 11.0
|
||||||
|
margin_right = 43.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 32, 32 )
|
||||||
|
|
||||||
|
[node name="WordChar2" type="Button" parent="."]
|
||||||
|
margin_left = 47.0
|
||||||
|
margin_right = 79.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 32, 32 )
|
||||||
|
|
||||||
|
[node name="WordChar3" type="Button" parent="."]
|
||||||
|
margin_left = 83.0
|
||||||
|
margin_right = 115.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 32, 32 )
|
||||||
|
|
||||||
|
[node name="WordChar4" type="Button" parent="."]
|
||||||
|
margin_left = 119.0
|
||||||
|
margin_right = 151.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 32, 32 )
|
||||||
|
|
||||||
|
[node name="WordChar5" type="Button" parent="."]
|
||||||
|
margin_left = 155.0
|
||||||
|
margin_right = 187.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 32, 32 )
|
|
@ -0,0 +1,29 @@
|
||||||
|
[gd_resource type="Theme" load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://stylebox_letter_normal_absent.tres" type="StyleBox" id=1]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id=1]
|
||||||
|
content_margin_left = 6.0
|
||||||
|
content_margin_right = 6.0
|
||||||
|
content_margin_top = 4.0
|
||||||
|
content_margin_bottom = 4.0
|
||||||
|
bg_color = Color( 0.18, 0.207, 0.279, 1 )
|
||||||
|
border_width_left = 1
|
||||||
|
border_width_top = 1
|
||||||
|
border_width_right = 1
|
||||||
|
border_width_bottom = 1
|
||||||
|
border_color = Color( 0.14, 0.161, 0.217, 1 )
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
Button/colors/font_color = Color( 0.8, 0.8075, 0.8275, 1 )
|
||||||
|
Button/colors/font_color_disabled = Color( 1, 1, 1, 0.3 )
|
||||||
|
Button/colors/font_color_focus = Color( 0.88, 0.8845, 0.8965, 1 )
|
||||||
|
Button/colors/font_color_hover = Color( 0.88, 0.8845, 0.8965, 1 )
|
||||||
|
Button/colors/font_color_pressed = Color( 0.41, 0.61, 0.91, 1 )
|
||||||
|
Button/colors/icon_color_hover = Color( 1.15, 1.15, 1.15, 1 )
|
||||||
|
Button/colors/icon_color_pressed = Color( 0.4715, 0.7015, 1.0465, 1 )
|
||||||
|
Button/styles/disabled = SubResource( 1 )
|
||||||
|
Button/styles/focus = ExtResource( 1 )
|
||||||
|
Button/styles/hover = ExtResource( 1 )
|
||||||
|
Button/styles/normal = ExtResource( 1 )
|
||||||
|
Button/styles/pressed = ExtResource( 1 )
|
|
@ -0,0 +1,29 @@
|
||||||
|
[gd_resource type="Theme" load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://stylebox_letter_normal_correct.tres" type="StyleBox" id=1]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id=1]
|
||||||
|
content_margin_left = 6.0
|
||||||
|
content_margin_right = 6.0
|
||||||
|
content_margin_top = 4.0
|
||||||
|
content_margin_bottom = 4.0
|
||||||
|
bg_color = Color( 0.18, 0.207, 0.279, 1 )
|
||||||
|
border_width_left = 1
|
||||||
|
border_width_top = 1
|
||||||
|
border_width_right = 1
|
||||||
|
border_width_bottom = 1
|
||||||
|
border_color = Color( 0.14, 0.161, 0.217, 1 )
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
Button/colors/font_color = Color( 0.8, 0.8075, 0.8275, 1 )
|
||||||
|
Button/colors/font_color_disabled = Color( 1, 1, 1, 0.3 )
|
||||||
|
Button/colors/font_color_focus = Color( 0.88, 0.8845, 0.8965, 1 )
|
||||||
|
Button/colors/font_color_hover = Color( 0.88, 0.8845, 0.8965, 1 )
|
||||||
|
Button/colors/font_color_pressed = Color( 0.41, 0.61, 0.91, 1 )
|
||||||
|
Button/colors/icon_color_hover = Color( 1.15, 1.15, 1.15, 1 )
|
||||||
|
Button/colors/icon_color_pressed = Color( 0.4715, 0.7015, 1.0465, 1 )
|
||||||
|
Button/styles/disabled = SubResource( 1 )
|
||||||
|
Button/styles/focus = ExtResource( 1 )
|
||||||
|
Button/styles/hover = ExtResource( 1 )
|
||||||
|
Button/styles/normal = ExtResource( 1 )
|
||||||
|
Button/styles/pressed = ExtResource( 1 )
|
|
@ -0,0 +1,29 @@
|
||||||
|
[gd_resource type="Theme" load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://stylebox_letter_normal_empty.tres" type="StyleBox" id=1]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id=1]
|
||||||
|
content_margin_left = 6.0
|
||||||
|
content_margin_right = 6.0
|
||||||
|
content_margin_top = 4.0
|
||||||
|
content_margin_bottom = 4.0
|
||||||
|
bg_color = Color( 0.18, 0.207, 0.279, 1 )
|
||||||
|
border_width_left = 1
|
||||||
|
border_width_top = 1
|
||||||
|
border_width_right = 1
|
||||||
|
border_width_bottom = 1
|
||||||
|
border_color = Color( 0.14, 0.161, 0.217, 1 )
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
Button/colors/font_color = Color( 0.8, 0.8075, 0.8275, 1 )
|
||||||
|
Button/colors/font_color_disabled = Color( 1, 1, 1, 0.3 )
|
||||||
|
Button/colors/font_color_focus = Color( 0.88, 0.8845, 0.8965, 1 )
|
||||||
|
Button/colors/font_color_hover = Color( 0.88, 0.8845, 0.8965, 1 )
|
||||||
|
Button/colors/font_color_pressed = Color( 0.41, 0.61, 0.91, 1 )
|
||||||
|
Button/colors/icon_color_hover = Color( 1.15, 1.15, 1.15, 1 )
|
||||||
|
Button/colors/icon_color_pressed = Color( 0.4715, 0.7015, 1.0465, 1 )
|
||||||
|
Button/styles/disabled = SubResource( 1 )
|
||||||
|
Button/styles/focus = ExtResource( 1 )
|
||||||
|
Button/styles/hover = ExtResource( 1 )
|
||||||
|
Button/styles/normal = ExtResource( 1 )
|
||||||
|
Button/styles/pressed = ExtResource( 1 )
|
|
@ -0,0 +1,29 @@
|
||||||
|
[gd_resource type="Theme" load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://stylebox_letter_normal_present.tres" type="StyleBox" id=1]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id=1]
|
||||||
|
content_margin_left = 6.0
|
||||||
|
content_margin_right = 6.0
|
||||||
|
content_margin_top = 4.0
|
||||||
|
content_margin_bottom = 4.0
|
||||||
|
bg_color = Color( 0.18, 0.207, 0.279, 1 )
|
||||||
|
border_width_left = 1
|
||||||
|
border_width_top = 1
|
||||||
|
border_width_right = 1
|
||||||
|
border_width_bottom = 1
|
||||||
|
border_color = Color( 0.14, 0.161, 0.217, 1 )
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
Button/colors/font_color = Color( 0.8, 0.8075, 0.8275, 1 )
|
||||||
|
Button/colors/font_color_disabled = Color( 1, 1, 1, 0.3 )
|
||||||
|
Button/colors/font_color_focus = Color( 0.88, 0.8845, 0.8965, 1 )
|
||||||
|
Button/colors/font_color_hover = Color( 0.88, 0.8845, 0.8965, 1 )
|
||||||
|
Button/colors/font_color_pressed = Color( 0.41, 0.61, 0.91, 1 )
|
||||||
|
Button/colors/icon_color_hover = Color( 1.15, 1.15, 1.15, 1 )
|
||||||
|
Button/colors/icon_color_pressed = Color( 0.4715, 0.7015, 1.0465, 1 )
|
||||||
|
Button/styles/disabled = SubResource( 1 )
|
||||||
|
Button/styles/focus = ExtResource( 1 )
|
||||||
|
Button/styles/hover = ExtResource( 1 )
|
||||||
|
Button/styles/normal = ExtResource( 1 )
|
||||||
|
Button/styles/pressed = ExtResource( 1 )
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,38 @@
|
||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=4
|
||||||
|
|
||||||
|
_global_script_classes=[ ]
|
||||||
|
_global_script_class_icons={
|
||||||
|
}
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="Word Hunt"
|
||||||
|
run/main_scene="res://Main.tscn"
|
||||||
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[autoload]
|
||||||
|
|
||||||
|
Game="*res://Game.gd"
|
||||||
|
|
||||||
|
[display]
|
||||||
|
|
||||||
|
window/size/width=420
|
||||||
|
window/dpi/allow_hidpi=true
|
||||||
|
window/handheld/orientation="portrait"
|
||||||
|
|
||||||
|
[physics]
|
||||||
|
|
||||||
|
common/enable_pause_aware_picking=true
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
quality/driver/driver_name="GLES2"
|
||||||
|
environment/default_environment="res://default_env.tres"
|
|
@ -0,0 +1,13 @@
|
||||||
|
[gd_resource type="StyleBoxFlat" format=2]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
content_margin_left = 6.0
|
||||||
|
content_margin_right = 6.0
|
||||||
|
content_margin_top = 4.0
|
||||||
|
content_margin_bottom = 4.0
|
||||||
|
bg_color = Color( 0.109804, 0.109804, 0.109804, 1 )
|
||||||
|
border_width_left = 1
|
||||||
|
border_width_top = 1
|
||||||
|
border_width_right = 1
|
||||||
|
border_width_bottom = 1
|
||||||
|
border_color = Color( 0.125, 0.14375, 0.19375, 1 )
|
|
@ -0,0 +1,13 @@
|
||||||
|
[gd_resource type="StyleBoxFlat" format=2]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
content_margin_left = 6.0
|
||||||
|
content_margin_right = 6.0
|
||||||
|
content_margin_top = 4.0
|
||||||
|
content_margin_bottom = 4.0
|
||||||
|
bg_color = Color( 0.447059, 0.439216, 0.631373, 1 )
|
||||||
|
border_width_left = 1
|
||||||
|
border_width_top = 1
|
||||||
|
border_width_right = 1
|
||||||
|
border_width_bottom = 1
|
||||||
|
border_color = Color( 0.125, 0.14375, 0.19375, 1 )
|
|
@ -0,0 +1,13 @@
|
||||||
|
[gd_resource type="StyleBoxFlat" format=2]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
content_margin_left = 6.0
|
||||||
|
content_margin_right = 6.0
|
||||||
|
content_margin_top = 4.0
|
||||||
|
content_margin_bottom = 4.0
|
||||||
|
bg_color = Color( 0.160784, 0.156863, 0.219608, 1 )
|
||||||
|
border_width_left = 1
|
||||||
|
border_width_top = 1
|
||||||
|
border_width_right = 1
|
||||||
|
border_width_bottom = 1
|
||||||
|
border_color = Color( 0.125, 0.14375, 0.19375, 1 )
|
|
@ -0,0 +1,13 @@
|
||||||
|
[gd_resource type="StyleBoxFlat" format=2]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
content_margin_left = 6.0
|
||||||
|
content_margin_right = 6.0
|
||||||
|
content_margin_top = 4.0
|
||||||
|
content_margin_bottom = 4.0
|
||||||
|
bg_color = Color( 0.631373, 0.439216, 0.439216, 1 )
|
||||||
|
border_width_left = 1
|
||||||
|
border_width_top = 1
|
||||||
|
border_width_right = 1
|
||||||
|
border_width_bottom = 1
|
||||||
|
border_color = Color( 0.125, 0.14375, 0.19375, 1 )
|
Loading…
Reference in New Issue