c++ – Simple Rock Paper Scissors

I made a Rock Paper Scissors game. It works fine but I would like to know how can I improve it further.

#include <iostream>
#include <algorithm>
#include <string>
#include <random>
#include <array>
#include <map>
#include <limits>

namespace
{
    enum Winner { Tie, Player, Computer, WinnerCount };
    enum Items { Rock, Paper, Scissors, ItemsCount };

    template<typename T, std::size_t N>
    using Matrix = std::array<std::array<T, N>, N>;
}


std::string user_choice(const std::array<std::string, Items::ItemsCount>& data)
{
    std::string result;
    static auto comp = (&result)(const std::string& str) { return str == result; };
    bool is_input_valid = false;

    do
    {
        std::cout << "Enter your choice, rock, paper, or scissors: ";
        std::getline(std::cin, result);

        is_input_valid = !(std::cin.fail() || std::none_of(data.begin(), data.end(), comp));

        if (!is_input_valid) {
            std::cout << "Not valid input.n";
        }

        std::cin.clear();
        std::cin.ignore(std::cin.rdbuf()->in_avail());
    } while (!is_input_valid);

    return result;
}

bool play_again()
{
    char result;
    bool is_input_valid = false;

    do
    {
        std::cout << "Do you want to play again? (y/n): ";
        std::cin >> result;

        result = std::toupper(result);

        is_input_valid = !(std::cin.fail() || (result != 'Y' && result != 'N'));

        if (!is_input_valid)
        {
            std::cout << "Not valid input.n";
        }

        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
    } while (!is_input_valid);

    return result == 'Y';
}

int main()
{
    // Set up game
    const Matrix<Winner, Winner::WinnerCount> table
    {
        {  // Rock      Paper      Scissors
            { Tie,      Computer,  Player   }, // Rock
            { Player,   Tie,       Computer }, // Paper
            { Computer, Player,    Tie      }, // Scissors
        }
    };

    const std::array<std::string, Items::ItemsCount> data
    {
        "rock",
        "paper",
        "scissors"
    };

    std::map<std::string, Items> binding_items
    {
       { data(Items::Rock),      Items::Rock     },
       { data(Items::Paper),     Items::Paper    },
       { data(Items::Scissors),  Items::Scissors },
    };

    const std::array<std::string, Winner::WinnerCount> winner_result
    {
       "It's a tie!nn",
       "You win!nn",
       "You lose!nn"
    };

    std::mt19937 engine{ std::random_device()() };
    auto dist = std::uniform_int_distribution<>(0, Items::ItemsCount - 1);

    // Game loop
    do
    {
        std::cout << "nntRock Paper Scissors Gamenn";

        const auto user_chose = user_choice(data);
        const Items player = binding_items(user_chose);

        const Items computer = static_cast<Items>(dist(engine));
        const auto computer_chose = data(computer);

        std::cout << "nnYou entered: " << user_chose << 'n';
        std::cout << "Computer chose: " << computer_chose << 'n';

        std::cout << winner_result(table(player)(computer));
    } while (play_again());
}