Compare commits

..

No commits in common. "master" and "dev" have entirely different histories.
master ... dev

44 changed files with 179 additions and 2098328 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 872 KiB

View File

@ -1,38 +0,0 @@
# Final Evaluation
## Introduction
PotatoPlan is an Inteligent Tractor AI Project and is written in C# using Monogame framework.
NuGet Packages used and requeired for the project to work ar as follows:
C5
Microsoft.ML
Microsoft.ML.LightGBM
System.Drawing.Common
In our project agent (tractor) moves on resizable grid, which starting size is dependant on primary screen resolution.
The task of the agent is to go through all soil tiles and plant different types of crops, use proper fertilizer and collect crops when fully grown.
Window can be resized usind WASD. Tractor speed can be changed using UP and DOWN arrow keys, while simulation speed can be changed using LEFT and RIGHT arrow keys.
Also house placement can be changed by left clicking on a tile, and get info about the tile by right clicking.
Apart from Machine Learning Algorithms used in project there are also many different features implemented like:
- Using A* algorithm to find an optimal path to previously selected target.
- Target is found by scoring system which assign score to a tile based on few factors like production rate or distance.
- Dynamically allocated cargo space for each fertilizer based on how often each fertilizer is used.
- Day and night cycle and season system.
- Using noise map generated for rainfall calculations to draw moving clouds.
- ... and few other.
## Machine Learning Algorithms
Project in its current state uses Machine Learning Algorithms to solve 2 problems. Light Gradient-Boosted Trees are used for both problems:
1. Choosing a proper fertilizer which should be applied to current tile, based on few variables like nutrients in soil.
Applying proper fertilizer boosts production rate of a crop (rate of growth of a crop). This part was done by Oskar Nastały.
2. Calculating production rate of a tile based on rainfall and few other variabels. Noise map is generated and used to simulate dynamically changing rainfall.
Then once a day AI is used to calculate base production rate multiplier. This part was done by Joel Städe.
## Examples
### Clouds
![Clouds](https://git.wmi.amu.edu.pl/s425077/PotatoPlan/raw/Joel-ML/Evaluation_examples/Example_clouds.PNG)
### UI
![UI](https://git.wmi.amu.edu.pl/s425077/PotatoPlan/raw/Joel-ML/Evaluation_examples/Example_UI.PNG)

BIN
Game1.bnp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 MiB

View File

@ -61,30 +61,6 @@
/processorParam:TextureFormat=Color
/build:CarronIcon.png;CarrotIcon.png
#begin Cloud.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:Cloud.png
#begin Clouds.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:Clouds.png
#begin CottonIcon.png
/importer:TextureImporter
/processor:TextureProcessor
@ -272,18 +248,6 @@
/processorParam:TextureFormat=Color
/build:PulsesIcon.png
#begin rain.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:rain.png
#begin Right.png
/importer:TextureImporter
/processor:TextureProcessor
@ -404,15 +368,3 @@
/processorParam:TextureFormat=Color
/build:WheatIcon.png
#begin WoodBackground.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:WoodBackground.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 872 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
Mean Absolute Error: 0.0108015636096701
Mean Squared Error: 0.0434908452113952
R Squared: 0.702723944791744

View File

@ -1,2 +0,0 @@
Mean Absolute Error: 187.060835104336
R Squared: 0.913526230109177

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -3,7 +3,6 @@ using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.IO;
using WinForm = System.Windows.Forms;
namespace Game1
{
@ -19,11 +18,9 @@ namespace Game1
private Texture2D[] tileConnected = new Texture2D[5];
private Texture2D[] Crops = new Texture2D[12];
private Texture2D tractor;
private Texture2D Background;
private Texture2D house;
private Texture2D markers;
private Texture2D mouseCursor;
private Texture2D Rain;
string directory = Directory.GetCurrentDirectory();
@ -46,10 +43,6 @@ namespace Game1
MouseState state;
private int cloudAnimationSpeed = 3;
private int cloudFrame = 0;
private int cloudSprite;
public Game1()
{
@ -76,19 +69,14 @@ namespace Game1
cropTypesNames[11] = "Wheat";
Engine.init();
Sources.ML_Joel.Engine.initArea();
//Sources.ML_Joel.Engine.CreateModel();
//Sources.ML_Joel.Engine.CreateModelArea();
//Generates the map with some random values
inventory.initInventorySystem();
string path = directory + "Game1/Content/ML/Fertilizer_Prediction.csv";
int res = WinForm.Screen.PrimaryScreen.Bounds.Height;
input.init(graphics, new Vector2((float)Math.Floor(WinForm.Screen.PrimaryScreen.Bounds.Width/56*0.6f), (float)Math.Floor((WinForm.Screen.PrimaryScreen.Bounds.Height / 56f) - 7)), 56, 0); //Generates the starting size
input.init(graphics, new Vector2(16,16), 56, 0); //Generates the starting size
houseUnit.init(input.getTileSize(), input.getSpacing()); //Generates the house position
tractorUnit.init(houseUnit.GetRectangle(), input); //Generates the Tractor
tractorUnit.updateSizing(input, 0, houseUnit.getVector(), Time); //Updates the first Size of the Tractor
@ -98,7 +86,7 @@ namespace Game1
graphics.PreferredBackBufferWidth = (input.getTileSize() + input.getSpacing()) * (int)input.getSize().X;
graphics.PreferredBackBufferHeight = (input.getTileSize() + input.getSpacing()) * (int)input.getSize().Y + 380;
graphics.PreferredBackBufferHeight = (input.getTileSize() + input.getSpacing()) * (int)input.getSize().Y + 300;
graphics.ApplyChanges();
}
@ -120,10 +108,8 @@ namespace Game1
tileConnected[2] = Content.Load<Texture2D>("Right");
tileConnected[3] = Content.Load<Texture2D>("Bottom");
Rain = Content.Load<Texture2D>("Clouds");
Background = Content.Load<Texture2D>("WoodBackground");
Crops[0] = Content.Load<Texture2D>("Markers");
@ -173,9 +159,9 @@ namespace Game1
input.controlWindowSize(); //Controls the size of the screen depending on the number of tiles
houseUnit.updateRectangle(input.getSize(), input.getTileSize(), input.getSpacing()); //Updates the position of the house if the house appears out of bound
Time.updateTime(tractorUnit.getSpeed());
//System.Threading.Thread updatethread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(Update));
base.Update(gameTime);
}
@ -185,6 +171,7 @@ namespace Game1
GraphicsDevice.Clear(Color.FromNonPremultiplied(255,255,255,140));
spriteBatch.Begin();
DrawTiles();
spriteBatch.Draw(markers, new Rectangle((int)tractorUnit.getTargetPosition().X / input.getSpacingTile() * (input.getTileSize() + input.getSpacing()) + input.getTileSize() / 4, (int)tractorUnit.getTargetPosition().Y / input.getSpacingTile() * (input.getTileSize() + input.getSpacing()) + input.getTileSize() / 4, input.getTileSize()/2, input.getTileSize()/2), Color.White);
@ -196,62 +183,52 @@ namespace Game1
spriteBatch.Draw(house, houseUnit.GetRectangle(), Time.GetTimeOfDay());
spriteBatch.Draw(markers, new Rectangle((int)tractorUnit.getPath().getFinalDest().getCords().X * (input.getSpacingTile()) + Convert.ToInt32(input.getTileSize() / 6), (int)tractorUnit.getPath().getFinalDest().getCords().Y * (input.getSpacingTile()) + Convert.ToInt32(input.getTileSize() / 6), Convert.ToInt32(input.getTileSize() / 1.5), Convert.ToInt32(input.getTileSize() / 1.5)), Color.White); //Draws the current target of the tractor
spriteBatch.Draw(tractor, new Vector2((int)tractorUnit.getPos().X + input.getTileSize() / 2, (int)tractorUnit.getPos().Y + input.getTileSize() / 2), new Rectangle(0, 0, input.getTileSize(), input.getTileSize()), Time.GetTimeOfDay(), tractorUnit.getRotation(), new Vector2(input.getTileSize() / 2, input.getTileSize() / 2), 1.0f, SpriteEffects.None, 1);
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
spriteBatch.Draw(Background, new Rectangle(i * 512, (int)input.getSize().Y * (input.getTileSize() + input.getSpacing()) + j * 512, 512, 512), Color.FromNonPremultiplied(125, 125, 125, 255));
}
spriteBatch.Draw(ProgressionBar, new Rectangle(i * 227, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())), 5, 295), Color.White);
}
for (int i = 0; i < 15; i++)
{
spriteBatch.Draw(ProgressionBar, new Rectangle(0, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())) + i * 20, (int)(input.getSize().X * (input.getTileSize() + input.getSpacing())), 1), Color.White);
}
for (int i = 0; i < 5; i++)
{
spriteBatch.Draw(tile[0], new Rectangle(i * 227, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())), 5, 500), Color.White);
}
for (int i = 0; i < 20; i++)
{
spriteBatch.Draw(tile[0], new Rectangle(0, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())) + i * 20, (int)(input.getSize().X * (input.getTileSize() + input.getSpacing())), 1), Color.White);
}
tractorUnit.drawInventory(input, spriteBatch, Bold, inventory.getPredefinedItems());
spriteBatch.DrawString(Bold, "Time: ", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
spriteBatch.DrawString(Bold, "Days " + Time.getDays(), new Vector2(60, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.Teal);
spriteBatch.DrawString(Bold, Time.getTimeOfYear(), new Vector2(120, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.Teal);
spriteBatch.DrawString(Bold, "Days " + Time.getDays(), new Vector2(60, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Day Progression: ", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.DarkRed);
spriteBatch.DrawString(Bold, Time.GetTimeOfDayInt().ToString() + "%", new Vector2(140, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.Teal);
spriteBatch.DrawString(Bold, Time.GetTimeOfDayInt().ToString() + "%", new Vector2(140, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Tractor Properties:", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 62), Color.DarkRed);
spriteBatch.DrawString(Bold, "Speed:" + tractorUnit.getSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 82), Color.Teal);
spriteBatch.DrawString(Bold, "Tractor Position:" + new Vector2((float)Math.Round(tractorUnit.getPos().X / input.getSpacingTile(), 1), (float)Math.Round(tractorUnit.getPos().Y / input.getSpacingTile(), 1)), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 102), Color.Teal);
spriteBatch.DrawString(Bold, "Tractor Rotation:" + Math.Round(tractorUnit.getRotation(), 2).ToString() + " Degrees", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 122), Color.Teal);
spriteBatch.DrawString(Bold, "Tractor Speed:" + tractorUnit.getTractorSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 142), Color.Teal);
spriteBatch.DrawString(Bold, "Tractor Target:" + tractorUnit.getPath().getFinalDest().getCords().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 162), Color.Teal);
spriteBatch.DrawString(Bold, "Speed:" + tractorUnit.getSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 82) , Color.DarkBlue);
spriteBatch.DrawString(Bold, "Tractor Position:" + new Vector2((float)Math.Round(tractorUnit.getPos().X / input.getSpacingTile(), 1), (float)Math.Round(tractorUnit.getPos().Y / input.getSpacingTile(), 1)), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 102), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Tractor Rotation:" + Math.Round(tractorUnit.getRotation(), 2).ToString() + " Degrees", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 122), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Tractor Speed:" + tractorUnit.getTractorSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 142), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Tractor Target:" + tractorUnit.getPath().getFinalDest().getCords().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 162), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Map Properties:", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 202), Color.DarkRed);
spriteBatch.DrawString(Bold, "Tile Size:" + input.getTileSize().ToString() + "pix", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 222), Color.Teal); //Draws the tile size
spriteBatch.DrawString(Bold, "Matrix Size: " + input.getSize().X.ToString() + " X " + input.getSize().Y.ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 242), Color.Teal);
spriteBatch.DrawString(Bold, "House Position: " + houseUnit.getVector() / input.getSpacingTile(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 262), Color.Teal);
tractorUnit.getFarm().drawWeatherInformation(spriteBatch, Bold, input);
spriteBatch.DrawString(Bold, "Tile Size:" + input.getTileSize().ToString() + "pix", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 222), Color.DarkBlue); //Draws the tile size
spriteBatch.DrawString(Bold, "Matrix Size: " + input.getSize().X.ToString() + " X " + input.getSize().Y.ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 242), Color.DarkBlue);
spriteBatch.DrawString(Bold, "House Position: " + houseUnit.getVector() / input.getSpacingTile(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 262), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Total Weight: ", new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 182), Color.DarkRed);
spriteBatch.DrawString(Bold, "(" + tractorUnit.getInventory().getWeight() + "/" + tractorUnit.getInventory().getMaxWeight() + ")", new Vector2(800, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 182), Color.Teal);
spriteBatch.DrawString(Bold, "(" + tractorUnit.getInventory().getWeight() + "/" + tractorUnit.getInventory().getMaxWeight() + ")", new Vector2(800, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 182), Color.DarkBlue);
tractorUnit.drawInventory(input, spriteBatch, Bold, inventory.getPredefinedItems());
InspectTile();
spriteBatch.Draw(mouseCursor, new Rectangle((int)mousePosition.X, (int)mousePosition.Y, 14, 21), Color.White);
spriteBatch.End();
spriteBatch.Begin();
InspectTile();
spriteBatch.End();
base.Draw(gameTime);
}
@ -262,9 +239,10 @@ namespace Game1
{
for (int j = 0; j < input.getSize().Y; j++)
{
Rectangle tilePos = new Rectangle(i * (input.getSpacingTile()), j * (input.getSpacingTile()), input.getTileSize(), input.getTileSize());
spriteBatch.Draw(tile[tractorUnit.getFarm().getCrop(i, j).getStatus()], tilePos, Time.GetTimeOfDay());
if (i > 0)
{
@ -328,23 +306,12 @@ namespace Game1
}
}
spriteBatch.Draw(house, houseUnit.GetRectangle(), Time.GetTimeOfDay());
spriteBatch.Draw(tractor, new Vector2((int)tractorUnit.getPos().X + input.getTileSize() / 2, (int)tractorUnit.getPos().Y + input.getTileSize() / 2), new Rectangle(0, 0, input.getTileSize(), input.getTileSize()), Time.GetTimeOfDay(), tractorUnit.getRotation(), new Vector2(input.getTileSize() / 2, input.getTileSize() / 2), 1.0f, SpriteEffects.None, 1);
for (int i = -1; i < input.getSize().X + 1; i++) //Draw the tiles
{
for (int j = -1; j < input.getSize().Y + 1; j++)
{
spriteBatch.Draw(Rain, tractorUnit.getFarm().getRainPosition(input.getTileSize(), i, j, input.getSize()), tractorUnit.getFarm().getDestinationRectangle(i, j, input.getSize()), tractorUnit.getFarm().getRainAmount(i, j, Time.GetTimeOfDay(), input.getSize()));
}
}
}
public void InspectTile()
{
spriteBatch.DrawString(Bold, "Crop:", new Vector2(240, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
spriteBatch.DrawString(Bold, "Selected tile: (" + x.ToString() + ", " + y.ToString() + ")", new Vector2(240, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.Teal);
spriteBatch.DrawString(Bold, "Selected tile: (" + x.ToString() + ", " + y.ToString() + ")", new Vector2(240, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.DarkBlue);
tractorUnit.getFarm().getCrop(x, y).Inspect(input.getTileSize(), input.getSpacing(), Bold, new SpriteBatch(GraphicsDevice), cropTypesNames);
}
}

View File

@ -90,12 +90,6 @@
<Compile Include="Sources\Crops\PerlinNoise.cs" />
<Compile Include="Sources\Crops\SoilProperties.cs" />
<Compile Include="Sources\ML\Engine.cs" />
<Compile Include="Sources\ML_Joel\DataModel\InputArea.cs" />
<Compile Include="Sources\ML_Joel\DataModel\Input.cs" />
<Compile Include="Sources\ML_Joel\DataModel\OutputArea.cs" />
<Compile Include="Sources\ML_Joel\DataModel\Output.cs" />
<Compile Include="Sources\ML_Joel\Engine.cs" />
<Compile Include="Sources\ML_Joel\Model.cs" />
<Compile Include="Sources\Objects\DayNightCycle.cs" />
<Compile Include="Sources\Objects\Fertilizer.cs" />
<Compile Include="Sources\Objects\FertilizerHolder.cs" />
@ -136,7 +130,6 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Numerics" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
@ -173,9 +166,6 @@
<PackageReference Include="LightGBM">
<Version>2.3.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.Common">
<Version>3.6.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.ML">
<Version>1.4.0</Version>
</PackageReference>

View File

@ -2,8 +2,6 @@
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Drawing;
using WinForm = System.Windows.Forms;
class Controller
{
@ -19,7 +17,7 @@ class Controller
public Vector2 updateWindow(int tileSize, int Spacing, Vector2 Size)
{
KeyboardState state = Keyboard.GetState();
if (state.IsKeyDown(Keys.D) && Size.X < Math.Floor(WinForm.Screen.PrimaryScreen.Bounds.Width / (float)tileSize))
if (state.IsKeyDown(Keys.D) && Size.X < 90)
{
Size.X++;
graphics.PreferredBackBufferWidth = (tileSize + Spacing) * (int)Size.X - Spacing;
@ -31,16 +29,16 @@ class Controller
graphics.PreferredBackBufferWidth = (tileSize + Spacing) * (int)Size.X - Spacing;
}
if (state.IsKeyDown(Keys.W) && Size.Y < Math.Floor(WinForm.Screen.PrimaryScreen.Bounds.Height / (float)tileSize) - 7)
if (state.IsKeyDown(Keys.W) && Size.Y < 20)
{
Size.Y++;
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 380;
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 300;
}
if (state.IsKeyDown(Keys.S) && Size.Y > 2)
{
Size.Y--;
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 380;
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 300;
}
return Size;
}

View File

@ -12,16 +12,12 @@ class CropTypes
public string[] soilType = new string[3];
public int[] Times = new int[3];
public string CropName;
public string[] Season = new string[5];
public float Temparature;
public float Humidity;
public float Moisture;
public float Nitrogen;
public float Potassium;
public float Phosphorous;
public float Area;
public int AreaMin;
public int AreaMax;
public CropTypes()

View File

@ -36,10 +36,6 @@ class CropTypesHolder
cropTypes[1].Nitrogen = 21 + 12.6f;
cropTypes[1].Potassium = 10 + 5.3f;
cropTypes[1].Phosphorous = 20 + 26.0f;
cropTypes[1].Season[0] = "Spring";
cropTypes[1].Season[1] = "Autumn";
cropTypes[1].AreaMin = 1;
cropTypes[1].AreaMax = 8000;
// Cotton
@ -57,11 +53,6 @@ class CropTypesHolder
cropTypes[2].Nitrogen = 21 + 16.4f;
cropTypes[2].Potassium = 10 + 3.3f;
cropTypes[2].Phosphorous = 20 + 23.8f;
cropTypes[2].Season[0] = "Spring";
cropTypes[2].Season[1] = "Autumn";
cropTypes[2].Season[2] = "Whole Year";
cropTypes[2].AreaMin = 1;
cropTypes[2].AreaMax = 199000;
// Ground Nuts
cropTypes[3] = new CropTypes();
@ -75,13 +66,6 @@ class CropTypesHolder
cropTypes[3].Nitrogen = 21 + 23.3f;
cropTypes[3].Potassium = 10 + 2.0f;
cropTypes[3].Phosphorous = 20 + 21.6f;
cropTypes[3].Season[0] = "Spring";
cropTypes[3].Season[1] = "Autumn";
cropTypes[3].Season[2] = "Whole Year";
cropTypes[3].Season[3] = "Winter";
cropTypes[3].Season[4] = "Summer";
cropTypes[3].AreaMin = 1;
cropTypes[3].AreaMax = 147000;
// Maize
@ -96,13 +80,6 @@ class CropTypesHolder
cropTypes[4].Nitrogen = 21 + 18.3f;
cropTypes[4].Potassium = 10 + 5.7f;
cropTypes[4].Phosphorous = 20 + 18.7f;
cropTypes[4].Season[0] = "Spring";
cropTypes[4].Season[1] = "Autumn";
cropTypes[4].Season[2] = "Whole Year";
cropTypes[4].Season[3] = "Winter";
cropTypes[4].Season[4] = "Summer";
cropTypes[4].AreaMin = 1;
cropTypes[4].AreaMax = 73000;
// Millets
cropTypes[5] = new CropTypes();
@ -118,11 +95,6 @@ class CropTypesHolder
cropTypes[5].Nitrogen = 21 + 23.2f;
cropTypes[5].Potassium = 10 + 0.1f;
cropTypes[5].Phosphorous = 20 + 14.4f;
cropTypes[5].Season[0] = "Spring";
cropTypes[5].Season[1] = "Autumn";
cropTypes[5].Season[2] = "Whole Year";
cropTypes[5].AreaMin = 1;
cropTypes[5].AreaMax = 59000;
//Oil Seeds
cropTypes[6] = new CropTypes();
@ -136,9 +108,6 @@ class CropTypesHolder
cropTypes[6].Nitrogen = 21 + 19.0f;
cropTypes[6].Potassium = 10 + 2.3f;
cropTypes[6].Phosphorous = 20 + 17.3f;
cropTypes[6].Season[0] = "Whole Year";
cropTypes[6].AreaMin = 25;
cropTypes[6].AreaMax = 25000;
//Paddys
cropTypes[7] = new CropTypes();
@ -152,11 +121,6 @@ class CropTypesHolder
cropTypes[7].Nitrogen = 21 + 20.8f;
cropTypes[7].Potassium = 10 + 3.7f;
cropTypes[7].Phosphorous = 20 + 16.3f;
cropTypes[7].Season[0] = "Autumn";
cropTypes[7].Season[1] = "Winter";
cropTypes[7].Season[2] = "Summer";
cropTypes[7].AreaMin = 200;
cropTypes[7].AreaMax = 270000;
//Pulses
cropTypes[8] = new CropTypes();
@ -170,12 +134,6 @@ class CropTypesHolder
cropTypes[8].Nitrogen = 21 + 18.4f;
cropTypes[8].Potassium = 10 + 4.2f;
cropTypes[8].Phosphorous = 20 + 17.5f;
cropTypes[8].Season[0] = "Spring";
cropTypes[8].Season[1] = "Autumn";
cropTypes[8].Season[2] = "Whole Year";
cropTypes[8].Season[3] = "Summer";
cropTypes[8].AreaMin = 40;
cropTypes[8].AreaMax = 140000;
//Sugarcane
cropTypes[9] = new CropTypes();
@ -191,12 +149,6 @@ class CropTypesHolder
cropTypes[9].Nitrogen = 21 + 14.6f;
cropTypes[9].Potassium = 10 + 4.2f;
cropTypes[9].Phosphorous = 20 + 17.6f;
cropTypes[9].Season[0] = "Spring";
cropTypes[9].Season[1] = "Autumn";
cropTypes[9].Season[2] = "Whole Year";
cropTypes[9].Season[3] = "Winter";
cropTypes[9].AreaMin = 1;
cropTypes[9].AreaMax = 23000;
//Tobacco
@ -211,11 +163,6 @@ class CropTypesHolder
cropTypes[10].Nitrogen = 21 + 19.1f;
cropTypes[10].Potassium = 10 + 4.9f;
cropTypes[10].Phosphorous = 20 + 19.3f;
cropTypes[10].Season[0] = "Spring";
cropTypes[10].Season[1] = "Autumn";
cropTypes[10].Season[2] = "Whole Year";
cropTypes[10].AreaMin = 1;
cropTypes[10].AreaMax = 9500;
//Wheat
@ -230,12 +177,6 @@ class CropTypesHolder
cropTypes[11].Nitrogen = 21 + 23.3f;
cropTypes[11].Potassium = 10 + 2.9f;
cropTypes[11].Phosphorous = 20 + 14.4f;
cropTypes[11].Season[0] = "Spring";
cropTypes[11].Season[1] = "Autumn";
cropTypes[11].Season[2] = "Whole Year";
cropTypes[11].Season[3] = "Summer";
cropTypes[11].AreaMin = 1;
cropTypes[11].AreaMax = 266000;
}

View File

@ -14,23 +14,18 @@ class Crops
private int cropType = 0;
private float Timer = 1;
private int UpdateCrop;
private float fullTimer = 1;
private float fullTimer;
private bool housePos = false;
private Vector2 Size;
private Random r = new Random();
private CropTypes DataSet;
SoilProperties soilProperties = new SoilProperties();
private float ProductionRate;
private float tempRain;
private float prevpred;
private DayNightCycle Time = new DayNightCycle();
private int previousDay = 0;
public void updateCrop(Vector2 newSize, DayNightCycle nTime)
public void updateCrop(Vector2 newSize)
{
Time = nTime;
getProductionRate(DataSet);
if (UpdateCrop == 60)
{
degradeSoil();
@ -50,11 +45,6 @@ class Crops
}
}
public void updateProductionRate()
{
getProductionRate(DataSet);
}
public float getSpeedFactor(float tractorSpeed)
{
if (getCostOnMovement() == 1)
@ -207,57 +197,27 @@ class Crops
public void degradeSoil()
{
Random r = new Random();
if (soilProperties.Nitrogen > 4.0f)
{
soilProperties.Nitrogen = soilProperties.Nitrogen - ((soilProperties.NitrogenDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
soilProperties.Nitrogen = soilProperties.Nitrogen - (soilProperties.NitrogenDegradeRate * (float)Math.Pow(ProductionRate, 2));
}
if (soilProperties.Phosphorous > 0.1f)
{
soilProperties.Phosphorous = soilProperties.Phosphorous - ((soilProperties.PhosphorousDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
soilProperties.Phosphorous = soilProperties.Phosphorous - (soilProperties.PhosphorousDegradeRate * (float)Math.Pow(ProductionRate, 2));
}
if (soilProperties.Potassium > 0.1f)
{
soilProperties.Potassium = soilProperties.Potassium - ((soilProperties.PotassiumDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
soilProperties.Potassium = soilProperties.Potassium - (soilProperties.PotassiumDegradeRate * (float)Math.Pow(ProductionRate, 2));
}
}
public void updateRainfall(float Rain)
{
if (Rain >= 0.45f)
{
soilProperties.Rainfall = soilProperties.Rainfall + Rain * 4;
}
}
public void setPrevRainfall()
{
soilProperties.prevRainfall = soilProperties.Rainfall;
if (soilProperties.prevRainfall > 3616)
soilProperties.prevRainfall = 3616;
else if (soilProperties.prevRainfall < 236)
soilProperties.prevRainfall = 236;
soilProperties.Rainfall = 0;
}
public void setCropType(int Type, CropTypes nCropType)
{
if (Timer == fullTimer)
{
CropTypes temp = DataSet;
DataSet = nCropType;
cropType = Type;
if (Status > 1)
{
soilProperties.Area = r.Next(nCropType.AreaMin, nCropType.AreaMax);
if (temp != nCropType)
updateMLModel(DataSet, 1.0f);
}
}
DataSet = nCropType;
cropType = Type;
}
public int getStatus()
@ -280,7 +240,6 @@ class Crops
public void setStatus(int newStatus)
{
Status = newStatus;
Timer = getCropTimer();
}
public void setOriginalStatus()
@ -294,7 +253,6 @@ class Crops
housePos = state;
if (state)
{
Timer = 1;
Status = 1;
}
else
@ -339,12 +297,6 @@ class Crops
public float getProductionRate(CropTypes Sample)
{
float predProd = 1.0f;
if (Status > 1 && Time.getDays() != previousDay)
{
predProd = updateMLModel(Sample, predProd);
}
prevpred = predProd;
ProductionRate = 1;
float min = 1.0f;
if (DataSet != null)
@ -383,31 +335,7 @@ class Crops
ProductionRate = ProductionRate / 1.5f;
}
ProductionRate = (float)Math.Pow(ProductionRate, 2.5f);
return ProductionRate * prevpred;
}
public float updateMLModel(CropTypes Sample, float predProd)
{
previousDay = Time.getDays();
bool correctSeason = false;
foreach (string i in Sample.Season)
{
if (i == Time.getTimeOfYear() || i == "Whole Year")
{
correctSeason = true;
break;
}
}
if (correctSeason)
{
predProd = Game1.Sources.ML_Joel.Engine.PredictProductionwithRainfall(soilProperties, Time);
predProd = (predProd / soilProperties.Area) / 2;
}
else
predProd = 0.20f;
return predProd;
return ProductionRate;
}
public float getProductionRate()
@ -435,26 +363,26 @@ class Crops
spriteBatch.Begin();
if (housePos)
{
spriteBatch.DrawString(Bold, "Tiletype: House", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
spriteBatch.DrawString(Bold, "Tiletype: House", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
}
else if (Status == 0)
{
spriteBatch.DrawString(Bold, "Tiletype: Boulders", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
spriteBatch.DrawString(Bold, "Tiletype: Boulders", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
}
else if (Status == 1)
{
spriteBatch.DrawString(Bold, "Tiletype: Grassfield", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
spriteBatch.DrawString(Bold, "Tiletype: Grassfield", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
}
else if (Status == 2)
{
spriteBatch.DrawString(Bold, "Tiletype: Soil", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
spriteBatch.DrawString(Bold, "Tiletype: Soil", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
}
else if (Status == 3)
{
int x = (int)(((float)Timer / fullTimer) * 100);
x = 100 - x;
spriteBatch.DrawString(Bold, "Tiletype: Crop ", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
spriteBatch.DrawString(Bold, "Completion: " + x + "%", new Vector2(240, Size.Y * (tileSize + Spacing) + 82), Color.Teal);
spriteBatch.DrawString(Bold, "Tiletype: Crop ", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Completion: " + x + "%", new Vector2(240, Size.Y * (tileSize + Spacing) + 82), Color.DarkBlue);
}
if (Status != 3)
{
@ -462,37 +390,29 @@ class Crops
}
if (Status > 1)
{
spriteBatch.DrawString(Bold, "Prefered Crop: " + cropTypesNames[cropType], new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.Teal);
spriteBatch.DrawString(Bold, "Prefered Crop: " + cropTypesNames[cropType], new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.DarkBlue);
}
else
{
spriteBatch.DrawString(Bold, "None", new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.Teal);
spriteBatch.DrawString(Bold, "None", new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.DarkBlue);
}
spriteBatch.DrawString(Bold, "Soil Properties:", new Vector2(240, Size.Y * (tileSize + Spacing) + 122), Color.DarkRed);
spriteBatch.DrawString(Bold, "Soil Type: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 142), Color.DarkRed);
spriteBatch.DrawString(Bold, soilProperties.soilType, new Vector2(370, Size.Y * (tileSize + Spacing) + 142), Color.Teal);
spriteBatch.DrawString(Bold, soilProperties.soilType, new Vector2(370, Size.Y * (tileSize + Spacing) + 142), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Temparature: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 162), Color.DarkRed);
spriteBatch.DrawString(Bold, soilProperties.Temperature.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 162), Color.Teal);
spriteBatch.DrawString(Bold, soilProperties.Temperature.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 162), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Moisture: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 182), Color.DarkRed);
spriteBatch.DrawString(Bold, soilProperties.Moisture.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 182), Color.Teal);
spriteBatch.DrawString(Bold, soilProperties.Moisture.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 182), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Humidity: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 202), Color.DarkRed);
spriteBatch.DrawString(Bold, soilProperties.Humidity.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 202), Color.Teal);
spriteBatch.DrawString(Bold, soilProperties.Humidity.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 202), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Phosphorous: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 222), Color.DarkRed);
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Phosphorous,1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 222), Color.Teal);
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Phosphorous,1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 222), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Potassium: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 242), Color.DarkRed);
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Potassium, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 242), Color.Teal);
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Potassium, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 242), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Nitrogen: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 262), Color.DarkRed);
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Nitrogen, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 262), Color.Teal);
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Nitrogen, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 262), Color.DarkBlue);
spriteBatch.DrawString(Bold, "Production Rate: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 282), Color.DarkRed);
spriteBatch.DrawString(Bold, Math.Round((ProductionRate * 100), 1).ToString() + "%", new Vector2(370, Size.Y * (tileSize + Spacing) + 282), Color.Teal);
spriteBatch.DrawString(Bold, "Last Years Rainfall: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 302), Color.DarkRed);
spriteBatch.DrawString(Bold, Math.Round((soilProperties.prevRainfall), 1).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 302), Color.Teal);
spriteBatch.DrawString(Bold, "Rainfall: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 322), Color.DarkRed);
spriteBatch.DrawString(Bold, Math.Round((soilProperties.Rainfall), 1).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 322), Color.Teal);
spriteBatch.DrawString(Bold, "Rain mm/s: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 342), Color.DarkRed);
spriteBatch.DrawString(Bold, Math.Round((tempRain * 2), 2).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 342), Color.Teal);
spriteBatch.DrawString(Bold, "Area: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 362), Color.DarkRed);
spriteBatch.DrawString(Bold, soilProperties.Area + "m^2", new Vector2(370, Size.Y * (tileSize + Spacing) + 362), Color.Teal);
spriteBatch.DrawString(Bold, Math.Round((ProductionRate * 100), 1).ToString() + "%", new Vector2(370, Size.Y * (tileSize + Spacing) + 282), Color.DarkBlue);
spriteBatch.End();
}
}

View File

@ -1,6 +1,4 @@
using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -16,17 +14,8 @@ class Farm
private int Update;
private Astar astar = new Astar();
private PerlinNoise perlin = new PerlinNoise();
private Vector2 RainPosition;
private Vector2 WindSpeed = new Vector2(0,0);
private System.Drawing.Color[][] RainfallMap;
private float[][] whiteNoise;
private float[][] perlinNoise;
private DayNightCycle Time;
private float updatePerc = 0.01f;
private float updateProgress = 0;
private float nextUpdate = 0;
private int productionUpdate = 0;
private string path_base = FindPath();
//initializes the crops
@ -43,7 +32,17 @@ class Farm
for (int j = 0; j < 99; j++)
{
int x = 0;
/*
int x = r.Next(0, 3);
if (x == 0)
{
x = r.Next(0, 2);
}
if (x == 2)
{
x = r.Next(1, 3);
}
*/
if (perlinNoise[i][j] > 0 && perlinNoise[i][j] < 0.15f)
x = 0;
else if (perlinNoise[i][j] >= 0.15f && perlinNoise[i][j] < 0.8f)
@ -53,7 +52,7 @@ class Farm
crops[i, j] = new Crops();
crops[i, j].setStatus(x);
crops[i, j].setOriginalStatus();
x = r.Next(1, 12);
x = r.Next(0, 12);
crops[i, j].setCropType(x, PresetCrops.getPresetCropTypes(x));
crops[i, j].init();
@ -71,6 +70,7 @@ class Farm
{
if (!astar.isReachable(crops, new Vector2((int)i, (int)j), housepos))
{
//crops[i, j].setStatus(1);
dirtCount--;
}
}
@ -78,52 +78,6 @@ class Farm
}
if (dirtCount != 0)
init(Size, housepos);
RainPosition.X = r.Next(0, 1900);
RainPosition.Y = r.Next(0, 1950);
float coef = GetRandomNumber(-1f, 1f);
if (coef < 0)
coef = -1.0f;
else
coef = 1.0f;
WindSpeed.X = GetRandomNumber(0.9f, 1f) / 50 * coef;
WindSpeed.Y = GetRandomNumber(0.9f, 1f) / 50 * coef;
RainfallMap = PerlinNoise.LoadImage(System.IO.Path.Combine(path_base, "Content/Rainfall.png"));
}
public Rectangle getRainPosition(int TileSize, int x, int y, Vector2 Size)
{
float xtrunc = RainPosition.X - (float)Math.Truncate(RainPosition.X);
float ytrunc = RainPosition.Y - (float)Math.Truncate(RainPosition.Y);
if (xtrunc > 0.5)
xtrunc = xtrunc - 1;
if (ytrunc > 0.5)
ytrunc = ytrunc - 1;
xtrunc = -xtrunc;
ytrunc = -ytrunc;
//return new Rectangle((int)(xtrunc * TileSize) + x * TileSize,(int)(ytrunc * TileSize) + y * TileSize, TileSize, TileSize);
return new Rectangle((int)(xtrunc * TileSize) + x * TileSize, (int)(ytrunc * TileSize) + y * TileSize, TileSize, TileSize);
}
public Rectangle getDestinationRectangle(int x, int y, Vector2 Size)
{
Vector2 temp = new Vector2((int)Math.Round(x + RainPosition.X), y + (int)Math.Round(RainPosition.Y));
if (temp.X >= 1999 - Size.X - 1)
temp.X = -(1999 - (int)Math.Round(RainPosition.X));
if (temp.Y >= 1999 - Size.Y - 1)
temp.Y = -(1999 - (int)Math.Round(RainPosition.Y));
return new Rectangle((int)temp.X, (int)temp.Y, 1, 1);
}
public void drawWeatherInformation(SpriteBatch spriteBatch, SpriteFont Bold, Input input)
{
spriteBatch.DrawString(Bold, "WindSpeed: " + Math.Round(WindSpeed.X, 4), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 282), Color.Teal);
spriteBatch.DrawString(Bold, " : ", new Vector2(153, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 282), Color.Teal);
spriteBatch.DrawString(Bold, Math.Round(WindSpeed.Y, 4).ToString(), new Vector2(163, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 282), Color.Teal);
}
public void updateFarm(Vector2 Size)
@ -135,58 +89,13 @@ class Farm
{
for (int j = 0; j < Size.Y; j++)
{
Vector2 temp = new Vector2((int)Math.Round(i + RainPosition.X), j + (int)Math.Round(RainPosition.Y));
if (temp.X >= 1999 - Size.X - 1)
temp.X = i + ((1999 - (int)Math.Round(RainPosition.X)));
if (temp.Y >= 1999 - Size.Y - 1)
temp.Y = i + ((1999 - (int)Math.Round(RainPosition.Y)));
crops[i, j].updateCrop(Size, Time);
crops[i, j].updateRainfall(RainfallMap[(int)Math.Round(temp.X)][(int)Math.Round(temp.Y)].GetBrightness());
crops[i, j].updateCrop(Size);
}
}
Update = 0;
}
updateRainMapPosition(Size);
if (productionUpdate == 2)
{
nextUpdate = updateProgress + updatePerc;
for (int i = (int)(updateProgress * Size.X); i < nextUpdate * Size.X; i++)
{
for (int j = 0; j < Size.Y; j++)
{
if (crops[i, j].getStatus() > 1)
{
int x = getHighestProductionRate(i, j);
crops[i, j].setCropType(x, PresetCrops.getPresetCropTypes(x));
crops[i, j].updateProductionRate();
}
}
}
updateProgress = updateProgress + updatePerc;
if (updateProgress >= 1)
{
updateProgress = 0;
}
productionUpdate = 0;
nextUpdate = 0;
}
productionUpdate++;
}
public void updateRainFall(Vector2 Size, DayNightCycle nTime)
{
Time = nTime;
if (nTime.nDay())
{
for (int i = 0; i < Size.X; i++)
{
for (int j = 0; j < Size.Y; j++)
{
crops[i, j].setPrevRainfall();
}
}
}
}
//Changes the properties of the tile when the tractor reaches this tile.
@ -220,42 +129,6 @@ class Farm
return crops;
}
private void updateRainMapPosition(Vector2 Size)
{
double x, y;
x = WindSpeed.X + GetRandomNumber(-1f, 1f) / 20000;
y = WindSpeed.Y + GetRandomNumber(-1f, 1f) / 20000;
if (x <= 0.02f && x >= -0.02f)
{
WindSpeed.X = (float)x;
}
if (y < 0.02f && y > -0.02f)
{
WindSpeed.Y = (float)y;
}
if (WindSpeed.X > 0 && RainPosition.X < 2000)
RainPosition.X = RainPosition.X + WindSpeed.X;
else if (WindSpeed.X < 0 && RainPosition.X > 0)
RainPosition.X = RainPosition.X + WindSpeed.X;
if (WindSpeed.Y > 0 && RainPosition.Y < 2000)
RainPosition.Y = RainPosition.Y + WindSpeed.Y;
else if (WindSpeed.Y < 0 && RainPosition.Y > 0)
RainPosition.Y = RainPosition.Y + WindSpeed.Y;
if (Math.Round(RainPosition.X) == 1999 && WindSpeed.X > 0)
RainPosition.X = 0;
else if (Math.Round(RainPosition.X) == 1 && WindSpeed.X < 0)
RainPosition.X = 1999;
if (Math.Round(RainPosition.Y) == 1999 && WindSpeed.Y > 0)
RainPosition.Y = 0;
else if (Math.Round(RainPosition.Y) == 1 && WindSpeed.Y < 0)
RainPosition.Y = 1999;
}
public void setNewHousePos(Vector2 pos, bool newState)
{
crops[(int)pos.X, (int)pos.Y].setHousePos(newState);
@ -263,7 +136,7 @@ class Farm
public CropTypes getPresetCropTypes(int Index)
{
return PresetCrops.getPresetCropTypes(Index);
return PresetCrops.getPresetCropTypes(Index - 1);
}
public void setCropType(int x, int y, int Type)
@ -277,7 +150,7 @@ class Farm
{
for (int j = 0; j < Size.X; j++)
{
if (crops[i, j].getStatus() == 2)
if (crops[i, j].getStatus() != 3)
{
int x = getHighestProductionRate(i, j);
crops[i, j].setCropType(x, PresetCrops.getPresetCropTypes(x));
@ -288,7 +161,7 @@ class Farm
private int getHighestProductionRate(int x, int y)
{
int i = 6, holderIndex = 0;
int i = 1, holderIndex = 0;
float holder = 0, SampleHolder = 0;
do
{
@ -303,47 +176,8 @@ class Farm
return holderIndex;
}
public Color getRainAmount(int x, int y, Color color, Vector2 Size)
{
Vector2 temp = new Vector2(x + (int)Math.Round(RainPosition.X), y + (int)Math.Round(RainPosition.Y));
if (temp.X >= 1999)
temp.X = -(1999 - (int)Math.Round(temp.X));
if (temp.Y >= 1999)
temp.Y = -(1999 - (int)Math.Round(temp.Y));
if (temp.X == -1)
temp.X = 1999;
if (temp.Y == -1)
temp.Y = 1999;
if (RainfallMap[(int)temp.X][(int)temp.Y].GetBrightness() < 0.45f)
{
return Color.FromNonPremultiplied(color.R, color.G, color.B, (int)(0));
}
else
{
return Color.FromNonPremultiplied(color.R, color.G, color.B, (int)(255 * RainfallMap[(int)temp.X][(int)temp.Y].GetBrightness()));
}
}
public float getProductionRate(int x, int y, int Type)
{
return crops[x, y]. getProductionRate(PresetCrops.getPresetCropTypes(Type));
}
public float GetRandomNumber(double minimum, double maximum)
{
return (float)(Math.Round(r.NextDouble() * (maximum - minimum) + minimum, 2));
}
private static string FindPath()
{
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).ToString();
while (true)
{
path = Directory.GetParent(path).ToString();
if (path.EndsWith("\\Game1"))
{
return path;
}
}
return crops[x, y].getProductionRate(PresetCrops.getPresetCropTypes(Type));
}
}

View File

@ -17,13 +17,10 @@ class SoilProperties
public float Nitrogen;
public float Potassium;
public float Phosphorous;
public float Rainfall;
public float prevRainfall;
public float NitrogenDegradeRate = 0.8f / 1.5f;
public float PotassiumDegradeRate = 0.3f / 1.5f;
public float PhosphorousDegradeRate = 0.6f / 1.5f;
public float NitrogenDegradeRate = 1.0f - (1.0f/55 * 40);
public float PotassiumDegradeRate = 1.0f - (1.0f/28 * 23);
public float PhosphorousDegradeRate = 1.0f - (1.0f/60 * 37);
public int Capacity = 80;
public int Area;
public void setSoilProperties()
{
@ -54,8 +51,6 @@ class SoilProperties
Nitrogen = GetRandomNumber(4 , 42); //was 4, 60
Potassium = GetRandomNumber(0.01f, 19); // was 0, 28
Phosphorous = GetRandomNumber(0.01f, 42); // was 0, 60
prevRainfall = r.Next(247, 3617);
Area = r.Next(1, 270000);
}
public float GetRandomNumber(double minimum, double maximum)

View File

@ -10,7 +10,6 @@ static class Engine
{
private static MLContext mlContext = new MLContext(seed: 1);
private static PredictionEngine<ModelInput, ModelOutput> PredictionEngine;
private static ModelOutput modelOutput;
public static void init()
{
@ -31,9 +30,7 @@ static class Engine
Phosporous = crop.getSoilProperties().Phosphorous
};
//ModelOutput modelOutput = new ModelOutput();
PredictionEngine.Predict(modelInput, ref modelOutput);
return modelOutput.Prediction;
return PredictionEngine.Predict(modelInput).Prediction;
}
}

View File

@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ML;
@ -12,16 +11,12 @@ using Microsoft.ML.Trainers.LightGbm;
class MLModel
{
private static MLContext mlContext = new MLContext(seed: 1);
private static string path_base = FindPath();
private static string path = System.IO.Path.Combine(path_base, "Content/ML/Fertilizer_Prediction.csv");
private static string modelpath = System.IO.Path.Combine(path_base, "Content/ML/MLmodel");
private static string report = System.IO.Path.Combine(path_base, "Content/ML/report");
private static string pathBig = System.IO.Path.Combine(path_base, "Content/ML/BigFertPredict.csv");
private static string modelpathBig = System.IO.Path.Combine(path_base, "Content/ML/MLmodelBig");
private static string reportBig = System.IO.Path.Combine(path_base, "Content/ML/report_BigModel");
private static string path = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/Fertilizer_Prediction.csv";
private static string modelpath = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodel";
private static string report = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report";
private static string pathBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/BigFertPredict.csv";
private static string modelpathBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodelBig";
private static string reportBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report_BigModel";
// Loading data, creatin and saving ML model for smaller dataset (100)
public static void CreateModel()
@ -162,25 +157,11 @@ class MLModel
return mlContext.Model.Load(modelpath, out DataViewSchema inputSchema);
}
public static PredictionEngine<ModelInput, ModelOutput> CreateEngine()
public static Microsoft.ML.PredictionEngine<ModelInput, ModelOutput> CreateEngine()
{
ITransformer mlModel = LoadModel(false);
return mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(mlModel);
}
private static string FindPath()
{
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).ToString();
while (true)
{
path = Directory.GetParent(path).ToString();
if (path.EndsWith("\\Game1"))
{
return path;
}
}
}
}

View File

@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ML.Data;
namespace Game1.Sources.ML_Joel
{
class Input
{
[ColumnName("Season"), LoadColumn(0)]
public String Season { get; set; }
[ColumnName("Crop"), LoadColumn(1)]
public String Crop { get; set; }
[ColumnName("Rainfall"), LoadColumn(2)]
public float Rainfall { get; set; }
[ColumnName("Production"), LoadColumn(3)]
public float Production { get; set; }
}
}

View File

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ML.Data;
namespace Game1.Sources.ML_Joel
{
class InputArea
{
[ColumnName("Season"), LoadColumn(0)]
public String Season { get; set; }
[ColumnName("Crop"), LoadColumn(1)]
public String Crop { get; set; }
[ColumnName("Area"), LoadColumn(2)]
public float Area { get; set; }
[ColumnName("Rainfall"), LoadColumn(3)]
public float Rainfall { get; set; }
[ColumnName("Production"), LoadColumn(4)]
public float Production { get; set; }
}
}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ML.Data;
namespace Game1.Sources.ML_Joel
{
class Output
{
//[ColumnName("PredictedLabel")]
public float Prediction { get; set; }
public float Score { get; set; }
//[ColumnName("Score")]
// public float[] Score { get; set; }
}
}

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ML.Data;
namespace Game1.Sources.ML_Joel
{
class OutputArea
{
public float Prediction { get; set; }
public float Score { get; set; }
}
}

View File

@ -1,55 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ML;
namespace Game1.Sources.ML_Joel
{
static class Engine
{
private static MLContext mlContext = new MLContext(seed: 1);
private static PredictionEngine<Input, Output> PredictionEngine;
private static PredictionEngine<InputArea, OutputArea> PredictionEngineArea;
private static OutputArea modelOutput;
public static void CreateModel()
{
Model.CreateModel();
}
public static void CreateModelArea()
{
Model.CreateModelArea();
}
public static void init()
{
PredictionEngine = Model.CreateEngine();
}
public static void initArea()
{
PredictionEngineArea = Model.CreateEngineArea();
}
public static float PredictProductionwithRainfall(SoilProperties soilProperties, DayNightCycle Time)
{
InputArea modelInput = new InputArea
{
Season = Time.getTimeOfYear(),
Area = soilProperties.Area,
Rainfall = soilProperties.prevRainfall,
};
//OutputArea modelOutput = new OutputArea();
PredictionEngineArea.Predict(modelInput, ref modelOutput);
return modelOutput.Score;
}
}
}

View File

@ -1,190 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.ML.Trainers.LightGbm;
namespace Game1.Sources.ML_Joel
{
class Model
{
private static MLContext mlContext = new MLContext(seed: 1);
private static string path_base = FindPath();
private static string path = System.IO.Path.Combine(path_base, "Content/ML/Rainfall.csv");
private static string modelpath = System.IO.Path.Combine(path_base, "Content/ML/MLmodel_Joel");
private static string report = System.IO.Path.Combine(path_base, "Content/ML/report_Joel");
private static string path_area = System.IO.Path.Combine(path_base, "Content/ML/Rainfall_area.csv");
private static string modelpath_area = System.IO.Path.Combine(path_base, "Content/ML/MLmodel_Joel_area");
private static string report_area = System.IO.Path.Combine(path_base, "Content/ML/report_Joel_area");
// Loading data, creatin and saving ML model for smaller dataset (100)
public static void CreateModel()
{
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<Input>(
path: path,
hasHeader: true,
separatorChar: ',',
allowQuoting: true,
allowSparse: false);
var splitData = mlContext.Data.TrainTestSplit(trainingDataView, testFraction: 0.2);
trainingDataView = splitData.TrainSet;
IDataView testDataView = splitData.TestSet;
Input sample = mlContext.Data.CreateEnumerable<Input>(trainingDataView, false).ElementAt(0);
ITransformer MLModel = BuildAndTrain(mlContext, trainingDataView, testDataView, sample, report);
SaveModel(mlContext, MLModel, modelpath, trainingDataView.Schema);
}
// Building and training ML model
public static ITransformer BuildAndTrain(MLContext mLContext, IDataView trainingDataView, IDataView testDataView, Input sample, string reportPath)
{
var options = new LightGbmRegressionTrainer.Options
{
MaximumBinCountPerFeature = 40,
LearningRate = 0.00020,
NumberOfIterations = 20000,
NumberOfLeaves = 55,
LabelColumnName = "Production",
FeatureColumnName = "Features",
Booster = new DartBooster.Options()
{
MaximumTreeDepth = 10
}
};
var pipeline = mlContext.Transforms
.Text.FeaturizeText("SeasonF", "Season")
.Append(mlContext.Transforms.Text.FeaturizeText("CropF", "Crop"))
.Append(mlContext.Transforms.Concatenate("Features", "SeasonF", "CropF", "Rainfall"))
.AppendCacheCheckpoint(mLContext)
.Append(mLContext.Regression.Trainers.LightGbm(options));
ITransformer MLModel = pipeline.Fit(trainingDataView);
var testEval = MLModel.Transform(testDataView);
Evaluate(mlContext, testEval, pipeline, 10, reportPath, "Production");
return MLModel;
}
public static void CreateModelArea()
{
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<InputArea>(
path: path_area,
hasHeader: true,
separatorChar: ',',
allowQuoting: true,
allowSparse: false);
var splitData = mlContext.Data.TrainTestSplit(trainingDataView, testFraction: 0.2);
trainingDataView = splitData.TrainSet;
IDataView testDataView = splitData.TestSet;
ITransformer MLModel = BuildAndTrainArea(mlContext, trainingDataView, testDataView, report_area);
SaveModel(mlContext, MLModel, modelpath_area, trainingDataView.Schema);
}
// Building and training ML model
public static ITransformer BuildAndTrainArea(MLContext mLContext, IDataView trainingDataView, IDataView testDataView, string reportPath)
{
var options = new LightGbmRegressionTrainer.Options
{
MaximumBinCountPerFeature = 40,
LearningRate = 0.00020,
NumberOfIterations = 20000,
NumberOfLeaves = 55,
LabelColumnName = "Production",
FeatureColumnName = "Features",
Booster = new DartBooster.Options()
{
MaximumTreeDepth = 10
}
};
var pipeline = mlContext.Transforms
.Text.FeaturizeText("SeasonF", "Season")
.Append(mlContext.Transforms.Text.FeaturizeText("CropF", "Crop"))
.Append(mlContext.Transforms.Concatenate("Features", "SeasonF", "CropF", "Area", "Rainfall"))
.AppendCacheCheckpoint(mLContext)
.Append(mLContext.Regression.Trainers.LightGbm(options));
ITransformer MLModel = pipeline.Fit(trainingDataView);
var testEval = MLModel.Transform(testDataView);
Evaluate(mlContext, testEval, pipeline, 10, reportPath, "Production");
return MLModel;
}
public static ITransformer TrainModel(MLContext mlContext, IDataView trainingDataView, IEstimator<ITransformer> trainingPipeline)
{
ITransformer model = trainingPipeline.Fit(trainingDataView);
return model;
}
// Evaluate and save results to a text file
public static void Evaluate(MLContext mlContext, IDataView trainingDataView, IEstimator<ITransformer> trainingPipeline, int folds, string reportPath, string labelColumnName)
{
var eval = mlContext.Regression.Evaluate(trainingDataView, labelColumnName: labelColumnName);
var report = File.CreateText(reportPath);
report.Write("Mean Absolute Error: " + eval.MeanAbsoluteError + '\n' + "R Squared: " + eval.RSquared, 0, 0);
report.Flush();
report.Close();
}
public static void SaveModel(MLContext mlContext, ITransformer Model, string modelPath, DataViewSchema modelInputSchema)
{
mlContext.Model.Save(Model, modelInputSchema, modelPath);
}
public static ITransformer LoadModel()
{
return mlContext.Model.Load(modelpath, out DataViewSchema inputSchema);
}
public static PredictionEngine<Input, Output> CreateEngine()
{
ITransformer mlModel = LoadModel();
return mlContext.Model.CreatePredictionEngine<Input, Output>(mlModel);
}
public static ITransformer LoadModelArea()
{
return mlContext.Model.Load(modelpath_area, out DataViewSchema inputSchema);
}
public static PredictionEngine<InputArea, OutputArea> CreateEngineArea()
{
ITransformer mlModel = LoadModelArea();
return mlContext.Model.CreatePredictionEngine<InputArea, OutputArea>(mlModel);
}
private static string FindPath()
{
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).ToString();
while(true)
{
path = Directory.GetParent(path).ToString();
if (path.EndsWith("\\Game1"))
{
return path;
}
}
}
}
}

View File

@ -8,30 +8,22 @@ using Microsoft.Xna.Framework;
class DayNightCycle
{
private bool Time = true;
private bool Day = true;
private int nightTime = 0;
private int dayTime = 0;
private int lengthOfDay = 20000;
private int lengthOfNight = 20000;
private int Days = 1;
private int DaysOfYear = 0;
private int speed = 1;
private bool nextDay = true;
private int Days = 1;
public void updateTime(int Speed)
{
speed = Speed;
Time = false;
for (int i = 0; i < Speed; i++)
{
if (Day)
if (Time)
{
dayTime++;
if (dayTime == lengthOfDay)
{
Time = false;
Day = false;
dayTime = 0;
}
}
@ -41,47 +33,32 @@ class DayNightCycle
if (nightTime == lengthOfNight)
{
Time = true;
Day = true;
nightTime = 0;
Days++;
DaysOfYear++;
}
}
if (DaysOfYear == 48)
{
DaysOfYear = 0;
}
}
}
//Season:
//0 - Whole Year
//1 - Spring
//2 - Summer
//3 - Autumn
//4 - Winter
public string getTimeOfYear()
public string getDayNight()
{
if (DaysOfYear < 12)
return "Spring";
else if (DaysOfYear < 24)
return "Summer";
else if (DaysOfYear < 36)
return "Autumn";
if (Time)
{
return "Day";
}
else
return "Winter";
{
return "Night";
}
}
public Color GetTimeOfDay()
{
int blue, red, brightness, green, potatorate = 255;
int blue, red, brightness;
if (nightTime == 0 && dayTime == 0)
{
red = 1;
blue = 1;
green = 1;
brightness = 1;
}
@ -89,29 +66,20 @@ class DayNightCycle
{
if ((float)dayTime / lengthOfDay < 0.5)
{
blue = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)((1.0f - (float)dayTime / lengthOfDay) * potatorate);
blue = (int)(((float)nightTime / lengthOfNight) * 255) + (int)((1.0f - (float)dayTime / lengthOfDay) * 255);
}
else
{
blue = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
blue = (int)(((float)nightTime / lengthOfNight) * 255) + (int)(((float)dayTime / lengthOfDay) * 255);
}
if ((float)nightTime / lengthOfNight < 0.5)
{
red = (int)((1.0 - (float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
red = (int)((1.0 - (float)nightTime / lengthOfNight) * 255) + (int)(((float)dayTime / lengthOfDay) * 255);
}
else
{
red = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
}
if ((float)nightTime / lengthOfNight < 0.5)
{
green = (int)((1.0 - (float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
}
else
{
green = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
red = (int)(((float)nightTime / lengthOfNight) * 255) + (int)(((float)dayTime / lengthOfDay) * 255);
}
if (Time)
@ -130,20 +98,13 @@ class DayNightCycle
}
}
}
return Color.FromNonPremultiplied(red, green, blue, 255);
}
public bool nDay()
{
if (Time)
return true;
else
return false;
return Color.FromNonPremultiplied(red, 255, blue, brightness);
}
public int GetTimeOfDayInt()
{
if (Day)
if (Time)
{
return (int)(100 * ((float)(dayTime + nightTime) / (lengthOfDay + lengthOfNight))) + 1;
}

View File

@ -16,72 +16,72 @@ class FertilizerHolder
{
ID = 999,
Name = "None",
Nitrogen = 0.0f / 2,
Phosphorus = 0 * 0.436f / 2,
Potassium = 0 * 0.83f / 2
Nitrogen = 0.0f / 5,
Phosphorus = 0 * 0.436f / 5,
Potassium = 0 * 0.83f / 5
};
FertilizerType[1] = new Fertilizer
{
ID = 0,
Name = "10-26-26",
Nitrogen = 10.0f / 2,
Phosphorus = 26 * 0.436f / 2,
Potassium = 26 * 0.83f / 2
Nitrogen = 10.0f / 5,
Phosphorus = 26 * 0.436f / 5,
Potassium = 26 * 0.83f / 5
};
FertilizerType[2] = new Fertilizer
{
ID = 1,
Name = "14-35-14",
Nitrogen = 14.0f / 2,
Phosphorus = 35 * 0.436f / 2,
Potassium = 14 * 0.83f / 2
Nitrogen = 14.0f / 5,
Phosphorus = 35 * 0.436f / 5,
Potassium = 14 * 0.83f / 5
};
FertilizerType[3] = new Fertilizer
{
ID = 2,
Name = "17-17-17",
Nitrogen = 17.0f / 2,
Phosphorus = 17 * 0.436f / 2,
Potassium = 17 * 0.83f / 2
Nitrogen = 17.0f / 5,
Phosphorus = 17 * 0.436f / 5,
Potassium = 17 * 0.83f / 5
};
FertilizerType[4] = new Fertilizer
{
ID = 3,
Name = "20-20",
Nitrogen = 20.0f / 2,
Phosphorus = 20 * 0.436f / 2,
Potassium = 0 * 0.83f / 2
Nitrogen = 20.0f / 5,
Phosphorus = 20 * 0.436f / 5,
Potassium = 0 * 0.83f / 5
};
FertilizerType[5] = new Fertilizer
{
ID = 4,
Name = "28-28",
Nitrogen = 28.0f / 2,
Phosphorus = 28 * 0.436f / 2,
Potassium = 0 * 0.83f / 2
Nitrogen = 28.0f / 5,
Phosphorus = 28 * 0.436f / 5,
Potassium = 0 * 0.83f / 5
};
FertilizerType[6] = new Fertilizer
{
ID = 5,
Name = "DAP",
Nitrogen = 18.0f / 2,
Phosphorus = 46 * 0.436f / 2,
Potassium = 0 * 0.83f / 2
Nitrogen = 18.0f / 5,
Phosphorus = 46 * 0.436f / 5,
Potassium = 0 * 0.83f / 5
};
FertilizerType[7] = new Fertilizer
{
ID = 6,
Name = "Urea",
Nitrogen = 46.0f / 2,
Phosphorus = 0 * 0.436f / 2,
Potassium = 0 * 0.83f / 2
Nitrogen = 46.0f / 5,
Phosphorus = 0 * 0.436f / 5,
Potassium = 0 * 0.83f / 5
};
}
*/
@ -89,72 +89,72 @@ class FertilizerHolder
{
ID = 999,
Name = "None",
Nitrogen = 0.0f / 2,
Phosphorus = 0 * 0.436f / 2,
Potassium = 0 * 0.83f / 2
Nitrogen = 0.0f / 5,
Phosphorus = 0 * 0.436f / 5,
Potassium = 0 * 0.83f / 5
};
FertilizerType[1] = new Fertilizer
{
ID = 0,
Name = "10-26-26",
Nitrogen = 17.21f / 2,
Phosphorus = 12.14f / 2,
Potassium = 0.64f / 2
Nitrogen = 17.21f / 5,
Phosphorus = 12.14f / 5,
Potassium = 0.64f / 5
};
FertilizerType[2] = new Fertilizer
{
ID = 1,
Name = "14-35-14",
Nitrogen = 16.89f / 2,
Phosphorus = 6.21f / 2,
Potassium = 5.21f / 2
Nitrogen = 16.89f / 5,
Phosphorus = 6.21f / 5,
Potassium = 5.21f / 5
};
FertilizerType[3] = new Fertilizer
{
ID = 2,
Name = "17-17-17",
Nitrogen = 14.92f / 2,
Phosphorus = 14.42f / 2,
Potassium = 3.0f / 2
Nitrogen = 14.92f / 5,
Phosphorus = 14.42f / 5,
Potassium = 3.0f / 5
};
FertilizerType[4] = new Fertilizer
{
ID = 3,
Name = "20-20",
Nitrogen = 15.39f / 2,
Phosphorus = 15.21f / 2,
Potassium = 9.5f / 2
Nitrogen = 15.39f / 5,
Phosphorus = 15.21f / 5,
Potassium = 9.5f / 5
};
FertilizerType[5] = new Fertilizer
{
ID = 4,
Name = "28-28",
Nitrogen = 9.67f / 2,
Phosphorus = 10.47f / 2,
Potassium = 9.5f / 2
Nitrogen = 9.67f / 5,
Phosphorus = 10.47f / 5,
Potassium = 9.5f / 5
};
FertilizerType[6] = new Fertilizer
{
ID = 5,
Name = "DAP",
Nitrogen = 14.52f / 2,
Phosphorus = 1.77f / 2,
Potassium = 9.5f / 2
Nitrogen = 14.52f / 5,
Phosphorus = 1.77f / 5,
Potassium = 9.5f / 5
};
FertilizerType[7] = new Fertilizer
{
ID = 6,
Name = "Urea",
Nitrogen = 1.81f / 2,
Phosphorus = 21.0f / 2,
Potassium = 9.5f / 2
Nitrogen = 1.81f / 5,
Phosphorus = 21.0f / 5,
Potassium = 9.5f / 5
};
}

View File

@ -7,7 +7,7 @@ using System.Threading.Tasks;
class Cargo
{
private Items[,] items = new Items[2, 281];
private Items[,] items = new Items[2, 351];
private int[] Count = new int[2];

View File

@ -11,12 +11,11 @@ using Microsoft.Xna.Framework.Input;
class Inventory
{
private int Weight = 0;
private int maxWeight = 280;
private int maxWeight = 350;
private int[] totalHarvested = new int[11];
private int[] totalFertilizerUsed = new int[8];
private Cargo cargo = new Cargo();
private Cargo itemStorage = new Cargo();
private int Refills = 0;
// Item list by index:
// ---------------------------------------
@ -129,64 +128,18 @@ class Inventory
for (int i = 0; i <= 10; i++)
while (useItem(i, 1, true)) ;
}
public void fillWithFertilizer()
{
Refills++;
int fert_amount = 7;
float weightPerFertilizer = maxWeight / fert_amount;
float min = weightPerFertilizer / 10;
float max = (2 * weightPerFertilizer) - min;
float expectedUse = Refills * weightPerFertilizer;
double[] useFactor = new double[fert_amount];
for (int i = 0; i < fert_amount; i++)
int i = 0;
while (getWeight() < getMaxWeight())
{
if (Refills <= 1)
useFactor[i] = weightPerFertilizer;
else
if (totalFertilizerUsed[i] / expectedUse + 0.85f > 1.0f)
useFactor[i] = Math.Round(Math.Pow((totalFertilizerUsed[i] / expectedUse) + 0.50f, 0.6f + Math.Min(Refills / 6.0f, 1.0f)) * weightPerFertilizer);
else
useFactor[i] = Math.Round(Math.Pow((totalFertilizerUsed[i] / expectedUse) + 0.50f, 1.0f + Math.Min(Refills / 6.0f, 1.8f)) * weightPerFertilizer);
if (useFactor[i] < min)
useFactor[i] = min;
else if (useFactor[i] > max)
useFactor[i] = max;
if (i > 6)
i = 0;
addItem(i, 0);
i++;
}
int j = 0;
bool change = false;
while (getWeight() < getMaxWeight() - fert_amount)
{
if (useFactor[j] > 0)
{
addItem(j, 0);
useFactor[j]--;
change = true;
}
j++;
if (j >= fert_amount)
{
if (!change)
break;
else
{
j = 0;
change = false;
}
}
}
int m = 0;
while (getWeight() < getMaxWeight()- fert_amount)
{
if (m > 6)
m = 0;
addItem(m, 0);
m++;
}
}
public bool isMissingFertilizer()
@ -206,16 +159,16 @@ class Inventory
spriteBatch.DrawString(Bold, "Harvested:", new Vector2(600, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
for (int i = 0; i < 11; i++) //Print Crops
{
spriteBatch.DrawString(Bold, cargo.getCount(i, 1) + " " + itemStorage.getItemByIndex(i, 1).getItemType(), new Vector2(470, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
spriteBatch.DrawString(Bold, totalHarvested[i].ToString(), new Vector2(620, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
spriteBatch.DrawString(Bold, cargo.getCount(i, 1) + " " + itemStorage.getItemByIndex(i, 1).getItemType(), new Vector2(470, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.DarkBlue);
spriteBatch.DrawString(Bold, totalHarvested[i].ToString(), new Vector2(620, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.DarkBlue);
}
spriteBatch.DrawString(Bold, "Fertilizers: ", new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
spriteBatch.DrawString(Bold, "Used ", new Vector2(830, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
for (int i = 0; i < 7; i++) //Print Fertilizers
{
spriteBatch.DrawString(Bold, cargo.getCount(i, 0) + " " + itemStorage.getItemByIndex(i, 0).getItemType(), new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
spriteBatch.DrawString(Bold, totalFertilizerUsed[i].ToString(), new Vector2(835, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
spriteBatch.DrawString(Bold, cargo.getCount(i, 0) + " " + itemStorage.getItemByIndex(i, 0).getItemType(), new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.DarkBlue);
spriteBatch.DrawString(Bold, totalFertilizerUsed[i].ToString(), new Vector2(835, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.DarkBlue);
}

View File

@ -6,10 +6,11 @@ class Tractor
{
private int Spacing, sizeTile, Speed = 1;
private float tractorSpeed = 1;
private Vector2 Position, TargetPosition, Size, housePos, DeltaPosition;
private Vector2 Position, TargetPosition, Size, housePos, oldDeltaPosition, DeltaPosition;
private Path path = new Path();
private SmartTractor smartTractor = new SmartTractor();
private HandleRotation handleRotation = new HandleRotation();
private int WaitFrame = 30;
private int j;
@ -21,7 +22,8 @@ class Tractor
Size = input.getSize();
updatePosition(input.getSize(), Status);
housePos = newHousePos;
smartTractor.UpdateCrops(Speed, Time);
smartTractor.UpdateCrops(Speed);
}
public void init(Rectangle house, Input input)

View File

@ -54,16 +54,11 @@ class AI
int testsize = 2;
Path newTarget;
Nodes nodes;
Random random = new Random();
if (astar.GetAdjacentNodes(tractorPos).Count == 0)
nodes = new Nodes(housePos);
else
{
List<Nodes> templist = astar.GetAdjacentNodes(tractorPos);
nodes = templist[random.Next(0, templist.Count())];
templist.Clear();
}
nodes = astar.GetAdjacentNodes(tractorPos)[0];
if (tractorPos != housePos)
if (inventory.getWeight() == inventory.getMaxWeight() || inventory.isMissingFertilizer())
@ -173,7 +168,7 @@ class AI
saturationScore = -100;
}
return score + (-aproxDistance * 10) + statusScore + timerScore + saturationScore;
return score + (-aproxDistance * 5) + statusScore + timerScore + saturationScore;
}
private float norm(float min, float max, float val)

View File

@ -16,9 +16,8 @@ class SmartTractor
//What to do next
public Path returnChoice()
{
//System.Threading.ThreadStart tractorThread = new System.Threading.ThreadStart(farm.UpdatePreferedCrops);
ai.update(farm, Size, tractorPos / (tileSize + Spacing), housePos / (tileSize + Spacing), Target / (tileSize + Spacing), Rotation);
//farm.UpdatePreferedCrops(Size);
farm.UpdatePreferedCrops(Size);
farm = ai.changeCropStatus();
astar.update(farm.getCrops(), Size, tractorPos / (tileSize + Spacing), housePos / (tileSize + Spacing), Rotation);
//getTargetPosition(ai.newTarget());
@ -44,6 +43,7 @@ class SmartTractor
tileSize = newTileSize;
Spacing = newSpacing;
Rotation = rotation;
}
public void init(Vector2 nHousePos)
@ -51,7 +51,6 @@ class SmartTractor
ai.init();
housePos = nHousePos;
farm.init(new Vector2(100, (GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height / tileSize) - 125 / tileSize), housePos / (tileSize + Spacing));
farm.UpdatePreferedCrops(Size);
}
public void drawInventory(Input input, SpriteBatch spriteBatch, SpriteFont Bold, Cargo itemStorageDefined)
@ -74,13 +73,12 @@ class SmartTractor
farm.setNewHousePos(pos, newState);
}
public void UpdateCrops(int Speed, DayNightCycle nTime)
public void UpdateCrops(int Speed)
{
for (int i = 0; i < Speed; i++)
{
farm.updateFarm(Size);
}
farm.updateRainFall(Size, nTime);
}
public Inventory getInventory()

View File

@ -1,103 +0,0 @@
Machine Learning Implementation
Introduction
I have implemented a ML to add in season, daily rainfall and area which can be cultivated into the Productivity rate of each crop. This dataset contains over 65000 entries of which we only use around 20000 as those are the only crops that are plantable for our agen and the lowest amount of entries for a single crop is 600. The daily rainfall has been added to SoilProperties in our tileset. Implementation of the needed properties into SoilProperties:
public float Rainfall;
public float prevRainfall;
public int Area;
.
.
.
//Randomize the first days rainfall and the area,
prevRainfall = r.Next(247, 3617);
Area = r.Next(1, 270000);
The dataset is said to be based on real life data. But for our our program is not able to fit the data 1 to 1 because some Crops only had an daily rainfall from 247 to 2000 but the Rainfall of that tile could still be 3617. I havent done anything to mitigate this but it doesnt result in any strange results when passing through our data into the ML Model. It would have been better for the dataset contained rainfall data from 247 to 3617. Then the yield could possibly be lower or higher as rainfall increases or decreases. We added dynamic rainfall in is therefore constricting the rain from going outside of the datasets parameters:
//Sets previous days rainfall to current days rainfall and constrict the total rainfall from going outside of the parameters
soilProperties.prevRainfall = soilProperties.Rainfall;
if (soilProperties.prevRainfall > 3616)
soilProperties.prevRainfall = 3616;
else if (soilProperties.prevRainfall < 236)
soilProperties.prevRainfall = 236;
soilProperties.Rainfall = 0;
Implementation
I have used gradient boosting decision tree algorithm due to the features.
I used Gradient Boosting Decision Tree Algorithm for this task due to many features it has.
First a csv file is loaded:
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<ModelInput>(
path: path,
hasHeader: true,
separatorChar: ',',
allowQuoting: true,
allowSparse: false);
Then it is passed to next function which will train, evaluate and build a model:
- maximizing number of leaves,
- limiting maximum tree depth,
- maximizing the amount of bins per feature,
maintaining high accuracy by:
- low learning rate combine with:
- high number of iterations.
Creating pipeline for the model:
var pipeline = mlContext.Transforms
.Text.FeaturizeText("SeasonF", "Season")
.Append(mlContext.Transforms.Text.FeaturizeText("CropF", "Crop"))
.Append(mlContext.Transforms.Concatenate("Features", "SeasonF", "CropF", "Area", "Rainfall"))
.AppendCacheCheckpoint(mLContext)
.Append(mLContext.Regression.Trainers.LightGbm(options));
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel", "PredictedLabel"));
Integration
Our tileset now has a dynamically moving overlay of clouds moving at the speed of WindSpeed and if the clouds are above at a tile we add to the total rainfall of the day. The rainfall we pass into the ML Model is the previous days rainfall and the first days rainfall is randomized.
We achieved this rainsystem by running a bitmap over our tileset, the bitmap is continues with itself so it runs seamlessly. Depending on the ransparency of each pixel on this bitmap we determine how much it is currently raining on set tile:
if (Rain >= 0.45f)
{
soilProperties.Rainfall = soilProperties.Rainfall + Rain * 4;
}
if the transparency is < 0.45 then there will be no cloud drawn and it will not be raining at all. And this is the result:
(https://git.wmi.amu.edu.pl/s425077/PotatoPlan/raw/Oskar-ML/Example.jpg)
To optimize the program we now update 10% of the columns every second or else it would freeze for seconds at a time and the ML Model is only being fed data once a day as the total rainfall is only updated once a day anyways.