From 5112fa6c5fcea0f6fa0e223e4d103ba05ee46383 Mon Sep 17 00:00:00 2001 From: Lexanx <61974560+Lexanx@users.noreply.github.com> Date: Fri, 26 Jul 2024 15:05:29 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=A2=D0=B5=D1=81=D1=82=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maps/event/iccgn_ship/icgnv_hound_shuttle.dm | 2 +- maps/event/sfv_arbiter/sfv_arbiter_shuttle.dm | 2 +- .../exoplanet_ruins/crashed_shuttle/crashed_shuttle.dm | 2 +- .../random_ruins/exoplanet_ruins/transshipment/transshipment.dm | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/maps/event/iccgn_ship/icgnv_hound_shuttle.dm b/maps/event/iccgn_ship/icgnv_hound_shuttle.dm index 6bf967f8e7f8f..ec23d3f840a9c 100644 --- a/maps/event/iccgn_ship/icgnv_hound_shuttle.dm +++ b/maps/event/iccgn_ship/icgnv_hound_shuttle.dm @@ -8,7 +8,7 @@ fuel_consumption = 0 ceiling_type = /turf/simulated/floor/shuttle_ceiling flags = SHUTTLE_FLAGS_PROCESS - defer_initialisation = TRUE + defer_initialisation = FALSE knockdown = FALSE /turf/simulated/floor/shuttle_ceiling/iccgn diff --git a/maps/event/sfv_arbiter/sfv_arbiter_shuttle.dm b/maps/event/sfv_arbiter/sfv_arbiter_shuttle.dm index 4a284a1fe8c1a..6c9fa53d7d5a0 100644 --- a/maps/event/sfv_arbiter/sfv_arbiter_shuttle.dm +++ b/maps/event/sfv_arbiter/sfv_arbiter_shuttle.dm @@ -7,7 +7,7 @@ range = 1 ceiling_type = /turf/simulated/floor/shuttle_ceiling flags = SHUTTLE_FLAGS_PROCESS - defer_initialisation = TRUE + defer_initialisation = FALSE knockdown = FALSE /turf/simulated/floor/shuttle_ceiling/sfv_arbiter diff --git a/maps/random_ruins/exoplanet_ruins/crashed_shuttle/crashed_shuttle.dm b/maps/random_ruins/exoplanet_ruins/crashed_shuttle/crashed_shuttle.dm index cce52b82fb14b..027f75cb01dd9 100644 --- a/maps/random_ruins/exoplanet_ruins/crashed_shuttle/crashed_shuttle.dm +++ b/maps/random_ruins/exoplanet_ruins/crashed_shuttle/crashed_shuttle.dm @@ -27,7 +27,7 @@ range = 1 shuttle_area = /area/map_template/crashed_shuttle/graysontug fuel_consumption = 4 - defer_initialisation = TRUE + defer_initialisation = FALSE flags = SHUTTLE_FLAGS_PROCESS skill_needed = SKILL_MIN ceiling_type = /turf/simulated/floor/shuttle_ceiling diff --git a/maps/random_ruins/exoplanet_ruins/transshipment/transshipment.dm b/maps/random_ruins/exoplanet_ruins/transshipment/transshipment.dm index 7f5e76560eba7..0cd80ffb0192d 100644 --- a/maps/random_ruins/exoplanet_ruins/transshipment/transshipment.dm +++ b/maps/random_ruins/exoplanet_ruins/transshipment/transshipment.dm @@ -52,6 +52,7 @@ flags = SHUTTLE_FLAGS_PROCESS skill_needed = SKILL_MIN ceiling_type = /turf/simulated/floor/shuttle_ceiling + defer_initialisation = FALSE /obj/machinery/computer/shuttle_control/explore/old_snz name = "SNZ-210 Shuttle control console" From 50afd59647e1ab990c72be6f7e574feec9007865 Mon Sep 17 00:00:00 2001 From: Lexanx <61974560+Lexanx@users.noreply.github.com> Date: Fri, 26 Jul 2024 15:05:58 +0300 Subject: [PATCH 2/3] =?UTF-8?q?Revert=20"=D0=A2=D0=B5=D1=81=D1=82=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=3F"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 5112fa6c5fcea0f6fa0e223e4d103ba05ee46383. --- maps/event/iccgn_ship/icgnv_hound_shuttle.dm | 2 +- maps/event/sfv_arbiter/sfv_arbiter_shuttle.dm | 2 +- .../exoplanet_ruins/crashed_shuttle/crashed_shuttle.dm | 2 +- .../random_ruins/exoplanet_ruins/transshipment/transshipment.dm | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/maps/event/iccgn_ship/icgnv_hound_shuttle.dm b/maps/event/iccgn_ship/icgnv_hound_shuttle.dm index ec23d3f840a9c..6bf967f8e7f8f 100644 --- a/maps/event/iccgn_ship/icgnv_hound_shuttle.dm +++ b/maps/event/iccgn_ship/icgnv_hound_shuttle.dm @@ -8,7 +8,7 @@ fuel_consumption = 0 ceiling_type = /turf/simulated/floor/shuttle_ceiling flags = SHUTTLE_FLAGS_PROCESS - defer_initialisation = FALSE + defer_initialisation = TRUE knockdown = FALSE /turf/simulated/floor/shuttle_ceiling/iccgn diff --git a/maps/event/sfv_arbiter/sfv_arbiter_shuttle.dm b/maps/event/sfv_arbiter/sfv_arbiter_shuttle.dm index 6c9fa53d7d5a0..4a284a1fe8c1a 100644 --- a/maps/event/sfv_arbiter/sfv_arbiter_shuttle.dm +++ b/maps/event/sfv_arbiter/sfv_arbiter_shuttle.dm @@ -7,7 +7,7 @@ range = 1 ceiling_type = /turf/simulated/floor/shuttle_ceiling flags = SHUTTLE_FLAGS_PROCESS - defer_initialisation = FALSE + defer_initialisation = TRUE knockdown = FALSE /turf/simulated/floor/shuttle_ceiling/sfv_arbiter diff --git a/maps/random_ruins/exoplanet_ruins/crashed_shuttle/crashed_shuttle.dm b/maps/random_ruins/exoplanet_ruins/crashed_shuttle/crashed_shuttle.dm index 027f75cb01dd9..cce52b82fb14b 100644 --- a/maps/random_ruins/exoplanet_ruins/crashed_shuttle/crashed_shuttle.dm +++ b/maps/random_ruins/exoplanet_ruins/crashed_shuttle/crashed_shuttle.dm @@ -27,7 +27,7 @@ range = 1 shuttle_area = /area/map_template/crashed_shuttle/graysontug fuel_consumption = 4 - defer_initialisation = FALSE + defer_initialisation = TRUE flags = SHUTTLE_FLAGS_PROCESS skill_needed = SKILL_MIN ceiling_type = /turf/simulated/floor/shuttle_ceiling diff --git a/maps/random_ruins/exoplanet_ruins/transshipment/transshipment.dm b/maps/random_ruins/exoplanet_ruins/transshipment/transshipment.dm index 0cd80ffb0192d..7f5e76560eba7 100644 --- a/maps/random_ruins/exoplanet_ruins/transshipment/transshipment.dm +++ b/maps/random_ruins/exoplanet_ruins/transshipment/transshipment.dm @@ -52,7 +52,6 @@ flags = SHUTTLE_FLAGS_PROCESS skill_needed = SKILL_MIN ceiling_type = /turf/simulated/floor/shuttle_ceiling - defer_initialisation = FALSE /obj/machinery/computer/shuttle_control/explore/old_snz name = "SNZ-210 Shuttle control console" From 03f70b8fe4c134eae21ea155516ce4c94cfcab6b Mon Sep 17 00:00:00 2001 From: Lexanx <61974560+Lexanx@users.noreply.github.com> Date: Sun, 25 May 2025 14:01:51 +0300 Subject: [PATCH 3/3] sudoku --- mods/utility_items/_utility_items_includes.dm | 1 + mods/utility_items/code/sudoku.dm | 470 ++++++++++++++++++ mods/utility_items/sounds/magic_light.ogg | Bin 0 -> 14119 bytes nano/templates/mods/sudoku.tmpl | 99 ++++ 4 files changed, 570 insertions(+) create mode 100644 mods/utility_items/code/sudoku.dm create mode 100644 mods/utility_items/sounds/magic_light.ogg create mode 100644 nano/templates/mods/sudoku.tmpl diff --git a/mods/utility_items/_utility_items_includes.dm b/mods/utility_items/_utility_items_includes.dm index cdc3a2d05c454..dc25827687d51 100644 --- a/mods/utility_items/_utility_items_includes.dm +++ b/mods/utility_items/_utility_items_includes.dm @@ -34,6 +34,7 @@ #include "code/top.dm" #include "code/skrell-ship.dm" #include "code/security.dm" +#include "code/sudoku.dm" #include "code/FBP_vox.dm" #include "code/rndloadout.dm" #include "code/money_resprite.dm" diff --git a/mods/utility_items/code/sudoku.dm b/mods/utility_items/code/sudoku.dm new file mode 100644 index 0000000000000..9c6aedaf091b2 --- /dev/null +++ b/mods/utility_items/code/sudoku.dm @@ -0,0 +1,470 @@ +/datum/computer_file/program/sudoku + filename = "sudoku" + filedesc = "Sudoku" + program_icon_state = "generic" + program_menu_icon = "script" + extended_desc = "A game of numbers, logic, and deduction. Popular for centuries to keep the mind sharp." + size = 5 + requires_ntnet = FALSE + available_on_ntnet = TRUE + nanomodule_path = /datum/nano_module/sudoku/ + usage_flags = PROGRAM_ALL + +/datum/nano_module/sudoku + var/list/grid = null + var/building = 0 + var/list/solution = list() + + var/cheated = 0 + + var/list/boxes = list(//Most efficient way i could think to do this + "11" = list(1,2,3,10,11,12,19,20,21), + "12" = list(4,5,6,13,14,15,22,23,24), + "13" = list(7,8,9,16,17,18,25,26,27), + "21" = list(28,29,30,37,38,39,46,47,48), + "22" = list(31,32,33,40,41,42,49,50,51), + "23" = list(34,35,36,43,44,45,52,53,54), + "31" = list(55,56,57,64,65,66,73,74,75), + "32" = list(58,59,60,67,68,69,76,77,78), + "33" = list(61,62,63,70,71,72,79,80,81) + ) + var/message = ""//Error or informational message shown on screen. + var/lastmessage = "" + var/messagesent = 0 + var/list/clues = list("Easy" = 36,"Medium"=31,"Hard"=26,"Robust"=17) + var/lastuser = null + var/wongame = 0 + var/datum/computer_file/sudoku + + var/newdifficulty = "Easy"//The selected difficulty mode for generating the next grid + + var/collapse = 0 + var/width = 900 + +/datum/nano_module/sudoku/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 0) + var/list/data = host.initial_data() + + if (!grid) + create_grid() + data["grid"] = grid + data["src"] = "\ref[src]" + data["collapse"] = collapse + data["message"] = message + data["difficulty"] = newdifficulty + if (message != lastmessage) + lastmessage = message + messagesent = world.time + else if ((world.time - messagesent) > 100)//Make sure that messages show onscreen for at least 10 seconds + message = ""//Displays for one refresh only + lastuser = user + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "mods-sudoku.tmpl", "Sudoku", width, 557) + //if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(0) + + + +/datum/nano_module/sudoku/Topic(href, list/href_list) + ..() + + + if(href_list["save"])//This is called with every keypress + save_grid(href_list) + return//No refreshing for every input + else if (href_list["check"]) + save_grid(href_list) + check_validity() + else if (href_list["hint"])//Reveals one tile + var/response = alert(usr,"Are you sure you want a hint? This will reveal the correct number for one tile. But you'll lose the pride of having figured it out yourself..","Ask for a hint","Help me","I can do it myself") + if (response == "Help me") + solver(1) + else + return + else if (href_list["solve"]) + solver(81) + else if (href_list["clear"]) + var/response = alert(usr,"Are you sure you want to clear the grid? This will remove all the numbers you've typed in. The starting clues will remain.","Clear board","Clear it","Wait no!") + if (response == "Clear it") + clear_grid(0) + else + return + else if (href_list["purge"]) + clear_grid(1) + else if (href_list["difficulty"]) + newdifficulty = href_list["difficulty"] + else if (href_list["newgame"]) + var/response = alert(usr,"Are you sure you want to start a new game? All progress on this one will be lost. Be sure to pick your desired difficulty first.","New Puzzle","Start Anew","Wait no!") + if (response == "Start Anew") + advanced_populate_grid(clues[newdifficulty]) + else + return + else if (href_list["collapse"]) + collapse = !collapse + set_width(usr) + return + + if (usr) + ui_interact(usr) + +/datum/nano_module/sudoku/proc/set_width(mob/user) + if (collapse) + width = 400 + else + width = 900 + + var/datum/nanoui/ui = SSnano.get_open_ui(user, src, "main") + if (ui) + ui.close() + ui_interact(user, force_open = 1) + +/datum/nano_module/sudoku/proc/save_grid(list/inputdata) + var/i = 1 + for (i = 1, i <= 81, i++) + var/list/cell = grid[i] + var/v = text2num(inputdata["[i]"]) + if (inputdata["[i]"] == "" || (v > 0 && v < 10)) + cell["value"] = inputdata["[i]"] + +/datum/nano_module/sudoku/proc/create_grid() + if (grid) + grid.Cut() + grid = list() + + var/n = 81 + var/list/numbers = list() + while (n) + n-- + numbers += rand(1,9) + var/row = 1 + var/column = 0 + n = 1//reuse this + for (var/a in numbers) + var/list/number = list() + number["value"] = "" + //if (prob(20)) + //number["static"] = 1 + + column++ + if (column > 9) + row++ + column = 1 + + number["id"] = "[row][column]" + number["row"] = row + number["column"] = column + number["index"] = n + number["tried"] = list()//used in grid generation + n++ + grid.Add(list(number)) + + var/box = "" + switch (row) + if (1 to 3) + box += "1" + if (4 to 6) + box += "2" + if (7 to 9) + box += "3" + + switch (column) + if (1 to 3) + box += "1" + if (4 to 6) + box += "2" + if (7 to 9) + box += "3" + + number["box"] = box + + advanced_populate_grid() + + + +/datum/nano_module/sudoku/proc/id_num(index) + var/row = 1 + var/column = 1 + + if (index <= 9) + column = index + else + while (index > 9) + index -= 9 + row++ + column = index + + + + return "[row][column]" + + + + + +//Clears the grid: +//With an input of 0, clears all user input and restores the grid to just the generated clues +//With input of 1, clears every cell, grid becomes empty +/datum/nano_module/sudoku/proc/clear_grid(full = 0) + for (var/t in grid) + var/list/tile = t + if (full || !tile["static"]) + tile["value"] = "" + tile["static"] = 0 + tile["highlight"] = 0 + if (full) + cheated = 0 + wongame = 0 + + +/********* +* HELPERS +*********/ +//This proc checks the validity of the current boardstate +//It will analyse all the tiles in sequence, and halt if it finds an invalid one. +//Tiles will be checked for conflicts along the row, border and 3x3 box +/datum/nano_module/sudoku/proc/check_validity() + + //This result will be returned at the end + . = 0 + //Return var of 0 is normal, that means the game is unfinished and the boardstate is valid + //Any return var > zero indicates invalid, with that number being the index of the first invalid tile + //Return var of -1 indicates all tiles filled and boardstate valid. IE: Game over, you win! + + var/empty = 0 + var/conflict = 0 + for (var/t in grid) + var/list/tile = t + if (tile["static"]) + continue + var/v = tile["value"] + var/i = tile["index"] + if (!v) + empty++ + continue + + var/list/group + group = get_row(i) + for (var/n in group) + if(n == v)//CONFLICT + conflict = i + break + + group = get_column(i) + for (var/n in group) + if(n == v)//CONFLICT + conflict = i + break + + group = get_box(i) + for (var/n in group) + if(n == v)//CONFLICT + conflict = i + break + + if (conflict) + break + + if (conflict) + message = "Error: Invalid tile found! The problem is highlighted" + highlight(list(conflict)) + .=conflict + + else if (empty > 0) + message = "Everything looks fine so far! You have [empty] tiles left to fill" + highlight() + + + //If we havent found any conflict and all tiles are filled, then the user has won the game. + else if (empty == 0) + message = "Congratulations! You win the game!" + if (!wongame) + playsound(get_turf(usr), 'mods/utility_items/sounds/magic_light.ogg', 50, 1) + wongame = 1 + .=-1 + + + + +//Attempts to solve the board using simple single-tile logic. This will solvve most easier boards +//May implement split timelines for solving boards where the answer isnt simple +//Number of steps indicates how many tiles to solve. Passing 1 can serve as a hint function +/datum/nano_module/sudoku/proc/solver(steps = 81) + if (check_validity() != 0) //Can't build on quicksand. The boardstate must be valid before we attempt to progress + return + + var/done = 0 + var/list/emptytiles = list() + + + for (var/t in grid) + var/list/tile = t + var/v = tile["value"] + + if (v)//Already has a valid value, next tile + continue + + emptytiles += text2num(tile["index"]) + + + + if(LAZYLEN(emptytiles)) + while (steps > 0 && !done) + + if (LAZYLEN(emptytiles) <= 0 ) + done = 1//If we get here then the solver has won the game. + var/i = pick_n_take(emptytiles) + var/list/tile = grid[i] + tile["value"] = solution[i]//Solution is the pre-saved correct solution for the puzzle + tile["static"] = 1 + steps-- + cheated++//Cheated var indicates the user had help + message = "A tile has been revealed for you. You've now had [cheated] hints" + highlight(list(i)) + + +//Returns all possible values for a tile +//If this ever returns nothing then the game is in an unwinnable state, a mistake has been made +/datum/nano_module/sudoku/proc/get_options(index) + . = list(1,2,3,4,5,6,7,8,9) + . -= get_row(index) + . -= get_column(index) + . -= get_box(index) + + +//Returns all tiles in the same row as index, excluding index +/datum/nano_module/sudoku/proc/get_row(index) + var/list/tile = grid[index] + //We get the row number from this + + var/rowstart = (((tile["row"]-1)*9) + 1)//Index of the first tile on the row we want + + var/i + var/list/indices = list() + for (i = 0, i <= 8, i++) + indices += rowstart+i + + indices -= index + + return get_tile_values(indices) + +//Returns all tiles in the same row as index, excluding index +/datum/nano_module/sudoku/proc/get_column(index) + var/list/tile = grid[index] + //We get the row number from this + + var/columnstart = tile["column"]//Index of the first tile on the row we want + var/i + var/list/indices = list() + for (i = 0, i <= 8, i++) + indices += columnstart+(i*9) + + indices -= index + + + return get_tile_values(indices) + +/datum/nano_module/sudoku/proc/get_box(index) + var/list/tile = grid[index] + var/list/temp = boxes[tile["box"]] + var/list/boxind = temp.Copy() + boxind -= index + return get_tile_values(boxind) + + +//Takes a list of indexes, returns the grid tiles with those indexes. +/datum/nano_module/sudoku/proc/get_tiles(list/indexes) + . = list() + for (var/i in indexes) + . += list(grid[i]) + +/datum/nano_module/sudoku/proc/get_tile_values(list/indexes) + . = list() + for (var/i in indexes) + var/list/tile = grid[i] + . += tile["value"] + + + + +//A not so simple grid builder which uses a backtracking algorithm. +//Attempts to build the grid linearly with random numbers, backtracking and trying again whenever a +//collision is found +/datum/nano_module/sudoku/proc/advanced_populate_grid(clues = 36) + set background = 1 + if (building) + return + + building = 1 + clear_grid(1) + var/iterations = 0 + var/i = 1 + for (i = 1, i <= 81, i++) + var/list/tile = grid[i] + iterations++ + + var/list/tried = tile["tried"] + var/list/options = get_options(i) + + options.Remove(tried)//The list of tried numbers is used when we backtrack + + //So long as we have any options left, we'll pick a random one and keep going + if (LAZYLEN(options) > 0) + tile["value"] = pick(options) + tile["static"] = 1 + else + //If there are no valid, non-colliding numbers for this tile, then things get interesting. + var/list/prev = grid[i-1]//Get the previous tile + var/list/t = prev["tried"] + t += prev["value"]//The value for the previous tile is now blacklisted + prev["value"] = "" + //grid[i-1] = prev + + //Now we wipe our own tried list since we're stepping back. How we've branched forward + //from this point is no longer relevant + tile["tried"] = list() + //And finally we set i back two decrements, so in the next cycle of the loop + //it will look at the previous cell + i -= 2 + if (iterations == 100) + iterations = 0 + sleep(1) + + //Now we copy over the solution + solution = list() + for (var/t in grid) + var/list/tile = t + solution += tile["value"] + + + + //And finally we start removing stuff until we have only the clues left + var/toremove = 81 - clues + var/list/filledtiles = list() + for (i = 1, i <= 81, i++) + filledtiles += i + while (toremove > 0) + i = pick_n_take(filledtiles) + toremove-- + var/list/tile = grid[i] + tile["value"] = "" + tile["static"] = 0 + tile["tried"] = list()//to prevent any cheating + + + building = 0 + + +//Highlights all indices in the list. Unhighlights every other cell +/datum/nano_module/sudoku/proc/highlight(list/indices) + if (!indices) + indices = list() + for (var/i = 1, i <= 81, i++) + var/list/tile = grid[i] + if (LAZYLEN(indices) && (i in indices)) + tile["highlight"] = 1 + else + tile["highlight"] = 0 diff --git a/mods/utility_items/sounds/magic_light.ogg b/mods/utility_items/sounds/magic_light.ogg new file mode 100644 index 0000000000000000000000000000000000000000..59b24d1630e4cc863b060447cfd6b918df58e9bc GIT binary patch literal 14119 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 + .lb{border-left: #222222 solid 6px;} + .rb{border-right: #222222 solid 6px;} + .tile, .lb,.rb,.nb{width: 32px; text-align: center; font-size: 24px; color: #5555DD} + .tb{border-top: #222222 solid 5px;} + .bb{border-bottom: #222222 solid 5px;} + .nanoformbutton{height: 22px; float: left; text-align: center; color: #ffffff; text-decoration: none; + background: #40628a; border: 1px solid #161616; margin: 0 2px 2px 0;cursor: default;white-space: nowrap;} + + + + + + + {{if data.collapse == 0}} +
+
+ + + + + {{for data.grid}} + + + {{if value.column == 9}} + + {{if value.row < 9}} + + {{/if}} + {{/if}} + {{/for}} +
+ + +
+
+ + {{:helper.link("Check", null, {'check' : value.ref})}} + {{:helper.link("Reset Grid", null, {'clear' : value.ref})}} + {{:helper.link((data.collapse) ? "Expand" : "Collapse", null, {'collapse' : value.ref})}} +
+
+ + + + + + + + + {{/if}} + +
+
Sudoku is a classic human game of logic and deduction originating from Earth, in the Sol system. Invented in 19th century France and later popularised in 20th century Japan, where the name originates. It has proven a popular and diverting pastime for almost 500 years.
+
+ The object of the game is simple. Complete the board by filling in digits from 1 to 9, with the constraint that each digit can only appear once per row, once per column, and once per 3x3 subgrid. The solution can usually be figured out by a process of elimination: Carefully check each tile against those around it based on the above rules, and fill in the tiles where there is only one option. Each new tile filled is a clue to the value of other tiles!
+
+ {{if data.message}} +
{{:data.message}}
+ {{/if}} +
+ {{:helper.link("Hint", null, {'hint' : value.ref})}} +
+
Start a New Game
+
+ + {{:helper.link("Easy", null, {'difficulty' : "Easy"}, data.difficulty == "Easy" ? 'selected' : null)}} + {{:helper.link("Medium", null, {'difficulty' : "Medium"}, data.difficulty == "Medium" ? 'selected' : null)}} + {{:helper.link("Hard", null, {'difficulty' : "Hard"}, data.difficulty == "Hard" ? 'selected' : null)}} + {{:helper.link("Robust", null, {'difficulty' : "Robust"}, data.difficulty == "Robust" ? 'selected' : null)}} +

+ {{:helper.link("Generate Grid", null, {'newgame' : value.ref})}} +