[{"data":1,"prerenderedAt":321},["ShallowReactive",2],{"nav-pages":3,"footer-socials":160,"$nLR9CPt1-i":183,"projects-python-sudoku":204,"tag-python":314},[4,127],{"id":5,"title":6,"body":7,"crumbs":115,"description":119,"extension":120,"icon":117,"meta":121,"navigation":122,"path":123,"seo":124,"stem":125,"__hash__":126},"pages\u002Fpages\u002F1.index.md","Home",{"type":8,"value":9,"toc":109},"minimark",[10,15,19,24,27,61,64,96,99,103],[11,12,14],"h1",{"id":13},"my-portfolio","My Portfolio",[16,17,18],"p",{},"Hi there, welcome to my portfolio website.",[20,21,23],"h2",{"id":22},"who-am-i","Who am I?",[16,25,26],{},"I'm George, a software engineer with an interest in self-hosting, programming, and hardware.",[16,28,29,30,37,38,43,44,49,50,55,56,60],{},"I studied BSC Computer Science at ",[31,32,36],"a",{"href":33,"rel":34},"https:\u002F\u002Fwww.cardiff.ac.uk\u002F",[35],"nofollow","Cardiff University",", the projects I did during my time there can be found on my ",[31,39,42],{"href":40,"rel":41},"https:\u002F\u002Fcode.ggrainger.uk\u002Fggrainger?tab=repositories",[35],"Forgejo"," or ",[31,45,48],{"href":46,"rel":47},"https:\u002F\u002Fgithub.com\u002Frandomman552",[35],"GitHub"," though I have migrated most of these to my self-hosted Forgejo instance. For my dissertation I created a website to show sensor information in Cardiff University's new Abacws building, which you can see the code for ",[31,51,54],{"href":52,"rel":53},"https:\u002F\u002Fcode.ggrainger.uk\u002Fggrainger\u002FAbacws-Data-Vis",[35],"here"," or my deployment of ",[31,57,54],{"href":58,"rel":59},"https:\u002F\u002Fabacws.ggrainger.uk\u002F",[35],".",[16,62,63],{},"In my spare time I maintain a Linux server in my house, on which I self-host a couple of things including:",[65,66,67,76,88],"ul",{},[68,69,70,71],"li",{},"My own personal cloud storage using ",[31,72,75],{"href":73,"rel":74},"https:\u002F\u002Fnextcloud.com\u002F",[35],"NextCloud",[68,77,78,79,83,84],{},"My ",[31,80,82],{"href":40,"rel":81},[35],"code"," using ",[31,85,42],{"href":86,"rel":87},"https:\u002F\u002Fforgejo.org\u002F",[35],[68,89,90,95],{},[31,91,94],{"href":92,"rel":93},"https:\u002F\u002Fheadscale.net\u002Fstable\u002F",[35],"HeadScale"," for easy, self-hosted VPN access",[16,97,98],{},"In my spare time, I also write some code for Arduino's here and there, the connection between software and hardware is always fun to play with. I work for a company based in North Yorkshire that makes robotic automation systems, so I've got to work with some really cool hardware.",[20,100,102],{"id":101},"what-is-this-site-for","What is this site for?",[16,104,105,106,60],{},"I wanted a place to write about interesting projects I've worked on, here it is. You can check them out ",[31,107,54],{"href":108},"\u002Fprojects",{"title":110,"searchDepth":111,"depth":111,"links":112},"",2,[113,114],{"id":22,"depth":111,"text":23},{"id":101,"depth":111,"text":102},[116],{"name":6,"icon":117,"href":118},"material-symbols:home-rounded","\u002F","Welcome to George's portfolio website","md",{},true,"\u002Fpages",{"title":6,"description":119},"pages\u002F1.index","iJZaQtML6AUZWO7oOxOQo8ckoA7ZFdLQwhAci4MVMik",{"id":128,"title":129,"body":130,"crumbs":150,"description":154,"extension":120,"icon":153,"meta":155,"navigation":122,"path":156,"seo":157,"stem":158,"__hash__":159},"pages\u002Fpages\u002F2.projects.md","Projects",{"type":8,"value":131,"toc":148},[132,135,138,145],[11,133,129],{"id":134},"projects",[16,136,137],{},"My recent projects can be found below.",[16,139,140,141,144],{},"Can't find anything that interests you? Check out my ",[31,142,42],{"href":40,"rel":143},[35]," for some other things I've made that didn't make the cut (or that I haven't finished).",[146,147],"card-project-grid",{},{"title":110,"searchDepth":111,"depth":111,"links":149},[],[151,152],{"name":6,"icon":117,"href":118},{"name":129,"icon":153,"href":108},"material-symbols:deployed-code","View my projects here",{},"\u002Fpages\u002Fprojects",{"title":129,"description":154},"pages\u002F2.projects","ZvgQ8iafkO8Vo_2oMkyd_n-BCCp-tAooB16GjR_rLf4",[161,169,175],{"id":162,"extension":163,"icon":164,"link":165,"meta":166,"name":42,"stem":167,"__hash__":168},"socials\u002Fsocials\u002Fforgejo.yml","yml","devicon-plain:forgejo","https:\u002F\u002Fcode.ggrainger.uk\u002Fggrainger",{},"socials\u002Fforgejo","eLo2tedWGBfxJY_VmYmV0uFkIDhRuQvm4fmj_5QD7f0",{"id":170,"extension":163,"icon":171,"link":46,"meta":172,"name":48,"stem":173,"__hash__":174},"socials\u002Fsocials\u002Fgithub.yml","mdi:github-box",{},"socials\u002Fgithub","umA4vGSgNhkainXfqvtesFnwEcchjMuYOaVvJl409do",{"id":176,"extension":163,"icon":177,"link":178,"meta":179,"name":180,"stem":181,"__hash__":182},"socials\u002Fsocials\u002Flinkedin.yml","mdi:linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fgeorge-grainger552\u002F",{},"LinkedIn","socials\u002Flinkedin","bTHOxI-WAMN6H2Ub1ipKl89w3nM34aSFOrB4ziV6Nhc",{"id":128,"title":129,"body":184,"crumbs":199,"description":154,"extension":120,"icon":153,"meta":202,"navigation":122,"path":156,"seo":203,"stem":158,"__hash__":159},{"type":8,"value":185,"toc":197},[186,188,190,195],[11,187,129],{"id":134},[16,189,137],{},[16,191,140,192,144],{},[31,193,42],{"href":40,"rel":194},[35],[146,196],{},{"title":110,"searchDepth":111,"depth":111,"links":198},[],[200,201],{"name":6,"icon":117,"href":118},{"name":129,"icon":153,"href":108},{},{"title":129,"description":154},{"id":205,"title":206,"body":207,"coverImage":302,"description":303,"extension":120,"liveDemo":304,"meta":305,"navigation":122,"ogImage":304,"path":306,"publishedAt":307,"seo":308,"sourceCode":309,"stem":310,"tags":311,"__hash__":313},"projects\u002Fprojects\u002Fpython-sudoku.md","Python Sudoku",{"type":8,"value":208,"toc":297},[209,213,216,221,225,228,234,237,252,256,259,270,273,276],[20,210,212],{"id":211},"overview","Overview",[16,214,215],{},"This project features a Python based Sudoku game, complete with a backtracking solver and puzzle generation.",[217,218],"prose-video",{"alt":219,"src":220},"Video of the Sudoku solver in action","\u002Fvideos\u002Fprojects\u002Fpython-sudoku\u002Fsolver.mp4",[20,222,224],{"id":223},"solver","Solver",[16,226,227],{},"A human might solve a Sudoku puzzle by looking for obvious number placements, and some trial and error.\nWe could build a solver that could work in a similar way using some sort of heuristic to figure out optimal placements,\nbut this is complicated and we have a secret weapon we can use here.",[229,230,231],"blockquote",{},[16,232,233],{},"Computers are really fast",[16,235,236],{},"Backtracking is a brute force algorithmic approach that tries all possible solutions until a valid one is found.\nFor a human, a backtracking approach is not feasible due to the sheer number of possibilities. But for a computer it is trivial.\nA backtracking Sudoku solver follows the following procedure:",[238,239,240,243,246,249],"ol",{},[68,241,242],{},"Place a number in an empty cell.",[68,244,245],{},"Move to the next empty cell and repeat step 1.",[68,247,248],{},"If a conflict arises (i.e., the number violates Sudoku rules), backtrack to the previous cell and try the next possible number.",[68,250,251],{},"Continue this process until the entire grid is filled correctly or all possibilities have been exhausted.",[20,253,255],{"id":254},"generator","Generator",[16,257,258],{},"The puzzle generator works by the following process:",[238,260,261,264,267],{},[68,262,263],{},"Randomly fill the first row of the Grid with numbers 1 to 9, in a valid fashion.",[68,265,266],{},"Use the backtracking solver to fill the rest of the grid with a valid solution.",[68,268,269],{},"Remove numbers from the grid randomly. Using the solver to ensure that the puzzle remains solvable, and only has a single solution.",[16,271,272],{},"Randomness can be increased further by \"blending\" the rows and columns of the Sudoku grid.\nThis blending can only be done in groups of 3, as each Sudoku sub-grid must contain all numbers from 1 to 9 in addition to the rows in order to be valid",[16,274,275],{},"Using this method, you can tweak the difficulty of the generated puzzles by adjusting how many numbers are removed from the grid.\nThe minimum number of numbers (clues) required for a valid Sudoku puzzle is 17, so removing all but 17 numbers will result in the hardest puzzles.",[16,277,278,279,284,285,288,289,292,293,296],{},"The puzzles generated by this generator and used in this project are stored in the ",[31,280,283],{"href":281,"rel":282},"https:\u002F\u002Fcode.ggrainger.uk\u002Fggrainger\u002Fpython-sudoku\u002Fsrc\u002Fbranch\u002Fmaster\u002Fpuzzles.json",[35],"puzzles.json"," file in the repository.\nWith each seed containing a puzzle configuration for ",[82,286,287],{},"easy",", ",[82,290,291],{},"medium",", and ",[82,294,295],{},"hard"," difficulty levels.",{"title":110,"searchDepth":111,"depth":111,"links":298},[299,300,301],{"id":211,"depth":111,"text":212},{"id":223,"depth":111,"text":224},{"id":254,"depth":111,"text":255},"\u002Fimages\u002Fprojects\u002Fpython-sudoku\u002Fcover.png","A Python based Sudoku game, featuring a backtracking solver and puzzle generator.",null,{},"\u002Fprojects\u002Fpython-sudoku","2020-08-12 12:16:00",{"title":206,"description":303},"https:\u002F\u002Fcode.ggrainger.uk\u002Fggrainger\u002Fpython-sudoku","projects\u002Fpython-sudoku",[312],"python","tWMg0MTsZSREjDi4J1Sd3gzgGJQYf29pPHJDQAPmXKI",{"id":315,"extension":163,"icon":316,"meta":317,"name":318,"slug":312,"stem":319,"__hash__":320},"tags\u002Ftags\u002Fpython.yml","mdi:language-python",{},"Python","tags\u002Fpython","DXYQ-taiDFi7QUOOmFmOBdpRRcUynoIBkjzCzHiE1Is",1791491939301]