Skip to content

Commit

Permalink
Merge pull request #57 from tmck-code/combine-name-and-category
Browse files Browse the repository at this point in the history
Support filtering by both name and category
  • Loading branch information
tmck-code authored Mar 12, 2024
2 parents 58bb84e + 4391aa4 commit b673963
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 2 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ DEBUG=test go test -v ./test/
## TODO

- Short-term
- [ ] add short versions of command line args
- [ ] support long and short cli args (e.g. --name/-n)
- [ ] optionally print ID assigned to each pokemon, support deterministic selection via the same ID
- Longer-term
- Completed
- [x] Make the category struct faster to load - currently takes up to 80% of the execution time
Expand All @@ -168,3 +169,4 @@ DEBUG=test go test -v ./test/
- [x] Make data structure to hold categories, names and pokemon
- [x] Increase speed
- [x] Improve categories to be more specific than shiny/regular
- [x] Filter by both name and category
18 changes: 18 additions & 0 deletions pokesay.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,22 @@ func runPrintByCategory(args pokesay.Args) {
t.PrintJson()
}

func runPrintByNameAndCategory(args pokesay.Args) {
t := timer.NewTimer("runPrintByNameAndCategory", true)

names := pokedex.ReadStructFromBytes[map[string][]int](GOBAllNames)
t.Mark("read name struct")

metadata, final := pokesay.ChooseByNameAndCategory(names, args.NameToken, GOBCowNames, MetadataRoot, args.Category)
t.Mark("find and read metadata")

pokesay.Print(args, final.EntryIndex, GenerateNames(metadata, args), final.Categories, GOBCowData)
t.Mark("print")

t.Stop()
t.PrintJson()
}

func runPrintRandom(args pokesay.Args) {
t := timer.NewTimer("runPrintRandom", true)
choice := pokesay.RandomInt(pokedex.ReadIntFromBytes(GOBTotal))
Expand All @@ -175,6 +191,8 @@ func main() {
runListCategories()
} else if args.ListNames {
runListNames()
} else if args.NameToken != "" && args.Category != "" {
runPrintByNameAndCategory(args)
} else if args.NameToken != "" {
runPrintByName(args)
} else if args.Category != "" {
Expand Down
53 changes: 52 additions & 1 deletion src/pokesay/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ func RandomInt(n int) int {
return rand.New(Rand).Intn(n)
}

// ChooseByCategory chooses a pokemon via a requested category
// 1. It loads the category search structure and finds the name of a random Pokemon matching the entry
// e.g. if given the category "small", this function might pick the file `1.cat` in
// - categories/
// - small/
// - 1.cat
// - 44.cat
//
// This file contains entries representing the <pokemon metadata index>/<the pokemon entry index>,
// e.g. "4/1" would represent 4.metadata, and the 2nd entry in that file
// 2. Using the indexes, load the corresponding metadata file and entry, and then return it
func ChooseByCategory(category string, categoryDir []fs.DirEntry, categoryFiles embed.FS, categoryRootDir string, metadataFiles embed.FS, metadataRootDir string) (pokedex.PokemonMetadata, pokedex.PokemonEntryMapping) {
if len(categoryDir) == 0 {
log.Fatalf("cannot find pokemon by category '%s'", category)
Expand Down Expand Up @@ -53,7 +64,7 @@ func ListNames(names map[string][]int) []string {
return pokedex.GatherMapKeys(names)
}

func ChooseByName(names map[string][]int, nameToken string, metadataFiles embed.FS, metadataRootDir string) (pokedex.PokemonMetadata, pokedex.PokemonEntryMapping) {
func fetchMetadataByName(names map[string][]int, nameToken string, metadataFiles embed.FS, metadataRootDir string) pokedex.PokemonMetadata {
match := names[nameToken]
if len(match) == 0 {
log.Fatalf("cannot find pokemon by name '%s'", nameToken)
Expand All @@ -64,10 +75,50 @@ func ChooseByName(names map[string][]int, nameToken string, metadataFiles embed.
metadataFiles,
pokedex.MetadataFpath(metadataRootDir, nameChoice),
)
return metadata

}

func ChooseByName(names map[string][]int, nameToken string, metadataFiles embed.FS, metadataRootDir string) (pokedex.PokemonMetadata, pokedex.PokemonEntryMapping) {
metadata := fetchMetadataByName(
names,
nameToken,
metadataFiles,
metadataRootDir,
)

// pick a random entry
choice := RandomInt(len(metadata.Entries))
return metadata, metadata.Entries[choice]
}

func ChooseByNameAndCategory(names map[string][]int, nameToken string, metadataFiles embed.FS, metadataRootDir string, category string) (pokedex.PokemonMetadata, pokedex.PokemonEntryMapping) {
// fetch the metadata of a pokemon matching the nameToken
metadata := fetchMetadataByName(
names,
nameToken,
metadataFiles,
metadataRootDir,
)

// now try and find a metadata entry that matches the requested category
matching := make([]pokedex.PokemonEntryMapping, 0)
for _, entry := range metadata.Entries {
for _, entryCategory := range entry.Categories {
if entryCategory == category {
matching = append(matching, entry)
}
}
}

// if the category is not found for this pokemon, return a random entry
if len(matching) == 0 {
return metadata, metadata.Entries[RandomInt(len(metadata.Entries))]
} else {
return metadata, matching[RandomInt(len(matching))]
}
}

func ChooseByRandomIndex(totalInBytes []byte) (int, int) {
total := pokedex.ReadIntFromBytes(totalInBytes)
return total, RandomInt(total)
Expand Down
15 changes: 15 additions & 0 deletions test/pokesay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,21 @@ func TestChooseByCategory(test *testing.T) {
Assert(expectedEntry, entry, test)
}

func TestChooseByNameAndCategory(test *testing.T) {
names := make(map[string][]int)
names["hoothoot"] = []int{4}
metadata, entry := pokesay.ChooseByNameAndCategory(
names,
"hoothoot",
GOBCowNames,
"data/cows",
"small",
)

Assert("small", entry.Categories[0], test)
Assert("Hoothoot", metadata.Name, test)
}

func TestChooseByRandomIndex(test *testing.T) {
resultTotal, result := pokesay.ChooseByRandomIndex(GOBTotal)
Assert(9, resultTotal, test)
Expand Down

0 comments on commit b673963

Please sign in to comment.