-module(ttt). -export_type([ player/0, square/0, board/0, game_result/0]). -export([ who_wins/1, empty_board/0, move/4, format/1]). -type player() :: 'X' | 'O'. -type square() :: player() | 'E'. -type board() :: list(square()). -type game_result() :: player() | 'draw' | 'running'. -define(EMPTY_BOARD, ['E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E']). -spec empty_board() -> board(). empty_board() -> ?EMPTY_BOARD. -spec who_wins(Board :: board()) -> game_result(). who_wins([A, A, A, _, _, _, _, _, _]) when A == 'X' orelse A == 'O' -> A; who_wins([_, _, _, A, A, A, _, _, _]) when A == 'X' orelse A == 'O' -> A; who_wins([_, _, _, _, _, _, A, A, A]) when A == 'X' orelse A == 'O' -> A; who_wins([A, _, _, A, _, _, A, _, _]) when A == 'X' orelse A == 'O' -> A; who_wins([_, A, _, _, A, _, _, A, _]) when A == 'X' orelse A == 'O' -> A; who_wins([_, _, A, _, _, A, _, _, A]) when A == 'X' orelse A == 'O' -> A; who_wins([A, _, _, _, A, _, _, _, A]) when A == 'X' orelse A == 'O' -> A; who_wins([_, _, A, _, A, _, A, _, _]) when A == 'X' orelse A == 'O' -> A; who_wins(Board) -> case lists:member('E', Board) of true -> running; false -> draw end. move(_, _, Row, _) when Row < 0 orelse Row > 2 -> {bad_arg}; move(_, _, _, Col) when Col < 0 orelse Col > 2 -> {bad_arg}; move(_, Move, _, _) when not (Move == 'X') -> {bad_arg}; move(Board, Move, Row, Col) -> I = Row * 3 + Col, Updated = lists:sublist(Board, I) ++ [Move] ++ lists:nthtail(I + 1, Board), {ok, Updated}. -spec format(board()) -> io_lib:chars(). format(Board) when length(Board) == 9 -> B = lists:map(fun(C) -> case C of 'E' -> ' '; _ -> C end end, Board), io_lib:format("+---+~n|~s~s~s|~n|~s~s~s|~n|~s~s~s|~n+---+~n", B); format(_) -> "bad board".