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
7 changes: 4 additions & 3 deletions bin/generate-spec
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,12 @@ if not path.exists(exercise_directory)
if not path.exists("#{exercise_directory}/.meta/spec_generator.moon")
die "#{exercise_name} does not have a spec_generator module.\n"

canonical_data_url = "https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/#{exercise_name}/canonical-data.json"
canonical_data_path = "canonical-data/#{exercise_name}.json"

assert os.execute('mkdir -p "$(dirname "' .. canonical_data_path .. '")"')
assert os.execute('curl "' .. canonical_data_url .. '" -s -o "' .. canonical_data_path .. '"')
if not path.exists canonical_data_path
canonical_data_url = "https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/#{exercise_name}/canonical-data.json"
assert os.execute('mkdir -p "$(dirname "' .. canonical_data_path .. '")"')
assert os.execute('curl "' .. canonical_data_url .. '" -s -o "' .. canonical_data_path .. '"')

-- "json.null" ref: https://dkolf.de/dkjson-lua/documentation
canonical_data = json.decode file.read(canonical_data_path, false), 1, json.null
Expand Down
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,14 @@
"prerequisites": [],
"difficulty": 4
},
{
"slug": "save-the-cow",
"name": "Save the Cow",
"uuid": "7b85dc03-54e5-45ea-ac02-a9da503c89e9",
"practices": [],
"prerequisites": [],
"difficulty": 4
},
{
"slug": "series",
"name": "Series",
Expand Down
5 changes: 5 additions & 0 deletions exercises/practice/save-the-cow/.busted
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
return {
default = {
ROOT = { '.' }
}
}
7 changes: 7 additions & 0 deletions exercises/practice/save-the-cow/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Instructions

Implement the logic for a word-guessing game.

A player tries to solve a secret word by guessing individual letters.
They win if they reveal all the letters in the secret word.
They lose if they make ten incorrect guesses before revealing the word.
4 changes: 4 additions & 0 deletions exercises/practice/save-the-cow/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Introduction

Bessie the cow has wandered onto an alien spaceship.
Guess the secret door code to bring her home before the ship blasts off.
17 changes: 17 additions & 0 deletions exercises/practice/save-the-cow/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"authors": [
"glennj"
],
"files": {
"solution": [
"save_the_cow.moon"
],
"test": [
"save_the_cow_spec.moon"
],
"example": [
".meta/example.moon"
]
},
"blurb": "Implement a word-guessing game."
}
35 changes: 35 additions & 0 deletions exercises/practice/save-the-cow/.meta/example.moon
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class SaveTheCow
new: (@word) =>
@guessed = {}
@errsAvailable = 9
@state = 'Ongoing'

guess: (letters) =>
for guess in *letters
if @state == 'Win' then error 'cannot guess after the game is won'
if @state == 'Lose' then error 'cannot guess after the game is lost'

if @guessed[guess]
@errsAvailable -= 1
else
found = not not @word\find guess
@guessed[guess] = found
if not found
@errsAvailable -= 1

@state = 'Lose' if @errsAvailable < 0
@state = 'Win' if not @mask!\find '_'

@currentState!

currentState: =>
{
state: @state,
maskedWord: @mask!,
remainingFailures: math.max 0, @errsAvailable
}

mask: =>
@word\gsub '%a', (c) -> @guessed[c] and c or '_'


21 changes: 21 additions & 0 deletions exercises/practice/save-the-cow/.meta/spec_generator.moon
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import indent, quote, table_dump, word_list from require 'spec_helpers'

{
module_name: 'SaveTheCow',

generate_test: (case, level) ->
lines = if case.expected.error
{
"game = SaveTheCow #{quote case.input.word}",
"f = -> game\\guess #{word_list case.input.guesses}",
"assert.has.error f, #{quote case.expected.error}"
}
else
{
"game = SaveTheCow #{quote case.input.word}",
"result = game\\guess #{word_list case.input.guesses}",
"expected = #{table_dump case.expected, level}",
"assert.are.same expected, result"
}
table.concat [indent line, level for line in *lines], '\n'
}
40 changes: 40 additions & 0 deletions exercises/practice/save-the-cow/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[71d340f9-fc29-4826-872e-ad7d0b83dd98]
description = "Initially 9 failures are allowed and no letters are guessed"

[76759c24-8f1a-4fc8-9ffd-d6a1ff0cf03b]
description = "After 10 failures the game is over"

[d6f2e202-7857-46fb-b709-43a7f3f3b2de]
description = "Losing with several correct guesses"

[71bc0cda-2032-4637-80c8-fc8771124c08]
description = "Feeding a correct letter removes underscores"

[5b568a1c-867d-418f-97a8-7b6f8a7ca0a2]
description = "Feeding a correct letter twice counts as a failure"

[3d40f15b-0271-4c5d-b1a4-3e1f66ff221f]
description = "Guessing a repeated letter reveals all instances"

[11a86435-e401-4250-a26e-3b0d8c4049ad]
description = "Getting all the letters right makes for a win"

[b3d81876-84ee-45bb-b531-baa1b05b4709]
description = "Winning on the last guess is still a win"

[cf204398-5e9f-402f-8bff-42cb7cbbbda9]
description = "Guessing after a lose is error"

[c2ec5b3d-4923-4a0e-a485-6aa6e78c7ece]
description = "Guessing after a win is error"
6 changes: 6 additions & 0 deletions exercises/practice/save-the-cow/save_the_cow.moon
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class SaveTheCow
new: (word) =>
error 'Implement the constructor'

guess: (letters) =>
error 'Implement the guess method'
92 changes: 92 additions & 0 deletions exercises/practice/save-the-cow/save_the_cow_spec.moon
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
SaveTheCow = require 'save_the_cow'

describe 'save-the-cow:', ->
it 'Initially 9 failures are allowed and no letters are guessed', ->
game = SaveTheCow 'loot'
result = game\guess {}
expected = {
remainingFailures: 9
state: 'Ongoing'
maskedWord: '____'
}
assert.are.same expected, result

pending 'After 10 failures the game is over', ->
game = SaveTheCow 'loot'
result = game\guess {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
expected = {
remainingFailures: 0
state: 'Lose'
maskedWord: '____'
}
assert.are.same expected, result

pending 'Losing with several correct guesses', ->
game = SaveTheCow 'loot'
result = game\guess {'t', 'o', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
expected = {
remainingFailures: 0
state: 'Lose'
maskedWord: '_oot'
}
assert.are.same expected, result

pending 'Feeding a correct letter removes underscores', ->
game = SaveTheCow 'loot'
result = game\guess {'t'}
expected = {
remainingFailures: 9
state: 'Ongoing'
maskedWord: '___t'
}
assert.are.same expected, result

pending 'Feeding a correct letter twice counts as a failure', ->
game = SaveTheCow 'loot'
result = game\guess {'t', 't'}
expected = {
remainingFailures: 8
state: 'Ongoing'
maskedWord: '___t'
}
assert.are.same expected, result

pending 'Guessing a repeated letter reveals all instances', ->
game = SaveTheCow 'loot'
result = game\guess {'t', 't', 'o'}
expected = {
remainingFailures: 8
state: 'Ongoing'
maskedWord: '_oot'
}
assert.are.same expected, result

pending 'Getting all the letters right makes for a win', ->
game = SaveTheCow 'loot'
result = game\guess {'t', 't', 'o', 'l'}
expected = {
remainingFailures: 8
state: 'Win'
maskedWord: 'loot'
}
assert.are.same expected, result

pending 'Winning on the last guess is still a win', ->
game = SaveTheCow 'loot'
result = game\guess {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 't', 'o', 'l'}
expected = {
remainingFailures: 0
state: 'Win'
maskedWord: 'loot'
}
assert.are.same expected, result

pending 'Guessing after a lose is error', ->
game = SaveTheCow 'loot'
f = -> game\guess {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'}
assert.has.error f, 'cannot guess after the game is lost'

pending 'Guessing after a win is error', ->
game = SaveTheCow 'loot'
f = -> game\guess {'t', 'o', 'l', 'l'}
assert.has.error f, 'cannot guess after the game is won'
Loading