Created
August 28, 2019 13:04
-
-
Save HolyMonkey/b2b12043c81635ade275e49ff8c5b578 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Reflection; | |
using System.Runtime.Serialization.Formatters.Binary; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace DmitryCherstvyi | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
using (MemoryStream chanel = new MemoryStream()) | |
{ | |
BinaryFormatter serializer = new BinaryFormatter(); | |
var gasStation = new GasStation(33); | |
var remoteFunctions = new RemoteFunctions(serializer, chanel); | |
var gasStationClient = new GasStationClientProxy(remoteFunctions); | |
var serverRouter = new ServerCallRouter(gasStation); | |
var car = new Car(); | |
var payer = new Player(); | |
gasStationClient.FillCar(car, payer); | |
chanel.Position = 0; | |
var message = serializer.Deserialize(chanel); | |
if (message is Call call) | |
{ | |
Console.WriteLine(call.Method.Name); | |
serverRouter.HandleCall(call); | |
} | |
} | |
} | |
} | |
class RemoteFunctions | |
{ | |
private readonly BinaryFormatter _serializer; | |
private readonly Stream _chanel; | |
public RemoteFunctions(BinaryFormatter serializer, Stream chanel) | |
{ | |
_serializer = serializer; | |
_chanel = chanel; | |
} | |
public Call<T1, T2> CallOnServer<T1, T2>(Action<T1, T2> function) | |
{ | |
return new Call<T1, T2>(function.Method, (call) => | |
{ | |
_serializer.Serialize(_chanel, call); | |
}); | |
} | |
} | |
[Serializable] | |
class Call | |
{ | |
public readonly MethodInfo Method; | |
public Call(MethodInfo method) | |
{ | |
Method = method; | |
} | |
} | |
[Serializable] | |
class Call<T1, T2> : Call | |
{ | |
public Tuple<T1, T2> Arguments { get; private set; } | |
[NonSerialized] private Action<Call<T1, T2>> _onReady; | |
public Call(MethodInfo method, Action<Call<T1, T2>> onReady) : base(method) | |
{ | |
_onReady = onReady; | |
} | |
public void WithArguments(T1 t1, T2 t2) | |
{ | |
Arguments = new Tuple<T1, T2>(t1, t2); | |
_onReady?.Invoke(this); | |
} | |
} | |
interface IGasStation | |
{ | |
void FillCar(Car car, Player payer); | |
} | |
class GasStationClientProxy : IGasStation | |
{ | |
private RemoteFunctions _remoteFunctions; | |
public GasStationClientProxy(RemoteFunctions remoteFunctions) | |
{ | |
_remoteFunctions = remoteFunctions; | |
} | |
public void FillCar(Car car, Player payer) | |
{ | |
_remoteFunctions.CallOnServer<Car, Player>(FillCar).WithArguments(car, payer); | |
} | |
} | |
class ServerCallRouter | |
{ | |
private object[] _handlers; | |
public ServerCallRouter(params object[] handlers) | |
{ | |
_handlers = handlers; | |
} | |
public void HandleCall(Call call) | |
{ | |
call.GetType(); | |
} | |
} | |
class GasStation : IGasStation | |
{ | |
private float _pricePerUnit; | |
private float _fuel; | |
public GasStation(float pricePerUnit) | |
{ | |
_pricePerUnit = pricePerUnit; | |
} | |
public void FillCar(Car car, Player payer) | |
{ | |
if (car == null) | |
throw new ArgumentNullException(nameof(car)); | |
if (payer == null) | |
throw new ArgumentNullException(nameof(payer)); | |
if(payer.TryWithdraw(GetFuelingCost(car, payer)) == false) | |
throw new InvalidOperationException("Can't withdraw money on driver"); | |
if(car.TryAddFuel(GetFuelingAmount(car, payer)) == false) | |
throw new InvalidOperationException("Can't add full fuel amount"); | |
_fuel -= GetFuelingAmount(car, payer); | |
} | |
/// <summary> | |
/// Просчитываете сколько топливо можно заправить в машину с учётом количества денег у платильщика и остатка топлива на заправке | |
/// </summary> | |
/// <returns>Количество топлива</returns> | |
private float GetFuelingAmount(Car car, Player payer) | |
{ | |
return GetFuelForPrice(GetPayAmount(payer, GetAvailableFuel(car.FuelLack))); | |
} | |
/// <summary> | |
/// Просчитываете сколько топливо можно заправить в машину с учётом количества денег у платильщика и остатка топлива на заправке | |
/// </summary> | |
/// <returns>Стоимость заправки</returns> | |
private int GetFuelingCost(Car car, Player payer) | |
{ | |
return GetPayAmount(payer, GetAvailableFuel(car.FuelLack)); | |
} | |
private float GetAvailableFuel(float targetAmount) | |
{ | |
return Mathf.Clamp(targetAmount, 0, _fuel); | |
} | |
private int GetPayAmount(Player payer, float fuel) | |
{ | |
return payer.GetClosestAmount(GetPriceForFuel(fuel)); | |
} | |
private int GetPriceForFuel(float amout) | |
{ | |
return (int)(amout * _pricePerUnit); | |
} | |
private float GetFuelForPrice(float amount) | |
{ | |
return amount / _pricePerUnit; | |
} | |
} | |
[Serializable] | |
class Car | |
{ | |
public float Fuel { get; private set; } | |
public float MaxFuel { get; private set; } | |
public float FuelLack => MaxFuel - Fuel; | |
public bool TryAddFuel(float amount) | |
{ | |
if (Fuel + amount > MaxFuel) | |
return false; | |
Fuel += amount; | |
return true; | |
} | |
} | |
[Serializable] | |
class Player | |
{ | |
public int Money { get; private set; } | |
public bool TryWithdraw(int amount) | |
{ | |
if (amount < 0 || amount > Money) | |
return false; | |
Money -= amount; | |
return true; | |
} | |
public int GetClosestAmount(int price) | |
{ | |
return (int)Mathf.Clamp(Money, 0, price); | |
} | |
} | |
static class Mathf | |
{ | |
public static float Clamp(float value, float min, float max) | |
{ | |
if (value < min) | |
return min; | |
if (value > max) | |
return max; | |
return value; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment