Time Count For Move (Threads)

Asked

Viewed 861 times

1

What you need to answer the question is comments in the code:

using System;
using System.Threading.Tasks;

class Program
{

    static void Main(string[] args)
    {
        player1.Start();
        t.Start();

        while (t.IsAlive); //A intenção seria depois que o Thread t acabar se a Thread player1 
                            //ainda estiver ativa o jogador perde a rodada.
                            //gostaria também de que se a Thread player1 já acabou
                            //a Thread t pode se encerrar.
        if (player1.IsAlive) player1.Abort(); Console.Write("\nSeu Tempo Acabou");
    }

    static void player()
    {
        Console.Write("Player1 Escreva Algo (Nao Deixe Passar 10 Segundos): ");
        str += Console.ReadLine() + " ";
        Console.Write(" {0}", str);
    }

    static void tempo()
    {
        System.Threading.Thread.Sleep(10000); //10 sec = 10.000 milisec
    }

    static String str = "";
    static System.Threading.Thread player1 = new System.Threading.Thread(player);
    static System.Threading.Thread t = new System.Threading.Thread(tempo);

}

Ex: In chess games you have a time available to move your piece, if you do not move within for example 30 seconds you lose your move and it is the next player’s turn (Ai would show the message), now if you move your piece ahead of time, You just pass the time to another player without losing anything. the idea is +/- this.

3 answers

3

Using the class Task it’s easy to do what you want:

class Program
{
    static void Main(string[] args)
    {
        String str = null;

        //Objectos que permitem cancelar as Tasks
        var tokenSourceTempo = new CancellationTokenSource();
        var ctTempo = tokenSourceTempo.Token;
        var tokenSourcePlayer = new CancellationTokenSource();
        var ctPlayer = tokenSourcePlayer.Token;

        //Cria a task que espera 10 segundos até 
        Task.Factory.StartNew(
            () =>
            {
                Thread.Sleep(10000);

                if (ctTempo.IsCancellationRequested != true)
                {
                    tokenSourcePlayer.Cancel(); //Cancela a task player
                    Console.Write("\nSeu Tempo Acabou\n");
                }
            }, ctTempo);

        //Cria a task player
        var taskPlayer = Task.Factory.StartNew(
            () =>
            {
                var key = new ConsoleKeyInfo();

                Console.Write("Player1 Escreva Algo (Nao Deixe Passar 10 Segundos): ");

                while (key.Key != ConsoleKey.Enter)//Aceita teclas até a tecla enter ser usada
                {

                    key = Console.ReadKey();
                    ctPlayer.ThrowIfCancellationRequested();//Se a task player foi cancelada aborta
                    tokenSourceTempo.Cancel();//O player teclou algo, cancela task tempo
                    str += key.KeyChar;//Constroi string
                }

            }, ctPlayer);

        try
        {
            taskPlayer.Wait();// Espera enquanto o player tecla algo
            Console.Write("\nVocê escreveu: {0}\n", str);
            Console.ReadKey();
        }
        catch (AggregateException e)//Quando a task player é cancelada é lançada uma Exception
        {
            if (taskPlayer.IsCanceled)
            {

            }
        }
    }
}

You will now have to adjust to your needs.
Utilize Ctrl+F5 to test if you are using Visual Studio.

  • I don’t know if this really serves is because it’s kind of confusing for me but for me it seems that always after passing the 10 seconds it will show " nseu Tempo Acabou" I want this only appears if the player does not type anything.

  • I hadn’t understood it that way. I’ll edit the answer. Whatever happens after the player types something?

  • Well just do the following if the user report something beauty put in str and close the program, if it does not report anything in 10 seconds say that your time is over and pause the program with a Readline() and then close.

  • How would I treat the case where for example the player keystrokes something and then deletes ? in this case should also be shown the message.

  • I discovered a bug mt loco kkkk if you type for example Asd and then go pressing Backspace until the cursor reaches the word 'player1' then just come pressing the arrow to the right and see it happen kkk

  • For that we would have to use Console.ReadLine() instead of Console.ReadKey();. In this situation it will only be considered that the player entered something after this typing enter, that is, the time is counting until it is keyboard enter

Show 1 more comment

1

Well, I’ve created a few classes to make it easier to understand. Comments will help you understand the flow.

using System;
using System.Threading;

namespace Pt.Stackoverflow
{
    class Program
    {
        static void Main()
        {
            // nova partida
            var match = new Match(new Player("Player 1"), 60);

            //Ação customizada que será executada quando o usuário digitar algum texto
            match.OnPlayerInput += input =>
            {
                Console.WriteLine("Usuário escreveu: \"{0}\"", input);
                match.Finish();
            };

            //Ação customizada que será executada quando a partida for encerrada, 
            //ou seja, por tempo ou pela chamada do método Finish() e não pelo fechamento da Aplicação.
            match.OnMatchEnd += () => Console.WriteLine("Tchau!");

            match.Start();
        }
    }

    class Match
    {
        /// <summary>
        /// Tempo em segundos.
        /// </summary>
        public uint Time { get; private set; }
        /// <summary>
        /// Player atual
        /// </summary>
        public Player CurrentPlayer { get; private set; }
        /// <summary>
        /// Chamado quando o usuário escreve algo.
        /// </summary>
        public event Action<string> OnPlayerInput;
        /// <summary>
        /// Chamado quando a partida termina.
        /// </summary>
        public event Action OnMatchEnd;

        private AutoResetEvent _autoEvent;
        private TimerCallback _tick;
        private Timer _timer;
        private readonly Thread _matchThread;

        private const int AGORA = 0, SEGUNDO = 1000, MINUTO = 60000;

        /// <summary>
        /// Criar uma nova partida
        /// </summary>
        /// <param name="player">Jogador atual</param>
        /// <param name="time">Tempo da partida</param>
        public Match(Player player, uint time) {
            CurrentPlayer = player; 
            Time = time;

            _matchThread = new Thread(() =>
            {
                Console.WriteLine(">> {0} Escreva Algo (Nao Deixe Passar 10 Segundos): ", player.Name);
                On_PlayerInput(Console.ReadLine());
            });
        }

        /// <summary>
        /// Inicia a partida
        /// </summary>
        public void Start()
        {
            if (Time == 0)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Esta partida já foi encerrada.");
                Console.ForegroundColor = ConsoleColor.White;
                return;
            }

            Console.Clear();
            Console.ForegroundColor = ConsoleColor.White;

            // Usado para fazer com que o timer seja repetido.
            _autoEvent = new AutoResetEvent(false);
            // Callback do Timer
            _tick = Tick;
            // Timer disparado imediatamente e chamado a cada segundo
            _timer = new Timer(_tick, _autoEvent, AGORA, SEGUNDO);

            //Capturar do input do usuário
            _matchThread.Start();

            Console.WriteLine(">> Partida Iniciada.");
        }

        /// <summary>
        /// Termina a partida
        /// </summary>
        public void Finish()
        {
            _timer.Dispose();
            _autoEvent.Dispose();
            Time = 0;

            if (OnMatchEnd != null) OnMatchEnd();
            Console.WriteLine(">> Partida concluída.");
            Console.Read();
            _matchThread.Abort();
        }

        /// <summary>
        /// Chamado a cada segundo passado
        /// </summary>
        /// <param name="stateInfo"></param>
        private void Tick(Object stateInfo)
        {
            //Console.WriteLine(">> Tempo atual da partida: {0}s", Time);
            if (--Time == 0) Finish();
        }

        /// <summary>
        /// Chamado quando o usuário digitar um texto (após apertar Enter)
        /// </summary>
        /// <param name="input">Texto digitado</param>
        private void On_PlayerInput(string input)
        {
            //Console.WriteLine(">> Usuário escreveu: {0}", (CurrentPlayer.Input = input));
            if (OnPlayerInput != null) OnPlayerInput(input);
        }
    }

    class Player
    {
        /// <summary>
        /// Nome do jogador
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// Texto digitado pelo jogador
        /// </summary>
        public string Input { get; set; }

        public Player(string name) { Name = name; }
    }
}

1


I came back in the code and I realized I just changed the function void player() that worked exactly the way I wanted it to, so it went like this:

static void player()
{
    Console.Write("Player1 Escreva Algo (Nao Deixe Passar 10 Segundos): ");
    str += Console.ReadLine();
    Console.Write("\"{0}\"", str);
    t.Abort();
}

And I changed that too:

while (t.IsAlive);
if (player1.IsAlive) { player1.Abort(); Console.Write("\nSeu Tempo Acabou"); }

For that reason:

while (t.IsAlive);
System.Threading.Thread.Sleep(1);
if (player1.IsAlive) { player1.Abort(); Console.Write("\nSeu Tempo Acabou"); }

When it occurs t.Abort() in Thread player1 the while(t.IsAlive) of the main thread is closed.

'Cause when he comes out of while (t.IsAlive); and went to: if (player1.IsAlive) I don’t know why player1 was still alive even after crossing the line t.Abort(); there when it comes to if (player1.IsAlive) It validated as true, with player1 already over. Ai decided putting 1 millisecond between the while and the if.

But I also really liked the other answers, I put mine here just to show one more way out.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.