From 960f4f4a068c11c9790c3d90f889e246b3dd292a Mon Sep 17 00:00:00 2001 From: FrederikBaerentsen Date: Sun, 15 Dec 2024 10:18:34 +0100 Subject: [PATCH] Solved 2024/15 P1 --- 2024/15/15.md | 478 +++++++++++++++++++++++++++++++ 2024/15/solution.py | 355 +++++++++++++++++++++++ __pycache__/fred.cpython-311.pyc | Bin 29514 -> 30163 bytes fred.py | 28 +- 4 files changed, 855 insertions(+), 6 deletions(-) create mode 100644 2024/15/15.md create mode 100644 2024/15/solution.py diff --git a/2024/15/15.md b/2024/15/15.md new file mode 100644 index 0000000..1c57b91 --- /dev/null +++ b/2024/15/15.md @@ -0,0 +1,478 @@ +## \-\-- Day 15: Warehouse Woes \-\-- + +You appear back inside your own mini submarine! Each Historian drives +their mini submarine in a different direction; maybe the Chief has his +own submarine down here somewhere as well? + +You look up to see a vast school of [lanternfish](/2021/day/6) swimming +past you. On closer inspection, they seem quite anxious, so you drive +your mini submarine over to see if you can help. + +Because lanternfish populations grow rapidly, they need a lot of food, +and that food needs to be stored somewhere. That\'s why these +lanternfish have built elaborate warehouse complexes operated by robots! + +These lanternfish seem so anxious because they have lost control of the +robot that operates one of their most important warehouses! It is +currently running +amok, +pushing around boxes in the warehouse with no regard for lanternfish +logistics *or* lanternfish inventory management strategies. + +Right now, none of the lanternfish are brave enough to swim up to an +unpredictable robot so they could shut it off. However, if you could +anticipate the robot\'s movements, maybe they could find a safe option. + +The lanternfish already have a map of the warehouse and a list of +movements the robot will *attempt* to make (your puzzle input). The +problem is that the movements will sometimes fail as boxes are shifted +around, making the actual movements of the robot difficult to predict. + +For example: + + ########## + #..O..O.O# + #......O.# + #.OO..O.O# + #..O@..O.# + #O#..O...# + #O..O..O.# + #.OO.O.OO# + #....O...# + ########## + + ^v>^vv^v>v<>v^v<<><>>v^v^>^<<<><^ + vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<^<^^>>>^<>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^v^^<^^vv< + <>^^^^>>>v^<>vvv^>^^^vv^^>v<^^^^v<>^>vvvv><>>v^<<^^^^^ + ^><^><>>><>^^<<^^v>>><^^>v>>>^v><>^v><<<>vvvv>^<><<>^>< + ^>><>^v<><^vvv<^^<><^v<<<><<<^^<^>>^<<<^>>^v^>>^v>vv>^<<^v<>><<><<>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^ + <><^^>^^^<>^vv<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<> + ^^>vv<^v^v^<>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<>< + v^^>>><<^^<>>^v^v^<<>^<^v^v><^<<<><<^vv>>v>v^<<^ + +As the robot (`@`) attempts to move, if there are any boxes (`O`) in the +way, the robot will also attempt to push those boxes. However, if this +action would cause the robot or a box to move into a wall (`#`), nothing +moves instead, including the robot. The initial positions of these are +shown on the map at the top of the document the lanternfish gave you. + +The rest of the document describes the *moves* (`^` for up, `v` for +down, `<` for left, `>` for right) that the robot will attempt to make, +in order. (The moves form a single giant sequence; they are broken into +multiple lines just to make copy-pasting easier. Newlines within the +move sequence should be ignored.) + +Here is a smaller example to get started: + + ######## + #..O.O.# + ##@.O..# + #...O..# + #.#.O..# + #...O..# + #......# + ######## + + <^^>>>vv>v<< + +Were the robot to attempt the given sequence of moves, it would push +around the boxes as follows: + + Initial state: + ######## + #..O.O.# + ##@.O..# + #...O..# + #.#.O..# + #...O..# + #......# + ######## + + Move <: + ######## + #..O.O.# + ##@.O..# + #...O..# + #.#.O..# + #...O..# + #......# + ######## + + Move ^: + ######## + #.@O.O.# + ##..O..# + #...O..# + #.#.O..# + #...O..# + #......# + ######## + + Move ^: + ######## + #.@O.O.# + ##..O..# + #...O..# + #.#.O..# + #...O..# + #......# + ######## + + Move >: + ######## + #..@OO.# + ##..O..# + #...O..# + #.#.O..# + #...O..# + #......# + ######## + + Move >: + ######## + #...@OO# + ##..O..# + #...O..# + #.#.O..# + #...O..# + #......# + ######## + + Move >: + ######## + #...@OO# + ##..O..# + #...O..# + #.#.O..# + #...O..# + #......# + ######## + + Move v: + ######## + #....OO# + ##..@..# + #...O..# + #.#.O..# + #...O..# + #...O..# + ######## + + Move v: + ######## + #....OO# + ##..@..# + #...O..# + #.#.O..# + #...O..# + #...O..# + ######## + + Move <: + ######## + #....OO# + ##.@...# + #...O..# + #.#.O..# + #...O..# + #...O..# + ######## + + Move v: + ######## + #....OO# + ##.....# + #..@O..# + #.#.O..# + #...O..# + #...O..# + ######## + + Move >: + ######## + #....OO# + ##.....# + #...@O.# + #.#.O..# + #...O..# + #...O..# + ######## + + Move >: + ######## + #....OO# + ##.....# + #....@O# + #.#.O..# + #...O..# + #...O..# + ######## + + Move v: + ######## + #....OO# + ##.....# + #.....O# + #.#.O@.# + #...O..# + #...O..# + ######## + + Move <: + ######## + #....OO# + ##.....# + #.....O# + #.#O@..# + #...O..# + #...O..# + ######## + + Move <: + ######## + #....OO# + ##.....# + #.....O# + #.#O@..# + #...O..# + #...O..# + ######## + +The larger example has many more moves; after the robot has finished +those moves, the warehouse would look like this: + + ########## + #.O.O.OOO# + #........# + #OO......# + #OO@.....# + #O#.....O# + #O.....OO# + #O.....OO# + #OO....OO# + ########## + +The lanternfish use their own custom Goods Positioning System (GPS for +short) to track the locations of the boxes. The *GPS coordinate* of a +box is equal to 100 times its distance from the top edge of the map plus +its distance from the left edge of the map. (This process does not stop +at wall tiles; measure all the way to the edges of the map.) + +So, the box shown below has a distance of `1` from the top edge of the +map and `4` from the left edge of the map, resulting in a GPS coordinate +of `100 * 1 + 4 = 104`. + + ####### + #...O.. + #...... + +The lanternfish would like to know the *sum of all boxes\' GPS +coordinates* after the robot finishes moving. In the larger example, the +sum of all boxes\' GPS coordinates is `10092`. In the smaller example, +the sum is `2028`. + +Predict the motion of the robot and boxes in the warehouse. After the +robot is finished moving, *what is the sum of all boxes\' GPS +coordinates?* + +Your puzzle answer was `1568399`. + +The first half of this puzzle is complete! It provides one gold star: \* + +## \-\-- Part Two \-\-- {#part2} + +The lanternfish use your information to find a safe moment to swim in +and turn off the malfunctioning robot! Just as they start preparing a +festival in your honor, reports start coming in that a *second* +warehouse\'s robot is *also* malfunctioning. + +This warehouse\'s layout is surprisingly similar to the one you just +helped. There is one key difference: everything except the robot is +*twice as wide*! The robot\'s list of movements doesn\'t change. + +To get the wider warehouse\'s map, start with your original map and, for +each tile, make the following changes: + +- If the tile is `#`, the new map contains `##` instead. +- If the tile is `O`, the new map contains `[]` instead. +- If the tile is `.`, the new map contains `..` instead. +- If the tile is `@`, the new map contains `@.` instead. + +This will produce a new warehouse map which is twice as wide and with +wide boxes that are represented by `[]`. (The robot does not change +size.) + +The larger example from before would now look like this: + + #################### + ##....[]....[]..[]## + ##............[]..## + ##..[][]....[]..[]## + ##....[]@.....[]..## + ##[]##....[]......## + ##[]....[]....[]..## + ##..[][]..[]..[][]## + ##........[]......## + #################### + +Because boxes are now twice as wide but the robot is still the same size +and speed, boxes can be aligned such that they directly push two other +boxes at once. For example, consider this situation: + + ####### + #...#.# + #.....# + #..OO@# + #..O..# + #.....# + ####### + + 1: + print(prepend+sign[0] + grid[idx][jdx] + sign[1], end='') # Print with sign + else: + print(prepend+colored(sign,'green',attrs=["underline","bold"]), end=' ') # Print sign + else: + print(prepend+colored(grid[idx][jdx],'green',attrs=["underline","bold"]), end=' ') + else: + if positions is not None: + if (idx,jdx) in positions: + print(prepend+colored(grid[idx][jdx],'red'),end=' ') + else: + + print(prepend+grid[idx][jdx], end=' ') + else: + if grid[idx][jdx] == '.': + print(prepend+colored(grid[idx][jdx],'blue',attrs=["concealed"]),end=' ') + elif grid[idx][jdx] == 'O': + print(prepend+colored(grid[idx][jdx],'red'),end=' ') + elif grid[idx][jdx] == '#': + print(prepend+colored(grid[idx][jdx],'white'),end=' ') + else: + print(prepend+grid[idx][jdx], end=' ') # Regular grid element + print() + + + for r in range(len(grid[0])): + if r == 0: + print(' ',end='') + print(r,end=' ') + print() + + +def loadFile(input_f): + grid = [] + instructions = [] + with open(input_f) as file: + for line in file: + # load map part + if line.startswith("#"): + grid.append(list(line.rstrip())) + + # load instructions + elif line.startswith(('v','<','>','^')): + instructions += list(line.rstrip()) + return grid,instructions + +######################################### +# # +# Part 1 # +# # +######################################### +def part1(): + grid, instructions = loadFile(input_f) + + start = () + + for r,row in enumerate(grid): + for c, col in enumerate(row): + if grid[r][c] == '@': + start = (r,c) + + # translate arrows to something get_value_in_direction can use + directions = { + '^':('up',(-1, 0)), + 'v':('down',(1, 0)), + '>':('right',(0, 1)), + '<':('left',(0, -1)), + } + + pos = start + #print('Initial state') + #nprint(grid,pos) + #print() + #input() + for idx, inst in enumerate(instructions): + #print('Move',inst,'(',len(instructions)-idx,')') + dir = directions[inst][0] + next = get_value_in_direction(grid,pos,dir) + + # If wall, don't do anything + if next == '#': + #nprint(grid,pos) + #input() + continue + + # If free space, move there + if next == '.': + grid[pos[0]][pos[1]] = '.' + pos = addTuples(pos,directions[inst][1]) + grid[pos[0]][pos[1]] = '@' + + # If box, move the box and the stack of boxes. + if next == 'O': + #print('@',pos) + prev = pos + next_chars = ['@'] + next_poss = [pos] + skip = False + while True: + nextPos = addTuples(pos,directions[inst][1]) + nextChar = get_value_in_direction(grid,nextPos) + #print(nextPos,nextChar) + if nextChar == 'O': + next_chars.append(nextChar) + next_poss.append(nextPos) + pos = nextPos + if nextChar == '.': + next_chars.append(nextChar) + next_poss.append(nextPos) + break + if nextChar == '#': + skip = True + pos = prev + break + + #input() + if not skip: + for ndx,n in enumerate(next_poss): + if ndx == 0: + grid[n[0]][n[1]] = '.' + pos = next_poss[ndx+1] + else: + grid[n[0]][n[1]] = next_chars[ndx-1] + #input() + #nprint(grid,pos) + #print(len(instructions)-idx) + #time.sleep(0.05) + #input() + result = 0 + for r,row in enumerate(grid): + for c,char in enumerate(row): + if char == 'O': + result += (100*r+c) + return result +start_time = time.time() +print('Part 1:',part1(), '\t\t', round((time.time() - start_time)*1000), 'ms') + + +######################################### +# # +# Part 2 # +# # +######################################### + +def resizeGrid(grid:list) -> list: + newGrid = [] + for r,row in enumerate(grid): + newRow = [] + for c, char in enumerate(row): + if char == '#': + newRow.append('#') + newRow.append('#') + if char == 'O': + newRow.append('[') + newRow.append(']') + if char == '.': + newRow.append('.') + newRow.append('.') + if char == '@': + newRow.append('@') + newRow.append('.') + newGrid.append(newRow) + return newGrid + +def part2(): + + + def nprint2(grid, cur: set = None, sign: str = None, positions:list = None): + + + prepend = 0 + for idx, i in enumerate(grid): + for jdx, j in enumerate(i): + if jdx == 0: + prepend = str(idx)+' ' + else: + prepend = '' + + if (idx, jdx) == cur: + if sign is not None: + if len(sign) > 1: + print(prepend+sign[0] + grid[idx][jdx] + sign[1], end=' ') # Print with sign + else: + print(prepend+colored(sign,'green',attrs=["underline","bold"]), end=' ') # Print sign + else: + print(prepend+colored(grid[idx][jdx],'green',attrs=["underline","bold"]), end='') + else: + if positions is not None: + if (idx,jdx) in positions: + print(prepend+colored(grid[idx][jdx],'red'),end=' ') + else: + + print(prepend+grid[idx][jdx], end=' ') + else: + if grid[idx][jdx] == '.': + print(prepend+colored(grid[idx][jdx],'blue',attrs=["concealed"]),end='') + elif grid[idx][jdx] == 'O': + print(prepend+colored(grid[idx][jdx],'red'),end='') + elif grid[idx][jdx] == '#': + print(prepend+colored(grid[idx][jdx],'white'),end='') + else: + print(prepend+grid[idx][jdx], end='') # Regular grid element + print() + + + for r in range(len(grid[0])): + if r == 0: + print(' 0',end='') + + else: + if r%2 == 0: + print(r,end='') + else: + print(' ',end='') + print() + for r in range(len(grid[0])): + if r == 0: + print(' ',end='') + + else: + if r%2 != 0: + print(r,end='') + else: + if r != 9: + print(' ',end='') + else: + print('',end='') + print() + + + grid, instructions = loadFile(input_f) + + start = () + + for r,row in enumerate(grid): + for c, col in enumerate(row): + if grid[r][c] == '@': + start = (r,c) + + # translate arrows to something get_value_in_direction can use + directions = { + '^':('up',(-1, 0)), + 'v':('down',(1, 0)), + '>':('right',(0, 1)), + '<':('left',(0, -1)), + } + + pos = start + + nprint(grid) + #print(grid) + grid = resizeGrid(grid) + print() + nprint2(grid) + #print(grid) + + print() + + for idx, inst in enumerate(instructions): + #print('Move',inst,'(',len(instructions)-idx,')') + dir = directions[inst][0] + next = get_value_in_direction(grid,pos,dir) + + # If wall, don't do anything + if next == '#': + #nprint(grid,pos) + #input() + continue + + # If free space, move there + if next == '.': + grid[pos[0]][pos[1]] = '.' + pos = addTuples(pos,directions[inst][1]) + grid[pos[0]][pos[1]] = '@' + + # If box, move the box and the stack of boxes. + if next == 'O': + #print('@',pos) + prev = pos + next_chars = ['@'] + next_poss = [pos] + skip = False + while True: + nextPos = addTuples(pos,directions[inst][1]) + nextChar = get_value_in_direction(grid,nextPos) + #print(nextPos,nextChar) + if nextChar == 'O': + next_chars.append(nextChar) + next_poss.append(nextPos) + pos = nextPos + if nextChar == '.': + next_chars.append(nextChar) + next_poss.append(nextPos) + break + if nextChar == '#': + skip = True + pos = prev + break + + #input() + if not skip: + for ndx,n in enumerate(next_poss): + if ndx == 0: + grid[n[0]][n[1]] = '.' + pos = next_poss[ndx+1] + else: + grid[n[0]][n[1]] = next_chars[ndx-1] + +start_time = time.time() +print('Part 2:',part2(), '\t\t', round((time.time() - start_time)*1000), 'ms') \ No newline at end of file diff --git a/__pycache__/fred.cpython-311.pyc b/__pycache__/fred.cpython-311.pyc index 5a6813bddbb71d57e4edc77cb0456cf69ff48ab3..88f68b7e10f5a7bef54001e1b0daedb579303cb9 100644 GIT binary patch delta 2682 zcmbVN4Qx}_6@J&x&p$~VC$(u_+{CycBsf3<3zUjvE|poKloEvy285CtKVwXc<6Rp_ zGJA2lKhx6I=?%q9ooZ>JOV(_pawmmprRg+jZ0a_@&1lhEEv4P)r0z#STiH}?)6RM3 zFDRX~J-_$e@1A?l&%O5?-=BR*e*H&M{%w<~goEe3rX?G*yl`cu1;spk ze|=fYap$-g8L4Lvu3W`3)n-=OUdb9(r*)DL*G5a(JB_xAtz3#cb@ZTyLNwM6yoqt&)LNjC)DxHhDb^l@!Wi0O}LV&vweOiVKpWR5kp z!-hVH0n}QfW^9X3OdHckLiMdKhn8Yo>@G=6f6u5!GAx!z`YGdU5Yp>vSZIoHXTGr5 zOSE$5Z66%CERjn6WUA~n*qqmKgVYC|OS&bDox9ftETD-(hi#0{gkj2LS`*tq1Ua+wOY`AZ33!I4d|1$EqsF_{gBeMCmLhZ4r z<+eF4YP!Q?oFuR}Hj2#HU4CFI_f%8d7&G3^vC6yGB9$+7)OXJS&85z7bukbF;Uv<< zInCKWt^JLr4b$Zl;!q$ZflU&H_k|=y@Kc{Jq!>?xBp(e1LOv%^1WzsmdEKs_P9&sjoOf<8Th;72$Lpy%+tI<>th;!hH{@3{BJVQo< zW5ES(nX&CU!s*A7?o{QR`M#9r*@5Ih!B(60o?rFKs!Z$oH7R{cKX0o6sIa8El0)gP zUzr^_vt!Oum9wlURN2xSMhC|RGwWZ9r{V>%HtiqINE7SF{pb6qwbNa18fR9#SuWdM zv({P9kE>++_A7^TVy7&2=EY7R@Lofu3;qdddeiLc+1gw~huqMS2efzOy7%S8{j#_} zFYX5d?=@?6y75BeMEyi$$~o|!rDiSrcOnqiJGVYvkk2lM zT7O2L)SuRWtmDcpXIoRz^rK^^M%%~QWs@Usax8GXP_06e%$1g<$g>Y6A1ahprs~t5 z$(7mVGJC$v4g@SEJt=q2Aj$?YZxDgNThJOuO1FJwTSEQOX6ER$vdoi0wzl=VMEDXU zNlW&Z8=862!T!C;Q~6~OY$1?2!$1<;$9DE;Q%m;MhX*u-GO?|me2sm!ty)OJ=-zBk z+hq+IWH#4 zb~4ZQ?sk&1EU~+t9A|Is9u?k#p?9-gU7&oKJ#pZ;co_tA0$`UK{vI{J$LK7}9oX0S zO&t6dfWmtuNzqZ?@&1!OI*DSuOeo$@G|D=9mXj>&?`a~J*f)9_>wbtT<r+ZjdV&F|H|&WXrKi~Mdg_Ei?w)4>2yx|?_J54mp z#KS!%)tn&t!k~GHB@Qjr7mRasSj6(+`pT0pSwDoyb0Q!OR@0A+NGEq0};UMR!#G zf)=haIph$o1AUI&2wk*b%I$KlRQSkXgnkugTx2u-PebiihwXduTA*0+6w91q5mT%^ zig`~le<|ioF$pmbiV>oDid#XO5%8w@#L#}cUpf)=x#*4T^Wh=Vyor=8Z~!T<+D!0j PGb5?Zy+E@Y=`!*klw!e% delta 1969 zcma)6du&rx7{8~tx7~xWjh51l#~y5yB6PUPcx}qEvILn6VVfYXgV9??x3YGp-6FGd zLk(;?L&qUnlMzasSipqgb;(3T^e;j*>BUBt8^=RI67d1SV4^Yc`)-E=vp+mJ_jkVY zJHPXt@1FCW^UWP{=|?j2gS5014oYf=qxqxFXJ-DcB~MAbaIw&k1S}8V{aJwTa6z)K zfaMh~W|6FP_Secxw&;nlCXmX$uw+-+xe#&i4H}N?)^-blRCJgqLE$*zxKr>Yik)*@ zQ+2v-eNY?J?a~BEE6n3K>SQ~X&bJ7yTD7-4ke--<7}SWmtbe;fE~sT^Dos6Ii6LQX z2pLiTVbXDMc}jJQvj{h^=}~uqOk@)UTqi%S7E`8~?+fz#HcbZ1cXD(o_?uexF^7}U zm5QnV!|(8;aXtL8Mbn1x<#bZhw9@OWrf6PDhztlKspYIQBwx`LO@0adF~v<$xD!O- zU2USG-RbFY{Yi2ap1MS9GJCbSq}rN93sJcXp&4N}&f(qSOA2u-d<(WMeoT+t$wG~& z(6#xfyDdOFq4NMf{}5rO5?|)6S#!ho!J@-Oce!*S;~tmJj#U_X(vnN=asd5ReU+ii z@eD(#wy!H(dpSKfmYzFdFognxs}HXZw;w7Gl}{M6!Uf^>Axp#_H4JZvI)`iI?BbES zvAmDB$k}BV@?*yJvT=RfxE>6sw~SdwERljpr<`qzXWK?9W5!joaaG*73Jj>%4fA?p zhQ;INx#7yt-pGd7oMlia%=3>lN5p8!uzQ3bZX2nW7p#phSbKqwneDRK9yi;;fO^Y3 zKP*N{hTKtpsBL6n%v>s)OXKEJFrdQP5UYR48mSzzMV&EYv1}}k8;ik!I+2vtuOHC& z>1Xuo@8-aEsCy#4x#A)b_QIa!NLyFhc=8N8u%=0P1&HO+FKZ+X@v&p&1v&e0SMg55 zzEAFXvn#Njy69^_R!KL@&ufUAy|-@L3oSsbzGhW*&RNHS@MCgMMopva)4DtoV-s~&5@P!LGU8$O`a$6n(43Q$dYE~ZU2fQ8 zJ_`gL2B=Y^uT#UXqUYEa$5u-i2af_Me3K|DI_lcv?R3%ik;a3d_z2K<*|&}ya+*DG zEFq&TuhBxr*oMYj;%6<5`NAcT{45PNF4K@<>GK`qe9~vYSkvffc2s;ZZ45e!Ai8{k z-E@@cT}y;3z!XWPt^)0nlc>}yget^IyP=cVlOWDX^#_`0V0&j1++ixS{q7ZHk95wR zK^7iF;UK~x1O{+|P<7R0`W;de?6;OI-8D32*6W)y=QfyK8R9O#t<2+fHhKI{+o0oP zWvy@LjH66l992}Eg%QxJ2r|3ZYD!T@5E`XSPd=XroL96?m&cIWY+(3Wd16Y&kPiQA%Me7HIn+T%_Q-P@AliMupn@0|^QD11b z8t#6^IzC3oe#_={{WK$2|oY; diff --git a/fred.py b/fred.py index 76ff892..cd59ccf 100644 --- a/fred.py +++ b/fred.py @@ -267,22 +267,38 @@ def nprint(grid, cur: set = None, sign: str = None, positions:list = None): if positions is not None and not isinstance(positions, list): raise TypeError("Positions must be a list.") + prepend = 0 for idx, i in enumerate(grid): for jdx, j in enumerate(i): + if jdx == 0: + prepend = str(idx)+' ' + else: + prepend = '' + if (idx, jdx) == cur: - if len(sign) > 1: - print(sign[0] + grid[idx][jdx] + sign[1], end='') # Print with sign + if sign is not None: + if len(sign) > 1: + print(prepend+sign[0] + grid[idx][jdx] + sign[1], end='') # Print with sign + else: + print(prepend+colored(sign,'green',attrs=["underline"]), end=' ') # Print sign else: - print(colored(sign,'blue'), end=' ') # Print sign + print(prepend+colored(grid[idx][jdx],'green',attrs=["underline"]), end=' ') else: if positions is not None: if (idx,jdx) in positions: - print(colored(grid[idx][jdx],'red'),end=' ') + print(prepend+colored(grid[idx][jdx],'red'),end=' ') else: - print(grid[idx][jdx], end=' ') + print(prepend+grid[idx][jdx], end=' ') else: - print(grid[idx][jdx], end=' ') # Regular grid element + print(prepend+grid[idx][jdx], end=' ') # Regular grid element print() + + + for r in range(len(grid[0])): + if r == 0: + print(' ',end='') + print(r,end=' ') + print() def list2int(x): """