“Wheel Of Fortune” game CHALLENGE!!!1!

Pages: 12
Console animations have simply never impressed me, so I really don't feel accomplished in doing them.

Any program that I'm serious about and needs a user interface I'll create a GUI for.

Hell, I made a copy of the dino game on chrome, which could have been on console, but I used a whole GUI for it lmao
Does it have to be C++? I think this is just the perfect use case for https://charm.sh/

Here's my attempt at console style wordle (very crude ATM -- might polish a bit later):
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
// wordle.go

package main

import (
    "fmt"
    "os"
    "bufio"
    "time"
    "math/rand"
    "strings"
    "strconv"

    tea "github.com/charmbracelet/bubbletea"
    lg "github.com/charmbracelet/lipgloss"
)

type model struct {
    curTarget   []string
    curGuess    []string
    oldGuesses  [][]string
    curLetter   int
    curTry      int
    found       bool
    msg         string
    letters     map[string]int
}

var wordList []string
var wordSet map[string]struct{}

func initialModel() model {

    wordSet = make(map[string]struct{})

    fin, _ := os.Open(os.Args[1]); defer fin.Close()

    fs := bufio.NewScanner(fin)
 
    fs.Split(bufio.ScanLines)
  
    for fs.Scan() {
        w := strings.ToUpper(strings.TrimSpace(fs.Text()))
        if len(w) == 5 {
            wordList = append(wordList, w)
            wordSet[w] = struct{}{}
        }
    }

    t := strings.Split(wordList[rand.Intn(len(wordList))], "")

    letters := make(map[string]int)

    for c := 'A'; c <= 'Z'; c++ {
        letters[string(c)] = 0
    }

    return model{
        []string{t[0], t[1], t[2], t[3], t[4]}, 
        []string{" ", " ", " ", " ", " "},
        [][]string{},
        0, 0, false, "", letters,
    }
}

func (m model) Init() tea.Cmd {
    return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {
    case tea.KeyMsg:

        mstr := strings.ToLower(msg.String())
        isLetter := len(mstr) == 1 && mstr >= "a" && mstr <= "z"

        if (isLetter) {

            mstr = strings.ToUpper(mstr)
            m.curGuess[m.curLetter] = mstr
            if (m.curLetter < 4) { m.curLetter++ }

        } else {
            switch mstr {
            case "left", "backspace":
                if (m.curLetter > 0) { m.curLetter-- }
            case "right":
                if (m.curLetter < 4 && m.curGuess[m.curLetter] != " ") { m.curLetter++ }
            case "ctrl+c", "esc":
                return m, tea.Quit
            case "enter":

                g := strings.TrimSpace(strings.Join(m.curGuess, ""))
                t := strings.Join(m.curTarget, "")
                _, exists := wordSet[g]

                if exists {

                    wd := wordDiff(t, g)

                    for i, c := range m.curGuess {
                        if wd[i] == 0 {
                            m.letters[c] = 3
                        } else if wd[i] == 2 {
                            m.letters[c] = 2
                        } else if m.letters[c] != 2 {
                            m.letters[c] = 1
                        }
                    }

                    m.found = m.found || g == t
                    m.oldGuesses = append(m.oldGuesses, m.curGuess[:])
                    m.curGuess = []string{" ", " ", " ", " ", " "}
                    m.curTry++
                    m.curLetter = 0
                    
                    if m.found {
                        m.msg = "congrats!"
                    } else if m.curTry > 5 {
                        m.msg = fmt.Sprintf("target word was '%v'", t)
                    } else {
                        m.msg = ""
                    }

                } else if (len(g) == 5) {
                    m.msg = fmt.Sprintf("word '%v' not in dictionary", g)
                    m.curGuess = []string{" ", " ", " ", " ", " "}
                    m.curLetter = 0    
                }
            }
        }
    }

    if (m.found || m.curTry == 6) {
        return m, tea.Quit
    } else {
        return m, nil
    }
}

func (m model) View() string {

    gs := []string{" ", " ", " ", " ", " ", " "}

    stDefault := lg.NewStyle()
    stRed := lg.NewStyle().Foreground(lg.Color("#ff0000"))
    stGreen := lg.NewStyle().Foreground(lg.Color("#00ff00"))
    stYellow := lg.NewStyle().Foreground(lg.Color("#ffff00"))
    stCursor := lg.NewStyle().Background(lg.Color("#646464"))

    var st lg.Style

    var ls []string

    for c := 'A'; c <= 'Z'; c++ {

        sc := string(c)

        switch m.letters[sc] {
        case 0: st = stDefault
        case 1: st = stYellow
        case 2: st = stGreen
        case 3: st = stRed
        }

        ls = append(ls, st.Render(sc))
    }

    for i := 0; i < 6; i++ {

        var mg []string
        g := []string{" ", " ", " ", " ", " "}

        if i < m.curTry {
            mg = m.oldGuesses[i]
            wd := wordDiff(strings.Join(m.curTarget, ""), strings.Join(mg, ""))

            for j := 0; j < 5; j++ {

                st = stDefault

                switch wd[j] {
                case 0: st = stRed
                case 1: st = stYellow
                case 2: st = stGreen
                }

                g[j] = fmt.Sprintf("[%v]", st.Render(mg[j]))
            }

        } else if i == m.curTry && !m.found {
            mg = m.curGuess

            for j := 0; j < 5; j++ {
                
                st = stDefault

                if (m.curLetter == j) {
                    st = stCursor
                }
                
                g[j] = fmt.Sprintf("[%v]", st.Render(mg[j]))
            }

        }

        if i < m.curTry || (i == m.curTry && !m.found)  {
            switch i {
            case 0, 1, 2: st = stGreen
            case 3, 4: st = stYellow
            case 5: st = stRed
            }

            gs[i] = fmt.Sprintf("%v - %v", st.Render(strconv.Itoa(i + 1)), 
                                           strings.TrimSpace(strings.Join(g, "")))
        }    

    }

    return fmt.Sprintf("\n%v\n\n%v\n\n%v\n\n", 
                        strings.Join(ls, " "), 
                        strings.TrimSpace(strings.Join(gs, "\n")), m.msg)
}

func wordDiff(target, guess string) (ret [5]int) {
    
    for i := 0; i < 5; i++ {
        if guess[i] == target[i] {
            ret[i] = 2
        } else {
            for j := 0; j < 5; j++ {
                if guess[i] == target[j] {
                    ret[i] = 1
                    break
                }
            }
        }
    }

    return
}

func main() {
    rand.Seed(time.Now().UnixNano())
    p := tea.NewProgram(initialModel())
    if err := p.Start(); err != nil {
        fmt.Printf("Alas, there's been an error: %v", err)
        os.Exit(1)
    }
}

Run it with:
$ go mod init wordle
$ go mod tidy # gets github deps
$ go run . wordlist.txt

You can find a list of words here: https://www-cs-faculty.stanford.edu/~knuth/sgb-words.txt
Last edited on
charm???
Sorry to be slow on the promised update. I forgot what a nightmare parsing input is for xterm, and I want to give you all something better than my usual hacks. (I know, I’ve been saying I’ll make a console how-to for ages.)

Maybe I’ll cut it down to just getting non-function keys from the keyboard and leave out the UTF-8/function/extended keys and mouse input...

Tell me what you want.

[edit]
Does WSL2 matter to y’all?
Because you could just get input from the linux event subsystem too...
But that doesn’t properly exist on WSL2.



OK, the REAL question is:

Anyone still using Windows Console in Windows < 10 (8, 7, Vista, XP, ...)?

Going forward, I’m going to assume Windows 10.
Last edited on
Is there a deadline before submitting?
Anyone still using Windows Console in Windows < 10 (8, 7, Vista, XP, ...)?


Yes - Windows 7!

PS. Isn't WSL a Windows virus that needs to be removed? :) :)
Last edited on
@Geckoo
The only deadline is a locked-n-archived topic.
AFAIK as long as there are recent replies to the topic it stays open.

I don't know what the idle time is needed to lock the topic, it's at least several months from what I've seen.
Anyone still using Windows Console in Windows < 10 (8, 7, Vista, XP, ...)?


I use it all the time. I have a number of work related batch files, and I use cygwin pathed into the console for grep and a few other unixy tools. I often delete files from the console, its faster (the windows delete likes to do a bunch of slow thinking about it operations up front and then prints what its doing which also slows it way down). I like the bulk copy (xcopy and the new one I keep forgetting) operations. I compile the little programs here in the forums in g++ (cygwin again) if I need to do so. I redirect to and from files a bit as well. I have any number of subst invocations to make fake drives for various reasons.

I think windows finally lets you do everything in the GUI that you can do in the console, but far less efficient. My oldest install is win 8, though. I had a 7 until fairly recently.
Last edited on
I’ve always done almost everything from the terminal. Way back from CP/M through Windows 95, XP, 7, and now 10, and all the random Linux variations I played with. Oh, and Sun OS at University, but I dunno if that counts here.

Clicking through a gazillion menus (folders) to do anything at all is truly obnoxious. I can fire up my terminal prompt and have everything at my fingertips.

As an aside, I can’t stand PowerShell. It took the terminal idea and goobered it to be as painful as possible.

The key to using the terminal is managing your PATH. The next is to keep utilities handy. I set my terminal startup to automatically run C:\Users\Michael\bin\prompt.bat, which is actually pretty simple:

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
@echo off
cls
path C:\Users\Michael\bin;%PATH%
chcp 65001 > nul

if "%ConEmuDir%"=="" (
  prompt $E[33;1m$P$G$E[90m 
)

set DIRCMD=/ogn

:: Macro Aliases

doskey apath=for %%F in ($1) do @path %%~fF;%%PATH%%
doskey mpath=for %%A in ("%%PATH:;=";"%%") do @if not "%%~A"=="" @echo   %%~A
doskey rpath=for %%F in ($1) do @for /F "usebackq delims=" %%M in (`echo set "PATH=%%PATH:%%~fF=%%"`) do @%%M

doskey deltree=rd/s/q $*
doskey dira=dir/a $*
doskey dird=dir/a-hd $*
doskey mcd=@md $* $T @cd $*

doskey 7z="C:\Program Files (x86)\7-Zip\7z.exe" $*
doskey npp="C:\Program Files (x86)\Notepad++\Notepad++" $*

... and so on.
`doskey` is the Windows version of the *nix `alias`. It works a little differently, though, so make sure to type help doskey before you use it. (And it is a much easier read than searching through man bash to read up on alias.)

Then I populate my C:\Users\Michael\bin directory with a bunch of useful little batch files. For example, I can look at all my macros (aliases) with:

  C:\Users\Michael\bin\macros.bat
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
::if 0 {
  @echo off
  tclsh "%~f0" %*
  goto :EOF
}

set f [open "|doskey /macros"]
set s [read $f]
if {[catch {close $f} err]} {
  puts $err
  exit
}

set lines []
set max 0
foreach line [lsort -dictionary [split $s \n]] {
  if {$line eq {}} continue
  lassign [split $line "="] alias command
  lappend lines [list $alias $command]
  set max [expr {max($max, [string length $alias])}]
}

foreach alias_command $lines {
  lassign $alias_command alias command
  puts "[format %${max}s $alias] = $command"
}
C:\Users\Michael> macros
     7z = "C:\Program Files (x86)\7-Zip\7z.exe" $*
  apath = for %F in ($1) do @path %~fF;%PATH%
 astyle = C:\m\bin\AStyle\bin\astyle.exe -A1 -s2 $*
blender = title blender 3.0 $T "C:\Program Files\Blender Foundation\Blender 3.0\blender.exe" $*
    npp = "C:\Program Files (x86)\Notepad++\Notepad++" $*
...


In order to keep the path clean when programming, I’ll actually nest invocations of cmd.exe. So, for example, I can type:

C:\Users\Michael> msvc x64

and C:\Users\Michael\bin\msvc.bat will start a new shell in the same terminal (cmd /k ...) and find and run vsvarsall.bat for an AMD-64 toolchain. (msvc.bat is actually rather lengthy, being both DOS batch script and being smart enough to complain if it has already been invoked and being able to find and invoke the correct vsvarsall.bat script — I have multiple versions of VS installed.)

That way when I am done I can get back to a “clean” prompt by simply typing exit. Here’s a useful script to report how many times the command shell has been nested for a particular terminal:

  C:\Users\Michael\bin\levels.bat
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
::if 0 {
  @echo off
  :: 
  :: Report the number of cmd.exe processes running in this Windows Console window
  :: (You can 'exit' n-1 times before this Windows Console closes.)
  ::
  set source=%~f0
  if exist %source%.bat set source=%source%.bat
  tclsh %source% %*
  goto :EOF
}

set pss [exec {*}[auto_execok wmic] process get processid,parentprocessid,executablepath]
foreach ps [split $pss \n] {
  lassign [lreverse [string map {\\ /} $ps]] pid ppid exename
  set PARENTS($pid) $ppid
  set EXES($pid) [file tail $exename]
}

set p [pid]
set n 0
while {$p in [array names PARENTS]} {
  if {$EXES($PARENTS($p)) ne "cmd.exe"} break
  incr n
  set p $PARENTS($p)
}

puts $n


You may have noticed that I tend to use tclsh (Tcl shell) for a lot of useful stuff when DOS batch is either insufficient or just too obnoxious and clumsy. It doesn’t really matter which shell/interpreter you recur to — VisualBasicSript is already installed on Windows systems and you could use that — Python is also a useful alternative. Heck, you could even make PowerShell scripts if that floats your boat. You could even compile little C++ programs to do stuff. The point is to have useful tools.

All this can be easily duplicated in a Linux prompt. I have WSL2 up and running (complete with an X Server so I can run graphical Linux programs from the Ubuntu prompt as well). I add aliases to my ~/.bashrc (or ~/.profile, if needed) to make switching between the two easy and convenient.

For example, I use Notepad++ regularly. Since it is a Windows program (and because notepadqq is currently garbage, sorry), I add it to my list of aliases.

  ~/.bashrc snippet
1
2
3
4
5
...
alias dir='ls -CF --color'
alias dira='ls -A'
alias npp='/mnt/c/Program\ Files\ \(x86\)/Notepad\+\+/Notepad\+\+.exe'
...

Now, whether I am on Windows or Linux, I can simply type:

    npp somefile.cpp

to begin editing somefile.cpp.


One interesting trick is to automagically add a utility to the path when it is first used. For example:

  C:\Users\Michael\bin\python.bat
1
2
3
@echo off
path C:\Python37\Scripts;C:\Python37;%PATH%
python.exe %*

Now I don’t have to care whether Python is already in the path or not. I just type python quux.py and quux.py runs properly, every time.

This works because the python.bat is initially the only thing found in the PATH, but after executing it, it is now listed after the actual python.exe executable in the PATH, so it never gets called by mistake.


Once you get everything set up, open a terminal and type mpath and look at all the junk in there. A lot of it can be removed. For example, I don’t need C:\gtkmm64\bin sitting in there. (I should have properly installed any programs using GTK!) Copy and save the list somewhere before the next step:

Click on Start (or the little hourglass on Windows 10) and type “environment variables” to get a suggestion to edit the system environment variables. (Where this actually is differs on Windows versions, so use the finder to find it.)

Be careful how aggressively you cull stuff from the list. In general, do not remove stuff from the global environment variables — especially anything in any subdirectory of C:\Windows! But feel free to remove anything you want from the local user’s (your) environment variables. If something you want stops working, you can add it back. (You did copy and save your original list, right?)

A lot of programs just add themselves to the path when they install, even when they don’t need to. Sometimes you will find stuff listed multiple times. And you will occasionally find something weird, like multiple semicolons. Feel free to fix all that, until mpath gives you a short, pretty list of essential items, with your bin directory listed right at the top.
The idea is to cull the PATH down to only those items currently needed, and restore it to that state when you are done needing anything extra.

This is the very same principle you should apply in Linux. *nixen tend to do most of that for you, so it is rare to have to care there.

On Windows, though, it might make all the difference. For example, if you open your prompt right now and type g++, exactly which GCC are you invoking? If you’ve installed Perl, you might get that one. Or TDM, that one. Or worse, parts of both.

Keep your PATH clean.

That’s the key.

[edit]
I’m really confused about how the Report button gets used by some people. George P’s commentary seemed right on and useful.

And, honestly, as it’s my topic, it would seem to me that, unless someone is posting spam or violent or vulgar or otherwise anti-social stuff, I ought to be the only one with my finger over what belongs in this thread or not...
Last edited on
Ah, takes me back to the good old days of MS-DOS and the clever 'tricks' done ...
:) :) :)

Apparently I have a semi any-mouse stalker reporting me. Heh.

Yo. loser! It doesn't matter, I am still here!

FYI, the new CPlusPlus version is having issues in the forums, I had to log out and log back in using the legacy version to be able to post this.
Heh, I can post again...

@seeplus
I never considered simply setting up your terminal and basic PATH control (something I learned from Unix) to be esoteric... I wonder what most people’s experience is?
<no archive>
*strolls through...*

Hmmmm, I'm still here. Gosh, darn! :Þ
Registered users can post here. Sign in or register to post.
Pages: 12