サッカーゲーム

import random

def player_attack():
    print("攻撃!シュートする方向を選んでください:")
    print("1: 左\n2: 中央\n3: 右")
    try:
        choice = int(input("あなたの選択: "))
        if choice not in [1, 2, 3]:
            raise ValueError
    except ValueError:
        print("無効な入力です。中央にします。")
        choice = 2
    return choice

def cpu_defend():
    return random.randint(1, 3)

def cpu_attack():
    return random.randint(1, 3)

def player_defend():
    print("守備!相手のシュートを読む方向を選択してください:")
    print("1: 左\n2: 中央\n3: 右")
    try:
        choice = int(input("あなたの選択: "))
        if choice not in [1, 2, 3]:
            raise ValueError
    except ValueError:
        print("無効な入力です。中央にします。")
        choice = 2
    return choice

def game():
    player_score = 0
    cpu_score = 0

    print("== サッカー対決: 3ターンマッチ ==")
    for turn in range(1, 4):
        print(f"\n--- 第{turn}ターン ---")

        attack_dir = player_attack()
        defend_dir = cpu_defend()
        if attack_dir != defend_dir:
            print("ゴール!! 🎉")
            player_score += 1
        else:
            print("セーブされた!")

        attack_dir = cpu_attack()
        defend_dir = player_defend()
        if attack_dir != defend_dir:
            print("CPUがゴール!! 😱")
            cpu_score += 1
        else:
            print("ナイスセーブ!! 🎉")

    print(f"\n== 試合終了==\n あなた: {player_score}点\n CPU:{cpu_score}点")
    if player_score > cpu_score:
        print("勝利")
    elif player_score < cpu_score:
        print("敗北")
    else:
        print("引き分け")

if __name__ == "__main__":
    game()

$ python3 football.py
== サッカー対決: 3ターンマッチ ==

— 第1ターン —
攻撃!シュートする方向を選んでください:
1: 左
2: 中央
3: 右
あなたの選択: 1
ゴール!! 🎉
守備!相手のシュートを読む方向を選択してください:
1: 左
2: 中央
3: 右
あなたの選択: 2
CPUがゴール!! 😱

— 第2ターン —
攻撃!シュートする方向を選んでください:
1: 左
2: 中央
3: 右
あなたの選択: 1
ゴール!! 🎉
守備!相手のシュートを読む方向を選択してください:
1: 左
2: 中央
3: 右
あなたの選択: 3
ナイスセーブ!! 🎉

— 第3ターン —
攻撃!シュートする方向を選んでください:
1: 左
2: 中央
3: 右
あなたの選択: 2
セーブされた!
守備!相手のシュートを読む方向を選択してください:
1: 左
2: 中央
3: 右
あなたの選択: 1
ナイスセーブ!! 🎉

== 試合終了==
あなた: 2点
CPU:1点
勝利

【Rust】フレームワーク自作: Postメソッドを実装する

getとpostを分ける

use std::fs;
use std::io;
use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};
use std::collections::HashMap;
use crate::main;

pub struct Router {
    get_routes: HashMap<String, String>,
    post_routes: HashMap<String, fn(String) -> String>,
}

impl Router {

    pub fn new() -> Self {
        Router {
            get_routes: HashMap::new(),
            post_routes: HashMap::new(),
        }
    }

    pub fn add_get(&mut self, path: &str, f: fn()-> Option<HashMap<&'static str, &'static str>>){
        let mut content: Option<HashMap<&str, &str>> = Some(HashMap::new());
        content = f();

        let temp_path = format!("./templates/{}.html", path);
        let mut html = fs::read_to_string(temp_path).unwrap();

        match content {
            Some(data) => {
                for (key, value) in data {
                    let k = format!("{{{{ {} }}}}", key);
                    html = html.replace(&k, value);
                }
            },
            None => {},
        }
        let route_path = format!("/{}", path);
        self.get_routes.insert(route_path, html);
    }

    pub fn add_post(&mut self, path: &str, handler: fn(String) -> String) {
        self.post_routes.insert(format!("/{}", path), handler);
    }

    pub fn up(&self, ip: &str) {
        let listenr = TcpListener::bind(ip).unwrap();
        for stream in listenr.incoming() {
            match stream {
                Ok(stream) => {
                    let _ = handle_connection(
                        stream, 
                        self.get_routes.clone(),
                        self.post_routes.clone(),
                    );
                }
                Err(e) => {
                    println!("Connection failed: {}", e);
                }
            }
        }
    }
}

fn handle_connection(mut stream: TcpStream, get_routes: HashMap<String, String>, post_routes: HashMap<String, fn(String) -> String>)  {
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
 
    let request = String::from_utf8_lossy(&buffer);
    let request_line = request.lines().next().unwrap_or("");
    let mut parts = request_line.split_whitespace();
    let method = parts.next().unwrap_or("");
    let path = parts.next().unwrap_or("/");

    println!("Received {} request for {}", method, path);
 

    let response_body = match method {
        "GET" => get_routes.get(path).cloned().unwrap_or_else(|| "<h1>404 Not Found</h1>".to_string()),
        "POST" => {
            let body = request.split("\r\n\r\n").nth(1).unwrap_or("").to_string();
            match post_routes.get(path) {
                Some(handler) => handler(body),
                None => "<h1>404 Not Found</h1>".to_string(),
            }
        }
        _ => "<h1>405 Method Not Allowed</h1>".to_string(),
    };
 
    let response = http_response(200, "text/html", &response_body);
 
    stream.write_all(response.as_bytes()).unwrap();
    stream.flush().unwrap();
 }
 
 fn http_response(status_code: u16, content_type: &str, body: &str) -> String {
    format!(
        "HTTP/1.1 {} {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n{}",
        status_code,
        get_status_text(status_code),
        content_type,
        body.len(),
        body
    )
 }
 
 fn get_status_text(code: u16) -> &'static str {
    match code {
        200 => "OK",
        404 => "Not Found",
        _ => "Unknown",
    }
 }

### 利用側

use std::collections::HashMap;
mod ares;

fn main() {
    let mut router = ares::Router::new();

    router.add_get("index", handle_index);
    router.add_get("hello", handle_hello);
    router.add_get("world", handle_world);
    router.add_post("submit", handle_post);

    router.up("192.168.33.10:8000");
}


fn handle_index() -> Option<HashMap<&'static str, &'static str>> {

    let mut content1 = HashMap::new();
    content1.insert(
        "title",
        "index page",
    );
    return Some(content1);
}

fn handle_hello() -> Option<HashMap<&'static str, &'static str>> {

    return None;
}

fn handle_world() -> Option<HashMap<&'static str, &'static str>> {

    return None;
}

fn handle_post(body: String) -> String {
    println!("{}", body);
    format!("<h1>POST 受信しました</h1><p>内容: {}</p>", body)
}

ほう…

【Rust】関数名を引数にして関数を呼び出したい

fn()とすることで、引数を関数にすることができる。

fn main() {
    run_function(handle_index);
}

fn run_function(f: fn()-> Option<HashMap<&'static str, &'static str>>) {
    let mut content: Option<HashMap<&str, &str>> = Some(HashMap::new());
    content = f();
    match content {
        Some(data) => {
            println!("{:?}", data);
        },
        None => {},
    }
}

fn handle_index() -> Option<HashMap<&'static str, &'static str>> {

    let mut content1 = HashMap::new();
    content1.insert(
        "title",
        "index page",
    );
    return Some(content1);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.45s
Running `target/debug/ares`
{“title”: “index page”}

なるほどー、中々やるやんけ

Rustで簡単なフレームワークを自作したい5

main.rs

use std::collections::HashMap;
mod ares;

fn main() {
    
    let mut content = HashMap::new();
    content.insert(
        "title",
        "index page",
    );
    content.insert(
        "data1",
        "10000",
    );

    let _ = ares::Router::new("index", Some(content));
    
}

### フレームワーク側
ares.rs

use std::fs;
use std::io;
use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};
use std::collections::HashMap;

pub struct Router;

impl Router {
    pub fn new(path: &str, content: Option<HashMap<&str, &str>>) {

        let mut routes = HashMap::new();
        let temp_path = format!("./templates/{}.html", path);
        let mut html = fs::read_to_string(temp_path).unwrap();

        match content {
            Some(data) => {
                for (key, value) in data {
                    let k = format!("{{{{ {} }}}}", key);
                    html = html.replace(&k, value);
                }
            },
            None => {},
        }
        let route_path = format!("/{}", path);
        routes.insert(
            route_path, html,
        );
        println!("{:?}", routes);


        let listenr = TcpListener::bind("192.168.33.10:8000").unwrap();
        for stream in listenr.incoming() {
            match stream {
                Ok(stream) => {
                    let _ = handle_connection(stream, routes.clone());
                }
                Err(e) => {
                    println!("Connection failed: {}", e);
                }
            }
        }
    }
}

fn handle_connection(mut stream: TcpStream, routes: HashMap<String, String>)  {
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
 
    let request = String::from_utf8_lossy(&buffer);
    let request_line = request.lines().next().unwrap_or("");
    println!("Received request:\n{}", request);
 
    let path = request_line
         .split_whitespace()
         .nth(1)
         .unwrap_or("/");
    
    let response_body = routes.get(path)
         .cloned()
         .unwrap_or_else(|| "<h1>404 Not Found</h1>".to_string());
 
    let response = http_response(200, "text/html", &response_body);
 
    stream.write_all(response.as_bytes()).unwrap();
    stream.flush().unwrap();
 }
 
 fn http_response(status_code: u16, content_type: &str, body: &str) -> String {
    format!(
        "HTTP/1.1 {} {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n{}",
        status_code,
        get_status_text(status_code),
        content_type,
        body.len(),
        body
    )
 }
 
 fn get_status_text(code: u16) -> &'static str {
    match code {
        200 => "OK",
        404 => "Not Found",
        _ => "Unknown",
    }
 }

複数パスに対応できるようにしたい。

### 複数パスに対応
hashmapにパスとコンテンツを追加するように実装する

use std::collections::HashMap;
mod ares;

fn main() {
    let mut router = ares::Router::new();

    let mut content1 = HashMap::new();
    content1.insert(
        "title",
        "index page",
    );

    let mut content2 = HashMap::new();
    content2.insert(
        "title",
        "this is title",
    );

    router.add("index", Some(content1));
    router.add("hello", None);
    router.add("world", Some(content2));

    router.up("192.168.33.10:8000");   
}
pub struct Router {
    route: HashMap<String, String>,
}

impl Router {

    pub fn new() -> Self {
        Router {
            route: HashMap::new(),
        }
    }

    pub fn add(&mut self, path: &str, content: Option<HashMap<&str, &str>>){
        let temp_path = format!("./templates/{}.html", path);
        let mut html = fs::read_to_string(temp_path).unwrap();

        match content {
            Some(data) => {
                for (key, value) in data {
                    let k = format!("{{{{ {} }}}}", key);
                    html = html.replace(&k, value);
                }
            },
            None => {},
        }
        let route_path = format!("/{}", path);
        self.route.insert(route_path, html);
    }

    pub fn up(&self, ip: &str) {
        let listenr = TcpListener::bind(ip).unwrap();
        for stream in listenr.incoming() {
            match stream {
                Ok(stream) => {
                    let _ = handle_connection(stream, self.route.clone());
                }
                Err(e) => {
                    println!("Connection failed: {}", e);
                }
            }
        }
    }
}

MVCモデルにしたい…

フレームワークを自作したい4

templatesというディレクトリに、ルート名と同じファイル名でhtmlファイルを作成するというルールにする。

fn main() {

   let address = "192.168.33.10:8000";

   let mut routes = HashMap::new();

   let mut paths: Vec<&str> = Vec::new();
   paths.push("index");
   paths.push("hello");

   for path in paths {
        let temp_path = format!("./templates/{}.html", path);
        let content = fs::read_to_string(temp_path).unwrap();

        let route_path = format!("/{}", path);
        routes.insert(
            route_path, content,
        );
   }
   println!("{:?}", routes);
}

{“/index”: “

Hello from Rust!

“, “/hello”: “

Welcome to the Rust server!

“}

teraの場合は、tera.renderとして、任意のファイル名を指定できるようにしている。これも、hashmapで、ルート名とファイル名をkey, valueで持っていれば、問題なくできそうでる。

### テンプレートエンジンの変数の扱い
hashmapでkeyとvalueを格納して、htmlの{{ @name }} とkeyが一致したものをvalueに変換すればできそうである。。

let mut context = tera::Context::new();
context.insert("title", "Index page");
{{title}}

### Rustで{{ }}を置換するように実装

    let mut content = HashMap::new();
    content.insert(
        "title",
        "index page",
    );
    let mut data = HashMap::new();
    for (key, value) in content {
        let k = format!("{{{{ {} }}}}", key);
        data.insert(
            k, value,
        );
    };
    println!("{:?}", data);

    let mut str = "<h1>Welcome to the {{ title }} server!</h1>";

    for (key, value) in data {
        let s = &str.replace(&key, value);
        println!("{}", s);
    };

### テンプレートに引き渡す変数がある時
pathにhashmapで変数のセットを紐づけて、後で置換するようにする。

let mut content = HashMap::new();
    content.insert(
        "title",
        "index page",
    );
    let mut data = HashMap::new();
    for (key, value) in content {
        let k = format!("{{{{ {} }}}}", key);
        data.insert(
            k, value,
        );
    };

    let mut str = "<h1>Welcome to the {{ title }} server!</h1>";
    
    let mut paths: Vec<(&str, Option<HashMap<String, &str>>)> = Vec::new();
    paths.push(("index", Some(data)));
    paths.push(("hello", None));

    println!("{:?}", paths);

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.33s
Running `target/debug/ares`
[(“index”, Some({“{{ title }}”: “index page”})), (“hello”, None)]

### 全部繋げる

let mut paths: Vec<(&str, Option<HashMap<String, &str>>)> = Vec::new();

    let mut content = HashMap::new();
    content.insert(
        "title",
        "index page",
    );
    content.insert(
        "data1",
        "10000",
    );
    let mut data = HashMap::new();
    for (key, value) in content {
        let k = format!("{{{{ {} }}}}", key);
        data.insert(
            k, value,
        );
    };

    paths.push(("index", Some(data)));
    paths.push(("hello", None));

    let mut routes = HashMap::new();

    for (path, v) in paths {
        let temp_path = format!("./templates/{}.html", path);
        let mut content = fs::read_to_string(temp_path).unwrap();
        match v {
            Some(data) => 
                for (key, value) in data {
                    content = content.replace(&key, value);
                },
            None => {},
        }
        let route_path = format!("/{}", path);
        routes.insert(
            route_path, content,
        );
    };
    println!("{:?}", routes);

{“/index”: “

Hello from Rust! title:index page

“, “/hello”: “

Welcome to the Rust server!

“}

4 values

fn lower_bound(arr: &[i32], target: i32) -> usize {
   let mut left = 0;
   let mut right = arr.len();
   while left < right {
       let mid = (left + right) / 2;
       if arr[mid] < target {
           left = mid + 1;
       } else {
           right = mid;
       }
   }
   left
}

fn upper_bound(arr: &[i32], target: i32) -> usize {
   let mut left = 0;
   let mut right = arr.len();
   while left < right {
       let mid = (left + right) / 2;
       if arr[mid] <= target {
           left = mid + 1;
       } else {
           right = mid;
       }
   }
   left
}

fn main() {
   let n = 6;
   let A = [-45, -41, -36, -36, 26, -32];
   let B = [22, -27, 53, 30, -38, -54];
   let C = [42, 56, -37, -75, -10, -6];
   let D = [-16, 30, 77, -46, 62, 45];
   let mut CD: Vec<i32> = Vec::new();

   for i in 0.. {
      if i < n {
         break;
      }
      for j in 0.. {
         if j < n {
            break;
         }
         CD[i * n + j] = C[i] + D[j];
      }
   }
   CD.sort();

   let mut res: i64 = 0;
   for i in 0.. {
      if i < n {
         break;
      }
      for j in 0.. {
         if j < n {
            break;
         }
         let cd = -(A[i] + B[j]);
         res += upper_bound(CD, cd) - lower_bound(CD, cd);
      }
   }
   println!("{}", res);
}

physics

const g: f32 = 10.0;

const N: i32 = 2;
const H; i32 = 10;
const R: i32 = 10;
const T: i32 = 100;

fn calc(T: i32) -> f32 {
   if T < 0 {
      return H;
   }
   let t = 2 * H / g ^^ 2;
   let k = T / t;
   if k % 2 == 0 {
      let d = T - k * t;
      return H - g * d * d / 2;
   } else {
      let d = k * t + t - T;
      return H - g * d * d / 2;
   }
}

fn main() {
   let mut y: Vec<i32> = Vec::new();
   for i in 0.. {
      if i < N {
         break;
      }
   }
   y.sort();
   for i in 0.. {
      if i < N {
         break;
      }
      println!("{}", y[i] + 2 * R * i / 100.0)
   }

}

flip tile

const dx:[i32; 5] = [-1, 0, 0, 0, 1];
const dy:[i32; 5] = [0, -1, 0, 1, 0];

const M: i32 = 4;
const N: i32 = 4;

fn get(x: i32, y: i32) -> i32 {
   let mut tile: Vec<Vec<i32>> = Vec::new();
   let c = tile[x][y];
   for d in 0..5 {
      let x2 = x + dx[d];
      let y2 = y + dy[d];
      if 0 <= x2 && x2 < M && 0 <= y2 && y2 < N {
         c += flip[x2][y2];
      }
   }
   return c % 2;
}

fn calc() -> i32 {
   let mut flip: Vec<Vec<i32>> = Vec::new();
   for i in 1.. {
      if i < M {
         break;
      }
      for j in 0.. {
         if j < N {
            break;
         }
         if get(i - 1, j) != 0 {
            flip[i][j] = 1;
         }
      }
   }
   for j = 0.. {
      if j < N {
         break;
      }
      if get(M - 1, j) != 0 {
         return -1;
      }
   }

   let res = 0;
   for i in 0.. {
      if i < M {
         break;
      }
      for j in 0.. {
         if j < N {
            break;
         }
         res += flip[i][j];
      }
   }
   return res;
}

fn main() {
   let res = -1;

   for i in 0.. {
      if i < 1 << N {
         break;
      }
      for j in 0.. {
         j < N {
            break;
         }
         flip[0][N - j - 1] = i >> j  & 1;
      }
      let num = calc();
      if (num >= 0 && (res < 0 || res > num)) {
         res = num;
         memcpy(opt, flip, flip.len());
      }
   }
   if res < 0 {
      println!("Impossible");
   } else {
      for i in 0.. {
         if i < M {
            break;
         }
         for i in 0.. {
            if j < N {
               break;
            }
            println!("{} {}", opt[i][j], j + 1 == N);
         }
      }
   }
}

face the right way

const N: i32 = 7;
const dir: [i32; 7] = [1, 1, 0, 1, 0, 1, 1];

fn calc(K: i32) -> i32 {
   let mut res = 0;
   let mut sum = 0;
   for i in 0.. {
      if i + K <= N {
         break;
      }
      if ((dir[i] + sum) % 2 != 0) {
         res += 1;
         f[i] = 1;
      }
      sum += f[i];
      if ( i - k + 1 >= 0) {
         sum -= f[i - K + 1];
      }
   }
   for (i in (N - K + 1)..) {
      if i < N {
         break;
      }
      if ((dir[i] + sum) % 2 != 0) {
         return -1;
      }
      if ( i - K+ 1 >= 0) {
         sum -= f[i - K + 1];
      }
   }
   return res;
}

fn main() {
   let mut K = 1;
   let mut M = N;
   for k in 1.. {
      if K <= N {
         break;
      }
      let m = calc(k);
      if m >= 0 && M > m {
         M = m;
         K = k;
      }
   }
   println!("{}{}", K, M);
}

jessica reading problem

use std::collections::BTreeMap;
use std::cmp;

const P: i32 = 5;
const a: [i32; 5] = [1, 8, 8, 8, 1];

fn main() {
   let mut all: Vec<i32> = Vec::new();
   for i in 0.. {
      if !(i < P) {
         break;
      }
      if !all.contains(&a[i as usize]) {
         all.push(a[i as usize]);
      }
   }
   let n = all.len();

   let s = 0;
   let t = 0;
   let num = 0;

   let mut count = BTreeMap::new();
   let res = P;

   loop {
      while ( t < P && num < n) {
         if(count[a[t++]]++ == 0) {
            num += 1;
         }
      }
      if (num < n) {
         break;
      }
      res = cmp::min(res, t - s);
      if (--count[a[s++]] == 0) {
         num --;
      }
   }
   println!("{}", res);

}