-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTERMINALDLE.PY
401 lines (368 loc) · 13.8 KB
/
TERMINALDLE.PY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
import datetime
from sys import argv,exit
Keyboards={
"QWERTY":"QWERTYUIOPASDFGHJKLZXCVBNM",
"ABC":"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"AZERTY":"AZERTYUIOPQSDFGHJKLMWXCVBN",
"WORKMAN":"QDRWBJFUPASHTGYNEOIZXMCVKL",
"FREQ":"ETAOINSHRDLCUMWFGYPBVKJXQZ",
"NONE":None
}
def Quinput(Request=""):
Exiting=False
try:
Response=input(Request).upper().strip()
if Response in Quittables:Exiting=True
except KeyboardInterrupt:
Exiting=True
print()
if Exiting:
QuitText=OWL+LtEE+"Game quit."+LtRst
if GameMode in ('I','M'):
QuitText+="The word was "+RandomWord+"."
exit(QuitText)
return Response
class ShareObj():
def __init__(self):
self.Sharings=('NO','YES','N','Y','0','1','F','T','FALSE','TRUE')
self.YON=2
self.ShareText=""
self.ShareYN=''
self.WGT="Infinite Wordle"
def Add(self,Char):
if self.YON:self.ShareText+=Char
def Determine(self):
if self.YON==2:
if self.ShareYN not in self.Sharings:
self.ShareYN=Quinput("Do you want to share? (Y)ES/(N)O\n")
while self.ShareYN not in self.Sharings:
print(OWL+' '*5+LtEE+"||Invalid||"+LtRst+OWL)
self.ShareYN=Quinput()
self.YON=self.Sharings.index(self.ShareYN)%2
print(OWL+self.Sharings[self.YON]+' ')
self.YON=self.Sharings.index(self.ShareYN)%2
def Print(self):
if self.YON==1:
self.__str__()
elif self.YON==2:
self.Determine()
self.__str__()
def __str__(self):
return f"You can copy the below text, normally with Ctrl-Shift-C, but it will change depending on your terminal.\nIt may look garbled or strange, but it should copy correctly.\n{self.WGT} {Attempt}/{Attempts}\n{self.ShareText}"
Share=ShareObj()
Attempts=6
GameMode=''
Share.YON=2
LoopGameloop,Unfair,KBH,HardMode=[False]*4
Modes=('I','Y','A','P','M')
Sharings=('N','Y','NO','YES','0','1','F','T','FALSE','TRUE')
Quittables=('QUIT','EXIT','CANCEL','Q','-Q')
Attempables=('-A','--ATTEMPTS')
Helpables=('-H','--HELP','/?','-?')
Playables=('-HTP','--HOW-TO-PLAY')
Linkables=('-L','--LINKS')
KBables=('-K','-KB','--KEYBOARD')
Historics=('-KBH','--KEYBOARD-HISTORY')
Modables=('-M','--MODE')
HardModes=('-HM','-H-M','--H-M','--HARDMODE','--HARD-MODE')
Shareable=('-S','--SHARE')
Colourables=('-C','-COL','--COLOURS','--COLOUR','--COLORS','--COLOR')
Unfairables=('-U','--UNFAIR')
ColourNames=('NORMAL','8COL','256COL','HICON','NYTHICON',
'WORDLE','8COLOR','256COLOR','HICONTRAST','NYTHICONTRAST',
'CLASSIC','8COLOUR','256COLOUR','HIGHCONTRAST','NYTHIGHCONTRAST')
LtRst='\x1b[0m'#Resets the colours to default.
LtRstW='\x1b[0;1;38;2;248;248;248m'#Resets the colours to white&bright.
LtC='\x1b[48;2;83;141;78m'#Changes the colour to green.
LtN='\x1b[48;2;181;159;59m'#Changes the colour to yellow/orange.
LtW='\x1b[48;2;58;58;60m'#Changes the colour to dark grey.
LtU='\x1b[48;2;81;83;84m'#Changes the colour to light grey.
LtEE='\x1b[38;2;255;0;0m'#Changes the colour to red.
OWL='\r\x1b[1A'#"Over Writes" the current line.
def JSONstr2Dict(InStr):
JSONLines=InStr[1:-1].split(',')
JSONDict=dict()
for i in JSONLines:
JSONDict[i[:i.find(':')].replace('"','')]=i[i.find(':')+1:].replace('"','')
return JSONDict
KBDisplay=Keyboards["ABC"]
argv=[i.upper() for i in argv]
for i in argv:
if i in Helpables:
exit("""-H\t--HELP /? -?\tExit the program and provide this screen.
-HTP\t--HOW-TO-PLAY\tExit the program and display a how-to-play screen.
-U\t--UNFAIR\tMakes any guessable word a possible answer. Only matters in marathon and infinite modes.
-L\t--LINKS\t\tExit the program and display links to the Wordle sub-websites, including help and solution sites.
-A\t--ATTEMPTS\tChange the number of maximum attempts to make it easier or harder. Default is 6.
-M\t--MODE\t\tSelect your mode.
-HM\t--HARD-MODE\tEnables hard mode. Correct letters must be in the same place every subsequent guess, and letters that are in the word must be included.
OPTIONS:
\t(I)nfinite
\tNew (Y)ork Times today
\t(A) Wordle from the NYT Archives
\t(P)ass&Play
\t(M)arathon
-KBH\t--KEYBOARD-HISTORY\tDoesn't clear the contents of previous word's keyboards.
-K\t--KEYBOARD\t\tSelect a keyboard to display during the game. Default is ABC.
OPTIONS: (In order of)
\tABC\tThe alphabet.
\tQWERTY\tA QWERTY keyboard
\tAZERTY\tAn AZERTY keyboard
\tWORKMAN\tA workman keyboard
\tFREQ\tFrequency of the letters in English
\tNONE\tNo keyboard display
-C\t--COLOURS\tChanges the colour modes the game runs in.
OPTIONS: (COLOUR=COLOR=COL, HIGH=HI, 256-COL=256COL)
\tCLASSIC\t\tThe normal colour scheme of the game. All correct and same as the website.
\t8-COLOUR\tFor terminals that only support 8 colours. Not recommended unless needed.
\t256-COLOUR\tFor terminals that only support up to the 256 colour palatte.
\tHIGH-CONTRAST\tIncreases vibrance of the colours to make them easier to see in a terminal.
\tNYT-HI-CONTRAST\tAdds the official high contrast colour palatte of Wordle.
Type 'QUIT' while the program's running to exit.
Arguments do not have to be capitalized.
If colours are not displaying properly, try the colours option.""")
if i in Colourables:
DisplayColours=argv[argv.index(i)+1].replace('-','')
if DisplayColours in ColourNames:
DisplayColours=ColourNames.index(DisplayColours)%5
else:
DisplayColours=0
match DisplayColours:
case 0:pass
case 1:
LtRstW='\x1b[0;1;37m'
LtC='\x1b[42m'
LtN='\x1b[43m'
LtW='\x1b[40;37m'
LtU=LtW
LtEE='\x1b[31m'
case 2:
LtRstW='\x1b[0;1;38;5;255m'
LtC='\x1b[48;5;107m'
LtN='\x1b[48;5;184m'
LtW='\x1b[48;5;238m'
LtU='\x1b[48;5;240m'
LtEE='\x1b[38;5;9m'
case 3:
LtRstW='\x1b[0;1;38;5;255m'
LtC='\x1b[48;5;46m'
LtN='\x1b[48;5;226m'
LtW='\x1b[48;5;232m'
LtU='\x1b[48;5;246m'
LtEE='\x1b[38;5;9m'
case 4:
LtC='\x1b[38;5;0;48;2;245;121;58m'
LtN='\x1b[38;5;0;48;2;133;192;249m'
LtW='\x1b[38;5;15;48;5;232m'
if i in Playables:
exit(f"""How To Play:
Guess the Wordle in 6 tries. Each guess must be a valid 5-letter word.
The color of the tiles will change to show how close your guess was to the word.
Examples:
{LtRstW+LtC}W{LtRstW}EARY
{LtRst}W is in the word and in the correct spot.
{LtRstW}P{LtN}I{LtRstW}LLS{LtRst}\nI is in the word but in the wrong spot.
{LtRstW}VAG{LtW}U{LtRstW}E{LtRst}\nU is not in the word in any spot.
In Infinite mode, you play a random word. In NYT mode, you play today's Wordle. In Archive, you play any Wordle from the past.
In Pass&Play, you choose words for your opponent to guess, until one of you fails.
In Marathon mode, you play as many games as you can without failing, and the last answer becomes your first guess for the next word.
If unfair mode is enabled, any guessable word can become the answer.""")
if i in Linkables:
print("Attempting to connect to the New York Times website. This may take a minute.")
from urllib import request
try:
NYT=JSONstr2Dict(str(request.urlopen(f"https://www.nytimes.com/svc/wordle/v2/{datetime.date.today():%Y-%m-%d}.json").read(),'utf-8'))
SolutionWeird=datetime.date.today().strftime('%Y/%m/')+str(int(datetime.date.today().strftime('%d'))-1).zfill(2)
except request.URLError:
exit(f"{LtEE}Connection to the NYT website failed{LtRst}, you may attempt to connect manually.")
exit(f"""The following are help and source links {LtEE}(SPOILERS FOR TODAY'S AND PAST WORDLES){LtRst}:
NYT Wordle Game\t\t\thttps://www.nytimes.com/games/wordle/index.html
Wordle \"API\" for today\t\thttps://www.nytimes.com/svc/wordle/v2/{NYT["print_date"]}.json
NYT Wordle solution page\thttps://www.nytimes.com/{SolutionWeird}/crosswords/wordle-review-{NYT["days_since_launch"]}.html
Word lists source\t\thttps://gist.github.com/cfreshman
This project's GitHub\t\thttps://github.com/uhRandomTree/Terminaldle""")
if i in Attempables:Attempts=int(argv[argv.index(i)+1])
if i in Modables:GameMode=argv[argv.index(i)+1]
if i in Shareable:
Share.ShareYN=argv[argv.index(i)+1]
Share.Determine()
if i in Unfairables:Unfair=True
if i in Historics:KBH=True
if i in HardModes:HardMode=True
if i in KBables:
try:KBDisplay=Keyboards[argv[argv.index(i)+1]]
except:print(LtEE+"Invalid keyboard option, using ABC."+LtRst)
if Unfair:
WordleList=open("ANSWERS.TXT").read().split('\n')
WordleList.extend(open("GUESSABLES.TXT").read().split('\n'))
else:
PossibleAnswers=open("ANSWERS.TXT").read().split('\n')
WordleList=list()
WordleList.extend(PossibleAnswers)
WordleList.extend(open("GUESSABLES.TXT").read().split('\n'))
def ValidWord(ShowWord=True):
PreWord=Quinput()
Word=str()
for Letter in PreWord:
if Letter.isalpha():Word+=Letter
while True:
if len(Word)!=5:
print(OWL+' '*5+LtEE+"||Wrong word length||"+LtRst+OWL)
elif Word not in WordleList:
print(OWL+' '*5+LtEE+"||Invalid word||"+LtRst+' '*5+OWL)
else:
if ShowWord:
print(OWL+Word+' '*22)
else:
print(OWL+"?????"+' '*22)
return Word
Word=Quinput()
def RandFromTime(ListLen):
return int(datetime.datetime.now().timestamp()*1000000)%ListLen
def DateFromWordleNum(GameNumber):
MonthArray=[0,31,28,31,30,31,30,31,31,30,31,30,31,30,31]
Day=19
Month=6
Year=2021
while GameNumber>0:
Day+=1
if Day>MonthArray[Month]:
Day=1
Month+=1
if Month>12:
Month=1
Year+=1
MonthArray[2]=28
if Year%100==0:
if Year%400==0:MonthArray[2]=29
else:
if Year%4==0:MonthArray[2]=29
GameNumber-=1
return f"{Year}-{Month:02d}-{Day:02d}"
if Unfair:
RandomWord=WordleList[RandFromTime(len(WordleList))]
else:
RandomWord=PossibleAnswers[RandFromTime(len(PossibleAnswers))]
if GameMode in Modes:pass
else:
GameMode=Quinput("Which mode do you want to play?\n(I)nfinite, New (Y)ork Times, NYT (A)rchive, (P)ass&Play, (M)arathon\n")
while GameMode not in Modes:
GameMode=print(OWL+' '+LtEE+"||Invalid mode||"+LtRst+OWL)#Gonna make some function for this whole mess. Later.
GameMode=Quinput()
print(OWL+GameMode+' '*16)
if GameMode=='P':
Share.YON=0
print(f"Choose your opponent's word and{LtEE} don't show them.{LtRst}")
RandomWord=ValidWord(False)
LoopGameloop=True
elif GameMode=='M':
LapCount=0
Share.YON=0
LoopGameloop=True
elif GameMode!='I':
from urllib import request
if GameMode=='Y':
print("Attempting to connect to the New York Times website. This may take a minute.")
RequestedDay=f"{datetime.date.today():%Y-%m-%d}"
elif GameMode=='A':
RequestedDay=Quinput("Please enter your chosen day in the format YYYY-MM-DD, or by which Wordle it was. (Wordles started counting at 0). Ex: 2023-02-26, or 617.\nThe first Wordle was June 19th, 2021 (2021-06-19, 0).\n")
print("Attempting to connect to the New York Times website. This may take a minute.")
if '-' in RequestedDay:
pass
else:
RequestedDay.replace(',','')
RequestedDay=DateFromWordleNum(int(RequestedDay))
try:
NYT=JSONstr2Dict(str(request.urlopen(f"https://www.nytimes.com/svc/wordle/v2/{RequestedDay}.json").read(),'utf-8'))
if 'days_since_launch' not in NYT.keys():NYT['days_since_launch']='0'
RandomWord=NYT['solution'].upper()
print("Game number: "+NYT['days_since_launch'])
print("Date: "+RequestedDay)
except request.URLError:
print(f"{LtEE}Connection to the NYT website failed{LtRst}, moving to Infinite Wordle mode.")
def GameLogic(Colour,Emoji):
print(Colour+CurLet,end='')
Share.Add(Emoji)
if KBDisplay:KBColours[KBDisplay.index(CurLet)]=Colour
Attempt=0
HitAnswer=1
if KBDisplay:KBColours=['']*26
if HardMode:
HardGreens=['']*5
HardYellows=dict()
while Attempt<Attempts:
if HitAnswer!=2:WordGuess=ValidWord()
HitAnswer=1
print(OWL+LtRstW,end='')
Letters=[*RandomWord]
for Let1,Let2 in zip(WordGuess,RandomWord):
if Let1==Let2:Letters.remove(Let1)
HardModePassed=True
if HardMode:
for Set,Checking in zip(HardGreens,WordGuess):
if Set:
if Checking!=Set:
HardModePassed=False
break
for ShouldBe in HardYellows.keys():
if HardYellows[ShouldBe] > WordGuess.count(ShouldBe):
HardModePassed=False
break
if HardModePassed:
for i in range(5):
CurLet=WordGuess[i]
if CurLet==RandomWord[i]:
GameLogic(LtC,'🟩')
if HardMode:HardGreens[i]=CurLet
elif CurLet in RandomWord and CurLet in Letters:
GameLogic(LtN,'🟨')
if HardMode:
if CurLet not in HardYellows.keys():HardYellows[CurLet]=1
else:HardYellows[CurLet]+=1
Letters.remove(CurLet)
HitAnswer=0
else:
GameLogic(LtW,'⬛')
HitAnswer=0
else:
print(' '*5+LtEE+"||Hard mode on||"+' '*5+LtRst+OWL)
continue
Share.Add('\n')
print(LtRst+' '*21,end='')
if KBDisplay:
print(LtU,end='')
for i in range(len(KBDisplay)):
print(KBColours[i]+KBDisplay[i]+LtRst+LtU,end='')
if not KBH and Attempt!=0:print(LtRst+'\x1b[1A\x1b[26D'+' '*26+'\x1b[1B')#Moves cursor up, back 26 characters, writes 26 spaces, back down, and to the bottom left.
else:
print(LtRst)
else:print()
Attempt+=1
if HitAnswer==1:
if not LoopGameloop:
print(f"You win! That took {Attempt} attempt(s).")
if GameMode!='I':Share.WGT="Wordle "+NYT['days_since_launch']
Share.Determine()
if Share.YON==1:print(Share)
break
else:
if HardMode:
HardGreens=['']*5
HardYellows=dict()
if KBDisplay:KBColours=['']*26
Attempt=0
if GameMode=='P':
print(LtRstW+"Change!"+LtRst)
RandomWord=ValidWord(False)
elif GameMode=='M':
print('-----\n')
HitAnswer=2
LapCount+=1
if Unfair:RandomWord=WordleList[RandFromTime(len(WordleList))]
else:RandomWord=PossibleAnswers[RandFromTime(len(PossibleAnswers))]
else:
if Attempt==Attempts:
print("Sorry, you ran out of attemps. ",end='')
if GameMode=='P':print("The other player wins.")
elif GameMode=='M':print(f"You made it {LapCount} round(s). The word was {RandomWord}.")
elif GameMode=='I':print("The word was "+RandomWord+".")