Best Python code snippet using molecule_python
code4life_l4.py
Source:code4life_l4.py
1# https://www.codingame.com/ide/puzzle/code4life2import sys3def print_debug(text):4 print(text, file=sys.stderr)5def cost_minus_cost(cost1, cost2):6 cost = {key: cost1.get(key, 0) - cost2.get(key, 0) for key in set(cost1) | set(cost2)}7 return dict(sorted(cost.items()))8def cost_add_cost(cost1, cost2):9 cost = {key: cost1.get(key, 0) + cost2.get(key, 0) for key in set(cost1) | set(cost2)}10 return dict(sorted(cost.items()))11def remove_zero_cost(cost):12 none_zero_cost = {x: y for x, y in cost.items() if y != 0}13 return none_zero_cost14def replace_neg_cost_with_zero(cost):15 for x, y in cost.items():16 if y < 0:17 cost[x] = 018 return dict(sorted(cost.items()))19def list_minus_list(list1, list2):20 for value in list2:21 list1.remove(value)22 return list123def sort_dict_by_value(dict1, reverse=True):24 return dict(sorted(dict1.items(), key=lambda x: x[1], reverse=reverse))25def get_distance(start, end):26 index_matrix = {27 'START_POS': 0,28 'SAMPLES': 1,29 'DIAGNOSIS': 2,30 'MOLECULES': 3,31 'LABORATORY': 432 }33 start_i = index_matrix[start]34 end_i = index_matrix[end]35 distance_matrix = [36 [0, 2, 2, 2, 2],37 [0, 3, 3, 3, 3],38 [0, 3, 0, 3, 4],39 [0, 3, 3, 0, 3],40 [0, 3, 4, 3, 0]41 ]42 return distance_matrix[start_i][end_i]43def is_sample_diagnosed(s):44 if s['health'] != -1:45 return True46 return False47def dead_lock_samples_id(his_samples, my_expertise, my_storage, molecule_left, all_samples):48 dead_lock_sample_list = []49 if len(his_samples) == 0:50 for sample_id, sample_data in all_samples.items():51 if sample_data['carried_by'] != 1:52 for molecule, cost in sample_data['cost'].items():53 my_needs = cost - my_expertise[molecule] - my_storage[molecule]54 if my_needs > molecule_left[molecule]:55 dead_lock_sample_list.append(sample_id)56 print_debug('dead_lock_samples:{}'.format(dead_lock_sample_list))57 return dead_lock_sample_list58def ready_to_submit_molecule(his_samples, his_storage, his_expertise, all_samples):59 total_ready_to_submit_molecule = {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0}60 storage_left = his_storage.copy()61 for sample_id in his_samples:62 print_debug('checking sample:{}'.format(sample_id))63 submit_molecule = {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0}64 tmp_storage = storage_left.copy()65 gain = all_samples[sample_id]['expertise_gain'].lower()66 print_debug('gain:{}'.format(gain))67 count = 068 for molecule, cost in all_samples[sample_id]['cost'].items():69 print_debug('{}:cost:{},exp:{},store_left:{}'.format(molecule, cost, his_expertise[molecule],70 storage_left[molecule]))71 need = cost - his_expertise[molecule] if cost > 0 else 072 if storage_left[molecule] >= need:73 submit_molecule[molecule] = need if need > 0 else 074 tmp_storage[molecule] -= submit_molecule[molecule]75 count += 176 if count == 5:77 print_debug('his sample:{},submit_molecule:{}'.format(sample_id, submit_molecule))78 storage_left = tmp_storage79 if gain != '0':80 storage_left[gain] += 181 total_ready_to_submit_molecule = cost_add_cost(submit_molecule, total_ready_to_submit_molecule)82 print_debug('total_ready_to_submit:{}'.format(total_ready_to_submit_molecule))83def undiagnosed_samples_id(samples_id, allsamples):84 undiagnosed_samples = []85 for sample_id in samples_id:86 if not is_sample_diagnosed(allsamples[sample_id]):87 undiagnosed_samples.append(sample_id)88 # print_debug('undiagnosed samples id:{}'.format(undiagnosed_samples))89 return undiagnosed_samples90def sample_ranks(samples_id, allsamples):91 samples_rank = []92 for sample_id in samples_id:93 samples_rank.append(allsamples[sample_id]['rank'])94 print_debug('sample ranks:{}'.format(samples_rank))95 return samples_rank96def sample_expertise_gain(samples_id, allsamples):97 samples_exp_gain = {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0}98 for sample_id in samples_id:99 gain = allsamples[sample_id]['expertise_gain'].lower()100 if gain != '0':101 samples_exp_gain[gain] += 1102 # print_debug('samples_exp_gain:{}'.format(samples_exp_gain))103 return samples_exp_gain104def all_current_needs(my_samples, his_samples, my_submit_samples, my_expertise, his_expertise, my_storage, his_storage,105 allsamples):106 my_samples_cost = get_total_molecule_needs(my_samples, allsamples)107 his_samples_cost = get_total_molecule_needs(his_samples, allsamples)108 my_current_needs = cost_minus_cost(my_samples_cost, my_expertise)109 my_current_needs = cost_minus_cost(my_current_needs, my_storage)110 his_current_needs = cost_minus_cost(his_samples_cost, his_expertise)111 his_current_needs = cost_minus_cost(his_current_needs, his_storage)112 my_exp_gain = sample_expertise_gain(my_samples, allsamples)113 his_exp_gain = sample_expertise_gain(his_samples, allsamples)114 # print_debug('available: {}'.format(available))115 # print_debug('my_cost: {}'.format(my_samples_cost))116 # print_debug('my_exp: {}'.format(my_expertise))117 # print_debug('my_storage: {}'.format(my_storage))118 # print_debug('my_needs: {}'.format(my_current_needs))119 # print_debug('my_exp_gain:{}'.format(my_exp_gain))120 if my_submit_samples:121 for sample_id in my_submit_samples:122 gain = allsamples[sample_id]['expertise_gain'].lower()123 my_current_needs[gain] -= 1124 # print_debug('his_cost: {}'.format(his_samples_cost))125 # print_debug('his_exp: {}'.format(his_expertise))126 # print_debug('his_storage: {}'.format(my_storage))127 # print_debug('his_needs: {}'.format(his_current_needs))128 # print_debug('his_exp_gain:{}'.format(his_exp_gain))129 my_current_needs = remove_zero_cost(replace_neg_cost_with_zero(my_current_needs))130 his_current_needs = remove_zero_cost(replace_neg_cost_with_zero(his_current_needs))131 return my_current_needs, his_current_needs132def get_min_common_needs(my_expertise, my_storage, my_samples_id, allsamples):133 min_common_needs = {'a': 5, 'b': 5, 'c': 5, 'd': 5, 'e': 5}134 for sample_id in my_samples_id:135 costs = allsamples[sample_id]['cost']136 gain = allsamples[sample_id]['expertise_gain']137 print_debug('{}:costs:{}:gain:{}'.format(sample_id, costs, gain))138 my_current_needs = cost_minus_cost(costs, my_expertise)139 my_current_needs = cost_minus_cost(my_current_needs, my_storage)140 # print_debug('{}:my_current_needs:{}'.format(sample_id,my_current_needs))141 for molecule, cost in my_current_needs.items():142 if cost < min_common_needs[molecule]:143 min_common_needs[molecule] = cost if cost >= 0 else 0144 # print_debug(' min_common_needs:{}'.format(min_common_needs))145 return min_common_needs146def is_expertise_enough_for_my_sample(my_expertise, sample_id, allsamples):147 # print_debug('validating sample:{}'.format(sample))148 molecule_limit = 10149 max_molecule = 5150 for molecule, cost in allsamples[sample_id]['cost'].items():151 # print_debug("checking {}: needed({}), myexp({}), available({})"152 # .format(molecule, needed, myexpertise[molecule], available[molecule]))153 molecule_limit = molecule_limit - (cost - my_expertise[molecule])154 if cost > (max_molecule + my_expertise[molecule]):155 print_debug("sample:{} {}:cost({}) > exp({}) + {}".format(sample_id, molecule, cost, my_expertise[molecule],156 max_molecule))157 return False158 if molecule_limit < 0:159 print_debug("sample:{} {}:cost({}) + exp({}) > {}".format(sample_id, molecule, cost, my_expertise[molecule],160 molecule_limit))161 return False162 return True163def cloud_samples_id(allsamples):164 cloud_samples = []165 for sample_id in allsamples.keys():166 if allsamples[sample_id]['carried_by'] == -1:167 cloud_samples.append(sample_id)168 print_debug('cloud samples id:{}'.format(cloud_samples))169 return cloud_samples170def his_samples_id(allsamples):171 his_samples = []172 for sample_id in allsamples.keys():173 if allsamples[sample_id]['carried_by'] == 1:174 his_samples.append(sample_id)175 # print_debug('his samples id:{}'.format(his_samples))176 return his_samples177def validated_samples_id(expertises, sample_ids, allsamples):178 validated_samples = []179 my_expertise = expertises[0]180 for sample_id in sample_ids:181 # print_debug('validating sample:{}'.format(sample_id))182 is_my_expertise_enough = is_expertise_enough_for_my_sample(my_expertise, sample_id, allsamples)183 is_max_molecule_enough = True184 if not is_sample_diagnosed(allsamples[sample_id]):185 continue186 if is_my_expertise_enough and is_max_molecule_enough and allsamples[sample_id]['expertise_gain'] != 0:187 validated_samples.append(sample_id)188 # print_debug('validated samples id:{}'.format(validated_samples))189 return validated_samples190def get_total_molecule_needs(samples_id, allsamples):191 total_melecule_needs = {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0}192 for sample_id in samples_id:193 # print_debug('checking submit:{}'.format(sample_id))194 for molecule, cost in allsamples[sample_id]['cost'].items():195 if cost > 0:196 total_melecule_needs[molecule] += cost197 return total_melecule_needs198def ready_for_lab_samples_id(myexpertise, mystorage, samples_id, allsamples):199 submit_samples_id = []200 storage_left = mystorage.copy()201 for sample_id in samples_id:202 # print_debug('checking submit:{}'.format(sample_id))203 # print_debug('storage({})'.format(mystorage))204 # print_debug('costs({})'.format(allsamples[sample_id]['cost'].items()))205 gain = allsamples[sample_id]['expertise_gain'].lower()206 if is_sample_diagnosed(allsamples[sample_id]):207 count = 0208 tmp_storage = storage_left.copy()209 for molecule, cost in allsamples[sample_id]['cost'].items():210 needs = cost - myexpertise[molecule]211 # print_debug("{},needs({}),exp({}),storage_left({})"\212 # .format(molecule.upper(), needs, myexpertise[molecule],storage_left[molecule]))213 if needs <= storage_left[molecule]:214 count += 1215 if needs > 0:216 tmp_storage[molecule] = tmp_storage[molecule] - needs217 # print_debug('count:{}'.format(count))218 if count == 5:219 submit_samples_id.append(sample_id)220 storage_left = tmp_storage221 storage_left[gain] += 1222 print_debug('submit samples id:{}'.format(submit_samples_id))223 # print_debug('storage left:{}'.format(storage_left))224 return submit_samples_id, storage_left225def best_sample_for_science_project(projects_needs, sample_candidates, myexpertise):226 best_samples = []227 if len(sample_candidates) > 1:228 smallest_needs = nearest_science_project_gap(projects_needs, myexpertise)229 for sample_id in sample_candidates:230 if samples[sample_id]['expertise_gain'].lower() in list(smallest_needs.keys()):231 best_samples.append(sample_id)232 print_debug('best samples:{}'.format(best_samples))233 return best_samples234def nearest_science_project_gap(projects, myexpertise):235 smallest_needs = {'a': 5, 'b': 5, 'c': 5, 'd': 5, 'e': 5}236 for project_need in projects:237 # print_debug('project needs:{}'.format(project_need))238 # print_debug('myexpertise :{}'.format(myexpertise))239 gaps = {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0}240 for molecule, needs in project_need.items():241 gap = needs - myexpertise[molecule]242 if gap > 0:243 gaps[molecule] = gap244 if sum(gaps.values()) < sum(smallest_needs.values()):245 smallest_needs = gaps246 # print_debug('smallest project gap:{}'.format(smallest_needs))247 smallest_needs_copy = remove_zero_cost(smallest_needs)248 print_debug('smallest project gap:{}'.format(smallest_needs_copy))249 return smallest_needs_copy250def cal_best_rank(available_storage, my_expertise, my_samples, undiagnosed_samples):251 not_completed_samples = len(my_samples) - len(undiagnosed_samples)252 rank = 1253 if sum(my_expertise.values()) > 10 and available_storage > 4 and not_completed_samples < 1:254 rank = 3255 elif sum(my_expertise.values()) > 5 and available_storage > 1 and not_completed_samples < 2:256 rank = 2257 return rank258def sort_samples_by_health(samples_id, allsamples):259 sample_health_mapping = {}260 for sample_id in samples_id:261 health = allsamples[sample_id]['health']262 sample_health_mapping[sample_id] = health263 print_debug('sample_health:{}'.format(sample_health_mapping))264 sorted_samples = [k for k in sorted(sample_health_mapping, key=sample_health_mapping.get, reverse=True)]265 print_debug('sorted_samples_by_health:{}'.format(sorted_samples))266 return sorted_samples267def sort_samples_by_cost(samples_id, my_expertise, allsamples):268 sample_needs_score = {}269 sample_needs_mapping = {}270 all_needs = {}271 for sample_id in samples_id:272 costs = allsamples[sample_id]['cost']273 total_need = cost_minus_cost(costs, my_expertise)274 total_need = replace_neg_cost_with_zero(total_need)275 sample_needs_mapping[sample_id] = total_need276 sample_needs_score[sample_id] = sum(total_need.values())277 all_needs = cost_add_cost(all_needs, total_need)278 print_debug('sample_needs_mapping:{}'.format(sample_needs_mapping))279 print_debug('sample_needs_score:{}'.format(sample_needs_score))280 print_debug('all_needs:{}'.format(all_needs))281 for sample_id, total_need in sample_needs_mapping.items():282 gain = samples[sample_id]['expertise_gain'].lower()283 others_needs = remove_zero_cost(cost_minus_cost(all_needs, total_need))284 # print_debug('gain:{}'.format(gain))285 # print_debug('others_needs:{}'.format(others_needs))286 if gain in list(others_needs.keys()):287 sample_needs_score[sample_id] -= 1288 print_debug('sample_needs_score:{}'.format(sample_needs_score))289 sorted_samples = [k for k in sorted(sample_needs_score, key=sample_needs_score.get, reverse=False)]290 print_debug('sorted_samples_by_needs_score:{}'.format(sorted_samples))291 return sorted_samples292def continue_collect_samples(available, my_samples, my_expertise, my_storage, allsamples):293 enough_samples = []294 # print_debug('available:{}'.format(available))295 # print_debug('my_storage:{}'.format(my_storage))296 all_have = cost_add_cost(available, my_storage)297 print_debug('all_have:{}'.format(all_have))298 for sample_id in my_samples:299 cost = allsamples[sample_id]['cost']300 print_debug('cost:{}'.format(cost))301 gain = allsamples[sample_id]['expertise_gain'].lower()302 need = cost_minus_cost(cost, my_expertise)303 print_debug('need:{}'.format(need))304 need = replace_neg_cost_with_zero(need)305 rest_molecule = cost_minus_cost(all_have, need)306 print_debug('sample:{}, rest_molecule:{}'.format(sample_id, rest_molecule))307 count = 0308 for molecule, value in rest_molecule.items():309 if value < 0:310 print_debug('{} not enough for sample:{}'.format(molecule, sample_id))311 break312 else:313 count += 1314 if count == 5:315 print_debug('sample {} can continue to collect'.format(sample_id))316 enough_samples.append(sample_id)317 all_have = rest_molecule318 all_have[gain] += 1319 return enough_samples320def cal_best_molecule(sorted_my_samples, submit_samples, storage_left, available, my_expertise, his_current_needs,321 allsamples):322 # min_common_needs = get_min_common_needs(my_expertise, storage_left, my_samples, available, allsamples)323 # min_common_needs = remove_zero_cost(min_common_needs)324 # print_debug('min_common_needs:{}'.format(min_common_needs))325 # if list(min_common_needs.keys()):326 # molecule = list(min_common_needs.keys())[0]327 # if available[molecule] != 0:328 # return molecule329 # collect by sorted samples first, not enough molecule samples put to break_samples330 collecting_samples = list_minus_list(sorted_my_samples.copy(), submit_samples)331 sorted_available_molecule = [k for k, v in sorted(available.items(), key=lambda x: x[1], reverse=False)]332 break_samples = []333 for working_sample_id in collecting_samples:334 working_sample = allsamples[working_sample_id]335 print_debug("working sample id: {}".format(working_sample_id))336 switch_sample = False337 for molecule in sorted_available_molecule:338 cost = working_sample['cost'][molecule]339 needs = cost - storage_left[molecule] - my_expertise[molecule]340 print_debug("getting {}:needs:{},cost:{},storage_left:{},exp:{},available:{}"341 .format(molecule.upper(), needs, cost, storage_left[molecule], my_expertise[molecule],342 available[molecule]))343 if available[molecule] == 0 and needs > 0:344 switch_sample = True345 break_samples.append(working_sample_id)346 break347 if available[molecule] != 0 and needs > 0:348 return molecule349 if switch_sample:350 continue351 # continue break samples to collect352 if break_samples:353 for working_sample_id in break_samples:354 working_sample = allsamples[working_sample_id]355 print_debug("break sample:{}".format(working_sample_id))356 for molecule in sorted_available_molecule:357 cost = working_sample['cost'][molecule]358 needs = cost - storage_left[molecule] - my_expertise[molecule]359 print_debug("getting {}:needs:{},cost:{},storage_left:{},exp:{},available:{}"360 .format(molecule.upper(), cost, storage_left[molecule], my_expertise[molecule], needs,361 available[molecule]))362 if available[molecule] != 0 and needs > 0:363 return molecule364 # start to collect his needs to prevent365 if his_current_needs:366 sorted_his_current_needs_key = [k for k, v in367 sorted(his_current_needs.items(), key=lambda x: x[1], reverse=True)]368 molecule = sorted_his_current_needs_key[0]369 if available[molecule] != 0:370 print_debug('working on his needs:{}'.format(sorted_his_current_needs_key))371 return molecule372 return 0373project_count = int(input())374projects_needs = []375for i in range(project_count):376 needs_value = [int(j) for j in input().split()]377 needs_key = ['a', 'b', 'c', 'd', 'e']378 needs = dict(zip(needs_key, needs_value))379 projects_needs.append(needs)380print_debug("projects_needs:{}".format(projects_needs))381game_loop = 0382# game loop383while True:384 # Contains both players, 0 is myself385 targets = []386 etas = []387 scores = []388 storages = []389 expertises = []390 # Contains data used for both player391 available = {}392 samples = {}393 my_samples = []394 for i in range(2):395 target, eta, score, sto_a, sto_b, sto_c, sto_d, sto_e, exp_a, exp_b, exp_c, exp_d, exp_e = input().split()396 storage = {'a': int(sto_a), 'b': int(sto_b), 'c': int(sto_c), 'd': int(sto_d), 'e': int(sto_e)}397 expertise = {'a': int(exp_a), 'b': int(exp_b), 'c': int(exp_c), 'd': int(exp_d), 'e': int(exp_e)}398 targets.append(target)399 etas.append(int(eta))400 scores.append(int(score))401 storages.append(storage)402 expertises.append(expertise)403 available['a'], available['b'], available['c'], available['d'], available['e'] = [int(i) for i in input().split()]404 sample_count = int(input())405 for i in range(sample_count):406 sample_id, carried_by, rank, expertise_gain, health, cost_a, cost_b, cost_c, cost_d, cost_e = input().split()407 cost = {'a': int(cost_a), 'b': int(cost_b), 'c': int(cost_c), 'd': int(cost_d), 'e': int(cost_e)}408 sample_data = {'carried_by': int(carried_by), 'rank': int(rank), 'expertise_gain': expertise_gain,409 'health': int(health), 'cost': cost}410 samples[sample_id] = sample_data411 if int(carried_by) == 0:412 my_samples.append(sample_id)413 game_loop += 1414 print_debug("game_loop:{}".format(game_loop))415 print_debug('---my---')416 his_samples = his_samples_id(samples)417 sorted_my_samples = sort_samples_by_cost(my_samples, expertises[0], samples)418 cloud_samples = cloud_samples_id(samples)419 valid_cloud_samples = validated_samples_id(expertises, cloud_samples, samples)420 undiagnosed_samples = undiagnosed_samples_id(sorted_my_samples, samples)421 validated_samples = validated_samples_id(expertises, sorted_my_samples, samples)422 submit_samples, storage_left = ready_for_lab_samples_id(expertises[0], storages[0], sorted_my_samples, samples)423 get_min_common_needs(expertises[0], storages[0], sorted_my_samples, samples)424 my_current_needs, his_current_needs = all_current_needs(sorted_my_samples, his_samples, submit_samples,425 expertises[0], expertises[1], storages[0], storages[1],426 samples)427 dead_lock_samples = dead_lock_samples_id(his_samples, expertises[0], storages[0], available, samples)428 available_storage = 10 - sum(storages[0].values())429 # print_debug('available_storage:{}'.format(available_storage))430 # print_debug("my targets:{}".format(targets[0]))431 # print_debug("my eta:{}".format(etas[0]))432 print_debug("valid_cloud_samples:{}".format(valid_cloud_samples))433 # print_debug("my samples:{}".format(my_samples))434 print_debug('all_current_needs:{}'.format(my_current_needs))435 print_debug('---his---')436 print_debug('all_current_needs:{}'.format(his_current_needs))437 print_debug('====================')438 if etas[0] > 0:439 print("GOTO EMPTY")440 continue441 if targets[0] == 'START_POS':442 print("GOTO SAMPLES")443 continue444 if targets[0] == 'SAMPLES':445 rank = cal_best_rank(available_storage, expertises[0], my_samples, undiagnosed_samples)446 if len(my_samples) == 3:447 print("GOTO DIAGNOSIS")448 else:449 print("CONNECT {}".format(rank))450 continue451 if targets[0] == 'DIAGNOSIS':452 # Diagnose all samples453 if len(undiagnosed_samples) != 0:454 print("CONNECT {}".format(undiagnosed_samples.pop()))455 continue456 # Deadlock samples457 if len(dead_lock_samples) != 0:458 sample_ids = [i for i in my_samples if i in dead_lock_samples]459 if sample_ids:460 print("CONNECT {}".format(sample_ids.pop()))461 continue462 # Handle storage is full situation463 if available_storage == 0:464 if len(submit_samples) != 0:465 print('GOTO LABORATORY')466 elif len(my_samples) > 0:467 print("CONNECT {}".format(my_samples.pop()))468 else:469 print('GOTO SAMPLES')470 continue471 # send invalid samples back to cloud472 store_to_cloud_samples = [i for i in my_samples if i not in validated_samples]473 # calculate best samples between my_samples and valid_cloud_samples474 download_from_cloud_samples = []475 best_samples = []476 if len(valid_cloud_samples) != 0:477 # avoid the dead_lock samples to download back478 for sample_id in dead_lock_samples:479 if sample_id not in best_samples and sample_id in valid_cloud_samples:480 valid_cloud_samples.remove(sample_id)481 sample_candidates = valid_cloud_samples + my_samples482 print_debug('sample_candidates:{}'.format(sample_candidates))483 best_samples = best_sample_for_science_project(projects_needs, sample_candidates, expertises[0])484 best_sample_inhand = [i for i in best_samples if i in my_samples]485 best_sample_not_inhand = [i for i in best_samples if i not in my_samples]486 best_sample_not_inhand = sort_samples_by_health(best_sample_not_inhand, samples)487 not_best_sample_inhand = [i for i in my_samples if i not in best_samples]488 not_best_sample_not_inhand = [i for i in valid_cloud_samples if i not in best_samples]489 not_best_sample_not_inhand = sort_samples_by_health(not_best_sample_not_inhand, samples)490 # Download all samples491 if len(sample_candidates) <= 3:492 download_from_cloud_samples = valid_cloud_samples493 # only download best sample not inhand494 elif len(best_sample_not_inhand) + len(my_samples) <= 3:495 download_from_cloud_samples = best_sample_not_inhand496 capacity_in_hand = 3 - len(best_sample_not_inhand) - len(my_samples)497 if capacity_in_hand > 0:498 download_from_cloud_samples += not_best_sample_not_inhand[:capacity_in_hand]499 # exchange the samples500 elif (len(best_sample_not_inhand) + len(my_samples)) > 3 and len(best_sample_inhand) != 3:501 capacity_in_hand = 3 - len(best_sample_inhand)502 if len(best_sample_not_inhand) < capacity_in_hand:503 download_from_cloud_samples = best_sample_not_inhand504 else:505 download_from_cloud_count = capacity_in_hand506 download_from_cloud_samples = best_sample_not_inhand[:download_from_cloud_count]507 store_to_cloud_samples = not_best_sample_inhand508 print_debug('store_to_cloud:{}'.format(store_to_cloud_samples))509 print_debug('download_from_cloud:{}'.format(download_from_cloud_samples))510 # store samples back to cloud511 if len(store_to_cloud_samples) != 0:512 print("CONNECT {}".format(store_to_cloud_samples.pop()))513 continue514 # download samples from cloud515 if len(download_from_cloud_samples) != 0 and len(my_samples) < 3:516 print("CONNECT {}".format(download_from_cloud_samples.pop()))517 continue518 # collect samples again if only 1 sample in hand519 if len(my_samples) < 2:520 print('GOTO SAMPLES')521 continue522 if targets[0] == 'MOLECULES':523 if (200 - game_loop) == (3 + len(submit_samples)):524 print('GOTO LABORATORY')525 continue526 if len(dead_lock_samples) == 3:527 print('GOTO DIAGNOSIS')528 continue529 if available_storage == 0:530 print_debug('10 molecule storage limit reached!')531 if len(submit_samples) != 0:532 print('GOTO LABORATORY')533 elif len(my_samples) != 3 and len(valid_cloud_samples) == 0:534 print('GOTO SAMPLES')535 else:536 print('GOTO DIAGNOSIS')537 continue538 molecule_tobe_collect = cal_best_molecule(sorted_my_samples, submit_samples, storage_left, available,539 expertises[0], his_current_needs, samples)540 if molecule_tobe_collect != 0:541 print('CONNECT {}'.format(molecule_tobe_collect))542 continue543 else:544 if len(submit_samples) > 0:545 print("GOTO LABORATORY")546 continue547 if len(my_samples) < 3:548 if len(valid_cloud_samples) != 0:549 print('GOTO DIAGNOSIS')550 else:551 print('GOTO SAMPLES')552 continue553 else:554 print("WAIT")555 continue556 if targets[0] == 'LABORATORY':557 if len(submit_samples) != 0:558 print("CONNECT {}".format(submit_samples.pop(0)))559 continue560 if len(my_samples) != 0:561 continue_samples = continue_collect_samples(available, my_samples, expertises[0], storages[0], samples)562 if len(continue_samples) == 0:563 if len(valid_cloud_samples) != 0:564 print('GOTO DIAGNOSIS')565 else:566 print('GOTO SAMPLES')567 continue568 elif available_storage != 0:569 print('GOTO MOLECULES')570 continue571 if targets[0] != 'SAMPLES' and len(my_samples) == 0:572 print_debug("====1====")573 print("GOTO SAMPLES")574 continue575 if targets[0] != 'DIAGNOSIS' and (len(undiagnosed_samples) != 0 and len(my_samples) == len(undiagnosed_samples)):576 print_debug("====2====")577 print("GOTO DIAGNOSIS")578 continue579 if targets[0] != 'MOLECULES' and available_storage != 0 and len(my_samples) > 0 \580 and len(undiagnosed_samples) == 0 and len(validated_samples) == len(my_samples):581 print_debug("====3====")582 print("GOTO MOLECULES")583 continue584 if targets[0] != 'LABORATORY' and len(submit_samples) != 0 and len(submit_samples) == len(my_samples):585 print_debug("====4====")586 print("GOTO LABORATORY")587 continue588 if available_storage == 0:589 if len(my_samples) != 3 and len(valid_cloud_samples) == 0:590 print('GOTO SAMPLES')591 else:...
relocate.py
Source:relocate.py
...58'''59A debug helper, why not?60'''61ENABLE_DEBUG = True62def print_debug(s, *argv):63 if ENABLE_DEBUG:64 out = '[Debug] (relocate.py): ' + str(s)65 for a in argv:66 out += ' ' + str(a)67 print(out)68'''69And an error printer :)70'''71ENABLE_ERROR = True72def print_error(s, *argv):73 if ENABLE_ERROR:74 out = '[Error] (relocate.py): ' + str(s)75 for a in argv:76 out += ' ' + str(a)77 print(out)78def write_to_elf(elf_bytes, offset, val, n, little_endian=True):79 byte_val = val.to_bytes(n, byteorder='little' if little_endian else 'big')80 elf_bytes[offset:offset+n] = byte_val81'''82Parse .rel.text entries, ignoring relocations that are nonzero (matching83entries in .rel.dyn for dynamic relocation) if desired. Zero-valued relocations84are more likely missing extern references that must be resolved.85'''86def parse_text_relocations(e, ignore_nonzero_symbol_vals=False):87 parsed_relocations = []88 rel_text = e.get_section_by_name('.rel.text')89 if not rel_text:90 return parsed_relocations91 rel_symtab = e.get_section(rel_text['sh_link'])92 rel_stringtable = e.get_section_by_name('.strtab')93 for relocation in rel_text.iter_relocations():94 relocation_symbol = rel_symtab.get_symbol(relocation['r_info_sym'])95 if ignore_nonzero_symbol_vals and relocation_symbol['st_value'] != 0:96 continue97 relocation_type = descriptions._DESCR_RELOC_TYPE_ARM[relocation['r_info_type']]98 if relocation_type != 'R_ARM_GOT_BREL':99 print_warning('found .text relocation with unexpected type ' + relocation_type)100 parsed_relocations.append({101 'offset': '{:08x}'.format(relocation['r_offset']),102 'offset_val': relocation['r_offset'],103 'info': '{:08x}'.format(relocation['r_info']),104 'type': relocation_type,105 'symbol_val': '{:08x}'.format(relocation_symbol['st_value']),106 'symbol_name': rel_stringtable.get_string(relocation_symbol['st_name']),107 })108 return parsed_relocations109def parse_got_offsets(e, relocations):110 # We're looking in the text section for the GOT offsets matching the parsed relocations111 text = e.get_section_by_name('.text')112 for r in relocations:113 text_offset = r['offset_val'] - text['sh_addr']114 115 if text_offset < 0 or text_offset >= text['sh_size']:116 print_warning('Relocation .text offset has bad value ' + text_offset)117 continue118 r['got_offset'] = text.data()[text_offset]119 120 121'''122Search through the provided `.map` file contents to find symbol addresses123matching the outstanding relocation entries.124'''125def parse_symbol_locations(map_contents, relocations):126 if not map_contents: # don't do anything if the map file doesn't exist127 return128 # Patterns can be very finnicky depending on the system and format of the129 # map file Should return a list of pattern lists, for which the last130 # result.group(1) contains the correct symbol location when applied to131 # successive lines after the first successful match.132 def generate_patterns(relocation):133 134 return [135 [ # symbol address on one line, try first for exact .text.`fn` match136 re.compile('\.text\.'+relocation['symbol_name']+'\s*0x0*([0-9a-f]{8})')137 ],138 [ # symbol address on one line139 re.compile('\.text\S*'+relocation['symbol_name']+'\s*0x0*([0-9a-f]{8})')140 ],141 [ # symbol address wrapped to next line, exact match first142 re.compile('\.text\.?'+relocation['symbol_name']),143 re.compile('\s*0x0*([0-9a-f]{8})')144 ],145 [ # symbol address wrapped to next line146 re.compile('\.text\S*?'+relocation['symbol_name']),147 re.compile('\s*0x0*([0-9a-f]{8})')148 ],149 [ # use the symbol name after the address instead, since apparently sometimes that's necessary150 re.compile('\s*0x0*([0-9a-f]{8})\s*'+r['symbol_name'])151 ],152 ]153 def apply_pattern(map_contents, pattern_list):154 print_debug('apply_pattern(contents, ' + str(pattern_list) + ')')155 final_result = None 156 first_match_index = -1157 print_debug('\ttrying to find first line match for pattern ' + str(pattern_list[0]) + ' in map contents')158 for i, l in enumerate(map_contents):159 result = pattern_list[0].match(l)160 if result:161 print_debug('\tfirst line matched at index ' + str(i) + ' line: ' + l)162 if len(pattern_list) == 1: # last pattern (only one)163 print_debug('\tonly one pattern, returning final result')164 final_result = result165 else:166 print_debug('\tmore than one pattern, setting first match index to ' + str(i))167 first_match_index = i168 break169 170 if first_match_index >= 0:171 print_debug('\tfirst_match_index set to 0 or greater, proceeding to secondary patterns')172 for i, p in enumerate(pattern_list[1:]):173 print_debug('\ttrying to find ' + str(i+1) + 'line match for pattern ' + str(p) + ' in text line ' + map_contents[first_match_index + 1 + i])174 result = p.match(map_contents[first_match_index + 1 + i])175 if not result:176 print_debug("\tdidn't find a match")177 break178 print_debug('\t'+str(i+1)+' line matched')179 if i == len(pattern_list[1:]) - 1: # last pattern180 print_debug("\tthat was the last pattern, returning final result")181 final_result = result182 return first_match_index, final_result183 for r in relocations:184 print_debug('generating patterns for unresolved symbol `' + r['symbol_name'] + '`')185 patterns = generate_patterns(r)186 for p_list in patterns:187 line_index, result = apply_pattern(map_contents, p_list)188 if result:189 r['symbol_val'] = result.group(1)190 # Print the symbol resolution for sanity checking191 info_string = 'resolved symbol `' + r['symbol_name'] + '` (GOT offset: ' + hex(r['got_offset']) + ') to ' + r['symbol_val'] + ' using line(s) \n'192 for i in range(len(p_list)):193 info_string += '\t\t' + map_contents[line_index + i]194 print_info(info_string)195 break196def resolve_got_symbols(e, e_contents, relocations):197 got = e.get_section_by_name('.got')198 for r in relocations:199 # Convert function calls to Thumb mode200 symbol_val = int(r['symbol_val'], base=16)201 if symbol_val < MUSCA_DATA_BASE:202 symbol_val |= 1203 got_entry_offset = got['sh_offset'] + r['got_offset']204 write_to_elf(e_contents, got_entry_offset, symbol_val, 4)205def to_hex(s, prefix_0x=True):206 if prefix_0x:207 return " ".join("0x{0:02x}".format(c) for c in s)208 else:209 return " ".join("{0:02x}".format(c) for c in s)210def to_x_32(s):211 from struct import pack212 if not s: return '0'213 x = pack(">i", s)214 while x[0] in ('\0', 0): x = x[1:]215 216 r = "".join("{0:02x}".format(c) for c in x)217 while r[0] == '0': r = r[1:]218 219 return r220def print_insn_detail(insn):221 # print address, mnemonic and operands222 print_debug("0x%x:\t%s\t%s" % (insn.address, insn.mnemonic, insn.op_str))223 # "data" instruction generated by SKIPDATA option has no detail224 if insn.id == 0:225 return226 if len(insn.operands) > 0:227 print_debug("\top_count: %u" % len(insn.operands))228 c = 0229 for i in insn.operands:230 if i.type == ARM_OP_REG:231 print_debug("\t\toperands[%u].type: REG = %s" % (c, insn.reg_name(i.reg)))232 if i.type == ARM_OP_IMM:233 print_debug("\t\toperands[%u].type: IMM = 0x%s" % (c, to_x_32(i.imm)))234 if i.type == ARM_OP_PIMM:235 print_debug("\t\toperands[%u].type: P-IMM = %u" % (c, i.imm))236 if i.type == ARM_OP_CIMM:237 print_debug("\t\toperands[%u].type: C-IMM = %u" % (c, i.imm))238 if i.type == ARM_OP_FP:239 print_debug("\t\toperands[%u].type: FP = %f" % (c, i.fp))240 if i.type == ARM_OP_SYSREG:241 print_debug("\t\toperands[%u].type: SYSREG = %u" % (c, i.reg))242 if i.type == ARM_OP_SETEND:243 if i.setend == ARM_SETEND_BE:244 print_debug("\t\toperands[%u].type: SETEND = be" % c)245 else:246 print_debug("\t\toperands[%u].type: SETEND = le" % c)247 if i.type == ARM_OP_MEM:248 print_debug("\t\toperands[%u].type: MEM" % c)249 if i.mem.base != 0:250 print_debug("\t\t\toperands[%u].mem.base: REG = %s" \251 % (c, insn.reg_name(i.mem.base)))252 if i.mem.index != 0:253 print_debug("\t\t\toperands[%u].mem.index: REG = %s" \254 % (c, insn.reg_name(i.mem.index)))255 if i.mem.scale != 1:256 print_debug("\t\t\toperands[%u].mem.scale: %u" \257 % (c, i.mem.scale))258 if i.mem.disp != 0:259 print_debug("\t\t\toperands[%u].mem.disp: 0x%s" \260 % (c, to_x_32(i.mem.disp)))261 if i.mem.lshift != 0:262 print_debug("\t\t\toperands[%u].mem.lshift: 0x%s" \263 % (c, to_x_32(i.mem.lshift)))264 if i.neon_lane != -1:265 print_debug("\t\toperands[%u].neon_lane = %u" % (c, i.neon_lane))266 if i.access == CS_AC_READ:267 print_debug("\t\toperands[%u].access: READ\n" % (c))268 elif i.access == CS_AC_WRITE:269 print_debug("\t\toperands[%u].access: WRITE\n" % (c))270 elif i.access == CS_AC_READ | CS_AC_WRITE:271 print_debug("\t\toperands[%u].access: READ | WRITE\n" % (c))272 if i.shift.type != ARM_SFT_INVALID and i.shift.value:273 print_debug("\t\t\tShift: %u = %u" \274 % (i.shift.type, i.shift.value))275 if i.vector_index != -1:276 print_debug("\t\t\toperands[%u].vector_index = %u" %(c, i.vector_index))277 if i.subtracted:278 print_debug("\t\t\toperands[%u].subtracted = True" %c)279 c += 1280 if insn.update_flags:281 print_debug("\tUpdate-flags: True")282 if insn.writeback:283 print_debug("\tWrite-back: True")284 if not insn.cc in [ARM_CC_AL, ARM_CC_INVALID]:285 print_debug("\tCode condition: %u" % insn.cc)286 if insn.cps_mode:287 print_debug("\tCPSI-mode: %u" %(insn.cps_mode))288 if insn.cps_flag:289 print_debug("\tCPSI-flag: %u" %(insn.cps_flag))290 if insn.vector_data:291 print_debug("\tVector-data: %u" %(insn.vector_data))292 if insn.vector_size:293 print_debug("\tVector-size: %u" %(insn.vector_size))294 if insn.usermode:295 print_debug("\tUser-mode: True")296 if insn.mem_barrier:297 print_debug("\tMemory-barrier: %u" %(insn.mem_barrier))298 (regs_read, regs_write) = insn.regs_access()299 if len(regs_read) > 0:300 print_debug("\tRegisters read:")301 for r in regs_read:302 print_debug(" %s" %(insn.reg_name(r)))303 print_debug("")304 if len(regs_write) > 0:305 print_debug("\tRegisters modified:")306 for r in regs_write:307 print_debug(" %s" %(insn.reg_name(r)))308 print_debug("")309def patch_ptr_indirection(e, e_contents, relocations, dump_contents):310 text_section = e.get_section_by_name('.text')311 offset = text_section['sh_offset']312 size = text_section['sh_size']313 text_bytes = e_contents[offset:offset+size]314 mode = Cs(CS_ARCH_ARM, CS_MODE_THUMB + CS_MODE_LITTLE_ENDIAN + CS_MODE_V8)315 mode.detail = True316 def get_got_load_register(instr_list, idx):317 instr = instr_list[idx]318 if not instr.mnemonic.startswith("ldr"):319 #print_debug('failed ldr', instr.mnemonic)320 return None321 o = instr.operands[1]322 if o.type != ARM_OP_MEM or (instr.reg_name(o.mem.base) != 'sb'):323 #print_debug('failed op mem', o.type, instr.reg_name(o.mem.base) != 'sb')324 return None325 dest_o = instr.operands[0]326 if dest_o.type != ARM_OP_REG:327 #print_debug('failed dst op reg', dest_o.type)328 return None329 return_reg = instr.reg_name(dest_o.reg)330 for curr_instr in reversed(instr_list[:idx]):331 if curr_instr.mnemonic.startswith('ldr') and curr_instr.reg_name(curr_instr.operands[0].reg) == instr.reg_name(o.mem.index) \332 and curr_instr.reg_name(curr_instr.operands[1].mem.base) == 'pc':333 got_index_location = curr_instr.operands[1].mem.disp + curr_instr.address + 2334 if curr_instr.address % 4 == 0:335 got_index_location += 2336 matched_r_flag = False337 for r in relocations:338 if r['offset_val'] == got_index_location:339 matched_r_flag = True340 if not matched_r_flag: # couldn't find a text relocation, so it must be a data reference (keep indirections)341 return_reg = None342 break343 return return_reg344 def get_branch_dest_idx(instr_list, target_instr_addr):345 for idx, i in enumerate(instr_list):346 if i.address == target_instr_addr:347 return idx348 def destroy_indirection(instr):349 text_offset = instr.address - text_section['sh_addr']350 offset_into_elf_contents = text_section['sh_offset'] + text_offset351 print_insn_detail(instr)352 353 r_dst = instr.reg_name(instr.operands[0].reg)354 if r_dst not in ARM_REG_VALS:355 print_warning('indirection destination register', r_dst, 'not found in ARM_REG_VALS')356 return357 r_dst_val = ARM_REG_VALS[r_dst]358 r_src = instr.reg_name(instr.operands[1].mem.base)359 if r_src not in ARM_REG_VALS:360 print_warning('indirection source register', r_src, 'not found in ARM_REG_VALS')361 return362 r_src_val = ARM_REG_VALS[r_src]363 mov_instr = (0b01000110 << 8) | ((r_dst_val >> 3) & 0b1) << 7 | ((r_src_val & 0b1111) << 3) | (r_dst_val & 0b111)364 write_to_elf(e_contents, offset_into_elf_contents, mov_instr, 2)365 if instr.size == 4: # append nop366 write_to_elf(e_contents, offset_into_elf_contents+2, 0x0, 2)367 def search_and_destroy_indirections(instr_list, idx, got_val_reg):368 visited_instructions = [idx]369 pending_search_queue = [idx + 1] # we already saw the GOT load, let's start at the next line370 while len(pending_search_queue) > 0:371 curr_idx = pending_search_queue.pop(0) 372 print_debug('\tdequeueing instruction: idx', curr_idx, 'addr', hex(instr_list[curr_idx].address))373 374 # iterate through instructions looking for indirect loads from `got_val_reg`375 # until we leave the local scope (return from function) or register is overwritten376 while True:377 if curr_idx >= len(instr_list):378 print_debug('\tran out of instructions, stopping iteration')379 break # no sense in reading off the end of .text380 curr_instr = instr_list[curr_idx]381 print_debug('\t** index, address, mnemonic:', curr_idx, hex(curr_instr.address), curr_instr.mnemonic)382 if curr_idx in visited_instructions:383 print_debug('\tgoing in a loop, terminating path')384 #print('>>>>')385 #print_insn_detail(curr_instr) 386 #print('<<<<')387 break # going in a loop, stop while we still can388 visited_instructions.append(curr_idx)389 if curr_instr.mnemonic.startswith('ldr'): # check for bad function pointer dereference390 o1 = curr_instr.operands[1]391 if o1.type == ARM_OP_MEM and curr_instr.reg_name(o1.mem.base) == got_val_reg:392 print_debug('\tfound bad function pointer dereference')393 #print('>>>>')394 #print_insn_detail(curr_instr) 395 #print('<<<<')396 dest_reg = curr_instr.reg_name(curr_instr.operands[0].reg)397 print_debug('\tdestination register', dest_reg)398 destroy_indirection(curr_instr)399 if curr_instr.mnemonic.startswith('bx') or curr_instr.mnemonic.startswith('bxns'):400 print_debug('\tbx or bxns, terminating path')401 #print('>>>>')402 #print_insn_detail(curr_instr) 403 #print('<<<<')404 break # returning from function, no need to continue405 if curr_instr.mnemonic.startswith('pop'):406 regs_read, regs_write = curr_instr.regs_access()407 pop_flag = False408 for r in regs_write:409 if curr_instr.reg_name(r) == 'pc':410 print_debug('\tpop pc return, terminating path')411 #print('>>>>')412 #print_insn_detail(curr_instr) 413 #print('<<<<')414 pop_flag = True415 break416 if pop_flag:417 break # common to return from function by loading old PC off stack418 CONDITIONAL_BRANCH_LIST = ['beq', 'bne', 'ble', 'blt', 'bge', 'bgt', 'cbnz', 'cbz']419 cb_flag = False420 for b in CONDITIONAL_BRANCH_LIST:421 if curr_instr.mnemonic.startswith(b):422 if curr_instr.operands[0].type == ARM_OP_IMM:423 target_o = curr_instr.operands[0]424 elif curr_instr.operands[1].type == ARM_OP_IMM:425 target_o = curr_instr.operands[1]426 else:427 target_o = None428 if target_o:429 cb_flag = True430 target = get_branch_dest_idx(instr_list, target_o.imm)431 print_debug('\tconditional jump detected, appending index', target)432 #print('>>>>')433 #print_insn_detail(curr_instr)434 #print('<<<<')435 pending_search_queue.append(target) # queue passing condition 436 curr_idx += 1 # simulate failing condition437 else:438 print_debug('\tconditional jump detected but no immediate target operand detected :(')439 if curr_instr.mnemonic == 'b' and curr_instr.operands[0].type == ARM_OP_IMM:440 target = get_branch_dest_idx(instr_list, curr_instr.operands[0].imm)441 print_debug('\tjump detected, going to index', target)442 #print('>>>>')443 #print_insn_detail(curr_instr)444 #print('<<<<')445 curr_idx = target446 else:447 _, regs_write = curr_instr.regs_access()448 if got_val_reg in regs_write: # overwriting the got_val register means we can stop looking for indirections449 break450 elif not cb_flag: # go to next instruction451 curr_idx += 1452 instr_list = []453 for i in mode.disasm(text_bytes, text_section['sh_addr']):454 #print_insn_detail(i)455 instr_list.append(i)456 for i, _ in enumerate(instr_list):457 r = get_got_load_register(instr_list, i)458 if r:459 print_debug('---------------------------------')460 print_debug('GOT LOAD REG', r)461 print_debug('---------------------------------')462 search_and_destroy_indirections(instr_list, i, r)463# For resolved relocations, change dynamic relocation type from R_ARM_RELATIVE464# to R_ARM_NONE The format of the .rel.dyn section is a simple list of 8-byte465# entries: ([32 bit offset into GOT] [32 bit info field])466def patch_dyn_relocations(e, e_contents, relocations):467 rel_dyn = e.get_section_by_name('.rel.dyn')468 if not rel_dyn:469 return470 rel_dyn_base_offset = rel_dyn['sh_offset']471 for i in range(rel_dyn.num_relocations()):472 relocation_entry = rel_dyn.get_relocation(i)473 for r in relocations:474 if r['got_offset'] == relocation_entry['r_offset']:475 write_to_elf(e_contents, rel_dyn_base_offset + (i * 8) + 4, enums.ENUM_RELOC_TYPE_ARM['R_ARM_NONE'], 4)...
string_handling.py
Source:string_handling.py
...15 f = open(log_filename, "ab")16 f.write( str )17 f.close()1819def print_debug( str ):20 if debug:21 print str2223##########################2425#LPTSTR lstrcat( 26# LPTSTR lpString1,27# LPTSTR lpString228#);29def lstrcat_handler(hookcall):30 print_debug( "kernel32.lstrcat() called!" )31 uhookerAPI = hookcall.proxy3233 _lpString1 = hookcall.params[0]34 _lpString2 = hookcall.params[1]3536 str1 = '<invalid>'37 str2 = '<invalid>'38 if _lpString1 != 0:39 str1 = uhookerAPI.readasciiz( _lpString1 )40 if _lpString2 != 0:41 str2 = uhookerAPI.readasciiz( _lpString2 )42 43 print_debug("String1: %s\nString2: %s\n" % (str1, str2) )4445 logf("-- kernel32.lstrcat( %.8X (%s), %.8X (%s) )\n" % (_lpString1, str1, _lpString2, str2) )464748 hookcall.sendack()49 return5051def lstrcatA_handler(hookcall):52 print_debug( "kernel32.lstrcatA() called!" )53 uhookerAPI = hookcall.proxy5455 _lpString1 = hookcall.params[0]56 _lpString2 = hookcall.params[1]5758 str1 = '<invalid>'59 str2 = '<invalid>'60 if _lpString1 != 0:61 str1 = uhookerAPI.readasciiz( _lpString1 )62 if _lpString2 != 0:63 str2 = uhookerAPI.readasciiz( _lpString2 )64 65 print_debug("String1: %s\nString2: %s\n" % (str1, str2) )6667 logf("-- kernel32.lstrcatA( %.8X (%s), %.8X (%s) )\n" % (_lpString1, str1, _lpString2, str2) )686970 hookcall.sendack()71 return7273def lstrcatW_handler(hookcall):74 print_debug( "kernel32.lstrcatW() called!" )75 uhookerAPI = hookcall.proxy7677 _lpString1 = hookcall.params[0]78 _lpString2 = hookcall.params[1]7980 str1 = ''81 str2 = ''82 ustr1 = ''83 ustr2 = ''84 if _lpString1 != 0:85 ustr1 = uhookerAPI.readunicode( _lpString1 )86 for j in ustr1:87 if j != '\x00':88 str1 = str1 + j89 else:90 str1 = '<invalid>'9192 if _lpString2 != 0:93 ustr2 = uhookerAPI.readunicode( _lpString2 )94 for j in ustr2:95 if j != '\x00':96 str2 = str2 + j97 else:98 str2 = '<invalid>'99 100 print_debug("String1: %s\nString2: %s\n" % (str1, str2) )101102 logf("-- kernel32.lstrcatW( %.8X (%s), %.8X (%s) )\n" % (_lpString1, str1, _lpString2, str2) )103104105 hookcall.sendack()106 return107108109#int lstrcmp( 110# LPCTSTR lpString1,111# LPCTSTR lpString2112#);113def lstrcmp_handler(hookcall):114 print_debug( "kernel32.lstrcmp() called!" )115 uhookerAPI = hookcall.proxy116117 _lpString1 = hookcall.params[0]118 _lpString2 = hookcall.params[1]119120 str1 = '<invalid>'121 str2 = '<invalid>'122 if _lpString1 != 0:123 str1 = uhookerAPI.readasciiz( _lpString1 )124 if _lpString2 != 0:125 str2 = uhookerAPI.readasciiz( _lpString2 )126 127 print_debug("String1: %s\nString2: %s\n" % (str1, str2) )128129130 logf("-- kernel32.lstrcmp( %.8X (%s), %.8X (%s) )\n" % (_lpString1, str1, _lpString2, str2) )131132 hookcall.sendack()133 return134135def lstrcmpA_handler(hookcall):136 print_debug( "kernel32.lstrcmpA() called!" )137 uhookerAPI = hookcall.proxy138139 _lpString1 = hookcall.params[0]140 _lpString2 = hookcall.params[1]141142 str1 = '<invalid>'143 str2 = '<invalid>'144 if _lpString1 != 0:145 str1 = uhookerAPI.readasciiz( _lpString1 )146 if _lpString2 != 0:147 str2 = uhookerAPI.readasciiz( _lpString2 )148 149 print_debug("String1: %s\nString2: %s\n" % (str1, str2) )150151 logf("-- kernel32.lstrcmpA( %.8X (%s), %.8X (%s) )\n" % (_lpString1, str1, _lpString2, str2) )152153154 hookcall.sendack()155 return156157def lstrcmpW_handler(hookcall):158 print_debug( "kernel32.lstrcmpW() called!" )159 uhookerAPI = hookcall.proxy160161 _lpString1 = hookcall.params[0]162 _lpString2 = hookcall.params[1]163164 str1 = ''165 str2 = ''166 ustr1 = ''167 ustr2 = ''168 if _lpString1 != 0:169 ustr1 = uhookerAPI.readunicode( _lpString1 )170 for j in ustr1:171 if j != '\x00':172 str1 = str1 + j173 else:174 str1 = '<invalid>'175176 if _lpString2 != 0:177 ustr2 = uhookerAPI.readunicode( _lpString2 )178 for j in ustr2:179 if j != '\x00':180 str2 = str2 + j181 else:182 str2 = '<invalid>'183 184 print_debug("String1: %s\nString2: %s\n" % (str1, str2) )185186 logf("-- kernel32.lstrcmpW( %.8X (%s), %.8X (%s) )\n" % (_lpString1, str1, _lpString2, str2) )187188189 hookcall.sendack()190 return191192def lstrcmpi_handler(hookcall):193 print_debug( "kernel32.lstrcmpi() called!" )194 uhookerAPI = hookcall.proxy195196 _lpString1 = hookcall.params[0]197 _lpString2 = hookcall.params[1]198199 str1 = '<invalid>'200 str2 = '<invalid>'201 if _lpString1 != 0:202 str1 = uhookerAPI.readasciiz( _lpString1 )203 if _lpString2 != 0:204 str2 = uhookerAPI.readasciiz( _lpString2 )205 206 print_debug("String1: %s\nString2: %s\n" % (str1, str2) )207208 logf("-- kernel32.lstrcmpi( %.8X (%s), %.8X (%s) )\n" % (_lpString1, str1, _lpString2, str2) )209210211 hookcall.sendack()212 return213214def lstrcmpiA_handler(hookcall):215 print_debug( "kernel32.lstrcmpiA() called!" )216 uhookerAPI = hookcall.proxy217218 _lpString1 = hookcall.params[0]219 _lpString2 = hookcall.params[1]220221 str1 = '<invalid>'222 str2 = '<invalid>'223 if _lpString1 != 0:224 str1 = uhookerAPI.readasciiz( _lpString1 )225 if _lpString2 != 0:226 str2 = uhookerAPI.readasciiz( _lpString2 )227 228 print_debug("String1: %s\nString2: %s\n" % (str1, str2) )229230 logf("-- kernel32.lstrcmpiA( %.8X (%s), %.8X (%s) )\n" % (_lpString1, str1, _lpString2, str2) )231232233 hookcall.sendack()234 return235236def lstrcmpiW_handler(hookcall):237 print_debug( "kernel32.lstrcmpiW() called!" )238 uhookerAPI = hookcall.proxy239240 _lpString1 = hookcall.params[0]241 _lpString2 = hookcall.params[1]242243 str1 = ''244 str2 = ''245 ustr1 = ''246 ustr2 = ''247 if _lpString1 != 0:248 ustr1 = uhookerAPI.readunicode( _lpString1 )249 for j in ustr1:250 if j != '\x00':251 str1 = str1 + j252 else:253 str1 = '<invalid>'254255 if _lpString2 != 0:256 ustr2 = uhookerAPI.readunicode( _lpString2 )257 for j in ustr2:258 if j != '\x00':259 str2 = str2 + j260 else:261 str2 = '<invalid>'262 263 print_debug("String1: %s\nString2: %s\n" % (str1, str2) )264265266 logf("-- kernel32.lstrcmpiW( %.8X (%s), %.8X (%s) )\n" % (_lpString1, str1, _lpString2, str2) )267268 hookcall.sendack()269 return270271#LPTSTR lstrcpy( 272# LPTSTR lpString1,273# LPTSTR lpString2274#);275def lstrcpy_handler(hookcall):276 print_debug( "kernel32.lstrcpy() called!" )277 uhookerAPI = hookcall.proxy278279 _lpDest = hookcall.params[0]280 _lpSrc = hookcall.params[1]281282 src = '<invalid>'283 print_debug( "Dst: %.8X" % int(_lpDest) )284285 if _lpSrc != 0:286 src = uhookerAPI.readasciiz( _lpSrc )287288 print_debug("Src: %s\n" % src)289290 logf("-- kernel32.lstrcpy( %.8X , %.8X (%s) )\n" % (_lpDest, _lpSrc, src) )291292 hookcall.sendack()293 return294295def lstrcpyA_handler(hookcall):296 print_debug( "kernel32.lstrcpyA() called!" )297 uhookerAPI = hookcall.proxy298299 _lpDest = hookcall.params[0]300 _lpSrc = hookcall.params[1]301302 src = '<invalid>'303 print_debug( "Dst: %.8X" % int(_lpDest) )304305 if _lpSrc != 0:306 src = uhookerAPI.readasciiz( _lpSrc )307308 print_debug("Src: %s" % src)309310 logf("-- kernel32.lstrcpyA( %.8X , %.8X (%s) )\n" % (_lpDest, _lpSrc, src) )311312 hookcall.sendack()313 return314315def lstrcpyW_handler(hookcall):316 print_debug( "kernel32.lstrcpyW() called!" )317 uhookerAPI = hookcall.proxy318319 _lpDest = hookcall.params[0]320 _lpSrc = hookcall.params[1]321322 src = ''323 usrc = ''324 print_debug( "Dst: %.8X" % int(_lpDest) )325326 if _lpSrc != 0:327 usrc = uhookerAPI.readunicode( _lpSrc )328 for j in usrc:329 if j != '\x00':330 src = src + j331 else:332 src = '<invalid>'333334 print_debug("Src: %s" % src)335336 logf("-- kernel32.lstrcpyW( %.8X , %.8X (%s) )\n" % (_lpDest, _lpSrc, src) )337338 hookcall.sendack()339 return340341342#LPTSTR lstrcpyn( 343# LPTSTR lpString1,344# LPCTSTR lpString2,345# int iMaxLength346#);347def lstrcpyn_handler(hookcall):348 print_debug( "kernel32.lstrcpyn() called!" )349 uhookerAPI = hookcall.proxy350351 _lpDest = hookcall.params[0]352 _lpSrc = hookcall.params[1]353 _iMaxLen = hookcall.params[2]354355 src = '<invalid>'356 print_debug( "Dst: %.8X" % int(_lpDest) )357358 if _lpSrc != 0:359 src = uhookerAPI.readasciiz( _lpSrc )360361 print_debug("Src: %s" % src)362 print_debug("Len: %d" % _iMaxLen )363364365 logf("-- kernel32.lstrcpyn( %.8X , %.8X (%s), %d )\n" % (_lpDest, _lpSrc, src, _iMaxLen) )366367 hookcall.sendack()368 return369370def lstrcpynA_handler(hookcall):371 print_debug( "kernel32.lstrcpynA() called!" )372 uhookerAPI = hookcall.proxy373374 _lpDest = hookcall.params[0]375 _lpSrc = hookcall.params[1]376 _iMaxLen = hookcall.params[2]377378 src = '<invalid>'379 print_debug( "Dst: %.8X" % int(_lpDest) )380381 if _lpSrc != 0:382 src = uhookerAPI.readasciiz( _lpSrc )383384 print_debug("Src: %s" % src)385 print_debug("Len: %d" % _iMaxLen )386387388 logf("-- kernel32.lstrcpynA( %.8X , %.8X (%s), %d )\n" % (_lpDest, _lpSrc, src, _iMaxLen) )389390 hookcall.sendack()391 return392393def lstrcpynW_handler(hookcall):394 print_debug( "kernel32.lstrcpynW() called!" )395 uhookerAPI = hookcall.proxy396397 _lpDest = hookcall.params[0]398 _lpSrc = hookcall.params[1]399 _iMaxLen = hookcall.params[2]400401 src = ''402 usrc = ''403 print_debug( "Dst: %.8X" % int(_lpDest) )404405 if _lpSrc != 0:406 usrc = uhookerAPI.readunicode( _lpSrc )407 for j in usrc:408 if j != '\x00':409 src = src + j410 else:411 src = '<invalid>'412413 print_debug("Src: %s" % src)414 print_debug("Len: %d" % _iMaxLen)415416417 logf("-- kernel32.lstrcpynW( %.8X , %.8X (%s), %d )\n" % (_lpDest, _lpSrc, src, _iMaxLen) )418419 hookcall.sendack()420 return421422423424#int lstrlen( 425# LPCTSTR lpString426#);427def lstrlen_handler(hookcall):428 print_debug( "kernel32.lstrlen() called!" )429 uhookerAPI = hookcall.proxy430431 _lpString = hookcall.params[0]432433 src = '<invalid>'434 if _lpSrc != 0:435 src = uhookerAPI.readasciiz( _lpString )436437 print_debug("String: %s" % src)438439 logf("-- kernel32.lstrlen( %.8X (%s) )\n" % (_lpString, src ) )440441 hookcall.sendack()442 return443444def lstrlenA_handler(hookcall):445 print_debug( "kernel32.lstrlenA() called!" )446 uhookerAPI = hookcall.proxy447448 _lpString = hookcall.params[0]449450 src = '<invalid>'451 if _lpString != 0:452 src = uhookerAPI.readasciiz( _lpString )453454 print_debug("String: %s" % src)455456457 logf("-- kernel32.lstrlenA( %.8X (%s) )\n" % (_lpString, src ) )458459 hookcall.sendack()460 return461462def lstrlenW_handler(hookcall):463 print_debug( "kernel32.lstrlenW() called!" )464 uhookerAPI = hookcall.proxy465466 _lpString = hookcall.params[0]467468 src = ''469 usrc = ''470 if _lpString != 0:471 usrc = uhookerAPI.readunicode( _lpString )472 for j in usrc:473 if j != '\x00':474 src = src + j475 else:476 src = '<invalid>'477478 print_debug("String: %s" % src)479480481 logf("-- kernel32.lstrlenW( %.8X (%s) )\n" % (_lpString, src ) )482483 hookcall.sendack()484 return485486487#int CompareString( 488# LCID Locale,489# DWORD dwCmpFlags,490# LPCTSTR lpString1,491# int cchCount1,492# LPCTSTR lpString2,493# int cchCount2494#);495496def CompareStringA_handler(hookcall):497 print_debug( "kernel32.CompareStringA() called!" )498 uhookerAPI = hookcall.proxy499500 _Locale = hookcall.params[0]501 _dwCmpFlags = hookcall.params[1]502 _lpString1 = hookcall.params[2]503 _cchCount1 = hookcall.params[3]504 _lpString2 = hookcall.params[4]505 _cchCount2 = hookcall.params[5]506507 print_debug("Locale: %d" % int(_Locale) )508 print_debug("dwCmpFlags: %d" % int(_dwCmpFlags) )509510 str1 = '<invalid>'511 if _lpString1 != 0:512 tmp = uhookerAPI.readasciiz( _lpString1 )513 for x in xrange(0, _cchCount1-1 ):514 if str1[x] != '\x00':515 tmp = tmp + str1[x]516 str1 = tmp517518 str2 = '<invalid>'519 if _lpString2 != 0:520 str2 = uhookerAPI.readasciiz( _lpString2 )521 for x in xrange( 0, _cchCount2-1 ):522 if str2[x] != '\x00':523 tmp = tmp + str2[x]524 str2 = tmp525526 print_debug("String1: %s" % str1)527 print_debug("String2: %s" % str2)528529530 logf("-- kernel32.CompareStringA( %d, %d, %.8X (%s), %d, %.8X (%s), %d )\n" % (_Locale, _dwCmpFlags, _lpString1, str1, _cchCount1, _lpString2, str2, _cchCount2 ) )531532533534 hookcall.sendack()535 return536537def CompareStringW_handler(hookcall):538 print_debug( "kernel32.CompareStringW() called!" )539 uhookerAPI = hookcall.proxy540541 _Locale = hookcall.params[0]542 _dwCmpFlags = hookcall.params[1]543 _lpString1 = hookcall.params[2]544 _cchCount1 = hookcall.params[3]545 _lpString2 = hookcall.params[4]546 _cchCount2 = hookcall.params[5]547548549 print_debug("Locale: %d" % _Locale )550 print_debug("dwCmpFlags: %d" % _dwCmpFlags )551552 str1 = ''553 ustr1 = ''554 if _lpString1 != 0:555 ustr1 = uhookerAPI.readunicode( _lpString1 )556 for x in xrange(0, (_cchCount1-1)*2 ):557 if ustr1[x] != '\x00':558 str1 = str1 + ustr1[x]559 else:560 str1 = '<invalid>'561562563564 str2 = ''565 ustr2 = ''566 if _lpString2 != 0:567 ustr2 = uhookerAPI.readunicode( _lpString2 )568 for x in xrange(0, (_cchCount2-1)*2):569 if ustr2[x] != '\x00':570 str2 = str2 + ustr2[x]571 else:572 str2 = '<invalid>'573574575 print_debug("String1: %s" % str1)576 print_debug("String2: %s" % str2)577578 logf("-- kernel32.CompareStringw( %d, %d, %.8X (%s), %d, %.8X (%s), %d )\n" % (_Locale, _dwCmpFlags, _lpString1, str1, _cchCount1, _lpString2, str2, _cchCount2 ) )579580581 hookcall.sendack()582 return583
...
code4life_l3.py
Source:code4life_l3.py
1import sys2import math3# Bring data on patient samples from the diagnosis machine to the laboratory with enough molecules to produce medicine!4def print_debug(text):5 print(text, file=sys.stderr)6 7def get_distance(start, end):8 index_matrx = {9 'START_POS' : 0,10 'SAMPLES' : 1,11 'DIAGNOSIS' : 2,12 'MOLECULES' : 3,13 'LABORATORY': 414 }15 start_i = index_matrx[start]16 end_i = index_matrx[end]17 distance_matrix = [18 [0,2,2,2,2],19 [0,3,3,3,3],20 [0,3,0,3,4],21 [0,3,3,0,3],22 [0,3,4,3,0]23 ]24 return distance_matrix[start_i][end_i]25def is_sample_diagnosed(sample):26 if sample['health'] != -1:27 return True28 return False29def undiagnosed_sample_count(samples):30 undiagnosed_count = 031 for sample_id in samples.keys():32 if not is_sample_diagnosed(samples[sample_id]):33 undiagnosed_count += 134 print_debug('my undiagnosed sample count:{}'.format(undiagnosed_count))35 return undiagnosed_count36def is_expertise_enough_for_my_sample(myexpertise, sample):37 #print_debug('validing sample:{}'.format(sample))38 molecule_limit = 1039 max_molecule = 540 for molecule, needed in sample['cost'].items():41 print_debug("checking {}: needed({}), myexp({}), available({})".format(molecule, needed, myexpertise[molecule], available[molecule]))42 molecule_limit = molecule_limit - (needed - myexpertise[molecule])43 if needed > (max_molecule + myexpertise[molecule]):44 print_debug("needed({}) > exp({}) + {}".format(needed, myexpertise[molecule],max_molecule))45 return False46 break47 if molecule_limit < 0:48 print_debug("needed({}) + exp({}) > {}".format(needed, myexpertise[molecule],molecule_limit))49 return False50 break51 return True52def get_validated_sample_count(myexpertise, samples):53 validated_count = 054 for sample_id in samples.keys():55 print_debug('validating sample:{}'.format(sample_id))56 if is_expertise_enough_for_my_sample(myexpertise, samples[sample_id]):57 validated_count += 158 print_debug('validated_count:{}'.format(validated_count))59 return validated_count60 61 62def ready_for_lab_sample_id(myexpertise, storages, samples):63 for sample_id in samples.keys():64 print_debug('submit id:{}?'.format(sample_id))65 count = 066 for molecule, needed in samples[sample_id]['cost'].items():67 if needed <= myexpertise[molecule] + storages[molecule] and needed != -1:68 print_debug("{},needed({}),exp({}),storage({})".format(molecule.upper(), needed, myexpertise[molecule],storages[molecule]))69 count += 170 print_debug('count:{}'.format(count))71 if count == 5:72 print_debug('ready_for_submit_sample_id:{}'.format(sample_id))73 return sample_id74 return -175project_count = int(input())76projects_needs = []77for i in range(project_count):78 needs_value = [int(j) for j in input().split()]79 needs_key = ['a','b','c','d','e']80 needs = dict(zip(needs_key, needs_value))81 projects_needs.append(needs)82print_debug("projects_needs:{}".format(projects_needs))83game_loop = 184# game loop85while True:86 print_debug("game_loop:{}".format(game_loop))87 88 89 # Contains both players, 0 is myself90 targets = []91 etas = []92 scores = []93 storages = []94 expertises = []95 96 # Contains data used for both player97 available = {}98 samples = {}99 mysamples = {}100 101 for i in range(2):102 storage = {}103 expertise = {}104 target, eta, score, storage_a, storage_b, storage_c, storage_d, storage_e, expertise_a, expertise_b, expertise_c, expertise_d, expertise_e = input().split()105 targets.append(target)106 etas.append(int(eta))107 scores.append(int(score))108 storage['a'] = int(storage_a)109 storage['b'] = int(storage_b)110 storage['c'] = int(storage_c)111 storage['d'] = int(storage_d)112 storage['e'] = int(storage_e)113 storages.append(storage)114 115 expertise['a'] = int(expertise_a)116 expertise['b'] = int(expertise_b)117 expertise['c'] = int(expertise_c)118 expertise['d'] = int(expertise_d)119 expertise['e'] = int(expertise_e)120 expertises.append(expertise)121 122 available['a'], available['b'], available['c'], available['d'], available['e'] = [int(i) for i in input().split()]123 sample_count = int(input())124 for i in range(sample_count):125 sample_id, carried_by, rank, expertise_gain, health, cost_a, cost_b, cost_c, cost_d, cost_e = input().split()126 sample = {}127 sample_data = {}128 sample_data['carried_by'] = int(carried_by)129 sample_data['rank'] = int(rank)130 sample_data['experties_gain'] = expertise_gain131 sample_data['health'] = int(health)132 sample_data['cost'] = {}133 sample_data['cost']['a'] = int(cost_a)134 sample_data['cost']['b'] = int(cost_b)135 sample_data['cost']['c'] = int(cost_c)136 sample_data['cost']['d'] = int(cost_d)137 sample_data['cost']['e'] = int(cost_e)138 samples[sample_id] = sample_data139 140 if int(carried_by) == 0:141 mysamples[sample_id] = sample_data142 my_undiagnosed_sample_count = undiagnosed_sample_count(mysamples)143 validated_sample_count = get_validated_sample_count(expertises[0], mysamples)144 submit_sample_id = ready_for_lab_sample_id(expertises[0], storages[0], mysamples)145 146 print_debug("my targets:{}".format(targets[0]))147 print_debug("my eta:{}".format(etas[0]))148 print_debug("my expertise:{}".format(expertises[0]))149 #print_debug("all samples:{}".format(samples))150 print_debug("my samples:{}".format(mysamples))151 152 if etas[0] > 0:153 print("WAIT")154 continue155 156 if targets[0] == 'START_POS' or (targets[0] != 'SAMPLES' and len(mysamples) == 0):157 print_debug("====1====")158 print("GOTO SAMPLES")159 continue160 if targets[0] != 'DIAGNOSIS' and my_undiagnosed_sample_count != 0 and len(mysamples) == 3:161 print_debug("====2====")162 print("GOTO DIAGNOSIS")163 continue164 165 if targets[0] != 'MOLECULES' and len(mysamples) != 0 and my_undiagnosed_sample_count == 0 and submit_sample_id == -1 and validated_sample_count == len(mysamples):166 print_debug("====3====")167 print("GOTO MOLECULES")168 continue169 170 if targets[0] != 'LABORATORY' and submit_sample_id != -1:171 print_debug("====4====")172 print_debug('ready to submit_id:{}'.format(submit_sample_id))173 print("GOTO LABORATORY")174 continue175 176 if targets[0] == 'SAMPLES' and len(mysamples) < 3:177 print_debug("====5====")178 rank = 2179 if sum(expertises[0].values()) > 5:180 rank = 3181 print_debug("rank:{}".format(rank))182 print("CONNECT {}".format(rank))183 continue184 185 if targets[0] == 'DIAGNOSIS' and (my_undiagnosed_sample_count != 0 or validated_sample_count < len(mysamples)):186 print_debug("====6====")187 for current_id in mysamples.keys():188 print_debug('Diagnosing sample id:{}'.format(current_id))189 working_sample = samples[current_id]190 working_sample_id = current_id191 if is_sample_diagnosed(working_sample):192 if not is_expertise_enough_for_my_sample(expertises[0], working_sample):193 print_debug('send back to cloud:{}'.format(working_sample_id))194 print("CONNECT {}".format(working_sample_id))195 break196 else:197 print_debug('Diagnose ID:{}'.format(working_sample_id))198 print("CONNECT {}".format(working_sample_id))199 break200 continue201 202 if targets[0] == 'MOLECULES':203 print_debug("====7====")204 for current_id in mysamples.keys():205 working_sample = samples[current_id]206 working_sample_id = current_id207 print_debug("working sample id {}".format(working_sample_id))208 for molecule, needed in working_sample['cost'].items():209 inner_loop_break = False210 switch_sample = False211 print_debug("getting {}: needed:{}, storage:{}, exp:{}, available:{}".format(molecule.upper(), needed, storages[0][molecule], expertises[0][molecule], available[molecule]))212 if available[molecule] == 0 and (storages[0][molecule] + expertises[0][molecule]) < needed:213 print_debug('+++++++++++++++++')214 print("GOTO SAMPLES")215 inner_loop_break = True216 break217 if (storages[0][molecule] + expertises[0][molecule]) < needed:218 print("CONNECT {}".format(molecule.upper()))219 inner_loop_break = True220 break221 if inner_loop_break:222 break223 if targets[0] == 'LABORATORY':224 print_debug("====8====")225 print("CONNECT {}".format(submit_sample_id))226 continue227 ...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!