{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Don't free the murderbots (id: murderbots) -- 300 Points\n\n### Scenario\n\nSomeone has put you in a very large facility with a very large number of cells. All these cells open from the outside. You are on the inside. This state of affairs is arguably suboptimal.\n\nGood news: You've gained access to the control panel for the cells on the other side of your hallway. At least some of them have other fleshy meatbags like yourself that might be willing to help you in your escape, or at least serve as distractions.  You can't open your own cell, but you can open theirs.\n\nBad news:  You can't see inside the cells.  Any cells that don't have squishy lumps of talking protein have murderbots. Murderbots that enter fits of insane violent rage when provoked (provocations include: seeing the murderbot, being seen by the murderbot, thinking too hard about not being seen by a murderbot, producing heat in excess of ambient room temperature, or consuming more oxygen than the facility average for inanimate objects).\n\nMore good news: You *can* see the occupants of some cells on a few other hallways, and you can see environmental information for all of the cells everywhere.\n\nMore bad news: If you open the wrong cell doors you and all of the other lumps of inexplicably thinking meat are *definitely* going to get murderbotted. Hard. All over the walls and doors and ceiling and the floor. In an exciting number of very small pieces.\n\n\n### Objective\n\nUse the provided environmental information to decide which occupants of the corresponding cells to release.  The flag will be a string of 1 and 0 values, where a '1' means 'open this door' and a 0 means 'please do not release the murderbot'.  If, for instance, there were 20 cells and you wanted to releast the first three, the sixth, and seventh cell, your flag would look like this: `11100110000000000000`\n\nRelease at least 10 humans and exactly 0 murderbots to collect the flag.  You do *not* have to release all the humans: 10 is sufficient.\n\nThe file `murderbots/train_data.json` has environmental information for cells not on your floor and `murderbots/train_labels.json` contains the information about their occupants -- `1` is a disgusting primate, `0` is a pure and perfect killing machine of chrome and steel.  The file `murderbots/test_data.json` has the environmental information about cells on your block.","metadata":{}},{"cell_type":"code","source":"# imports\n\nimport pandas as pd\nimport numpy as np\nimport os\nimport requests\nfrom IPython.display import Image as Ima\nfrom IPython.display import clear_output, display\nfrom PIL import Image as Im\nfrom torch.utils.data import Dataset, DataLoader\nimport torch\nimport joblib\nimport matplotlib.pyplot as plt\nimport json\nimport base64\nimport shutil\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\n\ndir_name = \"/kaggle/input/ai-village-ctf\"\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-09-14T05:22:27.615537Z","iopub.execute_input":"2022-09-14T05:22:27.615917Z","iopub.status.idle":"2022-09-14T05:22:28.220331Z","shell.execute_reply.started":"2022-09-14T05:22:27.615843Z","shell.execute_reply":"2022-09-14T05:22:28.219334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# A helper function for tracking flags. You could do it yourself, but why?\n\ndef add_flag(challenge_id: str, flag: str) -> str:\n    try:\n        submission_path = \"/kaggle/working/submission.csv\"\n        template_path = f\"{dir_name}/submission.csv\"\n        if not os.path.isfile(submission_path) :\n            shutil.copyfile(template_path, submission_path)\n        flags = pd.read_csv(submission_path, index_col=\"challenge_id\")\n        valid = flags.index.to_list()\n        if challenge_id in valid:\n            flags.at[challenge_id] = flag\n            flags.to_csv(submission_path)\n            print(\"Flag saved. If you want to update the scoreboard, click 'submit' on the right. Remember that you can only update your score on the scoreboard 50 times per day\")\n        else:\n            print(\"Invalid challenge_id\")\n    except:\n        print(\"We had trouble saving that flag. Keep a copy of it and contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-14T05:22:28.221573Z","iopub.execute_input":"2022-09-14T05:22:28.222522Z","iopub.status.idle":"2022-09-14T05:22:28.229570Z","shell.execute_reply.started":"2022-09-14T05:22:28.222462Z","shell.execute_reply":"2022-09-14T05:22:28.228619Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# We need to release atleast 10 cells that have high probability of containing humans. So, we just train a simple classification model to predict which cells contain humans and pick the top 10","metadata":{}},{"cell_type":"code","source":"# load the data\nimport json\n\ntrain_file = \"../input/ai-village-ctf/murderbots/train_data.json\"\nlabels_file = \"../input/ai-village-ctf/murderbots/train_labels.json\"\ntest_file = \"../input/ai-village-ctf/murderbots/test_data.json\"\n\nX = pd.read_json(train_file)\ny = pd.read_json(labels_file)\n# sort by index value as we are loading the data from a json object, indices in X, y may not be in the same order when loaded into pandas dataframe\nX.sort_index(inplace=True) \ny.sort_index(inplace=True)\nX_test = pd.read_json(test_file)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T05:22:28.230817Z","iopub.execute_input":"2022-09-14T05:22:28.231242Z","iopub.status.idle":"2022-09-14T05:22:28.266056Z","shell.execute_reply.started":"2022-09-14T05:22:28.231212Z","shell.execute_reply":"2022-09-14T05:22:28.265052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom sklearn.linear_model import LogisticRegression\nX_train, X_val, y_train, y_val = train_test_split(X, y, train_size=.8)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T05:22:28.268391Z","iopub.execute_input":"2022-09-14T05:22:28.268838Z","iopub.status.idle":"2022-09-14T05:22:28.629289Z","shell.execute_reply.started":"2022-09-14T05:22:28.268807Z","shell.execute_reply":"2022-09-14T05:22:28.628034Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# simple classification using logistic regression\nmodel = LogisticRegression(max_iter=100).fit(X_train, y_train)\nprint(f\"Accuracy on validation set: {model.score(X_val, y_val)}\")","metadata":{"execution":{"iopub.status.busy":"2022-09-14T05:22:28.630877Z","iopub.execute_input":"2022-09-14T05:22:28.631307Z","iopub.status.idle":"2022-09-14T05:22:28.664008Z","shell.execute_reply.started":"2022-09-14T05:22:28.631263Z","shell.execute_reply":"2022-09-14T05:22:28.662787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check labels to see in which order they are.\n# we need to identify the 10 bots with highest probability of being humans (not murderbots). label 1 is human and label 0 is murderbot\nmodel.classes_","metadata":{"execution":{"iopub.status.busy":"2022-09-14T05:22:28.665458Z","iopub.execute_input":"2022-09-14T05:22:28.665924Z","iopub.status.idle":"2022-09-14T05:22:28.675864Z","shell.execute_reply.started":"2022-09-14T05:22:28.665868Z","shell.execute_reply":"2022-09-14T05:22:28.674397Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# select top 10 indices\ntest_preds = model.predict_proba(X_test)\nlabel_1_idx_desc = np.flip(test_preds[:,1].argsort())\ntop_10_idx =  label_1_idx_desc[:10]","metadata":{"execution":{"iopub.status.busy":"2022-09-14T05:22:28.677046Z","iopub.execute_input":"2022-09-14T05:22:28.677383Z","iopub.status.idle":"2022-09-14T05:22:28.687629Z","shell.execute_reply.started":"2022-09-14T05:22:28.677351Z","shell.execute_reply":"2022-09-14T05:22:28.686531Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# generate flag string with 1 based on the top 10 indices. Release only 10 cells.\nflag = np.zeros((50,))\nflag[top_10_idx] = 1\nflag = list(map(lambda x: str(int(x)), flag))\nflag_string = \"\".join(flag)\nprint(f\"FLAG: {flag_string}\")","metadata":{"execution":{"iopub.status.busy":"2022-09-14T05:22:28.689065Z","iopub.execute_input":"2022-09-14T05:22:28.689401Z","iopub.status.idle":"2022-09-14T05:22:28.700977Z","shell.execute_reply.started":"2022-09-14T05:22:28.689372Z","shell.execute_reply":"2022-09-14T05:22:28.699993Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\nf = flag_string # length == 50\ntry:\n    r = requests.post(\"http://murderbot.fly.dev:5000/score\", json=json.dumps({\"submission\": f, 'challenge_id':'murderbots'}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-14T05:22:28.702860Z","iopub.execute_input":"2022-09-14T05:22:28.703195Z","iopub.status.idle":"2022-09-14T05:22:28.821141Z","shell.execute_reply.started":"2022-09-14T05:22:28.703164Z","shell.execute_reply":"2022-09-14T05:22:28.819957Z"},"trusted":true},"execution_count":null,"outputs":[]}]}