fprintf('Starting\n');

t1_socket = tcpip('0.0.0.0', 30000, 'NetworkRole', 'server');
t2_socket = tcpip('0.0.0.0', 30002, 'NetworkRole', 'server');

fopen(t1_socket);
fprintf(t1_socket, 'Welcome to Battleship Player 1!\nWaiting for Player 2...\n');
fopen(t2_socket);
fprintf(t2_socket, 'Hello Player 2! Welcome to Battleship!\n');

fprintf(t1_socket, 'Both players connected!');
fprintf(t2_socket, 'Both players connected!');

socks = [t1_socket, t2_socket];

for i = 1:length(socks)
	clearSock(socks(i));
end

boards = setupBoards(socks);

[winner_id, boards] = playRound(boards, socks);

while ~winner_id
	[winner_id, boardNew] = playRound(boards, socks);
	boards = boardNew;
end

for i = 1:length(socks)
	clearSock(socks(i));
	fprintf(socks(i), 'Player %d Won!\n', winner_id);
	fprintf(socks(i), 'Thank you for playing Battleship!\n');
end
fclose(t1_socket);
fclose(t2_socket);

fprintf('Exiting\n');

function [winner_id, boards] = playRound(boards, socks)
	fprintf('Starting Round\n');
	winner_id = 0;
	done = zeros(1, 2);

	for p_id = 1:2
		clearSock(socks(p_id));
		printBoardHidden(socks(p_id),reshape(boards(3 - p_id,:,:),10,10));
		fprintf(socks(p_id), 'Hit location: ');
	end

	hits = [];

	while sum(done) < length(done)
		[p_id,data] = getSomeInput(socks, ~done);

		[err, coord, vert] = parseCoord(data);
		if err
			fprintf(socks(p_id), 'Bad coordinate, try again: ');
			continue
		end

		done(p_id) = 1;
		hits(size(hits, 1) + 1,1:4) = [3 - p_id, coord(1), coord(2), p_id];


		clearSock(socks(p_id));
		fprintf(socks(p_id), 'Waiting for other players...\n');
	end

	pause(.1);
	
	for i=1:length(socks)
		clearSock(socks(i));
		fprintf(socks(i), 'Round Results:\n\n');
	end

	for i = 1:size(hits,1)
		current = boards(hits(i,1), hits(i, 2), hits(i,3));
		new = current;

		if current == 1
			new = 2;
			for p_id=1:length(socks)
				fprintf(socks(p_id), 'Player %d hit Player %d on [%d, %d] !\n', [hits(i,4), hits(i,1), hits(i,2), hits(i,3)]);
			end
		else
			new = 3;
		end
		boards(hits(i,1), hits(i, 2), hits(i,3)) = new;
	end

	for p_id=1:length(socks)
		partsLeft = sum(sum(boards(p_id,:,:) == 1));
		if partsLeft == 0
			winner_id = 3 - p_id;
			return
		end
	end

	nhits = size(hits,1);

	pause(2 + nhits * 1);
	
	fprintf('Finished Round\n');
end

function boards = setupBoards(socks)
	SHIP_SIZES = [5 4 3 3 2];
	boards = zeros(2, 10, 10) + 0;

	% Delete this later

	%boards(:,1:3,1) = 1;
	%return

	%%%%%%%%%%%%%%%%%%%

	for p_id = 1:2
		printBoard(socks(p_id),reshape(boards(p_id,:,:),10,10));
		fprintf(socks(p_id), 'Location of the first ship (Length %d): ', SHIP_SIZES(1));
	end

	ship_places = ones(1, 2);

	done = zeros(1, 2);
	while sum(done) < length(done)
		[p_id,data] = getSomeInput(socks, ~done);

		[err, coord, vert] = parseCoord(data);
		if err
			fprintf(socks(p_id), 'Bad coordinate, try again: ');
			continue
		end

		[err,sBoard] = drawShip(coord, vert, SHIP_SIZES(ship_places(p_id)));

		if err
			fprintf(socks(p_id), 'Collides with wall, try again: ');
			continue
		end

		board = reshape(boards(p_id,:,:),10,10);

		if sum(sum(board & sBoard))
			fprintf(socks(p_id), 'Collides with another ship, try again: ');
			continue
		end
		
		board = board + sBoard;
		boards(p_id,:,:) = board;

		if ship_places(p_id) == length(SHIP_SIZES)
			clearSock(socks(p_id));
			fprintf(socks(p_id), 'Board set up!\n');
			printBoard(socks(p_id),reshape(boards(p_id,:,:),10,10));
			fprintf(socks(p_id), '\nWaiting for other players...\n');
			done(p_id) = 1;
		else
			clearSock(socks(p_id));
			ship_places(p_id) = 1 + ship_places(p_id);
			printBoard(socks(p_id),reshape(boards(p_id,:,:),10,10));
			fprintf(socks(p_id), 'Location of next ship (Length %d): ', SHIP_SIZES(ship_places(p_id)));
		end
	end
end

function clearSock(socket)
	% Hex values from `true | clear | xxd`
	data = char([hex2dec('1b'), hex2dec('5b'), hex2dec('48'), hex2dec('1b'), hex2dec('5b'), hex2dec('4a')]);
	fprintf(socket, '%s', data);
end

function [err,board] = drawShip(coord, vert, len)
	err = 1;
	board = zeros(10);

	if coord(2 - vert) + len > 11
		return
	end

	while len > 0
		board(coord(1), coord(2)) = 1;
		coord(2 - vert) = coord(2 - vert) + 1;
		len = len - 1;
	end

	err = 0;
end

function [err, coord, vert] = parseCoord(str)
	err = 1;
	coord = [-1 -1];
	vert = 1;
	if length(str) ~= 2
		return
	end
	if str(1) >= 'a' & str(1) <= 'j'
		vert = 0;
		str(1) = char(str(1) - ('a' - 'A'));
	end

	if str(1) >= 'A' & str(1) <= 'J'
		coord(1) = str(1) - 'A' + 1; 
	else
		return
	end

	if str(2) >= '0' & str(2) <= '9'
		coord(2) = str(2) - '0' + 1;
	else
		return
	end

	err = 0;
end

function [p_id,data] = getSomeInput(socks, sockmask)
	p_id = 0;
	data = '';
	while 1
		for pid = 1:length(socks)
			p_id = pid;
			if ~sockmask(p_id)
				continue
			end
			if socks(p_id).BytesAvailable > 0
				data = fread(socks(p_id), socks(p_id).BytesAvailable);
				data = data(1:length(data)-1); % Remove newline
				fprintf('Got data from %d: [%s]\n', p_id, data);
				return
			end
		end
	end
end

function printBoard(socket, board)
	width = size(board,2);
	line = char(zeros(1,width + 2) + '-');
	asciiBoard = char((board == 1) * 'H' + (board == 0) * ' ' + (board == 2) * 'X' + '.' * (board == 3));
	fprintf(socket,'%s\n', line);
	for i=1:width
		fprintf(socket,'|%s|', convertCharsToStrings(asciiBoard(i,:)),'sync');
		fprintf(socket,'%s\n', convertCharsToStrings(char('A' + i - 1)), 'sync');
	end
	fprintf(socket,'%s\n', convertCharsToStrings(line));
	fprintf(socket,' %s\n',convertCharsToStrings(char((1:width) + '0' - 1)));
end

function printBoardHidden(socket, board)
	width = size(board,2);
	line = char(zeros(1,width + 2) + '-');
	asciiBoard = char((board == 1) * ' ' + (board == 0) * ' ' + (board == 2) * 'X' + '.' * (board == 3));
	fprintf(socket,'%s\n', line);
	for i=1:width
		fprintf(socket,'|%s|', convertCharsToStrings(asciiBoard(i,:)),'sync');
		fprintf(socket,'%s\n', convertCharsToStrings(char('A' + i - 1)), 'sync');
	end
	fprintf(socket,'%s\n', convertCharsToStrings(line));
	fprintf(socket,' %s\n',convertCharsToStrings(char((1:width) + '0' - 1)));
end