Esempio n. 1
0
class MultiplayerServerClass(NetworkPacketClass, CardDeckClass):

    def __init__(self, ip_port, game_rules):
        self.server_data = dict.copy(self.get_network_packet_definition())
        self.setup_game_rules_to_server_data(game_rules)
        self._dealer = DealerClass(data=self.server_data)
        self.mutex = QMutex()
        self.conn_player_number = 0
        self.conn_players_addresses = [0 for x in range(MAX_CLIENTS)]
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            self.s.bind(ip_port)
        except socket.error as e:
            str(e)
        self.s.listen(MAX_CLIENTS)
        print("Server Started... Waiting for a connection")
        thread = threading.Thread(target=self.server_listening_for_new_connections_loop, args=())
        thread.start()

    def server_listening_for_new_connections_loop(self):
        while True:
            conn, addr = self.s.accept()
            self.conn_players_addresses[self.conn_player_number] = addr  # save the connected player info
            print(f'SERVER: New Connection Established. Client (C{self.conn_player_number}) from {self.conn_players_addresses[CLIENT_SRV]}.')
            thread = threading.Thread(target=self.main_communication_loop, args=(conn, self.conn_player_number))
            thread.start()
            self.conn_player_number += 1
            print(f'SERVER: Active connections: {self.conn_player_number}. ')

    def main_communication_loop(self, conn, client_number):
        # Handshake message
        send_simple_message(conn, client_number)
        connected = True
        while connected:
            try:
                # We send 2 messages between client-server.
                # First we find the size of the dictionary we want to send, and tell the server to receive that size.
                # Second we send the dictionary in string format.
                client_data = receive_message_with_size_confirmation(conn)
                client_data = transform_into_data(client_data)

                while True:
                    # Try to access Server Data (Thread-Safe)
                    if self.mutex.tryLock():

                        # Are we still connected to this player?
                        if client_data:
                            self.server_data[client_number][PS_ConnectionStatus] = CONN_STATUS_CONNECTED
                        else:
                            self.server_data[client_number][PS_ConnectionStatus] = CONN_STATUS_DISCONNECTED

                        # Copy the clients data onto the server data.
                        self.server_update_from_this_player_data_fields(client_data=client_data, client_id=client_number)

                        if client_number == CLIENT_SRV:
                            # The server should theoretically loop through communication with all clients
                            # So if we do the dealer logic only on player0 (DEALER) then we should theoretically
                            # do the dealer logic only once per update to all other clients.

                            self._dealer.dealer_evaluate_next_step()

                        # Send the updated info back to the client:
                        server_reply = transform_into_string(self.server_data)

                        # Unlock the server_data_dict for other threads.
                        self.mutex.unlock()
                        break
                if connected:
                    send_message_with_size_confirmation(conn, server_reply)
                print(f'SERVER: Communication done for C{client_number}.')

            except socket.error as e:
                print(f'SERVER: main_communication_loop -> {e}')
                send_message_with_size_confirmation(conn, MESSAGE_DISCONNECTED)
                self.conn_player_number -= 1
                conn.close()
                break

    def setup_game_rules_to_server_data(self, rules):
        # 0 gameName = self._win.getGameName()
        # 1 startingMoney = self._win.getStartingAmount()
        # 2 currency = self._win.getCurrency()
        # 3 bigBlind = self._win.getBigBlind()
        # 4 blindInterval = self._win.getBlindInterval()
        # tpl = (gameName, startingMoney, currency, bigBlind, blindInterval)
        for player in range(MAX_CLIENTS):
            self.server_data[player][PS_MoneyAvailable] = rules[1]
            self.server_data[player][PS_MoneyBoughtIn] = rules[1]
        self.server_data[DL_GameName] = str(rules[0])
        self.server_data[DL_Currency] = str(rules[2])
        self.server_data[DL_BigBlind] = float(rules[3])

    def server_update_from_this_player_data_fields(self, client_data, client_id):
        self.server_data[client_id][PC_Name] = client_data[client_id][PC_Name]
        self.server_data[client_id][PC_Icon] = client_data[client_id][PC_Icon]
        self.server_data[client_id][PC_TableSpot] = client_data[client_id][PC_TableSpot]
        self.server_data[client_id][PC_BuyInReq] = client_data[client_id][PC_BuyInReq]
        self.server_data[client_id][PC_idPlayerAction] = client_data[client_id][PC_idPlayerAction]
        self.server_data[client_id][PC_isPlayerPlaying] = client_data[client_id][PC_isPlayerPlaying]
        self.server_data[client_id][PC_BetAmount] = client_data[client_id][PC_BetAmount]
        self.server_data[client_id][PC_ClientOverwrite] = client_data[client_id][PC_ClientOverwrite]
class RocketSimulator(QtCore.QObject):
    R_EARTH = 6371000 # meters
    G_0 = -9.80665 # m/s^2 (at sea level)

    new_data  = QtCore.pyqtSignal(object)


    def __init__(self, ticksize, param_file='parameters.json'):
        QtCore.QObject.__init__(self)
        self.load_data(param_file)


    def load_data(self, param_file):
        with open(param_file, 'r') as inputf:
            self.parameters = json.load(inputf)

        # Set imported parameters as properties
        for parameter in self.parameters:
            setattr(self, parameter, self.parameters[parameter])
        # use for threadsafe commnications with the GUI thread
        self.mutex = QMutex()

        self.atmosphere = Atmosphere()

        # TODO Error analysis vs. ticksize
        self.ticksize = 0.001

        self.time = 0
        self.height = self.launch_height
        self.velocity = 0
        self.acceleration = 0

        self.max_height = 0
        self.max_velocity = 0
        self.max_acceleration = 0

        self.mass = self.launch_mass

        self.thruster = Thruster()
        self.data = {}
        self.data['time'] = []
        self.data['height'] = []
        self.data['velocity'] = []
        self.data['acceleration'] = []


    def run_simulation(self):

        while self.height >= self.launch_height:
            self.run_tick()
        print(self.max_height, self.max_velocity, self.max_acceleration)

    def run_tick(self):

        self.height += self.velocity * self.ticksize
        self.velocity += self.acceleration * self.ticksize

        force = self.thrust_force() + self.drag_force() + self.gravity_force()
        self.acceleration = force / self.mass

        locked = False
        if self.mutex.tryLock(10):

            self.new_data.emit([self.time, self.height, self.velocity, self.acceleration])
            self.mutex.unlock()

        self.data['time'].append(self.time)
        self.data['height'].append(self.height)
        self.data['velocity'].append(self.velocity)
        self.data['acceleration'].append(self.acceleration)

        self.update_mass()
        self.update_max_values()
        self.time += self.ticksize

    def drag_force(self):
        pressure = self.atmosphere.get_density_by_height(self.height)
        # Rocket is heading up
        if self.velocity >= 0:
            drag_coef = self.rocket_drag_coef
            area = self.cross_sectional_area
        # Rocket is falling with parachute deployed
        else:
            drag_coef = self.parachute_drag_coef
            area = self.parachute_area

        # Drag force is the opposite direction of velocity
        if self.velocity > 0:
            direction = -1
        else:
             direction = 1

        # TODO use increased parachute area
        return (direction * drag_coef * pressure * self.velocity**2 * area ) / 2


    def gravity_force(self):
        return self.mass * self.get_g_at_alitude(self.height)

    def get_g_at_alitude(self, height):
        return self.G_0 * ((height + self.R_EARTH) / self.R_EARTH)**2


    def thrust_force(self):
        if self.time < self.burn_length:
            return self.thruster.get_thrust_at_time(self.time)
        else:
            return 0

    def update_mass(self):
        if self.time > self.burn_length:
            return
        else:
            self.mass -= (self.propellent_mass / self.burn_length) * self.ticksize

    def update_max_values(self):
        if self.height > self.max_height:
            self.max_height = self.height

        if self.velocity > self.max_velocity:
            self.max_velocity = self.velocity

        if self.acceleration > self.max_acceleration:
            self.max_acceleration = self.acceleration
Esempio n. 3
0
class AppWindow(QDialog):
    @staticmethod
    def error_window(txt='Unknown Error!'):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Critical)
        msg.setText("Error")
        msg.setInformativeText(txt)
        msg.setWindowTitle("Error")
        msg.exec_()

    def __init__(self):
        super().__init__()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)
        self.canvasMutex = QMutex(
        )  # protects canvas (probably redundant since I don't use workers)
        self.timer = QtCore.QTimer()

        self.timer.timeout.connect(self.draw_step)

        # connect actions
        self.ui.drawPushButton.clicked.connect(self.redraw_background)
        self.ui.startPushButton.clicked.connect(self.start_presentation)
        self.ui.stopPushButton.clicked.connect(self.timer.stop)
        self.ui.stepPushButton.clicked.connect(self.on_step_pushed)
        self.ui.functionEdit.textChanged.connect(self.set_redraw_needed)
        self.ui.x0DoubleSpinBox.valueChanged.connect(self.set_redraw_needed)
        self.ui.leftIntervalSpinBox.valueChanged.connect(
            self.set_redraw_needed)
        self.ui.rightIntervalSpinBox.valueChanged.connect(
            self.set_redraw_needed)
        self.ui.xyCheckBox.clicked.connect(self.set_redraw_needed)

        self.eps = 1e-15
        self.itTBD = 0
        self.xx = None  # x axes - linspace from left
        self.gx = None  # lambda function g(x)
        self.xc = None  # current value of x
        self.redraw = True  # indicates that old values are no longer valid!

        self.show()

    def set_redraw_needed(self):
        self.redraw = True

    def start_presentation(self):
        if not self.redraw_background():
            return

        self.itTBD = self.ui.iterationSpinBox.value()
        self.timer.start(int(self.ui.delaySpinBox.value() * 1000))

    def on_step_pushed(self):
        if self.redraw and not self.redraw_background():
            return

        self.itTBD = 1
        self.draw_step()

    # should only be called by draw_step()
    def reset_drawing(self):
        self.timer.stop()
        self.itTBD = 0
        self.canvasMutex.unlock()

    # draws one iteration on graph
    def draw_step(self):
        if self.canvasMutex.tryLock():
            if self.itTBD < 1:
                self.reset_drawing()
                return

            nxc = self.gx(self.xc)  # value of g(x_{n+1})

            if abs(self.xc - nxc) < self.eps:
                print('I am unable to reach better precision so I\'ll stop.')
                self.reset_drawing()
                return

            if nxc < self.ui.leftIntervalSpinBox.value(
            ) or nxc > self.ui.rightIntervalSpinBox.value():
                self.error_window('Out of interval!')
                self.reset_drawing()
                return

            # self.gx(nxc) may reach value out of interval but only on y-axis
            # I could also remember its value so I don't have to compute it in next iteration
            # but it is so cheap that I don't care
            self.ui.myMplCanvas.axes.plot([self.xc, nxc, nxc],
                                          [nxc, nxc, self.gx(nxc)],
                                          r'r--',
                                          linewidth=0.75)
            self.ui.myMplCanvas.draw()

            self.xc = nxc
            self.itTBD -= 1
            self.ui.xValueLabel.setText('Current value of x is: %.6f' %
                                        self.xc)
            self.canvasMutex.unlock()

    def redraw_background(self):
        self.gx = lambda x: eval(self.ui.functionEdit.text())
        self.xc = self.ui.x0DoubleSpinBox.value()
        li = self.ui.leftIntervalSpinBox.value()
        ri = self.ui.rightIntervalSpinBox.value()

        if li >= ri or self.xc < li or self.xc > ri:
            self.error_window('Invalid interval!')
            return False

        self.xx = np.linspace(self.ui.leftIntervalSpinBox.value(),
                              self.ui.rightIntervalSpinBox.value(), 10000)

        try:
            yy = self.gx(self.xx)
        except SyntaxError:
            self.error_window('Unable to parse g(x)!')
            return False

        if self.canvasMutex.tryLock():
            self.ui.myMplCanvas.clear()
            self.ui.myMplCanvas.axes.plot(self.xx, yy, label='g(x)')

            if self.ui.xyCheckBox.isChecked():
                self.ui.myMplCanvas.axes.plot(self.xx, self.xx, label='y = x')

            self.ui.myMplCanvas.draw()
            self.redraw = False
            self.canvasMutex.unlock()

        return True