2012-05-14 3 views
2

좋습니다. 일반 프로그램 일종입니다. 사용자가 컴퓨터 플레이어와 상호 작용할 수있는 포커 프로그램을 작성하려고합니다. 그러나 그것을 단순화하기 위해 두 명의 플레이어가 컴퓨터에서 숫자를 추측하려고하는 훨씬 간단한 프로그램으로 테스트하고 있습니다. 하나는 인간 플레이어이고 다른 하나는 컴퓨터 플레이어입니다.사용자가 wpf에서 상호 작용할 수 있도록 프로그램을 일시 중지

게임에서 플레이어는 프로그램에서 설정 한 숫자를 추측합니다. 컴퓨터 플레이어는 숫자를 무작위로 추출합니다. 사용자가 숫자를 입력하고 추측 버튼을 누르거나 종료 옵션이 있어야합니다.

내 문제는 인간 플레이어가 행동하기 시작했을 때 버튼을 누르거나 텍스트를 입력하여 인간이 반응하도록하기 위해 게임의 종료를 일시 중지 할 수있는 방법입니다.

나는 타이머를 사용하여 시도하고 그것을 시작하고 스레드가 끝날 때까지 기다리는 것처럼 보이지만 그것은 여전히 ​​GUI를 고정시킵니다.

또한 백그라운드 작업자 스레드에서 GUI를 업데이트하기 위해 메시지를 보내려고했지만 다른 스레드의 GUI 요소에 액세스 할 수 없다는 오류가 발생합니다.

누구든지 이것을 구현하는 방법에 대한 제안이 있습니까?

실행 중에 GUI와 상호 작용하는 방법을 이해 했으므로이 프로그램은 완전한 프로그램이 아닙니다.

수의를 추측 클래스 :

public class NumberGuesser { 

    public Player HumanPlayer { get; private set; } 

    public Player ComputerPlayer { get; private set;} 

    private Player[] _players = new Player[2]; 

    private int _maxNumber = 20; 

    private bool _done = false; 

    private Random random; 

    public NumberGuesser() { 

     HumanPlayer = new HumanPlayer("Me"); 

     ComputerPlayer = new ComputerPlayer("HAL9000"); 

     _players[0] = HumanPlayer; 
     _players[1] = ComputerPlayer; 

     random = new Random((int) DateTime.Now.Ticks); 

    } 

    public void Play() { 

     var myNumber = random.Next(_maxNumber); 
     var index = 0; 
     while (!_done) { 

      var currentPlayer = _players[index]; 

      var guess = currentPlayer.Act(_maxNumber); 
      if (guess == myNumber) { 
       currentPlayer.Score++; 
      } 

      index = (1 + index)%2; 
     } 

    } 
} 

컴퓨터 플레이어 :

public class ComputerPlayer : Player { 

    private readonly Random _random = new Random((int)DateTime.Now.Ticks); 

    public ComputerPlayer(string name) : base(name) { 
    } 

    public override int Act(int max) { 

     return _random.Next(max); 

    } 
} 

인간의 선수 :

public class HumanPlayer : Player { 

    public HumanPlayer(string name) : base(name) { 

    } 

    public override int Act(int max) { 

     return UserGuess(); 

    } 

    private int UserGuess() { 


     return 0; 

    } 
} 

플레이어 클래스 :

public class Player { 
    public string Name { get; private set; } 
    public int Score { get; set; } 

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


    public virtual int Act(int max) { 
     // How should the human enter the guess here??? 
     return 0; 
    } 
} 

내 주요 창

<Window x:Class="GuessMyNumber.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="395" Width="728"> 
<Grid> 
    <Label Content="Guess my number!" Height="28" HorizontalAlignment="Left" Margin="122,58,0,0" Name="label1" VerticalAlignment="Top" /> 
    <Grid Height="174" HorizontalAlignment="Left" Margin="31,170,0,0" Name="grid1" VerticalAlignment="Top" Width="272" DataContext="{Binding Path=HumanPlayer}"> 
     <Label Content="Human player" Height="28" HorizontalAlignment="Left" Margin="6,6,0,0" Name="label2" VerticalAlignment="Top" /> 
     <TextBox Height="23" HorizontalAlignment="Left" Margin="55,92,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" 
       Text="{Binding Path=HumanGuess, UpdateSourceTrigger=PropertyChanged}"/> 
     <Button Content="Guess" Height="23" HorizontalAlignment="Left" Margin="79,130,0,0" Name="button1" VerticalAlignment="Top" Width="75" 
       Command="{Binding Path=GuessCommand}"/> 
     <Label Content="{Binding Path=Name}" Height="28" HorizontalAlignment="Left" Margin="96,6,0,0" Name="label3" VerticalAlignment="Top" /> 
     <Label Content="Score" Height="28" HorizontalAlignment="Left" Margin="6,40,0,0" Name="label4" VerticalAlignment="Top" /> 
     <TextBox Height="23" HorizontalAlignment="Left" Margin="55,42,0,0" Name="textBox2" VerticalAlignment="Top" Width="75" Text="{Binding Path=Score, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" /> 
     <Button Content="Quit" Height="23" HorizontalAlignment="Left" Margin="182,130,0,0" Name="buttonQuit" VerticalAlignment="Top" Width="75" Command="{Binding Path=QuitCommand}" /> 
    </Grid> 
    <Grid Height="174" HorizontalAlignment="Left" Margin="328,170,0,0" Name="grid2" VerticalAlignment="Top" Width="270" DataContext="{Binding Path=ComputerPlayer}" > 

     <Label Content="Computer player" Height="28" HorizontalAlignment="Left" Margin="6,6,0,0" VerticalAlignment="Top" /> 
     <TextBox Height="23" HorizontalAlignment="Left" Margin="55,92,0,0" VerticalAlignment="Top" Width="120" Text="{Binding Path=HumanGuess, UpdateSourceTrigger=PropertyChanged}"/> 

     <Label Content="{Binding Path=Name}" Height="28" HorizontalAlignment="Left" Margin="111,6,0,0" VerticalAlignment="Top" /> 
     <Label Content="Score" Height="28" HorizontalAlignment="Left" Margin="6,40,0,0" VerticalAlignment="Top" /> 
     <TextBox Height="23" HorizontalAlignment="Left" Margin="55,42,0,0" VerticalAlignment="Top" Width="75" Text="{Binding Path=Score, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" /> 
    </Grid> 
    <Button Content="Start Playing" Height="23" HorizontalAlignment="Left" Margin="254,59,0,0" Name="buttonStartPlay" VerticalAlignment="Top" Width="75" Click="buttonStartPlay_Click" /> 
</Grid> 

그리고 뒤에있는 코드 :

/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window { 

    private readonly NumberGuesser _numberGuesser; 

    public MainWindow() { 
     InitializeComponent(); 
     _numberGuesser = new NumberGuesser(); 
     DataContext = _numberGuesser; 

    } 

    private void buttonStartPlay_Click(object sender, RoutedEventArgs e) { 

     _numberGuesser.Play(); 

    } 

} 

답변

2

다른 관점에서 문제에 접근해야합니다. 사용자에게 로컬 컴퓨터와 상호 작용할 것처럼 행동하도록 사용자에게 요청하는 동 기적으로 실행되는 메서드를 갖는 대신 사용자가 요청한 것을 필요로하고 사용자가 완료되었음을 알리기 위해 무언가 (예 : 이벤트)를 비동기 적으로 기다려야합니다.

여기 얻을 수있는 무언가 (원격 컴퓨터의 무언가를 요구하는 더 유사)를 시작 :

public abstract class Player 
{ 
    public string Name { get; private set; } 
    public int Score { get; set; } 

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

    public abstract void ActAsync(int max); 

    public virtual event EventHandler<ActEventArgs> ActComplete; 
} 
public class ActEventArgs : EventArgs 
{ 
    public int Result { get; private set; } 
    public ActEventArgs(int result) 
    { 
     this.Result = result; 
    } 
} 
public class HumanPlayer : Player 
{ 
    public HumanPlayer(string name) 
     : base(name) 
    { 
    } 

    public override void ActAsync(int max) 
    { 
     // button1 should be the user's guess button; anything else you need to do to allow them to interact should be done here 
     button1.IsEnabled = true; 
     // this will result in a handler being added each time the user is asked to act; you'll actually want to attach just once 
     button1.Click += (s, e) => 
      { 
       button1.IsEnabled = false; 
       if (ActComplete != null) 
        ActComplete(this, new ActEventArgs(int.Parse(data.HumanGuess))); // data.HumanGuess is their input, as a string 
      }; 
    } 

    public override event EventHandler<ActEventArgs> ActComplete; 
} 
public class ComputerPlayer : Player 
{ 
    private readonly Random _random = new Random((int)DateTime.Now.Ticks); 

    public ComputerPlayer(string name) 
     : base(name) 
    { 
    } 

    public override void ActAsync(int max) 
    { 
     if (ActComplete != null) 
      ActComplete(this, new ActEventArgs(_random.Next(max))); 
    } 
    public override event EventHandler<ActEventArgs> ActComplete; 
} 

편집 : 자신의 간단한 상호 작용에 대한 더 나은, 즉 로컬 사용자 : Jmyster의 솔루션 (IMHO)에 비해 로컬 컴퓨터까지 확장 할 수 있지만 다중 사용자 시나리오로 확장하려는 경우 이벤트가 개선 될 것입니다.

+0

좋습니다. 감사합니다. GuessNumber 클래스의 내 play 함수에서 ActAsync를 어떻게 호출합니까? – Ergodyne

+0

'player.ActCompleted + = SomeHandler; player.ActAsync (최대);' –

1

내가 루프가 게임을 플레이하는 동안 것을 사용하지 않을 것입니다. 나는 이런 식으로 뭔가를 할 거라고 :

private int numberToGuess = 0; 

private void buttonStartPlay_Click(object sender, RoutedEventArgs e) 
{   
    numberToGuess = //Create Random Int; 
} 

private void buttonHumanGuess_Click(object sender, RoutedEventArgs e) 
{   
    if(IsAnswerCorrect(//HumanGuess)) 
     //Human Wins 
    else 
     ComputerGuess(); 
     //Or 
     MoveToNextPlayer(); 
} 

private void MoveToNextPlayer() 
{ 
    //Do something to figure out who the next player is 
} 

private int ComputerGuess() 
{ 
    //Do something to get computer answer 
    if(IsAnswerCorrect(//ComputerGuess)) 
     //Computer Wins 
} 

private bool IsAnswerCorrect(int answer) 
{ 
    if(answer == numberToGuess) 
     return true; 
    else 
     return false; 
} 

이것은 매우 일반적인하지만 아이디어는 입력 뭔가 사용자위한 다음 추측 버튼을 클릭합니다. 응답을 처리 한 후 컴퓨터를 실행합니다.

편집 : @Tim s. 솔루션은보다 진보 된 방법을 처리 할 수 ​​있습니다. 타이머가 득점에 포함되는지 여부에 따라 스레딩을 사용해야 할 수도 있습니다. 이것들이 당신을위한 출발점이되어야합니다.

관련 문제