{"id":15009253,"url":"https://github.com/gsurma/slitherin","last_synced_at":"2025-08-01T05:08:12.728Z","repository":{"id":48932088,"uuid":"146071729","full_name":"gsurma/slitherin","owner":"gsurma","description":"AI research environment for the game of Snake 🐍 .","archived":false,"fork":false,"pushed_at":"2021-07-09T08:43:09.000Z","size":35011,"stargazers_count":90,"open_issues_count":3,"forks_count":24,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-09T17:54:23.568Z","etag":null,"topics":["ai","bfs","dfs","dnn","genetic-algorithm","genetic-algorithms","gym","hamiltonian","longest-path","monte-carlo","openai","openai-gym","python","python27","requests-for-research","rl","slitherin-gym","snake","snake-game"],"latest_commit_sha":null,"homepage":"https://gsurma.github.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gsurma.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"patreon":"gsurma"}},"created_at":"2018-08-25T06:32:55.000Z","updated_at":"2025-03-20T17:49:30.000Z","dependencies_parsed_at":"2022-09-24T00:23:53.827Z","dependency_job_id":null,"html_url":"https://github.com/gsurma/slitherin","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gsurma/slitherin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gsurma%2Fslitherin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gsurma%2Fslitherin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gsurma%2Fslitherin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gsurma%2Fslitherin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gsurma","download_url":"https://codeload.github.com/gsurma/slitherin/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gsurma%2Fslitherin/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268171959,"owners_count":24207437,"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-08-01T02:00:08.611Z","response_time":67,"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":["ai","bfs","dfs","dnn","genetic-algorithm","genetic-algorithms","gym","hamiltonian","longest-path","monte-carlo","openai","openai-gym","python","python27","requests-for-research","rl","slitherin-gym","snake","snake-game"],"created_at":"2024-09-24T19:24:01.158Z","updated_at":"2025-08-01T05:08:12.620Z","avatar_url":"https://github.com/gsurma.png","language":"Python","funding_links":["https://patreon.com/gsurma"],"categories":[],"sub_categories":[],"readme":"\u003ch3 align=\"center\"\u003e\n  \u003cimg src=\"assets/slitherin_icon_web.png\" width=\"300\"\u003e\n\u003c/h3\u003e\n\n# Slitherin\n\n\nAI research environment for the game of Snake written in Python 2.7. Part of the [OpenAI - Request For Research 2.0](https://blog.openai.com/requests-for-research-2/).\n\n\nCheck out corresponding Medium articles:\n\n[Slitherin - Solving the Classic Game of Snake🐍 with AI🤖 (Part 1: Domain Specific Solvers)](https://towardsdatascience.com/slitherin-solving-the-classic-game-of-snake-with-ai-part-1-domain-specific-solvers-d1f5a5ccd635)\n\n[Slitherin - Solving the Classic Game of Snake🐍 with AI🤖 (Part 2: General Purpose Solvers)](https://towardsdatascience.com/slitherin-solving-the-classic-game-of-snake-with-ai-part-2-general-purpose-random-monte-25dc0dd4c4cf)\n\n[Slitherin - Solving the Classic Game of Snake🐍 with AI🤖 (Part 3: Genetic Evolution)](https://towardsdatascience.com/slitherin-solving-the-classic-game-of-snake-with-ai-part-3-genetic-evolution-33186e6be110)\n\n\nTable of Contents\n=================\n\n  * [Usage](#usage)\n  * [Rules](#rules)\n  * [Modes](#modes)\n     * [Domain specific](#domain-specific)\n        * [Shortest Path BFS](#shortest-path-bfs)\n        * [Shortest Path DFS](#shortest-path-dfs)\n        * [Longest path](#longest-path)\n        * [Hamilton](#hamilton)\n        * [DNN](#dnn)\n        * [DNN Monte Carlo](#dnn-monte-carlo)\n     * [General purpose](#general-purpose)\n        * [Human](#human)\n        * [Random](#random)\n        * [Monte Carlo](#monte-carlo)\n        * [DNN Genetic Evolution](#dnn-genetic-evolution)\n  * [Work in progress](#work-in-progress)\n\n## Usage\n\n1. Clone the repo.\n2. Go to the project's root folder.\n3. Install required packages`pip install -r requirements.txt`.\n4. Launch slitherin. I recommend starting with the help mode to see all available modes `python slitherin.py --help`.\n\n## Rules\n1. Snake has to move either forward, left or right.\n2. Snake dies when hits wall or itself.\n3. For every eaten fruit, snake's length increases by 1 and a new fruit is generated on a random unoccupied place.\n\n## Modes\nAll mode previews contain \u003cspan style=\"color:green\"\u003ecurrent score\u003c/span\u003e **Mode Name (min/avg/max)**.\nAll modes are benchmarked on a 12x12 grid.\n\n### Domain specific\n\u003e Algorithms are using domain specific data like snake's position, direction, neighbors etc.\n\n\n#### Shortest Path BFS\n`python slitherin.py --shortest_path_bfs`\n\n\u003cimg src=\"assets/gifs/shortest_path_bfs.gif\" width=\"200\"\u003e\n\u003cimg src=\"scores/shortest_path_bfs.png\"\u003e\n\nGenerates the shortest path from the snake’s head to the fruit using BFS algorithm.\n\nOptimal performance during early stages, but as the snake grows, its body creates an unavoidable obstacle for the leading head. \n\n---\n\n#### Shortest Path DFS\n`python slitherin.py --shortest_path_dfs`\n\n\u003cimg src=\"assets/gifs/shortest_path_dfs.gif\" width=\"200\"\u003e\n\u003cimg src=\"scores/shortest_path_dfs.png\"\u003e\n\nGenerates the shortest path from the snake’s head to the fruit using DFS algorithm.\n\nPerforms worse than BFS due to the graph’s cyclicity.\n\n---\n\n#### Longest path\n`python slitherin.py --longest_path`\n\n\u003cimg src=\"assets/gifs/longest_path.gif\" width=\"200\"\u003e\n\u003cimg src=\"scores/longest_path.png\"\u003e\n\nFirstly, generates the shortest path (BFS) between the snake’s head and the fruit. Then for each pair of points in the path, tries to extend the distance between them with available actions.\n\nSnake dies when its body is on a generated path.\n\n---\n\n#### Hamilton\n`python slitherin.py --hamilton`\n\n\u003cimg src=\"assets/gifs/hamilton.gif\" width=\"200\"\u003e\n\u003cimg src=\"scores/hamilton.png\"\u003e\n\nGenerates a longest path between the snake’s head and its tail. \n\nIn the vast majority of the cases, such path covers the whole environment creating [Hamiltonian path](https://en.wikipedia.org/wiki/Hamiltonian_path), thus solving the game of snake with a perfect score.\n\n---\n\n#### DNN\n\n\u003e Each Deep Neural Net mode has a same model structure of:\n\u003e \n\u003e * input layer with 5 neurons [action\\_vector, left\\_neighbor, forward\\_neighbor, right\\_neighbor, angle\\_to\\_fruit]\n\u003e * hidden layer with 125 neurons (ReLU 6 activation)\n\u003e * output layer with 1 neuron (value for a given action\\_vector)\n\n`python slitherin.py --deep_neural_net`\n\n`python slitherin.py --deep_neural_net_trainer`\n\n\u003cimg src=\"assets/gifs/dnn.gif\" width=\"200\"\u003e\n\u003cimg src=\"scores/deep_neural_net.png\"\u003e\n\nTraining phase consists of performing random gameplays followed by the evaluation and backpropagation of performed actions and its results. \n\nRewards:\n\n* **0.7** for eating the fruit\n* **0.1** for moving towards the fruit\n* **-0.2** for moving away of the fruit\n* **-1.0** for dying\n\nAs expected, DNN solver performs well in the early stages. Snake goes straight to the fruit and doesn't go into cycles. However as it gets longer, it starts to have problems with going around itself. With the current model structure (data about only the nearest surroundings), a snake doesn't indicate any sense of 'the whole environment orientation and position'\n\n---\n\n#### DNN Monte Carlo\n`python slitherin.py --deep_neural_net_monte_carlo`\n\n\u003cimg src=\"assets/gifs/dnn_monte_carlo.gif\" width=\"200\"\u003e\n\u003cimg src=\"scores/deep_neural_net_monte_carlo.png\"\u003e\n\nFor each possible action, there is a DNN-driven gameplay generated. Gameplay with the highest score is chosen for an ultimate move.\n\nVery slow and inefficient performance in the beginning, but favorable in the late stages. DNN-driven simulations allow the snake to choose relatively wise long-term moves.\n\n\n---\n\n### General purpose\n\u003e Algorithms are not using any domain specific data.\n\n\n#### Human \n`python slitherin.py --human`\n\nUsed for debug, development and fun:).\n\n---\n\n#### Random \n`python slitherin.py --random`\n\n\u003cimg src=\"assets/gifs/random.gif\" width=\"200\"\u003e\n\u003cimg src=\"scores/random.png\"\u003e\n\n\nIt's always good to start benchmarking against randomness (at least pseudo).\n\nAs expected, very low performance.\n\n---\n\n#### Monte Carlo \n`python slitherin.py --monte_carlo`\n\n\u003cimg src=\"assets/gifs/monte_carlo.gif\" width=\"200\"\u003e\n\u003cimg src=\"scores/monte_carlo.png\"\u003e\n\nFor each move, performs a set of 1000 random run simulations. Then groups them by the initial action and finally picks the action that started gameplays with the highest average score.\n\nSlow and weak performance.\n\n---\n\n#### DNN Genetic Evolution\n`python slitherin.py --deep_neural_net_genetic_evolution`\n\n`python slitherin.py --deep_neural_net_genetic_evolution_trainer`\n\n\u003cimg src=\"assets/gifs/dnn_genetic_evolution.gif\" width=\"200\"\u003e\n\u003cimg src=\"scores/deep_neural_net_genetic_evolution.png\"\u003e\n\nInitial population starts with random weights. Then in the selection phase, the top 0.1 of the population gets picked to the uniform crossover stage. In the crossover phase, parents are paired using roulette selection (the highest the score, the highest the probability of breeding). Finally, in the mutation phase, 0.01 of the weights of all offsprings are being mutated to the random values. Then we start again with a new population created fully by the newly bred offsprings. Above cycle is being repeated until convergence which happens usually around 25th generation and the average score of 22.\n\nPerformance is relatively satisfactory. Snake correctly learned that taking the shortest path to the fruit isn't a good solution in the late stages, but ultimately still gets trapped within its own body.\n\n\n## Work in progress\nMultiplayer (multi-agent) version of slitherin is currently being developed.\n\nStay tuned!\n\n\n## Author\n\n**Greg (Grzegorz) Surma**\n\n[**PORTFOLIO**](https://gsurma.github.io)\n\n[**GITHUB**](https://github.com/gsurma)\n\n[**BLOG**](https://medium.com/@gsurma)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgsurma%2Fslitherin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgsurma%2Fslitherin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgsurma%2Fslitherin/lists"}