Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b63a752d8a | ||
|
|
73e92c88b9 | ||
|
|
ce081ba799 | ||
|
|
39a25350ee |
@@ -1,8 +1,6 @@
|
||||
# Demordle
|
||||
# Crowdle
|
||||
|
||||
- TODO: come up with a better name.
|
||||
|
||||
**Demordle** is *democratic wordle*. This is a nebulous premise with multiple interpretations; so instead of picking one, `demordle` implements them all!
|
||||
**Crowdle** is *democratic wordle*. This is a nebulous premise with multiple interpretations; so instead of picking one, `crowdle` implements them all!
|
||||
|
||||
In all cases, "democratic" means _multiplayer cooperative_ where game actions are decided by vote. The players agree to play ahead of time and share a victory or loss. We also specifically mean _direct_ democracy where every player has equal representation in the voting process.[^representative]
|
||||
|
||||
|
||||
+2315
-10657
File diff suppressed because it is too large
Load Diff
+83
-2
@@ -1,5 +1,86 @@
|
||||
const std = @import("std");
|
||||
const Wordle = @import("wordle.zig");
|
||||
const Dict = @import("dict.zig");
|
||||
|
||||
pub fn main() void {
|
||||
std.debug.print("Hello, {s}!\n", .{"World"});
|
||||
pub fn main() !void {
|
||||
// acquire stdout writer
|
||||
var stdoutBuf: [1024]u8 = undefined;
|
||||
var stdoutFile = std.fs.File.stdout().writer(&stdoutBuf);
|
||||
if (stdoutFile.err) |err| return err;
|
||||
const stdout = &stdoutFile.interface;
|
||||
|
||||
// acquire stdin reader
|
||||
var stdinBuf: [1024]u8 = undefined;
|
||||
var stdinFile = std.fs.File.stdin().reader(&stdinBuf);
|
||||
if (stdinFile.err) |err| return err;
|
||||
const stdin = &stdinFile.interface;
|
||||
|
||||
// select a random dictionary word as the solution
|
||||
const dict = Dict.getDictionary();
|
||||
const solutionIdx = std.crypto.random.intRangeAtMost(usize, 0, dict.len);
|
||||
|
||||
// create a game with the chosen solution
|
||||
var game: Wordle.Game = .{ .solution = dict[solutionIdx] };
|
||||
|
||||
// play game until over
|
||||
while (!game.isOver()) {
|
||||
// display guess prompt
|
||||
try stdout.writeAll("Guess: ");
|
||||
try stdout.flush();
|
||||
|
||||
// read next guess
|
||||
const input = try stdin.takeDelimiter('\n') orelse continue;
|
||||
|
||||
// assert that input is correct size
|
||||
if (input.len != Wordle.WordLen) {
|
||||
try stdout.writeAll("Guess is wrong length.\n");
|
||||
try stdout.flush();
|
||||
continue;
|
||||
}
|
||||
|
||||
// convert to word
|
||||
var guess: Wordle.Word = undefined;
|
||||
@memcpy(&guess, input);
|
||||
|
||||
// test if guess is valid
|
||||
if (!Dict.isInDictionary(guess)) {
|
||||
try stdout.writeAll("Guess is not in dictionary.\n");
|
||||
try stdout.flush();
|
||||
continue;
|
||||
}
|
||||
|
||||
// display clues
|
||||
const clues = Wordle.checkGuess(guess, game.solution);
|
||||
try writeClues(stdout, clues);
|
||||
|
||||
// add guess
|
||||
try game.addGuess(guess);
|
||||
}
|
||||
|
||||
// display message win/lose
|
||||
if (game.isWon()) {
|
||||
try stdout.writeAll("You win!\n");
|
||||
} else {
|
||||
try stdout.writeAll("You lose :(\n");
|
||||
}
|
||||
|
||||
// display spoilered guesses
|
||||
for (game.guesses()) |guess| {
|
||||
try writeClues(stdout, Wordle.checkGuess(guess, game.solution));
|
||||
}
|
||||
|
||||
// flush stdout
|
||||
try stdout.flush();
|
||||
}
|
||||
|
||||
pub fn writeClues(out: *std.io.Writer, clues: Wordle.Clues) !void {
|
||||
for (clues) |clue| {
|
||||
try out.writeAll(switch (clue) {
|
||||
Wordle.Clue.Gray => "⬛",
|
||||
Wordle.Clue.Yellow => "🟨",
|
||||
Wordle.Clue.Green => "🟩",
|
||||
});
|
||||
}
|
||||
|
||||
try out.writeAll("\n");
|
||||
}
|
||||
|
||||
@@ -9,6 +9,51 @@ pub const Word = [WordLen]u8;
|
||||
/// The type of string literals representing words.
|
||||
pub const WordLiteral = *const [WordLen:0]u8;
|
||||
|
||||
/// The number of rounds in a single Wordle game.
|
||||
pub const GameLen = 6;
|
||||
|
||||
/// An error reported when a move cannot be played since the game is over.
|
||||
pub const GameOver = error{GameOver};
|
||||
|
||||
/// A structure for a single Wordle game.
|
||||
pub const Game = struct {
|
||||
/// The hidden word to guess.
|
||||
solution: Word,
|
||||
|
||||
/// The round number (starts with 0).
|
||||
round: u32 = 0,
|
||||
|
||||
/// The current (and future) word guesses.
|
||||
///
|
||||
/// The values of guessBuf[self.round..] are undefined.
|
||||
guessBuf: [GameLen]Word = @splat(@splat(0)),
|
||||
|
||||
/// Fetches the current guesses.
|
||||
pub fn guesses(self: *const Game) []const Word {
|
||||
return self.guessBuf[0..self.round];
|
||||
}
|
||||
|
||||
/// Tests if the game is won.
|
||||
pub fn isWon(self: Game) bool {
|
||||
for (self.guesses()) |guess|
|
||||
if (std.mem.eql(u8, &guess, &self.solution)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Tests if the game is over.
|
||||
pub fn isOver(self: Game) bool {
|
||||
return self.round >= GameLen or self.isWon();
|
||||
}
|
||||
|
||||
/// Guesses a word unless the game is over.
|
||||
pub fn addGuess(self: *Game, guess: Word) GameOver!void {
|
||||
if (self.isOver()) return error.GameOver;
|
||||
self.guessBuf[self.round] = guess;
|
||||
self.round += 1;
|
||||
}
|
||||
};
|
||||
|
||||
/// A clue for a spot given a guess.
|
||||
pub const Clue = enum {
|
||||
Gray,
|
||||
@@ -98,3 +143,20 @@ test "anagram" {
|
||||
test "duplicate letters" {
|
||||
try expectGuessClues("fuzzy", "zesty", " Y G");
|
||||
}
|
||||
|
||||
test "game" {
|
||||
// default state
|
||||
var game: Game = .{ .solution = strToWord("poise") };
|
||||
try std.testing.expect(!game.isWon());
|
||||
try std.testing.expect(!game.isOver());
|
||||
|
||||
// first guess
|
||||
try game.addGuess(strToWord("brown"));
|
||||
try std.testing.expect(!game.isWon());
|
||||
try std.testing.expect(!game.isOver());
|
||||
|
||||
// second guess
|
||||
try game.addGuess(strToWord("poise"));
|
||||
try std.testing.expect(game.isWon());
|
||||
try std.testing.expect(game.isOver());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user