{"id":21714233,"url":"https://github.com/mingyi850/boggle-api","last_synced_at":"2026-05-18T03:04:39.030Z","repository":{"id":42585286,"uuid":"284743340","full_name":"mingyi850/boggle-api","owner":"mingyi850","description":"Backend service for a boggle game","archived":false,"fork":false,"pushed_at":"2023-01-19T20:16:40.000Z","size":271,"stargazers_count":0,"open_issues_count":8,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-20T19:34:52.219Z","etag":null,"topics":["games","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mingyi850.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-08-03T15:57:39.000Z","updated_at":"2024-04-20T15:22:54.000Z","dependencies_parsed_at":"2023-02-11T20:40:12.884Z","dependency_job_id":null,"html_url":"https://github.com/mingyi850/boggle-api","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mingyi850/boggle-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mingyi850%2Fboggle-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mingyi850%2Fboggle-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mingyi850%2Fboggle-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mingyi850%2Fboggle-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mingyi850","download_url":"https://codeload.github.com/mingyi850/boggle-api/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mingyi850%2Fboggle-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276235403,"owners_count":25608049,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-21T02:00:07.055Z","response_time":72,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["games","ruby"],"created_at":"2024-11-26T00:33:23.930Z","updated_at":"2025-09-21T11:46:15.406Z","avatar_url":"https://github.com/mingyi850.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# boggle-api\n\nAuthor: Lim Mingyi\n\nDate: 04/08/2020\n\nThis project is part of the assignment from Saleswhale as part of the recruitment process.\nIt contains the boggle api which can be used to serve a boggle\ngame for players. This readme will describe how to setup and run this \nbasic api. \n\nDocumentation of my thought process can be found below\n\n## Setup\n### Requirements\nRuby version: 2.6\n\nbundle (install using gem install bundle)\n\n### Building the Project\nStart by installing dependencies using\n\u003e \u003ccode\u003e bundle install \u003c/code\u003e\n\nThen, create the database by running\n\n\u003e \u003ccode\u003e rails db:migrate \u003c/code\u003e\n\n### Running rspecs (unit tests):\nBefore running rspecs, change the SERVER_URL in the .env file to the\nserver location. This defaults to http://localhost:3000 but varies with your\nconfiguration. \n\nOnce done, run\n\n\u003e \u003ccode\u003e bundle exec rspec spec \u003c/code\u003e\n\nthis should run all tests (including provided integration tests)\n\n### Initialising the Server\nOn a terminal, start by running\n\u003e \u003ccode\u003e rails server  \u003c/code\u003e\n\nThis should start the server on localhost at on given port (e.g http://localhost:3000)\n\n## API Use (from problem statement)\n### Create the game\n\n- Endpoint\n\n```\nPOST /games\n```\n\n- Parameters:\n  + `duration` (required): the time (in seconds) that specifies the duration of\n    the game\n  + `random` (required): if `true`, then the game will be generated with random\n    board.  Otherwise, it will be generated based on input.\n  + `board` (optional): if `random` is not true, this will be used as the board\n    for new game. If this is not present, new game will get the default board\n    from `test_board.txt`\n\n- Response:\n  + Success (status 201 Created)\n\n```json\n{\n  \"id\": 1,\n  \"token\": \"9dda26ec7e476fb337cb158e7d31ac6c\",\n  \"duration\": 12345,\n  \"board\": \"A, C, E, D, L, U, G, *, E, *, H, T, G, A, F, K\"\n}\n```\n\n### Play the game\n\n- Endpoint\n\n```\nPUT /games/:id\n```\n\n- Parameters:\n  + `id` (required): The ID of the game\n  + `token` (required): The token for authenticating the game\n  + `word` (required): The word that can be used to play the game\n\n- Response:\n  + Success (status 200 OK)\n\n```json\n{\n  \"id\": 1,\n  \"token\": \"9dda26ec7e476fb337cb158e7d31ac6c\",\n  \"duration\": 12345,\n  \"board\": \"A, C, E, D, L, U, G, *, E, *, H, T, G, A, F, K\",\n  \"time_left\": 10000,\n  \"points\": 10\n}\n```\n\n### Show the game\n\n- Endpoint\n\n```\nGET /games/:id\n```\n\n- Parameters:\n  + `id` (required): The ID of the game\n\n- Response:\n  + Success (status 200 OK)\n\n```json\n{\n  \"id\": 1,\n  \"token\": \"9dda26ec7e476fb337cb158e7d31ac6c\",\n  \"duration\": 12345,\n  \"board\": \"A, C, E, D, L, U, G, *, E, *, H, T, G, A, F, K\",\n  \"time_left\": 10000,\n  \"points\": 10\n}\n```\n## Discussion\nI want to start by saying that while my experience with the rails\nframework (but not ruby) is limited, I learnt a lot during this project, so I would\nlike to thank SalesWhale for the opportunity to work on this.\n\nIn this section I would like to document and explain my thoughts behind certain\ndesign decisions or choice methods in key areas of the code.\n\nI will describe my thought process behind the following major components\n1. Design Patterns\n2. Finding entries in board (search algorithm)\n3. Game Schema\n\n### Design Patterns\nGiven the MVC framework, separation of responsibility is important between\nthe controllers and the Model. \nThe Model should handle data related operations on the model object\nwhile controllers should serve the correct data to the model and render views.\n\n#### GamesCreator\nHowever, given the complex nature of the model initialisation, I decided to create\na new class called \u003ccode\u003e GamesCreator \u003c/code\u003e.\n\nGamesCreator handles the following:\n1. Input Validation\n2. Object construction for fixed and random attributes\n3. Construction of the game model\n\nBy designating these tasks to the GamesCreator, we reduce the bulk in the\ncorresponding controller which gives us more readable code, while delegating\nthe responsibility of object creation logic to another logical unit (or class).\n\nShould we decide to change how the game object is initialised in future, we can \ndo so easily by just editing the GamesCreator class and methods.\nThe model is built and returned to the controller. More importantly, only the \ncontroller calls save to publish any changes to the database if needed. Once again,\nseparation of responsibility.\n\n#### GamesManager\n\nOnce again, we have an issue with the logic of validation and search. While it \nshouldn't go into the controller, it doesn't directly deal with the model itself. \nThus, I decided to write a separate class to handle searching logic and model interaction.\nGamesManager contains all the GameError classes which allows us to specify custom errors\nin a readable form. This also allows us to group and consolidate errors which can be \nrescued by the controller.\n\nBy the use of these 2 service classes, we can keep the controller thin and the model\n(and services) fat, while achieving separation of components.\n\n### Search Algorithm: finding entries in the board\n\nFor this section, I considered several approaches, each with tradeoffs:\n1. Naive search: find every single substring on the board and check if\na word exists in the board. O(4^n) runtime, O(1) space, where n is length of a word\n2. Backtracking Depth First search: Find all the starting points of the word, conduct depth-first search \non all starting points to see if the word exists. O(4^n) runtime, O(n) space\n3. Word Hashing: upon initialisation of the board, we \niterate through the dictionary and check if each word exists on the board. If it does,\nwe save the word in a set. Future lookups just need to query the set. Lookup: O(1) time complexity\nInitialisastion: O(D) runtime where D is the chars in the dictionary. O(D) space complexity\n\nWhile both 2 and 3 were viable solutions here, I decided to go with algorithm 2 for\nthe following reason:\n1. Given the small size of the board, the runtime of the algorithm is not as much of \na concern. Given the random nature of the board and the rarity of words with a the average time complexity is \nunlikely to be near the worst-case, if at all.\n2. The storage of large amounts of words, while would provide a better worst-case runtime, might prove \nto be a bad tradeoff here as the database entries keep coming in. The response time of this search\npales in comparison to the latency from the API over a network connection and is thus not worth\nthe extra storage.\n\nThus, i decided to go with the DFS method which is easy to follow and provides decent average time\ncomplexity and space complexity.\n\n### Games Schema\nThe game schema is almost identically as described by the problem statement, with slight changes\n1. The game retains a set of all visited words. This is important for validation\n2. The game retains a alternate representation of the board in the form of a char_map.\nThis represents a slight tradeoff between space complexity for speed in searching.\n\n### Testing\nI've included rspec unit tests for each component except the controller (which should be tested using\nthe integration tests provided). \n\n### Conclusion\nI definitely enjoyed building this, and if anything it was a great learning experience.\nI would still like to learn more about design patterns in Rails if given the chance - as well\nas to validate some of the assumptions I had about the MVC architecture. While my understanding\nof the topic might be rudimentary for now, I will definitely look to learn more about it in \nmy own time, or better yet, given the change to do so in the Backend Engineering team.\n\nI hope this gives you a glimpse into my thought process, and that you can let me know\nwhat feedback you have for me after this assignment!\n\nMingyi\n\n\n\n \n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmingyi850%2Fboggle-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmingyi850%2Fboggle-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmingyi850%2Fboggle-api/lists"}