Skip to content
Merged
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
6 changes: 3 additions & 3 deletions thecardplace/Cribbage/WEB-ACCESSIBILITY-AUDIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@ after the game had all three. **A page nothing looks at is a page that rots.**

### Still open

- **#3 colour-only play count** — the count is given as text ("Count: 15"), so
- **#3 color-only play count** — the count is given as text ("Count: 15"), so
this is not a 1.4.1 failure as written, but there is still no textual cue when
the count approaches 31.
- **#6, #8, #10, #15, #16** — board focus indicator, redundant ARIA on the board,
focus restoration, ARIA descriptions, gradient background.
- **No interface tests at all.** There is nothing equivalent to Sheephead's
`ui-dom.js`: announcements, labels, focus behaviour and keyboard handling are
`ui-dom.js`: announcements, labels, focus behavior and keyboard handling are
untested. That is the layer this audit is about, and it is the most valuable
thing left to build. See `../TESTING.md`.

Expand All @@ -89,7 +89,7 @@ hands, under by three to nine points — and that the last card of every play ph
scored nothing at all.

No accessibility audit would ever have caught either. The game announced its
wrong answer perfectly clearly, in a well-labelled live region, at better than
wrong answer perfectly clearly, in a well-labeled live region, at better than
4.5:1 contrast. **It was accessible and wrong**, which for a player relying on
that announcement is the worse of the two failures.

Expand Down
10 changes: 5 additions & 5 deletions thecardplace/TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ Cribbage's found three real bugs, all now fixed:
The first is worth dwelling on: a 4-5-6-6 hand scored 9 instead of 12, and had done since the game
was written. It is not subtle, it is not rare, and no amount of accessibility auditing, geometry
measurement or interface testing would ever have found it — because the game announced its wrong
answer perfectly clearly, in a well-labelled live region, at 4.5:1 contrast.
answer perfectly clearly, in a well-labeled live region, at 4.5:1 contrast.

### Mutation tested

Expand Down Expand Up @@ -269,8 +269,8 @@ waits the deadline out, and it does catch the fault.
|---|---|
| `sheephead/tests/layout.js` | Horizontal overflow, card size and aspect ratio, tap targets, the setup screen, two-column reading order — 6 viewports × 2 font sizes |
| `sheephead/tests/card-overlap.js` | Every index, pip and court glyph measured for intersection |
| `sheephead/tests/appearance.js` | Both skins × both colour schemes: the chosen skin actually applies, red suits render red, an unplayable card keeps its colour and has nothing painted over it, a played card is readable at half size, and a blocked card still looks different from a playable one |
| `sheephead/tests/contrast.js` | Every text element's real colour against what is actually painted behind it, WCAG AA by size |
| `sheephead/tests/appearance.js` | Both skins × both color schemes: the chosen skin actually applies, red suits render red, an unplayable card keeps its color and has nothing painted over it, a played card is readable at half size, and a blocked card still looks different from a playable one |
| `sheephead/tests/contrast.js` | Every text element's real color against what is actually painted behind it, WCAG AA by size |
| `Cribbage/tests/audit.js` | **Both pages** — overflow, card geometry and collisions, contrast, tap targets, duplicate ids, heading order, main landmark, table captions, `th` scope, emoji or arrows in link text |

These found a formal accessibility audit's blind spot: Cribbage scored 78/100 in a review that
Expand Down Expand Up @@ -357,7 +357,7 @@ Listed because an undocumented gap reads as coverage.
connections to the in-process server, but only one of them is a real `Table`, because `Table` is a
module singleton. Two browsers racing for the same seat, or both pressing Deal, is covered at the
room level and not at the interface level.
- **Nothing checks colour contrast.** Sheephead has `contrast.js`; euchre inherits its stylesheet
- **Nothing checks color contrast.** Sheephead has `contrast.js`; euchre inherits its stylesheet
and has no equivalent, so a palette change here would go unmeasured.

### All of them
Expand All @@ -369,7 +369,7 @@ Listed because an undocumented gap reads as coverage.

Two things that suite learned the hard way, worth knowing before extending it. **A CSS filter is
invisible to `getComputedStyle`** — it changes the pixels and nothing else, so a greyscale that
flattens the red suits cannot be found by reading colours; the filter itself has to be asserted
flattens the red suits cannot be found by reading colors; the filter itself has to be asserted
on. And **measuring only the first suit glyph on a card missed a real break**, because a card
shows its suit in three places and the corner index was still red while the pips were not.
- **No shared harness.** The measurement logic in `sheephead/tests/*.js` and `Cribbage/tests/audit.js`
Expand Down
14 changes: 7 additions & 7 deletions thecardplace/euchre/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ deployed to Cloudflare from CI. Everything else runs in the browser.

Once a suit is trump, the two highest cards in the game are the **right bower**
(the jack of trump) and the **left bower** — the jack of the *other suit of the
same colour*. And while it is the left bower, **it is not a card of its printed
same color*. And while it is the left bower, **it is not a card of its printed
suit at all**. With spades trump, the jack of clubs is a spade: it follows
spades, and you may not play it on a club lead if you hold any spade.

A sighted player absorbs that from five cards at a glance. Read out card by card,
it is a memory exercise with a colour rule in it, performed while three other
it is a memory exercise with a color rule in it, performed while three other
people wait. So:

- **Both bowers are named as bowers** wherever a card is read out — in your hand,
Expand Down Expand Up @@ -72,7 +72,7 @@ down a per-player table — a number printed twice invites being read as two
numbers. <kbd>S</kbd> says the tricks each side has this hand, the game score,
the match, and how many more tricks you need to make it or to euchre them.

**The dealer's discard is shown, not summarised.** When a hand ends, the actual
**The dealer's discard is shown, not summarized.** When a hand ends, the actual
cards are laid out: the upcard, what the dealer put back, and the three cards
nobody ever sees at a real table. "The dealer discarded" tells you nothing.

Expand All @@ -83,7 +83,7 @@ it will never play. Its Cards column says "out".
becomes your turn — and to the bidding buttons when the decision is a bid rather
than a card — but not while you are in a text field, reading the help, or reading
back through the log. The announcement still tells you it is your turn. You can
turn the behaviour off in Settings.
turn the behavior off in Settings.

**Pace is configurable, in real seconds.** Computer turns can advance instantly,
after four seconds, after ten, or only when you press Continue. The timed
Expand All @@ -101,9 +101,9 @@ toolbar under the table — nothing depends on a shortcut being available, and
<kbd>Tab</kbd>, <kbd>Enter</kbd> and <kbd>Space</kbd> alone are enough to play a
whole game.

Also: visible focus outlines, no colour-only meaning (trump is labelled as well
Also: visible focus outlines, no color-only meaning (trump is labeled as well
as tinted), a skip link, semantic headings and tables, and support for
`prefers-reduced-motion`, `prefers-contrast` and forced-colours mode.
`prefers-reduced-motion`, `prefers-contrast` and forced-colors mode.

### Keys

Expand Down Expand Up @@ -184,7 +184,7 @@ Measured over 4,000 hands per row against the hard opponents (`npm run balance`)
| normal | 95.5% | 13.8% | 12.2% | 8.1% | 67.2% |
| hard | 94.1% | 12.9% | 14.2% | 9.1% | 65.3% |

Those are the numbers a euchre player would recognise, and they are the reason
Those are the numbers a euchre player would recognize, and they are the reason
`tests/balance.js` exists. The first draft of the bidding thresholds threw more
than two hands in five straight in the bin — a game nobody would sit through, and
completely invisible to every test that only checks the rules are obeyed.
Expand Down
6 changes: 3 additions & 3 deletions thecardplace/euchre/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ <h3>The bowers &mdash; the one rule that surprises everybody</h3>
<ul>
<li><strong>The right bower</strong> &mdash; the jack of the trump suit.</li>
<li><strong>The left bower</strong> &mdash; the jack of the <em>other suit of the same
colour</em>. And while it is the left bower, <strong>it is a trump card and not a card of
color</em>. And while it is the left bower, <strong>it is a trump card and not a card of
its printed suit at all</strong>. With spades trump, the jack of clubs is a spade: it
follows spades, and you may not play it on a club lead if you hold any spade.</li>
</ul>
Expand Down Expand Up @@ -568,7 +568,7 @@ <h3>Reading your hand while you bid</h3>
<p>Pressing <kbd>H</kbd> during the bidding tells you what your hand would look like
<em>with the suit on offer as trump</em> &mdash; which cards would be trump, and which jack
would become the left bower. A sighted player works that out at a glance from cards they can
see all at once. Having to hold four jacks and a colour rule in your head while a timer runs
see all at once. Having to hold four jacks and a color rule in your head while a timer runs
is a different game, and a harder one, so the program does the mapping and you make the
decision.</p>

Expand All @@ -589,7 +589,7 @@ <h3>Announcements</h3>
<h3>Focus</h3>
<p>Focus moves to your cards when it becomes your turn, but never while you are typing in a
field, reading this help, or reading back through the log. The announcement still tells you it
is your turn. You can turn the behaviour off in Settings.</p>
is your turn. You can turn the behavior off in Settings.</p>

<h3>Playing with other people</h3>
<p>At an online table you cannot see the other players, so the game says what silence means:
Expand Down
2 changes: 1 addition & 1 deletion thecardplace/euchre/tests/rules-oracle.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function check(cond, msg) { checks++; if (!cond) fails.push(msg); }
const SUITS = ['C', 'S', 'H', 'D'];
const RANKS = ['A', 'K', 'Q', 'J', 'T', '9'];

/* "the jack of the other suit of the same colour" */
/* "the jack of the other suit of the same color" */
const SAME_COLOUR = { C: 'S', S: 'C', H: 'D', D: 'H' };

/* "with spades trump the order is: jack of spades, jack of clubs, ace, king,
Expand Down
6 changes: 4 additions & 2 deletions thecardplace/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ <h3>Euchre</h3>
<p class="game-meta">4 players &middot; on your own or with other people</p>
</div>
<div class="game-body">
<p>The Midwest and Ontario standard. Two partnerships, five tricks a hand, first to ten points &mdash; and the jack of the same colour as trump quietly becomes a trump too.</p>
<p>The Midwest and Ontario standard. Two partnerships, five tricks a hand, first to ten points &mdash; and the jack of the same color as trump quietly becomes a trump too.</p>
<p class="game-links">
<a class="learn" href="euchre/#rules-h">Learn to play Euchre</a>
<a class="play" href="euchre/">Play Euchre</a>
Expand Down Expand Up @@ -276,7 +276,9 @@ <h2>Why these exist</h2>

<footer>
<p>Built by Kelly Ford. Source and issues on
<a href="https://github.com/kellylford/TheWorkBench">GitHub</a>.</p>
<a href="https://github.com/kellylford/TheWorkBench">GitHub</a>.
<a href="privacy.html">Privacy</a>.
Help with the app: <a href="mailto:support@theideaplace.net">support@theideaplace.net</a>.</p>
</footer>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public enum EuchreHelp {

("The bowers — the one rule that surprises everybody",
"Once a suit is trump, the two highest cards in the game are the right bower — the jack of the " +
"trump suit — and the left bower — the jack of the other suit of the same colour. And while it " +
"trump suit — and the left bower — the jack of the other suit of the same color. And while it " +
"is the left bower, it is a trump card and not a card of its printed suit at all. With spades " +
"trump, the jack of clubs is a spade: it follows spades, and you may not play it on a club lead " +
"if you hold any spade. " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ final class EuchreRulesOracleTests: XCTestCase {
static let suits: [Suit] = [.clubs, .spades, .hearts, .diamonds]
static let ranks = ["A", "K", "Q", "J", "T", "9"]

/// "the jack of the other suit of the same colour"
/// "the jack of the other suit of the same color"
static let sameColour: [Suit: Suit] = [.clubs: .spades, .spades: .clubs, .hearts: .diamonds, .diamonds: .hearts]

/// "with spades trump the order is: jack of spades, jack of clubs, ace, king,
Expand Down
14 changes: 7 additions & 7 deletions thecardplace/ios/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ once. (`Shared/PaceGate.swift`)
12, tricks 3" — and partnership games score by side, not by a number repeated
in two columns.

**Nothing by colour alone.** Red suits are red, but the suit is printed as a
symbol, trump and points are written on the card, an unplayable card is greyed
**Nothing by color alone.** Red suits are red, but the suit is printed as a
symbol, trump and points are written on the card, an unplayable card is grayed
and marked with a cross, a selected card has a thick border and a tick. The
red is 6.6:1 on white. Cards follow Dynamic Type up to the accessibility sizes
and wrap onto more rows rather than shrinking; every control is at least 44
Expand All @@ -173,11 +173,11 @@ yet.

| Criterion | How |
| --- | --- |
| 1.1.1 Non-text content | Card faces are hidden from VoiceOver; the button label carries everything the face shows. Icons are decorative or labelled. |
| 1.3.1 Info and relationships | Headings carry the header trait; tables are read as rows; the hand is a labelled group. |
| 1.3.3 Sensory characteristics | No instruction depends on position or colour. |
| 1.4.1 Use of colour | Suit symbols, text badges, cross and tick marks alongside colour. |
| 1.4.3 / 1.4.11 Contrast | Card ink 6.6:1 or better on its ground; system colours elsewhere; Increase Contrast thickens borders. |
| 1.1.1 Non-text content | Card faces are hidden from VoiceOver; the button label carries everything the face shows. Icons are decorative or labeled. |
| 1.3.1 Info and relationships | Headings carry the header trait; tables are read as rows; the hand is a labeled group. |
| 1.3.3 Sensory characteristics | No instruction depends on position or color. |
| 1.4.1 Use of color | Suit symbols, text badges, cross and tick marks alongside color. |
| 1.4.3 / 1.4.11 Contrast | Card ink 6.6:1 or better on its ground; system colors elsewhere; Increase Contrast thickens borders. |
| 1.4.4 / 1.4.12 Resize text | Dynamic Type everywhere, including inside cards via `@ScaledMetric`. |
| 1.4.10 Reflow | Cards wrap; nothing scrolls sideways. |
| 2.1.1 Keyboard | Every action is a button; shortcuts exist for review and Continue. |
Expand Down
12 changes: 10 additions & 2 deletions thecardplace/ios/TheCardPlace.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
03D04F7FE8F58D9184B73A56 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3F405F1AD88DD8A5285E1281 /* PrivacyInfo.xcprivacy */; };
044EB7E107C60C0C207EB597 /* CribbageEngine in Frameworks */ = {isa = PBXBuildFile; productRef = F94700B9513EA796740F09B3 /* CribbageEngine */; };
0D1B0DD6377E1CD0052394A7 /* Announcer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6568E1912006FA72B3DAA2C /* Announcer.swift */; };
0FDB6B6AEB144C7A27E905E0 /* CribbageTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAF045FB25E4ADB2CA67D558 /* CribbageTableView.swift */; };
Expand All @@ -20,6 +21,7 @@
30DB4DC415FC689D02F002B1 /* CribbageSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = F892E0A3B6953A3B37E00A59 /* CribbageSession.swift */; };
4594862BDB9DA6803DBF36D8 /* SheepheadSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A121D0F39113DF5761205 /* SheepheadSession.swift */; };
53641618134321494D720AA1 /* EuchreTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ACA079333595E3D760851C7 /* EuchreTableView.swift */; };
56E5ABE0C3D57BE5FA5FF190 /* ScreenshotUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3126D727AE0DE59B7E914C00 /* ScreenshotUITests.swift */; };
5C9E10A35902374CB686FEFB /* EuchreUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12686483D5D0F698A83F0DDE /* EuchreUITests.swift */; };
6710621CF6DA3E7983B4BA6C /* SpadesUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1F2D50DBA2115DF077A2CBF /* SpadesUITests.swift */; };
684B07A81624AD6E30F4A099 /* HeartsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7B915DFA27181FB20DE3E72 /* HeartsUITests.swift */; };
Expand Down Expand Up @@ -62,6 +64,8 @@
22AD0206ACBAF4A849EA37DF /* EuchreSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EuchreSession.swift; sourceTree = "<group>"; };
2D4B17D881934D07D0ACB538 /* HeartsSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartsSession.swift; sourceTree = "<group>"; };
2DD2B004D362E811BB4314AB /* GameDispatch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameDispatch.swift; sourceTree = "<group>"; };
3126D727AE0DE59B7E914C00 /* ScreenshotUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenshotUITests.swift; sourceTree = "<group>"; };
3F405F1AD88DD8A5285E1281 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
3FE0B1F95772E2B4F7FAF40A /* GameKind.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameKind.swift; sourceTree = "<group>"; };
4AC3B197FBCAF26199F2B6EA /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
4FB405CFABFA389A83F32338 /* Support.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Support.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -114,6 +118,7 @@
children = (
6DD4E6714CC3174B232DEBED /* Assets.xcassets */,
BA5231380811FB9C801986A6 /* Info.plist */,
3F405F1AD88DD8A5285E1281 /* PrivacyInfo.xcprivacy */,
DEC4F04C6B855D0E3A80F318 /* TheCardPlaceApp.swift */,
1A613F1CEB72A94C322F8404 /* Games */,
50DF580E37675B6BEE01C71C /* Hub */,
Expand Down Expand Up @@ -185,6 +190,7 @@
D40675BACF55461868978BF6 /* CribbageUITests.swift */,
12686483D5D0F698A83F0DDE /* EuchreUITests.swift */,
E7B915DFA27181FB20DE3E72 /* HeartsUITests.swift */,
3126D727AE0DE59B7E914C00 /* ScreenshotUITests.swift */,
CDA075E69F49B49AAB03E8E2 /* SheepheadUITests.swift */,
D1F2D50DBA2115DF077A2CBF /* SpadesUITests.swift */,
4FB405CFABFA389A83F32338 /* Support.swift */,
Expand Down Expand Up @@ -340,6 +346,7 @@
buildActionMask = 2147483647;
files = (
B93E79FD2C9DF036FE4E993B /* Assets.xcassets in Resources */,
03D04F7FE8F58D9184B73A56 /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -383,6 +390,7 @@
E8408F656A481472872DE22F /* CribbageUITests.swift in Sources */,
5C9E10A35902374CB686FEFB /* EuchreUITests.swift in Sources */,
684B07A81624AD6E30F4A099 /* HeartsUITests.swift in Sources */,
56E5ABE0C3D57BE5FA5FF190 /* ScreenshotUITests.swift in Sources */,
88439E0C853714EA8B2AC48C /* SheepheadUITests.swift in Sources */,
6710621CF6DA3E7983B4BA6C /* SpadesUITests.swift in Sources */,
6FE6B97889EA9F7152F0E6FD /* Support.swift in Sources */,
Expand Down Expand Up @@ -503,7 +511,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 3;
CURRENT_PROJECT_VERSION = 5;
INFOPLIST_FILE = TheCardPlace/Info.plist;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
Expand Down Expand Up @@ -592,7 +600,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 3;
CURRENT_PROJECT_VERSION = 5;
INFOPLIST_FILE = TheCardPlace/Info.plist;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
Expand Down
Loading
Loading