From 65afb1154630c31fd642e643dde86de20db0c8ba Mon Sep 17 00:00:00 2001 From: KtorZ Date: Tue, 16 Jul 2024 14:47:17 +0200 Subject: [PATCH] Implement quicksort on chess board. Note that it might be easier / cheaper to serialize and compare bytes? --- .../lib/benchmarks/knights/heuristic.ak | 73 ++++++++++++++++++- .../benchmarks/lib/benchmarks/knights/sort.ak | 20 ++++- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/examples/benchmarks/lib/benchmarks/knights/heuristic.ak b/examples/benchmarks/lib/benchmarks/knights/heuristic.ak index e89b5968..2c36662d 100644 --- a/examples/benchmarks/lib/benchmarks/knights/heuristic.ak +++ b/examples/benchmarks/lib/benchmarks/knights/heuristic.ak @@ -59,7 +59,11 @@ pub fn descendants(board: ChessSet) -> List { let singles = single_descend(board) when singles is { - [] -> board |> desc_and_no |> quick_sort |> list.map(builtin.snd_pair) + [] -> + board + |> desc_and_no + |> quicksort(compare_chess_set) + |> list.map(fn(t) { t.2nd }) [_] -> singles _ -> [] @@ -126,5 +130,70 @@ fn move_knight(board: ChessSet, direction: Direction) -> ChessSet { } fn possible_moves(board: ChessSet) -> List { - direction_list() |> list.filter(fn(direction) { can_move(board, direction) }) + direction_list() |> list.filter(can_move(board, _)) +} + +fn compare_tile(a: Tile, b: Tile) -> Ordering { + if a.1st == b.1st { + int.compare(a.2nd, b.2nd) + } else { + int.compare(a.1st, b.1st) + } +} + +fn compare_list(xs: List, ys: List) -> Ordering { + when xs is { + [] -> + when ys is { + [] -> Equal + _ -> Less + } + [x, ..xs] -> + when ys is { + [] -> Greater + [y, ..ys] -> { + let ord = compare_tile(x, y) + if ord == Equal { + compare_list(xs, ys) + } else { + ord + } + } + } + } +} + +fn compare_chess_set(a: (Int, ChessSet), b: (Int, ChessSet)) -> Ordering { + if a.1st != b.1st { + int.compare(a.1st, b.1st) + } else { + let ChessSet { + size: size_a, + move_number: move_a, + start: start_a, + visited: visited_a, + } = a.2nd + let ChessSet { + size: size_b, + move_number: move_b, + start: start_b, + visited: visited_b, + } = b.2nd + if size_a != size_b { + int.compare(size_a, size_b) + } else if move_a != move_b { + int.compare(move_a, move_b) + } else if start_a != start_b { + when start_a is { + Some(a) -> + when start_b is { + Some(b) -> compare_tile(a, b) + None -> Greater + } + None -> Less + } + } else { + compare_list(visited_a, visited_b) + } + } } diff --git a/examples/benchmarks/lib/benchmarks/knights/sort.ak b/examples/benchmarks/lib/benchmarks/knights/sort.ak index 6e429da9..40a59c8f 100644 --- a/examples/benchmarks/lib/benchmarks/knights/sort.ak +++ b/examples/benchmarks/lib/benchmarks/knights/sort.ak @@ -1,3 +1,19 @@ -pub fn quick_sort(l: List) -> List { - todo +use aiken/list + +pub fn quicksort(xs: List, compare: fn(a, a) -> Ordering) -> List { + when xs is { + [] -> + [] + [head, ..tail] -> { + let before = + tail + |> list.filter(fn(x) { compare(x, head) == Less }) + |> quicksort(compare) + let after = + tail + |> list.filter(fn(x) { compare(x, head) != Less }) + |> quicksort(compare) + list.concat(before, [head, ..after]) + } + } }