version-2.5[对战记录列表(+回放)+排名列表+实现分页功能]

pull/1/head
dyh 3 years ago
parent 1044fa0ff6
commit 3a7849163d

@ -0,0 +1,17 @@
package com.kob.backend.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}

@ -35,7 +35,7 @@ public class WebSocketServer {
//地图
public Game game ;
//加入数据库
private static UserMapper userMapper;
public static UserMapper userMapper;
public static RecordMapper recordMapper;
public static RestTemplate restTemplate;
public static BotMapper botMapper;

@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject;
import com.kob.backend.consumer.WebSocketServer;
import com.kob.backend.pojo.Bot;
import com.kob.backend.pojo.Record;
import com.kob.backend.pojo.User;
import org.springframework.security.core.parameters.P;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@ -201,7 +202,7 @@ public class Game extends Thread {
}
sendBotCode(playerA);
sendBotCode(playerA);//steps是一直动态增加的
sendBotCode(playerB);
@ -304,8 +305,26 @@ public class Game extends Thread {
WebSocketServer.users.get(playerB.getId()).sendMessage(message);
}
private void updateUserRating(Player player,Integer rating){
User user = WebSocketServer.userMapper.selectById(player.getId());//查询用户
user.setRating(rating);
WebSocketServer.userMapper.updateById(user);
}
private void saveToDatabase()
{
Integer ratingA = WebSocketServer.userMapper.selectById(playerA.getId()).getRating();//获取rating
Integer ratingB = WebSocketServer.userMapper.selectById(playerB.getId()).getRating();
if("A".equals(loser)){
ratingA = ratingA - 2 ;
ratingB = ratingB + 5;
} else if("B".equals(loser)) {
ratingA = ratingA + 5 ;
ratingB = ratingB - 2;
}
updateUserRating(playerA,ratingA);
updateUserRating(playerB,ratingB);
Record record = new Record(
null,
playerA.getId(),

@ -0,0 +1,22 @@
package com.kob.backend.controller.ranklist;
import com.alibaba.fastjson.JSONObject;
import com.kob.backend.service.ranklist.RankListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class RankListController {
@Autowired
private RankListService rankListService;
@GetMapping("/ranklist/getlist")
public JSONObject getList(@RequestParam Map<String,String> data){
Integer page = Integer.parseInt(data.get("page"));
return rankListService.getList(page);
}
}

@ -0,0 +1,22 @@
package com.kob.backend.controller.record;
import com.alibaba.fastjson.JSONObject;
import com.kob.backend.service.record.GetRecordListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class GetRecordListController {
@Autowired
private GetRecordListService getRecordListService;
@GetMapping("/record/getlist/")
public JSONObject getList(@RequestParam Map<String,String> data){
Integer page = Integer.parseInt(data.get("page"));
return getRecordListService.getList(page);
}
}

@ -0,0 +1,35 @@
package com.kob.backend.service.impl.ranklist;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kob.backend.mapper.UserMapper;
import com.kob.backend.pojo.User;
import com.kob.backend.service.ranklist.RankListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class RankListServiceImpl implements RankListService {
@Autowired
private UserMapper userMapper;
@Override
public JSONObject getList(Integer page) {
IPage<User> userIPage = new Page<>(page,10);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("rating");
List<User> users = userMapper.selectPage(userIPage,queryWrapper).getRecords();
JSONObject resp = new JSONObject();
for(User user:users){
user.setPassword("");
}
resp.put("users",users);
resp.put("users_count",userMapper.selectCount(null));
return resp;
}
}

@ -0,0 +1,56 @@
package com.kob.backend.service.impl.record;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kob.backend.mapper.RecordMapper;
import com.kob.backend.mapper.UserMapper;
import com.kob.backend.pojo.Record;
import com.kob.backend.pojo.User;
import com.kob.backend.service.record.GetRecordListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class GetRecordListServiceImpl implements GetRecordListService {
@Autowired
private RecordMapper recordMapper ;
@Autowired
private UserMapper userMapper;
@Override
public JSONObject getList(Integer page) {
IPage<Record> recordIPage = new Page<>(page,10);//API
QueryWrapper<Record> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("id");//按照降序排列
List<Record> records = recordMapper.selectPage(recordIPage,queryWrapper).getRecords();//一页
JSONObject resp = new JSONObject();
List<JSONObject> items = new ArrayList<>();
for(Record record:records){
User userA = userMapper.selectById(record.getAId());
User userB = userMapper.selectById(record.getBId());
JSONObject item = new JSONObject();
item.put("a_photo",userA.getPhoto());
item.put("a_username",userA.getUsername());
item.put("b_photo",userB.getPhoto());
item.put("b_username",userB.getUsername());
item.put("record",record);
String result = "平局" ;
if("A".equals(record.getLoser())){
result = "B胜" ;
} else if ("B".equals(record.getLoser())){
result = "A胜" ;
}
item.put("result",result);
items.add(item);
}
resp.put("records",items);
resp.put("records_count",recordMapper.selectCount(null));
return resp;
}
}

@ -1,5 +1,6 @@
package com.kob.backend.service.impl.user.bot;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kob.backend.mapper.BotMapper;
import com.kob.backend.pojo.Bot;
import com.kob.backend.pojo.User;
@ -60,7 +61,12 @@ public class AddServiceImpl implements AddService {
map.put("error_message","代码长度不能超过10000");
return map;
}
QueryWrapper<Bot> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id",user.getId());
if(botMapper.selectCount(queryWrapper)>=10){
map.put("error_message","每个用户最多创建10个Bot");
return map;
}
Date now = new Date();
Bot bot = new Bot(null,user.getId(),title,description,content,now,now);
botMapper.insert(bot);

@ -0,0 +1,7 @@
package com.kob.backend.service.ranklist;
import com.alibaba.fastjson.JSONObject;
public interface RankListService {
public JSONObject getList(Integer page);
}

@ -0,0 +1,7 @@
package com.kob.backend.service.record;
import com.alibaba.fastjson.JSONObject;
public interface GetRecordListService {
public JSONObject getList(Integer page);//传入第几页返回JSONObject
}

@ -11,7 +11,7 @@ public class BotRunningServiceImpl implements BotRunningService {
@Override
public String addBot(Integer userId, String botCode, String input) {
// System.out.println("add bot: " + userId + " " + botCode + " " + input);
System.out.println("add bot: " + userId + " " + botCode + " " + input);
botPool.addBot(userId,botCode,input);
return "add bot success";
}

@ -55,7 +55,7 @@ public class MatchingPool extends Thread {
}
private void matchPlayers(){//匹配所有玩家
System.out.println("match players: "+players.toString());
// System.out.println("match players: "+players.toString());
boolean[] used = new boolean[players.size()];
for(int i = 0 ; i < players.size() ; i++){
if(used[i])continue;

@ -94,25 +94,56 @@ export class GameMap extends AcGameObject
return true;
}
//获取键盘输入
add_listening_events(){
this.ctx.canvas.focus();//cts[DOM] canvas[画板]
//为画板绑定keydown事件
this.ctx.canvas.addEventListener("keydown",e => {
let d = -1;
if(e.key === "w") d = 0;
else if(e.key === "d") d = 1;
else if(e.key === 's') d = 2;
else if(e.key === 'a') d = 3;
if(d >= 0){
this.store.state.pk.socket.send(JSON.stringify({
event:"move",
direction:d,
}))
}
})
if(this.store.state.record.is_record){//record
let k = 0 ;//第k步
const [snake0, snake1] = this.snakes ;
const a_steps = this.store.state.record.a_steps ;
const b_steps = this.store.state.record.b_steps ;
const loser = this.store.state.record.record_loser ;
const interval_id = setInterval(()=>{
if(k >= a_steps.length - 1){
if(loser === "all" || loser === "A"){
snake0.status = "die";
}
if(loser === "all" || loser === "B"){
snake1.status = "die";
}
clearInterval(interval_id);
} else {
snake0.set_direction(parseInt(a_steps[k]));
snake1.set_direction(parseInt(b_steps[k]));
}
k ++ ;
},300)
}
else//PK
{
this.ctx.canvas.focus();//cts[DOM] canvas[画板]
//为画板绑定keydown事件
this.ctx.canvas.addEventListener("keydown",e => {
let d = -1;
if(e.key === "w") d = 0;
else if(e.key === "d") d = 1;
else if(e.key === 's') d = 2;
else if(e.key === 'a') d = 3;
if(d >= 0){
this.store.state.pk.socket.send(JSON.stringify({
event:"move",
direction:d,
}))
}
})
}
}
// else if(e.key === 'ArrowUp' ) snake1.set_direction(0);
// else if(e.key === 'ArrowRight') snake1.set_direction(1);

@ -33,7 +33,6 @@
<div class="col-12" style="text-align : center; padding-top : 12vh;">
<button type="button" class="btn btn-warning btn-lg" @click="click_match_btn">{{match_btn_info}}</button>
</div>
</div>
</div>
</template>
@ -53,7 +52,7 @@ export default {
const click_match_btn = ( )=>{
if(match_btn_info.value === "开始匹配"){
match_btn_info.value = "取消";
console.log(select_bot.value);
// console.log(select_bot.value);
//
store.state.pk.socket.send(JSON.stringify({
event:"start-matching",

@ -1,14 +1,17 @@
<template>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<router-link class='navbar-brand' :to="{name:'home'}">King Of Bots</router-link>
<router-link class='navbar-brand' :to="{name:'home'}">AI Snake</router-link>
<div class="collapse navbar-collapse" id="navbarText">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<!-- <li class="nav-item">
<router-link :class="route_name == 'pk_index' ? 'nav-link active' : 'nav-link' " :to="{name:'pk_index'}">游戏介绍</router-link>
</li> -->
<li class="nav-item">
<!-- router-link单页面 -->
<router-link :class="route_name == 'pk_index' ? 'nav-link active' : 'nav-link' " :to="{name:'pk_index'}">PK</router-link>
<router-link :class="route_name == 'pk_index' ? 'nav-link active' : 'nav-link' " :to="{name:'pk_index'}">挑战页面</router-link>
</li>
<li class="nav-item">

@ -3,6 +3,7 @@ import NotFound from '../views/error/NotFound'
import PkIndexView from '../views/pk/PkIndexView'
import RanklistIndexView from '../views/ranklist/RanklistIndexView'
import RecordIndexView from '../views/record/RecordIndexView'
import RecordContentView from '../views/record/RecordContentView'
import UserBotIndexView from '../views/user/bot/UserBotIndexView'
import UserAccountLoginView from '@/views/user/account/UserAccountLoginView'
import UserAccountRegisterView from '@/views/user/account/UserAccountRegisterView'
@ -37,6 +38,14 @@ const routes = [
requestAuth : true ,
}
},
{
path:"/record/:recordId/",
name:"record_content",
component:RecordContentView,
meta:{
requestAuth : true ,
}
},
//排行榜
{
path:"/ranklist/",

@ -2,6 +2,7 @@
import { createStore } from 'vuex'
import ModuleUser from './user';
import ModulePk from './pk';
import ModuleRecord from './record';
export default createStore({
state: {
},
@ -14,5 +15,6 @@ export default createStore({
modules: {
user:ModuleUser,
pk:ModulePk,
record:ModuleRecord,
}
})

@ -0,0 +1,28 @@
// import $ from "jquery"
export default {
state: {
is_record : false ,
a_steps:"",
b_steps:"",
record_loser:"",
},
getters: {
},
mutations: {
updateIsRecord(state,is_record){
state.is_record = is_record;
},
updateSteps(state,data){
state.a_steps = data.a_steps;
state.b_steps = data.b_steps;
},
updateRecordLoser(state,loser){
state.record_loser = loser ;
}
},
actions: {
},
modules: {
}
}

@ -26,6 +26,7 @@ export default {
let socket = null;
store.commit("updateLoser","none");
store.commit("updateIsRecord",false);
onMounted(()=>{
socket = new WebSocket(socketUrl);//Js

@ -1,19 +1,131 @@
<template>
<ContentField>
排行榜卡槽
<ContentField>
<table class="table table-striped table-hover">
<!-- 表头 -->
<thead>
<tr>
<th>玩家</th>
<th>天梯分数排名</th>
</tr>
</thead>
<!-- 表身 -->
<tbody>
<tr v-for="user in users" :key="user.id">
<td>
<img :src="user.photo" alt="" class="record-user-photo">
&nbsp;
<span class="record-user-username">{{ user.username }}</span>
</td>
<td>
{{user.rating}}
</td>
</tr>
</tbody>
</table>
<nav aria-label="..." >
<ul class="pagination" style="float: right;">
<li class="page-item" @click="click_page(-2)">
<a class="page-link" href="#" >前一页</a>
</li>
<li :class="'page-item ' + page.is_active " v-for="page of pages" :key="page.number" @click="click_page(page.number)">
<a class="page-link" href="#">{{page.number}}</a>
</li>
<li class="page-item" @click="click_page(-1)">
<a class="page-link" href="#">后一页</a>
</li>
</ul>
</nav>
</ContentField>
</template>
<script>
import ContentField from "@/components/ContentField"
import $ from "jquery"
import { useStore } from "vuex"
import { ref } from "vue"
export default {
components:{
ContentField
},
setup(){
const store = useStore();
let total_users = 0 ;
let current_page = 1 ;
let users = ref([]);
let pages = ref([]);
//,page-->-->
//page
const click_page = (page) => {
//&&<<>>
if(page === -2) page = current_page - 1 ;
else if(page === -1) page = current_page + 1 ;
let max_pages = parseInt(Math.ceil(total_users / 10));
if(page >= 1 && page <= max_pages){
pull_page(page);//
}
}
//
const update_pages = () => {
let max_pages = parseInt(Math.ceil(total_users / 10));
let new_pages = [] ;
for(let i = current_page -2 ; i <= current_page +2 ; i ++ ){
if(i >=1 && i <= max_pages){
new_pages.push({
number : i,
is_active : i === current_page ? "active" : "",
});
}
}
pages.value = new_pages ;
}
//page
const pull_page = page =>{
current_page = page ;
$.ajax({
url:"http://127.0.0.1:3000/ranklist/getlist/",
type:"get",
data:{
page:page,
},
headers:{
Authorization:"Bearer " + store.state.user.token,
},
success(resp){
users.value = resp.users ;
total_users = resp.users_count ;
update_pages();//
},
error(resp){
console.log(resp)
}
})
}
pull_page(current_page);
return {
users,
pages,
click_page,
}
}
}
</script>
<style>
<style scoped>
img.record-user-photo {
width: 5vh;
border-radius: 50% ;
}
</style>

@ -0,0 +1,22 @@
<template>
<PlayGround></PlayGround>
</template>
<script>
import PlayGround from "@/components/PlayGround"
export default {
components:{
PlayGround,
},
setup(){
}
}
</script>
<style>
</style>

@ -1,19 +1,193 @@
<template>
<ContentField>
对局列表卡槽
<table class="table table-striped table-hover">
<!-- 表头 -->
<thead>
<tr>
<th>序列号</th>
<th>A</th>
<th>B</th>
<th>对战结果</th>
<th>对战时间</th>
<th>操作</th>
</tr>
</thead>
<!-- 表身 -->
<tbody>
<tr v-for="record in records" :key="record.record.id">
<td>
{{record.record.id}}
</td>
<td>
<img :src="record.a_photo" alt="" class="record-user-photo">
&nbsp;
<span class="record-user-username">{{ record.a_username }}</span>
</td>
<td>
<img :src="record.b_photo" alt="" class="record-user-photo">
&nbsp;
<span class="record-user-username">{{ record.b_username }}</span>
</td>
<td>{{ record.result }}</td>
<td>{{ record.record.createtime }}</td>
<td>
<button @click="open_record_content(record.record.id)" type="button" class="btn btn-secondary">查看录像</button>
</td>
</tr>
</tbody>
</table>
<nav aria-label="..." >
<ul class="pagination" style="float: right;">
<li class="page-item" @click="click_page(-2)">
<a class="page-link" href="#" >前一页</a>
</li>
<li :class="'page-item ' + page.is_active " v-for="page of pages" :key="page.number" @click="click_page(page.number)">
<a class="page-link" href="#">{{page.number}}</a>
</li>
<li class="page-item" @click="click_page(-1)">
<a class="page-link" href="#">后一页</a>
</li>
</ul>
</nav>
</ContentField>
</template>
<script>
import ContentField from "@/components/ContentField"
import $ from "jquery"
import { useStore } from "vuex"
import { ref } from "vue"
import router from "@/router/index"
export default {
components:{
ContentField
},
setup(){
const store = useStore();
let total_records = 0 ;
let current_page = 1 ;
let records = ref([]);
let pages = ref([]);
//,page-->-->
//page
const click_page = (page) => {
//&&<<>>
if(page === -2) page = current_page - 1 ;
else if(page === -1) page = current_page + 1 ;
let max_pages = parseInt(Math.ceil(total_records / 10));
if(page >= 1 && page <= max_pages){
pull_page(page);//
}
}
//
const update_pages = () => {
let max_pages = parseInt(Math.ceil(total_records / 10));
let new_pages = [] ;
for(let i = current_page -2 ; i <= current_page +2 ; i ++ ){
if(i >=1 && i <= max_pages){
new_pages.push({
number : i,
is_active : i === current_page ? "active" : "",
});
}
}
pages.value = new_pages ;
}
//page
const pull_page = page =>{
console.log(total_records,current_page);
current_page = page ;
$.ajax({
url:"http://127.0.0.1:3000/record/getlist/",
type:"get",
data:{
page:page,
},
headers:{
Authorization:"Bearer " + store.state.user.token,
},
success(resp){
records.value = resp.records ;
total_records = resp.records_count ;
update_pages();//
},
error(resp){
console.log(resp)
}
})
}
pull_page(current_page);
const stringTo2D = map =>{
let g = [] ;
for(let i = 0,k = 0;i < 13 ;i ++ ){
let line = [];
for(let j = 0 ;j < 14 ;j++){
if(map[k] === '0')line.push(0);
else line.push(1);
k++;
}
g.push(line);
}
return g ;
}
const open_record_content = recordId => {
for(const record of records.value){
if(record.record.id === recordId){
store.commit("updateIsRecord",true);
store.commit("updateGame",{
map:stringTo2D(record.record.map),
a_id:record.record.aid,
a_sx:record.record.asx,
a_sy:record.record.asy,
b_id:record.record.bid,
b_sx:record.record.bsx,
b_sy:record.record.bsy,
});
store.commit("updateSteps",{
a_steps : record.record.asteps,
b_steps : record.record.bsteps,
});
store.commit("updateRecordLoser",record.record.loser);
router.push({
name:"record_content",
params:{
recordId:recordId,//pathrouter
}
})
break;
}
}
}
return {
records,
open_record_content,
pages,
click_page,
}
}
}
</script>
<style>
<style scoped>
img.record-user-photo {
width: 5vh;
border-radius: 50% ;
}
</style>
Loading…
Cancel
Save