Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .github/workflows/data-tests.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
name: Wordle Data Tests

on:
- push
- pull_request
push:
paths:
- 'content/**'
paths_ignore:
- 'assets/**'
pull_request:
paths:
- 'content/**'
paths_ignore:
- 'assets/**'

jobs:
run-data-tests:
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/node-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Node.js CI

on:
push:
paths:
- 'assets/js/wordle/**'
pull_request:
paths:
- 'assets/js/wordle/**'

jobs:
build:
name: Build
runs-on: ubuntu-latest
defaults:
run:
working-directory: assets/js/wordle
strategy:
matrix:
node-version: [16.x, 18.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"standard.autoFixOnSave": true,
"standard.enableGlobally": false
}
2 changes: 2 additions & 0 deletions assets/js/wordle/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
.nyc_output
3 changes: 3 additions & 0 deletions assets/js/wordle/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.nyc_output
.github
.vscode
5 changes: 5 additions & 0 deletions assets/js/wordle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Wordle Tools

## test

npm test
19 changes: 19 additions & 0 deletions assets/js/wordle/compare-word-lists.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const crypto = require('crypto')

const before = require('./solutions-nyt.json')
const after = require('./solutions-nyt-2022-04-03.json')

console.log(`
before: ${before.length}
after: ${after.length}
`)

for (let i = 0; i < after.length; i++) {
const beforeSha = crypto.createHash('sha1')
beforeSha.update(before[i + 1])

const afterSha = crypto.createHash('sha1')
afterSha.update(after[i])

console.log(`${i} ${beforeSha.digest('hex') === afterSha.digest('hex')}`)
}
75 changes: 75 additions & 0 deletions assets/js/wordle/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const epoch = new Date('2021-06-19T00:00:00')

function getPuzzleDate (num) {
const startDate = new Date(epoch)
const puzzleDate = startDate.setHours(0, 0, 0, 0) + (num * 864e5)
return (new Date(puzzleDate)).toISOString().substr(0, 10)
}

function decodeEmoji (input) {
const title = input.match(/Wordle [0-9]* [1-6]{1}\/6\*?/)
const titlePieces = title[0].split(' ')
const puzzleNum = parseInt(titlePieces[1], 10)
const puzzleDate = getPuzzleDate(puzzleNum)
const guessPieces = titlePieces[2].split('')
const [guessCount, slash, allowed, modeStr] = guessPieces // eslint-disable-line no-unused-vars

const results = input.match(/[🟩🟨⬛️]*/g) // eslint-disable-line no-misleading-character-class
.filter(r => r !== '')
.map((line) => {
return [...line]
.filter(a => /[^\ufe0f]/.test(a))
.map((char) => {
if (char === '🟩') {
return 'correct'
} else if (char === '🟨') {
return 'present'
} else {
return 'absent'
}
})
})

const enrichedResults = results.map((lineStatuses) => {
const lineEmoji = lineStatuses.map((status) => {
if (status === 'correct') return '🟩'
if (status === 'present') return '🟨'
return '⬛️' // absent
})

const lineProgress = lineStatuses.reduce((memo, status) => {
if (status === 'correct') return memo + 2
if (status === 'present') return memo + 1
return memo + 0 // absent
}, 0)

const lineScore = lineStatuses.reduce((memo, status) => {
if (status === 'correct') return memo + 0
if (status === 'present') return memo + 1
return memo + 2 // absent
}, 0)

return {
lineStatuses,
lineEmoji,
lineProgress,
lineScore
}
})

const puzzleScore = enrichedResults.reduce((memo, result) => {
return memo + result.lineScore
}, 0)

return {
results,
enrichedResults,
puzzleScore,
puzzleNum,
puzzleDate,
guessCount: parseInt(guessCount, 10),
isHardMode: modeStr === '*'
}
}

module.exports = { decodeEmoji }
72 changes: 72 additions & 0 deletions assets/js/wordle/ios-shortcut.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const stats = JSON.parse(window.localStorage.getItem('nyt-wordle-statistics'))
const state = JSON.parse(window.localStorage.getItem('nyt-wordle-state'))
const epoch = new Date('2021-06-19T00:00:00')
const solutionCount = 2309

function getDaysBetween (start, end) {
const startDate = new Date(start)
const daysBetween = new Date(end).setHours(0, 0, 0, 0) - startDate.setHours(0, 0, 0, 0)
return Math.floor(daysBetween / 864e5)
}

function getPuzzleNumber (today) {
const puzzleNumber = getDaysBetween(epoch, today) % solutionCount
return puzzleNumber
}

// from: https://usefulangle.com/post/30/javascript-get-date-time-with-offset-hours-minutes
function getLocalTimeZone () {
const timezoneOffsetMin = new Date().getTimezoneOffset()
let offsetHours = parseInt(Math.abs(timezoneOffsetMin / 60), 10)
let offsetMin = Math.abs(timezoneOffsetMin % 60)
let timezoneStandard
if (offsetHours < 10) { offsetHours = '0' + offsetHours }
if (offsetMin < 10) { offsetMin = '0' + offsetMin }
if (timezoneOffsetMin < 0) {
timezoneStandard = '+' + offsetHours + ':' + offsetMin
} else if (timezoneOffsetMin > 0) {
timezoneStandard = '-' + offsetHours + ':' + offsetMin
} else if (timezoneOffsetMin === 0) {
timezoneStandard = 'Z'
}
return timezoneStandard
}

function getDateTime (dateStr) {
const dt = new Date(dateStr)
let currentDate = dt.getDate()
let currentMonth = dt.getMonth() + 1
const currentYear = dt.getFullYear()
let currentHrs = dt.getHours()
let currentMins = dt.getMinutes()
let currentSecs = dt.getSeconds()

currentDate = currentDate < 10 ? '0' + currentDate : currentDate
currentMonth = currentMonth < 10 ? '0' + currentMonth : currentMonth
currentHrs = currentHrs < 10 ? '0' + currentHrs : currentHrs
currentMins = currentMins < 10 ? '0' + currentMins : currentMins
currentSecs = currentSecs < 10 ? '0' + currentSecs : currentSecs

const currentDatetime = currentYear + '-' + currentMonth + '-' + currentDate + 'T' + currentHrs + ':' + currentMins + ':' + currentSecs
return currentDatetime
}

const puzzleNumber = getPuzzleNumber(new Date())
const puzzleDate = getDateTime(state.lastCompletedTs).substring(0, 10)
const fileText = `---
title: "${puzzleNumber}: ${puzzleDate}"
date: ${getDateTime(state.lastCompletedTs) + getLocalTimeZone()}
tags: []
words: ${JSON.stringify(state.boardState.filter(w => w !== ''))}
puzzles: [${puzzleNumber}]
state: ${JSON.stringify(state, null, 2)}
stats: ${JSON.stringify(stats, null, 2)}
---
<!-- more -->
`

const encodedFileText = encodeURIComponent(fileText)
const filename = `${puzzleDate}.md`
const githubQueryLink = 'https://github.com/tphummel/wordle/new/main/content/w/new?quick_pull=1&labels=puzzle&value=' + encodedFileText + '&filename=' + filename
// Call completion to finish - iOS shortcuts specific function
completion(githubQueryLink) // eslint-disable-line no-undef
Loading