# ========================================================================== #
# These globals should be part of some library, hidden from the user
# The only exposed functions are: get_position, get_world_dimensions,
# move, measure, swap, and the directions (which should ideally be an enum)
_grid = [[4, 5, 2, 2],
[1, 3, 6, 4]]
_height = len(_grid)
_length = len(_grid[0])
def get_world_dimensions():
return (_length, _height)
_x = 0
_y = 0
def get_position():
return (_x, _y)
North = "N"
South = "S"
East = "E"
West = "W"
# Return the value of the current cell, or the one directly in the specified direction
def measure(direction=None):
if direction is None:
return _grid[_y][_x]
# Hacky solution to get the value in that direction
# (probably not how it would actually be implemented)
x, y = get_position()
move(direction)
val = measure()
move_to(x, y)
return val
# Move one cell in the specified direction
def move(direction):
global _x, _y
if direction == North:
_y = (_y + 1) % _height
elif direction == South:
_y = (_y - 1) % _height
elif direction == East:
_x = (_x + 1) % _length
elif direction == West:
_x = (_x - 1) % _length
else:
raise ValueError(f"{direction} is not a valid direction to move in")
# Move the values of the current cell and the one in the specified direction
# But not wrapping around the edges
def swap(direction):
# also kinda hacky, but this is not the point
if direction == North and _y + 1 < _height:
_grid[_y][_x], _grid[_y + 1][_x] = _grid[_y + 1][_x], _grid[_y][_x]
elif direction == South and _y > 0:
_grid[_y][_x], _grid[_y - 1][_x] = _grid[_y - 1][_x], _grid[_y][_x]
elif direction == East and _x + 1 < _length:
_grid[_y][_x], _grid[_y][_x + 1] = _grid[_y][_x + 1], _grid[_y][_x]
elif direction == West and _x > 0:
_grid[_y][_x], _grid[_y][_x - 1] = _grid[_y][_x - 1], _grid[_y][_x]
else:
raise ValueError(f"{direction} is not a valid direction to swap in from position {(_x, _y)}")
# ========================================================================== #
# Not a part of the API, but convenient for me here
# The user could make something with the same effect, through get_position() and move()
def move_to(x, y):
global _x, _y
_x = x
_y = y
# ========================================================================== #
# My solution
# assumes initial position is (0,y) for some y, then this sorts row number y
# and returns to (0, y)
def sort_row():
m, n = get_world_dimensions()
move(East)
for i in range(1, m):
val = measure()
k = i
while k > 0 and measure(West) > val:
swap(West)
move(West)
k -= 1
for j in range(k, i+1):
move(East)
# assumes initial position is (0, y), sorts all rows, and returns to (0, y)
def sort_all_rows():
m, n = get_world_dimensions()
for i in range(n):
sort_row()
move(North)
# assumes initial position is (x, 0) for some x, then this sorts column number x
# and returns to (x, 0)
def sort_col():
m, n = get_world_dimensions()
move(North)
for i in range(1, n):
val = measure()
k = i
while k > 0 and measure(South) > val:
swap(South)
move(South)
k -= 1
for j in range(k, i+1):
move(North)
# assumes initial position is (x, 0), sorts all columns, and returns to (x, 0)
def sort_all_cols():
m, n = get_world_dimensions()
for i in range(m):
sort_col()
move(East)
def sort_rows_then_cols():
move_to(0, 0)
sort_all_rows()
sort_all_cols()
print("Before")
print(_grid)
sort_rows_then_cols()
print("After")
print(_grid)
IyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAjCiMgVGhlc2UgZ2xvYmFscyBzaG91bGQgYmUgcGFydCBvZiBzb21lIGxpYnJhcnksIGhpZGRlbiBmcm9tIHRoZSB1c2VyCiMgVGhlIG9ubHkgZXhwb3NlZCBmdW5jdGlvbnMgYXJlOiBnZXRfcG9zaXRpb24sIGdldF93b3JsZF9kaW1lbnNpb25zLAojIG1vdmUsIG1lYXN1cmUsIHN3YXAsIGFuZCB0aGUgZGlyZWN0aW9ucyAod2hpY2ggc2hvdWxkIGlkZWFsbHkgYmUgYW4gZW51bSkKX2dyaWQgPSBbWzQsIDUsIDIsIDJdLAogICAgICAgICBbMSwgMywgNiwgNF1dCl9oZWlnaHQgPSBsZW4oX2dyaWQpCl9sZW5ndGggPSBsZW4oX2dyaWRbMF0pCmRlZiBnZXRfd29ybGRfZGltZW5zaW9ucygpOgogICAgcmV0dXJuIChfbGVuZ3RoLCBfaGVpZ2h0KQpfeCA9IDAKX3kgPSAwCmRlZiBnZXRfcG9zaXRpb24oKToKICAgIHJldHVybiAoX3gsIF95KQoKTm9ydGggPSAiTiIKU291dGggPSAiUyIKRWFzdCA9ICJFIgpXZXN0ID0gIlciCgojIFJldHVybiB0aGUgdmFsdWUgb2YgdGhlIGN1cnJlbnQgY2VsbCwgb3IgdGhlIG9uZSBkaXJlY3RseSBpbiB0aGUgc3BlY2lmaWVkIGRpcmVjdGlvbgpkZWYgbWVhc3VyZShkaXJlY3Rpb249Tm9uZSk6CiAgICBpZiBkaXJlY3Rpb24gaXMgTm9uZToKICAgICAgICByZXR1cm4gX2dyaWRbX3ldW194XQogICAgIyBIYWNreSBzb2x1dGlvbiB0byBnZXQgdGhlIHZhbHVlIGluIHRoYXQgZGlyZWN0aW9uCiAgICAjIChwcm9iYWJseSBub3QgaG93IGl0IHdvdWxkIGFjdHVhbGx5IGJlIGltcGxlbWVudGVkKQogICAgeCwgeSA9IGdldF9wb3NpdGlvbigpCiAgICBtb3ZlKGRpcmVjdGlvbikKICAgIHZhbCA9IG1lYXN1cmUoKQogICAgbW92ZV90byh4LCB5KQogICAgcmV0dXJuIHZhbAoKIyBNb3ZlIG9uZSBjZWxsIGluIHRoZSBzcGVjaWZpZWQgZGlyZWN0aW9uCmRlZiBtb3ZlKGRpcmVjdGlvbik6CiAgICBnbG9iYWwgX3gsIF95CiAgICBpZiBkaXJlY3Rpb24gPT0gTm9ydGg6CiAgICAgICAgX3kgPSAoX3kgKyAxKSAlIF9oZWlnaHQKICAgIGVsaWYgZGlyZWN0aW9uID09IFNvdXRoOgogICAgICAgIF95ID0gKF95IC0gMSkgJSBfaGVpZ2h0CiAgICBlbGlmIGRpcmVjdGlvbiA9PSBFYXN0OgogICAgICAgIF94ID0gKF94ICsgMSkgJSBfbGVuZ3RoCiAgICBlbGlmIGRpcmVjdGlvbiA9PSBXZXN0OgogICAgICAgIF94ID0gKF94IC0gMSkgJSBfbGVuZ3RoCiAgICBlbHNlOgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoZiJ7ZGlyZWN0aW9ufSBpcyBub3QgYSB2YWxpZCBkaXJlY3Rpb24gdG8gbW92ZSBpbiIpCgojIE1vdmUgdGhlIHZhbHVlcyBvZiB0aGUgY3VycmVudCBjZWxsIGFuZCB0aGUgb25lIGluIHRoZSBzcGVjaWZpZWQgZGlyZWN0aW9uCiMgQnV0IG5vdCB3cmFwcGluZyBhcm91bmQgdGhlIGVkZ2VzCmRlZiBzd2FwKGRpcmVjdGlvbik6CiAgICAjIGFsc28ga2luZGEgaGFja3ksIGJ1dCB0aGlzIGlzIG5vdCB0aGUgcG9pbnQKICAgIGlmIGRpcmVjdGlvbiA9PSBOb3J0aCBhbmQgX3kgKyAxIDwgX2hlaWdodDoKICAgICAgICBfZ3JpZFtfeV1bX3hdLCBfZ3JpZFtfeSArIDFdW194XSA9IF9ncmlkW195ICsgMV1bX3hdLCBfZ3JpZFtfeV1bX3hdCiAgICBlbGlmIGRpcmVjdGlvbiA9PSBTb3V0aCBhbmQgX3kgPiAwOgogICAgICAgIF9ncmlkW195XVtfeF0sIF9ncmlkW195IC0gMV1bX3hdID0gX2dyaWRbX3kgLSAxXVtfeF0sIF9ncmlkW195XVtfeF0KICAgIGVsaWYgZGlyZWN0aW9uID09IEVhc3QgYW5kIF94ICsgMSA8IF9sZW5ndGg6CiAgICAgICAgX2dyaWRbX3ldW194XSwgX2dyaWRbX3ldW194ICsgMV0gPSBfZ3JpZFtfeV1bX3ggKyAxXSwgX2dyaWRbX3ldW194XQogICAgZWxpZiBkaXJlY3Rpb24gPT0gV2VzdCBhbmQgX3ggPiAwOgogICAgICAgIF9ncmlkW195XVtfeF0sIF9ncmlkW195XVtfeCAtIDFdID0gX2dyaWRbX3ldW194IC0gMV0sIF9ncmlkW195XVtfeF0KICAgIGVsc2U6CiAgICAgICAgcmFpc2UgVmFsdWVFcnJvcihmIntkaXJlY3Rpb259IGlzIG5vdCBhIHZhbGlkIGRpcmVjdGlvbiB0byBzd2FwIGluIGZyb20gcG9zaXRpb24geyhfeCwgX3kpfSIpCiAgICAgICAgCiAgICAKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gIwoKIyBOb3QgYSBwYXJ0IG9mIHRoZSBBUEksIGJ1dCBjb252ZW5pZW50IGZvciBtZSBoZXJlCiMgVGhlIHVzZXIgY291bGQgbWFrZSBzb21ldGhpbmcgd2l0aCB0aGUgc2FtZSBlZmZlY3QsIHRocm91Z2ggZ2V0X3Bvc2l0aW9uKCkgYW5kIG1vdmUoKQpkZWYgbW92ZV90byh4LCB5KToKICAgIGdsb2JhbCBfeCwgX3kKICAgIF94ID0geAogICAgX3kgPSB5CgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICMKIyBNeSBzb2x1dGlvbgoKIyBhc3N1bWVzIGluaXRpYWwgcG9zaXRpb24gaXMgKDAseSkgZm9yIHNvbWUgeSwgdGhlbiB0aGlzIHNvcnRzIHJvdyBudW1iZXIgeQojIGFuZCByZXR1cm5zIHRvICgwLCB5KQpkZWYgc29ydF9yb3coKToKICAgIG0sIG4gPSBnZXRfd29ybGRfZGltZW5zaW9ucygpCiAgICBtb3ZlKEVhc3QpCiAgICBmb3IgaSBpbiByYW5nZSgxLCBtKToKICAgICAgICB2YWwgPSBtZWFzdXJlKCkKICAgICAgICBrID0gaQogICAgICAgIHdoaWxlIGsgPiAwIGFuZCBtZWFzdXJlKFdlc3QpID4gdmFsOgogICAgICAgICAgICBzd2FwKFdlc3QpCiAgICAgICAgICAgIG1vdmUoV2VzdCkKICAgICAgICAgICAgayAtPSAxCiAgICAgICAgZm9yIGogaW4gcmFuZ2UoaywgaSsxKToKICAgICAgICAgICAgbW92ZShFYXN0KQoKIyBhc3N1bWVzIGluaXRpYWwgcG9zaXRpb24gaXMgKDAsIHkpLCBzb3J0cyBhbGwgcm93cywgYW5kIHJldHVybnMgdG8gKDAsIHkpCmRlZiBzb3J0X2FsbF9yb3dzKCk6CiAgICBtLCBuID0gZ2V0X3dvcmxkX2RpbWVuc2lvbnMoKQogICAgZm9yIGkgaW4gcmFuZ2Uobik6CiAgICAgICAgc29ydF9yb3coKQogICAgICAgIG1vdmUoTm9ydGgpCgojIGFzc3VtZXMgaW5pdGlhbCBwb3NpdGlvbiBpcyAoeCwgMCkgZm9yIHNvbWUgeCwgdGhlbiB0aGlzIHNvcnRzIGNvbHVtbiBudW1iZXIgeAojIGFuZCByZXR1cm5zIHRvICh4LCAwKQpkZWYgc29ydF9jb2woKToKICAgIG0sIG4gPSBnZXRfd29ybGRfZGltZW5zaW9ucygpCiAgICBtb3ZlKE5vcnRoKQogICAgZm9yIGkgaW4gcmFuZ2UoMSwgbik6CiAgICAgICAgdmFsID0gbWVhc3VyZSgpCiAgICAgICAgayA9IGkKICAgICAgICB3aGlsZSBrID4gMCBhbmQgbWVhc3VyZShTb3V0aCkgPiB2YWw6CiAgICAgICAgICAgIHN3YXAoU291dGgpCiAgICAgICAgICAgIG1vdmUoU291dGgpCiAgICAgICAgICAgIGsgLT0gMQogICAgICAgIGZvciBqIGluIHJhbmdlKGssIGkrMSk6CiAgICAgICAgICAgIG1vdmUoTm9ydGgpCgojIGFzc3VtZXMgaW5pdGlhbCBwb3NpdGlvbiBpcyAoeCwgMCksIHNvcnRzIGFsbCBjb2x1bW5zLCBhbmQgcmV0dXJucyB0byAoeCwgMCkKZGVmIHNvcnRfYWxsX2NvbHMoKToKICAgIG0sIG4gPSBnZXRfd29ybGRfZGltZW5zaW9ucygpCiAgICBmb3IgaSBpbiByYW5nZShtKToKICAgICAgICBzb3J0X2NvbCgpCiAgICAgICAgbW92ZShFYXN0KQoKZGVmIHNvcnRfcm93c190aGVuX2NvbHMoKToKCW1vdmVfdG8oMCwgMCkKCXNvcnRfYWxsX3Jvd3MoKQoJc29ydF9hbGxfY29scygpCgoKcHJpbnQoIkJlZm9yZSIpCnByaW50KF9ncmlkKQoKc29ydF9yb3dzX3RoZW5fY29scygpCgpwcmludCgiQWZ0ZXIiKQpwcmludChfZ3JpZCk=