-
Notifications
You must be signed in to change notification settings - Fork 0
/
new_start_second_version.sql
305 lines (262 loc) · 11.6 KB
/
new_start_second_version.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
CREATE SCHEMA IF NOT EXISTS custom;
CREATE TABLE IF NOT EXISTS custom.contracts
(
id integer,
status varchar,
start_island integer,
vendor_id integer,
end_island integer,
customer_id integer,
item integer,
offer_buy integer,
buy_flag bool,
offer_sell integer,
sell_flag bool,
quantity double precision
);
CREATE TABLE IF NOT EXISTS custom.tasks
(
id integer,
status varchar,
ship integer,
contract_id integer
);
CREATE SEQUENCE contracts_id_seq START 1;
CREATE SEQUENCE tasks_id_seq START 1;
create function rejectContract() RETURNS TRIGGER AS $reject_contract$
declare
contract record;
exist_reject_buy bool;
exist_reject_sell bool;
begin
select exists (select * from custom.contracts t where t.offer_buy = new.offer) into exist_reject_buy;
select exists (select * from custom.contracts t where t.offer_sell = new.offer) into exist_reject_sell;
if exist_reject_buy THEN
select * from custom.contracts t where t.offer_buy = new.offer INTO contract;
update custom.contracts t set buy_flag = false where t.id = contract.id;
elsif exist_reject_sell THEN
select * from custom.contracts t where t.offer_sell = new.offer INTO contract;
update custom.contracts t set sell_flag = false where t.id = contract.id;
end if;
call update_contract_status(contract.id);
return new;
end
$reject_contract$ language plpgsql;
create trigger reject_contract after insert on events.offer_rejected
for each row
execute procedure rejectContract();
create function acceptContract() RETURNS TRIGGER AS $accept_contract$
declare
contract record;
exist_accept_buy bool;
exist_accept_sell bool;
begin
select exists (select * from custom.contracts t where t.offer_buy = new.offer) into exist_accept_buy;
select exists (select * from custom.contracts t where t.offer_sell = new.offer) into exist_accept_sell;
if exist_accept_buy THEN
select * from custom.contracts t where t.offer_buy = new.offer INTO contract;
update custom.contracts t set buy_flag = true where t.id = contract.id;
elsif exist_accept_sell THEN
select * from custom.contracts t where t.offer_sell = new.offer INTO contract;
update custom.contracts t set sell_flag = true where t.id = contract.id;
end if;
call update_contract_status(contract.id);
return new;
end
$accept_contract$ language plpgsql;
create trigger accept_contract after insert on events.contract_started
for each row
execute procedure acceptContract();
CREATE PROCEDURE update_contract_status(contract_id integer) LANGUAGE PLPGSQL AS $$
declare
contract record;
begin
select * from custom.contracts t where t.id = contract_id INTO contract;
IF contract.buy_flag AND contract.sell_flag THEN
update custom.contracts t set status = 'ACTIVE' where t.id = contract.id;
elsif contract.buy_flag AND not contract.sell_flag then
update custom.contracts t set status = 'BROKEN' where t.id = contract.id;
elsif not contract.buy_flag AND contract.sell_flag then
update custom.contracts t set status = 'BROKEN' where t.id = contract.id;
elsif not contract.buy_flag AND not contract.sell_flag then
update custom.contracts t set status = 'REJECTED' where t.id = contract.id;
END IF;
END $$;
CREATE PROCEDURE think(player_id INTEGER) LANGUAGE PLPGSQL AS $$
declare
activeContracts integer;
needCreateContracts integer;
existBrokenContracts bool;
existActiveContracts bool;
contract record;
currentTime double precision;
begin
select count(*) from custom.contracts where status in ('ACTIVE', 'NEW') into activeContracts;
if activeContracts > 0 then
call manage(player_id);
end if;
for contract in select * from custom.contracts where status = 'BROKEN'
loop
call try_fix(player_id, contract);
end loop;
select count(*) from custom.contracts where status in ('ACTIVE', 'NEW') into activeContracts;
needCreateContracts = 5 - activeContracts;
for cnt in 0..needCreateContracts loop
call research(player_id);
end loop;
SELECT exists (select * from custom.contracts where status in ('ACTIVE', 'NEW')) into existActiveContracts;
IF not existActiveContracts THEN
select game_time into currentTime from world.global;
insert into actions.wait values (nextval('actions.wait_id_seq'), currentTime + 10);
END IF;
END $$;
CREATE PROCEDURE manage(player_id INTEGER) LANGUAGE PLPGSQL AS $$
declare
contract record;
begin
for contract in select * from custom.contracts where status = 'ACTIVE'
loop
call handle_contract(player_id, contract);
end loop;
END $$;
CREATE PROCEDURE handle_contract(player_id INTEGER, contract record) LANGUAGE PLPGSQL AS $$
declare
task record;
moveToLoadComplete bool;
moveToUnLoadComplete bool;
loadComplete bool;
unloadComplete bool;
currentTime double precision;
begin
select * from custom.tasks t where t.contract_id = contract.id into task;
if task is null then
call create_task(player_id, contract);
elsif task.status = 'MOVE_TO_LOAD' then
select exists (select * from events.ship_move_finished where ship = task.ship) into moveToLoadComplete;
if moveToLoadComplete then
insert into actions.transfers values (task.ship, contract.item, contract.quantity, 'load'::actions.transfer_direction);
update custom.tasks t set status = 'LOAD' where t.id = task.id;
end if;
elsif task.status = 'LOAD' then
select exists (select * from events.transfer_completed where ship = task.ship) into loadComplete;
if loadComplete then
insert into actions.ship_moves values (task.ship, contract.end_island);
update custom.tasks t set status = 'MOVE_TO_UNLOAD' where t.id = task.id;
end if;
elsif task.status = 'MOVE_TO_UNLOAD' then
select exists (select * from events.ship_move_finished where ship = task.ship) into moveToUnLoadComplete;
if moveToUnLoadComplete then
insert into actions.transfers values (task.ship, contract.item, contract.quantity, 'unload'::actions.transfer_direction);
update custom.tasks t set status = 'UNLOAD' where t.id = task.id;
end if;
elsif task.status = 'UNLOAD' then
select exists (select * from events.transfer_completed where ship = task.ship) into unloadComplete;
if unloadComplete then
update custom.tasks t set status = 'COMPLETED' where t.id = task.id;
update custom.contracts t set status = 'COMPLETED' where t.id = contract.id;
call research(player_id);
end if;
end if;
END $$;
CREATE PROCEDURE create_task(player_id INTEGER, contract record) LANGUAGE PLPGSQL AS $$
declare
targetIsland record;
bestShip integer;
islandId integer;
island record;
shipsCandidatesId integer[];
distance double precision;
distanceBuffer double precision;
begin
distance = 100000;
select * from world.islands i where i.id = contract.start_island into targetIsland;
select ps.ship from world.parked_ships ps
join world.ships s on ps.ship = s.id where ps.island = contract.start_island
and s.capacity >= contract.quantity and s.player = player_id
AND not EXISTS (SELECT * FROM custom.tasks t WHERE t.ship = ps.ship AND status NOT IN ('COMPLETED','REJECTED'))
order by ps.ship limit 1 into bestShip;
if bestShip is null then
select array (select distinct i.id from world.islands i
join world.parked_ships ps on i.id = ps.island
join world.ships s on s.id = ps.ship where s.capacity >= contract.quantity and s.player = player_id ) into shipsCandidatesId;
foreach islandId in array shipsCandidatesId loop
select * from world.islands where id = islandId into island;
distanceBuffer = sqrt((island.x - targetIsland.x)^2 + (island.y - targetIsland.y)^2);
if distanceBuffer < distance then
distance = distanceBuffer;
select ps.ship from world.parked_ships ps
join world.ships s on ps.ship = s.id where ps.island = islandId
and s.capacity > contract.quantity and s.player = player_id
AND not EXISTS (SELECT * FROM custom.tasks t WHERE t.ship = ps.ship AND status NOT IN ('COMPLETED','REJECTED'))
order by ps.ship limit 1 into bestShip;
end if;
end loop;
if bestShip is not null then
insert into custom.tasks values (nextval('tasks_id_seq'),'MOVE_TO_LOAD', bestShip, contract.id);
insert into actions.ship_moves values (bestShip, targetIsland.id);
END IF;
else
insert into custom.tasks values (nextval('tasks_id_seq'),'LOAD', bestShip, contract.id);
insert into actions.transfers values (bestShip, contract.item, contract.quantity, 'load'::actions.transfer_direction);
end if;
END $$;
CREATE PROCEDURE research(player_id INTEGER) LANGUAGE PLPGSQL AS $$
declare
custOffer integer;
vendOffer integer;
maxQuantity double precision;
customer record;
vendor record;
currentTime double precision;
BEGIN
select game_time into currentTime from world.global;
IF currentTime < 97000 THEN
select s.capacity from world.ships s
WHERE not EXISTS (SELECT * FROM custom.tasks t WHERE t.ship = s.id AND status NOT IN ('COMPLETED','REJECTED'))
order by capacity desc limit 1 into maxQuantity;
select * from world.contractors cust where "type" = 'customer'
and exists (select * from world.contractors vend where "type" = 'vendor' and vend.item = cust.item and vend.price_per_unit < cust.price_per_unit
AND NOT exists (SELECT * FROM custom.contracts ct WHERE ct.vendor_id = vend.id AND status IN ('NEW','ACTIVE', 'BROKEN')))
AND NOT exists (SELECT * FROM custom.contracts ct WHERE ct.customer_id = cust.id AND status IN ('NEW','ACTIVE', 'BROKEN'))
order by price_per_unit desc limit 1 into customer;
select * from world.contractors vend where "type" = 'vendor' and item = customer.item
AND NOT exists (SELECT * FROM custom.contracts ct WHERE ct.vendor_id = vend.id AND status IN ('NEW','ACTIVE', 'BROKEN'))
order by price_per_unit limit 1 into vendor;
if maxQuantity > vendor.quantity then
maxQuantity = vendor.quantity;
end if;
if maxQuantity > customer.quantity then
maxQuantity = customer.quantity;
end if;
IF customer IS NOT NULL or vendor IS NOT NULL then
insert into actions.offers values (nextval('actions.offers_id_seq'), customer.id, maxQuantity) returning id into custOffer;
insert into actions.offers values (nextval('actions.offers_id_seq'), vendor.id, maxQuantity) returning id into vendOffer;
insert into custom.contracts values (nextval('contracts_id_seq'),'NEW', vendor.island, vendor.id, customer.island, customer.id, vendor.item, vendOffer, null, custOffer, null, maxQuantity);
END IF;
END IF;
END $$;
CREATE PROCEDURE try_fix(player_id INTEGER, contract record) LANGUAGE PLPGSQL AS $$
declare
vendor record;
vendOffer integer;
customer record;
custOffer integer;
begin
if not contract.buy_flag then
select * from world.contractors vend where "type" = 'vendor' and item = contract.item and quantity >= contract.quantity
AND NOT exists (SELECT * FROM custom.contracts ct WHERE ct.vendor_id = vend.id AND status IN ('NEW','ACTIVE', 'BROKEN'))
order by price_per_unit limit 1 into vendor;
if vendor is not null then
insert into actions.offers values (nextval('actions.offers_id_seq'), vendor.id, contract.quantity) returning id into vendOffer;
update custom.contracts ctr set start_island = vendor.island, offer_buy = vendOffer WHERE ctr.id = contract.id;
end if;
elsif not contract.sell_flag then
select * from world.contractors cust where "type" = 'customer' and item = contract.item and quantity >= contract.quantity
AND NOT exists (SELECT * FROM custom.contracts ct WHERE ct.customer_id = cust.id AND status IN ('NEW','ACTIVE', 'BROKEN'))
order by price_per_unit desc limit 1 into customer;
if customer is not null then
insert into actions.offers values (nextval('actions.offers_id_seq'), customer.id, contract.quantity) returning id into custOffer;
update custom.contracts ctr set end_island = customer.island, offer_sell = custOffer WHERE ctr.id = contract.id;
end if;
end if;
END $$;