Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
Jake | ead5522c68 | |
Jake | 7194fefc5c | |
Jake | a39fce6c07 | |
Jake | 147cb22e88 | |
Jake | 3ab9f195a3 | |
Jake | dbfbf0efa2 | |
Jake | f596b23055 |
|
@ -0,0 +1,26 @@
|
|||
# Wordle
|
||||
|
||||
This is a clone of Wordle which is played in your terminal!
|
||||
|
||||
The same wordlist is used in this project so you get the same words each
|
||||
day as if you played on the official website.
|
||||
|
||||
![Screenshot](./screenshot.png)
|
||||
|
||||
This is built using [Bubble Tea](https://github.com/charmbracelet/bubbletea)
|
||||
and [Lip Gloss](https://github.com/charmbracelet/lipgloss).
|
||||
|
||||
## Features
|
||||
|
||||
- [x] Statistics are saved to `~/.wordle.json` for use in other programs
|
||||
- [x] Same word list as the official website
|
||||
- [ ] Leaderboard of people on current tilde
|
||||
- [x] Update checking
|
||||
- [ ] Export to sharable message/emojis
|
||||
- [ ] Share to Mastodon
|
||||
- [ ] Play previous days
|
||||
|
||||
## Usage
|
||||
|
||||
Simply download one of the binaries from the [release page](https://tildegit.org/jakew/wordle/releases),
|
||||
then run it to get started.
|
|
@ -46,8 +46,11 @@ func (b *Board) AddWord(word string) string {
|
|||
}
|
||||
b.CurrentGuess += 1
|
||||
|
||||
if len(correct) == 5 || b.CurrentGuess >= 6 {
|
||||
if len(correct) == 5 {
|
||||
b.Done = true
|
||||
} else if b.CurrentGuess >= 6 {
|
||||
b.Done = true
|
||||
b.CurrentGuess = -1
|
||||
}
|
||||
|
||||
return ""
|
||||
|
|
|
@ -35,7 +35,12 @@ func ToGame(b *game.Board) *Game {
|
|||
Lines: []Line{},
|
||||
}
|
||||
|
||||
for i := 0; i < b.CurrentGuess; i++ {
|
||||
to := b.CurrentGuess
|
||||
if b.CurrentGuess == -1 {
|
||||
to = 6
|
||||
}
|
||||
|
||||
for i := 0; i < to; i++ {
|
||||
g.Lines = append(g.Lines, Line{
|
||||
Word: string(b.Guesses[i].Letters),
|
||||
Correct: b.Guesses[i].Correct,
|
||||
|
|
|
@ -49,6 +49,7 @@ func Check(word string, solution string) (correct, present []int) {
|
|||
// check if correct position
|
||||
if letter == int32(solution[i]) {
|
||||
correct = append(correct, i)
|
||||
exclude = append(exclude, i)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,12 @@ func TestCheck(t *testing.T) {
|
|||
wantCorrect: []int{0, 1, 2, 3, 4},
|
||||
wantPresent: []int{},
|
||||
},
|
||||
{
|
||||
name: "double letter guess",
|
||||
args: args{word: "trots", solution: "those"},
|
||||
wantCorrect: []int{0, 2},
|
||||
wantPresent: []int{4},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module tildegit.org/jakew/wordle
|
|||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/Masterminds/semver/v3 v3.1.1
|
||||
github.com/charmbracelet/bubbletea v0.19.3
|
||||
github.com/charmbracelet/lipgloss v0.4.0
|
||||
)
|
||||
|
|
2
go.sum
2
go.sum
|
@ -1,3 +1,5 @@
|
|||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/charmbracelet/bubbletea v0.19.3 h1:OKeO/Y13rQQqt4snX+lePB0QrnW80UdrMNolnCcmoAw=
|
||||
github.com/charmbracelet/bubbletea v0.19.3/go.mod h1:VuXF2pToRxDUHcBUcPmCRUHRvFATM4Ckb/ql1rBl3KA=
|
||||
github.com/charmbracelet/lipgloss v0.4.0 h1:768h64EFkGUr8V5yAKV7/Ta0NiVceiPaV+PphaW1K9g=
|
||||
|
|
19
main.go
19
main.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"os"
|
||||
|
@ -8,6 +9,7 @@ import (
|
|||
"tildegit.org/jakew/wordle/game/score"
|
||||
"tildegit.org/jakew/wordle/game/util"
|
||||
"tildegit.org/jakew/wordle/game/words"
|
||||
"tildegit.org/jakew/wordle/update"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
|
@ -20,6 +22,7 @@ type model struct {
|
|||
func initialModel() model {
|
||||
m := model{
|
||||
board: game.NewBoard(),
|
||||
buffer: []rune{},
|
||||
}
|
||||
|
||||
lastGame, err := score.GetLastGame()
|
||||
|
@ -28,7 +31,7 @@ func initialModel() model {
|
|||
return m
|
||||
}
|
||||
|
||||
if lastGame != nil {
|
||||
if lastGame != nil && lastGame.Day == m.board.Day {
|
||||
m.error = fmt.Sprintf("Come back tomorrow for a new word")
|
||||
m.board = &game.Board{
|
||||
Guesses: [6]game.Guess{},
|
||||
|
@ -83,7 +86,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
// clear input
|
||||
m.buffer = []rune{}
|
||||
|
||||
// save if win
|
||||
// save if done
|
||||
if m.board.Done {
|
||||
err := score.SaveBoard(m.board)
|
||||
if err != nil {
|
||||
|
@ -113,7 +116,7 @@ func (m model) View() string {
|
|||
for i, guess := range m.board.Guesses {
|
||||
line := " "
|
||||
for j := 0; j < 5; j++ {
|
||||
if i < m.board.CurrentGuess {
|
||||
if i < m.board.CurrentGuess || m.board.CurrentGuess == -1 {
|
||||
style := charEmptyStyle
|
||||
if util.ContainsInt(guess.Correct, j) {
|
||||
style = charCorrectStyle
|
||||
|
@ -144,8 +147,10 @@ func (m model) View() string {
|
|||
s += promptStyle.Render(footer) + "\n"
|
||||
} else {
|
||||
msg := ""
|
||||
if m.board.CurrentGuess >= 6 {
|
||||
if m.board.CurrentGuess == -1 {
|
||||
if m.board.Solution != "" {
|
||||
msg += fmt.Sprintf("Oof! The word was %s.", m.board.Solution)
|
||||
}
|
||||
} else {
|
||||
msg += fmt.Sprintf("Congrats! You guessed in %d.", m.board.CurrentGuess)
|
||||
}
|
||||
|
@ -162,6 +167,12 @@ func (m model) View() string {
|
|||
}
|
||||
|
||||
func main() {
|
||||
updateMsg := update.CheckVersion(update.GetGiteaRelease("tildegit.org", "jakew", "wordle"), BuildVersion)
|
||||
if updateMsg != "" {
|
||||
fmt.Println(fmt.Sprintf("%v. Press enter to continue...", updateMsg))
|
||||
bufio.NewReader(os.Stdin).ReadBytes('\n')
|
||||
}
|
||||
|
||||
p := tea.NewProgram(initialModel())
|
||||
if err := p.Start(); err != nil {
|
||||
fmt.Printf("Something has gone wrong: %v", err)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 258 KiB |
|
@ -32,11 +32,11 @@ var charEmptyStyle = lipgloss.NewStyle().
|
|||
|
||||
// character in wrong position
|
||||
var charWrongPositionStyle = charEmptyStyle.Copy().
|
||||
Foreground(lipgloss.Color("11"))
|
||||
Foreground(lipgloss.Color("1"))
|
||||
|
||||
// character in correct position
|
||||
var charCorrectStyle = charEmptyStyle.Copy().
|
||||
Foreground(lipgloss.Color("10"))
|
||||
Foreground(lipgloss.Color("2"))
|
||||
|
||||
var errorStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("9")).
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package update
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func GetGiteaRelease(instance string, owner string, repo string) *semver.Version {
|
||||
res, err := http.Get(fmt.Sprintf("https://%v/api/v1/repos/%v/%v/releases", instance, owner, repo))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer res.Body.Close()
|
||||
body, err := io.ReadAll(res.Body)
|
||||
|
||||
var data []struct {
|
||||
TagName string `json:"tag_name"`
|
||||
}
|
||||
err = json.Unmarshal(body, &data)
|
||||
if err != nil || len(data) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
v, err := semver.NewVersion(data[0].TagName)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func CheckVersion(latest *semver.Version, current string) string {
|
||||
if latest == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
current1, err := semver.NewVersion(current)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if latest.GreaterThan(current1) {
|
||||
return fmt.Sprintf("A new version, %s, is available for download", latest)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package main
|
||||
|
||||
var (
|
||||
BuildVersion string = "?"
|
||||
)
|
Loading…
Reference in New Issue