C# :: Aufgabe #193

2 Lösungen Lösungen öffentlich

Onkel Otto sitzt in der Badewanne

Profi - C# von Kath - 16.11.2017 um 15:26 Uhr
Schreibe ein Programm, welches das Spiel "Onkel Otto sitzt in der Badewanne" simuliert. Dabei geht es darum, dass jeder der Spieler ein gefaltetes Blatt mit 6 aufgezeichnete Spalten vor sich hat und in einer etwas eintragen muss. Danach wird das Blatt weitergereicht und der nächste Spieler füllt die nächste Spalte aus, solange bis keine mehr frei ist; dann werden die enstandenen Sätze vorgelesen.

Zur Vereinfachung kann jeder Spieler jeweils nacheinander ein Wort eingeben in seinem Client. Die eingegebenen Worte sollen an einen Server geschickt, dem jeweiligen Spiel ( jedes gestartete Spiel soll einen anderen Namen bekommen ) zugeordnet und anschließend die vollständigen Sätze an alle Clients zurückschicken, die an dem jeweiligen Spiel teilgenommen haben.

Designvorschlag für Homescreen: siehe Anhang

Aufgabe: Schreibe den Code für den Client und für den Server!

Lösungen:

vote_ok
von hollst (13980 Punkte) - 03.12.2017 um 17:23 Uhr
Quellcode ausblenden C#-Code
using System;
using System.Windows;
using System.Windows.Controls;

namespace onkel_otto_aufgabe_193
{
    public partial class MainWindow : Window
    {
        static string NL = Environment.NewLine;

        public MainWindow()
        {
            InitializeComponent();
            this.TBox_Regeln.Text = string_regeln;
            init_tb_content();
            this.Label0.Content = string_lable_content[0];
            this.Label1.Content = string_lable_content[1];
            this.Label2.Content = string_lable_content[2];
            this.Label3.Content = string_lable_content[3];            
        }

        string[] string_tb_content = new string[5];
        static TextBox[] tb = new TextBox[5];

        void init_tb_content()
        {
            string_tb_content = new string[5];
            tb[0] = this.textBox0;
            tb[1] = this.textBox1;
            tb[2] = this.textBox2;
            tb[3] = this.textBox3;
            tb[4] = this.textBoxResult;
            tb_index = 0;
            for (var i = 0; i < tb.Length; i++)
            {
                tb[i].Text = string.Empty;
                string_tb_content[i] = string.Empty;
                if (i != tb_index)
                    tb[i].Visibility = Visibility.Hidden;
                else
                    tb[i].Visibility = Visibility.Visible;
            }
            bt_neues_spiel.IsEnabled = false;
            bt_aufloesen.IsEnabled = false;
            tb[tb_index].Focus();
        }

        string string_regeln = NL +
            "Es gibt mindestens zwei Spieler, am besten vier." + NL + NL +
            "Der erste schreibt ins erste Textfeld ein (vielleicht auch zusammengesetztes) Subjekt, z. B." + NL +
            "\"Onkel Otto\"" + NL +
            "dann drückt er den nächstes-wort-BUTTON, das Spiel geht an Spieler #2 über." + NL + NL +
            "Dieser schreibt in sein Textfeld ein gebeugtes Verb (z. B. \"plätschert\") und drückt anschließend ebenfalls den " +
            "nächstes-wort-BUTTON." + NL + NL +
            "Es geht weiter mit einem Prädikat (z. B. \"lustig\"), anschließend wieder nächstes-wort-BUTTON." + NL + NL +
            "Abschließend kommt ein (ev. auch zusammengesetztes) Objektiv, wie z. B. \"in der Badewanne\"." + NL + NL + NL +
            "Wichtig ist, dass kein Spieler sehen kann, was ein anderer geschrieben hat." + NL + NL + NL +
            "Mit dem auflösen-BUTTON wird der so konstruierte und oft recht komische Satz allen angezeigt.";

        string[] string_lable_content = new string[]
        {
            "SUBJEKT"          + NL + NL + "z. B.:" + NL + NL + "Onkel Otto" + NL + "Tante Emma" + NL + "Harry" + NL +"...",
            "(gebeugtes) VERB" + NL + NL + "z. B.:" + NL + NL + "plätschert" + NL + "durchquert" + NL + "...",
            "PRÄDIKAT"         + NL + NL + "z. B.:" + NL + NL + "lustig" + NL + "gestresst" + NL + "...",
            "OBJEKT"           + NL + NL + "z. B.:" + NL + NL + "in der Badewanne" + NL + "beim Hasen" + NL + "..."
        };

        int tb_index = 0;

        private void bt_neues_spiel_Click(object sender, RoutedEventArgs e) 
        {
            init_tb_content();
            this.bt_neues_spiel.IsEnabled = false;
            this.bt_aufloesen.IsEnabled = false;
            this.bt_naechstes_wort.IsEnabled = true;
        }

        private void bt_naechstes_wort_Click(object sender, RoutedEventArgs e)
        {
            if ((tb_index < tb.Length - 1) && (string_tb_content[tb_index] != string.Empty))
            {
                string string_end = " ";
                if (tb_index == string_tb_content.Length - 2)
                    string_end = ".";

                string_tb_content[string_tb_content.Length - 1] += string_tb_content[tb_index] + string_end;

                tb_index++;
                for (var i = 0; i < tb.Length - 1; i++)
                {
                    if (i != tb_index)
                        tb[i].Visibility = Visibility.Hidden;
                    else
                        tb[i].Visibility = Visibility.Visible;
                }
                tb[tb_index].Focus();
                if (tb_index < tb.Length - 1)
                {
                    this.bt_neues_spiel.IsEnabled = false;
                    this.bt_aufloesen.IsEnabled = false;
                }
                else
                {
                    this.bt_aufloesen.IsEnabled = true;
                    this.bt_naechstes_wort.IsEnabled = false;
                }
                return;
            }
            MessageBox.Show("es ist nichts eingetragen!");
            tb[tb_index].Focus();
        }

        private void textBox0_LostFocus(object sender, RoutedEventArgs e)
        {
            string_tb_content[tb_index] = tb[tb_index].Text;
        }

        private void bt_aufloesen_Click(object sender, RoutedEventArgs e)
        {          
            tb[tb.Length - 1].Text = string_tb_content[string_tb_content.Length - 1];
            tb[tb.Length - 1].Visibility = Visibility.Visible;
            this.bt_neues_spiel.IsEnabled = true;
        }
    }
}


Quellcode ausblenden C#-Code
<Window x:Class="onkel_otto_aufgabe_193.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:onkel_otto_aufgabe_193"
        mc:Ignorable="d"
        Title="Onkel Otto" Height="400" Width="800" FontFamily="Courier New" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
    <Grid>
        <TabControl x:Name="tabControl" Margin="-1,0,0,0" TabStripPlacement="Bottom">
            <TabItem Header=" spiel ">
                <Grid Background="#FFE5E5E5">

                    <Grid.RowDefinitions>
                        <RowDefinition Height="150"/>
                        <RowDefinition Height="25"/>
                        <RowDefinition Height="80"/>
                        <RowDefinition Height="80"/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>

                    <Grid x:Name="grid2" Margin="0,0,10,0" Grid.Row="0">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="1*"/>
                            <ColumnDefinition Width="1*"/>
                            <ColumnDefinition Width="1*"/>
                            <ColumnDefinition Width="1*"/>
                        </Grid.ColumnDefinitions>
                        <Label x:Name="Label0"   Grid.Column="0"  Margin="10,20,0,0" />
                        <Label x:Name="Label1"   Grid.Column="1"  Margin=" 5,20,0,0" />
                        <Label x:Name="Label2"   Grid.Column="2"  Margin="5,79,0,-59" />
                        <Label x:Name="Label3"   Grid.Column="3"  Margin=" 5,20,0,0" />
                    </Grid>

                    <Grid x:Name="grid1" Margin="0,0,10,0" Grid.Row="1">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="1*"/>
                            <ColumnDefinition Width="1*"/>
                            <ColumnDefinition Width="1*"/>
                            <ColumnDefinition Width="1*"/>
                        </Grid.ColumnDefinitions>
                        <TextBox x:Name="textBox0" Margin="10,0,0,0"  Grid.Column="0" TextWrapping="Wrap" Text="TextBox" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Height="28" LostFocus="textBox0_LostFocus" FontWeight="Bold"/>
                        <TextBox x:Name="textBox1" Height="28"  Grid.Column="1" TextWrapping="Wrap" Text="TextBox" Margin="5,0,0,0" LostFocus="textBox0_LostFocus" FontWeight="Bold"/>
                        <TextBox x:Name="textBox2" Height="28"  Grid.Column="2" TextWrapping="Wrap" Text="TextBox" Margin="5,0,0,0" LostFocus="textBox0_LostFocus" FontWeight="Bold"/>
                        <TextBox x:Name="textBox3" Height="28"  Grid.Column="3" TextWrapping="Wrap" Text="TextBox" Margin="5,0,0,0" LostFocus="textBox0_LostFocus" FontWeight="Bold"/>
                    </Grid>

                    <StackPanel Height="32" Margin="10,25,0,0" Grid.Row="2" Width="492" Orientation="Horizontal">
                        <Button x:Name="bt_neues_spiel" Content=" neues spiel " Margin="5" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Center" VerticalAlignment="Center" Click="bt_neues_spiel_Click"/>
                        <Button x:Name="bt_naechstes_wort" Content=" nächstes wort " Margin="50,5,5,5" Padding="1" VerticalContentAlignment="Center" HorizontalContentAlignment="Left" HorizontalAlignment="Center" VerticalAlignment="Center" Click="bt_naechstes_wort_Click"/>
                        <Button x:Name="bt_aufloesen" Content=" auflösen " Margin="50,5,5,5" Padding="1" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" HorizontalAlignment="Center" VerticalAlignment="Center" Click="bt_aufloesen_Click"/>
                    </StackPanel>
                    <TextBox x:Name="textBoxResult" Margin="10,10,10,3" Grid.Row="3" TextWrapping="Wrap" Height="28" FontWeight="Bold" FontSize="24" FontStyle="Italic"/>

                </Grid>
            </TabItem>
            <TabItem Header=" regeln ">
                <Grid Background="#FFE5E5E5">
                    <TextBox x:Name="TBox_Regeln" Margin="5" TextWrapping="Wrap" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"/>
                </Grid>
            </TabItem>
        </TabControl>
    </Grid>
</Window>
vote_ok
von Mexx (2370 Punkte) - 14.12.2017 um 20:23 Uhr
Hi, habe mich auch mal versucht. Zur Umsetzung wurde ein WCF-Service genutzt. Die Implementierung ist sehr spartanisch gehalten (keine Fehlerbehandlung o. ä., ebenso wurden keine Sicherheitsaspekte beachtet...), aber das Programm tut was es soll. xD

Server:

Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Threading;

namespace Server
{
    class Program
    {
        /// <summary>
        /// Der Dienst, welcher die öffentlichen Serverfunktionen für die Clients bereit stellt
        /// </summary>
        static ServiceHost service;

        /// <summary>
        /// Startnachricht des Servers
        /// </summary>
        const string startMessage = "Willkommen... \nGeben Sie die auszuführenden Befehle ein. " +
            "Geben Sie help ein um eine Liste der möglichen Befehle anzuzeigen";

        /// <summary>
        /// Liste der ausführbaren Befehle
        /// </summary>
        const string commandList = "Übersicht der aufrubaren Befehle: \n" +
            "exit \tBeendet das Programm \n" +
            "help \tZeigt die möglichen Befehle an \n" +
            "start \tStartet den Service \n" +
            "stop \tBeendet den Service \n";

        static Thread thr = new Thread(new ThreadStart(Refresh));

        static void Main(string[] args)
        {
            Console.WriteLine(startMessage);
            StartService();
            thr.Start();

            while (true)
            {
                switch (Console.ReadLine())
                {
                    case "exit":
                        Console.WriteLine("Server wird beendet...");
                        Environment.Exit(0);
                        break;
                    case "help":
                        Console.WriteLine(commandList);
                        break;
                    case "start":
                        StartService();
                        break;
                    case "stop":
                        CloseService();
                        break;
                    default:
                        Console.WriteLine("\nDer Befehl konnte nicht gefunden werden");
                        break;
                }
            }
        }

        /// <summary>
        /// Startet den Dienst, welcher die öffentlichen Serverfunktionen für die Clients bereit stellt
        /// </summary>
        static void StartService()
        {
            if (service == null || service.State == CommunicationState.Closed)
            {
                service = new ServiceHost(typeof(Server));
                Uri baseAddress = new Uri("net.tcp://localhost:8999/MyService");
                NetTcpBinding binding = new NetTcpBinding();
                service.AddServiceEndpoint(typeof(IServer), binding, baseAddress);

                try
                {
                    service.Open();
                    Console.WriteLine("Service wurde gestartet.");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Service konnte nicht gestartet werden. \n\n" + ex.ToString());
                }
            }
            else
            {
                Console.WriteLine("Service wurde bereits gestartet.");
            }
        }

        /// <summary>
        /// Beendet den Dienst, welcher die öffentlichen Serverfunktionen für die Clients bereit stellt
        /// </summary>
        static void CloseService()
        {
            if (service == null)
            {
                Console.WriteLine("Der Dienst ist nicht gestartet");
            }
            else
            {
                Console.WriteLine("Der Dienst wird beendet...");
                service.Close();
                Console.WriteLine("Der Dienst wurde beendet");
            }
        }

        static void Refresh()
        {
            while (true)
            {
                Server.RefreshClients();
                Thread.Sleep(2000);
            }
        }
    }

    /// <summary>
    /// Stellt die Funktionen, die auf dem Host zur Verfügung stehen bereit.
    /// </summary>
    [ServiceContract(CallbackContract = typeof(IClient))]
    public interface IServer
    {
        /// <summary>
        /// Erstellt eine neue Gruppe
        /// </summary>
        /// <param name="groupName">Der Name der Gruppe</param>
        /// <param name="userID">Die ID des Users, der die Gruppe erstellt</param>
        /// <returns>True wenn erfolgreich, ansonsten false</returns>
        [OperationContract]
        bool CreateGroup(string groupName, int userID);

        /// <summary>
        /// Tritt einer bestehenden Gruppe bei
        /// </summary>
        /// <param name="userID">Die ID des Users</param>
        /// <param name="groupName">Der Gruppenname</param>
        /// <returns>True wenn erfolgreich, ansonsten false</returns>
        [OperationContract]
        bool JoinGroup(int userID, String groupName);

        /// <summary>
        /// Verbindet einen Client mit dem Server und gibt bei erfolgreicher Registrierung eine UserID zurück.
        /// </summary>
        /// <returns>Bei erfolg eine Userid, ansonten 0</returns>
        [OperationContract]
        int Connect();

        [OperationContract]
        object SendWordToGroup(int userID, string groupName, string word);
    }

    public class Server : IServer
    {
        static List<KeyValuePair<int, IClient>> userList = new List<KeyValuePair<int, IClient>>();
        static List<Group> groupList = new List<Group>();
        static Random ran = new Random();
        static KeyValuePair<int, IClient> EmptyUser;        

        public bool CreateGroup(string groupName, int userID)
        {
            Group g = new Group(groupName, GetUser(userID));
            if (groupList.Contains(g))
                return false;
            
            groupList.Add(g);
            return true;
        }

        public static void RefreshClients()
        {
            List<string> gruppen = new List<string>();
            foreach (var group in groupList)
                gruppen.Add(group.Name);

            try
            {
                //Liste der aktiven Gruppen auf den Clients aktualisieren
                foreach (var user in userList)
                    user.Value.SetGroupList(gruppen.ToArray());

                foreach (var v in groupList)
                    if (v.Ready)
                    {
                        foreach (var user in v.Member)
                            user.Value.SendMessage(v.ToString());
                        groupList.Remove(v);
                    }
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("{0}: Fehler beim aktualieren der Gruppen\n{1}\n", DateTime.Now, ex.Message));
            }
        }

        public bool JoinGroup(int userID, string groupName)
        {
            foreach (var g in groupList)
                if (g.Name == groupName)
                    if (g.JoinGroup(GetUser(userID)))
                        return true;
            return false;
        }

        public object SendWordToGroup(int userID, string groupName, string word)
        {
            foreach (var g in groupList)
                if (g.Name == groupName)
                    foreach (var u in g.Member)
                        if (u.Key == userID)
                            if (g.SendWord(word))
                                return true;
            return false;
        }

        public int Connect()
        {
            IClient callback = OperationContext.Current.GetCallbackChannel<IClient>();
            KeyValuePair<int, IClient> user;
            while (userList.Contains((user = new KeyValuePair<int, IClient>(ran.Next(1000000, int.MaxValue), callback))));
            userList.Add(user);
            Console.WriteLine(string.Format("Client {0} hat sich Registriert", user.Key));
            return user.Key;
        }

        private KeyValuePair<int, IClient> GetUser(int userID)
        {
            foreach (var v in userList)
                if (v.Key == userID)
                    return v;
            return EmptyUser;
        }
    }

    /// <summary>
    /// Stellt die Funktionen, die auf den Clients zur Verfügung stehen bereit.
    /// </summary>
    public interface IClient
    {
        /// <summary>
        /// Sendet eine Nachricht an den Client
        /// </summary>
        /// <param name="msg">Der Text der Nachricht</param>
        [OperationContract()]
        void SendMessage(string msg);

        /// <summary>
        /// Aktualisiert die Liste der aktiven Gruppen
        /// </summary>
        /// <param name="groups">Die Gruppennamen</param>
        [OperationContract()]
        void SetGroupList(string[] groups);
    }

    class Group
    {
        string name;
        static List<KeyValuePair<int, IClient>> member;
        static List<string> words;
        static bool ready = false;

        public List<KeyValuePair<int, IClient>> Member
        {
            get { return member; }
        }

        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }

        public bool Ready
        {
            get { return ready; }
        }

        public Group(string name, KeyValuePair<int, IClient> user)
        {
            Name = name;
            words = new List<string>();
            member = new List<KeyValuePair<int, IClient>>(6);
            member.Add(user);
        }

        public bool JoinGroup(KeyValuePair<int, IClient> user)
        {
            if (!(member.Count < 6) || member.Contains(user))
                return false;
            member.Add(user);
            return true;
        }

        public bool SendWord(string word)
        {
            words.Add(word);
            if (words.Count == 6)
                ready = true;
            return true;
        }

        public override string ToString()
        {
            string result = string.Empty;
            foreach (string s in words)
                result += s + " ";
            return result;
        }
    }
}



Client:
Quellcode ausblenden C#-Code
using System;
using System.Windows.Forms;
using System.ServiceModel;
using Server;

namespace Client
{
    public partial class Form1 : Form, IClient
    {
        static IServer service = null;
        static int userID = 0;

        public Form1()
        {
            InitializeComponent();

            Connect();
        }
                
        bool Connect()
        {
            Uri baseAddress = new Uri("net.tcp://localhost:8999/MyService");
            EndpointAddress address = new EndpointAddress(baseAddress);
            NetTcpBinding binding = new NetTcpBinding();
            DuplexChannelFactory<IServer> factory = new DuplexChannelFactory<IServer>(this, binding, address);

            try
            {
                service = factory.CreateChannel();
                userID = service.Connect();
            }
            catch (Exception ex)
            {
                return false;
            }

            if (userID != 0)
                return true;
            return false;
        }

        public void SendMessage(string msg)
        {
            rtbOutput.Text += string.Format("\n{0}\n", msg);
        }

        /// <summary>
        /// Aktualisiert die Liste der aktiven Gruppen
        /// </summary>
        /// <param name="groups">Die Gruppennamen</param>
        public void SetGroupList(string[] groups)
        {
            string selected = string.Empty;
            if (lbGroups.SelectedItems.Count > 0)
                selected = lbGroups.SelectedItem.ToString();
            lbGroups.Items.Clear();
            foreach (string s in groups)
            {
                lbGroups.Items.Add(s);
                if (selected != string.Empty)
                    if (s == selected)
                        lbGroups.SetSelected(lbGroups.Items.Count - 1, true);
            }
        }

        private void btnCreateGroup_Click(object sender, EventArgs e)
        {
            if (tbGroupName.Text == "")
            {
                rtbOutput.Text += "Sie müssen einen Gruppennamen eingeben.\n";
                return;
            }
            if (!service.CreateGroup(tbGroupName.Text, userID))
                rtbOutput.Text += "Gruppe konnte nicht erstellt werden. Versuche einen anderen Gruppennamen\n";

            lbGroups.Items.Add(tbGroupName.Text);
            rtbOutput.Text += "Gruppe wurde erstellt";
        }

        private void lbGroups_DoubleClick(object sender, EventArgs e)
        {
            var lb = sender as ListBox;
            if (lb.SelectedItem == null)
                return;

            string group = lb.SelectedItem.ToString();
            if (!service.JoinGroup(userID, group))
                rtbOutput.Text += string.Format("Fehler beim joinen in Gruppe {0}\n", group);
            rtbOutput.Text += string.Format("Du bist der Gruppe {0} beigetreten\n", group);
        }

        private void btnSenden_Click(object sender, EventArgs e)
        {
            object result = null;
            if (!(tbMessage.Text == string.Empty))
            {
                if (lbGroups.SelectedItem == null)
                {
                    rtbOutput.Text += "Du musst eine Gruppe wählen\n";
                    return;
                }

                result = service.SendWordToGroup(userID, lbGroups.SelectedItem.ToString(), tbMessage.Text);
                if (result is bool)
                    if ((bool)result)
                    {
                        rtbOutput.Text += string.Format("Wort \"{0}\" erfolgreich gesendet", tbMessage.Text);
                        return;
                    }
                    else
                    {
                        rtbOutput.Text += "Senden fehlgeschlagen";
                        return;
                    }
                else
                {
                    string[] words = (string[])result;
                }
            }
            rtbOutput.Text += "Gib ein Wort ein\n";
        }
    }
}