% % ttt.erl % -module(ttt). -compile(export_all). %-export([play/0]). play() -> io:fwrite("Welcome to Erlang's Tic-Tac-Toe. You are the X player and go first.~n"), turn(player, [ 0,0,0 , 0,0,0 , 0,0,0 ]). turn(player, Board) -> drawBoard(Board), getMove(Board); turn(computer, Board) -> drawBoard(Board), makeMove(Board). drawBoard(Board) -> io:fwrite(" ~s | ~s | ~s ~n", [getDisplay(Board,1), getDisplay(Board,2), getDisplay(Board,3)] ), io:fwrite("---+---+---~n", []), io:fwrite(" ~s | ~s | ~s ~n", [getDisplay(Board,4), getDisplay(Board,5), getDisplay(Board,6)] ), io:fwrite("---+---+---~n", []), io:fwrite(" ~s | ~s | ~s ~n", [getDisplay(Board,7), getDisplay(Board,8), getDisplay(Board,9)] ). getDisplay(Board,Position) -> case lists:nth(Position, Board) of -1 -> ["O"]; 0 -> [" "]; 1 -> ["X"] end. getMove(Board) -> {ok, PlayerMove} = io:fread("Where do you want to move [1-9]? ", "~d"), % PlayerMove gets returned as a list from io:fread. io:fwrite("Placing an X into position ~w.~n", PlayerMove), [Position | Tail] = PlayerMove, % 'cause PlayerMove is a list. turn(computer, replaceInList(1, Position, Board)). makeMove(Board) -> io:fwrite("Calculating computer move...", []), ComputerMove = computeMove(Board), io:fwrite("Pacing an O into position ~w.~n", [ComputerMove]), turn(player, replaceInList(-1, ComputerMove, Board)). computeMove(Board) -> findFirst(0, Board). findFirst(Target, [Head | Tail]) when (Target == Head) -> 1; % This is ugly because if the Target is never found in the list findFirst(Target, [Head | Tail]) when (Target /= Head) -> 1 + findFirst(Target, Tail); % this function will return length(List)+1. At least it's not a findFirst(Target, []) -> 1. % valid value, but this is NOT a standard convention. -1 would be better. replaceInList(Value, Position, List) -> {Part1, Part2} = lists:split(Position-1, List), % Break the list in two just before the specified Position. [Head | Tail] = Part2, % Separate Part2 into Head and Tail, discarding the Head. Part1 ++ [Value] ++ Tail. % Cons together the result: Part1 ++ the new Value ++ the Tail from Part2.