2016-11-05 5 views
1

現在、コンソールゲームを作成しようとしています。基本的な考え方は、ユーザーが多数のランダムな文字を取得し、これらの文字を可能な限り多くの単語にする時間が限られていることです。たとえば、有効な単語が「取得」、「取得」、「テスト」などである場合、ユーザーは[a、a、c、t、t、e、g、s、o、i]ユーザーの入力は、単語リストに存在するかどうか、およびそれが使用が許可されている文字で構成されているかどうかでチェックされます。残念ながら、このゲームのタイマーを実装して表示しようとするといくつかの問題があります。C# - ReadLine()を通じてユーザー入力のコンソールにカウントダウンタイマーを表示

注:私の初心者なので、私のC#の知識は非常に限られています。私はReadLineメソッド()関数でループが含まれているバックグラウンドスレッドを持っている瞬間

問題

。 「通常の」コードは、Sleep()関数で一時停止し、時間が経過すると続行されます。 hereに与えられた解決策に大いに触発されています。私が達成しようとしているのは、コンソールにタイマーを表示することです。これは、ユーザーが単語を何秒間入力するかを示します。しかし、私はこれを達成する方法を考え出していません。

次の理由により、私は解決策を検討することができません。 「通常の」コードが一時停止した後、ユーザー入力を求めるループを含むスレッドが中断することなくアクティブになるため、タイマーワードが存在する理由。これは、タイマーが印刷されるような中断がないことを意味します。私は、その機能を維持しながら、readline関数を定期的に「一時停止」する方法を知らない。

あなたに私の質問がありますが、これをどのように達成できますか?

コード

これは単に、この機能を含む単離されたコードの一部です。したがって、これらの単語は要件を満たしているかどうかについてはテストされません。

using System; 
using System.Collections.Generic; 
using System.Threading; 

namespace UnderstandingThreading 
{ 

    class Reader 
    { 
     private static Thread inputThread; 
     private static List<string> userInput = new List<string>(); 
     private static bool closeLoop = new bool(); 

     static Reader() 
     { 
      inputThread = new Thread(reader); 
      closeLoop = false; 
      inputThread.IsBackground = true; 
      inputThread.Start(); 
     } 

     private static void reader() 
     { 
      while (!closeLoop) 
      { 
       userInput.Add(Console.ReadLine()); 
      } 
     } 

     public static List<string> ReadLine(int timeOutMilliseconds) 
     { 
      Thread.Sleep(timeOutMilliseconds); 
      closeLoop = true; 
      return userInput; 
     } 
    } 


    class MainClass 
    { 
     public static void Main(string[] args) 
     { 
      List<string> allEntries = new List<string>(); 
      Console.WriteLine("Please enter random things for the next 5 seconds"); 
      allEntries = Reader.ReadLine(5000); 

      for (int i = 0; i < allEntries.Count; i++) 
      { 
       Console.WriteLine(allEntries[i]); 
      } 

     } 
    } 
} 

Sebastiaan

答えて

0

、ありがとう、私は)(Task.Delayを使用して、問題の解決策を見つけました。 基本的には、秒間にできるだけ多くのタスクを作成し、前のタスクより1秒以上待つようにします。タスクが完了すると、WriteTimeLeft()関数が呼び出されます。この関数は時間を正しく表示し、ユーザーが答えを入力させるようにします(時間を表示した行を消去し、新しい時間で置き換えてカーソルを戻しますそれがあった場所)。この目的のために、定数「遅延」と変数「time_left」を追加しました。このアクションは本当に速いように、ユーザはinteruption :)なしで入力することができます

私はコードがundertandableであると信じていますが、どんな質問がある場合私は(これは完璧ではありません:)

お気軽にお問い合わせくださいないのC#の専門家)が、それはあなたが何を求めてやる;)

class MainClass 
{ 
    private static int delay { get; set; } 
    private static int time_left { get; set; } 

    public static void Main(string[] args) 
    { 

     delay = 10; 
     time_left = delay; 

     List<string> allEntries = new List<string>(); 
     Console.WriteLine("Please enter random things for the next 10 seconds"); 
     Console.SetCursorPosition(0, 2); 
     Timer(); 
     allEntries = Reader.ReadLine(11000); 

     for (int i = 0; i < allEntries.Count; i++) 
     { 
      Console.WriteLine(allEntries[i]); 
     } 
     Console.Read(); 
    } 

    public static void Timer() 
    { 
     for (int i = 11; i > 0; i--) 
     { 
      var t = Task.Delay(i*1000).ContinueWith(_ => WriteTimeLeft()); 
     } 
    } 

    public static void WriteTimeLeft() 
    { 
     int currentLineCursorTop = Console.CursorTop; 
     int currentLineCursorLeft = Console.CursorLeft; 
     Console.CursorVisible = false; 
     Console.SetCursorPosition(0, 1); 
     Console.Write(new string(' ', Console.WindowWidth)); 
     Console.SetCursorPosition(0, 1); 
     Console.Write(time_left); 
     Console.SetCursorPosition(currentLineCursorLeft, currentLineCursorTop); 
     Console.CursorVisible = true; 
     time_left -= 1; 
    } 
} 
+0

ありがとう!それは素晴らしい仕事だと思われる!コードを理解するのに少し時間を費やしています。また、最後のコードブロックで最後の行に2番目の間違いがあるようです。 'Console.CursorVisible = true; currentLineCursorTopをコードする必要があります。 'be 'コードConsole.CursorVisible = true; '? – Fluous

+0

ちょっと@Luc、私はあなたのコードに関して1つの質問があります。この行では、 'var t = Task.Delay(i * 1000).ContinueWith(_ => WriteTimeLeft());'ラムダ式を使用します。私はなぜここでラムダを使用するのか、なぜ "_"が渡されるのかは分かりません。あなたは説明したいですか?ありがとうございました! – Fluous

+0

Hey @SebastiaanThuis、Console.CursorVisibleの行についてはまったく正しいですが、私は自分のコピー/パスを駄目にしています、それは修正されました) ラムダ式を使用すると、ContinueWithメソッドをパラメータとしてActionを取る必要があります。新しいアクションを作成するための最良の方法は、ラムダを使用することです。あなたのメソッドがパラメータを取っていないときにはコンベンションであるので、私は入れて、下線を引いています。あなたも見ることができます:()=> ... 詳細についてはこちらをご覧ください: - http://stackoverflow.com/questions/ 1382950/confusion-over-action-delegate-and-lambda-expressions –

1

実際に私が行う方法のより良い方法を発見し、実装すると理解することがはるかに容易になります。単純にSystem.Timers.Timerクラスを使用します。

class MainClass 
{ 
    private static int delay { get; set; } 
    private static int time_left { get; set; } 

    public static void Main(string[] args) 
    { 

     delay = 8; 
     time_left = delay; 

     List<string> allEntries = new List<string>(); 
     Console.WriteLine("Please enter random things for the next 5 seconds"); 
     Console.SetCursorPosition(0, 2); 

     System.Timers.Timer Timer = new System.Timers.Timer(1000); 
     Timer.Elapsed += WriteTimeLeft; 
     Timer.AutoReset = true; 
     Timer.Enabled = true; 
     Timer.Start(); 

     allEntries = Reader.ReadLine(10000); 
     Timer.Stop(); 

     for (int i = 0; i < allEntries.Count; i++) 
     { 
      Console.WriteLine(allEntries[i]); 
     } 
     Console.Read(); 
    } 

    public static void WriteTimeLeft(Object source, ElapsedEventArgs e) 
    { 
     int currentLineCursorTop = Console.CursorTop; 
     int currentLineCursorLeft = Console.CursorLeft; 
     Console.CursorVisible = false; 
     Console.SetCursorPosition(0, 1); 
     Console.Write(new string(' ', Console.WindowWidth)); 
     Console.SetCursorPosition(0, 1); 
     Console.Write(time_left); 
     Console.SetCursorPosition(currentLineCursorLeft, currentLineCursorTop); 
     Console.CursorVisible = true; 
     time_left -= 1; 
    } 

基本的に、我々は1000ミリ秒のインターバルを持っているタイマーを設定し、我々はそれがアクティブになったときので、それはイベントに各秒を発射します、自動リセットとして設定します。メソッドのリストに、カスタムメソッドWriteTimeLeft(Object source、ElapsedEventArgs e)を追加するだけで、私たちは行こうとしています! :)

関連する問題